suneditor 3.1.4 → 3.2.1

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 (217) hide show
  1. package/dist/suneditor-contents.min.css +1 -1
  2. package/dist/suneditor.min.css +28 -1
  3. package/dist/suneditor.min.js +1 -1
  4. package/package.json +2 -1
  5. package/src/assets/design/color.css +12 -0
  6. package/src/assets/design/size.css +9 -2
  7. package/src/assets/icons/defaultIcons.js +96 -47
  8. package/src/assets/suneditor-contents.css +3 -2
  9. package/src/assets/suneditor.css +481 -31
  10. package/src/core/config/contextProvider.js +2 -1
  11. package/src/core/config/eventManager.js +41 -2
  12. package/src/core/config/optionProvider.js +23 -2
  13. package/src/core/editor.js +32 -14
  14. package/src/core/event/actions/index.js +76 -9
  15. package/src/core/event/effects/common.registry.js +2 -1
  16. package/src/core/event/effects/keydown.registry.js +169 -33
  17. package/src/core/event/effects/ruleHelpers.js +20 -6
  18. package/src/core/event/eventOrchestrator.js +162 -30
  19. package/src/core/event/handlers/handler_toolbar.js +4 -2
  20. package/src/core/event/handlers/handler_ww_dragDrop.js +10 -0
  21. package/src/core/event/handlers/handler_ww_input.js +84 -2
  22. package/src/core/event/handlers/handler_ww_key.js +82 -21
  23. package/src/core/event/handlers/handler_ww_mouse.js +45 -8
  24. package/src/core/event/ports.js +27 -13
  25. package/src/core/event/reducers/keydown.reducer.js +33 -5
  26. package/src/core/event/rules/keydown.rule.arrow.js +12 -2
  27. package/src/core/event/rules/keydown.rule.backspace.js +110 -15
  28. package/src/core/event/rules/keydown.rule.delete.js +62 -7
  29. package/src/core/event/rules/keydown.rule.enter.js +62 -31
  30. package/src/core/event/support/defaultLineManager.js +9 -2
  31. package/src/core/event/support/selectionState.js +13 -3
  32. package/src/core/kernel/coreKernel.js +1 -0
  33. package/src/core/logic/dom/char.js +13 -3
  34. package/src/core/logic/dom/format.js +171 -39
  35. package/src/core/logic/dom/html.js +350 -72
  36. package/src/core/logic/dom/inline.js +229 -34
  37. package/src/core/logic/dom/listFormat.js +111 -20
  38. package/src/core/logic/dom/nodeTransform.js +36 -11
  39. package/src/core/logic/dom/offset.js +116 -31
  40. package/src/core/logic/dom/selection.js +147 -29
  41. package/src/core/logic/panel/blockHandle.js +785 -0
  42. package/src/core/logic/panel/blockResolver.js +278 -0
  43. package/src/core/logic/panel/finder.js +16 -6
  44. package/src/core/logic/panel/menu.js +119 -18
  45. package/src/core/logic/panel/toolbar.js +75 -19
  46. package/src/core/logic/panel/viewer.js +76 -20
  47. package/src/core/logic/shell/_commandExecutor.js +44 -9
  48. package/src/core/logic/shell/commandDispatcher.js +46 -4
  49. package/src/core/logic/shell/component.js +102 -25
  50. package/src/core/logic/shell/focusManager.js +13 -3
  51. package/src/core/logic/shell/history.js +21 -6
  52. package/src/core/logic/shell/pluginManager.js +21 -13
  53. package/src/core/logic/shell/shortcuts.js +9 -1
  54. package/src/core/logic/shell/ui.js +139 -37
  55. package/src/core/schema/frameContext.js +34 -3
  56. package/src/core/schema/options.js +46 -4
  57. package/src/core/section/constructor.js +537 -106
  58. package/src/core/section/documentType.js +35 -6
  59. package/src/helper/converter.js +24 -7
  60. package/src/helper/dom/domCheck.js +25 -5
  61. package/src/helper/dom/domQuery.js +2 -1
  62. package/src/helper/dom/domUtils.js +17 -4
  63. package/src/helper/env.js +11 -2
  64. package/src/helper/keyCodeMap.js +6 -2
  65. package/src/helper/markdown.js +24 -5
  66. package/src/helper/msOffice.js +9 -2
  67. package/src/interfaces/plugins.js +1 -1
  68. package/src/langs/ckb.js +0 -1
  69. package/src/langs/cs.js +0 -1
  70. package/src/langs/da.js +0 -1
  71. package/src/langs/de.js +0 -1
  72. package/src/langs/en.js +0 -1
  73. package/src/langs/es.js +0 -1
  74. package/src/langs/fa.js +0 -1
  75. package/src/langs/fr.js +0 -1
  76. package/src/langs/he.js +0 -1
  77. package/src/langs/hu.js +0 -1
  78. package/src/langs/index.js +27 -1
  79. package/src/langs/it.js +0 -1
  80. package/src/langs/ja.js +0 -1
  81. package/src/langs/km.js +0 -1
  82. package/src/langs/ko.js +0 -1
  83. package/src/langs/lv.js +0 -1
  84. package/src/langs/nl.js +0 -1
  85. package/src/langs/pl.js +0 -1
  86. package/src/langs/pt_br.js +0 -1
  87. package/src/langs/ro.js +0 -1
  88. package/src/langs/ru.js +0 -1
  89. package/src/langs/se.js +0 -1
  90. package/src/langs/tr.js +0 -1
  91. package/src/langs/uk.js +0 -1
  92. package/src/langs/ur.js +0 -1
  93. package/src/langs/zh_cn.js +0 -1
  94. package/src/modules/contract/Browser.js +58 -14
  95. package/src/modules/contract/ColorPicker.js +12 -4
  96. package/src/modules/contract/Controller.js +37 -7
  97. package/src/modules/contract/Figure.js +156 -36
  98. package/src/modules/contract/HueSlider.js +27 -4
  99. package/src/modules/contract/Modal.js +50 -10
  100. package/src/modules/manager/FileManager.js +50 -8
  101. package/src/modules/ui/CommandMenu.js +597 -0
  102. package/src/modules/ui/ModalAnchorEditor.js +33 -6
  103. package/src/modules/ui/SelectMenu.js +481 -36
  104. package/src/modules/ui/index.js +1 -0
  105. package/src/plugins/browser/audioGallery.js +2 -1
  106. package/src/plugins/browser/fileBrowser.js +9 -2
  107. package/src/plugins/browser/fileGallery.js +2 -1
  108. package/src/plugins/browser/imageGallery.js +18 -3
  109. package/src/plugins/browser/videoGallery.js +13 -4
  110. package/src/plugins/command/blockquote.js +6 -1
  111. package/src/plugins/command/codeBlock.js +43 -5
  112. package/src/plugins/command/exportPDF.js +20 -4
  113. package/src/plugins/command/fileUpload.js +46 -11
  114. package/src/plugins/command/list_bulleted.js +6 -1
  115. package/src/plugins/command/list_numbered.js +6 -1
  116. package/src/plugins/dropdown/align.js +21 -33
  117. package/src/plugins/dropdown/backgroundColor.js +10 -2
  118. package/src/plugins/dropdown/blockStyle.js +17 -22
  119. package/src/plugins/dropdown/font.js +34 -34
  120. package/src/plugins/dropdown/hr.js +15 -43
  121. package/src/plugins/dropdown/layout.js +10 -27
  122. package/src/plugins/dropdown/lineHeight.js +10 -33
  123. package/src/plugins/dropdown/list.js +19 -25
  124. package/src/plugins/dropdown/paragraphStyle.js +16 -24
  125. package/src/plugins/dropdown/table/index.js +72 -17
  126. package/src/plugins/dropdown/table/render/table.html.js +3 -1
  127. package/src/plugins/dropdown/table/services/table.cell.js +33 -7
  128. package/src/plugins/dropdown/table/services/table.clipboard.js +5 -1
  129. package/src/plugins/dropdown/table/services/table.grid.js +40 -9
  130. package/src/plugins/dropdown/table/services/table.resize.js +55 -11
  131. package/src/plugins/dropdown/table/services/table.selection.js +27 -7
  132. package/src/plugins/dropdown/table/services/table.style.js +120 -20
  133. package/src/plugins/dropdown/template.js +13 -29
  134. package/src/plugins/dropdown/textStyle.js +22 -35
  135. package/src/plugins/field/autocomplete.js +8 -4
  136. package/src/plugins/field/slashCommand.js +297 -0
  137. package/src/plugins/index.js +3 -0
  138. package/src/plugins/input/fontSize.js +37 -8
  139. package/src/plugins/input/pageNavigator.js +7 -1
  140. package/src/plugins/modal/audio.js +71 -17
  141. package/src/plugins/modal/drawing.js +41 -11
  142. package/src/plugins/modal/embed.js +92 -22
  143. package/src/plugins/modal/image/index.js +114 -28
  144. package/src/plugins/modal/image/services/image.size.js +9 -2
  145. package/src/plugins/modal/image/services/image.upload.js +38 -4
  146. package/src/plugins/modal/link.js +9 -2
  147. package/src/plugins/modal/math.js +10 -2
  148. package/src/plugins/modal/video/index.js +112 -26
  149. package/src/plugins/modal/video/render/video.html.js +4 -1
  150. package/src/plugins/modal/video/services/video.size.js +15 -4
  151. package/src/plugins/modal/video/services/video.upload.js +10 -2
  152. package/src/plugins/popup/anchor.js +14 -2
  153. package/src/suneditor.js +8 -2
  154. package/src/themes/cobalt.css +12 -0
  155. package/src/themes/cream.css +12 -0
  156. package/src/themes/dark.css +12 -0
  157. package/src/themes/midnight.css +12 -0
  158. package/src/typedef.js +32 -21
  159. package/types/assets/icons/defaultIcons.d.ts +1 -0
  160. package/types/core/config/contextProvider.d.ts +7 -1
  161. package/types/core/config/eventManager.d.ts +37 -4
  162. package/types/core/config/optionProvider.d.ts +5 -1
  163. package/types/core/event/actions/index.d.ts +44 -6
  164. package/types/core/event/effects/keydown.registry.d.ts +37 -7
  165. package/types/core/event/effects/ruleHelpers.d.ts +6 -1
  166. package/types/core/event/eventOrchestrator.d.ts +13 -3
  167. package/types/core/event/handlers/handler_ww_clipboard.d.ts +15 -3
  168. package/types/core/event/handlers/handler_ww_dragDrop.d.ts +14 -2
  169. package/types/core/event/handlers/handler_ww_input.d.ts +10 -2
  170. package/types/core/event/handlers/handler_ww_key.d.ts +10 -2
  171. package/types/core/event/handlers/handler_ww_mouse.d.ts +25 -5
  172. package/types/core/event/ports.d.ts +11 -4
  173. package/types/core/event/reducers/keydown.reducer.d.ts +12 -3
  174. package/types/core/event/rules/keydown.rule.backspace.d.ts +6 -1
  175. package/types/core/kernel/store.d.ts +4 -1
  176. package/types/core/logic/dom/format.d.ts +32 -14
  177. package/types/core/logic/dom/html.d.ts +11 -3
  178. package/types/core/logic/dom/nodeTransform.d.ts +6 -6
  179. package/types/core/logic/panel/blockHandle.d.ts +64 -0
  180. package/types/core/logic/panel/blockResolver.d.ts +50 -0
  181. package/types/core/logic/panel/menu.d.ts +72 -3
  182. package/types/core/logic/shell/commandDispatcher.d.ts +8 -0
  183. package/types/core/logic/shell/component.d.ts +5 -3
  184. package/types/core/logic/shell/shortcuts.d.ts +10 -1
  185. package/types/core/logic/shell/ui.d.ts +7 -1
  186. package/types/core/schema/context.d.ts +7 -1
  187. package/types/core/schema/frameContext.d.ts +36 -4
  188. package/types/core/schema/options.d.ts +83 -2
  189. package/types/core/section/constructor.d.ts +38 -1
  190. package/types/events.d.ts +208 -32
  191. package/types/helper/converter.d.ts +4 -2
  192. package/types/helper/dom/domCheck.d.ts +12 -2
  193. package/types/helper/dom/domQuery.d.ts +35 -7
  194. package/types/helper/dom/domUtils.d.ts +4 -1
  195. package/types/interfaces/plugins.d.ts +2 -2
  196. package/types/langs/_Lang.d.ts +0 -1
  197. package/types/modules/contract/ColorPicker.d.ts +2 -2
  198. package/types/modules/contract/Controller.d.ts +7 -0
  199. package/types/modules/contract/Figure.d.ts +31 -4
  200. package/types/modules/ui/CommandMenu.d.ts +262 -0
  201. package/types/modules/ui/SelectMenu.d.ts +56 -3
  202. package/types/modules/ui/index.d.ts +1 -0
  203. package/types/plugins/browser/audioGallery.d.ts +1 -1
  204. package/types/plugins/browser/fileBrowser.d.ts +1 -1
  205. package/types/plugins/browser/fileGallery.d.ts +1 -1
  206. package/types/plugins/browser/imageGallery.d.ts +1 -1
  207. package/types/plugins/browser/videoGallery.d.ts +1 -1
  208. package/types/plugins/dropdown/align.d.ts +1 -1
  209. package/types/plugins/dropdown/blockStyle.d.ts +3 -1
  210. package/types/plugins/dropdown/table/index.d.ts +4 -1
  211. package/types/plugins/dropdown/table/services/table.clipboard.d.ts +5 -1
  212. package/types/plugins/dropdown/table/services/table.grid.d.ts +10 -2
  213. package/types/plugins/field/autocomplete.d.ts +0 -1
  214. package/types/plugins/field/slashCommand.d.ts +165 -0
  215. package/types/plugins/index.d.ts +3 -0
  216. package/types/plugins/modal/link.d.ts +4 -1
  217. package/types/typedef.d.ts +48 -23
