@ckeditor/ckeditor5-ui
Advanced tools
Comparing version 0.0.0-nightly-20230908.0 to 0.0.0-nightly-20230909.0
{ | ||
"name": "@ckeditor/ckeditor5-ui", | ||
"version": "0.0.0-nightly-20230908.0", | ||
"version": "0.0.0-nightly-20230909.0", | ||
"description": "The UI framework and standard UI library of CKEditor 5.", | ||
@@ -14,4 +14,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-core": "0.0.0-nightly-20230908.0", | ||
"@ckeditor/ckeditor5-utils": "0.0.0-nightly-20230908.0", | ||
"@ckeditor/ckeditor5-core": "0.0.0-nightly-20230909.0", | ||
"@ckeditor/ckeditor5-utils": "0.0.0-nightly-20230909.0", | ||
"color-convert": "2.0.1", | ||
@@ -18,0 +18,0 @@ "color-parse": "1.4.2", |
@@ -131,3 +131,3 @@ /** | ||
if (this.panelPosition === 'auto') { | ||
this.panelView.position = DropdownView._getOptimalPosition({ | ||
const optimalPanelPosition = DropdownView._getOptimalPosition({ | ||
element: this.panelView.element, | ||
@@ -137,3 +137,4 @@ target: this.buttonView.element, | ||
positions: this._panelPositions | ||
}).name; | ||
}); | ||
this.panelView.position = (optimalPanelPosition ? optimalPanelPosition.name : this._panelPositions[0].name); | ||
} | ||
@@ -140,0 +141,0 @@ else { |
@@ -5,3 +5,3 @@ /** | ||
*/ | ||
import { Rect, DomEmitterMixin, findClosestScrollableAncestor, verifyLicense } from '@ckeditor/ckeditor5-utils'; | ||
import { DomEmitterMixin, Rect, verifyLicense } from '@ckeditor/ckeditor5-utils'; | ||
import BalloonPanelView from '../panel/balloon/balloonpanelview'; | ||
@@ -19,10 +19,2 @@ import IconView from '../icon/iconview'; | ||
const DEFAULT_LABEL = 'Powered by'; | ||
const OFF_THE_SCREEN_POSITION = { | ||
top: -99999, | ||
left: -99999, | ||
name: 'invalid', | ||
config: { | ||
withArrow: false | ||
} | ||
}; | ||
/** | ||
@@ -240,10 +232,6 @@ * A helper that enables the "powered by" feature in the editor and renders a link to the project's | ||
function getLowerCornerPosition(focusedEditableElement, config, getBalloonLeft) { | ||
return (editableElementRect, balloonRect) => { | ||
const visibleEditableElementRect = editableElementRect.getVisible(); | ||
// Root cropped by ancestors. | ||
if (!visibleEditableElementRect) { | ||
return OFF_THE_SCREEN_POSITION; | ||
} | ||
return (visibleEditableElementRect, balloonRect) => { | ||
const editableElementRect = new Rect(focusedEditableElement); | ||
if (editableElementRect.width < NARROW_ROOT_WIDTH_THRESHOLD || editableElementRect.height < NARROW_ROOT_HEIGHT_THRESHOLD) { | ||
return OFF_THE_SCREEN_POSITION; | ||
return null; | ||
} | ||
@@ -259,24 +247,13 @@ let balloonTop; | ||
const balloonLeft = getBalloonLeft(editableElementRect, balloonRect); | ||
if (config.position === 'inside') { | ||
const newBalloonRect = balloonRect.clone().moveTo(balloonLeft, balloonTop); | ||
// The watermark cannot be positioned in this corner because the corner is not quite visible. | ||
if (newBalloonRect.getIntersectionArea(visibleEditableElementRect) < newBalloonRect.getArea()) { | ||
return OFF_THE_SCREEN_POSITION; | ||
} | ||
// Clone the editable element rect and place it where the balloon would be placed. | ||
// This will allow getVisible() to work from editable element's perspective (rect source). | ||
// and yield a result as if the balloon was on the same (scrollable) layer as the editable element. | ||
const newBalloonPositionRect = visibleEditableElementRect | ||
.clone() | ||
.moveTo(balloonLeft, balloonTop) | ||
.getIntersection(balloonRect.clone().moveTo(balloonLeft, balloonTop)); | ||
const newBalloonPositionVisibleRect = newBalloonPositionRect.getVisible(); | ||
if (!newBalloonPositionVisibleRect || newBalloonPositionVisibleRect.getArea() < balloonRect.getArea()) { | ||
return null; | ||
} | ||
else { | ||
const firstScrollableEditableElementAncestor = findClosestScrollableAncestor(focusedEditableElement); | ||
if (firstScrollableEditableElementAncestor) { | ||
const firstScrollableEditableElementAncestorRect = new Rect(firstScrollableEditableElementAncestor); | ||
const notVisibleVertically = visibleEditableElementRect.bottom + balloonRect.height / 2 > | ||
firstScrollableEditableElementAncestorRect.bottom; | ||
const notVisibleHorizontally = config.side === 'left' ? | ||
editableElementRect.left < firstScrollableEditableElementAncestorRect.left : | ||
editableElementRect.right > firstScrollableEditableElementAncestorRect.right; | ||
// The watermark cannot be positioned in this corner because the corner is "not visible enough". | ||
if (notVisibleVertically || notVisibleHorizontally) { | ||
return OFF_THE_SCREEN_POSITION; | ||
} | ||
} | ||
} | ||
return { | ||
@@ -283,0 +260,0 @@ top: balloonTop, |
@@ -14,2 +14,18 @@ /** | ||
const defaultLimiterElement = global.document.body; | ||
// A static balloon panel positioning function that moves the balloon far off the viewport. | ||
// It is used as a fallback when there is no way to position the balloon using provided | ||
// positioning functions (see: `getOptimalPosition()`), for instance, when the target the | ||
// balloon should be attached to gets obscured by scrollable containers or the viewport. | ||
// | ||
// It prevents the balloon from being attached to the void and possible degradation of the UX. | ||
// At the same time, it keeps the balloon physically visible in the DOM so the focus remains | ||
// uninterrupted. | ||
const POSITION_OFF_SCREEN = { | ||
top: -99999, | ||
left: -99999, | ||
name: 'arrowless', | ||
config: { | ||
withArrow: false | ||
} | ||
}; | ||
/** | ||
@@ -157,3 +173,3 @@ * The balloon panel view class. | ||
}, options); | ||
const optimalPosition = BalloonPanelView._getOptimalPosition(positionOptions); | ||
const optimalPosition = BalloonPanelView._getOptimalPosition(positionOptions) || POSITION_OFF_SCREEN; | ||
// Usually browsers make some problems with super accurate values like 104.345px | ||
@@ -958,8 +974,14 @@ // so it is better to use int values. | ||
// ------- Sticky | ||
viewportStickyNorth: (targetRect, balloonRect, viewportRect) => { | ||
if (!targetRect.getIntersection(viewportRect)) { | ||
viewportStickyNorth: (targetRect, balloonRect, viewportRect, limiterRect) => { | ||
const boundaryRect = limiterRect || viewportRect; | ||
if (!targetRect.getIntersection(boundaryRect)) { | ||
return null; | ||
} | ||
// Engage when the target top and bottom edges are close or off the boundary. | ||
// By close, it means there's not enough space for the balloon arrow (offset). | ||
if (boundaryRect.height - targetRect.height > stickyVerticalOffset) { | ||
return null; | ||
} | ||
return { | ||
top: viewportRect.top + stickyVerticalOffset, | ||
top: boundaryRect.top + stickyVerticalOffset, | ||
left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2, | ||
@@ -966,0 +988,0 @@ name: 'arrowless', |
@@ -128,6 +128,4 @@ /** | ||
* Then handles the positioning of the panel. | ||
* | ||
* @param [scrollTarget] The element which is being scrolled. | ||
*/ | ||
checkIfShouldBeSticky(scrollTarget?: HTMLElement | Document): void; | ||
checkIfShouldBeSticky(): void; | ||
/** | ||
@@ -134,0 +132,0 @@ * Sticks the panel at the given CSS `top` offset. |
@@ -10,4 +10,7 @@ /** | ||
import Template from '../../template'; | ||
import { getElementsIntersectionRect, getScrollableAncestors, global, toUnit, Rect } from '@ckeditor/ckeditor5-utils'; | ||
// @if CK_DEBUG_STICKYPANEL // const RectDrawer = require( '@ckeditor/ckeditor5-utils/tests/_utils/rectdrawer' ).default | ||
import { global, toUnit, Rect } from '@ckeditor/ckeditor5-utils'; | ||
// @if CK_DEBUG_STICKYPANEL // const { | ||
// @if CK_DEBUG_STICKYPANEL // default: RectDrawer, | ||
// @if CK_DEBUG_STICKYPANEL // diagonalStylesBlack | ||
// @if CK_DEBUG_STICKYPANEL // } = require( '@ckeditor/ckeditor5-utils/tests/_utils/rectdrawer' ); | ||
import '../../../theme/components/panel/stickypanel.css'; | ||
@@ -93,4 +96,4 @@ const toPx = toUnit('px'); | ||
// Update sticky state of the panel as the window and ancestors are being scrolled. | ||
this.listenTo(global.document, 'scroll', (evt, data) => { | ||
this.checkIfShouldBeSticky(data.target); | ||
this.listenTo(global.document, 'scroll', () => { | ||
this.checkIfShouldBeSticky(); | ||
}, { useCapture: true }); | ||
@@ -105,6 +108,4 @@ // Synchronize with `model.isActive` because sticking an inactive panel is pointless. | ||
* Then handles the positioning of the panel. | ||
* | ||
* @param [scrollTarget] The element which is being scrolled. | ||
*/ | ||
checkIfShouldBeSticky(scrollTarget) { | ||
checkIfShouldBeSticky() { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.clear(); | ||
@@ -115,10 +116,12 @@ if (!this.limiterElement || !this.isActive) { | ||
} | ||
const scrollableAncestors = getScrollableAncestors(this.limiterElement); | ||
if (scrollTarget && !scrollableAncestors.includes(scrollTarget)) { | ||
return; | ||
const limiterRect = new Rect(this.limiterElement); | ||
let visibleLimiterRect = limiterRect.getVisible(); | ||
if (visibleLimiterRect) { | ||
const windowRect = new Rect(global.window); | ||
windowRect.top += this.viewportTopOffset; | ||
windowRect.height -= this.viewportTopOffset; | ||
visibleLimiterRect = visibleLimiterRect.getIntersection(windowRect); | ||
} | ||
const visibleAncestorsRect = getElementsIntersectionRect(scrollableAncestors, this.viewportTopOffset); | ||
const limiterRect = new Rect(this.limiterElement); | ||
// @if CK_DEBUG_STICKYPANEL // if ( visibleAncestorsRect ) { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleAncestorsRect, | ||
// @if CK_DEBUG_STICKYPANEL // if ( visibleLimiterRect ) { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect, | ||
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '3px', opacity: '.8', outlineColor: 'red', outlineOffset: '-3px' }, | ||
@@ -136,44 +139,36 @@ // @if CK_DEBUG_STICKYPANEL // 'Visible anc' | ||
// * and the limiter's top edge is above the visible ancestors' top edge. | ||
if (visibleAncestorsRect && limiterRect.top < visibleAncestorsRect.top) { | ||
const visibleLimiterRect = limiterRect.getIntersection(visibleAncestorsRect); | ||
// Sticky the panel only if the limiter's visible rect is at least partially visible in the | ||
// visible ancestors' rects intersection. | ||
if (visibleLimiterRect) { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect, | ||
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '3px', opacity: '.8', outlineColor: 'fuchsia', outlineOffset: '-3px', | ||
// @if CK_DEBUG_STICKYPANEL // backgroundColor: 'rgba(255, 0, 255, .3)' }, | ||
// @if CK_DEBUG_STICKYPANEL // 'Visible limiter' | ||
if (visibleLimiterRect && limiterRect.top < visibleLimiterRect.top) { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect, | ||
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '3px', opacity: '.8', outlineColor: 'fuchsia', outlineOffset: '-3px', | ||
// @if CK_DEBUG_STICKYPANEL // backgroundColor: 'rgba(255, 0, 255, .3)' }, | ||
// @if CK_DEBUG_STICKYPANEL // 'Visible limiter' | ||
// @if CK_DEBUG_STICKYPANEL // ); | ||
const visibleLimiterTop = visibleLimiterRect.top; | ||
// Check if there's a change the panel can be sticky to the bottom of the limiter. | ||
if (visibleLimiterTop + this._contentPanelRect.height + this.limiterBottomOffset > visibleLimiterRect.bottom) { | ||
const stickyBottomOffset = Math.max(limiterRect.bottom - visibleLimiterRect.bottom, 0) + this.limiterBottomOffset; | ||
// @if CK_DEBUG_STICKYPANEL // const stickyBottomOffsetRect = new Rect( { | ||
// @if CK_DEBUG_STICKYPANEL // top: limiterRect.bottom - stickyBottomOffset, left: 0, right: 2000, | ||
// @if CK_DEBUG_STICKYPANEL // bottom: limiterRect.bottom - stickyBottomOffset, width: 2000, height: 1 | ||
// @if CK_DEBUG_STICKYPANEL // } ); | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( stickyBottomOffsetRect, | ||
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '1px', opacity: '.8', outlineColor: 'black' }, | ||
// @if CK_DEBUG_STICKYPANEL // 'Sticky bottom offset' | ||
// @if CK_DEBUG_STICKYPANEL // ); | ||
const visibleAncestorsTop = visibleAncestorsRect.top; | ||
// Check if there's a change the panel can be sticky to the bottom of the limiter. | ||
if (visibleAncestorsTop + this._contentPanelRect.height + this.limiterBottomOffset > visibleLimiterRect.bottom) { | ||
const stickyBottomOffset = Math.max(limiterRect.bottom - visibleAncestorsRect.bottom, 0) + this.limiterBottomOffset; | ||
// @if CK_DEBUG_STICKYPANEL // const stickyBottomOffsetRect = new Rect( { | ||
// @if CK_DEBUG_STICKYPANEL // top: limiterRect.bottom - stickyBottomOffset, left: 0, right: 2000, | ||
// @if CK_DEBUG_STICKYPANEL // bottom: limiterRect.bottom - stickyBottomOffset, width: 2000, height: 1 | ||
// @if CK_DEBUG_STICKYPANEL // } ); | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( stickyBottomOffsetRect, | ||
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '1px', opacity: '.8', outlineColor: 'black' }, | ||
// @if CK_DEBUG_STICKYPANEL // 'Sticky bottom offset' | ||
// @if CK_DEBUG_STICKYPANEL // ); | ||
// Check if sticking the panel to the bottom of the limiter does not cause it to suddenly | ||
// move upwards if there's not enough space for it. | ||
if (limiterRect.bottom - stickyBottomOffset > limiterRect.top + this._contentPanelRect.height) { | ||
this._stickToBottomOfLimiter(stickyBottomOffset); | ||
} | ||
else { | ||
this._unstick(); | ||
} | ||
// Check if sticking the panel to the bottom of the limiter does not cause it to suddenly | ||
// move upwards if there's not enough space for it. | ||
if (limiterRect.bottom - stickyBottomOffset > limiterRect.top + this._contentPanelRect.height) { | ||
this._stickToBottomOfLimiter(stickyBottomOffset); | ||
} | ||
else { | ||
if (this._contentPanelRect.height + this.limiterBottomOffset < limiterRect.height) { | ||
this._stickToTopOfAncestors(visibleAncestorsTop); | ||
} | ||
else { | ||
this._unstick(); | ||
} | ||
this._unstick(); | ||
} | ||
} | ||
else { | ||
this._unstick(); | ||
if (this._contentPanelRect.height + this.limiterBottomOffset < limiterRect.height) { | ||
this._stickToTopOfAncestors(visibleLimiterTop); | ||
} | ||
else { | ||
this._unstick(); | ||
} | ||
} | ||
@@ -189,2 +184,10 @@ } | ||
// @if CK_DEBUG_STICKYPANEL // console.log( '_stickyBottomOffset', this._stickyBottomOffset ); | ||
// @if CK_DEBUG_STICKYPANEL // if ( visibleLimiterRect ) { | ||
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect, | ||
// @if CK_DEBUG_STICKYPANEL // { ...diagonalStylesBlack, | ||
// @if CK_DEBUG_STICKYPANEL // outlineWidth: '3px', opacity: '.8', outlineColor: 'orange', outlineOffset: '-3px', | ||
// @if CK_DEBUG_STICKYPANEL // backgroundColor: 'rgba(0, 0, 255, .2)' }, | ||
// @if CK_DEBUG_STICKYPANEL // 'visibleLimiterRect' | ||
// @if CK_DEBUG_STICKYPANEL // ); | ||
// @if CK_DEBUG_STICKYPANEL // } | ||
} | ||
@@ -191,0 +194,0 @@ /** |
@@ -10,3 +10,3 @@ /** | ||
import { Plugin, icons } from '@ckeditor/ckeditor5-core'; | ||
import { Rect, ResizeObserver, getOptimalPosition, toUnit } from '@ckeditor/ckeditor5-utils'; | ||
import { Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils'; | ||
import BlockButtonView from './blockbuttonview'; | ||
@@ -338,23 +338,14 @@ import BalloonPanelView from '../../panel/balloon/balloonpanelview'; | ||
const contentLineHeight = parseInt(contentStyles.lineHeight, 10) || parseInt(contentStyles.fontSize, 10) * 1.2; | ||
const position = getOptimalPosition({ | ||
element: this.buttonView.element, | ||
target: targetElement, | ||
positions: [ | ||
(contentRect, buttonRect) => { | ||
let left; | ||
if (this.editor.locale.uiLanguageDirection === 'ltr') { | ||
left = editableRect.left - buttonRect.width; | ||
} | ||
else { | ||
left = editableRect.right; | ||
} | ||
return { | ||
top: contentRect.top + contentPaddingTop + (contentLineHeight - buttonRect.height) / 2, | ||
left | ||
}; | ||
} | ||
] | ||
}); | ||
this.buttonView.top = position.top; | ||
this.buttonView.left = position.left; | ||
const buttonRect = new Rect(this.buttonView.element).toAbsoluteRect(); | ||
const contentRect = new Rect(targetElement).toAbsoluteRect(); | ||
let positionLeft; | ||
if (this.editor.locale.uiLanguageDirection === 'ltr') { | ||
positionLeft = editableRect.left - buttonRect.width; | ||
} | ||
else { | ||
positionLeft = editableRect.right; | ||
} | ||
const positionTop = contentRect.top + contentPaddingTop + (contentLineHeight - buttonRect.height) / 2; | ||
this.buttonView.top = positionTop; | ||
this.buttonView.left = positionLeft; | ||
} | ||
@@ -361,0 +352,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
1033108
20359
+ Added@ckeditor/ckeditor5-core@0.0.0-nightly-20230909.0(transitive)
+ Added@ckeditor/ckeditor5-engine@0.0.0-nightly-20230909.0(transitive)
+ Added@ckeditor/ckeditor5-utils@0.0.0-nightly-20230909.0(transitive)
- Removed@ckeditor/ckeditor5-core@0.0.0-nightly-20230908.0(transitive)
- Removed@ckeditor/ckeditor5-engine@0.0.0-nightly-20230908.0(transitive)
- Removed@ckeditor/ckeditor5-utils@0.0.0-nightly-20230908.0(transitive)