@ckeditor/ckeditor5-ui 35.3.2 → 36.0.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 (89) hide show
  1. package/LICENSE.md +1 -1
  2. package/package.json +21 -21
  3. package/src/bindings/addkeyboardhandlingforgrid.js +49 -14
  4. package/src/bindings/clickoutsidehandler.js +5 -7
  5. package/src/bindings/injectcsstransitiondisabler.js +1 -1
  6. package/src/bindings/preventdefault.js +1 -1
  7. package/src/bindings/submithandler.js +1 -1
  8. package/src/button/button.js +1 -1
  9. package/src/button/buttonview.js +2 -4
  10. package/src/button/switchbuttonview.js +1 -1
  11. package/src/colorgrid/colorgridview.js +4 -3
  12. package/src/colorgrid/colortileview.js +1 -1
  13. package/src/colorgrid/utils.js +1 -1
  14. package/src/componentfactory.js +3 -3
  15. package/src/dropdown/button/dropdownbutton.js +1 -1
  16. package/src/dropdown/button/dropdownbuttonview.js +1 -1
  17. package/src/dropdown/button/splitbuttonview.js +2 -3
  18. package/src/dropdown/dropdownpanelfocusable.js +1 -1
  19. package/src/dropdown/dropdownpanelview.js +2 -2
  20. package/src/dropdown/dropdownview.js +2 -4
  21. package/src/dropdown/utils.js +84 -27
  22. package/src/editableui/editableuiview.js +1 -1
  23. package/src/editableui/inline/inlineeditableuiview.js +1 -1
  24. package/src/editorui/bodycollection.js +2 -2
  25. package/src/editorui/boxed/boxededitoruiview.js +1 -1
  26. package/src/editorui/editorui.js +476 -0
  27. package/src/editorui/editoruiview.js +1 -1
  28. package/src/focuscycler.js +2 -2
  29. package/src/formheader/formheaderview.js +2 -2
  30. package/src/icon/iconview.js +1 -1
  31. package/src/iframe/iframeview.js +10 -10
  32. package/src/index.js +4 -1
  33. package/src/input/inputview.js +2 -2
  34. package/src/inputnumber/inputnumberview.js +1 -1
  35. package/src/inputtext/inputtextview.js +1 -1
  36. package/src/label/labelview.js +2 -2
  37. package/src/labeledfield/labeledfieldview.js +2 -2
  38. package/src/labeledfield/utils.js +1 -1
  39. package/src/labeledinput/labeledinputview.js +2 -2
  40. package/src/list/listitemview.js +1 -1
  41. package/src/list/listseparatorview.js +1 -1
  42. package/src/list/listview.js +11 -4
  43. package/src/model.js +3 -3
  44. package/src/notification/notification.js +2 -2
  45. package/src/panel/balloon/balloonpanelview.js +2 -5
  46. package/src/panel/balloon/contextualballoon.js +39 -20
  47. package/src/panel/sticky/stickypanelview.js +2 -3
  48. package/src/template.js +3 -6
  49. package/src/toolbar/balloon/balloontoolbar.js +5 -9
  50. package/src/toolbar/block/blockbuttonview.js +2 -2
  51. package/src/toolbar/block/blocktoolbar.js +4 -8
  52. package/src/toolbar/normalizetoolbarconfig.js +1 -1
  53. package/src/toolbar/toolbarlinebreakview.js +1 -1
  54. package/src/toolbar/toolbarseparatorview.js +1 -1
  55. package/src/toolbar/toolbarview.js +19 -19
  56. package/src/tooltipmanager.js +3 -4
  57. package/src/view.js +4 -8
  58. package/src/viewcollection.js +2 -3
  59. package/theme/components/button/button.css +1 -1
  60. package/theme/components/button/switchbutton.css +1 -1
  61. package/theme/components/colorgrid/colorgrid.css +1 -1
  62. package/theme/components/dropdown/dropdown.css +1 -1
  63. package/theme/components/dropdown/listdropdown.css +1 -1
  64. package/theme/components/dropdown/splitbutton.css +1 -1
  65. package/theme/components/dropdown/toolbardropdown.css +1 -1
  66. package/theme/components/editorui/editorui.css +1 -1
  67. package/theme/components/formheader/formheader.css +1 -1
  68. package/theme/components/icon/icon.css +1 -1
  69. package/theme/components/input/input.css +1 -1
  70. package/theme/components/label/label.css +1 -1
  71. package/theme/components/labeledfield/labeledfieldview.css +1 -1
  72. package/theme/components/labeledinput/labeledinput.css +1 -1
  73. package/theme/components/list/list.css +1 -1
  74. package/theme/components/panel/balloonpanel.css +1 -1
  75. package/theme/components/panel/balloonrotator.css +1 -1
  76. package/theme/components/panel/fakepanel.css +1 -1
  77. package/theme/components/panel/stickypanel.css +1 -1
  78. package/theme/components/responsive-form/responsiveform.css +1 -1
  79. package/theme/components/toolbar/blocktoolbar.css +1 -1
  80. package/theme/components/toolbar/toolbar.css +1 -1
  81. package/theme/components/tooltip/tooltip.css +1 -1
  82. package/theme/globals/_hidden.css +1 -1
  83. package/theme/globals/_reset.css +1 -1
  84. package/theme/globals/_transition.css +1 -1
  85. package/theme/globals/_zindex.css +1 -1
  86. package/theme/globals/globals.css +1 -1
  87. package/theme/mixins/_dir.css +1 -1
  88. package/theme/mixins/_rwd.css +1 -1
  89. package/theme/mixins/_unselectable.css +1 -1