@@ -91,7 +91,12 @@ class Toolbar {
91
91
  const isStickyPosible = !this.isSub && !balloon && !inline;
92
92
  const stickyTop = this.#options.get('_toolbar_sticky');
93
93
 
94
- this.#useCSSSticky = isStickyPosible && stickyTop >= 0 && !this.#options.get('toolbar_container') && typeof CSS !== 'undefined' && CSS.supports('position', 'sticky');
94
+ this.#useCSSSticky =
95
+ isStickyPosible &&
96
+ stickyTop >= 0 &&
97
+ !this.#options.get('toolbar_container') &&
98
+ typeof CSS !== 'undefined' &&
99
+ CSS.supports('position', 'sticky');
95
100
 
96
101
  this.isBottomMode = this.#store.mode.isBottom;
97
102
 
@@ -153,14 +158,20 @@ class Toolbar {
153
158
  this._moreLayerOff();
154
159
  this.#$.menu.dropdownOff();
155
160
  this.#$.menu.containerOff();
156
- dom.utils.setDisabled(this.#context.get(this.keyName.buttonTray).querySelectorAll('.se-menu-list .se-toolbar-btn[data-type]'), true);
161
+ dom.utils.setDisabled(
162
+ this.#context.get(this.keyName.buttonTray).querySelectorAll('.se-menu-list .se-toolbar-btn[data-type]'),
163
+ true,
164
+ );
157
165
  }
158
166
 
159
167
  /**
160
168
  * @description Enables all toolbar buttons.
161
169
  */
162
170
  enable() {
163
- dom.utils.setDisabled(this.#context.get(this.keyName.buttonTray).querySelectorAll('.se-menu-list .se-toolbar-btn[data-type]'), false);
171
+ dom.utils.setDisabled(
172
+ this.#context.get(this.keyName.buttonTray).querySelectorAll('.se-menu-list .se-toolbar-btn[data-type]'),
173
+ false,
174
+ );
164
175
  }
165
176
 
166
177
  /**
@@ -208,7 +219,10 @@ class Toolbar {
208
219
  const responsiveSize = this.#rButtonsize;
209
220
  if (responsiveSize) {
210
221
  let w = 0;
211
- if (((this.isBalloonMode || this.isInlineMode) && this.#options.get('toolbar_width') === 'auto') || (this.#store.mode.isSubBalloon && this.#options.get('toolbar_sub_width') === 'auto')) {
222
+ if (
223
+ ((this.isBalloonMode || this.isInlineMode) && this.#options.get('toolbar_width') === 'auto') ||
224
+ (this.#store.mode.isSubBalloon && this.#options.get('toolbar_sub_width') === 'auto')
225
+ ) {
212
226
  w = this.#frameContext.get('topArea').offsetWidth;
213
227
  } else {
214
228
  w = this.#context.get(this.keyName.main).offsetWidth;
@@ -243,12 +257,17 @@ class Toolbar {
243
257
 
244
258
  newToolbar.updateButtons.forEach((v) => UpdateButton(v.button, v.plugin, this.#icons, this.#lang));
245
259
 
246
- this.#context.get(this.keyName.main).replaceChild(newToolbar.buttonTray, this.#context.get(this.keyName.buttonTray));
260
+ this.#context
261
+ .get(this.keyName.main)
262
+ .replaceChild(newToolbar.buttonTray, this.#context.get(this.keyName.buttonTray));
247
263
  this.#context.set(this.keyName.buttonTray, newToolbar.buttonTray);
248
264
 
249
265
  this.#resetButtonInfo();
250
266
 
251
- this.#eventManager.triggerEvent('onSetToolbarButtons', { buttonTray: newToolbar.buttonTray, frameContext: this.#frameContext });
267
+ this.#eventManager.triggerEvent('onSetToolbarButtons', {
268
+ buttonTray: newToolbar.buttonTray,
269
+ frameContext: this.#frameContext,
270
+ });
252
271
  }
253
272
 
254
273
  /**
@@ -280,7 +299,9 @@ class Toolbar {
280
299
  const editorBottom = editorOffset.top + editorHeight;
281
300
  const y = viewportBottom - stickyTop - (this.isInlineMode ? toolbar.offsetHeight : 0);
282
301
 
283
- const offSticky = !this.#options.get('toolbar_container') ? y - editorOffset.top - minHeight : viewportBottom - stickyTop - editorOffset.top - minHeight - toolbar.offsetHeight;
302
+ const offSticky = !this.#options.get('toolbar_container')
303
+ ? y - editorOffset.top - minHeight
304
+ : viewportBottom - stickyTop - editorOffset.top - minHeight - toolbar.offsetHeight;
284
305
  if (y > editorBottom) {
285
306
  this.#offSticky();
286
307
  } else if (offSticky < 0) {
@@ -292,9 +313,15 @@ class Toolbar {
292
313
  }
293
314
  } else {
294
315
  const y = currentScrollY + stickyTop;
295
- const t = (this.isBalloonMode || this.isInlineMode ? editorOffset.top : this.#$.offset.getGlobal(this.#options.get('toolbar_container')).top) - (this.isInlineMode ? toolbar.offsetHeight : 0);
296
-
297
- const offSticky = !this.#options.get('toolbar_container') ? editorHeight + t + stickyTop - y - minHeight : editorOffset.top - currentScrollY + editorHeight - minHeight - stickyTop - toolbar.offsetHeight;
316
+ const t =
317
+ (this.isBalloonMode || this.isInlineMode
318
+ ? editorOffset.top
319
+ : this.#$.offset.getGlobal(this.#options.get('toolbar_container')).top) -
320
+ (this.isInlineMode ? toolbar.offsetHeight : 0);
321
+
322
+ const offSticky = !this.#options.get('toolbar_container')
323
+ ? editorHeight + t + stickyTop - y - minHeight
324
+ : editorOffset.top - currentScrollY + editorHeight - minHeight - stickyTop - toolbar.offsetHeight;
298
325
  if (y < t) {
299
326
  this.#offSticky();
300
327
  } else if (offSticky < 0) {
@@ -372,12 +399,18 @@ class Toolbar {
372
399
  isDirTop = selection.focusOffset < selection.anchorOffset;
373
400
  } else {
374
401
  const childNodes = dom.query.getListChildNodes(range.commonAncestorContainer, null, null);
375
- isDirTop = dom.utils.getArrayIndex(childNodes, selection.focusNode) < dom.utils.getArrayIndex(childNodes, selection.anchorNode);
402
+ isDirTop =
403
+ dom.utils.getArrayIndex(childNodes, selection.focusNode) <
404
+ dom.utils.getArrayIndex(childNodes, selection.anchorNode);
376
405
  }
377
406
 
378
407
  this._setBalloonOffset(isDirTop, range);
379
408
 
380
- this.#eventManager.triggerEvent('onShowToolbar', { toolbar, mode: 'balloon', frameContext: this.#frameContext });
409
+ this.#eventManager.triggerEvent('onShowToolbar', {
410
+ toolbar,
411
+ mode: 'balloon',
412
+ frameContext: this.#frameContext,
413
+ });
381
414
  }
382
415
 
383
416
  /**
@@ -392,7 +425,12 @@ class Toolbar {
392
425
  const offsets = this.#$.offset.getGlobal(topArea);
393
426
  const stickyTop = offsets.top;
394
427
 
395
- if (!this.#$.offset.setRangePosition(toolbar, range, { position: positionTop ? 'top' : 'bottom', addTop: stickyTop })) {
428
+ if (
429
+ !this.#$.offset.setRangePosition(toolbar, range, {
430
+ position: positionTop ? 'top' : 'bottom',
431
+ addTop: stickyTop,
432
+ })
433
+ ) {
396
434
  this.hide();
397
435
  return;
398
436
  }
@@ -404,7 +442,10 @@ class Toolbar {
404
442
  let left = container.offsetLeft;
405
443
  let top = container.offsetTop;
406
444
 
407
- while (!container.parentElement.contains(editorParent) && !/^(BODY|HTML)$/i.test(container.parentElement.nodeName)) {
445
+ while (
446
+ !container.parentElement.contains(editorParent) &&
447
+ !/^(BODY|HTML)$/i.test(container.parentElement.nodeName)
448
+ ) {
408
449
  container = /** @type {HTMLElement} */ (container.offsetParent);
409
450
  left += container.offsetLeft;
410
451
  top += container.offsetTop;
@@ -438,9 +479,18 @@ class Toolbar {
438
479
  this.inlineToolbarAttr.width = toolbar.style.width = this.#options.get(this.keyName.width);
439
480
  if (this.isBottomMode) {
440
481
  const topArea = this.#frameContext.get('topArea');
441
- this.inlineToolbarAttr.top = toolbar.style.top = this.#$.offset.getGlobal(topArea).top + topArea.offsetHeight - this.#$.offset.getGlobal(toolbar).top + 'px';
482
+ this.inlineToolbarAttr.top = toolbar.style.top =
483
+ this.#$.offset.getGlobal(topArea).top +
484
+ topArea.offsetHeight -
485
+ this.#$.offset.getGlobal(toolbar).top +
486
+ 'px';
442
487
  } else {
443
- this.inlineToolbarAttr.top = toolbar.style.top = -1 + (this.#$.offset.getGlobal(this.#frameContext.get('topArea')).top - this.#$.offset.getGlobal(toolbar).top - toolbar.offsetHeight) + 'px';
488
+ this.inlineToolbarAttr.top = toolbar.style.top =
489
+ -1 +
490
+ (this.#$.offset.getGlobal(this.#frameContext.get('topArea')).top -
491
+ this.#$.offset.getGlobal(toolbar).top -
492
+ toolbar.offsetHeight) +
493
+ 'px';
444
494
  }
445
495
 
446
496
  this._resetSticky();
@@ -470,7 +520,9 @@ class Toolbar {
470
520
  _moreLayerOff() {
471
521
  if (this.currentMoreLayerActiveButton) {
472
522
  /** @type {HTMLElement} */
473
- const layer = this.#context.get(this.keyName.main).querySelector('.' + this.currentMoreLayerActiveButton.getAttribute('data-command'));
523
+ const layer = this.#context
524
+ .get(this.keyName.main)
525
+ .querySelector('.' + this.currentMoreLayerActiveButton.getAttribute('data-command'));
474
526
  layer.style.display = 'none';
475
527
  dom.utils.removeClass(this.currentMoreLayerActiveButton, 'on');
476
528
  this.currentMoreLayerActiveButton = null;
@@ -484,7 +536,9 @@ class Toolbar {
484
536
  const toolbar = this.#context.get(this.keyName.main);
485
537
 
486
538
  if (!this.isInlineMode) {
487
- const stickyDummy = !this.#options.get('toolbar_container') ? this.#frameContext.get('_stickyDummy') : this.#context.get('_stickyDummy');
539
+ const stickyDummy = !this.#options.get('toolbar_container')
540
+ ? this.#frameContext.get('_stickyDummy')
541
+ : this.#context.get('_stickyDummy');
488
542
  stickyDummy.style.height = toolbar.offsetHeight + 'px';
489
543
  stickyDummy.style.display = 'block';
490
544
  }
@@ -554,7 +608,9 @@ class Toolbar {
554
608
  * @description Disable `sticky` toolbar mode.
555
609
  */
556
610
  #offSticky() {
557
- const stickyDummy = !this.#options.get('toolbar_container') ? this.#frameContext.get('_stickyDummy') : this.#context.get('_stickyDummy');
611
+ const stickyDummy = !this.#options.get('toolbar_container')
612
+ ? this.#frameContext.get('_stickyDummy')
613
+ : this.#context.get('_stickyDummy');
558
614
  stickyDummy.style.display = 'none';
559
615
 
560
616
  const toolbar = this.#context.get(this.keyName.main);
@@ -128,7 +128,8 @@ class Viewer {
128
128
  codeWrapper.style.setProperty('display', 'none', 'important');
129
129
  wysiwygFrame.style.display = 'block';
130
130
 
131
- if (this.#frameOptions.get('height') === 'auto' && !this.#options.get('hasCodeMirror')) fc.get('code').style.height = '0px';
131
+ if (this.#frameOptions.get('height') === 'auto' && !this.#options.get('hasCodeMirror'))
132
+ fc.get('code').style.height = '0px';
132
133
 
133
134
  if (!fc.get('isFullScreen')) {
134
135
  this.#$.ui.preventToolbarHide(false);
@@ -200,7 +201,8 @@ class Viewer {
200
201
  if (fc.get('isFullScreen')) {
201
202
  markdownFrame.style.height = '100%';
202
203
  } else if (this.#frameOptions.get('height') === 'auto') {
203
- markdownFrame.style.height = markdownFrame.scrollHeight > 0 ? markdownFrame.scrollHeight + 'px' : 'auto';
204
+ markdownFrame.style.height =
205
+ markdownFrame.scrollHeight > 0 ? markdownFrame.scrollHeight + 'px' : 'auto';
204
206
  }
205
207
 
206
208
  if (!fc.get('isFullScreen')) {
@@ -294,7 +296,9 @@ class Viewer {
294
296
  const arrow = this.#context.get('toolbar_arrow');
295
297
 
296
298
  this.#$.ui.offCurrentController();
297
- const wasToolbarHidden = toolbar.style.display === 'none' || (this.#store.mode.isInline && !this.#$.toolbar.inlineToolbarAttr.isShow);
299
+ const wasToolbarHidden =
300
+ toolbar.style.display === 'none' ||
301
+ (this.#store.mode.isInline && !this.#$.toolbar.inlineToolbarAttr.isShow);
298
302
 
299
303
  if (value) {
300
304
  this.#originCssText = topArea.style.cssText;
@@ -341,18 +345,25 @@ class Viewer {
341
345
 
342
346
  // frame
343
347
  editorArea.style.cssText = toolbar.style.cssText = '';
344
- wysiwygFrame.style.cssText = (wysiwygFrame.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + this.#frameOptions.get('_defaultStyles').editor + (isCodeView || isMarkdownView ? 'display: none;' : '');
348
+ wysiwygFrame.style.cssText =
349
+ (wysiwygFrame.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] +
350
+ this.#frameOptions.get('_defaultStyles').editor +
351
+ (isCodeView || isMarkdownView ? 'display: none;' : '');
345
352
 
346
353
  // code wrapper
347
354
  if (codeWrapper) {
348
- codeWrapper.style.cssText = (codeWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
355
+ codeWrapper.style.cssText =
356
+ (codeWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] +
357
+ `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
349
358
  codeWrapper.style.overflow = 'auto';
350
359
  codeWrapper.style.height = '100%';
351
360
  }
352
361
 
353
362
  // markdown wrapper
354
363
  if (markdownWrapper) {
355
- markdownWrapper.style.cssText = (markdownWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
364
+ markdownWrapper.style.cssText =
365
+ (markdownWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] +
366
+ `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
356
367
  markdownWrapper.style.overflow = 'auto';
357
368
  markdownWrapper.style.height = '100%';
358
369
  }
@@ -367,7 +378,11 @@ class Viewer {
367
378
  toolbar.style.display = 'block';
368
379
 
369
380
  this.#fullScreenInnerHeight = _w.innerHeight - toolbar.offsetHeight;
370
- editorArea.style.height = this.#fullScreenInnerHeight - (fc.has('statusbar') ? fc.get('statusbar').offsetHeight : 0) - this.#options.get('fullScreenOffset') + 'px';
381
+ editorArea.style.height =
382
+ this.#fullScreenInnerHeight -
383
+ (fc.has('statusbar') ? fc.get('statusbar').offsetHeight : 0) -
384
+ this.#options.get('fullScreenOffset') +
385
+ 'px';
371
386
 
372
387
  if (this.#frameOptions.get('iframe') && this.#frameOptions.get('height') === 'auto') {
373
388
  editorArea.style.overflow = 'auto';
@@ -383,11 +398,15 @@ class Viewer {
383
398
  });
384
399
  } else {
385
400
  // frame
386
- wysiwygFrame.style.cssText = this.#wysiwygOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + (isCodeView || isMarkdownView ? 'display: none;' : '');
401
+ wysiwygFrame.style.cssText =
402
+ this.#wysiwygOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') +
403
+ (isCodeView || isMarkdownView ? 'display: none;' : '');
387
404
 
388
405
  // code wrapper
389
406
  if (codeWrapper) {
390
- codeWrapper.style.cssText = this.#codeWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
407
+ codeWrapper.style.cssText =
408
+ this.#codeWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') +
409
+ `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
391
410
  }
392
411
 
393
412
  // code
@@ -396,7 +415,9 @@ class Viewer {
396
415
 
397
416
  // markdown wrapper
398
417
  if (markdownWrapper) {
399
- markdownWrapper.style.cssText = this.#markdownWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
418
+ markdownWrapper.style.cssText =
419
+ this.#markdownWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') +
420
+ `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
400
421
  }
401
422
  if (markdownFrame) markdownFrame.style.cssText = this.#markdownOriginCssText;
402
423
  if (markdownNumbers) markdownNumbers.style.cssText = this.#markdownNumberOriginCssText;
@@ -408,7 +429,8 @@ class Viewer {
408
429
  if (arrow) arrow.style.cssText = this.#arrowOriginCssText;
409
430
  _d.body.style.overflow = this.#bodyOverflow;
410
431
 
411
- if (this.#frameOptions.get('height') === 'auto' && !this.#options.get('hasCodeMirror')) this._codeViewAutoHeight(fc.get('code'), fc.get('codeNumbers'), true);
432
+ if (this.#frameOptions.get('height') === 'auto' && !this.#options.get('hasCodeMirror'))
433
+ this._codeViewAutoHeight(fc.get('code'), fc.get('codeNumbers'), true);
412
434
 
413
435
  if (this.#toolbarParent) {
414
436
  this.#toolbarParent.appendChild(toolbar);
@@ -522,7 +544,9 @@ class Viewer {
522
544
  _d.body.appendChild(iframe);
523
545
 
524
546
  const innerPadding = _w.getComputedStyle(this.#frameContext.get('wysiwyg')).padding;
525
- const contentHTML = this.#options.get('printTemplate') ? this.#options.get('printTemplate').replace(/\{\{\s*contents\s*\}\}/i, this.#$.html.get()) : this.#$.html.get();
547
+ const contentHTML = this.#options.get('printTemplate')
548
+ ? this.#options.get('printTemplate').replace(/\{\{\s*contents\s*\}\}/i, this.#$.html.get())
549
+ : this.#$.html.get();
526
550
  const printDocument = dom.query.getIframeDocument(iframe);
527
551
  const wDoc = this.#frameContext.get('_wd');
528
552
  const rtlClass = this.#options.get('_rtl') ? ' se-rtl' : '';
@@ -613,7 +637,11 @@ class Viewer {
613
637
  this.#$.ui.offCurrentController();
614
638
  this.#$.ui.offCurrentModal();
615
639
 
616
- const contentHTML = this.#options.get('previewTemplate') ? this.#options.get('previewTemplate').replace(/\{\{\s*contents\s*\}\}/i, this.#$.html.get({ withFrame: true })) : this.#$.html.get({ withFrame: true });
640
+ const contentHTML = this.#options.get('previewTemplate')
641
+ ? this.#options
642
+ .get('previewTemplate')
643
+ .replace(/\{\{\s*contents\s*\}\}/i, this.#$.html.get({ withFrame: true }))
644
+ : this.#$.html.get({ withFrame: true });
617
645
  const windowObject = _w.open('', '_blank');
618
646
  const wDoc = this.#frameContext.get('_wd');
619
647
  const rtlClass = this.#options.get('_rtl') ? ' se-rtl' : '';
@@ -670,7 +698,11 @@ class Viewer {
670
698
  */
671
699
  _resetFullScreenHeight() {
672
700
  if (this.#frameContext.get('isFullScreen')) {
673
- this.#fullScreenInnerHeight += _w.innerHeight - this.#context.get('toolbar_main').offsetHeight - (this.#frameContext.has('statusbar') ? this.#frameContext.get('statusbar').offsetHeight : 0) - this.#fullScreenInnerHeight;
701
+ this.#fullScreenInnerHeight +=
702
+ _w.innerHeight -
703
+ this.#context.get('toolbar_main').offsetHeight -
704
+ (this.#frameContext.has('statusbar') ? this.#frameContext.get('statusbar').offsetHeight : 0) -
705
+ this.#fullScreenInnerHeight;
674
706
  this.#frameContext.get('wrapper').style.height = this.#fullScreenInnerHeight + 'px';
675
707
  return true;
676
708
  }
@@ -795,12 +827,22 @@ class Viewer {
795
827
  }
796
828
 
797
829
  let headers = parseDocument.head.innerHTML;
798
- if (!parseDocument.head.querySelector('link[rel="stylesheet"]') || (this.#frameOptions.get('height') === 'auto' && !parseDocument.head.querySelector('style'))) {
799
- headers += converter._setIframeStyleLinks(this.#frameOptions.get('iframe_cssFileName')) + converter._setAutoHeightStyle(this.#frameOptions.get('height'));
830
+ if (
831
+ !parseDocument.head.querySelector('link[rel="stylesheet"]') ||
832
+ (this.#frameOptions.get('height') === 'auto' && !parseDocument.head.querySelector('style'))
833
+ ) {
834
+ headers +=
835
+ converter._setIframeStyleLinks(this.#frameOptions.get('iframe_cssFileName')) +
836
+ converter._setAutoHeightStyle(this.#frameOptions.get('height'));
800
837
  }
801
838
 
802
839
  wDoc.head.innerHTML = headers;
803
- wDoc.body.innerHTML = this.#$.html.clean(parseDocument.body.innerHTML, { forceFormat: true, whitelist: null, blacklist: null, _freeCodeViewMode: this.#options.get('freeCodeViewMode') });
840
+ wDoc.body.innerHTML = this.#$.html.clean(parseDocument.body.innerHTML, {
841
+ forceFormat: true,
842
+ whitelist: null,
843
+ blacklist: null,
844
+ _freeCodeViewMode: this.#options.get('freeCodeViewMode'),
845
+ });
804
846
 
805
847
  const attrs = parseDocument.body.attributes;
806
848
  for (let i = 0, len = attrs.length; i < len; i++) {
@@ -816,7 +858,12 @@ class Viewer {
816
858
  } else {
817
859
  this.#frameContext.get('wysiwyg').innerHTML =
818
860
  code_html.length > 0
819
- ? this.#$.html.clean(code_html, { forceFormat: true, whitelist: null, blacklist: null, _freeCodeViewMode: this.#options.get('freeCodeViewMode') })
861
+ ? this.#$.html.clean(code_html, {
862
+ forceFormat: true,
863
+ whitelist: null,
864
+ blacklist: null,
865
+ _freeCodeViewMode: this.#options.get('freeCodeViewMode'),
866
+ })
820
867
  : '<' + this.#options.get('defaultLine') + '><br></' + this.#options.get('defaultLine') + '>';
821
868
  }
822
869
  }
@@ -830,7 +877,14 @@ class Viewer {
830
877
 
831
878
  if (this.#frameOptions.get('iframe_fullPage')) {
832
879
  const attrs = dom.utils.getAttributesToString(this.#frameContext.get('_wd').body, null);
833
- codeValue = '<!DOCTYPE html>\n<html>\n' + this.#frameContext.get('_wd').head.outerHTML.replace(/>(?!\n)/g, '>\n') + '<body ' + attrs + '>\n' + codeContent + '</body>\n</html>';
880
+ codeValue =
881
+ '<!DOCTYPE html>\n<html>\n' +
882
+ this.#frameContext.get('_wd').head.outerHTML.replace(/>(?!\n)/g, '>\n') +
883
+ '<body ' +
884
+ attrs +
885
+ '>\n' +
886
+ codeContent +
887
+ '</body>\n</html>';
834
888
  } else {
835
889
  codeValue = codeContent;
836
890
  }
@@ -855,7 +909,9 @@ class Viewer {
855
909
  const html = markdown.markdownToHtml(md, this.#options.get('defaultLine'));
856
910
 
857
911
  this.#frameContext.get('wysiwyg').innerHTML =
858
- html.length > 0 ? this.#$.html.clean(html, { forceFormat: true, whitelist: null, blacklist: null }) : '<' + this.#options.get('defaultLine') + '><br></' + this.#options.get('defaultLine') + '>';
912
+ html.length > 0
913
+ ? this.#$.html.clean(html, { forceFormat: true, whitelist: null, blacklist: null })
914
+ : '<' + this.#options.get('defaultLine') + '><br></' + this.#options.get('defaultLine') + '>';
859
915
  }
860
916
 
861
917
  /**
@@ -59,7 +59,13 @@ export default class CommandExecutor {
59
59
  * @description Execute default command of command button
60
60
  */
61
61
  async execute(command, button) {
62
- if (this.#frameContext.get('isReadOnly') && !/copy|cut|selectAll|selectAll_full|codeView|markdownView|fullScreen|print|preview|showBlocks|finder/.test(command)) return;
62
+ if (
63
+ this.#frameContext.get('isReadOnly') &&
64
+ !/copy|cut|selectAll|selectAll_full|codeView|markdownView|fullScreen|print|preview|showBlocks|finder/.test(
65
+ command,
66
+ )
67
+ )
68
+ return;
63
69
 
64
70
  switch (command) {
65
71
  case 'selectAll':
@@ -162,7 +168,11 @@ export default class CommandExecutor {
162
168
  this.#$.inline.remove();
163
169
 
164
170
  if (n) {
165
- const insertedNode = this.#$.inline.apply(n, { stylesToModify: null, nodesToRemove: [n.nodeName], strictRemove: false });
171
+ const insertedNode = this.#$.inline.apply(n, {
172
+ stylesToModify: null,
173
+ nodesToRemove: [n.nodeName],
174
+ strictRemove: false,
175
+ });
166
176
  const { parent, inner } = this.#$.nodeTransform.createNestedNode(_styleNode);
167
177
  insertedNode.parentNode.insertBefore(parent, insertedNode);
168
178
  inner.appendChild(insertedNode);
@@ -200,14 +210,25 @@ export default class CommandExecutor {
200
210
  let commonNodeName = (prevScopeTagName = commonNode.nodeName?.toLowerCase());
201
211
  if (range.startOffset === 0 && range.endOffset === range.endContainer.textContent?.length) {
202
212
  const commonParent = commonNode.parentElement;
203
- if ((dom.check.isList(commonParent) || dom.check.isListCell(commonParent)) && commonParent.firstChild.contains?.(range.startContainer) && commonParent.lastChild?.contains(range.endContainer)) {
213
+ if (
214
+ (dom.check.isList(commonParent) || dom.check.isListCell(commonParent)) &&
215
+ commonParent.firstChild.contains?.(range.startContainer) &&
216
+ commonParent.lastChild?.contains(range.endContainer)
217
+ ) {
204
218
  prevScopeTag = commonNode = commonParent.parentElement;
205
219
  prevScopeTagName = commonNode.nodeName?.toLowerCase();
206
220
  }
207
221
  }
208
222
 
209
223
  commonNodeName = commonNode.nodeName?.toLowerCase();
210
- while (commonNode && ((!commonNode.nextSibling && !commonNode.previousSibling && !scopeSelectionTags.includes(commonNodeName)) || dom.check.isContentLess(commonNodeName)) && commonNode !== ww) {
224
+ while (
225
+ commonNode &&
226
+ ((!commonNode.nextSibling &&
227
+ !commonNode.previousSibling &&
228
+ !scopeSelectionTags.includes(commonNodeName)) ||
229
+ dom.check.isContentLess(commonNodeName)) &&
230
+ commonNode !== ww
231
+ ) {
211
232
  commonNode = commonNode.parentElement;
212
233
  commonNodeName = commonNode.nodeName?.toLowerCase();
213
234
  }
@@ -220,7 +241,9 @@ export default class CommandExecutor {
220
241
 
221
242
  // select all
222
243
  const scopeTagList = scopeSelectionTags.filter((tagName) => tagName !== prevScopeTagName);
223
- const scopeBaseTag = dom.query.getParentElement(prevScopeTag || this.#$.selection.getNode(), (current) => scopeTagList.includes(current.nodeName?.toLowerCase()));
244
+ const scopeBaseTag = dom.query.getParentElement(prevScopeTag || this.#$.selection.getNode(), (current) =>
245
+ scopeTagList.includes(current.nodeName?.toLowerCase()),
246
+ );
224
247
 
225
248
  let selectArea = scopeBaseTag || ww;
226
249
  let { first, last } = __findFirstAndLast(selectArea);
@@ -230,7 +253,11 @@ export default class CommandExecutor {
230
253
  const isZeroWidth = dom.check.isZeroWidth;
231
254
  while (isZeroWidth(first) && isZeroWidth(last) && selectArea !== ww) {
232
255
  selectArea = selectArea.parentElement;
233
- ({ first, last } = __findFirstAndLast(dom.query.getParentElement(selectArea, (current) => scopeTagList.includes(current.nodeName?.toLowerCase())) || ww));
256
+ ({ first, last } = __findFirstAndLast(
257
+ dom.query.getParentElement(selectArea, (current) =>
258
+ scopeTagList.includes(current.nodeName?.toLowerCase()),
259
+ ) || ww,
260
+ ));
234
261
  }
235
262
 
236
263
  if (!first || !last) return;
@@ -371,7 +398,9 @@ export default class CommandExecutor {
371
398
  command = this.#options.get('_defaultTagCommand')[command.toLowerCase()] || command;
372
399
  let nodeName = this.#options.get('convertTextTags')[command] || command;
373
400
  const nodesMap = this.#store.get('currentNodesMap');
374
- const el = nodesMap.includes(this.#options.get('_styleCommandMap')[nodeName]) ? null : dom.utils.createElement(nodeName);
401
+ const el = nodesMap.includes(this.#options.get('_styleCommandMap')[nodeName])
402
+ ? null
403
+ : dom.utils.createElement(nodeName);
375
404
 
376
405
  if (/^sub$/i.test(nodeName) && nodesMap.includes('superscript')) {
377
406
  nodeName = 'sup';
@@ -379,7 +408,11 @@ export default class CommandExecutor {
379
408
  nodeName = 'sub';
380
409
  }
381
410
 
382
- this.#$.inline.apply(el, { stylesToModify: StyleMap[command] || null, nodesToRemove: [nodeName], strictRemove: false });
411
+ this.#$.inline.apply(el, {
412
+ stylesToModify: StyleMap[command] || null,
413
+ nodesToRemove: [nodeName],
414
+ strictRemove: false,
415
+ });
383
416
  this.#$.focusManager.focus();
384
417
  }
385
418
 
@@ -387,7 +420,9 @@ export default class CommandExecutor {
387
420
  * @description Inserts a page break element into the editor.
388
421
  */
389
422
  #PAGE_BREAK() {
390
- const pageBreak = dom.utils.createElement('DIV', { class: 'se-component se-component-line-break se-page-break' });
423
+ const pageBreak = dom.utils.createElement('DIV', {
424
+ class: 'se-component se-component-line-break se-page-break',
425
+ });
391
426
  this.#$.component.insert(pageBreak, { skipCharCount: true, insertBehavior: 'line' });
392
427
  const line = pageBreak.nextElementSibling || this.#$.format.addLine(pageBreak);
393
428
  this.#$.selection.setRange(line, 1, line, 1);
@@ -9,14 +9,35 @@ export const COMMAND_BUTTONS = '.se-menu-list .se-toolbar-btn[data-command]';
9
9
  * - These commands typically apply inline formatting or structural changes.
10
10
  * @constant {string[]}
11
11
  */
12
- const ACTIVE_EVENT_COMMANDS = ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript', 'indent', 'outdent'];
12
+ const ACTIVE_EVENT_COMMANDS = [
13
+ 'bold',
14
+ 'underline',
15
+ 'italic',
16
+ 'strike',
17
+ 'subscript',
18
+ 'superscript',
19
+ 'indent',
20
+ 'outdent',
21
+ ];
13
22
 
14
23
  /**
15
24
  * @description List of basic editor commands, including active event commands and additional actions
16
25
  * - such as undo, redo, saving, full-screen toggle, and text direction commands.
17
26
  * @constant {string[]}
18
27
  */
19
- const BASIC_COMMANDS = ACTIVE_EVENT_COMMANDS.concat(['undo', 'redo', 'save', 'fullScreen', 'showBlocks', 'codeView', 'markdownView', 'finder', 'dir', 'dir_ltr', 'dir_rtl']);
28
+ const BASIC_COMMANDS = ACTIVE_EVENT_COMMANDS.concat([
29
+ 'undo',
30
+ 'redo',
31
+ 'save',
32
+ 'fullScreen',
33
+ 'showBlocks',
34
+ 'codeView',
35
+ 'markdownView',
36
+ 'finder',
37
+ 'dir',
38
+ 'dir_ltr',
39
+ 'dir_rtl',
40
+ ]);
20
41
 
21
42
  /**
22
43
  * @description Routes toolbar button commands to their handlers and manages active button states.
@@ -103,14 +124,20 @@ export default class CommandDispatcher {
103
124
  return;
104
125
  }
105
126
 
106
- if (/container/.test(type) && (this.#$.menu.targetMap[command] === null || button !== this.#$.menu.currentContainerActiveButton)) {
127
+ if (
128
+ /container/.test(type) &&
129
+ (this.#$.menu.targetMap[command] === null || button !== this.#$.menu.currentContainerActiveButton)
130
+ ) {
107
131
  this.#$.menu.containerOn(button);
108
132
  return;
109
133
  }
110
134
 
111
135
  if (this.#$.ui.isButtonDisabled(button)) return;
112
136
 
113
- if (/dropdown/.test(type) && (this.#$.menu.targetMap[command] === null || button !== this.#$.menu.currentDropdownActiveButton)) {
137
+ if (
138
+ /dropdown/.test(type) &&
139
+ (this.#$.menu.targetMap[command] === null || button !== this.#$.menu.currentDropdownActiveButton)
140
+ ) {
114
141
  this.#$.menu.dropdownOn(button);
115
142
  return;
116
143
  } else if (/modal/.test(type)) {
@@ -184,6 +211,21 @@ export default class CommandDispatcher {
184
211
  }
185
212
  }
186
213
 
214
+ /**
215
+ * @description Inverse of {@link registerTargets}. Removes a previously registered target so
216
+ * ephemeral participants (e.g. CommandMenu rows) can opt out of the active-state pass on close.
217
+ * Drops the command entry when its target array empties.
218
+ * @param {string} cmd - The command identifier.
219
+ * @param {HTMLElement} target - The target previously registered.
220
+ */
221
+ unregisterTargets(cmd, target) {
222
+ const arr = this.#commandTargets.get(cmd);
223
+ if (!arr) return;
224
+ const i = arr.indexOf(/** @type {HTMLButtonElement} */ (target));
225
+ if (i !== -1) arr.splice(i, 1);
226
+ if (arr.length === 0) this.#commandTargets.delete(cmd);
227
+ }
228
+
187
229
  resetTargets() {
188
230
  this.#commandTargets = new Map();
189
231
  this._initCommandButtons();