suneditor 3.0.0-rc.4 → 3.0.0

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 (171) hide show
  1. package/README.md +4 -3
  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 +10 -6
  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/char.js +11 -0
  21. package/src/core/logic/dom/format.js +22 -0
  22. package/src/core/logic/dom/html.js +126 -11
  23. package/src/core/logic/dom/nodeTransform.js +13 -0
  24. package/src/core/logic/dom/offset.js +100 -37
  25. package/src/core/logic/dom/selection.js +54 -22
  26. package/src/core/logic/panel/finder.js +982 -0
  27. package/src/core/logic/panel/menu.js +8 -6
  28. package/src/core/logic/panel/toolbar.js +112 -19
  29. package/src/core/logic/panel/viewer.js +214 -43
  30. package/src/core/logic/shell/_commandExecutor.js +7 -1
  31. package/src/core/logic/shell/commandDispatcher.js +1 -1
  32. package/src/core/logic/shell/component.js +5 -7
  33. package/src/core/logic/shell/history.js +24 -0
  34. package/src/core/logic/shell/shortcuts.js +3 -3
  35. package/src/core/logic/shell/ui.js +25 -26
  36. package/src/core/schema/frameContext.js +15 -1
  37. package/src/core/schema/options.js +180 -39
  38. package/src/core/section/constructor.js +61 -20
  39. package/src/core/section/documentType.js +2 -2
  40. package/src/events.js +12 -0
  41. package/src/helper/clipboard.js +1 -1
  42. package/src/helper/converter.js +15 -0
  43. package/src/helper/dom/domQuery.js +12 -0
  44. package/src/helper/dom/domUtils.js +26 -14
  45. package/src/helper/index.js +3 -0
  46. package/src/helper/markdown.js +876 -0
  47. package/src/interfaces/plugins.js +7 -5
  48. package/src/langs/ckb.js +9 -0
  49. package/src/langs/cs.js +9 -0
  50. package/src/langs/da.js +9 -0
  51. package/src/langs/de.js +9 -0
  52. package/src/langs/en.js +9 -0
  53. package/src/langs/es.js +9 -0
  54. package/src/langs/fa.js +9 -0
  55. package/src/langs/fr.js +9 -0
  56. package/src/langs/he.js +9 -0
  57. package/src/langs/hu.js +9 -0
  58. package/src/langs/it.js +9 -0
  59. package/src/langs/ja.js +9 -0
  60. package/src/langs/km.js +9 -0
  61. package/src/langs/ko.js +9 -0
  62. package/src/langs/lv.js +9 -0
  63. package/src/langs/nl.js +9 -0
  64. package/src/langs/pl.js +9 -0
  65. package/src/langs/pt_br.js +9 -0
  66. package/src/langs/ro.js +9 -0
  67. package/src/langs/ru.js +9 -0
  68. package/src/langs/se.js +9 -0
  69. package/src/langs/tr.js +9 -0
  70. package/src/langs/uk.js +9 -0
  71. package/src/langs/ur.js +9 -0
  72. package/src/langs/zh_cn.js +9 -0
  73. package/src/modules/contract/Browser.js +31 -1
  74. package/src/modules/contract/ColorPicker.js +6 -0
  75. package/src/modules/contract/Controller.js +77 -39
  76. package/src/modules/contract/Figure.js +57 -0
  77. package/src/modules/contract/Modal.js +6 -0
  78. package/src/modules/manager/ApiManager.js +53 -4
  79. package/src/modules/manager/FileManager.js +18 -1
  80. package/src/modules/ui/ModalAnchorEditor.js +35 -2
  81. package/src/modules/ui/SelectMenu.js +44 -12
  82. package/src/plugins/browser/fileBrowser.js +5 -2
  83. package/src/plugins/command/codeBlock.js +324 -0
  84. package/src/plugins/command/exportPDF.js +15 -3
  85. package/src/plugins/command/fileUpload.js +4 -1
  86. package/src/plugins/dropdown/backgroundColor.js +5 -1
  87. package/src/plugins/dropdown/blockStyle.js +8 -2
  88. package/src/plugins/dropdown/fontColor.js +5 -1
  89. package/src/plugins/dropdown/hr.js +6 -0
  90. package/src/plugins/dropdown/layout.js +4 -1
  91. package/src/plugins/dropdown/lineHeight.js +3 -0
  92. package/src/plugins/dropdown/paragraphStyle.js +5 -5
  93. package/src/plugins/dropdown/table/index.js +4 -1
  94. package/src/plugins/dropdown/table/render/table.html.js +1 -1
  95. package/src/plugins/dropdown/table/services/table.grid.js +16 -8
  96. package/src/plugins/dropdown/table/services/table.style.js +5 -9
  97. package/src/plugins/dropdown/template.js +3 -0
  98. package/src/plugins/dropdown/textStyle.js +5 -1
  99. package/src/plugins/field/mention.js +5 -1
  100. package/src/plugins/index.js +3 -0
  101. package/src/plugins/input/fontSize.js +10 -3
  102. package/src/plugins/modal/audio.js +7 -3
  103. package/src/plugins/modal/embed.js +23 -20
  104. package/src/plugins/modal/image/index.js +5 -1
  105. package/src/plugins/modal/math.js +7 -2
  106. package/src/plugins/modal/video/index.js +21 -4
  107. package/src/themes/cobalt.css +13 -4
  108. package/src/themes/cream.css +11 -2
  109. package/src/themes/dark.css +13 -4
  110. package/src/themes/midnight.css +13 -4
  111. package/src/typedef.js +4 -4
  112. package/types/assets/icons/defaultIcons.d.ts +12 -1
  113. package/types/assets/suneditor.css.d.ts +1 -1
  114. package/types/core/config/eventManager.d.ts +6 -8
  115. package/types/core/event/actions/index.d.ts +1 -0
  116. package/types/core/event/effects/keydown.registry.d.ts +2 -0
  117. package/types/core/event/eventOrchestrator.d.ts +2 -1
  118. package/types/core/kernel/coreKernel.d.ts +5 -0
  119. package/types/core/kernel/store.d.ts +5 -0
  120. package/types/core/logic/dom/char.d.ts +11 -0
  121. package/types/core/logic/dom/format.d.ts +22 -0
  122. package/types/core/logic/dom/html.d.ts +16 -0
  123. package/types/core/logic/dom/nodeTransform.d.ts +13 -0
  124. package/types/core/logic/dom/offset.d.ts +23 -2
  125. package/types/core/logic/dom/selection.d.ts +9 -3
  126. package/types/core/logic/panel/finder.d.ts +83 -0
  127. package/types/core/logic/panel/toolbar.d.ts +14 -1
  128. package/types/core/logic/panel/viewer.d.ts +22 -2
  129. package/types/core/logic/shell/shortcuts.d.ts +1 -1
  130. package/types/core/schema/frameContext.d.ts +22 -0
  131. package/types/core/schema/options.d.ts +362 -79
  132. package/types/events.d.ts +11 -0
  133. package/types/helper/converter.d.ts +15 -0
  134. package/types/helper/dom/domQuery.d.ts +12 -0
  135. package/types/helper/dom/domUtils.d.ts +23 -2
  136. package/types/helper/index.d.ts +5 -0
  137. package/types/helper/markdown.d.ts +27 -0
  138. package/types/interfaces/plugins.d.ts +7 -5
  139. package/types/langs/_Lang.d.ts +9 -0
  140. package/types/modules/contract/Browser.d.ts +36 -2
  141. package/types/modules/contract/ColorPicker.d.ts +6 -0
  142. package/types/modules/contract/Controller.d.ts +35 -1
  143. package/types/modules/contract/Figure.d.ts +57 -0
  144. package/types/modules/contract/Modal.d.ts +6 -0
  145. package/types/modules/manager/ApiManager.d.ts +26 -0
  146. package/types/modules/manager/FileManager.d.ts +17 -0
  147. package/types/modules/ui/ModalAnchorEditor.d.ts +41 -4
  148. package/types/modules/ui/SelectMenu.d.ts +40 -2
  149. package/types/plugins/browser/fileBrowser.d.ts +10 -4
  150. package/types/plugins/command/codeBlock.d.ts +53 -0
  151. package/types/plugins/command/fileUpload.d.ts +8 -2
  152. package/types/plugins/dropdown/backgroundColor.d.ts +10 -2
  153. package/types/plugins/dropdown/blockStyle.d.ts +14 -2
  154. package/types/plugins/dropdown/fontColor.d.ts +10 -2
  155. package/types/plugins/dropdown/hr.d.ts +12 -0
  156. package/types/plugins/dropdown/layout.d.ts +8 -2
  157. package/types/plugins/dropdown/lineHeight.d.ts +6 -0
  158. package/types/plugins/dropdown/paragraphStyle.d.ts +14 -3
  159. package/types/plugins/dropdown/table/index.d.ts +9 -3
  160. package/types/plugins/dropdown/template.d.ts +6 -0
  161. package/types/plugins/dropdown/textStyle.d.ts +10 -2
  162. package/types/plugins/field/mention.d.ts +10 -2
  163. package/types/plugins/index.d.ts +3 -0
  164. package/types/plugins/input/fontSize.d.ts +18 -4
  165. package/types/plugins/modal/audio.d.ts +14 -6
  166. package/types/plugins/modal/embed.d.ts +44 -38
  167. package/types/plugins/modal/image/index.d.ts +9 -1
  168. package/types/plugins/modal/link.d.ts +6 -2
  169. package/types/plugins/modal/math.d.ts +23 -5
  170. package/types/plugins/modal/video/index.d.ts +49 -9
  171. package/types/typedef.d.ts +5 -2
