@ckeditor/ckeditor5-utils
Advanced tools
Comparing version 37.0.0-alpha.2 to 37.0.0-alpha.3
{ | ||
"name": "@ckeditor/ckeditor5-utils", | ||
"version": "37.0.0-alpha.2", | ||
"version": "37.0.0-alpha.3", | ||
"description": "Miscellaneous utilities used by CKEditor 5.", | ||
@@ -17,6 +17,6 @@ "keywords": [ | ||
"devDependencies": { | ||
"@ckeditor/ckeditor5-build-classic": "^37.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-editor-classic": "^37.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-core": "^37.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-engine": "^37.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-build-classic": "^37.0.0-alpha.3", | ||
"@ckeditor/ckeditor5-editor-classic": "^37.0.0-alpha.3", | ||
"@ckeditor/ckeditor5-core": "^37.0.0-alpha.3", | ||
"@ckeditor/ckeditor5-engine": "^37.0.0-alpha.3", | ||
"@types/lodash-es": "^4.17.6", | ||
@@ -23,0 +23,0 @@ "typescript": "^4.8.4" |
@@ -5,2 +5,3 @@ /** | ||
*/ | ||
type IfTrue<T> = T extends true ? true : never; | ||
/** | ||
@@ -11,12 +12,47 @@ * Makes any page `HTMLElement` or `Range` (`target`) visible inside the browser viewport. | ||
* | ||
* @param options | ||
* @param options Additional configuration of the scrolling behavior. | ||
* @param options.target A target, which supposed to become visible to the user. | ||
* @param options.viewportOffset An offset from the edge of the viewport (in pixels) | ||
* the `target` will be moved by when the viewport is scrolled. It enhances the user experience | ||
* the `target` will be moved by if the viewport is scrolled. It enhances the user experience | ||
* by keeping the `target` some distance from the edge of the viewport and thus making it easier to | ||
* read or edit by the user. | ||
* @param options.ancestorOffset An offset from the boundary of scrollable ancestors (if any) | ||
* the `target` will be moved by if the viewport is scrolled. It enhances the user experience | ||
* by keeping the `target` some distance from the edge of the ancestors and thus making it easier to | ||
* read or edit by the user. | ||
* @param options.alignToTop When set `true`, the helper will make sure the `target` is scrolled up | ||
* to the top boundary of the viewport and/or scrollable ancestors if scrolled up. When not set | ||
* (default), the `target` will be revealed by scrolling as little as possible. This option will | ||
* not affect `targets` that must be scrolled down because they will appear at the top of the boundary | ||
* anyway. | ||
* | ||
* ``` | ||
* scrollViewportToShowTarget() with scrollViewportToShowTarget() with | ||
* Initial state alignToTop unset (default) alignToTop = true | ||
* | ||
* ┌────────────────────────────────┬─┐ ┌────────────────────────────────┬─┐ ┌────────────────────────────────┬─┐ | ||
* │ │▲│ │ │▲│ │ [ Target to be revealed ] │▲│ | ||
* │ │ │ │ │ │ │ │ │ | ||
* │ │█│ │ │ │ │ │ │ | ||
* │ │█│ │ │ │ │ │ │ | ||
* │ │ │ │ │█│ │ │ │ | ||
* │ │ │ │ │█│ │ │█│ | ||
* │ │ │ │ │ │ │ │█│ | ||
* │ │▼│ │ [ Target to be revealed ] │▼│ │ │▼│ | ||
* └────────────────────────────────┴─┘ └────────────────────────────────┴─┘ └────────────────────────────────┴─┘ | ||
* | ||
* | ||
* [ Target to be revealed ] | ||
*``` | ||
* | ||
* @param options.forceScroll When set `true`, the `target` will be aligned to the top of the viewport | ||
* and scrollable ancestors whether it is already visible or not. This option will only work when `alignToTop` | ||
* is `true` | ||
*/ | ||
export declare function scrollViewportToShowTarget({ target, viewportOffset }: { | ||
export declare function scrollViewportToShowTarget<T extends boolean, U extends IfTrue<T>>({ target, viewportOffset, ancestorOffset, alignToTop, forceScroll }: { | ||
readonly target: HTMLElement | Range; | ||
readonly viewportOffset?: number; | ||
readonly ancestorOffset?: number; | ||
readonly alignToTop?: T; | ||
readonly forceScroll?: U; | ||
}): void; | ||
@@ -28,3 +64,6 @@ /** | ||
* @param target A target, which supposed to become visible to the user. | ||
* @param ancestorOffset An offset between the target and the boundary of scrollable ancestors | ||
* to be maintained while scrolling. | ||
*/ | ||
export declare function scrollAncestorsToShowTarget(target: HTMLElement | Range): void; | ||
export declare function scrollAncestorsToShowTarget(target: HTMLElement | Range, ancestorOffset?: number): void; | ||
export {}; |
@@ -16,10 +16,42 @@ /** | ||
* | ||
* @param options | ||
* @param options Additional configuration of the scrolling behavior. | ||
* @param options.target A target, which supposed to become visible to the user. | ||
* @param options.viewportOffset An offset from the edge of the viewport (in pixels) | ||
* the `target` will be moved by when the viewport is scrolled. It enhances the user experience | ||
* the `target` will be moved by if the viewport is scrolled. It enhances the user experience | ||
* by keeping the `target` some distance from the edge of the viewport and thus making it easier to | ||
* read or edit by the user. | ||
* @param options.ancestorOffset An offset from the boundary of scrollable ancestors (if any) | ||
* the `target` will be moved by if the viewport is scrolled. It enhances the user experience | ||
* by keeping the `target` some distance from the edge of the ancestors and thus making it easier to | ||
* read or edit by the user. | ||
* @param options.alignToTop When set `true`, the helper will make sure the `target` is scrolled up | ||
* to the top boundary of the viewport and/or scrollable ancestors if scrolled up. When not set | ||
* (default), the `target` will be revealed by scrolling as little as possible. This option will | ||
* not affect `targets` that must be scrolled down because they will appear at the top of the boundary | ||
* anyway. | ||
* | ||
* ``` | ||
* scrollViewportToShowTarget() with scrollViewportToShowTarget() with | ||
* Initial state alignToTop unset (default) alignToTop = true | ||
* | ||
* ┌────────────────────────────────┬─┐ ┌────────────────────────────────┬─┐ ┌────────────────────────────────┬─┐ | ||
* │ │▲│ │ │▲│ │ [ Target to be revealed ] │▲│ | ||
* │ │ │ │ │ │ │ │ │ | ||
* │ │█│ │ │ │ │ │ │ | ||
* │ │█│ │ │ │ │ │ │ | ||
* │ │ │ │ │█│ │ │ │ | ||
* │ │ │ │ │█│ │ │█│ | ||
* │ │ │ │ │ │ │ │█│ | ||
* │ │▼│ │ [ Target to be revealed ] │▼│ │ │▼│ | ||
* └────────────────────────────────┴─┘ └────────────────────────────────┴─┘ └────────────────────────────────┴─┘ | ||
* | ||
* | ||
* [ Target to be revealed ] | ||
*``` | ||
* | ||
* @param options.forceScroll When set `true`, the `target` will be aligned to the top of the viewport | ||
* and scrollable ancestors whether it is already visible or not. This option will only work when `alignToTop` | ||
* is `true` | ||
*/ | ||
export function scrollViewportToShowTarget({ target, viewportOffset = 0 }) { | ||
export function scrollViewportToShowTarget({ target, viewportOffset = 0, ancestorOffset = 0, alignToTop, forceScroll }) { | ||
const targetWindow = getWindow(target); | ||
@@ -44,9 +76,15 @@ let currentWindow = targetWindow; | ||
// Scroll the target's ancestors first. Once done, scrolling the viewport is easy. | ||
scrollAncestorsToShowRect(firstAncestorToScroll, () => { | ||
// Note: If the target does not belong to the current window **directly**, | ||
// i.e. it resides in an iframe belonging to the window, obtain the target's rect | ||
// in the coordinates of the current window. By default, a Rect returns geometry | ||
// relative to the current window's viewport. To make it work in a parent window, | ||
// it must be shifted. | ||
return getRectRelativeToWindow(target, currentWindow); | ||
scrollAncestorsToShowRect({ | ||
parent: firstAncestorToScroll, | ||
getRect: () => { | ||
// Note: If the target does not belong to the current window **directly**, | ||
// i.e. it resides in an iframe belonging to the window, obtain the target's rect | ||
// in the coordinates of the current window. By default, a Rect returns geometry | ||
// relative to the current window's viewport. To make it work in a parent window, | ||
// it must be shifted. | ||
return getRectRelativeToWindow(target, currentWindow); | ||
}, | ||
alignToTop, | ||
ancestorOffset, | ||
forceScroll | ||
}); | ||
@@ -56,3 +94,9 @@ // Obtain the rect of the target after it has been scrolled within its ancestors. | ||
const targetRect = getRectRelativeToWindow(target, currentWindow); | ||
scrollWindowToShowRect(currentWindow, targetRect, viewportOffset); | ||
scrollWindowToShowRect({ | ||
window: currentWindow, | ||
rect: targetRect, | ||
viewportOffset, | ||
alignToTop, | ||
forceScroll | ||
}); | ||
if (currentWindow.parent != currentWindow) { | ||
@@ -83,7 +127,11 @@ // Keep the reference to the <iframe> element the "previous current window" was | ||
* @param target A target, which supposed to become visible to the user. | ||
* @param ancestorOffset An offset between the target and the boundary of scrollable ancestors | ||
* to be maintained while scrolling. | ||
*/ | ||
export function scrollAncestorsToShowTarget(target) { | ||
export function scrollAncestorsToShowTarget(target, ancestorOffset) { | ||
const targetParent = getParentElement(target); | ||
scrollAncestorsToShowRect(targetParent, () => { | ||
return new Rect(target); | ||
scrollAncestorsToShowRect({ | ||
parent: targetParent, | ||
getRect: () => new Rect(target), | ||
ancestorOffset | ||
}); | ||
@@ -137,7 +185,15 @@ } | ||
* | ||
* @param window A window which is scrolled to reveal the rect. | ||
* @param rect A rect which is to be revealed. | ||
* @param viewportOffset See scrollViewportToShowTarget. | ||
* @param options Additional configuration of the scrolling behavior. | ||
* @param options.window A window which is scrolled to reveal the rect. | ||
* @param options.rect A rect which is to be revealed. | ||
* @param options.viewportOffset An offset from the edge of the viewport (in pixels) the `rect` will be | ||
* moved by if the viewport is scrolled. | ||
* @param options.alignToTop When set `true`, the helper will make sure the `rect` is scrolled up | ||
* to the top boundary of the viewport if scrolled up. When not set (default), the `rect` will be | ||
* revealed by scrolling as little as possible. This option will not affect rects that must be scrolled | ||
* down because they will appear at the top of the boundary anyway. | ||
* @param options.forceScroll When set `true`, the `rect` will be aligned to the top of the viewport | ||
* whether it is already visible or not. This option will only work when `alignToTop` is `true` | ||
*/ | ||
function scrollWindowToShowRect(window, rect, viewportOffset) { | ||
function scrollWindowToShowRect({ window, rect, alignToTop, forceScroll, viewportOffset }) { | ||
const targetShiftedDownRect = rect.clone().moveBy(0, viewportOffset); | ||
@@ -147,4 +203,11 @@ const targetShiftedUpRect = rect.clone().moveBy(0, -viewportOffset); | ||
const rects = [targetShiftedUpRect, targetShiftedDownRect]; | ||
if (!rects.every(rect => viewportRect.contains(rect))) { | ||
let { scrollX, scrollY } = window; | ||
const forceScrollToTop = alignToTop && forceScroll; | ||
const allRectsFitInViewport = rects.every(rect => viewportRect.contains(rect)); | ||
let { scrollX, scrollY } = window; | ||
const initialScrollX = scrollX; | ||
const initialScrollY = scrollY; | ||
if (forceScrollToTop) { | ||
scrollY -= (viewportRect.top - rect.top) + viewportOffset; | ||
} | ||
else if (!allRectsFitInViewport) { | ||
if (isAbove(targetShiftedUpRect, viewportRect)) { | ||
@@ -154,4 +217,11 @@ scrollY -= viewportRect.top - rect.top + viewportOffset; | ||
else if (isBelow(targetShiftedDownRect, viewportRect)) { | ||
scrollY += rect.bottom - viewportRect.bottom + viewportOffset; | ||
if (alignToTop) { | ||
scrollY += rect.top - viewportRect.top - viewportOffset; | ||
} | ||
else { | ||
scrollY += rect.bottom - viewportRect.bottom + viewportOffset; | ||
} | ||
} | ||
} | ||
if (!allRectsFitInViewport) { | ||
// TODO: Web browsers scroll natively to place the target in the middle | ||
@@ -165,2 +235,4 @@ // of the viewport. It's not a very popular case, though. | ||
} | ||
} | ||
if (scrollX != initialScrollX || scrollY !== initialScrollY) { | ||
window.scrollTo(scrollX, scrollY); | ||
@@ -172,23 +244,45 @@ } | ||
* | ||
* @param parent A parent The first ancestors to start scrolling. | ||
* @param getRect A function which returns the Rect, which is to be revealed. | ||
* @param options Additional configuration of the scrolling behavior. | ||
* @param options.parent The first parent ancestor to start scrolling. | ||
* @param options.getRect A function which returns the Rect, which is to be revealed. | ||
* @param options.ancestorOffset An offset from the boundary of scrollable ancestors (if any) | ||
* the `Rect` instance will be moved by if the viewport is scrolled. | ||
* @param options.alignToTop When set `true`, the helper will make sure the `Rect` instance is scrolled up | ||
* to the top boundary of the scrollable ancestors if scrolled up. When not set (default), the `rect` | ||
* will be revealed by scrolling as little as possible. This option will not affect rects that must be | ||
* scrolled down because they will appear at the top of the boundary | ||
* anyway. | ||
* @param options.forceScroll When set `true`, the `rect` will be aligned to the top of scrollable ancestors | ||
* whether it is already visible or not. This option will only work when `alignToTop` is `true` | ||
*/ | ||
function scrollAncestorsToShowRect(parent, getRect) { | ||
function scrollAncestorsToShowRect({ parent, getRect, alignToTop, forceScroll, ancestorOffset = 0 }) { | ||
const parentWindow = getWindow(parent); | ||
let parentRect, targetRect; | ||
const forceScrollToTop = alignToTop && forceScroll; | ||
let parentRect, targetRect, targetFitsInTarget; | ||
while (parent != parentWindow.document.body) { | ||
targetRect = getRect(); | ||
parentRect = new Rect(parent).excludeScrollbarsAndBorders(); | ||
if (!parentRect.contains(targetRect)) { | ||
targetFitsInTarget = parentRect.contains(targetRect); | ||
if (forceScrollToTop) { | ||
parent.scrollTop -= (parentRect.top - targetRect.top) + ancestorOffset; | ||
} | ||
else if (!targetFitsInTarget) { | ||
if (isAbove(targetRect, parentRect)) { | ||
parent.scrollTop -= parentRect.top - targetRect.top; | ||
parent.scrollTop -= parentRect.top - targetRect.top + ancestorOffset; | ||
} | ||
else if (isBelow(targetRect, parentRect)) { | ||
parent.scrollTop += targetRect.bottom - parentRect.bottom; | ||
if (alignToTop) { | ||
parent.scrollTop += targetRect.top - parentRect.top - ancestorOffset; | ||
} | ||
else { | ||
parent.scrollTop += targetRect.bottom - parentRect.bottom + ancestorOffset; | ||
} | ||
} | ||
} | ||
if (!targetFitsInTarget) { | ||
if (isLeftOf(targetRect, parentRect)) { | ||
parent.scrollLeft -= parentRect.left - targetRect.left; | ||
parent.scrollLeft -= parentRect.left - targetRect.left + ancestorOffset; | ||
} | ||
else if (isRightOf(targetRect, parentRect)) { | ||
parent.scrollLeft += targetRect.right - parentRect.right; | ||
parent.scrollLeft += targetRect.right - parentRect.right + ancestorOffset; | ||
} | ||
@@ -195,0 +289,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
418116
10004