@ckeditor/ckeditor5-emoji 44.2.0-alpha.16 → 44.2.0-alpha.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-emoji",
3
- "version": "44.2.0-alpha.16",
3
+ "version": "44.2.0-alpha.3",
4
4
  "description": "Emoji feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,12 +13,12 @@
13
13
  "type": "module",
14
14
  "main": "src/index.js",
15
15
  "dependencies": {
16
- "@ckeditor/ckeditor5-core": "44.2.0-alpha.16",
17
- "@ckeditor/ckeditor5-mention": "44.2.0-alpha.16",
18
- "@ckeditor/ckeditor5-typing": "44.2.0-alpha.16",
19
- "@ckeditor/ckeditor5-ui": "44.2.0-alpha.16",
20
- "@ckeditor/ckeditor5-utils": "44.2.0-alpha.16",
21
- "ckeditor5": "44.2.0-alpha.16",
16
+ "@ckeditor/ckeditor5-core": "44.2.0-alpha.3",
17
+ "@ckeditor/ckeditor5-mention": "44.2.0-alpha.3",
18
+ "@ckeditor/ckeditor5-typing": "44.2.0-alpha.3",
19
+ "@ckeditor/ckeditor5-ui": "44.2.0-alpha.3",
20
+ "@ckeditor/ckeditor5-utils": "44.2.0-alpha.3",
21
+ "ckeditor5": "44.2.0-alpha.3",
22
22
  "fuse.js": "7.0.0",
23
23
  "lodash-es": "4.17.21"
24
24
  },
@@ -2,7 +2,7 @@
2
2
  * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import type { Emoji, EmojiConfig, EmojiMention, EmojiPicker, EmojiRepository, EmojiUtils, EmojiCommand } from './index.js';
5
+ import type { Emoji, EmojiConfig, EmojiMention, EmojiPicker, EmojiRepository, EmojiCommand } from './index.js';
6
6
  declare module '@ckeditor/ckeditor5-core' {
7
7
  interface EditorConfig {
8
8
  /**
@@ -17,7 +17,6 @@ declare module '@ckeditor/ckeditor5-core' {
17
17
  [EmojiMention.pluginName]: EmojiMention;
18
18
  [EmojiPicker.pluginName]: EmojiPicker;
19
19
  [EmojiRepository.pluginName]: EmojiRepository;
20
- [EmojiUtils.pluginName]: EmojiUtils;
21
20
  }
22
21
  interface CommandsMap {
23
22
  emoji: EmojiCommand;
@@ -58,22 +58,6 @@ export interface EmojiConfig {
58
58
  * @default 'default'
59
59
  */
60
60
  skinTone?: SkinToneId;
61
- /**
62
- * The URL from which the emoji definitions should be loaded.
63
- *
64
- * ```ts
65
- * ClassicEditor
66
- * .create( editorElement, {
67
- * plugins: [ Emoji, ... ],
68
- * emoji: {
69
- * definitionsUrl: ''
70
- * }
71
- * } )
72
- * .then( ... )
73
- * .catch( ... );
74
- * ```
75
- */
76
- definitionsUrl?: string;
77
61
  /**
78
62
  * The emoji database version.
79
63
  *
@@ -89,10 +73,8 @@ export interface EmojiConfig {
89
73
  * .catch( ... );
90
74
  * ```
91
75
  *
92
- * If the {@link module:emoji/emojiconfig~EmojiConfig#definitionsUrl `emoji.definitionsUrl`}
93
- * option is provided, `version` is ignored as the defined URL takes precedence over the `version`.
76
+ * @default 16
94
77
  */
95
- version?: EmojiVersion;
78
+ version?: 15 | 16;
96
79
  }
97
80
  export type SkinToneId = 'default' | 'light' | 'medium-light' | 'medium' | 'medium-dark' | 'dark';
98
- export type EmojiVersion = 15 | 16;
@@ -5,7 +5,6 @@
5
5
  import { Plugin, type Editor } from 'ckeditor5/src/core.js';
6
6
  import { Typing } from 'ckeditor5/src/typing.js';
7
7
  import EmojiRepository from './emojirepository.js';
8
- import type EmojiPicker from './emojipicker.js';
9
8
  /**
10
9
  * The emoji mention plugin.
11
10
  *
@@ -15,15 +14,11 @@ export default class EmojiMention extends Plugin {
15
14
  /**
16
15
  * An instance of the {@link module:emoji/emojipicker~EmojiPicker} plugin if it is loaded in the editor.
17
16
  */
18
- emojiPickerPlugin: EmojiPicker | null;
17
+ private _emojiPickerPlugin;
19
18
  /**
20
19
  * An instance of the {@link module:emoji/emojirepository~EmojiRepository} plugin.
21
20
  */
22
- emojiRepositoryPlugin: EmojiRepository;
23
- /**
24
- * A flag that informs if the {@link module:emoji/emojirepository~EmojiRepository} plugin is loaded correctly.
25
- */
26
- private _isEmojiRepositoryAvailable;
21
+ private _emojiRepositoryPlugin;
27
22
  /**
28
23
  * Defines a number of displayed items in the auto complete dropdown.
29
24
  *
@@ -50,16 +45,14 @@ export default class EmojiMention extends Plugin {
50
45
  * @inheritDoc
51
46
  */
52
47
  constructor(editor: Editor);
53
- /**
54
- * Initializes the configuration for emojis in the mention feature.
55
- * If the marker used by emoji mention is already registered, it displays a warning.
56
- * If emoji mention configuration is detected, it does not register it for a second time.
57
- */
58
- private _setupMentionConfiguration;
59
48
  /**
60
49
  * @inheritDoc
61
50
  */
62
51
  init(): Promise<void>;
52
+ /**
53
+ * Initializes the configuration for emojis in the mention feature.
54
+ */
55
+ private _setupMentionConfiguration;
63
56
  /**
64
57
  * Returns the `itemRenderer()` callback for mention config.
65
58
  */
@@ -46,21 +46,11 @@ export default class EmojiMention extends Plugin {
46
46
  });
