suneditor 3.0.0-rc.5 → 3.0.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 (118) hide show
  1. package/README.md +3 -2
  2. package/dist/suneditor-contents.min.css +1 -1
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +3 -3
  6. package/src/assets/design/color.css +14 -2
  7. package/src/assets/design/typography.css +5 -0
  8. package/src/assets/icons/defaultIcons.js +22 -4
  9. package/src/assets/suneditor-contents.css +1 -1
  10. package/src/assets/suneditor.css +312 -18
  11. package/src/core/config/eventManager.js +6 -9
  12. package/src/core/editor.js +1 -1
  13. package/src/core/event/actions/index.js +5 -0
  14. package/src/core/event/effects/keydown.registry.js +25 -0
  15. package/src/core/event/eventOrchestrator.js +69 -2
  16. package/src/core/event/handlers/handler_ww_mouse.js +1 -0
  17. package/src/core/event/rules/keydown.rule.backspace.js +9 -1
  18. package/src/core/kernel/coreKernel.js +4 -0
  19. package/src/core/kernel/store.js +2 -0
  20. package/src/core/logic/dom/html.js +110 -11
  21. package/src/core/logic/dom/offset.js +89 -35
  22. package/src/core/logic/dom/selection.js +46 -19
  23. package/src/core/logic/panel/finder.js +982 -0
  24. package/src/core/logic/panel/menu.js +8 -6
  25. package/src/core/logic/panel/toolbar.js +112 -19
  26. package/src/core/logic/panel/viewer.js +214 -43
  27. package/src/core/logic/shell/_commandExecutor.js +7 -1
  28. package/src/core/logic/shell/commandDispatcher.js +1 -1
  29. package/src/core/logic/shell/component.js +5 -7
  30. package/src/core/logic/shell/history.js +24 -0
  31. package/src/core/logic/shell/shortcuts.js +5 -3
  32. package/src/core/logic/shell/ui.js +25 -26
  33. package/src/core/schema/frameContext.js +15 -1
  34. package/src/core/schema/options.js +75 -16
  35. package/src/core/section/constructor.js +62 -21
  36. package/src/core/section/documentType.js +1 -1
  37. package/src/events.js +12 -0
  38. package/src/helper/clipboard.js +1 -1
  39. package/src/helper/dom/domUtils.js +5 -14
  40. package/src/helper/index.js +3 -0
  41. package/src/helper/markdown.js +876 -0
  42. package/src/langs/ckb.js +9 -0
  43. package/src/langs/cs.js +9 -0
  44. package/src/langs/da.js +9 -0
  45. package/src/langs/de.js +9 -0
  46. package/src/langs/en.js +9 -0
  47. package/src/langs/es.js +9 -0
  48. package/src/langs/fa.js +9 -0
  49. package/src/langs/fr.js +9 -0
  50. package/src/langs/he.js +9 -0
  51. package/src/langs/hu.js +9 -0
  52. package/src/langs/it.js +9 -0
  53. package/src/langs/ja.js +9 -0
  54. package/src/langs/km.js +9 -0
  55. package/src/langs/ko.js +9 -0
  56. package/src/langs/lv.js +9 -0
  57. package/src/langs/nl.js +9 -0
  58. package/src/langs/pl.js +9 -0
  59. package/src/langs/pt_br.js +9 -0
  60. package/src/langs/ro.js +9 -0
  61. package/src/langs/ru.js +9 -0
  62. package/src/langs/se.js +9 -0
  63. package/src/langs/tr.js +9 -0
  64. package/src/langs/uk.js +9 -0
  65. package/src/langs/ur.js +9 -0
  66. package/src/langs/zh_cn.js +9 -0
  67. package/src/modules/contract/Controller.js +50 -39
  68. package/src/modules/manager/ApiManager.js +27 -4
  69. package/src/modules/manager/FileManager.js +1 -1
  70. package/src/modules/ui/SelectMenu.js +22 -11
  71. package/src/plugins/command/codeBlock.js +324 -0
  72. package/src/plugins/command/exportPDF.js +15 -3
  73. package/src/plugins/dropdown/blockStyle.js +1 -1
  74. package/src/plugins/dropdown/paragraphStyle.js +1 -2
  75. package/src/plugins/dropdown/table/render/table.html.js +1 -1
  76. package/src/plugins/dropdown/table/services/table.grid.js +16 -8
  77. package/src/plugins/dropdown/table/services/table.style.js +5 -9
  78. package/src/plugins/index.js +3 -0
  79. package/src/plugins/input/fontSize.js +4 -2
  80. package/src/plugins/modal/audio.js +2 -1
  81. package/src/plugins/modal/image/index.js +2 -1
  82. package/src/plugins/modal/math.js +2 -1
  83. package/src/plugins/modal/video/index.js +2 -1
  84. package/src/themes/cobalt.css +13 -4
  85. package/src/themes/cream.css +44 -35
  86. package/src/themes/dark.css +13 -4
  87. package/src/themes/midnight.css +13 -4
  88. package/src/typedef.js +4 -4
  89. package/types/assets/icons/defaultIcons.d.ts +12 -1
  90. package/types/core/config/eventManager.d.ts +6 -8
  91. package/types/core/event/actions/index.d.ts +1 -0
  92. package/types/core/event/effects/keydown.registry.d.ts +2 -0
  93. package/types/core/event/eventOrchestrator.d.ts +2 -1
  94. package/types/core/kernel/coreKernel.d.ts +5 -0
  95. package/types/core/kernel/store.d.ts +5 -0
  96. package/types/core/logic/dom/offset.d.ts +16 -3
  97. package/types/core/logic/dom/selection.d.ts +3 -3
  98. package/types/core/logic/panel/finder.d.ts +83 -0
  99. package/types/core/logic/panel/toolbar.d.ts +14 -1
  100. package/types/core/logic/panel/viewer.d.ts +22 -2
  101. package/types/core/logic/shell/shortcuts.d.ts +1 -1
  102. package/types/core/schema/frameContext.d.ts +22 -0
  103. package/types/core/schema/options.d.ts +153 -31
  104. package/types/events.d.ts +11 -0
  105. package/types/helper/dom/domUtils.d.ts +2 -2
  106. package/types/helper/index.d.ts +5 -0
  107. package/types/helper/markdown.d.ts +27 -0
  108. package/types/langs/_Lang.d.ts +9 -0
  109. package/types/modules/contract/Controller.d.ts +8 -1
  110. package/types/modules/ui/SelectMenu.d.ts +12 -0
  111. package/types/plugins/command/codeBlock.d.ts +53 -0
  112. package/types/plugins/index.d.ts +3 -0
  113. package/types/plugins/input/fontSize.d.ts +6 -2
  114. package/types/plugins/modal/audio.d.ts +4 -2
  115. package/types/plugins/modal/image/index.d.ts +3 -1
  116. package/types/plugins/modal/math.d.ts +3 -1
  117. package/types/plugins/modal/video/index.d.ts +3 -1
  118. package/types/typedef.d.ts +5 -2