@@ -0,0 +1,476 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ * @module core/editor/editorui
7
+ */
8
+ /* globals console */
9
+ import ComponentFactory from '../componentfactory';
10
+ import TooltipManager from '../tooltipmanager';
11
+ import { ObservableMixin, isVisible, FocusTracker } from '@ckeditor/ckeditor5-utils';
12
+ /**
13
+ * A class providing the minimal interface that is required to successfully bootstrap any editor UI.
14
+ *
15
+ * @mixes module:utils/emittermixin~EmitterMixin
16
+ */
17
+ export default class EditorUI extends ObservableMixin() {
18
+ /**
19
+ * Creates an instance of the editor UI class.
20
+ *
21
+ * @param {module:core/editor/editor~Editor} editor The editor instance.
22
+ */
23
+ constructor(editor) {
24
+ super();
25
+ /**
26
+ * The editor that the UI belongs to.
27
+ *
28
+ * @readonly
29
+ * @member {module:core/editor/editor~Editor} #editor
30
+ */
31
+ this.editor = editor;
32
+ /**
33
+ * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins
34
+ * to register factories of specific UI components.
35
+ *
36
+ * @readonly
37
+ * @member {module:ui/componentfactory~ComponentFactory} #componentFactory
38
+ */
39
+ this.componentFactory = new ComponentFactory(editor);
40
+ /**
41
+ * Stores the information about the editor UI focus and propagates it so various plugins and components
42
+ * are unified as a focus group.
43
+ *
44
+ * @readonly
45
+ * @member {module:utils/focustracker~FocusTracker} #focusTracker
46
+ */
47
+ this.focusTracker = new FocusTracker();
48
+ /**
49
+ * Manages the tooltips displayed on mouseover and focus across the UI.
50
+ *
51
+ * @readonly
52
+ * @member {module:ui/tooltipmanager~TooltipManager}
53
+ */
54
+ this.tooltipManager = new TooltipManager(editor);
55
+ /**
56
+ * Stores viewport offsets from every direction.
57
+ *
58
+ * Viewport offset can be used to constrain balloons or other UI elements into an element smaller than the viewport.
59
+ * This can be useful if there are any other absolutely positioned elements that may interfere with editor UI.
60
+ *
61
+ * Example `editor.ui.viewportOffset` returns:
62
+ *
63
+ * ```js
64
+ * {
65
+ * top: 50,
66
+ * right: 50,
67
+ * bottom: 50,
68
+ * left: 50
69
+ * }
70
+ * ```
71
+ *
72
+ * This property can be overriden after editor already being initialized:
73
+ *
74
+ * ```js
75
+ * editor.ui.viewportOffset = {
76
+ * top: 100,
77
+ * right: 0,
78
+ * bottom: 0,
79
+ * left: 0
80
+ * };
81
+ * ```
82
+ *
83
+ * @observable
84
+ * @member {Object} #viewportOffset
85
+ */
86
+ this.set('viewportOffset', this._readViewportOffsetFromConfig());
87
+ /**
88
+ * Indicates the UI is ready. Set `true` after {@link #event:ready} event is fired.
89
+ *
90
+ * @readonly
91
+ * @default false
92
+ * @member {Boolean} #isReady
93
+ */
94
+ this.isReady = false;
95
+ this.once('ready', () => {
96
+ this.isReady = true;
97
+ });
98
+ /**
99
+ * Stores all editable elements used by the editor instance.
100
+ *
101
+ * @private
102
+ * @member {Map.<String,HTMLElement>}
103
+ */
104
+ this._editableElementsMap = new Map();
105
+ /**
106
+ * All available & focusable toolbars.
107
+ *
108
+ * @private
109
+ * @type {Array.<module:core/editor/editorui~FocusableToolbarDefinition>}
110
+ */
111
+ this._focusableToolbarDefinitions = [];
112
+ // Informs UI components that should be refreshed after layout change.
113
+ this.listenTo(editor.editing.view.document, 'layoutChanged', () => this.update());
114
+ this._initFocusTracking();
115
+ }
116
+ /**
117
+ * The main (outermost) DOM element of the editor UI.
118
+ *
119
+ * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `<div>` which
120
+ * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}
121
+ * it is the editable element itself (as there is no other wrapper). However, in
122
+ * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not
123
+ * come with a single "main" HTML element (its editable element and toolbar are separate).
124
+ *
125
+ * This property can be understood as a shorthand for retrieving the element that a specific editor integration
126
+ * considers to be its main DOM element.
127
+ *
128
+ * @readonly
129
+ * @member {HTMLElement|null} #element
130
+ */
131
+ get element() {
132
+ return null;
133
+ }
134
+ /**
135
+ * Fires the {@link module:core/editor/editorui~EditorUI#event:update `update`} event.
136
+ *
137
+ * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to
138
+ * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).
139
+ */
140
+ update() {
141
+ this.fire('update');
142
+ }
143
+ /**
144
+ * Destroys the UI.
145
+ */
146
+ destroy() {
147
+ this.stopListening();
148
+ this.focusTracker.destroy();
149
+ this.tooltipManager.destroy(this.editor);
150
+ // Clean–up the references to the CKEditor instance stored in the native editable DOM elements.
151
+ for (const domElement of this._editableElementsMap.values()) {
152
+ domElement.ckeditorInstance = null;
153
+ }
154
+ this._editableElementsMap = new Map();
155
+ this._focusableToolbarDefinitions = [];
156
+ }
157
+ /**
158
+ * Stores the native DOM editable element used by the editor under a unique name.
159
+ *
160
+ * Also, registers the element in the editor to maintain the accessibility of the UI. When the user is editing text in a focusable
161
+ * editable area, they can use the <kbd>Alt</kbd> + <kbd>F10</kbd> keystroke to navigate over editor toolbars. See {@link #addToolbar}.
162
+ *
163
+ * @param {String} rootName The unique name of the editable element.
164
+ * @param {HTMLElement} domElement The native DOM editable element.
165
+ */
166
+ setEditableElement(rootName, domElement) {
167
+ this._editableElementsMap.set(rootName, domElement);
168
+ // Put a reference to the CKEditor instance in the editable native DOM element.
169
+ // It helps 3rd–party software (browser extensions, other libraries) access and recognize
170
+ // CKEditor 5 instances (editing roots) and use their API (there is no global editor
171
+ // instance registry).
172
+ if (!domElement.ckeditorInstance) {
173
+ domElement.ckeditorInstance = this.editor;
174
+ }
175
+ // Register the element so it becomes available for Alt+F10 and Esc navigation.
176
+ this.focusTracker.add(domElement);
177
+ const setUpKeystrokeHandler = () => {
178
+ // The editing view of the editor is already listening to keystrokes from DOM roots (see: KeyObserver).
179
+ // Do not duplicate listeners.
180
+ if (this.editor.editing.view.getDomRoot(rootName)) {
181
+ return;
182
+ }
183
+ this.editor.keystrokes.listenTo(domElement);
184
+ };
185
+ // For editable elements set by features after EditorUI is ready (e.g. source editing).
186
+ if (this.isReady) {
187
+ setUpKeystrokeHandler();
188
+ }
189
+ // For editable elements set while the editor is being created (e.g. DOM roots).
190
+ else {
191
+ this.once('ready', setUpKeystrokeHandler);
192
+ }
193
+ }
194
+ /**
195
+ * Returns the editable editor element with the given name or null if editable does not exist.
196
+ *
197
+ * @param {String} [rootName=main] The editable name.
198
+ * @returns {HTMLElement|undefined}
199
+ */
200
+ getEditableElement(rootName = 'main') {
201
+ return this._editableElementsMap.get(rootName);
202
+ }
203
+ /**
204
+ * Returns array of names of all editor editable elements.
205
+ *
206
+ * @returns {Iterable.<String>}
207
+ */
208
+ getEditableElementsNames() {
209
+ return this._editableElementsMap.keys();
210
+ }
211
+ /**
212
+ * Adds a toolbar to the editor UI. Used primarily to maintain the accessibility of the UI.
213
+ *
214
+ * Focusable toolbars can be accessed (focused) by users by pressing the <kbd>Alt</kbd> + <kbd>F10</kbd> keystroke.
215
+ * Successive keystroke presses navigate over available toolbars.
216
+ *
217
+ * @param {module:ui/toolbar/toolbarview~ToolbarView} toolbarView A instance of the toolbar to be registered.
218
+ * @param {Object} [options]
219
+ * @param {Boolean} [options.isContextual] Set `true` if the toolbar is attached to the content of the editor. Such toolbar takes
220
+ * a precedence over other toolbars when a user pressed <kbd>Alt</kbd> + <kbd>F10</kbd>.
221
+ * @param {Function} [options.beforeFocus] Specify a callback executed before the toolbar instance DOM element gains focus
222
+ * upon the <kbd>Alt</kbd> + <kbd>F10</kbd> keystroke.
223
+ * @param {Function} [options.afterBlur] Specify a callback executed after the toolbar instance DOM element loses focus upon
224
+ * <kbd>Esc</kbd> keystroke but before the focus goes back to the {@link #setEditableElement editable element}.
225
+ */
226
+ addToolbar(toolbarView, options = {}) {
227
+ if (toolbarView.isRendered) {
228
+ this.focusTracker.add(toolbarView.element);
229
+ this.editor.keystrokes.listenTo(toolbarView.element);
230
+ }
231
+ else {
232
+ toolbarView.once('render', () => {
233
+ this.focusTracker.add(toolbarView.element);
234
+ this.editor.keystrokes.listenTo(toolbarView.element);
235
+ });
236
+ }
237
+ this._focusableToolbarDefinitions.push({ toolbarView, options });
238
+ }
239
+ /**
240
+ * Stores all editable elements used by the editor instance.
241
+ *
242
+ * @protected
243
+ * @deprecated
244
+ * @member {Map.<String,HTMLElement>}
245
+ */
246
+ get _editableElements() {
247
+ /**
248
+ * The {@link module:core/editor/editorui~EditorUI#_editableElements `EditorUI#_editableElements`} property has been
249
+ * deprecated and will be removed in the near future. Please use {@link #setEditableElement `setEditableElement()`} and
250
+ * {@link #getEditableElement `getEditableElement()`} methods instead.
251
+ *
252
+ * @error editor-ui-deprecated-editable-elements
253
+ * @param {module:core/editor/editorui~EditorUI} editorUI Editor UI instance the deprecated property belongs to.
254
+ */
255
+ console.warn('editor-ui-deprecated-editable-elements: ' +
256
+ 'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.', { editorUI: this });
257
+ return this._editableElementsMap;
258
+ }
259
+ /**
260
+ * Returns viewport offsets object:
261
+ *
262
+ * ```js
263
+ * {
264
+ * top: Number,
265
+ * right: Number,
266
+ * bottom: Number,
267
+ * left: Number
268
+ * }
269
+ * ```
270
+ *
271
+ * Only top property is currently supported.
272
+ *
273
+ * @private
274
+ * @return {Object}
275
+ */
276
+ _readViewportOffsetFromConfig() {
277
+ const editor = this.editor;
278
+ const viewportOffsetConfig = editor.config.get('ui.viewportOffset');
279
+ if (viewportOffsetConfig) {
280
+ return viewportOffsetConfig;
281
+ }
282
+ // Not present in EditorConfig type, because it's legacy. Hence the `as` expression.
283
+ const legacyOffsetConfig = editor.config.get('toolbar.viewportTopOffset');
284
+ // Fall back to deprecated toolbar config.
285
+ if (legacyOffsetConfig) {
286
+ /**
287
+ * The {@link module:core/editor/editorconfig~EditorConfig#toolbar `EditorConfig#toolbar.viewportTopOffset`}
288
+ * property has been deprecated and will be removed in the near future. Please use
289
+ * {@link module:core/editor/editorconfig~EditorConfig#ui `EditorConfig#ui.viewportOffset`} instead.
290
+ *
291
+ * @error editor-ui-deprecated-viewport-offset-config
292
+ */
293
+ console.warn('editor-ui-deprecated-viewport-offset-config: ' +
294
+ 'The `toolbar.vieportTopOffset` configuration option is deprecated. ' +
295
+ 'It will be removed from future CKEditor versions. Use `ui.viewportOffset.top` instead.');
296
+ return { top: legacyOffsetConfig };
297
+ }
298
+ // More keys to come in the future.
299
+ return { top: 0 };
300
+ }
301
+ /**
302
+ * Starts listening for <kbd>Alt</kbd> + <kbd>F10</kbd> and <kbd>Esc</kbd> keystrokes in the context of focusable
303
+ * {@link #setEditableElement editable elements} and {@link #addToolbar toolbars}
304
+ * to allow users navigate across the UI.
305
+ *
306
+ * @private
307
+ */
308
+ _initFocusTracking() {
309
+ const editor = this.editor;
310
+ const editingView = editor.editing.view;
311
+ let lastFocusedForeignElement;
312
+ let candidateDefinitions;
313
+ // Focus the next focusable toolbar on <kbd>Alt</kbd> + <kbd>F10</kbd>.
314
+ editor.keystrokes.set('Alt+F10', (data, cancel) => {
315
+ const focusedElement = this.focusTracker.focusedElement;
316
+ // Focus moved out of a DOM element that
317
+ // * is not a toolbar,
318
+ // * does not belong to the editing view (e.g. source editing).
319
+ if (Array.from(this._editableElementsMap.values()).includes(focusedElement) &&
320
+ !Array.from(editingView.domRoots.values()).includes(focusedElement)) {
321
+ lastFocusedForeignElement = focusedElement;
322
+ }
323
+ const currentFocusedToolbarDefinition = this._getCurrentFocusedToolbarDefinition();
324
+ // * When focusing a toolbar for the first time, set the array of definitions for successive presses of Alt+F10.
325
+ // This ensures, the navigation works always the same and no pair of toolbars takes over
326
+ // (e.g. image and table toolbars when a selected image is inside a cell).
327
+ // * It could be that the focus went to the toolbar by clicking a toolbar item (e.g. a dropdown). In this case,
328
+ // there were no candidates so they must be obtained (#12339).
329
+ if (!currentFocusedToolbarDefinition || !candidateDefinitions) {
330
+ candidateDefinitions = this._getFocusableCandidateToolbarDefinitions();
331
+ }
332
+ // In a single Alt+F10 press, check all candidates but if none were focused, don't go any further.
333
+ // This prevents an infinite loop.
334
+ for (let i = 0; i < candidateDefinitions.length; i++) {
335
+ const candidateDefinition = candidateDefinitions.shift();
336
+ // Put the first definition to the back of the array. This allows circular navigation over all toolbars
337
+ // on successive presses of Alt+F10.
338
+ candidateDefinitions.push(candidateDefinition);
339
+ // Don't focus the same toolbar again. If you did, this would move focus from the nth focused toolbar item back to the
340
+ // first item as per ToolbarView#focus() if the user navigated inside the toolbar.
341
+ if (candidateDefinition !== currentFocusedToolbarDefinition &&
342
+ this._focusFocusableCandidateToolbar(candidateDefinition)) {
343
+ // Clean up after a current visible toolbar when switching to the next one.
344
+ if (currentFocusedToolbarDefinition && currentFocusedToolbarDefinition.options.afterBlur) {
345
+ currentFocusedToolbarDefinition.options.afterBlur();
346
+ }
347
+ break;
348
+ }
349
+ }
350
+ cancel();
351
+ });
352
+ // Blur the focused toolbar on <kbd>Esc</kbd> and bring the focus back to its origin.
353
+ editor.keystrokes.set('Esc', (data, cancel) => {
354
+ const focusedToolbarDef = this._getCurrentFocusedToolbarDefinition();
355
+ if (!focusedToolbarDef) {
356
+ return;
357
+ }
358
+ // Bring focus back to where it came from before focusing the toolbar:
359
+ // 1. If it came from outside the engine view (e.g. source editing), move it there.
360
+ if (lastFocusedForeignElement) {
361
+ lastFocusedForeignElement.focus();
362
+ lastFocusedForeignElement = null;
363
+ }
364
+ // 2. There are two possibilities left:
365
+ // 2.1. It could be that the focus went from an editable element in the view (root or nested).
366
+ // 2.2. It could be the focus went straight to the toolbar before even focusing the editing area.
367
+ // In either case, just focus the view editing. The focus will land where it belongs.
368
+ else {
369
+ editor.editing.view.focus();
370
+ }
371
+ // Clean up after the toolbar if there is anything to do there.
372
+ if (focusedToolbarDef.options.afterBlur) {
373
+ focusedToolbarDef.options.afterBlur();
374
+ }
375
+ cancel();
376
+ });
377
+ }
378
+ /**
379
+ * Returns definitions of toolbars that could potentially be focused, sorted by their importance for the user.
380
+ *
381
+ * Focusable toolbars candidates are either:
382
+ * * already visible,
383
+ * * have `beforeFocus()` set in their {@link module:core/editor/editorui~FocusableToolbarDefinition definition} that suggests that
384
+ * they might show up when called. Keep in mind that determining whether a toolbar will show up (and become focusable) is impossible
385
+ * at this stage because it depends on its implementation, that in turn depends on the editing context (selection).
386
+ *
387
+ * **Note**: Contextual toolbars take precedence over regular toolbars.
388
+ *
389
+ * @private
390
+ * @returns {Array.<module:core/editor/editorui~FocusableToolbarDefinition>}
391
+ */
392
+ _getFocusableCandidateToolbarDefinitions() {
393
+ const definitions = [];
394
+ for (const toolbarDef of this._focusableToolbarDefinitions) {
395
+ const { toolbarView, options } = toolbarDef;
396
+ if (isVisible(toolbarView.element) || options.beforeFocus) {
397
+ definitions.push(toolbarDef);
398
+ }
399
+ }
400
+ // Contextual and already visible toolbars have higher priority. If both are true, the toolbar will always focus first.
401
+ // For instance, a selected widget toolbar vs inline editor toolbar: both are visible but the widget toolbar is contextual.
402
+ definitions.sort((defA, defB) => getToolbarDefinitionWeight(defA) - getToolbarDefinitionWeight(defB));
403
+ return definitions;
404
+ }
405
+ /**
406
+ * Returns a definition of the toolbar that is currently visible and focused (one of its children has focus).
407
+ *
408
+ * `null` is returned when no toolbar is currently focused.
409
+ *
410
+ * @private
411
+ * @returns {module:core/editor/editorui~FocusableToolbarDefinition|null}
412
+ */
413
+ _getCurrentFocusedToolbarDefinition() {
414
+ for (const definition of this._focusableToolbarDefinitions) {
415
+ if (definition.toolbarView.element && definition.toolbarView.element.contains(this.focusTracker.focusedElement)) {
416
+ return definition;
417
+ }
418
+ }
419
+ return null;
420
+ }
421
+ /**
422
+ * Focuses a focusable toolbar candidate using its definition.
423
+ *
424
+ * @private
425
+ * @param {module:core/editor/editorui~FocusableToolbarDefinition} candidateToolbarDefinition A definition of the toolbar to focus.
426
+ * @returns {Boolean} `true` when the toolbar candidate was focused. `false` otherwise.
427
+ */
428
+ _focusFocusableCandidateToolbar(candidateToolbarDefinition) {
429
+ const { toolbarView, options: { beforeFocus } } = candidateToolbarDefinition;
430
+ if (beforeFocus) {
431
+ beforeFocus();
432
+ }
433
+ // If it didn't show up after beforeFocus(), it's not focusable at all.
434
+ if (!isVisible(toolbarView.element)) {
435
+ return false;
436
+ }
437
+ toolbarView.focus();
438
+ return true;
439
+ }
440
+ }
441
+ /**
442
+ * An instance of a focusable toolbar view.
443
+ *
444
+ * @member {module:ui/toolbar/toolbarview~ToolbarView} #toolbarView
445
+ */
446
+ /**
447
+ * Options of a focusable toolbar view:
448
+ *
449
+ * * `isContextual`: Marks the higher priority toolbar. For example when there are 2 visible toolbars,
450
+ * it allows to distinguish which toolbar should be focused first after the `alt+f10` keystroke
451
+ * * `beforeFocus`: A callback executed before the `ToolbarView` gains focus upon the `Alt+F10` keystroke.
452
+ * * `afterBlur`: A callback executed after `ToolbarView` loses focus upon `Esc` keystroke but before the focus goes back to the `origin`.
453
+ *
454
+ * @member {Object} #options
455
+ */
456
+ // Returns a number (weight) for a toolbar definition. Visible toolbars have a higher priority and so do
457
+ // contextual toolbars (displayed in the context of a content, for instance, an image toolbar).
458
+ //
459
+ // A standard invisible toolbar is the heaviest. A visible contextual toolbar is the lightest.
460
+ //
461
+ // @private
462
+ // @param {module:core/editor/editorui~FocusableToolbarDefinition} toolbarDef A toolbar definition to be weighted.
463
+ // @returns {Number}
464
+ function getToolbarDefinitionWeight(toolbarDef) {
465
+ const { toolbarView, options } = toolbarDef;
466
+ let weight = 10;
467
+ // Prioritize already visible toolbars. They should get focused first.
468
+ if (isVisible(toolbarView.element)) {
469
+ weight--;
470
+ }
471
+ // Prioritize contextual toolbars. They are displayed at the selection.
472
+ if (options.isContextual) {
473
+ weight--;
474
+ }
475
+ return weight;
476
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
6
6
  * @module ui/focuscycler
7
7
  */
8
- import isVisible from '@ckeditor/ckeditor5-utils/src/dom/isvisible';
8
+ import { isVisible } from '@ckeditor/ckeditor5-utils';
9
9
  /**
10
10
  * A utility class that helps cycling over focusable {@link module:ui/view~View views} in a
11
11
  * {@link module:ui/viewcollection~ViewCollection} when the focus is tracked by the
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -68,7 +68,7 @@ export default class FormHeaderView extends View {
68
68
  });
69
69
  const label = new View(locale);
70
70
  label.setTemplate({
71
- tag: 'span',
71
+ tag: 'h2',
72
72
  attributes: {
73
73
  class: [
74
74
  'ck',
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /* global DOMParser */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -9,18 +9,18 @@ import View from '../view';
9
9
  /**
10
10
  * The iframe view class.
11
11
  *
12
- * const iframe = new IframeView();
12
+ * ```ts
13
+ * const iframe = new IframeView();
13
14
  *
14
- * iframe.render();
15
- * document.body.appendChild( iframe.element );
15
+ * iframe.render();
16
+ * document.body.appendChild( iframe.element );
16
17
  *
17
- * iframe.on( 'loaded', () => {
18
- * console.log( 'The iframe has loaded', iframe.element.contentWindow );
19
- * } );
18
+ * iframe.on( 'loaded', () => {
19
+ * console.log( 'The iframe has loaded', iframe.element.contentWindow );
20
+ * } );
20
21
  *
21
- * iframe.element.src = 'https://ckeditor.com';
22
- *
23
- * @extends module:ui/view~View
22
+ * iframe.element.src = 'https://ckeditor.com';
23
+ * ```
24
24
  */
25
25
  export default class IframeView extends View {
26
26
  /**
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -15,9 +15,12 @@ export { default as SwitchButtonView } from './button/switchbuttonview';
15
15
  export * from './colorgrid/utils';
16
16
  export { default as ColorGridView } from './colorgrid/colorgridview';
17
17
  export { default as ColorTileView } from './colorgrid/colortileview';
18
+ export { default as ComponentFactory } from './componentfactory';
19
+ export { default as DropdownView } from './dropdown/dropdownview';
18
20
  export { default as DropdownButtonView } from './dropdown/button/dropdownbuttonview';
19
21
  export { default as SplitButtonView } from './dropdown/button/splitbuttonview';
20
22
  export * from './dropdown/utils';
23
+ export { default as EditorUI } from './editorui/editorui';
21
24
  export { default as EditorUIView } from './editorui/editoruiview';
22
25
  export { default as BoxedEditorUIView } from './editorui/boxed/boxededitoruiview';
23
26
  export { default as InlineEditableUIView } from './editableui/inline/inlineeditableuiview';
@@ -1,12 +1,12 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
6
6
  * @module ui/input/inputview
7
7
  */
8
8
  import View from '../view';
9
- import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
9
+ import { FocusTracker } from '@ckeditor/ckeditor5-utils';
10
10
  import '../../theme/components/input/input.css';
11
11
  /**
12
12
  * The base input view class.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -1,12 +1,12 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
6
6
  * @module ui/label/labelview
7
7
  */
8
8
  import View from '../view';
9
- import uid from '@ckeditor/ckeditor5-utils/src/uid';
9
+ import { uid } from '@ckeditor/ckeditor5-utils';
10
10
  import '../../theme/components/label/label.css';
11
11
  /**
12
12
  * The label view class.
@@ -1,13 +1,13 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
6
6
  * @module ui/labeledfield/labeledfieldview
7
7
  */
8
8
  import View from '../view';
9
- import uid from '@ckeditor/ckeditor5-utils/src/uid';
10
9
  import LabelView from '../label/labelview';
10
+ import { uid } from '@ckeditor/ckeditor5-utils';
11
11
  import '../../theme/components/labeledfield/labeledfieldview.css';
12
12
  /**
13
13
  * The labeled field view class. It can be used to enhance any view with the following features:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
@@ -1,13 +1,13 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  /**
6
6
  * @module ui/labeledinput/labeledinputview
7
7
  */
8
8
  import View from '../view';
9
- import uid from '@ckeditor/ckeditor5-utils/src/uid';
10
9
  import LabelView from '../label/labelview';
10
+ import { uid } from '@ckeditor/ckeditor5-utils';
11
11
  import '../../theme/components/labeledinput/labeledinput.css';
12
12
  /**
13
13
  * The labeled input view class.