47
47
  this._emojiDropdownLimit = editor.config.get('emoji.dropdownLimit');
48
48
  this._skinTone = editor.config.get('emoji.skinTone');
49
- this._setupMentionConfiguration(editor);
50
- }
51
- /**
52
- * Initializes the configuration for emojis in the mention feature.
53
- * If the marker used by emoji mention is already registered, it displays a warning.
54
- * If emoji mention configuration is detected, it does not register it for a second time.
55
- */
56
- _setupMentionConfiguration(editor) {
57
- const mergeFieldsPrefix = editor.config.get('mergeFields.prefix');
58
49
  const mentionFeedsConfigs = editor.config.get('mention.feeds');
59
- const isEmojiMarkerUsedByMergeFields = mergeFieldsPrefix ? mergeFieldsPrefix[0] === EMOJI_MENTION_MARKER : false;
60
- const isEmojiMarkerUsedByMention = mentionFeedsConfigs
61
- .filter(config => !config._isEmojiMarker)
62
- .some(config => config.marker === EMOJI_MENTION_MARKER);
63
- if (isEmojiMarkerUsedByMention || isEmojiMarkerUsedByMergeFields) {
50
+ const mergeFieldsPrefix = editor.config.get('mergeFields.prefix');
51
+ const markerAlreadyUsed = mentionFeedsConfigs.some(config => config.marker === EMOJI_MENTION_MARKER);
52
+ const isMarkerUsedByMergeFields = mergeFieldsPrefix ? mergeFieldsPrefix[0] === EMOJI_MENTION_MARKER : false;
53
+ if (markerAlreadyUsed || isMarkerUsedByMergeFields) {
64
54
  /**
65
55
  * The `marker` in the `emoji` config is already used by other plugin configuration.
66
56
  *
@@ -70,12 +60,26 @@ export default class EmojiMention extends Plugin {
70
60
  logWarning('emoji-config-marker-already-used', { marker: EMOJI_MENTION_MARKER });
71
61
  return;
72
62
  }
73
- const isEmojiConfigDefined = mentionFeedsConfigs.some(config => config._isEmojiMarker);
74
- if (isEmojiConfigDefined) {
63
+ this._setupMentionConfiguration(mentionFeedsConfigs);
64
+ }
65
+ /**
66
+ * @inheritDoc
67
+ */
68
+ async init() {
69
+ const editor = this.editor;
70
+ this._emojiPickerPlugin = editor.plugins.has('EmojiPicker') ? editor.plugins.get('EmojiPicker') : null;
71
+ this._emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
72
+ // Skip overriding the `mention` command listener if the emoji repository is not ready.
73
+ if (!await this._emojiRepositoryPlugin.isReady()) {
75
74
  return;
76
75
  }
76
+ editor.once('ready', this._overrideMentionExecuteListener.bind(this));
77
+ }
78
+ /**
79
+ * Initializes the configuration for emojis in the mention feature.
80
+ */
81
+ _setupMentionConfiguration(mentionFeedsConfigs) {
77
82
  const emojiMentionFeedConfig = {
78
- _isEmojiMarker: true,
79
83
  marker: EMOJI_MENTION_MARKER,
80
84
  dropdownLimit: this._emojiDropdownLimit,
81
85
  itemRenderer: this._customItemRendererFactory(this.editor.t),
@@ -83,19 +87,6 @@ export default class EmojiMention extends Plugin {
83
87
  };
84
88
  this.editor.config.set('mention.feeds', [...mentionFeedsConfigs, emojiMentionFeedConfig]);
85
89
  }
86
- /**
87
- * @inheritDoc
88
- */
89
- async init() {
90
- const editor = this.editor;
91
- this.emojiPickerPlugin = editor.plugins.has('EmojiPicker') ? editor.plugins.get('EmojiPicker') : null;
92
- this.emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
93
- this._isEmojiRepositoryAvailable = await this.emojiRepositoryPlugin.isReady();
94
- // Override the `mention` command listener if the emoji repository is ready.
95
- if (this._isEmojiRepositoryAvailable) {
96
- editor.once('ready', this._overrideMentionExecuteListener.bind(this));
97
- }
98
- }
99
90
  /**
100
91
  * Returns the `itemRenderer()` callback for mention config.
101
92
  */
@@ -152,7 +143,7 @@ export default class EmojiMention extends Plugin {
152
143
  editor.model.change(writer => {
153
144
  editor.model.deleteContent(writer.createSelection(eventData.range));
154
145
  });
155
- const emojiPickerPlugin = this.emojiPickerPlugin;
146
+ const emojiPickerPlugin = this._emojiPickerPlugin;
156
147
  emojiPickerPlugin.showUI(text.slice(1));
157
148
  setTimeout(() => {
158
149
  emojiPickerPlugin.emojiPickerView.focus();
@@ -176,26 +167,18 @@ export default class EmojiMention extends Plugin {
176
167
  if (searchQuery.startsWith(' ')) {
177
168
  return [];
178
169
  }
179
- // Do not show anything when a query starts with a marker character.
180
- if (searchQuery.startsWith(EMOJI_MENTION_MARKER)) {
181
- return [];
182
- }
183
- // If the repository plugin is not available, return an empty feed to avoid confusion. See: #17842.
184
- if (!this._isEmojiRepositoryAvailable) {
185
- return [];
186
- }
187
- const emojis = this.emojiRepositoryPlugin.getEmojiByQuery(searchQuery)
170
+ const emojis = this._emojiRepositoryPlugin.getEmojiByQuery(searchQuery)
188
171
  .map(emoji => {
189
172
  let text = emoji.skins[this._skinTone] || emoji.skins.default;
190
- if (this.emojiPickerPlugin) {
191
- text = emoji.skins[this.emojiPickerPlugin.skinTone] || emoji.skins.default;
173
+ if (this._emojiPickerPlugin) {
174
+ text = emoji.skins[this._emojiPickerPlugin.skinTone] || emoji.skins.default;
192
175
  }
193
176
  return {
194
177
  id: `:${emoji.annotation}:`,
195
178
  text
196
179
  };
197
180
  });
198
- if (!this.emojiPickerPlugin) {
181
+ if (!this._emojiPickerPlugin) {
199
182
  return emojis.slice(0, this._emojiDropdownLimit);
200
183
  }
201
184
  const actionItem = {
@@ -25,11 +25,11 @@ export default class EmojiPicker extends Plugin {
25
25
  /**
26
26
  * The contextual balloon plugin instance.
27
27
  */
28
- balloonPlugin: ContextualBalloon;
28
+ _balloonPlugin: ContextualBalloon;
29
29
  /**
30
30
  * An instance of the {@link module:emoji/emojirepository~EmojiRepository} plugin.
31
31
  */
32
- emojiRepositoryPlugin: EmojiRepository;
32
+ private _emojiRepositoryPlugin;
33
33
  /**
34
34
  * @inheritDoc
35
35
  */
@@ -80,7 +80,7 @@ export default class EmojiPicker extends Plugin {
80
80
  */
81
81
  private _setupConversion;
82
82
  /**
83
- * Returns positioning options for the {@link #balloonPlugin}. They control the way the balloon is attached
83
+ * Returns positioning options for the {@link #_balloonPlugin}. They control the way the balloon is attached
84
84
  * to the target element or selection.
85
85
  */
86
86
  private _getBalloonPositionData;
@@ -42,10 +42,10 @@ export default class EmojiPicker extends Plugin {
42
42
  */
43
43
  async init() {
44
44
  const editor = this.editor;
45
- this.balloonPlugin = editor.plugins.get('ContextualBalloon');
46
- this.emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
45
+ this._balloonPlugin = editor.plugins.get('ContextualBalloon');
46
+ this._emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
47
47
  // Skip registering a button in the toolbar and list item in the menu bar if the emoji repository is not ready.
48
- if (!await this.emojiRepositoryPlugin.isReady()) {
48
+ if (!await this._emojiRepositoryPlugin.isReady()) {
49
49
  return;
50
50
  }
51
51
  const command = new EmojiCommand(editor);
@@ -99,8 +99,8 @@ export default class EmojiPicker extends Plugin {
99
99
  this.emojiPickerView.searchView.setInputValue(searchValue);
100
100
  }
101
101
  this.emojiPickerView.searchView.search(searchValue);
102
- if (!this.balloonPlugin.hasView(this.emojiPickerView)) {
103
- this.balloonPlugin.add({
102
+ if (!this._balloonPlugin.hasView(this.emojiPickerView)) {
103
+ this._balloonPlugin.add({
104
104
  view: this.emojiPickerView,
105
105
  position: this._getBalloonPositionData()
106
106
  });
@@ -129,11 +129,11 @@ export default class EmojiPicker extends Plugin {
129
129
  */
130
130
  _createEmojiPickerView() {
131
131
  const emojiPickerView = new EmojiPickerView(this.editor.locale, {
132
- emojiCategories: this.emojiRepositoryPlugin.getEmojiCategories(),
132
+ emojiCategories: this._emojiRepositoryPlugin.getEmojiCategories(),
133
133
  skinTone: this.editor.config.get('emoji.skinTone'),
134
- skinTones: this.emojiRepositoryPlugin.getSkinTones(),
134
+ skinTones: this._emojiRepositoryPlugin.getSkinTones(),
135
135
  getEmojiByQuery: (query) => {
136
- return this.emojiRepositoryPlugin.getEmojiByQuery(query);
136
+ return this._emojiRepositoryPlugin.getEmojiByQuery(query);
137
137
  }
138
138
  });
139
139
  // Insert an emoji on a tile click.
@@ -145,8 +145,8 @@ export default class EmojiPicker extends Plugin {
145
145
  });
146
146
  // Update the balloon position when layout is changed.
147
147
  this.listenTo(emojiPickerView, 'update', () => {
148
- if (this.balloonPlugin.visibleView === emojiPickerView) {
149
- this.balloonPlugin.updatePosition();
148
+ if (this._balloonPlugin.visibleView === emojiPickerView) {
149
+ this._balloonPlugin.updatePosition();
150
150
  }
151
151
  });
152
152
  // Close the panel on `Esc` key press when the **actions have focus**.
@@ -157,9 +157,9 @@ export default class EmojiPicker extends Plugin {
157
157
  // Close the dialog when clicking outside of it.
158
158
  clickOutsideHandler({
159
159
  emitter: emojiPickerView,
160
- contextElements: [this.balloonPlugin.view.element],
160
+ contextElements: [this._balloonPlugin.view.element],
161
161
  callback: () => this._hideUI(),
162
- activator: () => this.balloonPlugin.visibleView === emojiPickerView
162
+ activator: () => this._balloonPlugin.visibleView === emojiPickerView
163
163
  });
164
164
  return emojiPickerView;
165
165
  }
@@ -167,7 +167,7 @@ export default class EmojiPicker extends Plugin {
167
167
  * Hides the balloon with the emoji picker.
168
168
  */
169
169
  _hideUI() {
170
- this.balloonPlugin.remove(this.emojiPickerView);
170
+ this._balloonPlugin.remove(this.emojiPickerView);
171
171
  this.emojiPickerView.searchView.setInputValue('');
172
172
  this.editor.editing.view.focus();
173
173
  this._hideFakeVisualSelection();
@@ -198,7 +198,7 @@ export default class EmojiPicker extends Plugin {
198
198
  });
199
199
  }
200
200
  /**
201
- * Returns positioning options for the {@link #balloonPlugin}. They control the way the balloon is attached
201
+ * Returns positioning options for the {@link #_balloonPlugin}. They control the way the balloon is attached
202
202
  * to the target element or selection.
203
203
  */
204
204
  _getBalloonPositionData() {
@@ -2,36 +2,31 @@
2
2
  * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { type Editor, Plugin } from 'ckeditor5/src/core.js';
6
- import EmojiUtils from './emojiutils.js';
5
+ import { Plugin, type Editor } from 'ckeditor5/src/core.js';
7
6
  import type { SkinToneId } from './emojiconfig.js';
8
7
  /**
9
8
  * The emoji repository plugin.
10
9
  *
11
- * Loads the emoji repository from URL during plugin initialization and provides utility methods to search it.
10
+ * Loads the emoji database from URL during plugin initialization and provides utility methods to search it.
12
11
  */
13
12
  export default class EmojiRepository extends Plugin {
14
13
  /**
15
- * A callback to resolve the {@link #_repositoryPromise} to control the return value of this promise.
14
+ * Emoji database.
16
15
  */
17
- private _repositoryPromiseResolveCallback;
16
+ private _database;
18
17
  /**
19
- * An instance of the [Fuse.js](https://www.fusejs.io/) library.
18
+ * A promise resolved after downloading the emoji database.
19
+ * The promise resolves with `true` when the database is successfully downloaded or `false` otherwise.
20
20
  */
21
- private _fuseSearch;
21
+ private _databasePromise;
22
22
  /**
23
- * The resolved URL from which the emoji repository is downloaded.
23
+ * A callback to resolve the {@link #_databasePromise} to control the return value of this promise.
24
24
  */
25
- private readonly _url;
25
+ private _databasePromiseResolveCallback;
26
26
  /**
27
- * A promise resolved after downloading the emoji collection.
28
- * The promise resolves with `true` when the repository is successfully downloaded or `false` otherwise.
29
- */
30
- private readonly _repositoryPromise;
31
- /**
32
- * @inheritDoc
27
+ * An instance of the [Fuse.js](https://www.fusejs.io/) library.
33
28
  */
34
- static get requires(): readonly [typeof EmojiUtils];
29
+ private _fuseSearch;
35
30
  /**
36
31
  * @inheritDoc
37
32
  */
@@ -50,7 +45,7 @@ export default class EmojiRepository extends Plugin {
50
45
  init(): Promise<void>;
51
46
  /**
52
47
  * Returns an array of emoji entries that match the search query.
53
- * If the emoji repository is not loaded, the [Fuse.js](https://www.fusejs.io/) instance is not created,
48
+ * If the emoji database is not loaded, the [Fuse.js](https://www.fusejs.io/) instance is not created,
54
49
  * hence this method returns an empty array.
55
50
  *
56
51
  * @param searchQuery A search query to match emoji.
@@ -59,7 +54,7 @@ export default class EmojiRepository extends Plugin {
59
54
  getEmojiByQuery(searchQuery: string): Array<EmojiEntry>;
60
55
  /**
61
56
  * Groups all emojis by categories.
62
- * If the emoji repository is not loaded, it returns an empty array.
57
+ * If the emoji database is not loaded, it returns an empty array.
63
58
  *
64
59
  * @returns An array of emoji entries grouped by categories.
65
60
  */
@@ -69,40 +64,15 @@ export default class EmojiRepository extends Plugin {
69
64
  */
70
65
  getSkinTones(): Array<SkinTone>;
71
66
  /**
72
- * Indicates whether the emoji repository has been successfully downloaded and the plugin is operational.
67
+ * Indicates whether the emoji database has been successfully downloaded and the plugin is operational.
73
68
  */
74
69
  isReady(): Promise<boolean>;
75
70
  /**
76
- * Returns the URL from which the emoji repository is downloaded. If the URL is not provided
77
- * in the configuration, the default URL is used with the version from the configuration.
78
- *
79
- * If both the URL and version are provided, a warning is logged.
80
- */
81
- private _getUrl;
82
- /**
83
- * Warn users on self-hosted installations that this plugin uses a CDN to fetch the emoji repository.
84
- */
85
- private _warnAboutCdnUse;
86
- /**
87
- * Returns the emoji repository in a configured version if it is a non-empty array. Returns `null` otherwise.
88
- */
89
- private _getItems;
90
- /**
91
- * Loads the emoji repository. If the repository is already loaded, it returns the cached result.
92
- * Otherwise, it fetches the repository from the URL and adds it to the cache.
93
- */
94
- private _loadAndCacheEmoji;
95
- /**
96
- * Normalizes the raw data fetched from CDN. By normalization, we meant:
71
+ * A function used to check if the given emoji is supported in the operating system.
97
72
  *
98
- * * Filter out unsupported emoji (these that will not render correctly),
99
- * * Prepare skin tone variants if an emoji defines them.
100
- */
101
- private _normalizeEmoji;
102
- /**
103
- * Versioned emoji repository.
73
+ * Referenced for unit testing purposes.
104
74
  */
105
- private static _results;
75
+ private static _isEmojiSupported;
106
76
  }
107
77
  /**
108
78
  * Represents a single group of the emoji category, e.g., "Smileys & Expressions".