@ckeditor/ckeditor5-emoji 0.0.0-nightly-20250129.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.
- package/CHANGELOG.md +4 -0
- package/LICENSE.md +28 -0
- package/README.md +31 -0
- package/build/emoji.js +4 -0
- package/ckeditor5-metadata.json +32 -0
- package/dist/index-content.css +4 -0
- package/dist/index-editor.css +111 -0
- package/dist/index.css +143 -0
- package/dist/index.css.map +1 -0
- package/dist/index.js +1477 -0
- package/dist/index.js.map +1 -0
- package/lang/contexts.json +24 -0
- package/package.json +67 -0
- package/src/augmentation.d.ts +24 -0
- package/src/augmentation.js +5 -0
- package/src/emoji.d.ts +32 -0
- package/src/emoji.js +38 -0
- package/src/emojicommand.d.ts +24 -0
- package/src/emojicommand.js +33 -0
- package/src/emojiconfig.d.ts +80 -0
- package/src/emojiconfig.js +5 -0
- package/src/emojimention.d.ts +68 -0
- package/src/emojimention.js +193 -0
- package/src/emojipicker.d.ts +97 -0
- package/src/emojipicker.js +255 -0
- package/src/emojirepository.d.ts +139 -0
- package/src/emojirepository.js +267 -0
- package/src/index.d.ts +14 -0
- package/src/index.js +13 -0
- package/src/ui/emojicategoriesview.d.ts +68 -0
- package/src/ui/emojicategoriesview.js +131 -0
- package/src/ui/emojigridview.d.ts +140 -0
- package/src/ui/emojigridview.js +183 -0
- package/src/ui/emojipickerview.d.ts +91 -0
- package/src/ui/emojipickerview.js +172 -0
- package/src/ui/emojisearchview.d.ts +51 -0
- package/src/ui/emojisearchview.js +89 -0
- package/src/ui/emojitoneview.d.ts +46 -0
- package/src/ui/emojitoneview.js +89 -0
- package/theme/emojicategories.css +29 -0
- package/theme/emojigrid.css +55 -0
- package/theme/emojipicker.css +32 -0
- package/theme/emojitone.css +21 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module emoji/ui/emojigridview
|
|
7
|
+
*/
|
|
8
|
+
import { addKeyboardHandlingForGrid, ButtonView, View } from 'ckeditor5/src/ui.js';
|
|
9
|
+
import { FocusTracker, global, KeystrokeHandler } from 'ckeditor5/src/utils.js';
|
|
10
|
+
import '../../theme/emojigrid.css';
|
|
11
|
+
/**
|
|
12
|
+
* A grid of emoji tiles. It allows browsing emojis and selecting them to be inserted into the content.
|
|
13
|
+
*/
|
|
14
|
+
export default class EmojiGridView extends View {
|
|
15
|
+
/**
|
|
16
|
+
* @inheritDoc
|
|
17
|
+
*/
|
|
18
|
+
constructor(locale, { categoryName, emojiCategories, getEmojiByQuery, skinTone }) {
|
|
19
|
+
super(locale);
|
|
20
|
+
this.set('isEmpty', true);
|
|
21
|
+
this.set('categoryName', categoryName);
|
|
22
|
+
this.set('skinTone', skinTone);
|
|
23
|
+
this.tiles = this.createCollection();
|
|
24
|
+
this.cachedTiles = this.createCollection();
|
|
25
|
+
this.focusTracker = new FocusTracker();
|
|
26
|
+
this.keystrokes = new KeystrokeHandler();
|
|
27
|
+
this._getEmojiByQuery = getEmojiByQuery;
|
|
28
|
+
this.emojiCategories = emojiCategories;
|
|
29
|
+
const bind = this.bindTemplate;
|
|
30
|
+
this.setTemplate({
|
|
31
|
+
tag: 'div',
|
|
32
|
+
children: [
|
|
33
|
+
{
|
|
34
|
+
tag: 'div',
|
|
35
|
+
attributes: {
|
|
36
|
+
role: 'grid',
|
|
37
|
+
class: [
|
|
38
|
+
'ck',
|
|
39
|
+
'ck-emoji__grid'
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
children: this.tiles
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
attributes: {
|
|
46
|
+
role: 'tabpanel',
|
|
47
|
+
class: [
|
|
48
|
+
'ck',
|
|
49
|
+
'ck-emoji__tiles',
|
|
50
|
+
// To avoid issues with focus cycling, ignore a grid when it's empty.
|
|
51
|
+
bind.if('isEmpty', 'ck-hidden', value => value)
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
addKeyboardHandlingForGrid({
|
|
56
|
+
keystrokeHandler: this.keystrokes,
|
|
57
|
+
focusTracker: this.focusTracker,
|
|
58
|
+
gridItems: this.tiles,
|
|
59
|
+
numberOfColumns: () => global.window
|
|
60
|
+
.getComputedStyle(this.element.firstChild) // Responsive `.ck-emoji-grid__tiles`.
|
|
61
|
+
.getPropertyValue('grid-template-columns')
|
|
62
|
+
.split(' ')
|
|
63
|
+
.length,
|
|
64
|
+
uiLanguageDirection: this.locale && this.locale.uiLanguageDirection
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @inheritDoc
|
|
69
|
+
*/
|
|
70
|
+
render() {
|
|
71
|
+
super.render();
|
|
72
|
+
this.keystrokes.listenTo(this.element);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* @inheritDoc
|
|
76
|
+
*/
|
|
77
|
+
destroy() {
|
|
78
|
+
super.destroy();
|
|
79
|
+
this.keystrokes.destroy();
|
|
80
|
+
this.focusTracker.destroy();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Focuses the first focusable in {@link ~EmojiGridView#tiles} if available.
|
|
84
|
+
*/
|
|
85
|
+
focus() {
|
|
86
|
+
const firstTile = this.tiles.first;
|
|
87
|
+
if (firstTile) {
|
|
88
|
+
firstTile.focus();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Filters the grid view by the given regular expression.
|
|
93
|
+
*
|
|
94
|
+
* It filters either by the pattern or an emoji category, but never both.
|
|
95
|
+
*
|
|
96
|
+
* @param pattern Expression to search or `null` when filter by category name.
|
|
97
|
+
*/
|
|
98
|
+
filter(pattern) {
|
|
99
|
+
const { matchingItems, allItems } = pattern ? this._getItemsByQuery(pattern.source) : this._getItemsByCategory();
|
|
100
|
+
this._updateGrid(matchingItems);
|
|
101
|
+
this.set('isEmpty', matchingItems.length === 0);
|
|
102
|
+
return {
|
|
103
|
+
resultsCount: matchingItems.length,
|
|
104
|
+
totalItemsCount: allItems.length
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Filters emojis to show based on the specified query phrase.
|
|
109
|
+
*
|
|
110
|
+
* @param query A query used to filter the grid.
|
|
111
|
+
*/
|
|
112
|
+
_getItemsByQuery(query) {
|
|
113
|
+
return {
|
|
114
|
+
matchingItems: this._getEmojiByQuery(query),
|
|
115
|
+
allItems: this.emojiCategories.flatMap(group => group.items)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Returns emojis that belong to the specified category.
|
|
120
|
+
*/
|
|
121
|
+
_getItemsByCategory() {
|
|
122
|
+
const emojiCategory = this.emojiCategories.find(item => item.title === this.categoryName);
|
|
123
|
+
const { items } = emojiCategory;
|
|
124
|
+
return {
|
|
125
|
+
matchingItems: items,
|
|
126
|
+
allItems: items
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Updates the grid by removing the existing items and insert the new ones.
|
|
131
|
+
*
|
|
132
|
+
* @param items An array of items to insert.
|
|
133
|
+
*/
|
|
134
|
+
_updateGrid(items) {
|
|
135
|
+
// Clean-up.
|
|
136
|
+
[...this.tiles].forEach(item => {
|
|
137
|
+
this.focusTracker.remove(item);
|
|
138
|
+
this.tiles.remove(item);
|
|
139
|
+
});
|
|
140
|
+
items
|
|
141
|
+
// Create tiles from matching results.
|
|
142
|
+
.map(item => {
|
|
143
|
+
const emoji = item.skins[this.skinTone] || item.skins.default;
|
|
144
|
+
return this.cachedTiles.get(emoji) || this._createTile(emoji, item.annotation);
|
|
145
|
+
})
|
|
146
|
+
// Insert new elements.
|
|
147
|
+
.forEach(item => {
|
|
148
|
+
this.tiles.add(item);
|
|
149
|
+
this.focusTracker.add(item);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Creates a new tile for the grid. Created tile is added to the {@link #cachedTiles} collection for further usage, if needed.
|
|
154
|
+
*
|
|
155
|
+
* @param emoji The emoji itself.
|
|
156
|
+
* @param name The name of the emoji (e.g. "Smiling Face with Smiling Eyes").
|
|
157
|
+
*/
|
|
158
|
+
_createTile(emoji, name) {
|
|
159
|
+
const tile = new ButtonView(this.locale);
|
|
160
|
+
tile.viewUid = emoji;
|
|
161
|
+
tile.extendTemplate({
|
|
162
|
+
attributes: {
|
|
163
|
+
class: [
|
|
164
|
+
'ck-emoji__tile'
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
tile.set({
|
|
169
|
+
label: emoji,
|
|
170
|
+
tooltip: name,
|
|
171
|
+
withText: true,
|
|
172
|
+
ariaLabel: name,
|
|
173
|
+
// To improve accessibility, disconnect a button and its label connection so that screen
|
|
174
|
+
// readers can read the `[aria-label]` attribute directly from the more descriptive button.
|
|
175
|
+
ariaLabelledBy: undefined
|
|
176
|
+
});
|
|
177
|
+
tile.on('execute', () => {
|
|
178
|
+
this.fire('execute', { name, emoji });
|
|
179
|
+
});
|
|
180
|
+
this.cachedTiles.add(tile);
|
|
181
|
+
return tile;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module emoji/ui/emojipickerview
|
|
7
|
+
*/
|
|
8
|
+
import { FocusCycler, SearchInfoView, View, type FocusableView, type ViewCollection } from 'ckeditor5/src/ui.js';
|
|
9
|
+
import { FocusTracker, KeystrokeHandler, type Locale } from 'ckeditor5/src/utils.js';
|
|
10
|
+
import EmojiGridView, { type EmojiSearchQueryCallback } from './emojigridview.js';
|
|
11
|
+
import EmojiCategoriesView from './emojicategoriesview.js';
|
|
12
|
+
import EmojiSearchView from './emojisearchview.js';
|
|
13
|
+
import EmojiToneView from './emojitoneview.js';
|
|
14
|
+
import type { SkinToneId } from '../emojiconfig.js';
|
|
15
|
+
import type { EmojiCategory, SkinTone } from '../emojirepository.js';
|
|
16
|
+
/**
|
|
17
|
+
* A view that glues pieces of the emoji panel together.
|
|
18
|
+
*/
|
|
19
|
+
export default class EmojiPickerView extends View<HTMLDivElement> {
|
|
20
|
+
/**
|
|
21
|
+
* A collection of the focusable children of the view.
|
|
22
|
+
*/
|
|
23
|
+
readonly items: ViewCollection<FocusableView>;
|
|
24
|
+
/**
|
|
25
|
+
* Tracks information about the DOM focus in the view.
|
|
26
|
+
*/
|
|
27
|
+
readonly focusTracker: FocusTracker;
|
|
28
|
+
/**
|
|
29
|
+
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
|
30
|
+
*/
|
|
31
|
+
readonly keystrokes: KeystrokeHandler;
|
|
32
|
+
/**
|
|
33
|
+
* Helps cycling over focusable {@link #items} in the view.
|
|
34
|
+
*/
|
|
35
|
+
readonly focusCycler: FocusCycler;
|
|
36
|
+
/**
|
|
37
|
+
* An instance of the `EmojiSearchView`.
|
|
38
|
+
*/
|
|
39
|
+
readonly searchView: EmojiSearchView;
|
|
40
|
+
/**
|
|
41
|
+
* An instance of the `EmojiToneView`.
|
|
42
|
+
*/
|
|
43
|
+
readonly toneView: EmojiToneView;
|
|
44
|
+
/**
|
|
45
|
+
* An instance of the `EmojiCategoriesView`.
|
|
46
|
+
*/
|
|
47
|
+
readonly categoriesView: EmojiCategoriesView;
|
|
48
|
+
/**
|
|
49
|
+
* An instance of the `EmojiGridView`.
|
|
50
|
+
*/
|
|
51
|
+
readonly gridView: EmojiGridView;
|
|
52
|
+
/**
|
|
53
|
+
* An instance of the `EmojiGridView`.
|
|
54
|
+
*/
|
|
55
|
+
readonly infoView: SearchInfoView;
|
|
56
|
+
/**
|
|
57
|
+
* @inheritDoc
|
|
58
|
+
*/
|
|
59
|
+
constructor(locale: Locale, { emojiCategories, getEmojiByQuery, skinTone, skinTones }: {
|
|
60
|
+
emojiCategories: Array<EmojiCategory>;
|
|
61
|
+
getEmojiByQuery: EmojiSearchQueryCallback;
|
|
62
|
+
skinTone: SkinToneId;
|
|
63
|
+
skinTones: Array<SkinTone>;
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* @inheritDoc
|
|
67
|
+
*/
|
|
68
|
+
render(): void;
|
|
69
|
+
/**
|
|
70
|
+
* @inheritDoc
|
|
71
|
+
*/
|
|
72
|
+
destroy(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Focuses the search input.
|
|
75
|
+
*/
|
|
76
|
+
focus(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Initializes interactions between sub-views.
|
|
79
|
+
*/
|
|
80
|
+
private _setupEventListeners;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Fired when the {@link module:emoji/ui/emojipickerview~EmojiPickerView} layout is changed, either by filtering emoji tiles or
|
|
84
|
+
* showing a hint to a user regarding the provided query.
|
|
85
|
+
*
|
|
86
|
+
* @eventName ~EmojiPickerView#update
|
|
87
|
+
*/
|
|
88
|
+
export type EmojiPickerViewUpdateEvent = {
|
|
89
|
+
name: 'update';
|
|
90
|
+
args: [];
|
|
91
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module emoji/ui/emojipickerview
|
|
7
|
+
*/
|
|
8
|
+
import { FocusCycler, SearchInfoView, View } from 'ckeditor5/src/ui.js';
|
|
9
|
+
import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils.js';
|
|
10
|
+
import EmojiGridView from './emojigridview.js';
|
|
11
|
+
import EmojiCategoriesView from './emojicategoriesview.js';
|
|
12
|
+
import EmojiSearchView from './emojisearchview.js';
|
|
13
|
+
import EmojiToneView from './emojitoneview.js';
|
|
14
|
+
/**
|
|
15
|
+
* A view that glues pieces of the emoji panel together.
|
|
16
|
+
*/
|
|
17
|
+
export default class EmojiPickerView extends View {
|
|
18
|
+
/**
|
|
19
|
+
* @inheritDoc
|
|
20
|
+
*/
|
|
21
|
+
constructor(locale, { emojiCategories, getEmojiByQuery, skinTone, skinTones }) {
|
|
22
|
+
super(locale);
|
|
23
|
+
const categoryName = emojiCategories[0].title;
|
|
24
|
+
this.gridView = new EmojiGridView(locale, {
|
|
25
|
+
categoryName,
|
|
26
|
+
emojiCategories,
|
|
27
|
+
getEmojiByQuery,
|
|
28
|
+
skinTone
|
|
29
|
+
});
|
|
30
|
+
this.infoView = new SearchInfoView();
|
|
31
|
+
this.searchView = new EmojiSearchView(locale, {
|
|
32
|
+
gridView: this.gridView,
|
|
33
|
+
resultsView: this.infoView
|
|
34
|
+
});
|
|
35
|
+
this.categoriesView = new EmojiCategoriesView(locale, {
|
|
36
|
+
emojiCategories,
|
|
37
|
+
categoryName
|
|
38
|
+
});
|
|
39
|
+
this.toneView = new EmojiToneView(locale, {
|
|
40
|
+
skinTone,
|
|
41
|
+
skinTones
|
|
42
|
+
});
|
|
43
|
+
this.items = this.createCollection([
|
|
44
|
+
this.searchView,
|
|
45
|
+
this.toneView,
|
|
46
|
+
this.categoriesView,
|
|
47
|
+
this.gridView,
|
|
48
|
+
this.infoView
|
|
49
|
+
]);
|
|
50
|
+
this.focusTracker = new FocusTracker();
|
|
51
|
+
this.keystrokes = new KeystrokeHandler();
|
|
52
|
+
this.focusCycler = new FocusCycler({
|
|
53
|
+
focusables: this.items,
|
|
54
|
+
focusTracker: this.focusTracker,
|
|
55
|
+
keystrokeHandler: this.keystrokes,
|
|
56
|
+
actions: {
|
|
57
|
+
focusPrevious: 'shift + tab',
|
|
58
|
+
focusNext: 'tab'
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
this.setTemplate({
|
|
62
|
+
tag: 'div',
|
|
63
|
+
children: [
|
|
64
|
+
{
|
|
65
|
+
tag: 'div',
|
|
66
|
+
children: [
|
|
67
|
+
this.searchView,
|
|
68
|
+
this.toneView
|
|
69
|
+
],
|
|
70
|
+
attributes: {
|
|
71
|
+
class: ['ck', 'ck-emoji__search']
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
this.categoriesView,
|
|
75
|
+
this.gridView,
|
|
76
|
+
{
|
|
77
|
+
tag: 'div',
|
|
78
|
+
children: [
|
|
79
|
+
this.infoView
|
|
80
|
+
],
|
|
81
|
+
attributes: {
|
|
82
|
+
class: ['ck', 'ck-search__results']
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
attributes: {
|
|
87
|
+
tabindex: '-1',
|
|
88
|
+
class: ['ck', 'ck-emoji', 'ck-search']
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
this._setupEventListeners();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @inheritDoc
|
|
95
|
+
*/
|
|
96
|
+
render() {
|
|
97
|
+
super.render();
|
|
98
|
+
this.focusTracker.add(this.searchView.element);
|
|
99
|
+
this.focusTracker.add(this.toneView.element);
|
|
100
|
+
this.focusTracker.add(this.categoriesView.element);
|
|
101
|
+
this.focusTracker.add(this.gridView.element);
|
|
102
|
+
this.focusTracker.add(this.infoView.element);
|
|
103
|
+
// Start listening for the keystrokes coming from #element.
|
|
104
|
+
this.keystrokes.listenTo(this.element);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @inheritDoc
|
|
108
|
+
*/
|
|
109
|
+
destroy() {
|
|
110
|
+
super.destroy();
|
|
111
|
+
this.focusTracker.destroy();
|
|
112
|
+
this.keystrokes.destroy();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Focuses the search input.
|
|
116
|
+
*/
|
|
117
|
+
focus() {
|
|
118
|
+
this.searchView.focus();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Initializes interactions between sub-views.
|
|
122
|
+
*/
|
|
123
|
+
_setupEventListeners() {
|
|
124
|
+
const t = this.locale.t;
|
|
125
|
+
// Disable the category switcher when filtering by a query.
|
|
126
|
+
this.searchView.on('search', (evt, data) => {
|
|
127
|
+
if (data.query) {
|
|
128
|
+
this.categoriesView.disableCategories();
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
this.categoriesView.enableCategories();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
// Show a user-friendly message depending on the search query.
|
|
135
|
+
this.searchView.on('search', (evt, data) => {
|
|
136
|
+
if (data.query.length === 1) {
|
|
137
|
+
this.infoView.set({
|
|
138
|
+
primaryText: t('Keep on typing to see the emoji.'),
|
|
139
|
+
secondaryText: t('The query must contain at least two characters.'),
|
|
140
|
+
isVisible: true
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else if (!data.resultsCount) {
|
|
144
|
+
this.infoView.set({
|
|
145
|
+
primaryText: t('No emojis were found matching "%0".', data.query),
|
|
146
|
+
secondaryText: t('Please try a different phrase or check the spelling.'),
|
|
147
|
+
isVisible: true
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this.infoView.set({
|
|
152
|
+
isVisible: false
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
// Emit an update event to react to balloon dimensions changes.
|
|
157
|
+
this.searchView.on('search', () => {
|
|
158
|
+
this.fire('update');
|
|
159
|
+
});
|
|
160
|
+
// Update the grid of emojis when the selected category is changed.
|
|
161
|
+
this.categoriesView.on('change:categoryName', (ev, args, categoryName) => {
|
|
162
|
+
this.gridView.categoryName = categoryName;
|
|
163
|
+
this.searchView.search('');
|
|
164
|
+
});
|
|
165
|
+
// Update the grid of emojis when the selected skin tone is changed.
|
|
166
|
+
// In such a case, the displayed emoji should use an updated skin tone value.
|
|
167
|
+
this.toneView.on('change:skinTone', (evt, propertyName, newValue) => {
|
|
168
|
+
this.gridView.skinTone = newValue;
|
|
169
|
+
this.searchView.search(this.searchView.getInputValue());
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
import { SearchTextView, View, type SearchInfoView } from 'ckeditor5/src/ui.js';
|
|
6
|
+
import type { Locale } from 'ckeditor5/src/utils.js';
|
|
7
|
+
import type EmojiGridView from './emojigridview.js';
|
|
8
|
+
/**
|
|
9
|
+
* A view responsible for providing an input element that allows filtering emoji by the provided query.
|
|
10
|
+
*/
|
|
11
|
+
export default class EmojiSearchView extends View {
|
|
12
|
+
/**
|
|
13
|
+
* The find in text input view that stores the searched string.
|
|
14
|
+
*/
|
|
15
|
+
readonly inputView: SearchTextView;
|
|
16
|
+
/**
|
|
17
|
+
* An instance of the `EmojiGridView`.
|
|
18
|
+
*/
|
|
19
|
+
readonly gridView: EmojiGridView;
|
|
20
|
+
/**
|
|
21
|
+
* @inheritDoc
|
|
22
|
+
*/
|
|
23
|
+
constructor(locale: Locale, { gridView, resultsView }: {
|
|
24
|
+
gridView: EmojiGridView;
|
|
25
|
+
resultsView: SearchInfoView;
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* @inheritDoc
|
|
29
|
+
*/
|
|
30
|
+
destroy(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Searches the {@link #gridView} for the given query.
|
|
33
|
+
*
|
|
34
|
+
* @param query The search query string.
|
|
35
|
+
*/
|
|
36
|
+
search(query: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Allows defining the default value in the search text field.
|
|
39
|
+
*
|
|
40
|
+
* @param value The new value.
|
|
41
|
+
*/
|
|
42
|
+
setInputValue(value: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Returns an input provided by a user in the search text field.
|
|
45
|
+
*/
|
|
46
|
+
getInputValue(): string;
|
|
47
|
+
/**
|
|
48
|
+
* @inheritDoc
|
|
49
|
+
*/
|
|
50
|
+
focus(): void;
|
|
51
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module emoji/ui/emojisearchview
|
|
7
|
+
*/
|
|
8
|
+
import { escapeRegExp } from 'lodash-es';
|
|
9
|
+
import { createLabeledInputText, SearchTextView, View } from 'ckeditor5/src/ui.js';
|
|
10
|
+
/**
|
|
11
|
+
* A view responsible for providing an input element that allows filtering emoji by the provided query.
|
|
12
|
+
*/
|
|
13
|
+
export default class EmojiSearchView extends View {
|
|
14
|
+
/**
|
|
15
|
+
* @inheritDoc
|
|
16
|
+
*/
|
|
17
|
+
constructor(locale, { gridView, resultsView }) {
|
|
18
|
+
super(locale);
|
|
19
|
+
this.gridView = gridView;
|
|
20
|
+
const t = locale.t;
|
|
21
|
+
this.inputView = new SearchTextView(this.locale, {
|
|
22
|
+
queryView: {
|
|
23
|
+
label: t('Find an emoji (min. 2 characters)'),
|
|
24
|
+
creator: createLabeledInputText
|
|
25
|
+
},
|
|
26
|
+
filteredView: this.gridView,
|
|
27
|
+
infoView: {
|
|
28
|
+
instance: resultsView
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
this.setTemplate({
|
|
32
|
+
tag: 'div',
|
|
33
|
+
attributes: {
|
|
34
|
+
class: [
|
|
35
|
+
'ck',
|
|
36
|
+
'ck-search'
|
|
37
|
+
],
|
|
38
|
+
tabindex: '-1'
|
|
39
|
+
},
|
|
40
|
+
children: [
|
|
41
|
+
this.inputView.queryView
|
|
42
|
+
]
|
|
43
|
+
});
|
|
44
|
+
// Pass through the `search` event to handle it by a parent view.
|
|
45
|
+
this.inputView.delegate('search').to(this);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @inheritDoc
|
|
49
|
+
*/
|
|
50
|
+
destroy() {
|
|
51
|
+
super.destroy();
|
|
52
|
+
this.inputView.destroy();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Searches the {@link #gridView} for the given query.
|
|
56
|
+
*
|
|
57
|
+
* @param query The search query string.
|
|
58
|
+
*/
|
|
59
|
+
search(query) {
|
|
60
|
+
const regExp = query ? new RegExp(escapeRegExp(query), 'ig') : null;
|
|
61
|
+
const filteringResults = this.gridView.filter(regExp);
|
|
62
|
+
this.inputView.fire('search', { query, ...filteringResults });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Allows defining the default value in the search text field.
|
|
66
|
+
*
|
|
67
|
+
* @param value The new value.
|
|
68
|
+
*/
|
|
69
|
+
setInputValue(value) {
|
|
70
|
+
if (!value) {
|
|
71
|
+
this.inputView.queryView.fieldView.reset();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.inputView.queryView.fieldView.value = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns an input provided by a user in the search text field.
|
|
79
|
+
*/
|
|
80
|
+
getInputValue() {
|
|
81
|
+
return this.inputView.queryView.fieldView.element.value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* @inheritDoc
|
|
85
|
+
*/
|
|
86
|
+
focus() {
|
|
87
|
+
this.inputView.focus();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module emoji/ui/emojitoneview
|
|
7
|
+
*/
|
|
8
|
+
import { View, type DropdownView } from 'ckeditor5/src/ui.js';
|
|
9
|
+
import { type Locale } from 'ckeditor5/src/utils.js';
|
|
10
|
+
import type { SkinToneId } from '../emojiconfig.js';
|
|
11
|
+
import type { SkinTone } from '../emojirepository.js';
|
|
12
|
+
import '../../theme/emojitone.css';
|
|
13
|
+
/**
|
|
14
|
+
* A view responsible for selecting a skin tone for an emoji.
|
|
15
|
+
*/
|
|
16
|
+
export default class EmojiToneView extends View {
|
|
17
|
+
/**
|
|
18
|
+
* Active skin tone.
|
|
19
|
+
*
|
|
20
|
+
* @observable
|
|
21
|
+
*/
|
|
22
|
+
skinTone: SkinToneId;
|
|
23
|
+
/**
|
|
24
|
+
* A dropdown element for selecting an active skin tone.
|
|
25
|
+
*/
|
|
26
|
+
readonly dropdownView: DropdownView;
|
|
27
|
+
/**
|
|
28
|
+
* An array of available skin tones.
|
|
29
|
+
*/
|
|
30
|
+
private readonly _skinTones;
|
|
31
|
+
/**
|
|
32
|
+
* @inheritDoc
|
|
33
|
+
*/
|
|
34
|
+
constructor(locale: Locale, { skinTone, skinTones }: {
|
|
35
|
+
skinTone: SkinToneId;
|
|
36
|
+
skinTones: Array<SkinTone>;
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* @inheritDoc
|
|
40
|
+
*/
|
|
41
|
+
focus(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Helper method for receiving an object describing the active skin tone.
|
|
44
|
+
*/
|
|
45
|
+
private _getSkinTone;
|
|
46
|
+
}
|