@ckeditor/ckeditor5-ui 42.0.2 → 43.0.0-alpha.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 (85) hide show
  1. package/CHANGELOG.md +1 -539
  2. package/dist/button/button.d.ts +0 -6
  3. package/dist/button/buttonview.d.ts +16 -4
  4. package/dist/button/filedialogbuttonview.d.ts +42 -15
  5. package/dist/button/listitembuttonview.d.ts +82 -0
  6. package/dist/editorui/accessibilityhelp/accessibilityhelp.d.ts +1 -1
  7. package/dist/editorui/editorui.d.ts +57 -0
  8. package/dist/editorui/editoruiview.d.ts +5 -0
  9. package/dist/focuscycler.d.ts +53 -7
  10. package/dist/formheader/formheaderview.d.ts +1 -2
  11. package/dist/highlightedtext/buttonlabelwithhighlightview.d.ts +34 -0
  12. package/dist/highlightedtext/labelwithhighlightview.d.ts +30 -0
  13. package/dist/index-editor.css +32 -0
  14. package/dist/index.css +42 -0
  15. package/dist/index.css.map +1 -1
  16. package/dist/index.d.ts +6 -2
  17. package/dist/index.js +4934 -4291
  18. package/dist/index.js.map +1 -1
  19. package/dist/menubar/menubarmenubuttonview.d.ts +2 -2
  20. package/dist/menubar/menubarmenulistitembuttonview.d.ts +2 -2
  21. package/dist/menubar/menubarmenulistitemfiledialogbuttonview.d.ts +2 -2
  22. package/dist/menubar/menubarmenulistview.d.ts +5 -0
  23. package/dist/menubar/menubarview.d.ts +10 -1
  24. package/dist/menubar/utils.d.ts +16 -10
  25. package/dist/panel/balloon/balloonpanelview.d.ts +13 -1
  26. package/dist/search/filtergroupanditemnames.d.ts +19 -0
  27. package/dist/toolbar/block/blocktoolbar.d.ts +14 -0
  28. package/dist/tooltipmanager.d.ts +0 -7
  29. package/dist/translations/sr-latn.js +1 -1
  30. package/dist/translations/sr-latn.umd.js +1 -1
  31. package/lang/translations/sr-latn.po +17 -17
  32. package/package.json +3 -3
  33. package/src/arialiveannouncer.js +0 -1
  34. package/src/bindings/draggableviewmixin.js +1 -1
  35. package/src/button/button.d.ts +0 -6
  36. package/src/button/buttonview.d.ts +16 -4
  37. package/src/button/buttonview.js +32 -2
  38. package/src/button/filedialogbuttonview.d.ts +42 -15
  39. package/src/button/filedialogbuttonview.js +69 -27
  40. package/src/button/listitembuttonview.d.ts +78 -0
  41. package/src/button/listitembuttonview.js +129 -0
  42. package/src/colorpicker/colorpickerview.js +5 -0
  43. package/src/colorselector/colorgridsfragmentview.js +9 -5
  44. package/src/dialog/dialog.js +4 -1
  45. package/src/dialog/dialogview.js +1 -14
  46. package/src/dropdown/utils.js +23 -3
  47. package/src/editorui/accessibilityhelp/accessibilityhelp.d.ts +1 -1
  48. package/src/editorui/accessibilityhelp/accessibilityhelp.js +20 -12
  49. package/src/editorui/bodycollection.js +2 -1
  50. package/src/editorui/editorui.d.ts +57 -0
  51. package/src/editorui/editorui.js +104 -12
  52. package/src/editorui/editoruiview.d.ts +5 -0
  53. package/src/focuscycler.d.ts +53 -7
  54. package/src/focuscycler.js +79 -1
  55. package/src/formheader/formheaderview.d.ts +1 -2
  56. package/src/formheader/formheaderview.js +1 -2
  57. package/src/highlightedtext/buttonlabelwithhighlightview.d.ts +30 -0
  58. package/src/highlightedtext/buttonlabelwithhighlightview.js +31 -0
  59. package/src/highlightedtext/labelwithhighlightview.d.ts +26 -0
  60. package/src/highlightedtext/labelwithhighlightview.js +33 -0
  61. package/src/index.d.ts +6 -2
  62. package/src/index.js +6 -2
  63. package/src/menubar/menubarmenubuttonview.d.ts +2 -2
  64. package/src/menubar/menubarmenubuttonview.js +2 -2
  65. package/src/menubar/menubarmenulistitembuttonview.d.ts +2 -2
  66. package/src/menubar/menubarmenulistitembuttonview.js +2 -2
  67. package/src/menubar/menubarmenulistitemfiledialogbuttonview.d.ts +2 -2
  68. package/src/menubar/menubarmenulistitemfiledialogbuttonview.js +2 -2
  69. package/src/menubar/menubarmenulistview.d.ts +5 -0
  70. package/src/menubar/menubarmenulistview.js +49 -0
  71. package/src/menubar/menubarview.d.ts +10 -1
  72. package/src/menubar/menubarview.js +11 -4
  73. package/src/menubar/utils.d.ts +16 -10
  74. package/src/menubar/utils.js +84 -53
  75. package/src/panel/balloon/balloonpanelview.d.ts +13 -1
  76. package/src/panel/balloon/balloonpanelview.js +41 -3
  77. package/src/search/filtergroupanditemnames.d.ts +15 -0
  78. package/src/search/filtergroupanditemnames.js +38 -0
  79. package/src/search/text/searchtextview.js +1 -0
  80. package/src/toolbar/balloon/balloontoolbar.js +1 -1
  81. package/src/toolbar/block/blocktoolbar.d.ts +14 -0
  82. package/src/toolbar/block/blocktoolbar.js +83 -3
  83. package/src/tooltipmanager.d.ts +0 -7
  84. package/src/tooltipmanager.js +1 -18
  85. package/theme/components/button/listitembutton.css +38 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * A filter function that returns matching item and group names in the list view.
