bridgerte 0.9.4 → 0.9.5

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/README.md CHANGED
@@ -377,8 +377,7 @@ toolbar.update();
377
377
  `toolbarConfig` 规则:
378
378
 
379
379
  - `toolbarKeys`:完整控制显示顺序。
380
- - 字符串项使用 `MenuItem.id`;`'|'` 是唯一可见分割线来源,不执行命令;
381
- `MenuItem.group` 只保留语义分组,不会自动画线。
380
+ - 字符串项使用 `MenuItem.id`,按配置顺序直接渲染按钮;`'|'` 是唯一可见分割线来源,不执行命令。
382
381
  - 分组项使用 `{ key, title, icon, menuKeys }`;DOM toolbar 会渲染一个分组按钮,点击后打开
383
382
  Y 轴纵向收纳菜单,例如上面的配置会显示 `[历史]` 按钮,菜单里是 `[撤销]`、`[重做]`。
384
383
  - `key` 是分组入口的稳定 id,`title` 是按钮文案和 `aria-label`,`icon` 用于分组按钮图标;
@@ -427,13 +426,12 @@ toolbar.update();
427
426
  import { createRichTextEditor, createRichTextToolbar } from 'bridgerte/dom';
428
427
  import { defaultMenuSchema, type MenuItem } from 'bridgerte/native-spec';
429
428
 
430
- const customMenu: MenuItem = {
431
- id: 'custom-clear',
432
- command: { type: 'content.clear' },
433
- label: '清空',
434
- icon: 'custom-clear',
435
- group: 'history'
436
- };
429
+ const customMenu: MenuItem = {
430
+ id: 'custom-clear',
431
+ command: { type: 'content.clear' },
432
+ label: '清空',
433
+ icon: 'custom-clear'
434
+ };
437
435
 
438
436
  const menuSchema = [...defaultMenuSchema, customMenu];
