fix(creator-studio): hide block-delete overlay inside the editor iframe

块级删除浮层插在 TinyMCE 的 iframe 里,但隐藏规则只写在父页面样式表,
iframe 是独立文档、拿不到这些样式,于是 opacity:0 / position:absolute 全部
失效,✕ 退化成正文顶部的常显元素。

- 把 #jio-block-actions 的定位与隐藏规则移入 content_style,并给 body 加
  position:relative 作为定位基准;隐藏时 pointer-events:none 避免挡住正文
- 浮层加 data-mce-bogus="all",让 TinyMCE 在序列化、字数和选区计算时跳过它,
  否则 ✕ 会被写进保存内容
- 删除 _block-tools.scss 中作用于同一选择器的页面级死样式
- 契约测试锁定「样式必须在 content_style」与 bogus 属性

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-08 22:36:57 +08:00
1 parent 1970db0b56
commit 3e48fdf61e
7 files changed
+77 -44

No files matched your search

@@ -2,14 +2,15 @@
* TinyMCE iframe 内的正文样式。
*
* 编辑器正文跑在 iframe 里,页面级 SCSS 影响不到它,所以这里显式给出:
* 正文排版、主题引用 .quote_q、表格、公式、目录占位,以及代码块右上角的
* 语言标签(可点击,由父组件监听 pre 的点击打开语言选择)。
* 正文排版、主题引用 .quote_q、表格、公式、目录占位、块级删除控件,以及
* 代码块右上角的语言标签。
*
* @package Jio
*/
export const EDITOR_CONTENT_STYLE = `
body {
position: relative;
margin: 0;
color: #2b2b2b;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
@@ -22,6 +23,46 @@ h1, h2, h3, h4, h5, h6 { margin: 1.5em 0 0.65em; line-height: 1.4; }
img, iframe { max-width: 100%; }
img { height: auto; }
/*
* 块级删除控件。它由 editor-runtime 插进 iframe 的 body,样式必须写在这里:
* 父页面样式表管不到 iframe 内部,缺这条规则时按钮会退化成正文顶部的常显 ✕。
* 正文是流式布局且 iframe 高度随内容增长,所以按整篇正文定位,而不是相对某个块。
*/
#jio-block-actions {
position: absolute;
z-index: 5;
top: 6px;
right: 6px;
display: flex;
gap: 6px;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s ease;
}
#jio-block-actions.is-visible {
opacity: 1;
pointer-events: auto;
}
#jio-block-actions .jio-creator__block-action {
display: inline-flex;
width: 26px;
height: 26px;
align-items: center;
justify-content: center;
padding: 0;
border: 1px solid #e3e7e5;
border-radius: 6px;
background: #fff;
color: #7d8683;
cursor: pointer;
font-size: 12px;
line-height: 1;
}
#jio-block-actions .jio-creator__block-action:hover {
border-color: #e6b8ad;
color: #b4573f;
}
/* 代码块:右上角显示当前语言,点击即可更换(交互在父组件里接管)。 */
.enlighter-pre {
position: relative;
@@ -143,6 +143,10 @@ export function syncCodeLabels(editor: any): void {
*
* 与 WPS 的块操作一致:鼠标悬停到块上时在右上角出现删除入口,
* 避免只能靠反复按退格键。
*
* 浮层直接插在 iframe 的 body 里,因此用 data-mce-bogus 让 TinyMCE 在
* 序列化、字数和选区计算时完全忽略它;它的样式写在 editor-content-style.ts
* (父页面样式表管不到 iframe 内部)。
*/
export function installBlockActions(editor: any): void {
const doc = editor.getDoc();
@@ -152,6 +156,8 @@ export function installBlockActions(editor: any): void {
const bar = doc.createElement('div');
bar.id = 'jio-block-actions';
bar.className = 'jio-creator__block-actions';
// "all" 让 TinyMCE 连同子节点一起跳过。
bar.setAttribute('data-mce-bogus', 'all');
bar.innerHTML =
'<button type="button" class="jio-creator__block-action" data-jio-block-delete title="' +
'删除此块' +
@@ -366,43 +366,10 @@
}
}
/* ---------- 块级删除控件(接近 WPS 的「块操作」) ---------- */
.jio-creator__block-actions {
position: absolute;
z-index: 5;
top: 6px;
right: 6px;
display: flex;
gap: 6px;
opacity: 0;
transition: opacity 0.15s ease;
}
.jio-creator__block-actions.is-visible {
opacity: 1;
}
.jio-creator__block-action {
display: inline-flex;
width: 26px;
height: 26px;
align-items: center;
justify-content: center;
border: 1px solid #e3e7e5;
border-radius: 6px;
background: #fff;
color: #7d8683;
cursor: pointer;
font-size: 12px;
&:hover,
&:focus-visible {
border-color: #e6b8ad;
color: #b4573f;
outline: 0;
}
}
/*
* 块级删除控件的样式在 editor-content-style.ts 里:该控件插在 TinyMCE
* iframe 内部,页面级样式表作用不到。这里不再重复定义。
*/
@media (max-width: 767px) {
.jio-creator__status {