@ckeditor/ckeditor5-ui
Advanced tools
Comparing version 0.0.0-nightly-20240723.0 to 0.0.0-nightly-20240724.0
@@ -141,2 +141,6 @@ /** | ||
/** | ||
* Repositions the button on scroll. | ||
*/ | ||
private _repositionButtonOnScroll; | ||
/** | ||
* Attaches the {@link #buttonView} to the target block of content. | ||
@@ -148,2 +152,12 @@ * | ||
/** | ||
* Clips the button element to the viewport of the editable element. | ||
* | ||
* * If the button overflows the editable viewport, it is clipped to make it look like it's cut off by the editable scrollable region. | ||
* * If the button is fully hidden by the top of the editable, it is not clickable but still visible in the DOM. | ||
* | ||
* @param buttonView The button view to clip. | ||
* @param editableElement The editable element whose viewport is used for clipping. | ||
*/ | ||
private _clipButtonToViewport; | ||
/** | ||
* Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly. | ||
@@ -150,0 +164,0 @@ */ |
{ | ||
"name": "@ckeditor/ckeditor5-ui", | ||
"version": "0.0.0-nightly-20240723.0", | ||
"version": "0.0.0-nightly-20240724.0", | ||
"description": "The UI framework and standard UI library of CKEditor 5.", | ||
@@ -15,4 +15,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-core": "0.0.0-nightly-20240723.0", | ||
"@ckeditor/ckeditor5-utils": "0.0.0-nightly-20240723.0", | ||
"@ckeditor/ckeditor5-core": "0.0.0-nightly-20240724.0", | ||
"@ckeditor/ckeditor5-utils": "0.0.0-nightly-20240724.0", | ||
"color-convert": "2.0.1", | ||
@@ -19,0 +19,0 @@ "color-parse": "1.4.2", |
@@ -137,2 +137,6 @@ /** | ||
/** | ||
* Repositions the button on scroll. | ||
*/ | ||
private _repositionButtonOnScroll; | ||
/** | ||
* Attaches the {@link #buttonView} to the target block of content. | ||
@@ -144,2 +148,12 @@ * | ||
/** | ||
* Clips the button element to the viewport of the editable element. | ||
* | ||
* * If the button overflows the editable viewport, it is clipped to make it look like it's cut off by the editable scrollable region. | ||
* * If the button is fully hidden by the top of the editable, it is not clickable but still visible in the DOM. | ||
* | ||
* @param buttonView The button view to clip. | ||
* @param editableElement The editable element whose viewport is used for clipping. | ||
*/ | ||
private _clipButtonToViewport; | ||
/** | ||
* Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly. | ||
@@ -146,0 +160,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
import { Plugin } from '@ckeditor/ckeditor5-core'; | ||
import { Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils'; | ||
import { global, Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils'; | ||
import BlockButtonView from './blockbuttonview.js'; | ||
@@ -135,2 +135,4 @@ import BalloonPanelView from '../../panel/balloon/balloonpanelview.js'; | ||
}); | ||
// Reposition button on scroll. | ||
this._repositionButtonOnScroll(); | ||
// Register the toolbar so it becomes available for Alt+F10 and Esc navigation. | ||
@@ -334,2 +336,33 @@ editor.ui.addToolbar(this.toolbarView, { | ||
/** | ||
* Repositions the button on scroll. | ||
*/ | ||
_repositionButtonOnScroll() { | ||
const { buttonView } = this; | ||
let pendingAnimationFrame = false; | ||
// Reposition the button on scroll, but do it only once per animation frame to avoid performance issues. | ||
const repositionOnScroll = () => { | ||
if (pendingAnimationFrame) { | ||
return; | ||
} | ||
pendingAnimationFrame = true; | ||
global.window.requestAnimationFrame(() => { | ||
this._updateButton(); | ||
pendingAnimationFrame = false; | ||
}); | ||
}; | ||
// Watch scroll event only when the button is visible, it prevents attaching the scroll event listener | ||
// to the document when the button is not visible. | ||
buttonView.on('change:isVisible', (evt, name, isVisible) => { | ||
if (isVisible) { | ||
buttonView.listenTo(global.document, 'scroll', repositionOnScroll, { | ||
useCapture: true, | ||
usePassive: true | ||
}); | ||
} | ||
else { | ||
buttonView.stopListening(global.document, 'scroll', repositionOnScroll); | ||
} | ||
}); | ||
} | ||
/** | ||
* Attaches the {@link #buttonView} to the target block of content. | ||
@@ -340,4 +373,6 @@ * | ||
_attachButtonToElement(targetElement) { | ||
const buttonElement = this.buttonView.element; | ||
const editableElement = this._getSelectedEditableElement(); | ||
const contentStyles = window.getComputedStyle(targetElement); | ||
const editableRect = new Rect(this._getSelectedEditableElement()); | ||
const editableRect = new Rect(editableElement); | ||
const contentPaddingTop = parseInt(contentStyles.paddingTop, 10); | ||
@@ -347,3 +382,3 @@ // When line height is not an integer then treat it as "normal". | ||
const contentLineHeight = parseInt(contentStyles.lineHeight, 10) || parseInt(contentStyles.fontSize, 10) * 1.2; | ||
const buttonRect = new Rect(this.buttonView.element); | ||
const buttonRect = new Rect(buttonElement); | ||
const contentRect = new Rect(targetElement); | ||
@@ -362,4 +397,49 @@ let positionLeft; | ||
this.buttonView.left = absoluteButtonRect.left; | ||
this._clipButtonToViewport(this.buttonView, editableElement); | ||
} | ||
/** | ||
* Clips the button element to the viewport of the editable element. | ||
* | ||
* * If the button overflows the editable viewport, it is clipped to make it look like it's cut off by the editable scrollable region. | ||
* * If the button is fully hidden by the top of the editable, it is not clickable but still visible in the DOM. | ||
* | ||
* @param buttonView The button view to clip. | ||
* @param editableElement The editable element whose viewport is used for clipping. | ||
*/ | ||
_clipButtonToViewport(buttonView, editableElement) { | ||
const absoluteButtonRect = new Rect(buttonView.element); | ||
const scrollViewportRect = new Rect(editableElement).getVisible(); | ||
// Sets polygon clip path for the button element, if there is no argument provided, the clip path is removed. | ||
const setButtonClipping = (...paths) => { | ||
buttonView.element.style.clipPath = paths.length ? `polygon(${paths.join(',')})` : ''; | ||
}; | ||
// Hide the button if it's fully hidden by the top of the editable. | ||
// Note that the button is still visible in the DOM, but it's not clickable. It's because we don't | ||
// want to hide the button completely, as there are plenty of `isVisible` watchers which toggles | ||
// the button scroll listeners. | ||
const markAsHidden = (isHidden) => { | ||
buttonView.isEnabled = !isHidden; | ||
buttonView.element.style.pointerEvents = isHidden ? 'none' : ''; | ||
}; | ||
if (scrollViewportRect && scrollViewportRect.bottom < absoluteButtonRect.bottom) { | ||
// Calculate the delta between the button bottom and the editable bottom, and clip the button | ||
// to make it look like it's cut off by the editable scrollable region. | ||
const delta = Math.min(absoluteButtonRect.height, absoluteButtonRect.bottom - scrollViewportRect.bottom); | ||
markAsHidden(delta >= absoluteButtonRect.height); | ||
setButtonClipping('0 0', '100% 0', `100% calc(100% - ${toPx(delta)})`, `0 calc(100% - ${toPx(delta)}`); | ||
} | ||
else if (scrollViewportRect && scrollViewportRect.top > absoluteButtonRect.top) { | ||
// Calculate the delta between the button top and the editable top, and clip the button | ||
// to make it look like it's cut off by the editable scrollable region. | ||
const delta = Math.min(absoluteButtonRect.height, scrollViewportRect.top - absoluteButtonRect.top); | ||
markAsHidden(delta >= absoluteButtonRect.height); | ||
setButtonClipping(`0 ${toPx(delta)}`, `100% ${toPx(delta)}`, '100% 100%', '0 100%'); | ||
} | ||
else { | ||
// Reset the clip path if button is fully visible. | ||
markAsHidden(false); | ||
setButtonClipping(); | ||
} | ||
} | ||
/** | ||
* Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly. | ||
@@ -366,0 +446,0 @@ */ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
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
6282108
61187
+ Added@ckeditor/ckeditor5-core@0.0.0-nightly-20240724.0(transitive)
+ Added@ckeditor/ckeditor5-engine@0.0.0-nightly-20240724.0(transitive)
+ Added@ckeditor/ckeditor5-utils@0.0.0-nightly-20240724.0(transitive)
+ Added@ckeditor/ckeditor5-watchdog@0.0.0-nightly-20240724.0(transitive)
- Removed@ckeditor/ckeditor5-core@0.0.0-nightly-20240723.0(transitive)
- Removed@ckeditor/ckeditor5-engine@0.0.0-nightly-20240723.0(transitive)
- Removed@ckeditor/ckeditor5-utils@0.0.0-nightly-20240723.0(transitive)
- Removed@ckeditor/ckeditor5-watchdog@0.0.0-nightly-20240723.0(transitive)