@@ -59,7 +59,7 @@ 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|codeView|fullScreen|print|preview|showBlocks/.test(command)) return;
62
+ if (this.#frameContext.get('isReadOnly') && !/copy|cut|selectAll|codeView|markdownView|fullScreen|print|preview|showBlocks|finder/.test(command)) return;
63
63
 
64
64
  switch (command) {
65
65
  case 'selectAll':
@@ -83,9 +83,15 @@ export default class CommandExecutor {
83
83
  this.#frameContext.get('documentType').reHeader();
84
84
  }
85
85
  break;
86
+ case 'finder':
87
+ this.#$.finder.open(true);
88
+ break;
86
89
  case 'codeView':
87
90
  this.#$.viewer.codeView(!this.#frameContext.get('isCodeView'));
88
91
  break;
92
+ case 'markdownView':
93
+ this.#$.viewer.markdownView(!this.#frameContext.get('isMarkdownView'));
94
+ break;
89
95
  case 'fullScreen':
90
96
  this.#$.viewer.fullScreen(!this.#frameContext.get('isFullScreen'));
91
97
  break;
@@ -16,7 +16,7 @@ const ACTIVE_EVENT_COMMANDS = ['bold', 'underline', 'italic', 'strike', 'subscri
16
16
  * - such as undo, redo, saving, full-screen toggle, and text direction commands.
17
17
  * @constant {string[]}
18
18
  */
19
- const BASIC_COMMANDS = ACTIVE_EVENT_COMMANDS.concat(['undo', 'redo', 'save', 'fullScreen', 'showBlocks', 'codeView', 'dir', 'dir_ltr', 'dir_rtl']);
19
+ const BASIC_COMMANDS = ACTIVE_EVENT_COMMANDS.concat(['undo', 'redo', 'save', 'fullScreen', 'showBlocks', 'codeView', 'markdownView', 'finder', 'dir', 'dir_ltr', 'dir_rtl']);
20
20
 
21
21
  /**
22
22
  * @description Routes toolbar button commands to their handlers and manages active button states.
@@ -1,4 +1,4 @@
1
- import { dom, env, numbers, unicode, keyCodeMap, converter } from '../../../helper';
1
+ import { dom, env, numbers, unicode, keyCodeMap } from '../../../helper';
2
2
  import { Figure } from '../../../modules/contract';
3
3
  import { _DragHandle } from '../../../modules/ui';
4
4
 
@@ -339,11 +339,8 @@ class Component {
339
339
  _DragHandle.set('__overInfo', __overInfo === ON_OVER_COMPONENT ? undefined : false);
340
340
  if (__overInfo !== ON_OVER_COMPONENT) this.#addGlobalEvent();
341
341
  if (!info.isFile) this.#addNotFileGlobalEvent();
342
- }, 0);
343
-
344
- converter.debounce(() => {
345
342
  dom.utils.addClass(info.container, 'se-component-selected');
346
- }, 0)();
343
+ }, 0);
347
344
 
348
345
  if (notOver && !this.#store.get('hasFocus') && !this.#store.get('_preventFocus')) {
349
346
  this.#kernel._eventOrchestrator.__postFocusEvent(this.#frameContext, null);
@@ -513,10 +510,11 @@ class Component {
513
510
  if (this.currentInfo) {
514
511
  const infoContainer = this.currentInfo.container;
515
512
  const infoCover = this.currentInfo.cover;
516
- converter.debounce(() => {
513
+
514
+ _w.setTimeout(() => {
517
515
  RemoveSelectedClass(infoContainer);
518
516
  dom.utils.removeClass(infoCover, 'se-figure-over-selected');
519
- }, 0)();
517
+ }, 0);
520
518
  }
521
519
 
522
520
  if (this.#frameContext.get('lineBreaker_t')) {
@@ -17,6 +17,7 @@ export default function History(kernel) {
17
17
  const frameContext = contextProvider.frameContext;
18
18
 
19
19
  let delayTime = $.options.get('historyStackDelayTime');
20
+ const maxStackSize = $.options.get('historyStackSize');
20
21
  let pushDelay = null;
21
22
  let stackIndex, stack, rootStack, rootInitContents;
22
23
  let waiting = false;
@@ -204,6 +205,29 @@ export default function History(kernel) {
204
205
 
205
206
  setStack(current, range, rootKey, 1);
206
207
 
208
+ // Enforce max stack size
209
+ if (root.value.length > maxStackSize) {
210
+ const overflow = root.value.length - maxStackSize;
211
+ root.value.splice(0, overflow);
212
+ root.index -= overflow;
213
+
214
+ // Remove corresponding global stack entries
215
+ let removed = 0;
216
+ for (let i = stack.length - 1; i >= 0 && removed < overflow; i--) {
217
+ if (stack[i] === rootKey) {
218
+ // find the oldest entry for this rootKey
219
+ for (let j = 0; j < stack.length; j++) {
220
+ if (stack[j] === rootKey) {
221
+ stack.splice(j, 1);
222
+ removed++;
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ stackIndex -= overflow;
229
+ }
230
+
207
231
  if (stackIndex === 1) {
208
232
  $.commandDispatcher.applyTargets('undo', (e) => {
209
233
  e.disabled = false;
@@ -106,14 +106,16 @@ class Shortcuts {
106
106
  * @description Registers custom shortcut keys (keys starting with `_`) into the shortcut map.
107
107
  * Called during initialization and when toolbar is reset.
108
108
  */
109
- _registerCustomShortcuts() {
109
+ _registerShortcuts() {
110
110
  const shortcuts = this.#options.get('shortcuts');
111
111
  const reverseCommandArray = this.#options.get('_reverseCommandArray');
112
112
  const keyMap = (this.keyMap = new Map());
113
113
  const reverseKeys = this.reverseKeys;
114
114
  for (const key of Object.keys(shortcuts)) {
115
- if (!key.startsWith('_')) continue;
116
- CreateShortcuts('', null, shortcuts[key], keyMap, reverseCommandArray, reverseKeys);
115
+ // Plugin shortcuts are registered in commandDispatcher.#saveCommandButtons.
116
+ if (this.#$.plugins[key]) continue;
117
+ const command = key.startsWith('_') ? '' : key;
118
+ CreateShortcuts(command, null, shortcuts[key], keyMap, reverseCommandArray, reverseKeys);
117
119
  }
118
120
  }
119
121
 
@@ -28,6 +28,7 @@ class UIManager {
28
28
  #alertInner;
29
29
  #closeListener;
30
30
  #closeSignal;
31
+ #bindAlertClick = null;
31
32
  #backWrapper;
32
33
 
33
34
  #controllerOnBtnDisabled = false;
@@ -97,7 +98,7 @@ class UIManager {
97
98
  this.#alertArea = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-alert'));
98
99
  this.#alertInner = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-alert .se-modal-inner'));
99
100
  this.#alertInner.appendChild(alertModal);
100
- this.#closeListener = [CloseListener.bind(this), OnClick_alert.bind(this)];
101
+ this.#closeListener = [this.#OnCloseListener.bind(this), this.#OnClick_alert.bind(this)];
101
102
  this.#closeSignal = false;
102
103
  this.#backWrapper = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-back-wrapper'));
103
104
 
@@ -393,7 +394,7 @@ class UIManager {
393
394
  dom.utils.removeClass(this.alertModal, 'se-alert-error|se-alert-success');
394
395
  if (type) dom.utils.addClass(this.alertModal, `se-alert-${type}`);
395
396
 
396
- if (this.#closeSignal) this.#alertInner.addEventListener('click', this.#closeListener[1]);
397
+ if (this.#closeSignal) this.#bindAlertClick = this.#eventManager.addEvent(this.#alertInner, 'click', this.#closeListener[1]);
397
398
  this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
398
399
  this.#bindClose = this.#eventManager.addGlobalEvent('keydown', this.#closeListener[0]);
399
400
 
@@ -408,7 +409,7 @@ class UIManager {
408
409
  dom.utils.removeClass(this.alertModal, 'se-modal-show');
409
410
  dom.utils.removeClass(this.alertModal, 'se-alert-*');
410
411
  this.#alertArea.style.display = 'none';
411
- if (this.#closeSignal) this.#alertInner.removeEventListener('click', this.#closeListener[1]);
412
+ this.#bindAlertClick &&= this.#eventManager.removeEvent(this.#bindAlertClick);
412
413
  this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
413
414
  }
414
415
 
@@ -580,10 +581,10 @@ class UIManager {
580
581
  const y = eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0;
581
582
  const x = eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0;
582
583
 
583
- if (this.#store.mode.isBalloon) {
584
+ if (this.#store.mode.isBalloon && this.#context.get('toolbar_main').style.display === 'block') {
584
585
  this.#context.get('toolbar_main').style.top = this.#$.toolbar.balloonOffset.top - y + 'px';
585
586
  this.#context.get('toolbar_main').style.left = this.#$.toolbar.balloonOffset.left - x + 'px';
586
- } else if (this.#store.mode.isSubBalloon) {
587
+ } else if (this.#store.mode.isSubBalloon && this.#context.get('toolbar_sub_main').style.display === 'block') {
587
588
  this.#context.get('toolbar_sub_main').style.top = this.#$.subToolbar.balloonOffset.top - y + 'px';
588
589
  this.#context.get('toolbar_sub_main').style.left = this.#$.subToolbar.balloonOffset.left - x + 'px';
589
590
  }
@@ -855,6 +856,24 @@ class UIManager {
855
856
  this._initToggleButtons();
856
857
  }
857
858
 
859
+ /**
860
+ * @param {MouseEvent} e - Event object
861
+ */
862
+ #OnClick_alert(e) {
863
+ const eventTarget = dom.query.getEventTarget(e);
864
+ if (/close/.test(eventTarget.getAttribute('data-command')) || eventTarget === this.#alertInner) {
865
+ this.alertClose();
866
+ }
867
+ }
868
+
869
+ /**
870
+ * @param {KeyboardEvent} e - Event object
871
+ */
872
+ #OnCloseListener(e) {
873
+ if (!keyCodeMap.isEsc(e.code)) return;
874
+ this.alertClose();
875
+ }
876
+
858
877
  /**
859
878
  * @internal
860
879
  * @description Destroy the UI instance and release memory
@@ -869,9 +888,7 @@ class UIManager {
869
888
  this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
870
889
 
871
890
  // Remove alert click event listener
872
- if (this.#closeSignal && this.#alertInner) {
873
- this.#alertInner.removeEventListener('click', this.#closeListener[1]);
874
- }
891
+ this.#bindAlertClick &&= this.#eventManager.removeEvent(this.#bindAlertClick);
875
892
 
876
893
  this.opendModal = null;
877
894
  this.opendBrowser = null;
@@ -882,24 +899,6 @@ class UIManager {
882
899
  }
883
900
  }
884
901
 
885
- /**
886
- * @param {MouseEvent} e - Event object
887
- */
888
- function OnClick_alert(e) {
889
- const eventTarget = dom.query.getEventTarget(e);
890
- if (/close/.test(eventTarget.getAttribute('data-command')) || eventTarget === this._alertInner) {
891
- this.alertClose();
892
- }
893
- }
894
-
895
- /**
896
- * @param {KeyboardEvent} e - Event object
897
- */
898
- function CloseListener(e) {
899
- if (!keyCodeMap.isEsc(e.code)) return;
900
- this.alertClose();
901
- }
902
-
903
902
  function CreateAlertHTML({ lang, icons }) {
904
903
  const html = '<div><button class="close" data-command="close" title="' + lang.close + '">' + icons.cancel + '</button></div><div><span></span></div>';
905
904
  return dom.utils.createElement('DIV', { class: 'se-alert-content' }, html);
@@ -30,6 +30,9 @@ import { get as getNumber } from '../../helper/numbers';
30
30
  * @property {HTMLElement} codeWrapper - Wrapper element for the code-view mode.
31
31
  * @property {HTMLElement & HTMLTextAreaElement} code - Code view editing element (a <textarea> or <pre>).
32
32
  * @property {HTMLTextAreaElement} codeNumbers - Element displaying line numbers in code view mode.
33
+ * @property {HTMLElement} markdownWrapper - Wrapper element for the markdown-view mode.
34
+ * @property {HTMLTextAreaElement} markdown - Markdown view editing element (a <textarea>).
35
+ * @property {HTMLTextAreaElement} markdownNumbers - Element displaying line numbers in markdown view mode.
33
36
  * @property {HTMLElement} placeholder - Placeholder element shown when the editor is empty.
34
37
  * @property {HTMLElement} statusbar - Editor status bar element (for resizing, info, etc.).
35
38
  * @property {HTMLElement} navigation - Navigation element (e.g., for outline or bookmarks).
@@ -47,6 +50,7 @@ import { get as getNumber } from '../../helper/numbers';
47
50
  *
48
51
  * === State Flags ===
49
52
  * @property {boolean} isCodeView - Whether the editor is currently in code view mode.
53
+ * @property {boolean} isMarkdownView - Whether the editor is currently in markdown view mode.
50
54
  * @property {boolean} isFullScreen - Whether the editor is currently in fullscreen mode.
51
55
  * @property {boolean} isReadOnly - Whether the editor is set to readonly mode.
52
56
  * @property {boolean} isDisabled - Whether the editor is currently disabled.
@@ -90,7 +94,7 @@ import { get as getNumber } from '../../helper/numbers';
90
94
  * @param {*} key root key
91
95
  * @returns {FrameContexType}
92
96
  */
93
- export function CreateFrameContext(editorTarget, top, wwFrame, codeWrapper, codeFrame, statusbar, documentTypeInner, key) {
97
+ export function CreateFrameContext(editorTarget, top, wwFrame, codeWrapper, codeFrame, markdownWrapper, markdownFrame, statusbar, documentTypeInner, key) {
94
98
  const m = /** @type {FrameContexType} */ (
95
99
  new Map([
96
100
  ['key', key],
@@ -101,21 +105,31 @@ export function CreateFrameContext(editorTarget, top, wwFrame, codeWrapper, code
101
105
  ['wrapper', top.querySelector('.se-wrapper')],
102
106
  ['wysiwygFrame', wwFrame],
103
107
  ['wysiwyg', wwFrame], // options.iframe ? wwFrame.contentDocument.body : wwFrame
108
+ // codeview
104
109
  ['codeWrapper', codeWrapper],
105
110
  ['code', codeFrame],
106
111
  ['codeNumbers', /** @type {HTMLTextAreaElement} */ (codeWrapper?.querySelector('.se-code-view-line'))],
112
+ // markdown
113
+ ['markdownWrapper', markdownWrapper],
114
+ ['markdown', markdownFrame],
115
+ ['markdownNumbers', /** @type {HTMLTextAreaElement} */ (markdownWrapper?.querySelector('.se-markdown-view-line'))],
116
+ // linebreak, toolbar internal
107
117
  ['lineBreaker_t', top.querySelector('.se-line-breaker-component-t')],
108
118
  ['lineBreaker_b', top.querySelector('.se-line-breaker-component-b')],
109
119
  ['_stickyDummy', top.querySelector('.se-toolbar-sticky-dummy')],
110
120
  ['_toolbarShadow', top.querySelector('.se-toolbar-shadow')],
111
121
  ['_minHeight', getNumber(wwFrame.style.minHeight || '65', 0)],
122
+ // is
112
123
  ['isCodeView', false],
124
+ ['isMarkdownView', false],
113
125
  ['isFullScreen', false],
114
126
  ['isReadOnly', false],
115
127
  ['isDisabled', false],
116
128
  ['isChanged', false],
129
+ // index
117
130
  ['historyIndex', -1],
118
131
  ['savedIndex', -1],
132
+ // document type
119
133
  ['documentTypeInner', documentTypeInner.inner],
120
134
  ['documentTypePage', documentTypeInner.page],
121
135
  ['documentTypePageMirror', documentTypeInner.pageMirror],
@@ -43,7 +43,7 @@ export const DEFAULTS = {
43
43
 
44
44
  SIZE_UNITS: ['px', 'pt', 'em', 'rem'],
45
45
 
46
- CLASS_NAME: '^__se__|^se-|^katex|^MathJax',
46
+ CLASS_NAME: '^__se__|^se-|^katex|^MathJax|^language-',
47
47
  CLASS_MJX: 'mjx-container|mjx-math|mjx-mrow|mjx-mi|mjx-mo|mjx-mn|mjx-msup|mjx-mfrac|mjx-munderover',
48
48
  EXTRA_TAG_MAP: { script: false, style: false, meta: false, link: false, '[a-z]+:[a-z]+': false },
49
49
 
@@ -246,8 +246,10 @@ export const DEFAULTS = {
246
246
  * @property {{pluginName: string, we: boolean}|boolean} [__pluginRetainFilter=true] - Plugin retain filter configuration. (Internal use primarily)
247
247
  * - You can turn it off/on globally with `true`/`false` or set it per plugin.
248
248
  * ```js
249
- * // __pluginRetainFilter - disable filter for table plugin only
250
- * { __pluginRetainFilter: { table: false } }
249
+ * // disable filter for table plugin only
250
+ * {
251
+ * __pluginRetainFilter: { table: false }
252
+ * }
251
253
  * ```
252
254
  */
253
255
 
@@ -277,7 +279,7 @@ export const DEFAULTS = {
277
279
  *
278
280
  * === Modes & Themes ===
279
281
  * @property {boolean} [v2Migration=false] - Enables migration mode for SunEditor v2.
280
- * @property {"classic"|"inline"|"balloon"|"balloon-always"} [mode="classic"] - Toolbar mode: `classic`, `inline`, `balloon`, `balloon-always`.
282
+ * @property {"classic"|"inline"|"balloon"|"balloon-always"|"classic:bottom"|"inline:bottom"} [mode="classic"] - Toolbar mode: `classic`, `inline`, `balloon`, `balloon-always`. Append `:bottom` to place toolbar at the bottom (e.g. `classic:bottom`, `inline:bottom`).
281
283
  * @property {string} [type=""] - Editor type. Use `"document"` for a document-style layout, with optional sub-types after `:`.
282
284
  * ```js
283
285
  * // type
@@ -311,7 +313,16 @@ export const DEFAULTS = {
311
313
  * - `styleFilter`: Filters disallowed inline styles (`spanStyles`/`lineStyles`/`allUsedStyles`)
312
314
  * ```js
313
315
  * // disable only attribute and style filters
314
- * { strictMode: { tagFilter: true, formatFilter: true, classFilter: true, textStyleTagFilter: true, attrFilter: false, styleFilter: false } }
316
+ * {
317
+ * strictMode: {
318
+ * tagFilter: true,
319
+ * formatFilter: true,
320
+ * classFilter: true,
321
+ * textStyleTagFilter: true,
322
+ * attrFilter: false,
323
+ * styleFilter: false
324
+ * }
325
+ * }
315
326
  * ```
316
327
  * @property {Array<string>} [scopeSelectionTags=CONSTANTS.SCOPE_SELECTION_TAGS] - Tags treated as whole units when selecting all content.
317
328
  * - The default follows {@link DEFAULTS.SCOPE_SELECTION_TAGS}
@@ -341,7 +352,13 @@ export const DEFAULTS = {
341
352
  * @property {{[key: string]: string|undefined}} [attributeWhitelist=null] - Specifies additional attributes to allow for each tag. `"*"` applies to all tags.
342
353
  * - Rules specified here will be merged into {@link PrivateBaseOptions.__defaultAttributeWhitelist}.
343
354
  * ```js
344
- * { attributeWhitelist: { a: 'href|target', img: 'src|alt', '*': 'id|data-*' } }
355
+ * {
356
+ * attributeWhitelist: {
357
+ * a: 'href|target',
358
+ * img: 'src|alt',
359
+ * '*': 'id|data-*'
360
+ * }
361
+ * }
345
362
  * ```
346
363
  * @property {{[key: string]: string|undefined}} [attributeBlacklist=null] - Specifies attributes to disallow by tag. `"*"` applies to all tags.
347
364
  * - Attributes specified here will eventually be removed even if they are allowed by other settings.
@@ -356,7 +373,14 @@ export const DEFAULTS = {
356
373
  * - The default follows {@link PrivateBaseOptions.__textStyleTags}
357
374
  * @property {Object<string, string>} [convertTextTags={bold: "strong", underline: "u", italic: "em", strike: "del", subscript: "sub", superscript: "sup"}] - Maps text styles to specific HTML tags.
358
375
  * ```js
359
- * { convertTextTags: { bold: 'b', italic: 'i', underline: 'u', strike: 's' } }
376
+ * {
377
+ * convertTextTags: {
378
+ * bold: 'b',
379
+ * italic: 'i',
380
+ * underline: 'u',
381
+ * strike: 's'
382
+ * }
383
+ * }
360
384
  * ```
361
385
  * @property {string} [allUsedStyles] - Specifies additional styles to the list of allowed styles. Delimiter: `"|"`.
362
386
  * ```js
@@ -364,7 +388,12 @@ export const DEFAULTS = {
364
388
  * ```
365
389
  * @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags. Key is tag name(s), value is pipe-delimited allowed styles.
366
390
  * ```js
367
- * { tagStyles: { 'table|td': 'border|color|background-color', hr: 'border-top' } }
391
+ * {
392
+ * tagStyles: {
393
+ * 'table|td': 'border|color|background-color',
394
+ * hr: 'border-top'
395
+ * }
396
+ * }
368
397
  * ```
369
398
  * @property {string} [spanStyles=CONSTANTS.SPAN_STYLES] - Specifies allowed styles for the `span` tag.
370
399
  * - The default follows {@link DEFAULTS.SPAN_STYLES}
@@ -444,11 +473,16 @@ export const DEFAULTS = {
444
473
  * @property {boolean} [shortcutsHint=true] - Displays shortcut hints in tooltips.
445
474
  * @property {boolean} [shortcutsDisable=false] - Disables keyboard shortcuts.
446
475
  * @property {{[key: string]: Array<string>|undefined}} [shortcuts={}] - Custom keyboard shortcuts.
447
- * Keys starting with `_` are user-defined custom shortcuts. Each value is an array of `[keyCombo, hintLabel]` pairs.
448
- * Key combos use `c` (Ctrl/Cmd), `s` (Shift), and `KeyEvent.code` values joined by `+`.
449
- * Use `$~pluginName.method` to call a specific plugin method.
476
+ * - Keys starting with `_` are user-defined custom shortcuts. Each value is an array of `[keyCombo, hintLabel]` pairs.
477
+ * - Key combos use `c` (Ctrl/Cmd), `s` (Shift), and `KeyEvent.code` values joined by `+`.
478
+ * - Use `$~pluginName.method` to call a specific plugin method.
450
479
  * ```js
451
- * { shortcuts: { bold: ['c+KeyB', 'B'], _h1: ['c+s+Digit1+$~blockStyle.applyHeaderByShortcut', ''] } }
480
+ * {
481
+ * shortcuts: {
482
+ * bold: ['c+KeyB', 'B'],
483
+ * _h1: ['c+s+Digit1+$~blockStyle.applyHeaderByShortcut', '']
484
+ * }
485
+ * }
452
486
  * ```
453
487
  * ///
454
488
  *
@@ -458,6 +492,7 @@ export const DEFAULTS = {
458
492
  * - Default: `Boolean(plugins.link)` — determined by whether the `link` plugin is enabled.
459
493
  * @property {Array<string>} [autoStyleify=["bold", "underline", "italic", "strike"]] - Styles applied automatically on text input.
460
494
  * @property {number} [historyStackDelayTime=400] - Delay time for history stack updates (ms).
495
+ * @property {number} [historyStackSize=100] - Maximum number of history entries per root frame. Oldest entries are discarded when exceeded.
461
496
  * @property {string} [printClass=""] - Class name for printing.
462
497
  * @property {number} [fullScreenOffset=0] - Offset applied when entering fullscreen mode.
463
498
  * @property {?string} [previewTemplate=null] - Custom HTML template for preview mode. Use `{{ contents }}` as a placeholder for editor content.
@@ -475,24 +510,45 @@ export const DEFAULTS = {
475
510
  * @property {?string} [defaultUrlProtocol=null] - Default URL protocol for links.
476
511
  * @property {Object<"copy", number>} [toastMessageTime={copy: 1500}] - Duration for displaying toast messages (ms).
477
512
  * @property {boolean} [freeCodeViewMode=false] - Enables free code view mode.
513
+ * @property {boolean} [finder_panel=true] - Shows the built-in Find/Replace panel UI.
514
+ * - The finder is always created internally; this option controls whether the panel is visible to users (Ctrl+F / Ctrl+H).
515
+ * @property {boolean} [finder_liveSearch=true] - Searches instantly as you type (debounced). When false, search runs only on Enter.
516
+ *
517
+ * ///
478
518
  *
479
519
  * === Dynamic Options ===
480
520
  * @property {Object<string, *>} [externalLibs] - External libraries like CodeMirror, KaTeX, or MathJax.
481
521
  * - See {@link https://github.com/ARA-developer/suneditor/blob/develop/guide/external-libraries.md External Libraries Guide}
482
522
  * ```js
483
- * { externalLibs: { katex: window.katex, codeMirror: { src: CodeMirror } } }
523
+ * {
524
+ * externalLibs: {
525
+ * katex: window.katex,
526
+ * codeMirror: { src: CodeMirror }
527
+ * }
528
+ * }
484
529
  * ```
485
530
  * @property {Object<string, boolean>} [allowedExtraTags=CONSTANTS.EXTRA_TAG_MAP] - Specifies extra allowed or disallowed tags. `true` to allow, `false` to disallow.
486
531
  * - The default follows {@link DEFAULTS.EXTRA_TAG_MAP}
487
532
  * ```js
488
- * { allowedExtraTags: { script: false, style: false, mark: true } }
533
+ * {
534
+ * allowedExtraTags: {
535
+ * script: false,
536
+ * style: false,
537
+ * mark: true
538
+ * }
539
+ * }
489
540
  * ```
490
541
  * ///
491
542
  *
492
543
  * === User Events ===
493
544
  * @property {SunEditor.Event.Handlers} [events] - User event handlers configuration.
494
545
  * ```js
495
- * { events: { onChange: (content) => console.log(content), onImageUploadBefore: (files, info) => true } }
546
+ * {
547
+ * events: {
548
+ * onChange: (content) => console.log(content),
549
+ * onImageUploadBefore: (files, info) => true
550
+ * }
551
+ * }
496
552
  * ```
497
553
  * ///
498
554
  *
@@ -503,6 +559,7 @@ export const DEFAULTS = {
503
559
  * @property {import('../../plugins/browser/audioGallery.js').AudioGalleryPluginOptions} [audioGallery]
504
560
  * @property {import('../../plugins/dropdown/backgroundColor.js').BackgroundColorPluginOptions} [backgroundColor]
505
561
  * @property {import('../../plugins/dropdown/blockStyle.js').BlockStylePluginOptions} [blockStyle]
562
+ * @property {import('../../plugins/command/codeBlock.js').CodeBlockPluginOptions} [codeBlock]
506
563
  * @property {import('../../plugins/modal/drawing.js').DrawingPluginOptions} [drawing]
507
564
  * @property {import('../../plugins/modal/embed.js').EmbedPluginOptions} [embed]
508
565
  * @property {import('../../plugins/command/exportPDF.js').ExportPDFPluginOptions} [exportPDF]
@@ -562,7 +619,6 @@ export const DEFAULTS = {
562
619
  * @property {*} [codeMirror] - CodeMirror configuration object from `externalLibs.codeMirror`.
563
620
  * @property {boolean} [codeMirrorEditor] - Whether CodeMirror is available (base-level flag). Frame-level stores the actual CM instance.
564
621
  * @property {boolean} [hasCodeMirror] - Uses CodeMirror for code view.
565
- *
566
622
  * @property {Set<string>} [allUsedStyles] - Processed set of all allowed CSS styles.
567
623
  * - Converted from user's `string` input ("|" delimited) to `Set<string>` in constructor.
568
624
  */
@@ -648,6 +704,7 @@ export const OPTION_FIXED_FLAG = {
648
704
  textDirection: true,
649
705
  reverseButtons: 'fixed',
650
706
  historyStackDelayTime: true,
707
+ historyStackSize: 'fixed',
651
708
  lineAttrReset: true,
652
709
  printClass: true,
653
710
  defaultLine: 'fixed',
@@ -688,6 +745,8 @@ export const OPTION_FIXED_FLAG = {
688
745
  toastMessageTime: true,
689
746
  icons: 'fixed',
690
747
  freeCodeViewMode: true,
748
+ finder_panel: 'fixed',
749
+ finder_liveSearch: true,
691
750
  __lineFormatFilter: true,
692
751
  __pluginRetainFilter: true,
693
752
  __listCommonStyle: 'fixed',