问题
多个插件都想在窗口右下角放一个常驻按钮时,按钮会完全叠在一起:宿主没有给插件任何角落锚点,pi.ui.openLayer() 又是每个插件一个独立的层,层与层之间没有任何协调机制。
真机复现(PI-Desktop 0.16.1,macOS):pi-open-in-vscode 与 pi-open-git-web 两个插件的右下角按钮位置完全重合,肉眼只看得见一颗,另一颗被压在下面。
客户端侧的事实:
-
渲染器插槽里没有角落类。PLUGIN_RENDERER_SLOTS 是 ["userAction", "assistantAction", "entryExtra", "toolCard", "blockRenderer", "composerControl", "composerTrigger"],没有 corner / overlay 一类。
-
pi.ui.openLayer() 给每个插件建一个独立的层(打包产物里的层管理器):
const div = document.createElement("div");
const z = Math.min(899, Math.max(600 - 1, ...this.layers.values()) + 1);
div.setAttribute("data-pi-plugin", pluginId);
div.setAttribute("data-pi-layer", "");
Object.assign(div.style, { position: "fixed", top: "0", left: "0", width: "0", height: "0", zIndex: String(z) });
层是零尺寸的 fixed 元素,插件用 position: fixed 自己定位,各层之间没有共享的定位容器。
-
injectStyle 的 CSS 又是 @scope ([data-pi-plugin="<id>"]),只在本插件自己的层里生效——插件既不该、也没法去给别的插件的元素排版。
-
官方 apps/desktop/src/plugins/renderer-slots/slot-shell.css 里其实已经写好了角落浮层的样式:
.p-overlay { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; }
.p-overlay__corner { align-items: flex-end; justify-content: flex-end; background: transparent; pointer-events: none; padding: 16px; }
.p-overlay__corner > * { pointer-events: auto; }
……但宿主 JS 里没有任何地方用它(打包产物里 p-overlay__corner 只出现在 CSS 里),插件也拿不到这个容器。
结果:插件只能照 docs/plugin-plan/ui/self-dialog/ 的「角落浮层由插件自理」各自 inset: 0 + justify-content: flex-end 画自己的盒子,两颗必然落在同一个像素上。这不是某一个插件写错了,是当前接口下的必然结果。
期望改动
给插件一个宿主管理的角落锚点,让多个插件的角落元素能自动排开:
- 首选:在
PLUGIN_RENDERER_SLOTS 里加一个角落插槽(例如 corner),宿主把各插件注册的角落元素放进同一个 .p-overlay__corner 容器,由宿主负责竖向排列、间距与 pointer-events(盒子 none、子元素 auto),插件只提供自己的元素、卸载即移除。
- 或者退一步:暴露
pi.ui.getCornerContainer()(或等价的角落层入口),宿主保证同一个容器里的元素不重叠、插件卸载即清掉自己的元素。
两种都能把「位置」这件事收回到宿主,插件之间不必互相知道对方存在。
现状变通(如果短期不做)
我自己的两个插件之间定了一条约定,把重叠糊住了,但新插件都得照抄一遍,很脆:
- 角落按钮带属性
data-pi-corner-button(空值);
- 同窗口里所有带这个属性的按钮按 DOM 顺序从右下角往上排,靠后的按下面几颗按钮的高度
transform: translateY() 让位;
- 高度取
getBoundingClientRect().height,隐藏(高度 0)的按钮跳过、不占位;
- 每颗按钮只写自己的内联样式,不碰别人的元素。
实现(两个仓里各一份,逐字相同):https://github.com/w1ndys/pi-open-git-web/blob/main/renderer/corner-stack.mjs
缺点:跨插件强耦合、顺序只能取 DOM 顺序、尺寸或可见性变化要各自重算、新插件不知道这条约定照样会叠。
补充信息
环境:PI-Desktop 0.16.1(macOS)。
受影响的公开插件(都是我自己的):
宿主取证位置:apps/desktop/src/plugins/renderer-slots/slot-shell.css(.p-overlay__corner 样式)、渲染器层管理器(open(pluginId) 建 0×0 fixed 层),以及 SDK 的 PLUGIN_RENDERER_SLOTS。
问题
多个插件都想在窗口右下角放一个常驻按钮时,按钮会完全叠在一起:宿主没有给插件任何角落锚点,
pi.ui.openLayer()又是每个插件一个独立的层,层与层之间没有任何协调机制。真机复现(PI-Desktop 0.16.1,macOS):
pi-open-in-vscode与pi-open-git-web两个插件的右下角按钮位置完全重合,肉眼只看得见一颗,另一颗被压在下面。客户端侧的事实:
渲染器插槽里没有角落类。
PLUGIN_RENDERER_SLOTS是["userAction", "assistantAction", "entryExtra", "toolCard", "blockRenderer", "composerControl", "composerTrigger"],没有 corner / overlay 一类。pi.ui.openLayer()给每个插件建一个独立的层(打包产物里的层管理器):层是零尺寸的
fixed元素,插件用position: fixed自己定位,各层之间没有共享的定位容器。injectStyle的 CSS 又是@scope ([data-pi-plugin="<id>"]),只在本插件自己的层里生效——插件既不该、也没法去给别的插件的元素排版。官方
apps/desktop/src/plugins/renderer-slots/slot-shell.css里其实已经写好了角落浮层的样式:……但宿主 JS 里没有任何地方用它(打包产物里
p-overlay__corner只出现在 CSS 里),插件也拿不到这个容器。结果:插件只能照
docs/plugin-plan/ui/self-dialog/的「角落浮层由插件自理」各自inset: 0+justify-content: flex-end画自己的盒子,两颗必然落在同一个像素上。这不是某一个插件写错了,是当前接口下的必然结果。期望改动
给插件一个宿主管理的角落锚点,让多个插件的角落元素能自动排开:
PLUGIN_RENDERER_SLOTS里加一个角落插槽(例如corner),宿主把各插件注册的角落元素放进同一个.p-overlay__corner容器,由宿主负责竖向排列、间距与 pointer-events(盒子none、子元素auto),插件只提供自己的元素、卸载即移除。pi.ui.getCornerContainer()(或等价的角落层入口),宿主保证同一个容器里的元素不重叠、插件卸载即清掉自己的元素。两种都能把「位置」这件事收回到宿主,插件之间不必互相知道对方存在。
现状变通(如果短期不做)
我自己的两个插件之间定了一条约定,把重叠糊住了,但新插件都得照抄一遍,很脆:
data-pi-corner-button(空值);transform: translateY()让位;getBoundingClientRect().height,隐藏(高度 0)的按钮跳过、不占位;实现(两个仓里各一份,逐字相同):https://github.com/w1ndys/pi-open-git-web/blob/main/renderer/corner-stack.mjs
缺点:跨插件强耦合、顺序只能取 DOM 顺序、尺寸或可见性变化要各自重算、新插件不知道这条约定照样会叠。
补充信息
环境:PI-Desktop 0.16.1(macOS)。
受影响的公开插件(都是我自己的):
v0.6.0v0.2.0宿主取证位置:
apps/desktop/src/plugins/renderer-slots/slot-shell.css(.p-overlay__corner样式)、渲染器层管理器(open(pluginId)建 0×0 fixed 层),以及 SDK 的PLUGIN_RENDERER_SLOTS。