@ckeditor/ckeditor5-ui 37.1.0 → 38.0.0-rc.1
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.
- package/lang/contexts.json +2 -1
- package/lang/translations/ar.po +5 -1
- package/lang/translations/ast.po +5 -1
- package/lang/translations/az.po +5 -1
- package/lang/translations/bg.po +5 -1
- package/lang/translations/bn.po +5 -1
- package/lang/translations/ca.po +5 -1
- package/lang/translations/cs.po +5 -1
- package/lang/translations/da.po +5 -1
- package/lang/translations/de-ch.po +5 -1
- package/lang/translations/de.po +5 -1
- package/lang/translations/el.po +5 -1
- package/lang/translations/en-au.po +6 -2
- package/lang/translations/en-gb.po +5 -1
- package/lang/translations/en.po +4 -0
- package/lang/translations/eo.po +5 -1
- package/lang/translations/es.po +5 -1
- package/lang/translations/et.po +5 -1
- package/lang/translations/eu.po +5 -1
- package/lang/translations/fa.po +5 -1
- package/lang/translations/fi.po +5 -1
- package/lang/translations/fr.po +5 -1
- package/lang/translations/gl.po +5 -1
- package/lang/translations/he.po +5 -1
- package/lang/translations/hi.po +5 -1
- package/lang/translations/hr.po +6 -2
- package/lang/translations/hu.po +5 -1
- package/lang/translations/id.po +5 -1
- package/lang/translations/it.po +5 -1
- package/lang/translations/ja.po +5 -1
- package/lang/translations/km.po +5 -1
- package/lang/translations/kn.po +5 -1
- package/lang/translations/ko.po +5 -1
- package/lang/translations/ku.po +5 -1
- package/lang/translations/lt.po +5 -1
- package/lang/translations/lv.po +5 -1
- package/lang/translations/ms.po +5 -1
- package/lang/translations/nb.po +5 -1
- package/lang/translations/ne.po +5 -1
- package/lang/translations/nl.po +5 -1
- package/lang/translations/no.po +5 -1
- package/lang/translations/pl.po +5 -1
- package/lang/translations/pt-br.po +5 -1
- package/lang/translations/pt.po +5 -1
- package/lang/translations/ro.po +5 -1
- package/lang/translations/ru.po +5 -1
- package/lang/translations/sk.po +5 -1
- package/lang/translations/sl.po +5 -1
- package/lang/translations/sq.po +5 -1
- package/lang/translations/sr-latn.po +5 -1
- package/lang/translations/sr.po +5 -1
- package/lang/translations/sv.po +5 -1
- package/lang/translations/th.po +5 -1
- package/lang/translations/tk.po +5 -1
- package/lang/translations/tr.po +5 -1
- package/lang/translations/tt.po +5 -1
- package/lang/translations/ug.po +5 -1
- package/lang/translations/uk.po +5 -1
- package/lang/translations/ur.po +5 -1
- package/lang/translations/uz.po +5 -1
- package/lang/translations/vi.po +5 -1
- package/lang/translations/zh-cn.po +5 -1
- package/lang/translations/zh.po +6 -2
- package/package.json +27 -22
- package/src/button/button.d.ts +24 -0
- package/src/button/buttonview.d.ts +24 -2
- package/src/button/buttonview.js +33 -10
- package/src/colorpicker/colorpickerview.d.ts +110 -0
- package/src/colorpicker/colorpickerview.js +250 -0
- package/src/colorpicker/utils.d.ts +35 -0
- package/src/colorpicker/utils.js +99 -0
- package/src/dropdown/button/splitbuttonview.d.ts +16 -0
- package/src/dropdown/dropdownpanelview.js +6 -1
- package/src/dropdown/utils.d.ts +2 -0
- package/src/dropdown/utils.js +2 -0
- package/src/editorui/editorui.d.ts +5 -0
- package/src/editorui/editorui.js +3 -0
- package/src/editorui/poweredby.d.ts +71 -0
- package/src/editorui/poweredby.js +285 -0
- package/src/index.d.ts +3 -0
- package/src/index.js +2 -0
- package/src/list/listitemview.js +2 -1
- package/src/list/listview.d.ts +6 -0
- package/src/list/listview.js +2 -0
- package/src/toolbar/block/blocktoolbar.js +3 -25
- package/src/toolbar/toolbarview.js +3 -1
- package/theme/components/colorpicker/colorpicker.css +24 -0
- package/theme/globals/_poweredby.css +67 -0
- package/theme/globals/globals.css +1 -0
- package/theme/icons/color-palette.svg +1 -0
- package/theme/icons/project-logo.svg +1 -0
package/src/editorui/editorui.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
/* globals console */
|
|
9
9
|
import ComponentFactory from '../componentfactory';
|
|
10
10
|
import TooltipManager from '../tooltipmanager';
|
|
11
|
+
import PoweredBy from './poweredby';
|
|
11
12
|
import { ObservableMixin, isVisible, FocusTracker } from '@ckeditor/ckeditor5-utils';
|
|
12
13
|
/**
|
|
13
14
|
* A class providing the minimal interface that is required to successfully bootstrap any editor UI.
|
|
@@ -39,6 +40,7 @@ export default class EditorUI extends ObservableMixin() {
|
|
|
39
40
|
this.componentFactory = new ComponentFactory(editor);
|
|
40
41
|
this.focusTracker = new FocusTracker();
|
|
41
42
|
this.tooltipManager = new TooltipManager(editor);
|
|
43
|
+
this.poweredBy = new PoweredBy(editor);
|
|
42
44
|
this.set('viewportOffset', this._readViewportOffsetFromConfig());
|
|
43
45
|
this.once('ready', () => {
|
|
44
46
|
this.isReady = true;
|
|
@@ -78,6 +80,7 @@ export default class EditorUI extends ObservableMixin() {
|
|
|
78
80
|
this.stopListening();
|
|
79
81
|
this.focusTracker.destroy();
|
|
80
82
|
this.tooltipManager.destroy(this.editor);
|
|
83
|
+
this.poweredBy.destroy();
|
|
81
84
|
// Clean–up the references to the CKEditor instance stored in the native editable DOM elements.
|
|
82
85
|
for (const domElement of this._editableElementsMap.values()) {
|
|
83
86
|
domElement.ckeditorInstance = null;
|
|
@@ -0,0 +1,71 @@
|
|
|
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 ui/editorui/poweredby
|
|
7
|
+
*/
|
|
8
|
+
import type { Editor } from '@ckeditor/ckeditor5-core';
|
|
9
|
+
declare const PoweredBy_base: {
|
|
10
|
+
new (): import("@ckeditor/ckeditor5-utils").DomEmitter;
|
|
11
|
+
prototype: import("@ckeditor/ckeditor5-utils").DomEmitter;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A helper that enables the "powered by" feature in the editor and renders a link to the project's
|
|
15
|
+
* webpage next to the bottom of the editable element (editor root, source editing area, etc.) when the editor is focused.
|
|
16
|
+
*
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
export default class PoweredBy extends PoweredBy_base {
|
|
20
|
+
/**
|
|
21
|
+
* Editor instance the helper was created for.
|
|
22
|
+
*/
|
|
23
|
+
private readonly editor;
|
|
24
|
+
/**
|
|
25
|
+
* A reference to the balloon panel hosting and positioning the "powered by" link and logo.
|
|
26
|
+
*/
|
|
27
|
+
private _balloonView;
|
|
28
|
+
/**
|
|
29
|
+
* A throttled version of the {@link #_showBalloon} method meant for frequent use to avoid performance loss.
|
|
30
|
+
*/
|
|
31
|
+
private _showBalloonThrottled;
|
|
32
|
+
/**
|
|
33
|
+
* A reference to the last editable element (root, source editing area, etc.) focused by the user.
|
|
34
|
+
* Since the focus can move to other focusable elements in the UI, this reference allows positioning the balloon over the
|
|
35
|
+
* right element whether the user is typing or using the UI.
|
|
36
|
+
*/
|
|
37
|
+
private _lastFocusedEditableElement;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a "powered by" helper for a given editor. The feature is initialized on Editor#ready
|
|
40
|
+
* event.
|
|
41
|
+
*
|
|
42
|
+
* @param editor
|
|
43
|
+
*/
|
|
44
|
+
constructor(editor: Editor);
|
|
45
|
+
/**
|
|
46
|
+
* Destroys the "powered by" helper along with its view.
|
|
47
|
+
*/
|
|
48
|
+
destroy(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Enables "powered by" label once the editor (ui) is ready.
|
|
51
|
+
*/
|
|
52
|
+
private _handleEditorReady;
|
|
53
|
+
/**
|
|
54
|
+
* Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
|
|
55
|
+
* with the "powered by" view inside ready for positioning.
|
|
56
|
+
*/
|
|
57
|
+
private _createBalloonView;
|
|
58
|
+
/**
|
|
59
|
+
* Attempts to display the balloon with the "powered by" view.
|
|
60
|
+
*/
|
|
61
|
+
private _showBalloon;
|
|
62
|
+
/**
|
|
63
|
+
* Hides the "powered by" balloon if already visible.
|
|
64
|
+
*/
|
|
65
|
+
private _hideBalloon;
|
|
66
|
+
/**
|
|
67
|
+
* Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
|
|
68
|
+
*/
|
|
69
|
+
private _updateLastFocusedEditableElement;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,285 @@
|
|
|
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
|
+
import { Rect, DomEmitterMixin, findClosestScrollableAncestor, verifyLicense } from '@ckeditor/ckeditor5-utils';
|
|
6
|
+
import BalloonPanelView from '../panel/balloon/balloonpanelview';
|
|
7
|
+
import IconView from '../icon/iconview';
|
|
8
|
+
import View from '../view';
|
|
9
|
+
import { throttle } from 'lodash-es';
|
|
10
|
+
import poweredByIcon from '../../theme/icons/project-logo.svg';
|
|
11
|
+
const ICON_WIDTH = 53;
|
|
12
|
+
const ICON_HEIGHT = 10;
|
|
13
|
+
const NARROW_ROOT_HEIGHT_THRESHOLD = 50;
|
|
14
|
+
const NARROW_ROOT_WIDTH_THRESHOLD = 350;
|
|
15
|
+
const OFF_THE_SCREEN_POSITION = {
|
|
16
|
+
top: -99999,
|
|
17
|
+
left: -99999,
|
|
18
|
+
name: 'invalid',
|
|
19
|
+
config: {
|
|
20
|
+
withArrow: false
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A helper that enables the "powered by" feature in the editor and renders a link to the project's
|
|
25
|
+
* webpage next to the bottom of the editable element (editor root, source editing area, etc.) when the editor is focused.
|
|
26
|
+
*
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
export default class PoweredBy extends DomEmitterMixin() {
|
|
30
|
+
/**
|
|
31
|
+
* Creates a "powered by" helper for a given editor. The feature is initialized on Editor#ready
|
|
32
|
+
* event.
|
|
33
|
+
*
|
|
34
|
+
* @param editor
|
|
35
|
+
*/
|
|
36
|
+
constructor(editor) {
|
|
37
|
+
super();
|
|
38
|
+
this.editor = editor;
|
|
39
|
+
this._balloonView = null;
|
|
40
|
+
this._lastFocusedEditableElement = null;
|
|
41
|
+
this._showBalloonThrottled = throttle(this._showBalloon.bind(this), 50, { leading: true });
|
|
42
|
+
editor.on('ready', this._handleEditorReady.bind(this));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Destroys the "powered by" helper along with its view.
|
|
46
|
+
*/
|
|
47
|
+
destroy() {
|
|
48
|
+
const balloon = this._balloonView;
|
|
49
|
+
if (balloon) {
|
|
50
|
+
// Balloon gets destroyed by the body collection.
|
|
51
|
+
// The powered by view gets destroyed by the balloon.
|
|
52
|
+
balloon.unpin();
|
|
53
|
+
this._balloonView = null;
|
|
54
|
+
}
|
|
55
|
+
this._showBalloonThrottled.cancel();
|
|
56
|
+
this.stopListening();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Enables "powered by" label once the editor (ui) is ready.
|
|
60
|
+
*/
|
|
61
|
+
_handleEditorReady() {
|
|
62
|
+
const editor = this.editor;
|
|
63
|
+
/* istanbul ignore next -- @preserve */
|
|
64
|
+
if (verifyLicense(editor.config.get('licenseKey')) === 'VALID') {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// No view means no body collection to append the powered by balloon to.
|
|
68
|
+
if (!editor.ui.view) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
editor.ui.focusTracker.on('change:isFocused', (evt, data, isFocused) => {
|
|
72
|
+
this._updateLastFocusedEditableElement();
|
|
73
|
+
if (isFocused) {
|
|
74
|
+
this._showBalloon();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this._hideBalloon();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
editor.ui.focusTracker.on('change:focusedElement', (evt, data, focusedElement) => {
|
|
81
|
+
this._updateLastFocusedEditableElement();
|
|
82
|
+
if (focusedElement) {
|
|
83
|
+
this._showBalloon();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
editor.ui.on('update', () => {
|
|
87
|
+
this._showBalloonThrottled();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
|
|
92
|
+
* with the "powered by" view inside ready for positioning.
|
|
93
|
+
*/
|
|
94
|
+
_createBalloonView() {
|
|
95
|
+
const editor = this.editor;
|
|
96
|
+
const balloon = this._balloonView = new BalloonPanelView();
|
|
97
|
+
const view = new PoweredByView(editor.locale);
|
|
98
|
+
balloon.content.add(view);
|
|
99
|
+
balloon.set({
|
|
100
|
+
class: 'ck-powered-by-balloon'
|
|
101
|
+
});
|
|
102
|
+
editor.ui.view.body.add(balloon);
|
|
103
|
+
editor.ui.focusTracker.add(balloon.element);
|
|
104
|
+
this._balloonView = balloon;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Attempts to display the balloon with the "powered by" view.
|
|
108
|
+
*/
|
|
109
|
+
_showBalloon() {
|
|
110
|
+
if (!this._lastFocusedEditableElement) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const attachOptions = getBalloonAttachOptions(this.editor, this._lastFocusedEditableElement);
|
|
114
|
+
if (attachOptions) {
|
|
115
|
+
if (!this._balloonView) {
|
|
116
|
+
this._createBalloonView();
|
|
117
|
+
}
|
|
118
|
+
this._balloonView.pin(attachOptions);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Hides the "powered by" balloon if already visible.
|
|
123
|
+
*/
|
|
124
|
+
_hideBalloon() {
|
|
125
|
+
if (this._balloonView) {
|
|
126
|
+
this._balloonView.unpin();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
|
|
131
|
+
*/
|
|
132
|
+
_updateLastFocusedEditableElement() {
|
|
133
|
+
const editor = this.editor;
|
|
134
|
+
const isFocused = editor.ui.focusTracker.isFocused;
|
|
135
|
+
const focusedElement = editor.ui.focusTracker.focusedElement;
|
|
136
|
+
if (!isFocused || !focusedElement) {
|
|
137
|
+
this._lastFocusedEditableElement = null;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const editableEditorElements = Array.from(editor.ui.getEditableElementsNames()).map(name => {
|
|
141
|
+
return editor.ui.getEditableElement(name);
|
|
142
|
+
});
|
|
143
|
+
if (editableEditorElements.includes(focusedElement)) {
|
|
144
|
+
this._lastFocusedEditableElement = focusedElement;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// If it's none of the editable element, then the focus is somewhere in the UI. Let's display powered by
|
|
148
|
+
// over the first element then.
|
|
149
|
+
this._lastFocusedEditableElement = editableEditorElements[0];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A view displaying a "powered by" label and project logo wrapped in a link.
|
|
155
|
+
*/
|
|
156
|
+
class PoweredByView extends View {
|
|
157
|
+
/**
|
|
158
|
+
* Created an instance of the "powered by" view.
|
|
159
|
+
*
|
|
160
|
+
* @param locale The localization services instance.
|
|
161
|
+
*/
|
|
162
|
+
constructor(locale) {
|
|
163
|
+
super(locale);
|
|
164
|
+
const iconView = new IconView();
|
|
165
|
+
const bind = this.bindTemplate;
|
|
166
|
+
iconView.set({
|
|
167
|
+
content: poweredByIcon,
|
|
168
|
+
isColorInherited: false
|
|
169
|
+
});
|
|
170
|
+
iconView.extendTemplate({
|
|
171
|
+
attributes: {
|
|
172
|
+
style: {
|
|
173
|
+
width: ICON_WIDTH + 'px',
|
|
174
|
+
height: ICON_HEIGHT + 'px'
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
this.setTemplate({
|
|
179
|
+
tag: 'div',
|
|
180
|
+
attributes: {
|
|
181
|
+
class: ['ck', 'ck-powered-by'],
|
|
182
|
+
'aria-hidden': true
|
|
183
|
+
},
|
|
184
|
+
children: [
|
|
185
|
+
{
|
|
186
|
+
tag: 'a',
|
|
187
|
+
attributes: {
|
|
188
|
+
href: 'https://ckeditor.com/?utm_source=ckeditor&' +
|
|
189
|
+
'utm_medium=referral&utm_campaign=701Dn000000hVgmIAE_powered_by_ckeditor_logo',
|
|
190
|
+
target: '_blank',
|
|
191
|
+
tabindex: '-1'
|
|
192
|
+
},
|
|
193
|
+
children: [
|
|
194
|
+
{
|
|
195
|
+
tag: 'span',
|
|
196
|
+
attributes: {
|
|
197
|
+
class: ['ck', 'ck-powered-by__label']
|
|
198
|
+
},
|
|
199
|
+
children: ['Powered by']
|
|
200
|
+
},
|
|
201
|
+
iconView
|
|
202
|
+
],
|
|
203
|
+
on: {
|
|
204
|
+
dragstart: bind.to(evt => evt.preventDefault())
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function getBalloonAttachOptions(editor, focusedEditableElement) {
|
|
212
|
+
const poweredByConfig = getNormalizedConfig(editor);
|
|
213
|
+
const positioningFunction = poweredByConfig.side === 'right' ?
|
|
214
|
+
getLowerRightCornerPosition(focusedEditableElement, poweredByConfig) :
|
|
215
|
+
getLowerLeftCornerPosition(focusedEditableElement, poweredByConfig);
|
|
216
|
+
return {
|
|
217
|
+
target: focusedEditableElement,
|
|
218
|
+
positions: [positioningFunction]
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function getLowerRightCornerPosition(focusedEditableElement, config) {
|
|
222
|
+
return getLowerCornerPosition(focusedEditableElement, config, (rootRect, balloonRect) => {
|
|
223
|
+
return rootRect.left + rootRect.width - balloonRect.width - config.horizontalOffset;
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function getLowerLeftCornerPosition(focusedEditableElement, config) {
|
|
227
|
+
return getLowerCornerPosition(focusedEditableElement, config, rootRect => rootRect.left + config.horizontalOffset);
|
|
228
|
+
}
|
|
229
|
+
function getLowerCornerPosition(focusedEditableElement, config, getBalloonLeft) {
|
|
230
|
+
return (editableElementRect, balloonRect) => {
|
|
231
|
+
const visibleEditableElementRect = editableElementRect.getVisible();
|
|
232
|
+
// Root cropped by ancestors.
|
|
233
|
+
if (!visibleEditableElementRect) {
|
|
234
|
+
return OFF_THE_SCREEN_POSITION;
|
|
235
|
+
}
|
|
236
|
+
if (editableElementRect.width < NARROW_ROOT_WIDTH_THRESHOLD || editableElementRect.height < NARROW_ROOT_HEIGHT_THRESHOLD) {
|
|
237
|
+
return OFF_THE_SCREEN_POSITION;
|
|
238
|
+
}
|
|
239
|
+
let balloonTop;
|
|
240
|
+
if (config.position === 'inside') {
|
|
241
|
+
balloonTop = editableElementRect.bottom - balloonRect.height;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
balloonTop = editableElementRect.bottom - balloonRect.height / 2;
|
|
245
|
+
}
|
|
246
|
+
balloonTop -= config.verticalOffset;
|
|
247
|
+
const balloonLeft = getBalloonLeft(editableElementRect, balloonRect);
|
|
248
|
+
if (config.position === 'inside') {
|
|
249
|
+
const newBalloonRect = balloonRect.clone().moveTo(balloonLeft, balloonTop);
|
|
250
|
+
// The watermark cannot be positioned in this corner because the corner is not quite visible.
|
|
251
|
+
if (newBalloonRect.getIntersectionArea(visibleEditableElementRect) < newBalloonRect.getArea()) {
|
|
252
|
+
return OFF_THE_SCREEN_POSITION;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
const firstScrollableEditableElementAncestor = findClosestScrollableAncestor(focusedEditableElement);
|
|
257
|
+
if (firstScrollableEditableElementAncestor) {
|
|
258
|
+
const firstScrollableEditableElementAncestorRect = new Rect(firstScrollableEditableElementAncestor);
|
|
259
|
+
// The watermark cannot be positioned in this corner because the corner is "not visible enough".
|
|
260
|
+
if (visibleEditableElementRect.bottom + balloonRect.height / 2 > firstScrollableEditableElementAncestorRect.bottom) {
|
|
261
|
+
return OFF_THE_SCREEN_POSITION;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
top: balloonTop,
|
|
267
|
+
left: balloonLeft,
|
|
268
|
+
name: `position_${config.position}-side_${config.side}`,
|
|
269
|
+
config: {
|
|
270
|
+
withArrow: false
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function getNormalizedConfig(editor) {
|
|
276
|
+
const userConfig = editor.config.get('ui.poweredBy');
|
|
277
|
+
const position = userConfig && userConfig.position || 'border';
|
|
278
|
+
return {
|
|
279
|
+
position,
|
|
280
|
+
verticalOffset: position === 'inside' ? 5 : 0,
|
|
281
|
+
horizontalOffset: 5,
|
|
282
|
+
side: editor.locale.contentLanguageDirection === 'ltr' ? 'right' : 'left',
|
|
283
|
+
...userConfig
|
|
284
|
+
};
|
|
285
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { default as SwitchButtonView } from './button/switchbuttonview';
|
|
|
17
17
|
export * from './colorgrid/utils';
|
|
18
18
|
export { default as ColorGridView, type ColorDefinition } from './colorgrid/colorgridview';
|
|
19
19
|
export { default as ColorTileView } from './colorgrid/colortileview';
|
|
20
|
+
export { default as ColorPickerView } from './colorpicker/colorpickerview';
|
|
21
|
+
export type { ColorPickerConfig, ColorPickerOutputFormat } from './colorpicker/utils';
|
|
20
22
|
export { default as ComponentFactory } from './componentfactory';
|
|
21
23
|
export { default as DropdownView } from './dropdown/dropdownview';
|
|
22
24
|
export { default as DropdownPanelView } from './dropdown/dropdownpanelview';
|
|
@@ -53,4 +55,5 @@ export { default as BalloonToolbar, type BalloonToolbarShowEvent } from './toolb
|
|
|
53
55
|
export { default as BlockToolbar } from './toolbar/block/blocktoolbar';
|
|
54
56
|
export { default as View, type UIViewRenderEvent } from './view';
|
|
55
57
|
export { default as ViewCollection } from './viewcollection';
|
|
58
|
+
export { default as ColorPaletteIcon } from '../theme/icons/color-palette.svg';
|
|
56
59
|
import './augmentation';
|
package/src/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { default as SwitchButtonView } from './button/switchbuttonview';
|
|
|
16
16
|
export * from './colorgrid/utils';
|
|
17
17
|
export { default as ColorGridView } from './colorgrid/colorgridview';
|
|
18
18
|
export { default as ColorTileView } from './colorgrid/colortileview';
|
|
19
|
+
export { default as ColorPickerView } from './colorpicker/colorpickerview';
|
|
19
20
|
export { default as ComponentFactory } from './componentfactory';
|
|
20
21
|
export { default as DropdownView } from './dropdown/dropdownview';
|
|
21
22
|
export { default as DropdownPanelView } from './dropdown/dropdownpanelview';
|
|
@@ -52,4 +53,5 @@ export { default as BalloonToolbar } from './toolbar/balloon/balloontoolbar';
|
|
|
52
53
|
export { default as BlockToolbar } from './toolbar/block/blocktoolbar';
|
|
53
54
|
export { default as View } from './view';
|
|
54
55
|
export { default as ViewCollection } from './viewcollection';
|
|
56
|
+
export { default as ColorPaletteIcon } from '../theme/icons/color-palette.svg';
|
|
55
57
|
import './augmentation';
|
package/src/list/listitemview.js
CHANGED
package/src/list/listview.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown
|
|
|
32
32
|
* @observable
|
|
33
33
|
*/
|
|
34
34
|
ariaLabel: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The property reflected by the `role` DOM attribute to be used by assistive technologies.
|
|
37
|
+
*
|
|
38
|
+
* @observable
|
|
39
|
+
*/
|
|
40
|
+
role: string | undefined;
|
|
35
41
|
/**
|
|
36
42
|
* Helps cycling over focusable {@link #items} in the list.
|
|
37
43
|
*/
|
package/src/list/listview.js
CHANGED
|
@@ -34,6 +34,7 @@ export default class ListView extends View {
|
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
this.set('ariaLabel', undefined);
|
|
37
|
+
this.set('role', undefined);
|
|
37
38
|
this.setTemplate({
|
|
38
39
|
tag: 'ul',
|
|
39
40
|
attributes: {
|
|
@@ -42,6 +43,7 @@ export default class ListView extends View {
|
|
|
42
43
|
'ck-reset',
|
|
43
44
|
'ck-list'
|
|
44
45
|
],
|
|
46
|
+
role: bind.to('role'),
|
|
45
47
|
'aria-label': bind.to('ariaLabel')
|
|
46
48
|
},
|
|
47
49
|
children: this.items
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/* global window */
|
|
9
9
|
import { Plugin, icons } from '@ckeditor/ckeditor5-core';
|
|
10
|
-
import { Rect, ResizeObserver, getOptimalPosition,
|
|
10
|
+
import { Rect, ResizeObserver, getOptimalPosition, toUnit } from '@ckeditor/ckeditor5-utils';
|
|
11
11
|
import BlockButtonView from './blockbuttonview';
|
|
12
12
|
import BalloonPanelView from '../../panel/balloon/balloonpanelview';
|
|
13
13
|
import ToolbarView from '../toolbarview';
|
|
@@ -177,12 +177,6 @@ export default class BlockToolbar extends Plugin {
|
|
|
177
177
|
isFloating: true
|
|
178
178
|
});
|
|
179
179
|
toolbarView.ariaLabel = t('Editor block content toolbar');
|
|
180
|
-
// When toolbar lost focus then panel should hide.
|
|
181
|
-
toolbarView.focusTracker.on('change:isFocused', (evt, name, is) => {
|
|
182
|
-
if (!is) {
|
|
183
|
-
this._hidePanel();
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
180
|
return toolbarView;
|
|
187
181
|
}
|
|
188
182
|
/**
|
|
@@ -209,27 +203,11 @@ export default class BlockToolbar extends Plugin {
|
|
|
209
203
|
const editor = this.editor;
|
|
210
204
|
const t = editor.t;
|
|
211
205
|
const buttonView = new BlockButtonView(editor.locale);
|
|
212
|
-
const bind = buttonView.bindTemplate;
|
|
213
206
|
buttonView.set({
|
|
214
207
|
label: t('Edit block'),
|
|
215
208
|
icon: pilcrow,
|
|
216
209
|
withText: false
|
|
217
210
|
});
|
|
218
|
-
// Note that this piece over here overrides the default mousedown logic in ButtonView
|
|
219
|
-
// to make it work with BlockToolbar. See the implementation of the ButtonView class to learn more.
|
|
220
|
-
buttonView.extendTemplate({
|
|
221
|
-
on: {
|
|
222
|
-
mousedown: bind.to(evt => {
|
|
223
|
-
// On Safari we have to force the focus on a button on click as it's the only browser
|
|
224
|
-
// that doesn't do that automatically. See #12115.
|
|
225
|
-
if (env.isSafari && this.panelView.isVisible) {
|
|
226
|
-
this.toolbarView.focus();
|
|
227
|
-
}
|
|
228
|
-
// Workaround to #12184, see https://github.com/ckeditor/ckeditor5/issues/12184#issuecomment-1199147964.
|
|
229
|
-
evt.preventDefault();
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
211
|
// Bind the panelView observable properties to the buttonView.
|
|
234
212
|
buttonView.bind('isOn').to(this.panelView, 'isVisible');
|
|
235
213
|
buttonView.bind('tooltip').to(this.panelView, 'isVisible', isVisible => !isVisible);
|
|
@@ -259,8 +237,8 @@ export default class BlockToolbar extends Plugin {
|
|
|
259
237
|
this._hideButton();
|
|
260
238
|
return;
|
|
261
239
|
}
|
|
262
|
-
// Hides the button when the
|
|
263
|
-
if (editor.
|
|
240
|
+
// Hides the button when the selection is in non-editable place.
|
|
241
|
+
if (!editor.model.canEditAt(editor.model.document.selection)) {
|
|
264
242
|
this._hideButton();
|
|
265
243
|
return;
|
|
266
244
|
}
|
|
@@ -83,7 +83,8 @@ export default class ToolbarView extends View {
|
|
|
83
83
|
'aria-label': bind.to('ariaLabel'),
|
|
84
84
|
style: {
|
|
85
85
|
maxWidth: bind.to('maxWidth')
|
|
86
|
-
}
|
|
86
|
+
},
|
|
87
|
+
tabindex: -1
|
|
87
88
|
},
|
|
88
89
|
children: this.children,
|
|
89
90
|
on: {
|
|
@@ -98,6 +99,7 @@ export default class ToolbarView extends View {
|
|
|
98
99
|
*/
|
|
99
100
|
render() {
|
|
100
101
|
super.render();
|
|
102
|
+
this.focusTracker.add(this.element);
|
|
101
103
|
// Children added before rendering should be known to the #focusTracker.
|
|
102
104
|
for (const item of this.items) {
|
|
103
105
|
this.focusTracker.add(item.element);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 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
|
+
.ck.ck-input {
|
|
7
|
+
min-width: unset;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.color-picker-hex-input {
|
|
11
|
+
width: max-content;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ck.ck-color-picker__row {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
flex-wrap: nowrap;
|
|
18
|
+
justify-content: space-between;
|
|
19
|
+
|
|
20
|
+
& .ck-color-picker__hash-view {
|
|
21
|
+
padding-top: var(--ck-spacing-tiny);
|
|
22
|
+
padding-right: var(--ck-spacing-medium);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 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
|
+
:root {
|
|
7
|
+
--ck-powered-by-line-height: 10px;
|
|
8
|
+
--ck-powered-by-padding-top: 2px;
|
|
9
|
+
--ck-powered-by-padding-left: 4px;
|
|
10
|
+
--ck-powered-by-text-color: hsl(0, 0%, 31%);
|
|
11
|
+
--ck-powered-by-border-radius: var(--ck-border-radius);
|
|
12
|
+
--ck-powered-by-background: hsl(0, 0%, 100%);
|
|
13
|
+
--ck-powered-by-border-color: var(--ck-color-focus-border);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.ck.ck-balloon-panel.ck-powered-by-balloon {
|
|
17
|
+
--ck-border-radius: var(--ck-powered-by-border-radius);
|
|
18
|
+
|
|
19
|
+
border: 0;
|
|
20
|
+
box-shadow: none;
|
|
21
|
+
background: var(--ck-powered-by-background);
|
|
22
|
+
min-height: unset;
|
|
23
|
+
|
|
24
|
+
& .ck.ck-powered-by {
|
|
25
|
+
line-height: var(--ck-powered-by-line-height);
|
|
26
|
+
|
|
27
|
+
& a {
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
opacity: .66;
|
|
32
|
+
filter: grayscale(80%);
|
|
33
|
+
line-height: var(--ck-powered-by-line-height);
|
|
34
|
+
padding: var(--ck-powered-by-padding-top) var(--ck-powered-by-padding-left);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
& .ck-powered-by__label {
|
|
38
|
+
font-size: 7.5px;
|
|
39
|
+
letter-spacing: -.2px;
|
|
40
|
+
padding-left: 2px;
|
|
41
|
+
text-transform: uppercase;
|
|
42
|
+
font-weight: bold;
|
|
43
|
+
margin-right: 4px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
line-height: normal;
|
|
46
|
+
color: var(--ck-powered-by-text-color);
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
& .ck-icon {
|
|
51
|
+
display: block;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&:hover {
|
|
56
|
+
& a {
|
|
57
|
+
filter: grayscale(0%);
|
|
58
|
+
opacity: 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&[class*="position_border"] {
|
|
64
|
+
border: var(--ck-focus-ring);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.209 18.717A8.5 8.5 0 1 1 18.686 9.6h-.008l.002.12a3 3 0 0 1-2.866 2.997h-.268l-.046-.002v.002h-4.791a2 2 0 1 0 0 4 1 1 0 1 1-.128 1.992 8.665 8.665 0 0 1-.372.008Zm-3.918-7.01a1.25 1.25 0 1 0-2.415-.648 1.25 1.25 0 0 0 2.415.647ZM5.723 8.18a1.25 1.25 0 1 0 .647-2.414 1.25 1.25 0 0 0-.647 2.414ZM9.76 6.155a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Zm4.028 1.759a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="53" height="10" viewBox="0 0 53 10"><g clip-path="url(#a)"><path fill="#1C2331" d="M31.724 1.492a15.139 15.139 0 0 0 .045 1.16 2.434 2.434 0 0 0-.687-.34 3.68 3.68 0 0 0-1.103-.166 2.332 2.332 0 0 0-1.14.255 1.549 1.549 0 0 0-.686.87c-.15.41-.225.98-.225 1.712 0 .939.148 1.659.444 2.161.297.503.792.754 1.487.754.452.015.9-.094 1.294-.316.296-.174.557-.4.771-.669l.14.852h1.282V.007h-1.623v1.485ZM31 6.496a1.77 1.77 0 0 1-.494.061.964.964 0 0 1-.521-.127.758.758 0 0 1-.296-.466 3.984 3.984 0 0 1-.093-.992 4.208 4.208 0 0 1 .098-1.052.753.753 0 0 1 .307-.477 1.08 1.08 0 0 1 .55-.122c.233-.004.466.026.69.089l.483.144v2.553c-.11.076-.213.143-.307.2a1.73 1.73 0 0 1-.417.189ZM35.68 0l-.702.004c-.322.002-.482.168-.48.497l.004.581c.002.33.164.493.486.49l.702-.004c.322-.002.481-.167.48-.496L36.165.49c-.002-.33-.164-.493-.486-.491ZM36.145 2.313l-1.612.01.034 5.482 1.613-.01-.035-5.482ZM39.623.79 37.989.8 38 2.306l-.946.056.006 1.009.949-.006.024 2.983c.003.476.143.844.419 1.106.275.26.658.39 1.148.387.132 0 .293-.01.483-.03.19-.02.38-.046.57-.08.163-.028.324-.068.482-.119l-.183-1.095-.702.004a.664.664 0 0 1-.456-.123.553.553 0 0 1-.14-.422l-.016-2.621 1.513-.01-.006-1.064-1.514.01-.01-1.503ZM46.226 2.388c-.41-.184-.956-.274-1.636-.27-.673.004-1.215.101-1.627.29-.402.179-.72.505-.888.91-.18.419-.268.979-.264 1.68.004.688.1 1.24.285 1.655.172.404.495.724.9.894.414.18.957.268 1.63.264.68-.004 1.224-.099 1.632-.284.4-.176.714-.501.878-.905.176-.418.263-.971.258-1.658-.004-.702-.097-1.261-.28-1.677a1.696 1.696 0 0 0-.888-.9Zm-.613 3.607a.77.77 0 0 1-.337.501 1.649 1.649 0 0 1-1.317.009.776.776 0 0 1-.343-.497 4.066 4.066 0 0 1-.105-1.02 4.136 4.136 0 0 1 .092-1.03.786.786 0 0 1 .337-.507 1.59 1.59 0 0 1 1.316-.008.79.79 0 0 1 .344.502c.078.337.113.683.105 1.03.012.343-.019.685-.092 1.02ZM52.114 2.07a2.67 2.67 0 0 0-1.128.278c-.39.191-.752.437-1.072.73l-.157-.846-1.273.008.036 5.572 1.623-.01-.024-3.78c.35-.124.646-.22.887-.286.26-.075.53-.114.8-.118l.45-.003.144-1.546-.286.001ZM22.083 7.426l-1.576-2.532a2.137 2.137 0 0 0-.172-.253 1.95 1.95 0 0 0-.304-.29.138.138 0 0 1 .042-.04 1.7 1.7 0 0 0 .328-.374l1.75-2.71c.01-.015.025-.028.024-.048-.01-.01-.021-.007-.031-.007L20.49 1.17a.078.078 0 0 0-.075.045l-.868 1.384c-.23.366-.46.732-.688 1.099a.108.108 0 0 1-.112.06c-.098-.005-.196-.001-.294-.002-.018 0-.038.006-.055-.007.002-.02.002-.039.005-.058a4.6 4.6 0 0 0 .046-.701V1.203c0-.02-.009-.032-.03-.03h-.033L16.93 1.17c-.084 0-.073-.01-.073.076v6.491c-.001.018.006.028.025.027h1.494c.083 0 .072.007.072-.071v-2.19c0-.055-.003-.11-.004-.166a3.366 3.366 0 0 0-.05-.417h.06c.104 0 .209.002.313-.002a.082.082 0 0 1 .084.05c.535.913 1.07 1.824 1.607 2.736a.104.104 0 0 0 .103.062c.554-.003 1.107-.002 1.66-.002l.069-.003-.019-.032-.188-.304ZM27.112 6.555c-.005-.08-.004-.08-.082-.08h-2.414c-.053 0-.106-.003-.159-.011a.279.279 0 0 1-.246-.209.558.558 0 0 1-.022-.15c0-.382 0-.762-.002-1.143 0-.032.007-.049.042-.044h2.504c.029.003.037-.012.034-.038V3.814c0-.089.013-.078-.076-.078h-2.44c-.07 0-.062.003-.062-.06v-.837c0-.047.004-.093.013-.14a.283.283 0 0 1 .241-.246.717.717 0 0 1 .146-.011h2.484c.024.002.035-.009.036-.033l.003-.038.03-.496c.01-.183.024-.365.034-.548.005-.085.003-.087-.082-.094-.218-.018-.437-.038-.655-.05a17.845 17.845 0 0 0-.657-.026 72.994 72.994 0 0 0-1.756-.016 1.7 1.7 0 0 0-.471.064 1.286 1.286 0 0 0-.817.655c-.099.196-.149.413-.145.633v3.875c0 .072.003.144.011.216a1.27 1.27 0 0 0 .711 1.029c.228.113.48.167.734.158.757-.005 1.515.002 2.272-.042.274-.016.548-.034.82-.053.03-.002.043-.008.04-.041-.008-.104-.012-.208-.019-.312a69.964 69.964 0 0 1-.05-.768ZM16.14 7.415l-.127-1.075c-.004-.03-.014-.04-.044-.037a13.125 13.125 0 0 1-.998.073c-.336.01-.672.02-1.008.016-.116-.001-.233-.014-.347-.039a.746.746 0 0 1-.45-.262c-.075-.1-.132-.211-.167-.33a3.324 3.324 0 0 1-.126-.773 9.113 9.113 0 0 1-.015-.749c0-.285.022-.57.065-.852.023-.158.066-.312.127-.46a.728.728 0 0 1 .518-.443 1.64 1.64 0 0 1 .397-.048c.628-.001 1.255.003 1.882.05.022.001.033-.006.036-.026l.003-.031.06-.55c.019-.177.036-.355.057-.532.004-.034-.005-.046-.04-.056a5.595 5.595 0 0 0-1.213-.21 10.783 10.783 0 0 0-.708-.02c-.24-.003-.48.01-.719.041a3.477 3.477 0 0 0-.625.14 1.912 1.912 0 0 0-.807.497c-.185.2-.33.433-.424.688a4.311 4.311 0 0 0-.24 1.096c-.031.286-.045.572-.042.86-.006.43.024.86.091 1.286.04.25.104.497.193.734.098.279.26.53.473.734.214.205.473.358.756.446.344.11.702.17 1.063.177a8.505 8.505 0 0 0 1.578-.083 6.11 6.11 0 0 0 .766-.18c.03-.008.047-.023.037-.057a.157.157 0 0 1-.003-.025Z"/><path fill="#AFE229" d="M6.016 6.69a1.592 1.592 0 0 0-.614.21c-.23.132-.422.32-.56.546-.044.072-.287.539-.287.539l-.836 1.528.009.006c.038.025.08.046.123.063.127.046.26.07.395.073.505.023 1.011-.007 1.517-.003.29.009.58.002.869-.022a.886.886 0 0 0 .395-.116.962.962 0 0 0 .312-.286c.056-.083.114-.163.164-.249.24-.408.48-.816.718-1.226.075-.128.148-.257.222-.386l.112-.192a1.07 1.07 0 0 0 .153-.518l-1.304.023s-1.258-.005-1.388.01Z"/><path fill="#771BFF" d="m2.848 9.044.76-1.39.184-.352c-.124-.067-.245-.14-.367-.21-.346-.204-.706-.384-1.045-.6a.984.984 0 0 1-.244-.207c-.108-.134-.136-.294-.144-.46-.021-.409-.002-.818-.009-1.227-.003-.195 0-.39.003-.585.004-.322.153-.553.427-.713l.833-.488c.22-.13.44-.257.662-.385.05-.029.105-.052.158-.077.272-.128.519-.047.76.085l.044.028c.123.06.242.125.358.196.318.178.635.357.952.537.095.056.187.117.275.184.194.144.254.35.266.578.016.284.007.569.006.853-.001.28.004.558 0 .838.592-.003 1.259 0 1.259 0l.723-.013c-.003-.292-.007-.584-.007-.876 0-.524.015-1.048-.016-1.571-.024-.42-.135-.8-.492-1.067a5.02 5.02 0 0 0-.506-.339A400.52 400.52 0 0 0 5.94.787C5.722.664 5.513.524 5.282.423 5.255.406 5.228.388 5.2.373 4.758.126 4.305-.026 3.807.21c-.097.046-.197.087-.29.14A699.896 699.896 0 0 0 .783 1.948c-.501.294-.773.717-.778 1.31-.004.36-.009.718-.001 1.077.016.754-.017 1.508.024 2.261.016.304.07.6.269.848.127.15.279.28.448.382.622.4 1.283.734 1.92 1.11l.183.109Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h52.4v10H0z"/></clipPath></defs></svg>
|