439
437
  const icons = {
package/dist/bridge.d.ts CHANGED
@@ -182,7 +182,7 @@ export type ToolbarGroupConfig = {
182
182
  /**
183
183
  * toolbar JSON 配置项。
184
184
  *
185
- * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,视觉保持和默认 group 分隔一致。
185
+ * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,收纳菜单用对象配置显式声明。
186
186
  */
187
187
  export type ToolbarKey = string | ToolbarGroupConfig;
188
188
  /**
@@ -513,7 +513,6 @@ export type SlashCommandItem = {
513
513
  icon?: string;
514
514
  description?: string;
515
515
  keywords?: string[];
516
- group?: string;
517
516
  requiresPayload?: boolean;
518
517
  payloadPanel?: PayloadPanelSchema;
519
518
  };
@@ -579,7 +578,6 @@ export type MenuItem = {
579
578
  command: EditorCommand;
580
579
  label: string;
581
580
  icon: string;
582
- group: 'text' | 'style' | 'block' | 'list' | 'align' | 'insert' | 'media' | 'table' | 'history' | 'view';
583
581
  requiresPayload?: boolean;
584
582
  payloadPanel?: PayloadPanelSchema;
585
583
  children?: MenuItem[];
package/dist/core.d.ts CHANGED
@@ -182,7 +182,7 @@ export type ToolbarGroupConfig = {
182
182
  /**
183
183
  * toolbar JSON 配置项。
184
184
  *
185
- * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,视觉保持和默认 group 分隔一致。
185
+ * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,收纳菜单用对象配置显式声明。
186
186
  */
187
187
  export type ToolbarKey = string | ToolbarGroupConfig;
188
188
  /**
@@ -513,7 +513,6 @@ export type SlashCommandItem = {
513
513
  icon?: string;
514
514
  description?: string;
515
515
  keywords?: string[];
516
- group?: string;
517
516
  requiresPayload?: boolean;
518
517
  payloadPanel?: PayloadPanelSchema;
519
518
  };
@@ -579,7 +578,6 @@ export type MenuItem = {
579
578
  command: EditorCommand;
580
579
  label: string;
581
580
  icon: string;
582
- group: 'text' | 'style' | 'block' | 'list' | 'align' | 'insert' | 'media' | 'table' | 'history' | 'view';
583
581
  requiresPayload?: boolean;
584
582
  payloadPanel?: PayloadPanelSchema;
585
583
  children?: MenuItem[];
@@ -912,3 +910,11 @@ export declare const BRIDGERTE_CONTENT_VERSION = "0.1.0";
912
910
  export declare const BRIDGERTE_TABLE_INSERT_MAX_ROWS = 20;
913
911
  export declare const BRIDGERTE_TABLE_INSERT_MAX_COLS = 20;
914
912
 
913
+ /**
914
+ * 判断 BridgeRTE 内容快照是否为空。
915
+ *
916
+ * 函数只读取已生成的 `EditorContent` 字段,不触发 DOM 解析或编辑器序列化;调用方应在保存、
917
+ * 提交或离开确认这类低频动作里配合 `editor.getContent()` 使用。
918
+ */
919
+ export declare const isEditorContentEmpty: (content: Partial<EditorContent> | null | undefined) => boolean;
920
+
package/dist/dom.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DKalD8mx.cjs"),t=require("./index-5d8qaSP5.cjs");exports.createFloatingLayer=e.createFloatingLayer;exports.createRichTextEditor=e.createRichTextEditor;exports.createWebViewBridgeRuntime=e.createWebViewBridgeRuntime;exports.createRichTextToolbar=t.createRichTextToolbar;exports.hasMeaningfulHtmlContent=t.hasMeaningfulHtmlContent;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-B_g23O7q.cjs"),t=require("./index-H5V0EMkq.cjs");exports.createFloatingLayer=e.createFloatingLayer;exports.createRichTextEditor=e.createRichTextEditor;exports.createWebViewBridgeRuntime=e.createWebViewBridgeRuntime;exports.createRichTextToolbar=t.createRichTextToolbar;exports.hasMeaningfulHtmlContent=t.hasMeaningfulHtmlContent;
2
2
  //# sourceMappingURL=dom.cjs.map
package/dist/dom.d.ts CHANGED
@@ -182,7 +182,7 @@ export type ToolbarGroupConfig = {
182
182
  /**
183
183
  * toolbar JSON 配置项。
184
184
  *
185
- * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,视觉保持和默认 group 分隔一致。
185
+ * 字符串使用 `MenuItem.id`;特殊字符串 `|` 表示分割线,收纳菜单用对象配置显式声明。
186
186
  */
187
187
  export type ToolbarKey = string | ToolbarGroupConfig;
188
188
  /**
@@ -513,7 +513,6 @@ export type SlashCommandItem = {
513
513
  icon?: string;
514
514
  description?: string;
515
515
  keywords?: string[];
516
- group?: string;
517
516
  requiresPayload?: boolean;
518
517
  payloadPanel?: PayloadPanelSchema;
519
518
  };
@@ -579,7 +578,6 @@ export type MenuItem = {
579
578
  command: EditorCommand;
580
579
  label: string;
581
580
  icon: string;
582
- group: 'text' | 'style' | 'block' | 'list' | 'align' | 'insert' | 'media' | 'table' | 'history' | 'view';
583
581
  requiresPayload?: boolean;
584
582
  payloadPanel?: PayloadPanelSchema;
585
583
  children?: MenuItem[];
@@ -1018,3 +1016,11 @@ export declare function createFloatingLayer(reference: HTMLElement, floating: HT
1018
1016
  */
1019
1017
  export declare function createRichTextEditor(container: HTMLElement, options?: RichTextEditorOptions): EditorAPI;
1020
1018
 
1019
+ /**
1020
+ * 判断一段 HTML 片段是否包含可保存的富文本内容。
1021
+ *
1022
+ * 这个工具会使用浏览器 template 解析 HTML,适合只拿到 HTML 字符串的业务表单;如果已经持有
1023
+ * `EditorContent`,优先使用 core 的 `isEditorContentEmpty()`,避免额外 DOM parse。
1024
+ */
1025
+ export declare const hasMeaningfulHtmlContent: (html: string) => boolean;
1026
+
package/dist/dom.js CHANGED
@@ -1,5 +1,5 @@
1
- import { c as t, a as r, b as o } from "./index-BzpD9bI2.js";
2
- import { c as i, h as n } from "./index-C26bdJ7I.js";
1
+ import { c as t, a as r, b as o } from "./index-DyCMSFrm.js";
2
+ import { c as i, h as n } from "./index-BWi3d-Zp.js";
3
3
  export {
4
4
  t as createFloatingLayer,
5
5
  r as createRichTextEditor,
@@ -0,0 +1,314 @@
1
+ import { defaultMenuSchema as oe, resolveToolbarMenu as re } from "./native-spec.js";
2
+ import { g as C, d as D, e as A, r as ne, f as X, h as ae, c as se } from "./index-DyCMSFrm.js";
3
+ const U = {
4
+ toolbarGroup: `
5
+ <svg
6
+ aria-hidden="true"
7
+ class="lucide lucide-ellipsis"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ width="18"
10
+ height="18"
11
+ viewBox="0 0 24 24"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="2"
15
+ stroke-linecap="round"
16
+ stroke-linejoin="round"
17
+ >
18
+ <circle cx="12" cy="12" r="1" />
19
+ <circle cx="19" cy="12" r="1" />
20
+ <circle cx="5" cy="12" r="1" />
21
+ </svg>
22
+ `,
23
+ chevronDown: `
24
+ <svg
25
+ aria-hidden="true"
26
+ class="lucide lucide-chevron-down"
27
+ xmlns="http://www.w3.org/2000/svg"
28
+ width="12"
29
+ height="12"
30
+ viewBox="0 0 24 24"
31
+ fill="none"
32
+ stroke="currentColor"
33
+ stroke-width="2"
34
+ stroke-linecap="round"
35
+ stroke-linejoin="round"
36
+ >
37
+ <path d="m6 9 6 6 6-6" />
38
+ </svg>
39
+ `
40
+ }, W = (e) => Array.from(
41
+ e.querySelectorAll(".bridgerte__toolbar-group-menu-item")
42
+ ).filter((t) => !t.disabled), le = (e, t) => {
43
+ const l = W(e)[t];
44
+ l && l.focus();
45
+ }, ie = (e) => {
46
+ le(e, 0);
47
+ }, de = (e, t, s, l, d) => {
48
+ var c, u;
49
+ const n = W(t), a = document.activeElement instanceof HTMLButtonElement ? n.indexOf(document.activeElement) : -1, b = (E) => {
50
+ var f;
51
+ if (n.length === 0) return;
52
+ const m = ((a >= 0 ? a : 0) + E + n.length) % n.length;
53
+ (f = n[m]) == null || f.focus();
54
+ };
55
+ switch (e.key) {
56
+ case "ArrowDown":
57
+ e.preventDefault(), b(1);
58
+ break;
59
+ case "ArrowUp":
60
+ e.preventDefault(), b(-1);
61
+ break;
62
+ case "Home":
63
+ e.preventDefault(), (c = n[0]) == null || c.focus();
64
+ break;
65
+ case "End":
66
+ e.preventDefault(), (u = n.at(-1)) == null || u.focus();
67
+ break;
68
+ case "Enter":
69
+ case " ":
70
+ document.activeElement instanceof HTMLButtonElement && (e.preventDefault(), l(document.activeElement), d(), s.focus());
71
+ break;
72
+ case "Escape":
73
+ e.preventDefault(), s.focus(), d();
74
+ break;
75
+ }
76
+ }, G = "button[data-bridgerte-toolbar-group-id]", ce = "button[data-bridgerte-toolbar-item-id]", ue = [
77
+ ce,
78
+ ".bridgerte__toolbar-group-menu-item"
79
+ ].join(","), pe = (e, t) => {
80
+ const s = e.map((l) => C(l, t));
81
+ return {
82
+ active: s.some((l) => l.active),
83
+ disabled: s.length > 0 && s.every((l) => l.disabled)
84
+ };
85
+ }, be = (e, t, s, l, d) => {
86
+ const n = C(t, s), a = document.createElement("button"), b = l[t.icon] ?? D[t.icon];
87
+ a.type = "button", a.className = "bridgerte__toolbar-button", a.disabled = n.disabled, a.dataset.active = String(n.active), a.dataset.bridgerteToolbarItemId = t.id, a.setAttribute("aria-label", t.label), a.setAttribute("aria-pressed", String(n.active)), d && (a.dataset.tooltip = t.label), A(a, b, t.label), e.append(a);
88
+ }, me = (e, t, s, l, d) => {
89
+ const n = document.createElement("button"), a = pe(t.items, s), b = t.icon ? l[t.icon] ?? D[t.icon] : U.toolbarGroup, c = document.createElement("span");
90
+ n.type = "button", n.className = "bridgerte__toolbar-button bridgerte__toolbar-group-button", n.disabled = a.disabled, n.dataset.active = String(a.active), n.dataset.bridgerteToolbarGroupId = t.key, n.dataset.open = "false", n.setAttribute("aria-label", t.title), n.setAttribute("aria-haspopup", "menu"), n.setAttribute("aria-expanded", "false"), n.setAttribute("aria-pressed", String(a.active)), d && (n.dataset.tooltip = t.title), A(n, b, t.title), c.className = "bridgerte__toolbar-group-indicator", c.setAttribute("aria-hidden", "true"), c.innerHTML = U.chevronDown, n.append(c), e.append(n);
91
+ }, ge = (e, t, s, l, d) => {
92
+ e.textContent = "", t.forEach((n) => {
93
+ if (n.type === "separator") {
94
+ const b = document.createElement("span");
95
+ b.className = "bridgerte__toolbar-separator", b.dataset.separatorId = n.key, b.setAttribute("aria-hidden", "true"), e.append(b);
96
+ return;
97
+ }
98
+ if (n.type === "button") {
99
+ be(
100
+ e,
101
+ n.item,
102
+ s,
103
+ l,
104
+ d
105
+ );
106
+ return;
107
+ }
108
+ const a = document.createElement("div");
109
+ a.className = "bridgerte__toolbar-group", a.dataset.group = n.key, a.setAttribute("aria-label", n.title), e.append(a), me(
110
+ a,
111
+ n,
112
+ s,
113
+ l,
114
+ d
115
+ );
116
+ });
117
+ }, _ = (e, t, s, l) => {
118
+ if (e.textContent = "", !t) {
119
+ e.dataset.visible = "false";
120
+ return;
121
+ }
122
+ t.items.forEach((d) => {
123
+ const n = C(d, s), a = document.createElement("button"), b = l[d.icon] ?? D[d.icon], c = document.createElement("span");
124
+ a.type = "button", a.className = "bridgerte__menu-item bridgerte__toolbar-group-menu-item", a.disabled = n.disabled, a.dataset.active = String(n.active), a.dataset.bridgerteToolbarItemId = d.id, a.setAttribute("role", "menuitem"), a.setAttribute("aria-label", d.label), a.setAttribute("aria-pressed", String(n.active)), A(a, b, d.label), c.className = "bridgerte__toolbar-group-menu-label", c.textContent = d.label, a.append(c), e.append(a);
125
+ }), e.dataset.visible = "true", e.style.minWidth = `${t.button.offsetWidth}px`;
126
+ }, B = (e, t) => {
127
+ e.querySelectorAll(G).forEach((s) => {
128
+ const l = (t == null ? void 0 : t.groupKey) === s.dataset.bridgerteToolbarGroupId;
129
+ s.dataset.open = String(l), s.setAttribute("aria-expanded", String(l));
130
+ });
131
+ }, $ = (e, t) => e.find((s) => s.type === "group" && s.key === t), fe = 4, ve = 8, he = 6, ye = () => {
132
+ var e;
133
+ return typeof window < "u" && ((e = window.matchMedia) == null ? void 0 : e.call(window, "(hover: hover) and (pointer: fine)").matches) === !0;
134
+ }, x = (e) => {
135
+ const t = e instanceof Element ? e.closest(ue) : null;
136
+ return t instanceof HTMLButtonElement ? t : null;
137
+ }, Ee = (e) => {
138
+ const t = e instanceof Element ? e.closest(G) : null;
139
+ return t instanceof HTMLButtonElement ? t : null;
140
+ };
141
+ function ke(e, t) {
142
+ const s = t.placement ?? "top", l = ne(t.menuSchema ?? oe, {
143
+ menuLabels: t.menuLabels,
144
+ payloadPanelConfig: t.payloadPanelConfig
145
+ }), d = re(t.toolbarConfig, l), n = d.flatMap((o) => o.type === "button" ? [o.item] : o.type === "group" ? o.items : []), a = t.icons ?? {}, b = ye(), c = document.createElement("div"), u = document.createElement("div"), E = e.closest(".bridgerte") ?? e;
146
+ let y = !1, m = null, f = !1, T = t.editor.getCommandStates(), i = null, g = null;
147
+ const z = X(e, {
148
+ targetSelector: [
149
+ "button[data-bridgerte-toolbar-item-id]",
150
+ "button[data-bridgerte-toolbar-group-id]"
151
+ ].join(",")
152
+ }), J = X(u, {
153
+ targetSelector: ".bridgerte__toolbar-group-menu-item"
154
+ }), M = () => {
155
+ E.append(c), E.append(u);
156
+ }, k = () => {
157
+ g == null || g.setOpen(!1), g == null || g.destroy(), g = null;
158
+ }, P = () => {
159
+ i && (k(), g = se(i.button, u, {
160
+ placement: s === "bottom" ? "top-start" : "bottom-start",
161
+ offset: he,
162
+ strategy: "fixed"
163
+ }), g.setOpen(!0));
164
+ }, v = () => {
165
+ k(), i = null, _(u, i, T, a), B(e, i);
166
+ }, H = (o) => {
167
+ if (!y && (T = o, i && k(), ge(e, d, o, a, b), M(), i)) {
168
+ const r = Array.from(
169
+ e.querySelectorAll(G)
170
+ ).find((te) => te.dataset.bridgerteToolbarGroupId === (i == null ? void 0 : i.groupKey)), p = $(d, i.groupKey);
171
+ i = r && p ? {
172
+ groupKey: i.groupKey,
173
+ button: r,
174
+ items: p.items
175
+ } : null, _(u, i, T, a), B(e, i), i && P();
176
+ }
177
+ }, Q = () => {
178
+ y || H(t.editor.getCommandStates());
179
+ }, h = () => {
180
+ c.dataset.visible = "false", c.textContent = "";
181
+ }, Y = (o) => {
182
+ const r = o.dataset.tooltip;
183
+ if (!b || !r || m) return;
184
+ const p = o.getBoundingClientRect();
185
+ c.textContent = r, c.dataset.visible = "true", c.style.left = `${p.left + p.width / 2}px`, c.style.top = `${p.top - ve}px`;
186
+ }, I = (o) => {
187
+ const r = x(o.target);
188
+ r && Y(r);
189
+ }, N = (o) => {
190
+ const r = o.relatedTarget, p = x(o.target);
191
+ p && r instanceof Node && p.contains(r) || h();
192
+ }, K = () => {
193
+ m = null, delete e.dataset.dragging, document.removeEventListener("pointermove", F), document.removeEventListener("pointerup", L), document.removeEventListener("pointercancel", L);
194
+ }, F = (o) => {
195
+ if (!m) return;
196
+ const r = m.startClientX - o.clientX;
197
+ Math.abs(r) > fe && (m.hasDragged = !0, f = !0, h(), v()), e.scrollLeft = m.startScrollLeft + r;
198
+ }, L = (o) => {
199
+ const r = m;
200
+ K(), r && o.type !== "pointercancel" && r.pointerType !== "mouse" && !r.hasDragged && r.startButton && (S(r.startButton), f = !0);
201
+ }, R = (o) => {
202
+ if (o.pointerType === "mouse" && o.button !== 0) return;
203
+ const r = x(o.target);
204
+ o.preventDefault(), m = {
205
+ startClientX: o.clientX,
206
+ startScrollLeft: e.scrollLeft,
207
+ pointerType: o.pointerType,
208
+ hasDragged: !1,
209
+ startButton: r ?? void 0
210
+ }, e.dataset.dragging = "true", h(), document.addEventListener("pointermove", F), document.addEventListener("pointerup", L), document.addEventListener("pointercancel", L);
211
+ }, S = (o) => {
212
+ if (!(o instanceof HTMLButtonElement) || o.disabled) return;
213
+ const r = n.find((p) => p.id === o.dataset.bridgerteToolbarItemId);
214
+ if (r) {
215
+ if (r.payloadPanel) {
216
+ const p = o.getBoundingClientRect();
217
+ t.editor.requestPayloadPanel({
218
+ menuId: r.id,
219
+ command: r.command,
220
+ panel: r.payloadPanel,
221
+ currentValues: ae(r, t.editor.getCommandStates()),
222
+ anchorRect: {
223
+ x: p.left,
224
+ y: p.top,
225
+ width: p.width,
226
+ height: p.height
227
+ }
228
+ });
229
+ return;
230
+ }
231
+ t.editor.executeCommand(r.command);
232
+ }
233
+ }, Z = (o) => {
234
+ const r = $(
235
+ d,
236
+ o.dataset.bridgerteToolbarGroupId
237
+ );
238
+ if (!(!r || o.disabled)) {
239
+ if ((i == null ? void 0 : i.groupKey) === r.key) {
240
+ v();
241
+ return;
242
+ }
243
+ i = {
244
+ groupKey: r.key,
245
+ button: o,
246
+ items: r.items
247
+ }, h(), _(u, i, T, a), B(e, i), P(), ie(u);
248
+ }
249
+ }, w = (o) => {
250
+ if (f) {
251
+ f = !1, o.preventDefault(), o.stopPropagation();
252
+ return;
253
+ }
254
+ const r = Ee(o.target);
255
+ if (r) {
256
+ o.preventDefault(), o.stopPropagation(), Z(r);
257
+ return;
258
+ }
259
+ const p = x(o.target);
260
+ p && (o.preventDefault(), o.stopPropagation(), S(p), v());
261
+ }, O = (o) => {
262
+ o.pointerType === "mouse" && o.button !== 0 || o.preventDefault();
263
+ }, j = (o) => {
264
+ const r = o.target;
265
+ r instanceof Node && (e.contains(r) || u.contains(r)) || v();
266
+ }, q = (o) => {
267
+ if (i && u.contains(document.activeElement)) {
268
+ de(
269
+ o,
270
+ u,
271
+ i.button,
272
+ S,
273
+ v
274
+ );
275
+ return;
276
+ }
277
+ o.key === "Escape" && v();
278
+ };
279
+ e.classList.add("bridgerte__toolbar"), c.className = "bridgerte__toolbar-tooltip", c.dataset.visible = "false", u.className = "bridgerte__floating-menu bridgerte__toolbar-group-menu", u.dataset.visible = "false", u.setAttribute("role", "menu"), e.dataset.placement = s, e.setAttribute("role", "toolbar"), e.setAttribute(
280
+ "aria-label",
281
+ s === "bottom" ? "BridgeRTE tabbar" : "BridgeRTE toolbar"
282
+ ), e.addEventListener("pointerdown", R, !0), e.addEventListener("click", w), u.addEventListener("pointerdown", O, !0), u.addEventListener("click", w), document.addEventListener("click", j), document.addEventListener("keydown", q), b && (e.addEventListener("mouseover", I), e.addEventListener("mouseout", N)), e.addEventListener("focusout", h), M();
283
+ const ee = t.editor.subscribeCommandStateChange(H);
284
+ return {
285
+ update: Q,
286
+ destroy() {
287
+ y || (y = !0, K(), ee(), v(), e.removeEventListener("pointerdown", R, !0), e.removeEventListener("click", w), u.removeEventListener("pointerdown", O, !0), u.removeEventListener("click", w), document.removeEventListener("click", j), document.removeEventListener("keydown", q), b && (e.removeEventListener("mouseover", I), e.removeEventListener("mouseout", N)), z(), J(), e.removeEventListener("focusout", h), c.remove(), u.remove(), e.classList.remove("bridgerte__toolbar"), delete e.dataset.placement, e.textContent = "", e.removeAttribute("role"), e.removeAttribute("aria-label"));
288
+ }
289
+ };
290
+ }
291
+ const Te = /[\u200B-\u200D\uFEFF]/g, Le = [
292
+ "img",
293
+ "video",
294
+ "audio",
295
+ "iframe",
296
+ "table",
297
+ "pre",
298
+ "code",
299
+ "hr",
300
+ "figure",
301
+ "canvas",
302
+ "svg",
303
+ "math",
304
+ '[data-type="mention"]'
305
+ ].join(","), V = (e) => (e == null ? void 0 : e.replace(Te, "").trim()) ?? "", Se = (e) => {
306
+ if (!V(e)) return !1;
307
+ const t = document.createElement("template");
308
+ return t.innerHTML = e, !!(V(t.content.textContent) || t.content.querySelector(Le));
309
+ };
310
+ export {
311
+ ke as c,
312
+ Se as h
313
+ };
314
+ //# sourceMappingURL=index-BWi3d-Zp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BWi3d-Zp.js","sources":["../../dom/src/menuIcon/uiIcons.ts","../../dom/src/richTextToolbar/groupMenuKeyboard.ts","../../dom/src/richTextToolbar/render.ts","../../dom/src/richTextToolbar/index.ts","../../dom/src/htmlContent/index.ts"],"sourcesContent":["/**\r\n * DOM UI chrome icon 表。\r\n *\r\n * 这里放 toolbar 收纳入口、下拉箭头这类控件自身图标。它们不属于 `MenuItem.icon`\r\n * 跨端 schema,也不应该进入 `defaultMenuIcons` 的 schema 对齐检查。\r\n */\r\nexport const defaultMenuUiIcons = {\r\n toolbarGroup: `\r\n <svg\r\n aria-hidden=\"true\"\r\n class=\"lucide lucide-ellipsis\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\r\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\r\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\r\n </svg>\r\n `,\r\n chevronDown: `\r\n <svg\r\n aria-hidden=\"true\"\r\n class=\"lucide lucide-chevron-down\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"12\"\r\n height=\"12\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n `\r\n} as const;\r\n","export const getEnabledGroupMenuButtons = (menuElement: HTMLElement) => (\r\n Array.from(\r\n menuElement.querySelectorAll<HTMLButtonElement>('.bridgerte__toolbar-group-menu-item')\r\n ).filter((button) => !button.disabled)\r\n);\r\n\r\nexport const focusToolbarGroupMenuItem = (menuElement: HTMLElement, index: number) => {\r\n const buttons = getEnabledGroupMenuButtons(menuElement);\r\n const nextButton = buttons[index];\r\n\r\n if (nextButton) nextButton.focus();\r\n};\r\n\r\nexport const focusFirstToolbarGroupMenuItem = (menuElement: HTMLElement) => {\r\n /*\r\n * group menu 使用 ARIA menu 语义,打开后焦点必须进入第一个可操作项。\r\n * 这样键盘用户可以继续用方向键浏览,而不是停留在展开按钮上。\r\n */\r\n focusToolbarGroupMenuItem(menuElement, 0);\r\n};\r\n\r\nexport const handleToolbarGroupMenuKeyDown = (\r\n event: KeyboardEvent,\r\n menuElement: HTMLElement,\r\n returnButton: HTMLButtonElement,\r\n executeToolbarButton: (button: HTMLButtonElement) => void,\r\n closeGroupMenu: () => void\r\n) => {\r\n const buttons = getEnabledGroupMenuButtons(menuElement);\r\n const activeIndex = document.activeElement instanceof HTMLButtonElement\r\n ? buttons.indexOf(document.activeElement)\r\n : -1;\r\n const focusByOffset = (offset: number) => {\r\n if (buttons.length === 0) return;\r\n\r\n const baseIndex = activeIndex >= 0 ? activeIndex : 0;\r\n const nextIndex = (baseIndex + offset + buttons.length) % buttons.length;\r\n\r\n buttons[nextIndex]?.focus();\r\n };\r\n\r\n /*\r\n * ARIA menu 语义要求支持 roving focus。这里不改 toolbar 的横向键盘模型,\r\n * 只在已打开的纵向收纳菜单内处理上下方向、首尾跳转和执行/关闭。\r\n */\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n focusByOffset(1);\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n focusByOffset(-1);\r\n break;\r\n case 'Home':\r\n event.preventDefault();\r\n buttons[0]?.focus();\r\n break;\r\n case 'End':\r\n event.preventDefault();\r\n buttons.at(-1)?.focus();\r\n break;\r\n case 'Enter':\r\n case ' ':\r\n if (document.activeElement instanceof HTMLButtonElement) {\r\n event.preventDefault();\r\n executeToolbarButton(document.activeElement);\r\n closeGroupMenu();\r\n returnButton.focus();\r\n }\r\n break;\r\n case 'Escape':\r\n event.preventDefault();\r\n returnButton.focus();\r\n closeGroupMenu();\r\n break;\r\n default:\r\n break;\r\n }\r\n};\r\n","import type { CommandState } from '@bridgerte/core';\r\nimport type { MenuItem, ResolvedToolbarItem } from '@bridgerte/native-spec';\r\nimport {\r\n appendMenuIcon,\r\n defaultMenuIcons,\r\n defaultMenuUiIcons\r\n} from './icons';\r\nimport { getMenuStateForItem } from '../menuRuntime';\r\nimport type {\r\n RichTextToolbarIcons,\r\n ToolbarGroupMenuState\r\n} from './type';\r\n\r\nexport const toolbarGroupButtonSelector = 'button[data-bridgerte-toolbar-group-id]';\r\nexport const toolbarButtonSelector = 'button[data-bridgerte-toolbar-item-id]';\r\n// 可执行按钮同时覆盖 toolbar 主按钮和 group menu 子项,避免浮层子菜单绕过统一命令入口。\r\nexport const toolbarExecutableButtonSelector = [\n toolbarButtonSelector,\n '.bridgerte__toolbar-group-menu-item'\n].join(',');\n\r\nconst getGroupMenuState = (items: MenuItem[], commandStates: CommandState[]) => {\r\n const itemStates = items.map((item) => getMenuStateForItem(item, commandStates));\r\n\r\n return {\r\n active: itemStates.some((state) => state.active),\r\n disabled: itemStates.length > 0 && itemStates.every((state) => state.disabled)\r\n };\r\n};\r\n\r\nconst renderToolbarButton = (\r\n groupElement: HTMLElement,\r\n item: MenuItem,\r\n commandStates: CommandState[],\r\n icons: RichTextToolbarIcons,\r\n enableTooltip: boolean\r\n) => {\r\n const state = getMenuStateForItem(item, commandStates);\r\n const button = document.createElement('button');\r\n // icon 兜底顺序固定为:业务覆盖 > DOM 默认 SVG > label 文本。\r\n const iconSvg = icons[item.icon] ?? defaultMenuIcons[item.icon];\r\n\r\n button.type = 'button';\r\n button.className = 'bridgerte__toolbar-button';\r\n button.disabled = state.disabled;\r\n button.dataset.active = String(state.active);\r\n button.dataset.bridgerteToolbarItemId = item.id;\r\n button.setAttribute('aria-label', item.label);\r\n button.setAttribute('aria-pressed', String(state.active));\r\n if (enableTooltip) button.dataset.tooltip = item.label;\r\n\r\n appendMenuIcon(button, iconSvg, item.label);\r\n\r\n groupElement.append(button);\r\n};\r\n\r\nconst renderToolbarGroupButton = (\r\n groupElement: HTMLElement,\r\n toolbarItem: Extract<ResolvedToolbarItem, { type: 'group' }>,\r\n commandStates: CommandState[],\r\n icons: RichTextToolbarIcons,\r\n enableTooltip: boolean\r\n) => {\r\n const button = document.createElement('button');\r\n const groupState = getGroupMenuState(toolbarItem.items, commandStates);\r\n const iconSvg = toolbarItem.icon\r\n ? icons[toolbarItem.icon] ?? defaultMenuIcons[toolbarItem.icon]\r\n : defaultMenuUiIcons.toolbarGroup;\r\n const indicator = document.createElement('span');\r\n\r\n button.type = 'button';\r\n button.className = 'bridgerte__toolbar-button bridgerte__toolbar-group-button';\r\n button.disabled = groupState.disabled;\r\n button.dataset.active = String(groupState.active);\r\n button.dataset.bridgerteToolbarGroupId = toolbarItem.key;\r\n button.dataset.open = 'false';\r\n button.setAttribute('aria-label', toolbarItem.title);\r\n button.setAttribute('aria-haspopup', 'menu');\r\n button.setAttribute('aria-expanded', 'false');\r\n button.setAttribute('aria-pressed', String(groupState.active));\r\n if (enableTooltip) button.dataset.tooltip = toolbarItem.title;\r\n\r\n appendMenuIcon(button, iconSvg, toolbarItem.title);\r\n\r\n indicator.className = 'bridgerte__toolbar-group-indicator';\r\n indicator.setAttribute('aria-hidden', 'true');\r\n indicator.innerHTML = defaultMenuUiIcons.chevronDown;\r\n button.append(indicator);\r\n groupElement.append(button);\r\n};\r\n\r\n/**\r\n * 渲染 toolbar 横向主入口。\n *\n * 字符串菜单直接渲染为按钮,`|` 渲染分割线。\n * 只有用户显式声明的 group 配置才生成收纳入口,避免 schema 隐式改变 DOM 结构。\n */\r\nexport const renderToolbar = (\r\n toolbarElement: HTMLElement,\r\n toolbarItems: ResolvedToolbarItem[],\r\n commandStates: CommandState[],\r\n icons: RichTextToolbarIcons,\r\n enableTooltip: boolean\r\n) => {\r\n toolbarElement.textContent = '';\r\n\r\n toolbarItems.forEach((toolbarItem) => {\n if (toolbarItem.type === 'separator') {\n const separatorElement = document.createElement('span');\n\n separatorElement.className = 'bridgerte__toolbar-separator';\n separatorElement.dataset.separatorId = toolbarItem.key;\r\n separatorElement.setAttribute('aria-hidden', 'true');\r\n toolbarElement.append(separatorElement);\r\n return;\n }\n\n if (toolbarItem.type === 'button') {\n renderToolbarButton(\n toolbarElement,\n toolbarItem.item,\n commandStates,\n icons,\n enableTooltip\n );\n return;\n }\n\n /*\n * 收纳菜单是用户在 toolbarConfig 里显式声明的结构;普通菜单不会自动生成 DOM 包裹,\n * 显示分组完全交给用户用 group 配置或 `|` 控制。\n */\n const groupElement = document.createElement('div');\n\n groupElement.className = 'bridgerte__toolbar-group';\n groupElement.dataset.group = toolbarItem.key;\n groupElement.setAttribute('aria-label', toolbarItem.title);\n toolbarElement.append(groupElement);\n\n renderToolbarGroupButton(\n groupElement,\n toolbarItem,\n commandStates,\n icons,\n enableTooltip\r\n );\r\n });\r\n};\r\n\r\n/**\r\n * 渲染 group button 打开的纵向收纳菜单。\r\n *\r\n * 浮层只展示 MenuItem 子项并复用现有 item id,点击执行仍由 index.ts 统一走 EditorAPI。\r\n */\r\nexport const renderToolbarGroupMenu = (\r\n menuElement: HTMLElement,\r\n groupMenuState: ToolbarGroupMenuState | null,\r\n commandStates: CommandState[],\r\n icons: RichTextToolbarIcons\r\n) => {\r\n menuElement.textContent = '';\r\n\r\n if (!groupMenuState) {\r\n menuElement.dataset.visible = 'false';\r\n return;\r\n }\r\n\r\n groupMenuState.items.forEach((item) => {\r\n const state = getMenuStateForItem(item, commandStates);\r\n const button = document.createElement('button');\r\n const iconSvg = icons[item.icon] ?? defaultMenuIcons[item.icon];\r\n const labelElement = document.createElement('span');\n\n button.type = 'button';\n button.className = 'bridgerte__menu-item bridgerte__toolbar-group-menu-item';\n button.disabled = state.disabled;\r\n button.dataset.active = String(state.active);\r\n button.dataset.bridgerteToolbarItemId = item.id;\r\n button.setAttribute('role', 'menuitem');\r\n button.setAttribute('aria-label', item.label);\r\n button.setAttribute('aria-pressed', String(state.active));\r\n\r\n appendMenuIcon(button, iconSvg, item.label);\r\n labelElement.className = 'bridgerte__toolbar-group-menu-label';\r\n labelElement.textContent = item.label;\r\n button.append(labelElement);\r\n menuElement.append(button);\r\n });\r\n\r\n menuElement.dataset.visible = 'true';\r\n menuElement.style.minWidth = `${groupMenuState.button.offsetWidth}px`;\r\n};\r\n\r\nexport const syncToolbarGroupButtonState = (\r\n container: HTMLElement,\r\n groupMenuState: ToolbarGroupMenuState | null\r\n) => {\r\n container.querySelectorAll<HTMLButtonElement>(toolbarGroupButtonSelector).forEach((button) => {\r\n const open = groupMenuState?.groupKey === button.dataset.bridgerteToolbarGroupId;\r\n\r\n button.dataset.open = String(open);\r\n button.setAttribute('aria-expanded', String(open));\r\n });\r\n};\r\n\r\nexport const findToolbarGroupMenuItem = (\r\n toolbarItems: ResolvedToolbarItem[],\r\n groupKey: string | undefined\r\n) => toolbarItems.find((item): item is Extract<ResolvedToolbarItem, { type: 'group' }> => (\r\n item.type === 'group' && item.key === groupKey\r\n));\r\n","import type { CommandState } from '@bridgerte/core';\r\nimport {\r\n defaultMenuSchema,\r\n resolveToolbarMenu\r\n} from '@bridgerte/native-spec';\r\nimport { createFloatingLayer, type RichTextFloatingLayer } from '../floatingLayer';\r\nimport { bindTouchPressedState } from '../interactionState';\r\nimport {\r\n getPayloadPanelCurrentValues,\r\n resolveMenuSchemaForDom\r\n} from '../menuRuntime';\r\nimport {\r\n focusFirstToolbarGroupMenuItem,\r\n handleToolbarGroupMenuKeyDown\r\n} from './groupMenuKeyboard';\r\nimport {\r\n findToolbarGroupMenuItem,\r\n renderToolbar,\r\n renderToolbarGroupMenu,\r\n syncToolbarGroupButtonState,\r\n toolbarExecutableButtonSelector,\r\n toolbarGroupButtonSelector\r\n} from './render';\r\nimport type {\r\n RichTextToolbarAPI,\r\n ToolbarGroupMenuState,\r\n RichTextToolbarOptions,\r\n ToolbarDragState\r\n} from './type';\r\n\r\nconst toolbarDragClickThresholdPx = 4;\r\nconst toolbarTooltipOffsetPx = 8;\r\nconst toolbarGroupMenuOffsetPx = 6;\r\n\r\nexport type * from './type';\r\n\r\nconst canUseHoverTooltip = () => (\r\n typeof window !== 'undefined'\r\n && window.matchMedia?.('(hover: hover) and (pointer: fine)').matches === true\r\n);\r\n\r\nconst getToolbarButtonFromTarget = (target: EventTarget | null) => {\r\n /*\r\n * 图标覆盖常用 SVG,H5 pointer 事件可能落在 svg/path 上。\r\n * 这里用 Element 而不是 HTMLElement,保证触屏兜底和 click 都能向上命中真实按钮。\r\n */\r\n const button = target instanceof Element\r\n ? target.closest<HTMLButtonElement>(toolbarExecutableButtonSelector)\r\n : null;\r\n\r\n return button instanceof HTMLButtonElement ? button : null;\r\n};\r\n\r\nconst getToolbarGroupButtonFromTarget = (target: EventTarget | null) => {\r\n const button = target instanceof Element\r\n ? target.closest<HTMLButtonElement>(toolbarGroupButtonSelector)\r\n : null;\r\n\r\n return button instanceof HTMLButtonElement ? button : null;\r\n};\r\n\r\n/**\r\n * 创建独立菜单实例。\r\n *\r\n * toolbar/tabbar 只订阅 EditorAPI 状态并派发命令,不接触编辑器内部 DOM 或 Lexical 实例。\r\n */\r\nexport function createRichTextToolbar(\r\n container: HTMLElement,\r\n options: RichTextToolbarOptions\r\n): RichTextToolbarAPI {\r\n const placement = options.placement ?? 'top';\r\n const menuSchema = resolveMenuSchemaForDom(options.menuSchema ?? defaultMenuSchema, {\r\n menuLabels: options.menuLabels,\r\n payloadPanelConfig: options.payloadPanelConfig\r\n });\r\n const toolbarItems = resolveToolbarMenu(options.toolbarConfig, menuSchema);\r\n /*\r\n * click 事件只需要能执行命令的菜单项。分割线和 group 容器是渲染结构,\r\n * 先在这里摊平,后续点击时就不用理解 toolbarConfig 的展示层级。\r\n */\r\n const executableMenuItems = toolbarItems.flatMap((toolbarItem) => (\r\n toolbarItem.type === 'button' ? [toolbarItem.item]\r\n : toolbarItem.type === 'group' ? toolbarItem.items\r\n : []\r\n ));\r\n const icons = options.icons ?? {};\r\n /*\r\n * tooltip 只属于 PC 精细指针体验。H5 上即使没有原生 title,部分浏览器也会把 hover/mouseover\r\n * 模拟成首触摸状态,导致第一次点像是只唤醒提示;所以触屏端不写 tooltip 数据也不挂监听。\r\n */\r\n const enableTooltip = canUseHoverTooltip();\r\n const tooltipElement = document.createElement('div');\r\n const groupMenuElement = document.createElement('div');\r\n const overlayHost = container.closest('.bridgerte') ?? container;\r\n let destroyed = false;\r\n let dragState: ToolbarDragState | null = null;\r\n let shouldSuppressNextClick = false;\r\n let latestCommandStates = options.editor.getCommandStates();\r\n let groupMenuState: ToolbarGroupMenuState | null = null;\r\n let groupMenuFloatingLayer: RichTextFloatingLayer | null = null;\r\n const clearToolbarPressedState = bindTouchPressedState(container, {\r\n targetSelector: [\r\n 'button[data-bridgerte-toolbar-item-id]',\r\n 'button[data-bridgerte-toolbar-group-id]'\r\n ].join(',')\r\n });\r\n const clearGroupMenuPressedState = bindTouchPressedState(groupMenuElement, {\r\n targetSelector: '.bridgerte__toolbar-group-menu-item'\r\n });\r\n\r\n const mountToolbarOverlays = () => {\r\n // 独立 toolbar 可能不在 `.bridgerte` 内,渲染按钮会清空 container,需要把浮层重新挂回去。\r\n overlayHost.append(tooltipElement);\r\n overlayHost.append(groupMenuElement);\r\n };\r\n\r\n const closeGroupMenuFloatingLayer = () => {\r\n groupMenuFloatingLayer?.setOpen(false);\r\n groupMenuFloatingLayer?.destroy();\r\n groupMenuFloatingLayer = null;\r\n };\r\n\r\n const openGroupMenuFloatingLayer = () => {\r\n if (!groupMenuState) return;\r\n\r\n closeGroupMenuFloatingLayer();\r\n /*\r\n * group menu 和 hoverbar/mention/slash 一样属于轻浮层,必须走 floatingLayer。\r\n * 这里按 toolbar placement 给出首选方向,真正的翻转、键盘可视区和左右夹紧交给\r\n * createFloatingLayer 内部的 visualViewport + flip + shift + clamp 统一处理。\r\n */\r\n groupMenuFloatingLayer = createFloatingLayer(groupMenuState.button, groupMenuElement, {\r\n placement: placement === 'bottom' ? 'top-start' : 'bottom-start',\r\n offset: toolbarGroupMenuOffsetPx,\r\n strategy: 'fixed'\r\n });\r\n groupMenuFloatingLayer.setOpen(true);\r\n };\r\n\r\n const closeGroupMenu = () => {\r\n closeGroupMenuFloatingLayer();\r\n groupMenuState = null;\r\n renderToolbarGroupMenu(groupMenuElement, groupMenuState, latestCommandStates, icons);\r\n syncToolbarGroupButtonState(container, groupMenuState);\r\n };\r\n\r\n const renderStates = (states: CommandState[]) => {\r\n if (destroyed) return;\r\n\r\n latestCommandStates = states;\r\n if (groupMenuState) closeGroupMenuFloatingLayer();\r\n renderToolbar(container, toolbarItems, states, icons, enableTooltip);\r\n mountToolbarOverlays();\r\n if (groupMenuState) {\r\n const nextButton = Array.from(\r\n container.querySelectorAll<HTMLButtonElement>(toolbarGroupButtonSelector)\r\n ).find((button) => button.dataset.bridgerteToolbarGroupId === groupMenuState?.groupKey);\r\n const nextGroupItem = findToolbarGroupMenuItem(toolbarItems, groupMenuState.groupKey);\r\n\r\n groupMenuState = nextButton && nextGroupItem\r\n ? {\r\n groupKey: groupMenuState.groupKey,\r\n button: nextButton,\r\n items: nextGroupItem.items\r\n }\r\n : null;\r\n renderToolbarGroupMenu(groupMenuElement, groupMenuState, latestCommandStates, icons);\r\n syncToolbarGroupButtonState(container, groupMenuState);\r\n if (groupMenuState) openGroupMenuFloatingLayer();\r\n }\r\n };\r\n\r\n const update = () => {\r\n if (destroyed) return;\r\n\r\n renderStates(options.editor.getCommandStates());\r\n };\r\n\r\n const hideTooltip = () => {\r\n tooltipElement.dataset.visible = 'false';\r\n tooltipElement.textContent = '';\r\n };\r\n\r\n const showTooltip = (button: HTMLButtonElement) => {\r\n const tooltipText = button.dataset.tooltip;\r\n\r\n if (!enableTooltip || !tooltipText || dragState) return;\r\n\r\n const buttonRect = button.getBoundingClientRect();\r\n\r\n tooltipElement.textContent = tooltipText;\r\n tooltipElement.dataset.visible = 'true';\r\n tooltipElement.style.left = `${buttonRect.left + buttonRect.width / 2}px`;\r\n tooltipElement.style.top = `${buttonRect.top - toolbarTooltipOffsetPx}px`;\r\n };\r\n\r\n const handleTooltipTarget = (event: Event) => {\r\n const button = getToolbarButtonFromTarget(event.target);\r\n\r\n if (button) {\r\n showTooltip(button);\r\n }\r\n };\r\n\r\n const handleTooltipLeave = (event: MouseEvent) => {\r\n const relatedTarget = event.relatedTarget;\r\n const button = getToolbarButtonFromTarget(event.target);\r\n\r\n if (\r\n button\r\n && relatedTarget instanceof Node\r\n && button.contains(relatedTarget)\r\n ) return;\r\n\r\n hideTooltip();\r\n };\r\n\r\n const stopToolbarDrag = () => {\r\n dragState = null;\r\n\r\n delete container.dataset.dragging;\r\n // 拖动过程中监听挂在 document 上,松手或 destroy 必须统一清掉,避免离开 toolbar 后残留滚动状态。\r\n document.removeEventListener('pointermove', handlePointerMove);\r\n document.removeEventListener('pointerup', handlePointerUp);\r\n document.removeEventListener('pointercancel', handlePointerUp);\r\n };\r\n\r\n const handlePointerMove = (event: PointerEvent) => {\r\n if (!dragState) return;\r\n\r\n const deltaX = dragState.startClientX - event.clientX;\r\n\r\n if (Math.abs(deltaX) > toolbarDragClickThresholdPx) {\r\n dragState.hasDragged = true;\r\n shouldSuppressNextClick = true;\r\n hideTooltip();\r\n closeGroupMenu();\r\n }\r\n\r\n container.scrollLeft = dragState.startScrollLeft + deltaX;\r\n };\r\n\r\n const handlePointerUp = (event: PointerEvent) => {\r\n const currentDragState = dragState;\r\n\r\n stopToolbarDrag();\r\n if (\r\n currentDragState\r\n && event.type !== 'pointercancel'\r\n && currentDragState.pointerType !== 'mouse'\r\n && !currentDragState.hasDragged\r\n && currentDragState.startButton\r\n ) {\r\n executeToolbarButton(currentDragState.startButton);\r\n shouldSuppressNextClick = true;\r\n }\r\n };\r\n\r\n const handlePointerDown = (event: PointerEvent) => {\r\n if (event.pointerType === 'mouse' && event.button !== 0) return;\r\n\r\n const startButton = getToolbarButtonFromTarget(event.target);\r\n\r\n // 点击和拖动 toolbar 都要保留编辑区 selection,命令才能继续作用在原选区。\r\n event.preventDefault();\r\n dragState = {\r\n startClientX: event.clientX,\r\n startScrollLeft: container.scrollLeft,\r\n pointerType: event.pointerType,\r\n hasDragged: false,\r\n startButton: startButton ?? undefined\r\n };\r\n container.dataset.dragging = 'true';\r\n hideTooltip();\r\n // pointermove 放到 document,保证用户按住 X 轴拖出 toolbar 后仍能完成滚动和释放。\r\n document.addEventListener('pointermove', handlePointerMove);\r\n document.addEventListener('pointerup', handlePointerUp);\r\n document.addEventListener('pointercancel', handlePointerUp);\r\n };\r\n\r\n const executeToolbarButton = (button: HTMLButtonElement) => {\r\n if (!(button instanceof HTMLButtonElement) || button.disabled) return;\r\n\r\n const menuItem = executableMenuItems.find((item) => (\r\n item.id === button.dataset.bridgerteToolbarItemId\r\n ));\r\n\r\n if (!menuItem) return;\r\n\r\n if (menuItem.payloadPanel) {\r\n const buttonRect = button.getBoundingClientRect();\r\n\r\n /*\r\n * 带 payloadPanel 的菜单不直接执行基础 command,而是发起参数请求。\r\n * DOM 内置面板和业务/RN/Flutter 自绘都走同一个 request,避免后续颜色、\r\n * 字体、链接等参数菜单各自发明一套协议。\r\n */\r\n options.editor.requestPayloadPanel({\r\n menuId: menuItem.id,\r\n command: menuItem.command,\r\n panel: menuItem.payloadPanel,\r\n currentValues: getPayloadPanelCurrentValues(menuItem, options.editor.getCommandStates()),\r\n anchorRect: {\r\n x: buttonRect.left,\r\n y: buttonRect.top,\r\n width: buttonRect.width,\r\n height: buttonRect.height\r\n }\r\n });\r\n return;\r\n }\r\n\r\n options.editor.executeCommand(menuItem.command);\r\n };\r\n\r\n const toggleGroupMenu = (button: HTMLButtonElement) => {\r\n const groupItem = findToolbarGroupMenuItem(\r\n toolbarItems,\r\n button.dataset.bridgerteToolbarGroupId\r\n );\r\n\r\n if (!groupItem || button.disabled) return;\r\n\r\n if (groupMenuState?.groupKey === groupItem.key) {\r\n closeGroupMenu();\r\n return;\r\n }\r\n\r\n groupMenuState = {\r\n groupKey: groupItem.key,\r\n button,\r\n items: groupItem.items\r\n };\r\n hideTooltip();\r\n renderToolbarGroupMenu(groupMenuElement, groupMenuState, latestCommandStates, icons);\r\n syncToolbarGroupButtonState(container, groupMenuState);\r\n openGroupMenuFloatingLayer();\r\n focusFirstToolbarGroupMenuItem(groupMenuElement);\r\n };\r\n\r\n const handleClick = (event: MouseEvent) => {\r\n if (shouldSuppressNextClick) {\r\n shouldSuppressNextClick = false;\r\n event.preventDefault();\r\n event.stopPropagation();\r\n return;\r\n }\r\n\r\n const groupButton = getToolbarGroupButtonFromTarget(event.target);\r\n if (groupButton) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n toggleGroupMenu(groupButton);\r\n return;\r\n }\r\n\r\n const button = getToolbarButtonFromTarget(event.target);\r\n if (!button) return;\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n executeToolbarButton(button);\r\n closeGroupMenu();\r\n };\r\n\r\n const handleGroupMenuPointerDown = (event: PointerEvent) => {\r\n /*\r\n * group 菜单浮层挂在 toolbar 容器外,不能复用容器级 pointerdown。\r\n * 子菜单点击仍要保留编辑区 selection,否则格式命令会丢失原选区。\r\n */\r\n if (event.pointerType === 'mouse' && event.button !== 0) return;\r\n\r\n event.preventDefault();\r\n };\r\n\r\n const handleDocumentClick = (event: MouseEvent) => {\r\n const target = event.target;\r\n\r\n if (\r\n target instanceof Node\r\n && (container.contains(target) || groupMenuElement.contains(target))\r\n ) return;\r\n\r\n closeGroupMenu();\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent) => {\r\n if (groupMenuState && groupMenuElement.contains(document.activeElement)) {\r\n handleToolbarGroupMenuKeyDown(\r\n event,\r\n groupMenuElement,\r\n groupMenuState.button,\r\n executeToolbarButton,\r\n closeGroupMenu\r\n );\r\n return;\r\n }\r\n\r\n if (event.key !== 'Escape') return;\r\n\r\n closeGroupMenu();\r\n };\r\n\r\n container.classList.add('bridgerte__toolbar');\r\n tooltipElement.className = 'bridgerte__toolbar-tooltip';\r\n tooltipElement.dataset.visible = 'false';\r\n groupMenuElement.className = 'bridgerte__floating-menu bridgerte__toolbar-group-menu';\n groupMenuElement.dataset.visible = 'false';\r\n groupMenuElement.setAttribute('role', 'menu');\r\n container.dataset.placement = placement;\r\n container.setAttribute('role', 'toolbar');\r\n container.setAttribute(\r\n 'aria-label',\r\n placement === 'bottom' ? 'BridgeRTE tabbar' : 'BridgeRTE toolbar'\r\n );\r\n container.addEventListener('pointerdown', handlePointerDown, true);\r\n container.addEventListener('click', handleClick);\r\n groupMenuElement.addEventListener('pointerdown', handleGroupMenuPointerDown, true);\r\n groupMenuElement.addEventListener('click', handleClick);\r\n document.addEventListener('click', handleDocumentClick);\r\n document.addEventListener('keydown', handleKeyDown);\r\n if (enableTooltip) {\r\n container.addEventListener('mouseover', handleTooltipTarget);\r\n container.addEventListener('mouseout', handleTooltipLeave);\r\n }\r\n container.addEventListener('focusout', hideTooltip);\r\n // 浮层挂在最近的编辑器根容器下,既能继承变量,也不会操作编辑内容 DOM。\r\n mountToolbarOverlays();\r\n\r\n // 独立 toolbar 只订阅 public API 状态,不依赖 DOM 编辑器内部实现。\r\n const unsubscribe = options.editor.subscribeCommandStateChange(renderStates);\r\n\r\n return {\r\n update,\r\n destroy() {\r\n if (destroyed) return;\r\n\r\n destroyed = true;\r\n stopToolbarDrag();\r\n unsubscribe();\r\n closeGroupMenu();\r\n container.removeEventListener('pointerdown', handlePointerDown, true);\r\n container.removeEventListener('click', handleClick);\r\n groupMenuElement.removeEventListener('pointerdown', handleGroupMenuPointerDown, true);\r\n groupMenuElement.removeEventListener('click', handleClick);\r\n document.removeEventListener('click', handleDocumentClick);\r\n document.removeEventListener('keydown', handleKeyDown);\r\n if (enableTooltip) {\r\n container.removeEventListener('mouseover', handleTooltipTarget);\r\n container.removeEventListener('mouseout', handleTooltipLeave);\r\n }\r\n clearToolbarPressedState();\r\n clearGroupMenuPressedState();\r\n container.removeEventListener('focusout', hideTooltip);\r\n tooltipElement.remove();\r\n groupMenuElement.remove();\r\n container.classList.remove('bridgerte__toolbar');\r\n delete container.dataset.placement;\r\n container.textContent = '';\r\n container.removeAttribute('role');\r\n container.removeAttribute('aria-label');\r\n }\r\n };\r\n}\r\n","const invisibleTextPattern = /[\\u200B-\\u200D\\uFEFF]/g;\n\n/*\n * HTML 片段里这些元素没有 textContent 也应算有效内容。\n * 纯排版容器不放进来,避免 `<p><br></p>`、空列表项这类编辑器占位被误判为非空。\n */\nconst meaningfulHtmlContentSelector = [\n 'img',\n 'video',\n 'audio',\n 'iframe',\n 'table',\n 'pre',\n 'code',\n 'hr',\n 'figure',\n 'canvas',\n 'svg',\n 'math',\n '[data-type=\"mention\"]'\n].join(',');\n\nconst normalizeHtmlText = (text: string | null | undefined): string => (\n text?.replace(invisibleTextPattern, '').trim() ?? ''\n);\n\n/**\n * 判断一段 HTML 片段是否包含可保存的富文本内容。\n *\n * 这个工具会使用浏览器 template 解析 HTML,适合只拿到 HTML 字符串的业务表单;如果已经持有\n * `EditorContent`,优先使用 core 的 `isEditorContentEmpty()`,避免额外 DOM parse。\n */\nexport const hasMeaningfulHtmlContent = (html: string): boolean => {\n if (!normalizeHtmlText(html)) return false;\n\n const template = document.createElement('template');\n\n template.innerHTML = html;\n\n return Boolean(\n normalizeHtmlText(template.content.textContent)\n || template.content.querySelector(meaningfulHtmlContentSelector)\n );\n};\n"],"names":["defaultMenuUiIcons","getEnabledGroupMenuButtons","menuElement","button","focusToolbarGroupMenuItem","index","nextButton","focusFirstToolbarGroupMenuItem","handleToolbarGroupMenuKeyDown","event","returnButton","executeToolbarButton","closeGroupMenu","buttons","activeIndex","focusByOffset","offset","nextIndex","_a","_b","toolbarGroupButtonSelector","toolbarButtonSelector","toolbarExecutableButtonSelector","getGroupMenuState","items","commandStates","itemStates","item","getMenuStateForItem","state","renderToolbarButton","groupElement","icons","enableTooltip","iconSvg","defaultMenuIcons","appendMenuIcon","renderToolbarGroupButton","toolbarItem","groupState","indicator","renderToolbar","toolbarElement","toolbarItems","separatorElement","renderToolbarGroupMenu","groupMenuState","labelElement","syncToolbarGroupButtonState","container","open","findToolbarGroupMenuItem","groupKey","toolbarDragClickThresholdPx","toolbarTooltipOffsetPx","toolbarGroupMenuOffsetPx","canUseHoverTooltip","getToolbarButtonFromTarget","target","getToolbarGroupButtonFromTarget","createRichTextToolbar","options","placement","menuSchema","resolveMenuSchemaForDom","defaultMenuSchema","resolveToolbarMenu","executableMenuItems","tooltipElement","groupMenuElement","overlayHost","destroyed","dragState","shouldSuppressNextClick","latestCommandStates","groupMenuFloatingLayer","clearToolbarPressedState","bindTouchPressedState","clearGroupMenuPressedState","mountToolbarOverlays","closeGroupMenuFloatingLayer","openGroupMenuFloatingLayer","createFloatingLayer","renderStates","states","nextGroupItem","update","hideTooltip","showTooltip","tooltipText","buttonRect","handleTooltipTarget","handleTooltipLeave","relatedTarget","stopToolbarDrag","handlePointerMove","handlePointerUp","deltaX","currentDragState","handlePointerDown","startButton","menuItem","getPayloadPanelCurrentValues","toggleGroupMenu","groupItem","handleClick","groupButton","handleGroupMenuPointerDown","handleDocumentClick","handleKeyDown","unsubscribe","invisibleTextPattern","meaningfulHtmlContentSelector","normalizeHtmlText","text","hasMeaningfulHtmlContent","html","template"],"mappings":"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"}