7
+ */
8
+ export default function filterGroupAndItemNames(regExp, items) {
9
+ let totalItemsCount = 0;
10
+ let resultsCount = 0;
11
+ for (const groupView of items) {
12
+ const group = groupView;
13
+ const groupItems = group.items;
14
+ const isGroupLabelMatching = regExp && !!group.label.match(regExp);
15
+ group.labelView.highlightText(isGroupLabelMatching ? regExp : null);
16
+ for (const listItemView of groupItems) {
17
+ const buttonView = listItemView.children.first;
18
+ const labelView = buttonView.labelView;
19
+ if (!regExp) {
20
+ listItemView.isVisible = true;
21
+ labelView.highlightText(null);
22
+ }
23
+ else {
24
+ const isItemLabelMatching = !!buttonView.label.match(regExp);
25
+ labelView.highlightText(isItemLabelMatching ? regExp : null);
26
+ listItemView.isVisible = isGroupLabelMatching || isItemLabelMatching;
27
+ }
28
+ }
29
+ const visibleInGroupCount = groupItems.filter(listItemView => listItemView.isVisible).length;
30
+ totalItemsCount += group.items.length;
31
+ resultsCount += isGroupLabelMatching ? group.items.length : visibleInGroupCount;
32
+ group.isVisible = isGroupLabelMatching || !!visibleInGroupCount;
33
+ }
34
+ return {
35
+ resultsCount,
36
+ totalItemsCount
37
+ };
38
+ }
@@ -127,6 +127,7 @@ export default class SearchTextView extends View {
127
127
  reset() {
128
128
  this.queryView.reset();
129
129
  this.search('');
130
+ this.filteredView.element.scrollTo(0, 0);
130
131
  }
131
132
  /**
132
133
  * Searches the {@link #filteredView} for the given query.
@@ -162,7 +162,7 @@ export default class BalloonToolbar extends Plugin {
162
162
  if (selectionContainsOnlyMultipleSelectables(selection, schema)) {
163
163
  return;
164
164
  }
165
- // Don not show the toolbar when all components inside are disabled
165
+ // Do not show the toolbar when all components inside are disabled
166
166
  // see https://github.com/ckeditor/ckeditor5-ui/issues/269.
167
167
  if (Array.from(this.toolbarView.items).every((item) => item.isEnabled !== undefined && !item.isEnabled)) {
168
168
  return;
@@ -133,12 +133,26 @@ export default class BlockToolbar extends Plugin {
133
133
  * @param focusEditable When `true`, the editable will be focused after hiding the panel.
134
134
  */
135
135
  private _hidePanel;
136
+ /**
137
+ * Repositions the button on scroll.
138
+ */
139
+ private _repositionButtonOnScroll;
136
140
  /**
137
141
  * Attaches the {@link #buttonView} to the target block of content.
138
142
  *
139
143
  * @param targetElement Target element.
140
144
  */
141
145
  private _attachButtonToElement;
146
+ /**
147
+ * Clips the button element to the viewport of the editable element.
148
+ *
149
+ * * If the button overflows the editable viewport, it is clipped to make it look like it's cut off by the editable scrollable region.
150
+ * * If the button is fully hidden by the top of the editable, it is not clickable but still visible in the DOM.
151
+ *
152
+ * @param buttonView The button view to clip.
153
+ * @param editableElement The editable element whose viewport is used for clipping.
154
+ */
155
+ private _clipButtonToViewport;
142
156
  /**
143
157
  * Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly.
144
158
  */
@@ -7,7 +7,7 @@
7
7
  */
8
8
  /* global window */
9
9
  import { Plugin } from '@ckeditor/ckeditor5-core';
10
- import { Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils';
10
+ import { global, Rect, ResizeObserver, toUnit } from '@ckeditor/ckeditor5-utils';
11
11
  import BlockButtonView from './blockbuttonview.js';
12
12
  import BalloonPanelView from '../../panel/balloon/balloonpanelview.js';
13
13
  import ToolbarView, { NESTED_TOOLBAR_ICONS } from '../toolbarview.js';
@@ -131,6 +131,8 @@ export default class BlockToolbar extends Plugin {
131
131
  this._hidePanel();
132
132
  }
133
133
  });