@@ -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
 
@@ -100,7 +100,10 @@ export const DEFAULTS = {
100
100
  * === Content & Editing ===
101
101
  * @property {string} [value=""] - Initial value for the editor.
102
102
  * @property {string} [placeholder=""] - Placeholder text.
103
- * @property {Object<string, string>} [editableFrameAttributes={spellcheck: "false"}] - Attributes for the editable frame[.sun-editor-editable]. (e.g. [key]: value)
103
+ * @property {Object<string, string>} [editableFrameAttributes={spellcheck: "false"}] - Attributes for the editable frame[.sun-editor-editable].
104
+ * ```js
105
+ * { editableFrameAttributes: { spellcheck: 'true', autocomplete: 'on' } }
106
+ * ```
104
107
  * ///
105
108
  *
106
109
  * === Layout & Sizing ===
@@ -110,19 +113,26 @@ export const DEFAULTS = {
110
113
  * @property {string|number} [height="auto"] - Height for the editor.
111
114
  * @property {string|number} [minHeight=""] - Min height for the editor.
112
115
  * @property {string|number} [maxHeight=""] - Max height for the editor.
113
- * @property {string} [editorStyle=""] - Style string of the top frame of the editor. (e.g. "border: 1px solid #ccc;").
116
+ * @property {string} [editorStyle=""] - Style string of the top frame of the editor.
117
+ * ```js
118
+ * { editorStyle: 'border: 1px solid #ccc; border-radius: 4px;' }
119
+ * ```
114
120
  * ///
115
121
  *
116
122
  * === Iframe Mode ===
117
123
  * @property {boolean} [iframe=false] - Content will be placed in an iframe and isolated from the rest of the page.
118
124
  * @property {boolean} [iframe_fullPage=false] - Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration on the `iframe`.
119
- * @property {Object<string, string>} [iframe_attributes={}] - Attributes of the `iframe`. (e.g. {'allow-scripts': 'true'})
125
+ * @property {Object<string, string>} [iframe_attributes={}] - Attributes of the `iframe`.
126
+ * ```js
127
+ * { iframe_attributes: { 'allow-scripts': 'true', sandbox: 'allow-same-origin' } }
128
+ * ```
120
129
  * @property {Array<string>} [iframe_cssFileName=["suneditor"]] - CSS files to apply inside the iframe.
121
130
  * - String: Filename pattern to search in document `<link>` tags.
122
- * - (e.g. "suneditor" or "suneditor.[a-z0-9]+" matches "suneditor.abc123.css")
123
- * - "*": Wildcard to include ALL stylesheets from the page.
124
- * - Array: Multiple patterns (e.g. ["suneditor", "custom", "*"]).
125
- * - Absolute URLs and data URLs (data:text/css,) are also supported.
131
+ * - `"*"`: Wildcard to include ALL stylesheets from the page.
132
+ * - Absolute URLs and data URLs (`data:text/css,`) are also supported.
133
+ * ```js
134
+ * { iframe_cssFileName: ['suneditor', 'custom', 'https://example.com/style.css'] }
135
+ * ```
126
136
  * ///
127
137
  *
128
138
  * === Statusbar & Character Counter ===
@@ -132,12 +142,14 @@ export const DEFAULTS = {
132
142
  * @property {boolean} [charCounter=false] - Shows the number of characters in the editor.
133
143
  * - If the `maxCharCount` option has a value, it becomes `true`.
134
144
  * @property {?number} [charCounter_max=null] - The maximum number of characters allowed to be inserted into the editor.
135
- * @property {?string} [charCounter_label=null] - Text to be displayed in the `charCounter` area of the bottom bar. (e.g. "Characters : 20/200")
145
+ * @property {?string} [charCounter_label=null] - Text to be displayed in the `charCounter` area of the bottom bar.
146
+ * ```js
147
+ * { charCounter_label: 'Characters :' }
148
+ * ```
136
149
  * @property {"char"|"byte"|"byte-html"} [charCounter_type="char"] - Defines the calculation method of the `charCounter` option.
137
150
  * - `char`: Characters length.
138
151
  * - `byte`: Binary data size of characters.
139
152
  * - `byte-html`: Binary data size of the full HTML string.
140
- *
141
153
  */
142
154
 
143
155
  /** ================================================================================================================================ */
@@ -206,9 +218,11 @@ export const DEFAULTS = {
206
218
  * - 'a|img|p|div|...' (REQUIRED + DEFAULT)
207
219
  * - 2. If options are given directly, the final pattern is:
208
220
  * - 'a|img|custom|tags' (REQUIRED + options.__defaultElementWhitelist)
209
- * @property {string} [__defaultAttributeWhitelist=CONSTANTS.ATTRIBUTE_WHITELIST] - A complete list of attributes that are allowed by default on all tags.
210
- * - Delimiter: "|" (e.g. "href|target").
221
+ * @property {string} [__defaultAttributeWhitelist=CONSTANTS.ATTRIBUTE_WHITELIST] - A complete list of attributes that are allowed by default on all tags. Delimiter: `"|"`.
211
222
  * - The default follows {@link DEFAULTS.ATTRIBUTE_WHITELIST}
223
+ * ```js
224
+ * { __defaultAttributeWhitelist: 'href|target|src|alt|class' }
225
+ * ```
212
226
  * ///
213
227
  *
214
228
  * === Formatting ===
@@ -230,7 +244,13 @@ export const DEFAULTS = {
230
244
  * - For example, when changing the font size or color of a list item (`<li>`),
231
245
  * - these styles apply to the `<li>` tag instead of wrapping content in additional tags.
232
246
  * @property {{pluginName: string, we: boolean}|boolean} [__pluginRetainFilter=true] - Plugin retain filter configuration. (Internal use primarily)
233
- * - You can turn it off/on globally with `true`/`false` or set it per plugin. (e.g. { table: false })
247
+ * - You can turn it off/on globally with `true`/`false` or set it per plugin.
248
+ * ```js
249
+ * // disable filter for table plugin only
250
+ * {
251
+ * __pluginRetainFilter: { table: false }
252
+ * }
253
+ * ```
234
254
  */
235
255
 
236
256
  /**
@@ -241,16 +261,30 @@ export const DEFAULTS = {
241
261
  * -----------------
242
262
  *
243
263
  * === Plugins & Toolbar ===
244
- * @property {Object<string, *>|Array<Object<string, *>>} [plugins] - Plugin configuration.
245
- * @property {Array<string>} [excludedPlugins=[]] - Plugin configuration.
264
+ * @property {Object<string, *>|Array<Object<string, *>>} [plugins] - Plugin configuration. Pass an array of plugin classes or an object keyed by plugin name.
265
+ * ```js
266
+ * import plugins, { image, link, table } from 'suneditor/src/plugins';
267
+ * { plugins: plugins,
268
+ * plugins: [image, link, table],
269
+ * plugins: { image, link, table }
270
+ * }
271
+ * ```
272
+ * @property {Array<string>} [excludedPlugins=[]] - List of plugin names to exclude.
273
+ * ```js
274
+ * { excludedPlugins: ['image', 'video'] }
275
+ * ```
246
276
  * @property {SunEditor.UI.ButtonList} [buttonList=CONSTANTS.BUTTON_LIST] - List of toolbar buttons, grouped by sub-arrays.
247
277
  * - The default follows {@link DEFAULTS.BUTTON_LIST}
248
278
  * ///
249
279
  *
250
280
  * === Modes & Themes ===
251
281
  * @property {boolean} [v2Migration=false] - Enables migration mode for SunEditor v2.
252
- * @property {"classic"|"inline"|"balloon"|"balloon-always"} [mode="classic"] - Toolbar mode: `classic`, `inline`, `balloon`, `balloon-always`.
253
- * @property {string} [type=""] - Editor type: `document:header,page`.
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`).
283
+ * @property {string} [type=""] - Editor type. Use `"document"` for a document-style layout, with optional sub-types after `:`.
284
+ * ```js
285
+ * // type
286
+ * 'document:header,page'
287
+ * ```
254
288
  * @property {string} [theme=""] - Editor theme.
255
289
  * @property {Object<string, string>} [lang] - Language configuration. default : EN
256
290
  * @property {Object<string, string>} [icons] - Overrides the default icons.
@@ -277,6 +311,19 @@ export const DEFAULTS = {
277
311
  * - `textStyleTagFilter`: Filters text style tags (b, i, u, span, etc.)
278
312
  * - `attrFilter`: Filters disallowed HTML attributes (`attributeWhitelist`/`attributeBlacklist`)
279
313
  * - `styleFilter`: Filters disallowed inline styles (`spanStyles`/`lineStyles`/`allUsedStyles`)
314
+ * ```js
315
+ * // disable only attribute and style filters
316
+ * {
317
+ * strictMode: {
318
+ * tagFilter: true,
319
+ * formatFilter: true,
320
+ * classFilter: true,
321
+ * textStyleTagFilter: true,
322
+ * attrFilter: false,
323
+ * styleFilter: false
324
+ * }
325
+ * }
326
+ * ```
280
327
  * @property {Array<string>} [scopeSelectionTags=CONSTANTS.SCOPE_SELECTION_TAGS] - Tags treated as whole units when selecting all content.
281
328
  * - The default follows {@link DEFAULTS.SCOPE_SELECTION_TAGS}
282
329
  * ///
@@ -284,12 +331,16 @@ export const DEFAULTS = {
284
331
  * === Content Filtering & Formatting ===
285
332
  * ==
286
333
  * #### 1) Tag & Element Control
287
- * @property {string} [elementWhitelist=""] - Specifies HTML elements to additionally allow beyond the default allow list.
288
- * - Delimiter: "|" (e.g. "p|div", "*").
334
+ * @property {string} [elementWhitelist=""] - Specifies HTML elements to additionally allow beyond the default allow list. Delimiter: `"|"`.
289
335
  * - Added to the default list determined by {@link PrivateBaseOptions.__defaultElementWhitelist}.
290
- * @property {string} [elementBlacklist=""] - Specifies HTML elements that should not be used.
291
- * - Delimiter: "|" (e.g. "script|style").
336
+ * ```js
337
+ * { elementWhitelist: 'mark|details|summary' }
338
+ * ```
339
+ * @property {string} [elementBlacklist=""] - Specifies HTML elements that should not be used. Delimiter: `"|"`.
292
340
  * - Tags specified here will eventually be removed, even if they are included in other whitelists.
341
+ * ```js
342
+ * { elementBlacklist: 'script|style|iframe' }
343
+ * ```
293
344
  * @property {string} [allowedEmptyTags=CONSTANTS.ALLOWED_EMPTY_NODE_LIST] - A list of tags that are allowed to be kept even if their values are empty.
294
345
  * - The default follows {@link DEFAULTS.ALLOWED_EMPTY_NODE_LIST}
295
346
  * - Concatenated with `ALLOWED_EMPTY_NODE_LIST` to form the final `allowedEmptyTags` list.
@@ -298,22 +349,52 @@ export const DEFAULTS = {
298
349
  * ///
299
350
  *
300
351
  * #### 2) Attribute Control
301
- * @property {{[key: string]: string|undefined}} [attributeWhitelist=null] - Specifies additional attributes to allow for each tag.
302
- * - (e.g. {a: "href|target", img: "src|alt", "*": "id"})
352
+ * @property {{[key: string]: string|undefined}} [attributeWhitelist=null] - Specifies additional attributes to allow for each tag. `"*"` applies to all tags.
303
353
  * - Rules specified here will be merged into {@link PrivateBaseOptions.__defaultAttributeWhitelist}.
304
- * @property {{[key: string]: string|undefined}} [attributeBlacklist=null] - Specifies attributes to disallow by tag.
305
- * - (e.g. {a: "href|target", img: "src|alt", "*": "name"})
354
+ * ```js
355
+ * {
356
+ * attributeWhitelist: {
357
+ * a: 'href|target',
358
+ * img: 'src|alt',
359
+ * '*': 'id|data-*'
360
+ * }
361
+ * }
362
+ * ```
363
+ * @property {{[key: string]: string|undefined}} [attributeBlacklist=null] - Specifies attributes to disallow by tag. `"*"` applies to all tags.
306
364
  * - Attributes specified here will eventually be removed even if they are allowed by other settings.
307
365
  * - A list of required elements, {@link DEFAULTS.REQUIRED_FORMAT_LINE}, is always included.
366
+ * ```js
367
+ * { attributeBlacklist: { '*': 'onclick|onerror' } }
368
+ * ```
308
369
  * ///
309
370
  *
310
371
  * #### 3) Text & Inline Style Control
311
372
  * @property {string} [textStyleTags=__textStyleTags] - Additional text style tags.
312
373
  * - The default follows {@link PrivateBaseOptions.__textStyleTags}
313
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.
314
- * @property {string} [allUsedStyles] - Specifies additional styles to the list of allowed styles.
315
- * - Delimiter: "|" (e.g. "color|background-color").
316
- * @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags.
375
+ * ```js
376
+ * {
377
+ * convertTextTags: {
378
+ * bold: 'b',
379
+ * italic: 'i',
380
+ * underline: 'u',
381
+ * strike: 's'
382
+ * }
383
+ * }
384
+ * ```
385
+ * @property {string} [allUsedStyles] - Specifies additional styles to the list of allowed styles. Delimiter: `"|"`.
386
+ * ```js
387
+ * { allUsedStyles: 'color|background-color|text-shadow' }
388
+ * ```
389
+ * @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags. Key is tag name(s), value is pipe-delimited allowed styles.
390
+ * ```js
391
+ * {
392
+ * tagStyles: {
393
+ * 'table|td': 'border|color|background-color',
394
+ * hr: 'border-top'
395
+ * }
396
+ * }
397
+ * ```
317
398
  * @property {string} [spanStyles=CONSTANTS.SPAN_STYLES] - Specifies allowed styles for the `span` tag.
318
399
  * - The default follows {@link DEFAULTS.SPAN_STYLES}
319
400
  * @property {string} [lineStyles=CONSTANTS.LINE_STYLES] - Specifies allowed styles for the `line` element (p..).
@@ -338,14 +419,23 @@ export const DEFAULTS = {
338
419
  * - Formats that include `line`, such as "Quote", still operate on a `line` basis.
339
420
  * - suneditor processes work in `line` units.
340
421
  * - When set to `br`, performance may decrease when editing a lot of data.
341
- * @property {string} [lineAttrReset=""] - Line properties that should be reset when changing lines (e.g. "id|name").
342
- * @property {string} [formatLine=__defaultFormatLine] - Additionally allowed `line` elements beyond the default. Delimiter: "|" (e.g. "p|div").
422
+ * @property {string} [lineAttrReset=""] - Line properties that should be reset when changing lines. Delimiter: `"|"`.
423
+ * ```js
424
+ * { lineAttrReset: 'id|name' }
425
+ * ```
426
+ * @property {string} [formatLine=__defaultFormatLine] - Additionally allowed `line` elements beyond the default. Delimiter: `"|"`.
343
427
  * - Concatenated with {@link PrivateBaseOptions.__defaultFormatLine} to form the final `line` list.
344
428
  * - `line` element also contains `brLine` element.
345
- * @property {string} [formatBrLine=__defaultFormatBrLine] - Additionally allowed `brLine` elements beyond the default. (e.g. "PRE").
429
+ * ```js
430
+ * { formatLine: 'ARTICLE|SECTION' }
431
+ * ```
432
+ * @property {string} [formatBrLine=__defaultFormatBrLine] - Additionally allowed `brLine` elements beyond the default.
346
433
  * - Concatenated with {@link PrivateBaseOptions.__defaultFormatBrLine} to form the final `brLine` list.
347
434
  * - `brLine` elements are included in the `line` element.
348
435
  * - `brLine` elements' line break is `BR` tag.
436
+ * ```js
437
+ * { formatBrLine: 'CODE' }
438
+ * ```
349
439
  * - ※ Entering the Enter key on the last line ends `brLine` and appends `line`.
350
440
  * @property {string} [formatClosureBrLine=__defaultFormatClosureBrLine] - Additionally allowed `closureBrLine` elements beyond the default.
351
441
  * - Concatenated with {@link PrivateBaseOptions.__defaultFormatClosureBrLine} for the final `closureBrLine` list.
@@ -372,14 +462,28 @@ export const DEFAULTS = {
372
462
  * @property {?HTMLElement} [toolbar_container] - Container element for the toolbar.
373
463
  * @property {number} [toolbar_sticky=0] - Enables sticky toolbar with optional offset.
374
464
  * @property {boolean} [toolbar_hide=false] - Hides toolbar initially.
375
- * @property {Object} [subToolbar={}] - Sub-toolbar configuration.
465
+ * @property {Object} [subToolbar={}] - Sub-toolbar configuration. A secondary toolbar that appears on text selection.
376
466
  * @property {SunEditor.UI.ButtonList} [subToolbar.buttonList] - List of Sub-toolbar buttons, grouped by sub-arrays.
377
467
  * @property {"balloon"|"balloon-always"} [subToolbar.mode="balloon"] - Sub-toolbar mode: `balloon`, `balloon-always`.
378
468
  * @property {string} [subToolbar.width="auto"] - Sub-toolbar width.
469
+ * ```js
470
+ * { subToolbar: { buttonList: [['bold', 'italic', 'link']], mode: 'balloon' } }
471
+ * ```
379
472
  * @property {?HTMLElement} [statusbar_container] - Container element for the status bar.
380
473
  * @property {boolean} [shortcutsHint=true] - Displays shortcut hints in tooltips.
381
474
  * @property {boolean} [shortcutsDisable=false] - Disables keyboard shortcuts.
382
475
  * @property {{[key: string]: Array<string>|undefined}} [shortcuts={}] - Custom keyboard shortcuts.
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.
479
+ * ```js
480
+ * {
481
+ * shortcuts: {
482
+ * bold: ['c+KeyB', 'B'],
483
+ * _h1: ['c+s+Digit1+$~blockStyle.applyHeaderByShortcut', '']
484
+ * }
485
+ * }
486
+ * ```
383
487
  * ///
384
488
  *
385
489
  * === Advanced Features ===
@@ -388,10 +492,14 @@ export const DEFAULTS = {
388
492
  * - Default: `Boolean(plugins.link)` — determined by whether the `link` plugin is enabled.
389
493
  * @property {Array<string>} [autoStyleify=["bold", "underline", "italic", "strike"]] - Styles applied automatically on text input.
390
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.
391
496
  * @property {string} [printClass=""] - Class name for printing.
392
497
  * @property {number} [fullScreenOffset=0] - Offset applied when entering fullscreen mode.
393
- * @property {?string} [previewTemplate=null] - Custom template for preview mode.
394
- * @property {?string} [printTemplate=null] - Custom template for print mode.
498
+ * @property {?string} [previewTemplate=null] - Custom HTML template for preview mode. Use `{{ contents }}` as a placeholder for editor content.
499
+ * @property {?string} [printTemplate=null] - Custom HTML template for print mode. Use `{{ contents }}` as a placeholder for editor content.
500
+ * ```js
501
+ * { previewTemplate: '<div class="my-preview"><h1>Preview</h1>{{ contents }}</div>' }
502
+ * ```
395
503
  * @property {SunEditor.ComponentInsertType} [componentInsertBehavior="auto"] - Enables automatic selection of inserted components.
396
504
  * - For inline components: places cursor near the component, or selects if no nearby range.
397
505
  * - For block components: executes behavior based on `selectMode`:
@@ -400,18 +508,48 @@ export const DEFAULTS = {
400
508
  * - `line`: Move cursor to the next line if possible, or create a new line and move there.
401
509
  * - `none`: Do nothing.
402
510
  * @property {?string} [defaultUrlProtocol=null] - Default URL protocol for links.
403
- * @property {Object<"copy", number>} [toastMessageTime={copy: 1500}] - {"copy": 1500} - Duration for displaying toast messages.
511
+ * @property {Object<"copy", number>} [toastMessageTime={copy: 1500}] - Duration for displaying toast messages (ms).
404
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
+ * ///
405
518
  *
406
519
  * === Dynamic Options ===
407
- * @property {Object<string, *>} [externalLibs] - External libraries like CodeMirror or MathJax.
520
+ * @property {Object<string, *>} [externalLibs] - External libraries like CodeMirror, KaTeX, or MathJax.
408
521
  * - See {@link https://github.com/ARA-developer/suneditor/blob/develop/guide/external-libraries.md External Libraries Guide}
409
- * @property {Object<string, boolean>} [allowedExtraTags=CONSTANTS.EXTRA_TAG_MAP] - Specifies extra allowed or disallowed tags.
522
+ * ```js
523
+ * {
524
+ * externalLibs: {
525
+ * katex: window.katex,
526
+ * codeMirror: { src: CodeMirror }
527
+ * }
528
+ * }
529
+ * ```
530
+ * @property {Object<string, boolean>} [allowedExtraTags=CONSTANTS.EXTRA_TAG_MAP] - Specifies extra allowed or disallowed tags. `true` to allow, `false` to disallow.
410
531
  * - The default follows {@link DEFAULTS.EXTRA_TAG_MAP}
532
+ * ```js
533
+ * {
534
+ * allowedExtraTags: {
535
+ * script: false,
536
+ * style: false,
537
+ * mark: true
538
+ * }
539
+ * }
540
+ * ```
411
541
  * ///
412
542
  *
413
543
  * === User Events ===
414
- * @property {SunEditor.Event.Handlers} [events] - User event handlers configuration
544
+ * @property {SunEditor.Event.Handlers} [events] - User event handlers configuration.
545
+ * ```js
546
+ * {
547
+ * events: {
548
+ * onChange: (content) => console.log(content),
549
+ * onImageUploadBefore: (files, info) => true
550
+ * }
551
+ * }
552
+ * ```
415
553
  * ///
416
554
  *
417
555
  * === [ Plugin-Specific Options ] ===
@@ -421,6 +559,7 @@ export const DEFAULTS = {
421
559
  * @property {import('../../plugins/browser/audioGallery.js').AudioGalleryPluginOptions} [audioGallery]
422
560
  * @property {import('../../plugins/dropdown/backgroundColor.js').BackgroundColorPluginOptions} [backgroundColor]
423
561
  * @property {import('../../plugins/dropdown/blockStyle.js').BlockStylePluginOptions} [blockStyle]
562
+ * @property {import('../../plugins/command/codeBlock.js').CodeBlockPluginOptions} [codeBlock]
424
563
  * @property {import('../../plugins/modal/drawing.js').DrawingPluginOptions} [drawing]
425
564
  * @property {import('../../plugins/modal/embed.js').EmbedPluginOptions} [embed]
426
565
  * @property {import('../../plugins/command/exportPDF.js').ExportPDFPluginOptions} [exportPDF]
@@ -480,7 +619,6 @@ export const DEFAULTS = {
480
619
  * @property {*} [codeMirror] - CodeMirror configuration object from `externalLibs.codeMirror`.
481
620
  * @property {boolean} [codeMirrorEditor] - Whether CodeMirror is available (base-level flag). Frame-level stores the actual CM instance.
482
621
  * @property {boolean} [hasCodeMirror] - Uses CodeMirror for code view.
483
- *
484
622
  * @property {Set<string>} [allUsedStyles] - Processed set of all allowed CSS styles.
485
623
  * - Converted from user's `string` input ("|" delimited) to `Set<string>` in constructor.
486
624
  */
@@ -566,6 +704,7 @@ export const OPTION_FIXED_FLAG = {
566
704
  textDirection: true,
567
705
  reverseButtons: 'fixed',
568
706
  historyStackDelayTime: true,
707
+ historyStackSize: 'fixed',
569
708
  lineAttrReset: true,
570
709
  printClass: true,
571
710
  defaultLine: 'fixed',
@@ -606,6 +745,8 @@ export const OPTION_FIXED_FLAG = {
606
745
  toastMessageTime: true,
607
746
  icons: 'fixed',
608
747
  freeCodeViewMode: true,
748
+ finder_panel: 'fixed',
749
+ finder_liveSearch: true,
609
750
  __lineFormatFilter: true,
610
751
  __pluginRetainFilter: true,
611
752
  __listCommonStyle: 'fixed',
@@ -115,6 +115,9 @@ function Constructor(editorTargets, options) {
115
115
  toolbar.style.width = o.get('toolbar_width');
116
116
  toolbar.appendChild(dom.utils.createElement('DIV', { class: 'se-arrow' }));
117
117
  }
118
+ if (o.get('_toolbar_bottom')) {
119
+ toolbar.className += ' se-toolbar-bottom';
120
+ }
118
121
 
119
122
  /** --- subToolbar --------------------------------------------------------------- */
120
123
  if (optionMap.subButtons) {
@@ -180,20 +183,36 @@ function Constructor(editorTargets, options) {
180
183
  // root key
181
184
  const key = editTarget.key || null;
182
185
 
183
- // code view - wrapper
184
- const codeWrapper = dom.utils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
185
- codeWrapper.style.setProperty('display', 'none', 'important');
186
- editor_div.appendChild(codeWrapper);
187
-
188
- // check code mirror
189
- const codeMirrorEl = _checkCodeMirror(o, to, textarea);
190
- // not used code mirror
191
- if (textarea === codeMirrorEl) {
192
- // add line nubers
193
- const codeNumbers = dom.utils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
194
- codeWrapper.insertBefore(codeNumbers, textarea);
195
- } else {
196
- textarea = codeMirrorEl;
186
+ // code view - wrapper (only created when codeView button exists)
187
+ let codeWrapper = null;
188
+ if (o.get('buttons').has('codeView')) {
189
+ codeWrapper = dom.utils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
190
+ codeWrapper.style.setProperty('display', 'none', 'important');
191
+ editor_div.appendChild(codeWrapper);
192
+
193
+ // check code mirror
194
+ const codeMirrorEl = _checkCodeMirror(o, to, textarea);
195
+ // not used code mirror
196
+ if (textarea === codeMirrorEl) {
197
+ // add line nubers
198
+ const codeNumbers = dom.utils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
199
+ codeWrapper.insertBefore(codeNumbers, textarea);
200
+ } else {
201
+ textarea = codeMirrorEl;
202
+ }
203
+ }
204
+
205
+ // markdown view - wrapper (only created when markdownView button exists)
206
+ let markdownWrapper = null;
207
+ let markdownTextarea = null;
208
+ if (o.get('buttons').has('markdownView')) {
209
+ markdownTextarea = initElements.markdownView;
210
+ const markdownNumbers = dom.utils.createElement('TEXTAREA', { class: 'se-markdown-view-line', readonly: 'true' }, null);
211
+ markdownWrapper = dom.utils.createElement('DIV', { class: 'se-markdown-wrapper' });
212
+ markdownWrapper.appendChild(markdownNumbers);
213
+ markdownWrapper.appendChild(markdownTextarea);
214
+ markdownWrapper.style.setProperty('display', 'none', 'important');
215
+ editor_div.appendChild(markdownWrapper);
197
216
  }
198
217
 
199
218
  // document type
@@ -216,7 +235,10 @@ function Constructor(editorTargets, options) {
216
235
  // set container
217
236
  top_div.appendChild(container);
218
237
  rootKeys.push(key);
219
- frameRoots.set(key, CreateFrameContext({ target: editTarget.target, key: editTarget.key, options: to }, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, documentTypeInner, key));
238
+ frameRoots.set(
239
+ key,
240
+ CreateFrameContext({ target: editTarget.target, key: editTarget.key, options: to }, top_div, wysiwyg_div, codeWrapper, textarea, markdownWrapper, markdownTextarea, default_status_bar || statusbar, documentTypeInner, key),
241
+ );
220
242
  }
221
243
  /** frame - root set - end -------------------------------------------------------------- */
222
244
 
@@ -232,8 +254,14 @@ function Constructor(editorTargets, options) {
232
254
  toolbar_container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
233
255
  } else {
234
256
  const rootContainer = frameRoots.get(rootId).get('container');
235
- rootContainer.insertBefore(toolbar, rootContainer.firstElementChild);
236
- if (subbar) rootContainer.insertBefore(subbar, rootContainer.firstElementChild);
257
+ if (o.get('_toolbar_bottom')) {
258
+ const statusbar = rootContainer.querySelector('.se-statusbar');
259
+ rootContainer.insertBefore(toolbar, statusbar);
260
+ if (subbar) rootContainer.insertBefore(subbar, toolbar);
261
+ } else {
262
+ rootContainer.insertBefore(toolbar, rootContainer.firstElementChild);
263
+ if (subbar) rootContainer.insertBefore(subbar, rootContainer.firstElementChild);
264
+ }
237
265
  }
238
266
 
239
267
  return {
@@ -395,9 +423,13 @@ export function InitOptions(options, editorTargets, plugins) {
395
423
  ...(typeof options.strictMode === 'boolean' ? {} : options.strictMode),
396
424
  });
397
425
  o.set('freeCodeViewMode', !!options.freeCodeViewMode);
426
+ o.set('finder_panel', options.finder_panel !== false);
427
+ o.set('finder_liveSearch', options.finder_liveSearch !== false);
398
428
  o.set('__lineFormatFilter', options.__lineFormatFilter ?? true);
399
429
  o.set('__pluginRetainFilter', options.__pluginRetainFilter ?? true);
400
- o.set('mode', options.mode || 'classic'); // classic, inline, balloon, balloon-always
430
+ const [modeBase, modePart] = (options.mode || 'classic').split(':');
431
+ o.set('mode', modeBase); // classic, inline, balloon, balloon-always
432
+ o.set('_toolbar_bottom', modePart === 'bottom' && /^(classic|inline)$/i.test(modeBase));
401
433
  o.set('type', options.type?.split(':')[0] || ''); // document:header,page
402
434
  o.set('theme', options.theme || '');
403
435
  o.set('_themeClass', options.theme ? ` se-theme-${options.theme}` : '');
@@ -506,6 +538,7 @@ export function InitOptions(options, editorTargets, plugins) {
506
538
 
507
539
  // etc
508
540
  o.set('historyStackDelayTime', typeof options.historyStackDelayTime === 'number' ? options.historyStackDelayTime : 400);
541
+ o.set('historyStackSize', typeof options.historyStackSize === 'number' && options.historyStackSize > 0 ? options.historyStackSize : 100);
509
542
  o.set('_editableClass', 'sun-editor-editable' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') + (o.get('type') === 'document' ? ' se-type-document-editable-a4' : ''));
510
543
  o.set('lineAttrReset', ['id'].concat(options.lineAttrReset && typeof options.lineAttrReset === 'string' ? options.lineAttrReset.toLowerCase().split('|') : []));
511
544
  o.set('printClass', typeof options.printClass === 'string' ? options.printClass + ' ' + o.get('_editableClass') : null);
@@ -624,6 +657,7 @@ export function InitOptions(options, editorTargets, plugins) {
624
657
  indent: ['c+BracketRight', ']'],
625
658
  outdent: ['c+BracketLeft', '['],
626
659
  save: ['c+KeyS', 'S'],
660
+ ...(o.get('finder_panel') ? { finder: ['c+KeyF', 'F'] } : {}),
627
661
  // plugins
628
662
  link: ['c+KeyK', 'K'],
629
663
  hr: ['!+---+=+~shortcut', ''],
@@ -844,7 +878,7 @@ function InitFrameOptions(o, origin) {
844
878
  * @param {Map<string, *>} options - Options
845
879
  * @param {HTMLElement} topDiv - Top div
846
880
  * @param {SunEditor.FrameOptions} targetOptions - `editor.frameOptions`
847
- * @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, placeholder: HTMLElement}}
881
+ * @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, markdownView: HTMLElement, placeholder: HTMLElement}}
848
882
  */
849
883
  function _initTargetElements(key, options, topDiv, targetOptions) {
850
884
  const editorStyles = targetOptions.get('_defaultStyles');
@@ -900,6 +934,10 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
900
934
 
901
935
  // textarea for code view
902
936
  const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
937
+
938
+ // textarea for markdown view
939
+ const markdownTextarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-markdown-viewer', style: editorStyles.frame });
940
+
903
941
  const placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
904
942
  if (targetOptions.get('placeholder')) {
905
943
  placeholder.textContent = targetOptions.get('placeholder');
@@ -909,6 +947,7 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
909
947
  bottomBar: CreateStatusbar(targetOptions, null),
910
948
  wysiwygFrame: wysiwygDiv,
911
949
  codeView: textarea,
950
+ markdownView: markdownTextarea,
912
951
  placeholder: placeholder,
913
952
  };
914
953
  }
@@ -929,7 +968,7 @@ function _checkCodeMirror(options, targetOptions, textarea) {
929
968
  mode: 'htmlmixed',
930
969
  htmlMode: true,
931
970
  lineNumbers: true,
932
- lineWrapping: true,
971
+ lineWrapping: false,
933
972
  },
934
973
  codeMirror.options || {},
935
974
  ].reduce((init, option) => {
@@ -1038,6 +1077,7 @@ function _defaultButtons(isRTL, icons, lang) {
1038
1077
  fullScreen: ['se-code-view-enabled se-component-enabled', lang.fullScreen, 'fullScreen', '', icons.expansion],
1039
1078
  showBlocks: ['', lang.showBlocks, 'showBlocks', '', icons.show_blocks],
1040
1079
  codeView: ['se-code-view-enabled se-component-enabled', lang.codeView, 'codeView', '', icons.code_view],
1080
+ markdownView: ['se-code-view-enabled se-component-enabled', lang.markdownView, 'markdownView', '', icons.markdown_view],
1041
1081
  undo: ['se-component-enabled', lang.undo, 'undo', '', icons.undo],
1042
1082
  redo: ['se-component-enabled', lang.redo, 'redo', '', icons.redo],
1043
1083
  preview: ['se-component-enabled', lang.preview, 'preview', '', icons.preview],
@@ -1046,6 +1086,7 @@ function _defaultButtons(isRTL, icons, lang) {
1046
1086
  dir: ['', lang[isRTL ? 'dir_ltr' : 'dir_rtl'], 'dir', '', icons[isRTL ? 'dir_ltr' : 'dir_rtl']],
1047
1087
  dir_ltr: ['', lang.dir_ltr, 'dir_ltr', '', icons.dir_ltr],
1048
1088
  dir_rtl: ['', lang.dir_rtl, 'dir_rtl', '', icons.dir_rtl],
1089
+ finder: ['se-component-enabled', lang.find, 'finder', '', icons.finder],
1049
1090
  save: ['se-component-enabled', lang.save, 'save', '', icons.save],
1050
1091
  newDocument: ['se-component-enabled', lang.newDocument, 'newDocument', '', icons.new_document],
1051
1092
  selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all],
@@ -183,7 +183,7 @@ class DocumentType {
183
183
  const pages = [];
184
184
 
185
185
  for (let i = 0; i < pageBreaks.length; i++) {
186
- pages.push({ number: i, top: pageBreaks[i].offsetTop + pageBreakHeight / 2 - scrollTop });
186
+ pages.push({ number: i, top: pageBreaks[i].offsetTop + pageBreakHeight / 2 });
187
187
  }
188
188
 
189
189
  this.#mirrorCache = 0;
@@ -489,7 +489,7 @@ class DocumentType {
489
489
  if (!force) this.#selection.setRange(c, 0, c, 0);
490
490
  const scrollTop = i === 0 && isScrollable ? 0 : c.offsetTop - this.#page.offsetTop - c.offsetHeight + globalTop;
491
491
  this._applyPageScroll(scrollTop, () => {
492
- if (this.#toolbar.isSticky) {
492
+ if (this.#toolbar.isSticky && !this.#store.mode.isBottom) {
493
493
  this._getDisplayPage().scrollTo({ top: scrollTop - this.#context.get('toolbar_main').offsetHeight, behavior: 'smooth' });
494
494
  }
495
495
  });
package/src/events.js CHANGED
@@ -312,6 +312,17 @@ function onBeforeShowController(params) {}
312
312
  */
313
313
  function onToggleCodeView(params) {}
314
314
 
315
+ /**
316
+ * @callback
317
+ * @description Fired when the editor switches between WYSIWYG view and markdown view.
318
+ * The `is` parameter indicates whether markdown view is now active (`true`) or WYSIWYG view is active (`false`).
319
+ * @param {Object} params
320
+ * @param {SunEditor.Deps} params.$ - Kernel dependencies
321
+ * @param {SunEditor.FrameContext} params.frameContext - frame context
322
+ * @param {boolean} params.is - markdown view status
323
+ */
324
+ function onToggleMarkdownView(params) {}
325
+
315
326
  /**
316
327
  * @callback
317
328
  * @description Fired when the editor enters or exits fullscreen mode.
@@ -859,6 +870,7 @@ function onEmbedDeleteBefore(params) {
859
870
  * @property {?onShowController} [onShowController]
860
871
  * @property {?onBeforeShowController} [onBeforeShowController]
861
872
  * @property {?onToggleCodeView} [onToggleCodeView]
873
+ * @property {?onToggleMarkdownView} [onToggleMarkdownView]
862
874
  * @property {?onToggleFullScreen} [onToggleFullScreen]
863
875
  * @property {?onResizeEditor} [onResizeEditor]
864
876
  * @property {?onSetToolbarButtons} [onSetToolbarButtons]
@@ -43,7 +43,7 @@ export async function write(content) {
43
43
 
44
44
  try {
45
45
  await navigator.clipboard.write([
46
- /* eslint-disable-next-line compat/compat */
46
+ // eslint-disable-next-line compat/compat
47
47
  new ClipboardItem({
48
48
  'text/html': new Blob([htmlString], { type: 'text/html' }),
49
49
  'text/plain': new Blob([plainText], { type: 'text/plain' }),