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
@@ -83,7 +83,10 @@ class Selection_ {
83
83
  getRange() {
84
84
  const range = this.#store.get('_range') || this.#createDefaultRange();
85
85
  const selection = this.get();
86
- if (range.collapsed === selection.isCollapsed || !this.#frameContext.get('wysiwyg').contains(selection.focusNode)) {
86
+ if (
87
+ range.collapsed === selection.isCollapsed ||
88
+ !this.#frameContext.get('wysiwyg').contains(selection.focusNode)
89
+ ) {
87
90
  if (this.#$.component.is(range.startContainer)) {
88
91
  const compInfo = this.#$.component.get(range.startContainer);
89
92
  const container = compInfo?.container;
@@ -104,7 +107,9 @@ class Selection_ {
104
107
  so = selection.anchorOffset,
105
108
  eo = selection.focusOffset;
106
109
  const compareValue = dom.query.compareElements(sc, ec);
107
- const rightDir = compareValue.ancestor && (compareValue.result === 0 ? so <= eo : compareValue.result > 1 ? true : false);
110
+ const rightDir =
111
+ compareValue.ancestor &&
112
+ (compareValue.result === 0 ? so <= eo : compareValue.result > 1 ? true : false);
108
113
  return this.setRange(rightDir ? sc : ec, rightDir ? so : eo, rightDir ? ec : sc, rightDir ? eo : so);
109
114
  }
110
115
  }
@@ -157,18 +162,35 @@ class Selection_ {
157
162
  if ((dom.check.isBreak(ec) || ec.nodeType === 3) && eo > ec.textContent.length) eo = ec.textContent.length;
158
163
  if (this.#$.format.isLine(sc)) {
159
164
  sc = sc.childNodes[so > 0 ? sc.childNodes.length - 1 : 0] || sc;
160
- so = so > 0 ? (sc.nodeType === 1 && !dom.check.isBreak(sc) ? 1 : sc.textContent ? sc.textContent.length : 0) : 0;
165
+ so =
166
+ so > 0
167
+ ? sc.nodeType === 1 && !dom.check.isBreak(sc)
168
+ ? 1
169
+ : sc.textContent
170
+ ? sc.textContent.length
171
+ : 0
172
+ : 0;
161
173
  }
162
174
  if (this.#$.format.isLine(ec)) {
163
175
  ec = ec.childNodes[eo > 0 ? ec.childNodes.length - 1 : 0] || ec;
164
- eo = eo > 0 ? (ec.nodeType === 1 && !dom.check.isBreak(ec) ? 1 : ec.textContent ? ec.textContent.length : 0) : 0;
176
+ eo =
177
+ eo > 0
178
+ ? ec.nodeType === 1 && !dom.check.isBreak(ec)
179
+ ? 1
180
+ : ec.textContent
181
+ ? ec.textContent.length
182
+ : 0
183
+ : 0;
165
184
  }
166
185
 
167
186
  const range = this.#frameContext.get('_wd').createRange();
168
187
 
169
188
  try {
170
189
  so = Math.min(so, sc.textContent?.length || 0);
171
- eo = eo > 0 && (ec.textContent?.length || 0) === 0 && ec.nodeType === 1 ? 1 : Math.min(Math.max(eo, 0), ec.textContent?.length || 0);
190
+ eo =
191
+ eo > 0 && (ec.textContent?.length || 0) === 0 && ec.nodeType === 1
192
+ ? 1
193
+ : Math.min(Math.max(eo, 0), ec.textContent?.length || 0);
172
194
  range.setStart(sc, so);
173
195
  range.setEnd(ec, eo);
174
196
  this.#store.set('hasFocus', true);
@@ -242,7 +264,14 @@ class Selection_ {
242
264
  if (this.#isNone(range)) {
243
265
  const parent = container?.parentElement || this.#frameContext.get('wysiwyg');
244
266
  const op = dom.utils.createElement(this.#options.get('defaultLine'), null, '<br>');
245
- parent.insertBefore(op, container && container !== parent ? (!(/** @type {HTMLElement} */ (container).previousElementSibling) ? container : /** @type {HTMLElement} */ (container).nextElementSibling) : parent.firstElementChild);
267
+ parent.insertBefore(
268
+ op,
269
+ container && container !== parent
270
+ ? !(/** @type {HTMLElement} */ (container).previousElementSibling)
271
+ ? container
272
+ : /** @type {HTMLElement} */ (container).nextElementSibling
273
+ : parent.firstElementChild,
274
+ );
246
275
  this.setRange(op.firstElementChild, 0, op.firstElementChild, 1);
247
276
  range = this.#store.get('_range');
248
277
  }
@@ -259,7 +288,13 @@ class Selection_ {
259
288
  getNode() {
260
289
  if (!this.#frameContext.get('wysiwyg').contains(this.selectionNode)) this.init();
261
290
  if (!this.selectionNode) {
262
- const selectionNode = /** @type {HTMLElement|Text} */ (dom.query.getEdgeChild(this.#frameContext.get('wysiwyg').firstChild, (current) => current.childNodes.length === 0 || current.nodeType === 3, false));
291
+ const selectionNode = /** @type {HTMLElement|Text} */ (
292
+ dom.query.getEdgeChild(
293
+ this.#frameContext.get('wysiwyg').firstChild,
294
+ (current) => current.childNodes.length === 0 || current.nodeType === 3,
295
+ false,
296
+ )
297
+ );
263
298
  if (!selectionNode) {
264
299
  this.init();
265
300
  } else {
@@ -290,8 +325,12 @@ class Selection_ {
290
325
  * tooltip.style.top = rects.top + 'px';
291
326
  */
292
327
  getRects(target, position) {
293
- const targetAbs = dom.check.isElement(/** @type {Node} */ (target)) ? _w.getComputedStyle(target).position === 'absolute' : false;
294
- target = /** @type {Range} */ (!target || dom.check.isText(/** @type {Node} */ (target)) ? this.getRange() : target);
328
+ const targetAbs = dom.check.isElement(/** @type {Node} */ (target))
329
+ ? _w.getComputedStyle(target).position === 'absolute'
330
+ : false;
331
+ target = /** @type {Range} */ (
332
+ !target || dom.check.isText(/** @type {Node} */ (target)) ? this.getRange() : target
333
+ );
295
334
  let isStartPosition = position === 'start';
296
335
  let scrollLeft = _w.scrollX;
297
336
  let scrollTop = _w.scrollY;
@@ -326,7 +365,9 @@ class Selection_ {
326
365
  isStartPosition = true;
327
366
  }
328
367
 
329
- const iframeRects = /^iframe$/i.test(this.#frameContext.get('wysiwygFrame').nodeName) ? this.#frameContext.get('wysiwygFrame').getClientRects()[0] : null;
368
+ const iframeRects = /^iframe$/i.test(this.#frameContext.get('wysiwygFrame').nodeName)
369
+ ? this.#frameContext.get('wysiwygFrame').getClientRects()[0]
370
+ : null;
330
371
  if (!targetAbs && iframeRects) {
331
372
  rects = {
332
373
  left: rects.left + iframeRects.left,
@@ -407,7 +448,10 @@ class Selection_ {
407
448
  ref = this.setRange(ref, 1, ref, 1);
408
449
  }
409
450
  } else if (typeof ref?.startContainer === 'undefined') {
410
- console.warn('[SUNEDITOR.html.scrollTo.warn] "selectionRange" must be Selection or Range or Node object.', ref);
451
+ console.warn(
452
+ '[SUNEDITOR.html.scrollTo.warn] "selectionRange" must be Selection or Range or Node object.',
453
+ ref,
454
+ );
411
455
  }
412
456
 
413
457
  const el = dom.query.getParentElement(ref?.startContainer, (current) => current.nodeType === 1);
@@ -425,11 +469,18 @@ class Selection_ {
425
469
  const isBottom = this.#store.mode.isBottom;
426
470
  const realToolbarHeight = this.#context.get('toolbar_main').offsetHeight;
427
471
  const toolbarHeight = this.#$.toolbar.isSticky ? realToolbarHeight : 0;
428
- const positionToolbarHeight = this.#$.toolbar.isSticky ? toolbarHeight + this.#options.get('_toolbar_sticky') : toolbarHeight;
472
+ const positionToolbarHeight = this.#$.toolbar.isSticky
473
+ ? toolbarHeight + this.#options.get('_toolbar_sticky')
474
+ : toolbarHeight;
429
475
  const statusbarHeight = this.#frameContext.get('statusbar')?.offsetHeight || 0;
430
476
 
431
477
  if (this.#hasScrollParents) {
432
- el?.scrollIntoView(scrollOption);
478
+ const caretRect = this.#$.format.isBrLine(el) ? ref?.getBoundingClientRect?.() : null;
479
+ if (caretRect?.height > 0) {
480
+ this.#scrollCaretIntoView(caretRect, scrollOption.behavior);
481
+ } else {
482
+ el?.scrollIntoView(scrollOption);
483
+ }
433
484
 
434
485
  if (scrollOption?.behavior === 'auto' && scrollY !== _w.scrollY) {
435
486
  if (positionToolbarHeight) {
@@ -455,7 +506,9 @@ class Selection_ {
455
506
  // --- When there is no upper scroll and it is an iframe ---
456
507
  const PADDING = this.#scrollMargin;
457
508
  // Reduce effective viewport height by toolbar+offset when bottom toolbar is sticky
458
- const viewHeight = isAutoHeight ? viewportHeight - (isBottom ? positionToolbarHeight : 0) : wwFrame.offsetHeight;
509
+ const viewHeight = isAutoHeight
510
+ ? viewportHeight - (isBottom ? positionToolbarHeight : 0)
511
+ : wwFrame.offsetHeight;
459
512
 
460
513
  // Use range rect for accurate height — el.offsetHeight includes nested children (e.g. nested lists)
461
514
  const refRect = ref?.getBoundingClientRect?.();
@@ -476,12 +529,15 @@ class Selection_ {
476
529
  behavior,
477
530
  });
478
531
  } else {
479
- const rect = this.#$.offset.getGlobal(el);
480
- const scrollMargin = viewHeight + scrollY - rect.top - elH;
532
+ const rectTop = refRect?.height > 0 ? refRect.top + scrollY : this.#$.offset.getGlobal(el).top;
533
+ const scrollMargin = viewHeight + scrollY - rectTop - elH;
481
534
 
482
535
  if (scrollMargin - PADDING > 0 && viewHeight > scrollMargin + PADDING + topToolbarH) return;
483
536
 
484
- const newScrollTop = scrollMargin <= PADDING ? scrollY - scrollMargin + PADDING + statusbarHeight : scrollY - scrollMargin + (viewHeight - elH - PADDING);
537
+ const newScrollTop =
538
+ scrollMargin <= PADDING
539
+ ? scrollY - scrollMargin + PADDING + statusbarHeight
540
+ : scrollY - scrollMargin + (viewHeight - elH - PADDING);
485
541
  _w.scrollTo({
486
542
  top: newScrollTop < scrollY ? newScrollTop - topToolbarH : newScrollTop,
487
543
  behavior,
@@ -493,8 +549,15 @@ class Selection_ {
493
549
  const targetTop = hasRefRect ? refRect.top : el.getBoundingClientRect().top;
494
550
  const innerTop = isIframe ? targetTop : targetTop - wwFrame.getBoundingClientRect().top;
495
551
 
496
- const keepLocalScroll = innerTop - PADDING > 0 && innerTop + PADDING <= viewHeight;
497
- const rectScroll = isBottom ? (innerTop - PADDING > 0 ? innerTop + PADDING - viewHeight + toolbarHeight : innerTop - elH) : innerTop - PADDING > 0 ? innerTop + PADDING - viewHeight : innerTop - (toolbarHeight + elH);
552
+ const topSafe = isBottom ? 0 : toolbarHeight;
553
+ const keepLocalScroll = innerTop >= topSafe && innerTop + PADDING <= viewHeight;
554
+ const rectScroll = isBottom
555
+ ? innerTop - PADDING > 0
556
+ ? innerTop + PADDING - viewHeight + toolbarHeight
557
+ : innerTop - elH
558
+ : innerTop - PADDING > 0
559
+ ? innerTop + PADDING - viewHeight
560
+ : innerTop - (toolbarHeight + elH);
498
561
  let newScrollTop = scrollY + rectScroll;
499
562
 
500
563
  // frame scroll
@@ -507,7 +570,8 @@ class Selection_ {
507
570
 
508
571
  // set frame scroll
509
572
  if (topMargin > 0) {
510
- const newFrameY = (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) - elH - PADDING - topMargin;
573
+ const newFrameY =
574
+ (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) - elH - PADDING - topMargin;
511
575
  if (newFrameY < 0) {
512
576
  newScrollTop += topToolbarFrame;
513
577
  _w.scrollTo({
@@ -517,7 +581,11 @@ class Selection_ {
517
581
  }
518
582
  }
519
583
  if (bottomMargin > 0) {
520
- const newFrameY = (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) + elH + PADDING - (globalRect.height - bottomMargin);
584
+ const newFrameY =
585
+ (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) +
586
+ elH +
587
+ PADDING -
588
+ (globalRect.height - bottomMargin);
521
589
  if (newFrameY > 0) {
522
590
  newScrollTop += isBottom ? bottomToolbarFrame : statusbarHeight;
523
591
  _w.scrollTo({
@@ -537,6 +605,34 @@ class Selection_ {
537
605
  }
538
606
  }
539
607
 
608
+ /**
609
+ * @description Scroll the caret rect into view across all scroll-parents (and the window), non-destructively.
610
+ * @param {DOMRect} caretRect Caret rect in viewport coordinates (`range.getBoundingClientRect()`).
611
+ * @param {ScrollBehavior} [behavior] Scroll behavior.
612
+ */
613
+ #scrollCaretIntoView(caretRect, behavior) {
614
+ let { top, bottom } = caretRect;
615
+ const containers = [...(this.#kernel._eventOrchestrator.scrollparents || []), _w];
616
+
617
+ for (const container of containers) {
618
+ const isWindow = container === _w;
619
+ const viewTop = isWindow ? 0 : /** @type {HTMLElement} */ (container).getBoundingClientRect().top;
620
+ const viewBottom = isWindow
621
+ ? this.#store.get('currentViewportHeight')
622
+ : /** @type {HTMLElement} */ (container).getBoundingClientRect().bottom;
623
+
624
+ let delta = 0;
625
+ if (top < viewTop) delta = top - viewTop;
626
+ else if (bottom > viewBottom) delta = bottom - viewBottom;
627
+ if (delta === 0) continue;
628
+
629
+ container.scrollBy({ top: delta, behavior });
630
+
631
+ top -= delta;
632
+ bottom -= delta;
633
+ }
634
+ }
635
+
540
636
  /**
541
637
  * @description Normalizes and resets the selection range to properly target text nodes instead of element nodes for accurate text editing.
542
638
  * @returns {boolean} Returns `false` if there is no valid selection.
@@ -544,7 +640,8 @@ class Selection_ {
544
640
  resetRangeToTextNode() {
545
641
  let rangeObj = this.getRange();
546
642
  if (this.#isNone(rangeObj)) {
547
- if (!dom.check.isWysiwygFrame(rangeObj.startContainer) || !dom.check.isWysiwygFrame(rangeObj.endContainer)) return false;
643
+ if (!dom.check.isWysiwygFrame(rangeObj.startContainer) || !dom.check.isWysiwygFrame(rangeObj.endContainer))
644
+ return false;
548
645
  const ww = /** @type {HTMLElement} */ (rangeObj.commonAncestorContainer);
549
646
  const first = ww.children[rangeObj.startOffset];
550
647
  const end = ww.children[rangeObj.endOffset];
@@ -593,14 +690,23 @@ class Selection_ {
593
690
  tempChild = tempCon.childNodes;
594
691
  if (tempChild.length === 0) break;
595
692
  tempCon =
596
- tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : /** @type {HTMLElement} */ (tempCon).previousElementSibling || tempCon.previousSibling || startCon;
693
+ tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] ||
694
+ !/FIGURE/i.test(tempChild[0].nodeName)
695
+ ? tempChild[0]
696
+ : /** @type {HTMLElement} */ (tempCon).previousElementSibling ||
697
+ tempCon.previousSibling ||
698
+ startCon;
597
699
  tempOffset = tempOffset > 0 ? tempCon.textContent.length : tempOffset;
598
700
  }
599
701
 
600
702
  let format = this.#$.format.getLine(tempCon, null);
601
703
  if (format === this.#$.format.getBlock(format, null)) {
602
704
  tempCon ||= tempConCache;
603
- format = dom.utils.createElement(dom.query.getParentElement(tempCon, dom.check.isTableCell) ? 'DIV' : this.#options.get('defaultLine'));
705
+ format = dom.utils.createElement(
706
+ dom.query.getParentElement(tempCon, dom.check.isTableCell)
707
+ ? 'DIV'
708
+ : this.#options.get('defaultLine'),
709
+ );
604
710
  tempCon.parentNode.insertBefore(format, tempCon);
605
711
  if (tempCon !== tempConCache) format.appendChild(tempCon);
606
712
  }
@@ -634,13 +740,20 @@ class Selection_ {
634
740
  tempChild = tempCon.childNodes;
635
741
  if (tempChild.length === 0) break;
636
742
  tempCon =
637
- tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : /** @type {HTMLElement} */ (tempCon).previousElementSibling || tempCon.previousSibling || startCon;
743
+ tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] ||
744
+ !/FIGURE/i.test(tempChild[0].nodeName)
745
+ ? tempChild[0]
746
+ : /** @type {HTMLElement} */ (tempCon).previousElementSibling ||
747
+ tempCon.previousSibling ||
748
+ startCon;
638
749
  tempOffset = tempOffset > 0 ? tempCon.textContent.length : tempOffset;
639
750
  }
640
751
 
641
752
  let format = this.#$.format.getLine(tempCon, null);
642
753
  if (format === this.#$.format.getBlock(format, null)) {
643
- format = dom.utils.createElement(dom.check.isTableCell(format) ? 'DIV' : this.#options.get('defaultLine'));
754
+ format = dom.utils.createElement(
755
+ dom.check.isTableCell(format) ? 'DIV' : this.#options.get('defaultLine'),
756
+ );
644
757
  tempCon.parentNode.insertBefore(format, tempCon);
645
758
  format.appendChild(tempCon);
646
759
  }
@@ -700,7 +813,9 @@ class Selection_ {
700
813
  this.#store.set('_range', range);
701
814
 
702
815
  if (range.collapsed) {
703
- if (dom.check.isWysiwygFrame(range.commonAncestorContainer)) selectionNode = range.commonAncestorContainer.children[range.startOffset] || range.commonAncestorContainer;
816
+ if (dom.check.isWysiwygFrame(range.commonAncestorContainer))
817
+ selectionNode =
818
+ range.commonAncestorContainer.children[range.startOffset] || range.commonAncestorContainer;
704
819
  else selectionNode = range.commonAncestorContainer;
705
820
  } else {
706
821
  selectionNode = selection.anchorNode;
@@ -719,7 +834,9 @@ class Selection_ {
719
834
  return (
720
835
  (dom.check.isWysiwygFrame(range.startContainer) && dom.check.isWysiwygFrame(range.endContainer)) ||
721
836
  /FIGURE/i.test(comm.nodeName) ||
722
- (this.#$.pluginManager.fileInfo.regExp.test(comm.nodeName) && (!this.#$.pluginManager.fileInfo.tagAttrs[comm.nodeName] || this.#$.pluginManager.fileInfo.tagAttrs[comm.nodeName]?.every((v) => comm.hasAttribute(v)))) ||
837
+ (this.#$.pluginManager.fileInfo.regExp.test(comm.nodeName) &&
838
+ (!this.#$.pluginManager.fileInfo.tagAttrs[comm.nodeName] ||
839
+ this.#$.pluginManager.fileInfo.tagAttrs[comm.nodeName]?.every((v) => comm.hasAttribute(v)))) ||
723
840
  this.#$.component.is(comm)
724
841
  );
725
842
  }
@@ -779,7 +896,8 @@ class Selection_ {
779
896
  this.#hasScrollParents = this.#kernel._eventOrchestrator.scrollparents?.length > 0;
780
897
  this.#scrollMargin = !this.#frameContext?.get('wysiwyg')
781
898
  ? 40
782
- : (numbers.get(_w.getComputedStyle(this.#frameContext.get('wysiwyg')).scrollMargin, 0) || 40) + numbers.get(_w.getComputedStyle(this.#frameContext.get('wrapper')).paddingBottom, 0);
899
+ : (numbers.get(_w.getComputedStyle(this.#frameContext.get('wysiwyg')).scrollMargin, 0) || 40) +
900
+ numbers.get(_w.getComputedStyle(this.#frameContext.get('wrapper')).paddingBottom, 0);
783
901
  }
784
902
  }
785
903