suneditor 3.0.2 → 3.0.3
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.
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +1 -1
- package/src/assets/suneditor.css +2 -1
- package/src/core/event/eventOrchestrator.js +29 -3
- package/src/core/event/ports.js +2 -2
- package/src/core/logic/dom/html.js +8 -0
- package/src/core/logic/dom/offset.js +1 -1
- package/src/core/logic/dom/selection.js +1 -1
- package/src/core/logic/panel/finder.js +1 -1
- package/src/core/logic/panel/toolbar.js +49 -7
- package/src/core/logic/panel/viewer.js +1 -1
- package/src/core/schema/options.js +19 -3
- package/src/core/section/constructor.js +14 -1
- package/src/modules/manager/ApiManager.js +1 -0
- package/types/core/event/ports.d.ts +1 -1
- package/types/core/schema/options.d.ts +52 -5
package/package.json
CHANGED
package/src/assets/suneditor.css
CHANGED
|
@@ -916,13 +916,13 @@
|
|
|
916
916
|
.sun-editor .se-toolbar.se-toolbar-bottom {
|
|
917
917
|
top: auto;
|
|
918
918
|
bottom: 0;
|
|
919
|
-
outline-offset: -1px;
|
|
920
919
|
}
|
|
921
920
|
|
|
922
921
|
/* Bottom toolbar: more layer opens above buttons */
|
|
923
922
|
.sun-editor .se-toolbar.se-toolbar-bottom .se-btn-tray {
|
|
924
923
|
display: flex;
|
|
925
924
|
flex-wrap: wrap;
|
|
925
|
+
padding: 4px 3px;
|
|
926
926
|
}
|
|
927
927
|
|
|
928
928
|
.sun-editor .se-toolbar.se-toolbar-bottom .se-btn-tray > .se-toolbar-more-layer {
|
|
@@ -934,6 +934,7 @@
|
|
|
934
934
|
.sun-editor .se-toolbar.se-toolbar-bottom .se-toolbar-more-layer .se-more-layer {
|
|
935
935
|
border-top: none;
|
|
936
936
|
border-bottom: 1px solid var(--se-main-divider-color);
|
|
937
|
+
margin-bottom: 4px;
|
|
937
938
|
}
|
|
938
939
|
|
|
939
940
|
/* JS fallback sticky for bottom */
|
|
@@ -138,6 +138,21 @@ class EventOrchestrator extends KernelInjector {
|
|
|
138
138
|
}, 250);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* @description Toggle toolbar-balloon with delay (debounced for selectionchange).
|
|
143
|
+
*/
|
|
144
|
+
#toggleToolbarBalloonDelay() {
|
|
145
|
+
if (this.#balloonDelay) {
|
|
146
|
+
_w.clearTimeout(this.#balloonDelay);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.#balloonDelay = _w.setTimeout(() => {
|
|
150
|
+
_w.clearTimeout(this.#balloonDelay);
|
|
151
|
+
this.#balloonDelay = null;
|
|
152
|
+
this._toggleToolbarBalloon();
|
|
153
|
+
}, 250);
|
|
154
|
+
}
|
|
155
|
+
|
|
141
156
|
/**
|
|
142
157
|
* @internal
|
|
143
158
|
* @description Show or hide the toolbar-balloon.
|
|
@@ -909,17 +924,23 @@ class EventOrchestrator extends KernelInjector {
|
|
|
909
924
|
}
|
|
910
925
|
|
|
911
926
|
#OnResize_viewport() {
|
|
912
|
-
if (isMobile && this.#options.get('
|
|
927
|
+
if (isMobile && this.#options.get('_toolbar_sticky') > -1) {
|
|
913
928
|
this.#toolbar._resetSticky();
|
|
914
929
|
this.#menu.__restoreMenuPosition();
|
|
915
930
|
}
|
|
916
931
|
|
|
917
932
|
this.#scrollContainer();
|
|
933
|
+
|
|
934
|
+
const prevHeight = this.#store.get('currentViewportHeight');
|
|
918
935
|
this.__setViewportSize();
|
|
936
|
+
|
|
937
|
+
if (isMobile && prevHeight > 0 && prevHeight - _w.visualViewport.height > 100 && this.#store.get('hasFocus')) {
|
|
938
|
+
this.$.selection.scrollTo(this.$.selection.getRange(), { behavior: 'auto', block: 'nearest', inline: 'nearest' });
|
|
939
|
+
}
|
|
919
940
|
}
|
|
920
941
|
|
|
921
942
|
#OnScroll_window() {
|
|
922
|
-
if (this.#options.get('
|
|
943
|
+
if (this.#options.get('_toolbar_sticky') > -1) {
|
|
923
944
|
this.#toolbar._resetSticky();
|
|
924
945
|
}
|
|
925
946
|
|
|
@@ -938,7 +959,7 @@ class EventOrchestrator extends KernelInjector {
|
|
|
938
959
|
}
|
|
939
960
|
|
|
940
961
|
#OnMobileScroll_viewport() {
|
|
941
|
-
if (this.#options.get('
|
|
962
|
+
if (this.#options.get('_toolbar_sticky') > -1) {
|
|
942
963
|
this.#toolbar._resetSticky();
|
|
943
964
|
this.#menu.__restoreMenuPosition();
|
|
944
965
|
}
|
|
@@ -959,6 +980,11 @@ class EventOrchestrator extends KernelInjector {
|
|
|
959
980
|
this.$.selection.init();
|
|
960
981
|
this.applyTagEffect();
|
|
961
982
|
|
|
983
|
+
// balloon toolbar - touch devices
|
|
984
|
+
if (isTouchDevice && (this.#store.mode.isBalloon || this.#store.mode.isSubBalloon)) {
|
|
985
|
+
this.#toggleToolbarBalloonDelay();
|
|
986
|
+
}
|
|
987
|
+
|
|
962
988
|
// document type
|
|
963
989
|
if (root.has('documentType_use_header')) {
|
|
964
990
|
const el = dom.query.getParentElement(this.$.selection.selectionNode, this.$.format.isLine.bind(this.$.format));
|
package/src/core/event/ports.js
CHANGED
|
@@ -158,14 +158,14 @@ export function makePorts(inst, { _styleNodes }) {
|
|
|
158
158
|
|
|
159
159
|
// === enter event specific ===
|
|
160
160
|
/**
|
|
161
|
-
* @description Scrolls the editor view to the caret position after pressing `Enter`.
|
|
161
|
+
* @description Scrolls the editor view to the caret position after pressing `Enter`.
|
|
162
162
|
* @param {Range} range Range object
|
|
163
163
|
*/
|
|
164
164
|
enterScrollTo(range) {
|
|
165
165
|
ui._iframeAutoHeight(frameContext);
|
|
166
166
|
|
|
167
167
|
// scroll to
|
|
168
|
-
if (isMobile && inst.scrollparents.length > 0) return;
|
|
168
|
+
// if (isMobile && inst.scrollparents.length > 0) return;
|
|
169
169
|
selection.scrollTo(range, { behavior: 'auto', block: 'nearest', inline: 'nearest' });
|
|
170
170
|
},
|
|
171
171
|
/**
|
|
@@ -2134,6 +2134,14 @@ function _isSafeURL(url) {
|
|
|
2134
2134
|
return _SAFE_URL_PROTOCOL.test(normalized) || !_RE_COLON.test(normalized);
|
|
2135
2135
|
}
|
|
2136
2136
|
|
|
2137
|
+
/**
|
|
2138
|
+
* @description Checks whether an HTML attribute string is safe from XSS injection.
|
|
2139
|
+
* - Non-URL attributes (anything other than `href` or `src`) are always safe.
|
|
2140
|
+
* - For URL attributes, extracts the URL value and delegates to {@link _isSafeURL}
|
|
2141
|
+
* to verify the protocol against the allowed whitelist.
|
|
2142
|
+
* @param {string} attr A single attribute string (e.g. `href="https://example.com"`, `class="foo"`)
|
|
2143
|
+
* @returns {boolean} `true` if the attribute is safe, `false` if it contains a dangerous URL protocol.
|
|
2144
|
+
*/
|
|
2137
2145
|
function _isSafeAttribute(attr) {
|
|
2138
2146
|
if (!_URL_ATTR_PATTERN.test(attr)) return true;
|
|
2139
2147
|
|
|
@@ -503,7 +503,7 @@ class Offset {
|
|
|
503
503
|
const th = this.#context.get('toolbar_main').offsetHeight;
|
|
504
504
|
const containerToolbar = this.#options.get('toolbar_container');
|
|
505
505
|
const headLess = this.#store.mode.isBalloon || this.#store.mode.isInline || containerToolbar;
|
|
506
|
-
const toolbarH = (containerToolbar && globalTop - wScrollY - th > 0) || (!this.#$.toolbar.isSticky && headLess) ? 0 : th + (this.#$.toolbar.isSticky ? this.#options.get('
|
|
506
|
+
const toolbarH = (containerToolbar && globalTop - wScrollY - th > 0) || (!this.#$.toolbar.isSticky && headLess) ? 0 : th + (this.#$.toolbar.isSticky ? this.#options.get('_toolbar_sticky') : 0);
|
|
507
507
|
const statusBarH = this.#frameContext.get('statusbar')?.offsetHeight || 0;
|
|
508
508
|
|
|
509
509
|
// check margin
|
|
@@ -425,7 +425,7 @@ class Selection_ {
|
|
|
425
425
|
const isBottom = this.#store.mode.isBottom;
|
|
426
426
|
const realToolbarHeight = this.#context.get('toolbar_main').offsetHeight;
|
|
427
427
|
const toolbarHeight = this.#$.toolbar.isSticky ? realToolbarHeight : 0;
|
|
428
|
-
const positionToolbarHeight = this.#$.toolbar.isSticky ? toolbarHeight + this.#options.get('
|
|
428
|
+
const positionToolbarHeight = this.#$.toolbar.isSticky ? toolbarHeight + this.#options.get('_toolbar_sticky') : toolbarHeight;
|
|
429
429
|
const statusbarHeight = this.#frameContext.get('statusbar')?.offsetHeight || 0;
|
|
430
430
|
|
|
431
431
|
if (this.#hasScrollParents) {
|
|
@@ -154,7 +154,7 @@ class Finder {
|
|
|
154
154
|
*/
|
|
155
155
|
#updateStickyTop() {
|
|
156
156
|
if (!this.#isOpen || !this.#panel) return;
|
|
157
|
-
const stickyTop = this.#$.options.get('
|
|
157
|
+
const stickyTop = this.#$.options.get('_toolbar_sticky');
|
|
158
158
|
if (this.#store.mode.isBottom) {
|
|
159
159
|
this.#panel.style.top = 'auto';
|
|
160
160
|
this.#panel.style.bottom = stickyTop >= 0 ? stickyTop + this.#$.context.get('toolbar_main').offsetHeight + 'px' : '0px';
|
|
@@ -28,6 +28,7 @@ class Toolbar {
|
|
|
28
28
|
|
|
29
29
|
#useCSSSticky = false;
|
|
30
30
|
#_isStickyFlag = false;
|
|
31
|
+
#_cssStickyShifted = false;
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* @constructor
|
|
@@ -88,7 +89,7 @@ class Toolbar {
|
|
|
88
89
|
|
|
89
90
|
// CSS sticky: non-balloon, non-inline, non-container, sticky enabled
|
|
90
91
|
const isStickyPosible = !this.isSub && !balloon && !inline;
|
|
91
|
-
const stickyTop = this.#options.get('
|
|
92
|
+
const stickyTop = this.#options.get('_toolbar_sticky');
|
|
92
93
|
|
|
93
94
|
this.#useCSSSticky = isStickyPosible && stickyTop >= 0 && !this.#options.get('toolbar_container') && typeof CSS !== 'undefined' && CSS.supports('position', 'sticky');
|
|
94
95
|
|
|
@@ -119,14 +120,15 @@ class Toolbar {
|
|
|
119
120
|
*/
|
|
120
121
|
get isSticky() {
|
|
121
122
|
if (this.isSub) return false;
|
|
122
|
-
const stickyTop = this.#options.get('
|
|
123
|
+
const stickyTop = this.#options.get('_toolbar_sticky');
|
|
123
124
|
if (stickyTop < 0) return false;
|
|
124
125
|
|
|
125
126
|
if (this.#useCSSSticky) {
|
|
126
127
|
const toolbar = this.#context.get(this.keyName.main);
|
|
127
128
|
if (!toolbar || toolbar.offsetWidth === 0 || toolbar.style.display === 'none') return false;
|
|
128
129
|
if (this.isBottomMode) {
|
|
129
|
-
|
|
130
|
+
const viewportHeight = this.#isViewPortSize ? _w.visualViewport.height : _w.innerHeight;
|
|
131
|
+
return toolbar.getBoundingClientRect().bottom >= viewportHeight - stickyTop - 1;
|
|
130
132
|
}
|
|
131
133
|
return toolbar.getBoundingClientRect().top <= stickyTop + 1;
|
|
132
134
|
}
|
|
@@ -254,13 +256,16 @@ class Toolbar {
|
|
|
254
256
|
* @description Reset the sticky toolbar position based on the editor state.
|
|
255
257
|
*/
|
|
256
258
|
_resetSticky() {
|
|
257
|
-
if (this.#useCSSSticky)
|
|
259
|
+
if (this.#useCSSSticky) {
|
|
260
|
+
this.#resetCSSStickyOffset();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
258
263
|
|
|
259
264
|
const wrapper = this.#frameContext.get('wrapper');
|
|
260
265
|
if (!wrapper) return;
|
|
261
266
|
|
|
262
267
|
const toolbar = this.#context.get(this.keyName.main);
|
|
263
|
-
const stickyTop = this.#options.get('
|
|
268
|
+
const stickyTop = this.#options.get('_toolbar_sticky');
|
|
264
269
|
if (this.#frameContext.get('isFullScreen') || toolbar.offsetWidth === 0 || stickyTop < 0) return;
|
|
265
270
|
|
|
266
271
|
const currentScrollY = this.#isViewPortSize ? _w.visualViewport.pageTop : _w.scrollY;
|
|
@@ -485,11 +490,11 @@ class Toolbar {
|
|
|
485
490
|
}
|
|
486
491
|
|
|
487
492
|
if (this.isBottomMode) {
|
|
488
|
-
const toolbarBottomPosition = this.#options.get('
|
|
493
|
+
const toolbarBottomPosition = this.#options.get('_toolbar_sticky') + this.#getViewportTop();
|
|
489
494
|
toolbar.style.bottom = `${toolbarBottomPosition}px`;
|
|
490
495
|
toolbar.style.top = 'auto';
|
|
491
496
|
} else {
|
|
492
|
-
const toolbarTopPosition = this.#options.get('
|
|
497
|
+
const toolbarTopPosition = this.#options.get('_toolbar_sticky') + inlineOffset + this.#getViewportTop();
|
|
493
498
|
toolbar.style.top = `${toolbarTopPosition}px`;
|
|
494
499
|
}
|
|
495
500
|
toolbar.style.width = this.isInlineMode ? this.inlineToolbarAttr.width : toolbar.offsetWidth + 'px';
|
|
@@ -508,6 +513,43 @@ class Toolbar {
|
|
|
508
513
|
return 0;
|
|
509
514
|
}
|
|
510
515
|
|
|
516
|
+
/**
|
|
517
|
+
* @description Adjust CSS sticky toolbar position when the mobile virtual keyboard changes the visual viewport.
|
|
518
|
+
*/
|
|
519
|
+
#resetCSSStickyOffset() {
|
|
520
|
+
if (!this.#isViewPortSize) return;
|
|
521
|
+
// When the editor is inside a scrollable container (e.g., modal),
|
|
522
|
+
// position:sticky is relative to that container, not the viewport.
|
|
523
|
+
if (this.#kernel._eventOrchestrator.scrollparents.length > 0) return;
|
|
524
|
+
|
|
525
|
+
const viewportOffset = Math.round(_w.visualViewport.offsetTop);
|
|
526
|
+
if (viewportOffset === 0 && !this.#_cssStickyShifted) return;
|
|
527
|
+
|
|
528
|
+
const toolbar = this.#context.get(this.keyName.main);
|
|
529
|
+
const stickyOffset = this.#options.get('_toolbar_sticky_offset');
|
|
530
|
+
|
|
531
|
+
if (viewportOffset > 0) {
|
|
532
|
+
this.#_cssStickyShifted = true;
|
|
533
|
+
if (this.isBottomMode) {
|
|
534
|
+
const viewportBottom = Math.round(_w.innerHeight - _w.visualViewport.height - viewportOffset);
|
|
535
|
+
toolbar.style.bottom = stickyOffset + viewportBottom + 'px';
|
|
536
|
+
toolbar.style.top = 'auto';
|
|
537
|
+
} else {
|
|
538
|
+
toolbar.style.top = stickyOffset + viewportOffset + 'px';
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
541
|
+
// restore original CSS sticky value
|
|
542
|
+
this.#_cssStickyShifted = false;
|
|
543
|
+
const stickyTop = this.#options.get('_toolbar_sticky');
|
|
544
|
+
if (this.isBottomMode) {
|
|
545
|
+
toolbar.style.bottom = stickyTop + 'px';
|
|
546
|
+
toolbar.style.top = 'auto';
|
|
547
|
+
} else {
|
|
548
|
+
toolbar.style.top = stickyTop > 0 ? stickyTop + 'px' : '';
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
511
553
|
/**
|
|
512
554
|
* @description Disable `sticky` toolbar mode.
|
|
513
555
|
*/
|
|
@@ -460,7 +460,22 @@ export const DEFAULTS = {
|
|
|
460
460
|
* @property {boolean} [tabDisable=false] - Disables tab key input.
|
|
461
461
|
* @property {string} [toolbar_width="auto"] - Toolbar width.
|
|
462
462
|
* @property {?HTMLElement} [toolbar_container] - Container element for the toolbar.
|
|
463
|
-
* @property {number} [toolbar_sticky=0] - Enables sticky toolbar
|
|
463
|
+
* @property {number|{top: number, offset: number}} [toolbar_sticky=0] - Enables sticky toolbar.
|
|
464
|
+
* - `number`: Sets the sticky top position (px). Use `-1` to disable sticky.
|
|
465
|
+
* - `{top, offset}`: `top` is the sticky position when the page header is visible.
|
|
466
|
+
* - `offset` is the sticky position when a virtual keyboard shifts the viewport (e.g., on tablets, touch devices).
|
|
467
|
+
* - When the virtual keyboard is active, `offset` replaces `top` so the toolbar doesn't leave a gap
|
|
468
|
+
* - for a page header that has scrolled out of view. Default `offset` is `0`.
|
|
469
|
+
* ```js
|
|
470
|
+
* // Basic usage — sticky at top with 0px offset
|
|
471
|
+
* toolbar_sticky: 0
|
|
472
|
+
*
|
|
473
|
+
* // Account for a 92px fixed/sticky site header
|
|
474
|
+
* toolbar_sticky: 92
|
|
475
|
+
*
|
|
476
|
+
* // 92px header on desktop, but 0px when virtual keyboard pushes the viewport
|
|
477
|
+
* toolbar_sticky: { top: 92, offset: 0 }
|
|
478
|
+
* ```
|
|
464
479
|
* @property {boolean} [toolbar_hide=false] - Hides toolbar initially.
|
|
465
480
|
* @property {Object} [subToolbar={}] - Sub-toolbar configuration. A secondary toolbar that appears on text selection.
|
|
466
481
|
* @property {SunEditor.UI.ButtonList} [subToolbar.buttonList] - List of Sub-toolbar buttons, grouped by sub-arrays.
|
|
@@ -754,7 +769,7 @@ export const OPTION_FIXED_FLAG = {
|
|
|
754
769
|
};
|
|
755
770
|
|
|
756
771
|
/**
|
|
757
|
-
* @typedef {'formatClosureBrLine' | 'formatBrLine' | 'formatLine' | 'formatClosureBlock' | 'formatBlock' | 'toolbar_width' | 'toolbar_container' | '
|
|
772
|
+
* @typedef {'formatClosureBrLine' | 'formatBrLine' | 'formatLine' | 'formatClosureBlock' | 'formatBlock' | 'toolbar_width' | 'toolbar_container' | '_toolbar_sticky' | '_toolbar_sticky_offset' | 'strictMode' | 'lineAttrReset'} TransformedOptionKeys
|
|
758
773
|
*/
|
|
759
774
|
|
|
760
775
|
/**
|
|
@@ -776,7 +791,8 @@ export const OPTION_FIXED_FLAG = {
|
|
|
776
791
|
* @property {{ reg: RegExp, str: string }} formatBlock
|
|
777
792
|
* @property {string} toolbar_width
|
|
778
793
|
* @property {HTMLElement|null} toolbar_container
|
|
779
|
-
* @property {number}
|
|
794
|
+
* @property {number} _toolbar_sticky
|
|
795
|
+
* @property {number} _toolbar_sticky_offset
|
|
780
796
|
* @property {StrictModeOptions} strictMode
|
|
781
797
|
* @property {string[]} lineAttrReset
|
|
782
798
|
*/
|
|
@@ -616,7 +616,20 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
616
616
|
/** Toolbar */
|
|
617
617
|
o.set('toolbar_width', options.toolbar_width ? (numbers.is(options.toolbar_width) ? options.toolbar_width + 'px' : options.toolbar_width) : 'auto');
|
|
618
618
|
o.set('toolbar_container', options.toolbar_container && !/inline/i.test(o.get('mode')) ? (typeof options.toolbar_container === 'string' ? _d.querySelector(options.toolbar_container) : options.toolbar_container) : null);
|
|
619
|
-
|
|
619
|
+
|
|
620
|
+
const _stickyOpt = options.toolbar_sticky;
|
|
621
|
+
const _isBalloon = /balloon/i.test(o.get('mode'));
|
|
622
|
+
if (_isBalloon) {
|
|
623
|
+
o.set('_toolbar_sticky', -1);
|
|
624
|
+
o.set('_toolbar_sticky_offset', 0);
|
|
625
|
+
} else if (_stickyOpt !== null && typeof _stickyOpt === 'object') {
|
|
626
|
+
o.set('_toolbar_sticky', numbers.get(_stickyOpt.top, 0));
|
|
627
|
+
o.set('_toolbar_sticky_offset', numbers.get(_stickyOpt.offset, 0));
|
|
628
|
+
} else {
|
|
629
|
+
o.set('_toolbar_sticky', _stickyOpt === undefined ? 0 : numbers.is(_stickyOpt) ? _stickyOpt : -1);
|
|
630
|
+
o.set('_toolbar_sticky_offset', 0);
|
|
631
|
+
}
|
|
632
|
+
|
|
620
633
|
o.set('toolbar_hide', !!options.toolbar_hide);
|
|
621
634
|
|
|
622
635
|
/** subToolbar */
|
|
@@ -166,7 +166,7 @@ export function makePorts(
|
|
|
166
166
|
formatAttrsTempCache: (attrs: any) => any;
|
|
167
167
|
setOnShortcutKey: (v: any) => any;
|
|
168
168
|
/**
|
|
169
|
-
* @description Scrolls the editor view to the caret position after pressing `Enter`.
|
|
169
|
+
* @description Scrolls the editor view to the caret position after pressing `Enter`.
|
|
170
170
|
* @param {Range} range Range object
|
|
171
171
|
*/
|
|
172
172
|
enterScrollTo(range: Range): void;
|
|
@@ -406,7 +406,22 @@ export namespace DEFAULTS {
|
|
|
406
406
|
* @property {boolean} [tabDisable=false] - Disables tab key input.
|
|
407
407
|
* @property {string} [toolbar_width="auto"] - Toolbar width.
|
|
408
408
|
* @property {?HTMLElement} [toolbar_container] - Container element for the toolbar.
|
|
409
|
-
* @property {number} [toolbar_sticky=0] - Enables sticky toolbar
|
|
409
|
+
* @property {number|{top: number, offset: number}} [toolbar_sticky=0] - Enables sticky toolbar.
|
|
410
|
+
* - `number`: Sets the sticky top position (px). Use `-1` to disable sticky.
|
|
411
|
+
* - `{top, offset}`: `top` is the sticky position when the page header is visible.
|
|
412
|
+
* - `offset` is the sticky position when a virtual keyboard shifts the viewport (e.g., on tablets, touch devices).
|
|
413
|
+
* - When the virtual keyboard is active, `offset` replaces `top` so the toolbar doesn't leave a gap
|
|
414
|
+
* - for a page header that has scrolled out of view. Default `offset` is `0`.
|
|
415
|
+
* ```js
|
|
416
|
+
* // Basic usage — sticky at top with 0px offset
|
|
417
|
+
* toolbar_sticky: 0
|
|
418
|
+
*
|
|
419
|
+
* // Account for a 92px fixed/sticky site header
|
|
420
|
+
* toolbar_sticky: 92
|
|
421
|
+
*
|
|
422
|
+
* // 92px header on desktop, but 0px when virtual keyboard pushes the viewport
|
|
423
|
+
* toolbar_sticky: { top: 92, offset: 0 }
|
|
424
|
+
* ```
|
|
410
425
|
* @property {boolean} [toolbar_hide=false] - Hides toolbar initially.
|
|
411
426
|
* @property {Object} [subToolbar={}] - Sub-toolbar configuration. A secondary toolbar that appears on text selection.
|
|
412
427
|
* @property {SunEditor.UI.ButtonList} [subToolbar.buttonList] - List of Sub-toolbar buttons, grouped by sub-arrays.
|
|
@@ -1201,9 +1216,29 @@ export type EditorBaseOptions = {
|
|
|
1201
1216
|
*/
|
|
1202
1217
|
toolbar_container?: HTMLElement | null;
|
|
1203
1218
|
/**
|
|
1204
|
-
* - Enables sticky toolbar
|
|
1219
|
+
* - Enables sticky toolbar.
|
|
1220
|
+
* - `number`: Sets the sticky top position (px). Use `-1` to disable sticky.
|
|
1221
|
+
* - `{top, offset}`: `top` is the sticky position when the page header is visible.
|
|
1222
|
+
* - `offset` is the sticky position when a virtual keyboard shifts the viewport (e.g., on tablets, touch devices).
|
|
1223
|
+
* - When the virtual keyboard is active, `offset` replaces `top` so the toolbar doesn't leave a gap
|
|
1224
|
+
* - for a page header that has scrolled out of view. Default `offset` is `0`.
|
|
1225
|
+
* ```js
|
|
1226
|
+
* // Basic usage — sticky at top with 0px offset
|
|
1227
|
+
* toolbar_sticky: 0
|
|
1228
|
+
*
|
|
1229
|
+
* // Account for a 92px fixed/sticky site header
|
|
1230
|
+
* toolbar_sticky: 92
|
|
1231
|
+
*
|
|
1232
|
+
* // 92px header on desktop, but 0px when virtual keyboard pushes the viewport
|
|
1233
|
+
* toolbar_sticky: { top: 92, offset: 0 }
|
|
1234
|
+
* ```
|
|
1205
1235
|
*/
|
|
1206
|
-
toolbar_sticky?:
|
|
1236
|
+
toolbar_sticky?:
|
|
1237
|
+
| number
|
|
1238
|
+
| {
|
|
1239
|
+
top: number;
|
|
1240
|
+
offset: number;
|
|
1241
|
+
};
|
|
1207
1242
|
/**
|
|
1208
1243
|
* - Hides toolbar initially.
|
|
1209
1244
|
*/
|
|
@@ -1513,7 +1548,18 @@ export type InternalBaseOptions = {
|
|
|
1513
1548
|
};
|
|
1514
1549
|
export type EditorInitOptions = EditorBaseOptions & PrivateBaseOptions & EditorFrameOptions;
|
|
1515
1550
|
export type AllBaseOptions = EditorBaseOptions & PrivateBaseOptions & InternalBaseOptions;
|
|
1516
|
-
export type TransformedOptionKeys =
|
|
1551
|
+
export type TransformedOptionKeys =
|
|
1552
|
+
| 'formatClosureBrLine'
|
|
1553
|
+
| 'formatBrLine'
|
|
1554
|
+
| 'formatLine'
|
|
1555
|
+
| 'formatClosureBlock'
|
|
1556
|
+
| 'formatBlock'
|
|
1557
|
+
| 'toolbar_width'
|
|
1558
|
+
| 'toolbar_container'
|
|
1559
|
+
| '_toolbar_sticky'
|
|
1560
|
+
| '_toolbar_sticky_offset'
|
|
1561
|
+
| 'strictMode'
|
|
1562
|
+
| 'lineAttrReset';
|
|
1517
1563
|
export type StrictModeOptions = {
|
|
1518
1564
|
/**
|
|
1519
1565
|
* - Filters disallowed HTML tags (`elementWhitelist`/`elementBlacklist`)
|
|
@@ -1563,7 +1609,8 @@ export type TransformedOptions = {
|
|
|
1563
1609
|
};
|
|
1564
1610
|
toolbar_width: string;
|
|
1565
1611
|
toolbar_container: HTMLElement | null;
|
|
1566
|
-
|
|
1612
|
+
_toolbar_sticky: number;
|
|
1613
|
+
_toolbar_sticky_offset: number;
|
|
1567
1614
|
strictMode: StrictModeOptions;
|
|
1568
1615
|
lineAttrReset: string[];
|
|
1569
1616
|
};
|