134
+ // Reposition button on scroll.
135
+ this._repositionButtonOnScroll();
134
136
  // Register the toolbar so it becomes available for Alt+F10 and Esc navigation.
135
137
  editor.ui.addToolbar(this.toolbarView, {
136
138
  beforeFocus: () => this._showPanel(),
@@ -328,19 +330,52 @@ export default class BlockToolbar extends Plugin {
328
330
  this.editor.editing.view.focus();
329
331
  }
330
332
  }
333
+ /**
334
+ * Repositions the button on scroll.
335
+ */
336
+ _repositionButtonOnScroll() {
337
+ const { buttonView } = this;
338
+ let pendingAnimationFrame = false;
339
+ // Reposition the button on scroll, but do it only once per animation frame to avoid performance issues.
340
+ const repositionOnScroll = () => {
341
+ if (pendingAnimationFrame) {
342
+ return;
343
+ }
344
+ pendingAnimationFrame = true;
345
+ global.window.requestAnimationFrame(() => {
346
+ this._updateButton();
347
+ pendingAnimationFrame = false;
348
+ });
349
+ };
350
+ // Watch scroll event only when the button is visible, it prevents attaching the scroll event listener
351
+ // to the document when the button is not visible.
352
+ buttonView.on('change:isVisible', (evt, name, isVisible) => {
353
+ if (isVisible) {
354
+ buttonView.listenTo(global.document, 'scroll', repositionOnScroll, {
355
+ useCapture: true,
356
+ usePassive: true
357
+ });
358
+ }
359
+ else {
360
+ buttonView.stopListening(global.document, 'scroll', repositionOnScroll);
361
+ }
362
+ });
363
+ }
331
364
  /**
332
365
  * Attaches the {@link #buttonView} to the target block of content.
333
366
  *
334
367
  * @param targetElement Target element.
335
368
  */
336
369
  _attachButtonToElement(targetElement) {
370
+ const buttonElement = this.buttonView.element;
371
+ const editableElement = this._getSelectedEditableElement();
337
372
  const contentStyles = window.getComputedStyle(targetElement);
338
- const editableRect = new Rect(this._getSelectedEditableElement());
373
+ const editableRect = new Rect(editableElement);
339
374
  const contentPaddingTop = parseInt(contentStyles.paddingTop, 10);
340
375
  // When line height is not an integer then treat it as "normal".
341
376
  // MDN says that 'normal' == ~1.2 on desktop browsers.
342
377
  const contentLineHeight = parseInt(contentStyles.lineHeight, 10) || parseInt(contentStyles.fontSize, 10) * 1.2;
343
- const buttonRect = new Rect(this.buttonView.element);
378
+ const buttonRect = new Rect(buttonElement);
344
379
  const contentRect = new Rect(targetElement);
345
380
  let positionLeft;
346
381
  if (this.editor.locale.uiLanguageDirection === 'ltr') {
@@ -354,6 +389,51 @@ export default class BlockToolbar extends Plugin {
354
389
  const absoluteButtonRect = buttonRect.toAbsoluteRect();
355
390
  this.buttonView.top = absoluteButtonRect.top;
356
391
  this.buttonView.left = absoluteButtonRect.left;
392
+ this._clipButtonToViewport(this.buttonView, editableElement);
393
+ }
394
+ /**
395
+ * Clips the button element to the viewport of the editable element.
396
+ *
397
+ * * If the button overflows the editable viewport, it is clipped to make it look like it's cut off by the editable scrollable region.
398
+ * * If the button is fully hidden by the top of the editable, it is not clickable but still visible in the DOM.
399
+ *
400
+ * @param buttonView The button view to clip.
401
+ * @param editableElement The editable element whose viewport is used for clipping.
402
+ */
403
+ _clipButtonToViewport(buttonView, editableElement) {
404
+ const absoluteButtonRect = new Rect(buttonView.element);
405
+ const scrollViewportRect = new Rect(editableElement).getVisible();
406
+ // Sets polygon clip path for the button element, if there is no argument provided, the clip path is removed.
407
+ const setButtonClipping = (...paths) => {
408
+ buttonView.element.style.clipPath = paths.length ? `polygon(${paths.join(',')})` : '';
409
+ };
410
+ // Hide the button if it's fully hidden by the top of the editable.
411
+ // Note that the button is still visible in the DOM, but it's not clickable. It's because we don't
412
+ // want to hide the button completely, as there are plenty of `isVisible` watchers which toggles
413
+ // the button scroll listeners.
414
+ const markAsHidden = (isHidden) => {
415
+ buttonView.isEnabled = !isHidden;
416
+ buttonView.element.style.pointerEvents = isHidden ? 'none' : '';
417
+ };
418
+ if (scrollViewportRect && scrollViewportRect.bottom < absoluteButtonRect.bottom) {
419
+ // Calculate the delta between the button bottom and the editable bottom, and clip the button
420
+ // to make it look like it's cut off by the editable scrollable region.
421
+ const delta = Math.min(absoluteButtonRect.height, absoluteButtonRect.bottom - scrollViewportRect.bottom);
422
+ markAsHidden(delta >= absoluteButtonRect.height);
423
+ setButtonClipping('0 0', '100% 0', `100% calc(100% - ${toPx(delta)})`, `0 calc(100% - ${toPx(delta)}`);
424
+ }
425
+ else if (scrollViewportRect && scrollViewportRect.top > absoluteButtonRect.top) {
426
+ // Calculate the delta between the button top and the editable top, and clip the button
427
+ // to make it look like it's cut off by the editable scrollable region.
428
+ const delta = Math.min(absoluteButtonRect.height, scrollViewportRect.top - absoluteButtonRect.top);
429
+ markAsHidden(delta >= absoluteButtonRect.height);
430
+ setButtonClipping(`0 ${toPx(delta)}`, `100% ${toPx(delta)}`, '100% 100%', '0 100%');
431
+ }
432
+ else {
433
+ // Reset the clip path if button is fully visible.
434
+ markAsHidden(false);
435
+ setButtonClipping();
436
+ }
357
437
  }
358
438
  /**
359
439
  * Creates a resize observer that observes selected editable and resizes the toolbar panel accordingly.
@@ -93,13 +93,6 @@ export default class TooltipManager extends /* #__PURE__ */ TooltipManager_base
93
93
  * Stores the current tooltip position. `null` when there's no tooltip in the UI.
94
94
  */
95
95
  private _currentTooltipPosition;
96
- /**
97
- * An instance of the resize observer that keeps track on target element visibility,
98
- * when it hides the tooltip should also disappear.
99
- *
100
- * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.
101
- */
102
- private _resizeObserver;
103
96
  /**
104
97
  * An instance of the mutation observer that keeps track on target element attributes changes.
105
98
  */
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import View from './view.js';
9
9
  import BalloonPanelView from './panel/balloon/balloonpanelview.js';
10
- import { DomEmitterMixin, ResizeObserver, first, global, isVisible } from '@ckeditor/ckeditor5-utils';
10
+ import { DomEmitterMixin, first, global, isVisible } from '@ckeditor/ckeditor5-utils';
11
11
  import { isElement, debounce } from 'lodash-es';
12
12
  import '../theme/components/tooltip/tooltip.css';
13
13
  const BALLOON_CLASS = 'ck-tooltip';
@@ -80,13 +80,6 @@ class TooltipManager extends /* #__PURE__ */ DomEmitterMixin() {
80
80
  * Stores the current tooltip position. `null` when there's no tooltip in the UI.
81
81
  */
82
82
  this._currentTooltipPosition = null;
83
- /**
84
- * An instance of the resize observer that keeps track on target element visibility,
85
- * when it hides the tooltip should also disappear.
86
- *
87
- * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.
88
- */
89
- this._resizeObserver = null;
90
83
  /**
91
84
  * An instance of the mutation observer that keeps track on target element attributes changes.
92
85
  */
@@ -319,13 +312,6 @@ class TooltipManager extends /* #__PURE__ */ DomEmitterMixin() {
319
312
  target: targetDomElement,
320
313
  positions: TooltipManager.getPositioningFunctions(position)
321
314
  });
322
- this._resizeObserver = new ResizeObserver(targetDomElement, () => {
323
- // The ResizeObserver will call its callback when the target element hides and the tooltip
324
- // should also disappear (https://github.com/ckeditor/ckeditor5/issues/12492).
325
- if (!isVisible(targetDomElement)) {
326
- this._unpinTooltip();
327
- }
328
- });
329
315
  this._mutationObserver.attach(targetDomElement);
330
316
  // Start responding to changes in editor UI or content layout. For instance, when collaborators change content
331
317
  // and a contextual toolbar attached to a content starts to move (and so should move the tooltip).
@@ -349,9 +335,6 @@ class TooltipManager extends /* #__PURE__ */ DomEmitterMixin() {
349
335
  this._currentElementWithTooltip = null;
350
336
  this._currentTooltipPosition = null;
351
337
  this.tooltipTextView.text = '';
352
- if (this._resizeObserver) {
353
- this._resizeObserver.destroy();
354
- }
355
338
  this._mutationObserver.detach();
356
339
  }
357
340
  /**
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ @import "../../mixins/_dir.css";
7
+
8
+ .ck.ck-list-item-button {
9
+ min-height: unset;
10
+ width: 100%;
11
+ border-radius: 0;
12
+
13
+ @mixin ck-dir ltr {
14
+ text-align: left;
15
+ }
16
+
17
+ @mixin ck-dir rtl {
18
+ text-align: right;
19
+ }
20
+
21
+ & .ck-list-item-button__check-holder {
22
+ display: inline-flex;
23
+ width: 1em;
24
+ height: 1em;
25
+
26
+ @mixin ck-dir ltr {
27
+ margin-right: var(--ck-spacing-standard);
28
+ }
29
+
30
+ @mixin ck-dir rtl {
31
+ margin-left: var(--ck-spacing-standard);
32
+ }
33
+ }
34
+
35
+ & .ck-list-item-button__check-icon {
36
+ height: 100%;
37
+ }
38
+ }