bridgerte 0.9.3 → 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.
Files changed (47) hide show
  1. package/README.md +892 -861
  2. package/dist/bridge.cjs.map +1 -1
  3. package/dist/bridge.d.ts +1 -3
  4. package/dist/bridge.js.map +1 -1
  5. package/dist/core.cjs +1 -1
  6. package/dist/core.cjs.map +1 -1
  7. package/dist/core.d.ts +9 -3
  8. package/dist/core.js +44 -54
  9. package/dist/core.js.map +1 -1
  10. package/dist/dom.cjs +1 -1
  11. package/dist/dom.d.ts +9 -3
  12. package/dist/dom.js +6 -5
  13. package/dist/index-BWi3d-Zp.js +314 -0
  14. package/dist/index-BWi3d-Zp.js.map +1 -0
  15. package/dist/index-B_g23O7q.cjs +4 -0
  16. package/dist/index-B_g23O7q.cjs.map +1 -0
  17. package/dist/index-CuNKUHed.js.map +1 -1
  18. package/dist/index-DF8OhKI4.cjs +2 -0
  19. package/dist/index-DF8OhKI4.cjs.map +1 -0
  20. package/dist/{index-BwZ0II4h.js → index-DyCMSFrm.js} +1135 -1141
  21. package/dist/index-DyCMSFrm.js.map +1 -0
  22. package/dist/index-GaS65GL0.cjs.map +1 -1
  23. package/dist/index-H5V0EMkq.cjs +36 -0
  24. package/dist/index-H5V0EMkq.cjs.map +1 -0
  25. package/dist/index-sbZNOcCB.js +54 -0
  26. package/dist/index-sbZNOcCB.js.map +1 -0
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.d.ts +17 -3
  29. package/dist/index.js +24 -21
  30. package/dist/index.js.map +1 -1
  31. package/dist/native-spec.cjs +1 -1
  32. package/dist/native-spec.cjs.map +1 -1
  33. package/dist/native-spec.d.ts +1 -3
  34. package/dist/native-spec.js +73 -119
  35. package/dist/native-spec.js.map +1 -1
  36. package/dist/style.css +1 -1
  37. package/dist/webview.cjs +1 -1
  38. package/dist/webview.d.ts +1 -3
  39. package/dist/webview.js +1 -1
  40. package/package.json +1 -1
  41. package/dist/index-BaOlPu8L.cjs +0 -4
  42. package/dist/index-BaOlPu8L.cjs.map +0 -1
  43. package/dist/index-BwZ0II4h.js.map +0 -1
  44. package/dist/index-bN5Hs6-3.js +0 -299
  45. package/dist/index-bN5Hs6-3.js.map +0 -1
  46. package/dist/index-hd9Zi2DV.cjs +0 -36
  47. package/dist/index-hd9Zi2DV.cjs.map +0 -1
@@ -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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"}