@sequent-org/moodboard 1.2.11 → 1.2.13

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": "@sequent-org/moodboard",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -174,6 +174,14 @@ export { initMoodBoardNoBundler, quickInitMoodBoard, injectCriticalStyles, force
174
174
  export { StyleLoader } from './utils/styleLoader.js';
175
175
  export { EmojiLoaderNoBundler } from './utils/emojiLoaderNoBundler.js';
176
176
 
177
+ // Экспорт встроенных SVG эмоджи
178
+ export {
179
+ addInlineSvgEmoji,
180
+ bulkAddInlineSvgEmojis,
181
+ getAvailableInlineEmojis,
182
+ isInlineSvgEmoji
183
+ } from './utils/inlineSvgEmojis.js';
184
+
177
185
  /**
178
186
  * СУПЕР-АГРЕССИВНАЯ функция для исправления панелей в проектах с конфликтами CSS
179
187
  */
package/src/ui/Toolbar.js CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { Events } from '../core/events/Events.js';
5
5
  import { IconLoader } from '../utils/iconLoader.js';
6
+ import { getAvailableInlineEmojis, getInlineEmojiUrl } from '../utils/inlineSvgEmojis.js';
6
7
 
7
8
  export class Toolbar {
8
9
  constructor(container, eventBus, theme = 'light', options = {}) {
@@ -905,9 +906,24 @@ export class Toolbar {
905
906
  this.emojiPopupEl.className = 'moodboard-toolbar__popup moodboard-toolbar__popup--emoji';
906
907
  this.emojiPopupEl.style.display = 'none';
907
908
 
908
- // Определяем способ загрузки эмоджи
909
+ // ПРИОРИТЕТ 1: Добавляем встроенные SVG эмоджи
909
910
  let groups = new Map();
910
911
 
912
+ console.log('🎯 Создание EmojiPopup: добавляем встроенные SVG эмоджи...');
913
+ const inlineEmojis = getAvailableInlineEmojis();
914
+
915
+ if (inlineEmojis.length > 0) {
916
+ // Добавляем встроенные эмоджи в категорию "Встроенные"
917
+ groups.set('Встроенные', inlineEmojis.map(emoji => ({
918
+ path: `inline:${emoji}`,
919
+ url: getInlineEmojiUrl(emoji),
920
+ isInline: true,
921
+ emoji: emoji
922
+ })));
923
+ console.log(`✅ Добавлено ${inlineEmojis.length} встроенных SVG эмоджи`);
924
+ }
925
+
926
+ // ПРИОРИТЕТ 2: Дополняем файловыми эмоджи (если нужны)
911
927
  if (typeof import.meta !== 'undefined' && import.meta.glob) {
912
928
  // Режим с bundler (Vite) - используем import.meta.glob
913
929
  const modules = import.meta.glob('../assets/emodji/**/*.{png,PNG,svg,SVG}', { eager: true, as: 'url' });
@@ -924,15 +940,19 @@ export class Toolbar {
924
940
  category = parts.length > 1 ? parts[0] : 'Разное';
925
941
  }
926
942
  if (!groups.has(category)) groups.set(category, []);
927
- groups.get(category).push({ path, url });
943
+ groups.get(category).push({ path, url, isInline: false });
928
944
  });
929
945
  } else {
930
946
  // Режим без bundler - используем статичный список
931
- groups = this.getFallbackEmojiGroups();
947
+ const fallbackGroups = this.getFallbackEmojiGroups();
948
+ fallbackGroups.forEach((items, category) => {
949
+ if (!groups.has(category)) groups.set(category, []);
950
+ groups.get(category).push(...items.map(item => ({ ...item, isInline: false })));
951
+ });
932
952
  }
933
953
 
934
- // Задаем желаемый порядок категорий
935
- const ORDER = ['Смайлики', 'Жесты', 'Женские эмоции', 'Котики', 'Разное'];
954
+ // Задаем желаемый порядок категорий (встроенные SVG - первые!)
955
+ const ORDER = ['Встроенные', 'Смайлики', 'Жесты', 'Женские эмоции', 'Котики', 'Разное'];
936
956
  const present = [...groups.keys()];
937
957
  const orderedFirst = ORDER.filter(name => groups.has(name));
938
958
  const theRest = present.filter(name => !ORDER.includes(name)).sort((a, b) => a.localeCompare(b));
@@ -951,14 +971,14 @@ export class Toolbar {
951
971
  const grid = document.createElement('div');
952
972
  grid.className = 'moodboard-emoji__grid';
953
973
 
954
- groups.get(cat).forEach(({ url }) => {
974
+ groups.get(cat).forEach(({ url, isInline, emoji }) => {
955
975
  const btn = document.createElement('button');
956
976
  btn.className = 'moodboard-emoji__btn';
957
- btn.title = 'Добавить изображение';
977
+ btn.title = isInline ? `Встроенный эмоджи: ${emoji}` : 'Добавить изображение';
958
978
  const img = document.createElement('img');
959
979
  img.className = 'moodboard-emoji__img';
960
980
  img.src = url;
961
- img.alt = '';
981
+ img.alt = emoji || '';
962
982
  btn.appendChild(img);
963
983
 
964
984
  // Перетаскивание: начинаем только если был реальный drag (движение > 4px)
@@ -1024,9 +1044,19 @@ export class Toolbar {
1024
1044
  const target = 64; // кратно 128 для лучшей четкости при даунскейле
1025
1045
  const targetW = target;
1026
1046
  const targetH = target;
1047
+
1048
+ console.log(`🎯 Создаем эмоджи: ${isInline ? 'встроенный SVG' : 'файл'}, url: ${url.substring(0, 50)}...`);
1049
+
1027
1050
  this.eventBus.emit(Events.Place.Set, {
1028
1051
  type: 'image',
1029
- properties: { src: url, width: targetW, height: targetH, isEmojiIcon: true },
1052
+ properties: {
1053
+ src: url,
1054
+ width: targetW,
1055
+ height: targetH,
1056
+ isEmojiIcon: true,
1057
+ isInlineSvg: isInline || false,
1058
+ originalEmoji: emoji || null
1059
+ },
1030
1060
  size: { width: targetW, height: targetH }
1031
1061
  });
1032
1062
  this.closeEmojiPopup();
@@ -1,3 +1,6 @@
1
+ // Импортируем встроенные SVG эмоджи
2
+ import { getInlineEmojiUrl, isInlineSvgEmoji } from './inlineSvgEmojis.js';
3
+
1
4
  // Явные переопределения соответствия эмодзи → имя файла (без расширения)
2
5
  // Ключ и значение — в нижнем регистре, кодпоинты через дефис
3
6
  const EMOJI_OVERRIDES = new Map([
@@ -124,6 +127,24 @@ export function buildLocalPaths(emoji) {
124
127
  }
125
128
  }
126
129
 
130
+ /**
131
+ * ПРИОРИТЕТНЫЙ РЕЗОЛВЕР: Сначала встроенные SVG, потом файлы
132
+ * @param {string} emoji - эмоджи символ
133
+ * @returns {string|null} Data URL для встроенного SVG или null
134
+ */
135
+ export function resolveInlineEmojiFirst(emoji) {
136
+ // Приоритет 1: Встроенные SVG эмоджи (мгновенная загрузка, нет проблем с путями)
137
+ if (isInlineSvgEmoji(emoji)) {
138
+ const dataUrl = getInlineEmojiUrl(emoji);
139
+ if (dataUrl) {
140
+ console.log('✅ Используем встроенный SVG эмоджи:', emoji);
141
+ return dataUrl;
142
+ }
143
+ }
144
+
145
+ return null; // Эмоджи не найден во встроенных
146
+ }
147
+
127
148
  /**
128
149
  * Возвращает абсолютный URL для эмоджи с учетом базового пути
129
150
  * @param {string} emoji - эмоджи символ
@@ -131,6 +152,9 @@ export function buildLocalPaths(emoji) {
131
152
  * @returns {string|null} абсолютный URL или null
132
153
  */
133
154
  export function resolveEmojiAbsoluteUrl(emoji, basePath = null) {
155
+ // ПРИОРИТЕТ 1: Проверяем встроенные SVG эмоджи
156
+ const inlineUrl = resolveInlineEmojiFirst(emoji);
157
+ if (inlineUrl) return inlineUrl;
134
158
  try {
135
159
  const base = emojiFilenameBase(emoji);
136
160
  if (!base) return null;
@@ -179,8 +203,20 @@ export function resolveEmojiAbsoluteUrl(emoji, basePath = null) {
179
203
  // Формируем URL (приоритет PNG, потом SVG)
180
204
  if (!resolvedBasePath.endsWith('/')) resolvedBasePath += '/';
181
205
 
182
- // Возвращаем URL в формате готовом для использования
183
- return `${resolvedBasePath}Смайлики/${base}.png`; // Большинство эмоджи в папке Смайлики
206
+ // ПРИОРИТЕТ 2: Файлы в папках (только если нет встроенных SVG)
207
+ // Сначала проверяем разные папки
208
+ const possiblePaths = [
209
+ `${resolvedBasePath}Смайлики/${base}.png`,
210
+ `${resolvedBasePath}Жесты/${base}.png`,
211
+ `${resolvedBasePath}Женские эмоции/${base}.png`,
212
+ `${resolvedBasePath}Котики/${base}.png`,
213
+ `${resolvedBasePath}Разное/${base}.png`,
214
+ `${resolvedBasePath}Обезьянка/${base}.png`,
215
+ `${resolvedBasePath}${base}.png` // Прямо в корне папки эмоджи
216
+ ];
217
+
218
+ // Возвращаем первый возможный путь (браузер сам проверит доступность)
219
+ return possiblePaths[0];
184
220
 
185
221
  } catch (error) {
186
222
  return null;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Встроенная коллекция SVG эмоджи
3
+ * SVG код встроен прямо в JavaScript для избежания проблем с загрузкой файлов
4
+ */
5
+
6
+ // Встроенные SVG эмоджи как строки
7
+ export const INLINE_SVG_EMOJIS = {
8
+ // Смайлики
9
+ '😀': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
10
+ <circle fill="#FFCC4D" cx="18" cy="18" r="18"/>
11
+ <path fill="#664500" d="M10.515 23.621C10.56 23.8 11.683 28 18 28c6.318 0 7.44-4.2 7.485-4.379.055-.222-.025-.447-.204-.571-.18-.124-.403-.115-.571.024C24.629 23.145 22.112 25 18 25s-6.63-1.855-6.71-1.926c-.168-.139-.39-.148-.571-.024-.179.124-.259.349-.204.571z"/>
12
+ <ellipse fill="#664500" cx="12" cy="13.5" rx="2.5" ry="3.5"/>
13
+ <ellipse fill="#664500" cx="24" cy="13.5" rx="2.5" ry="3.5"/>
14
+ </svg>`,
15
+
16
+ '😊': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
17
+ <circle fill="#FFCC4D" cx="18" cy="18" r="18"/>
18
+ <path fill="#664500" d="M10.515 23.621C10.56 23.8 11.683 28 18 28c6.318 0 7.44-4.2 7.485-4.379.055-.222-.025-.447-.204-.571-.18-.124-.403-.115-.571.024C24.629 23.145 22.112 25 18 25s-6.63-1.855-6.71-1.926c-.168-.139-.39-.148-.571-.024-.179.124-.259.349-.204.571z"/>
19
+ <ellipse fill="#664500" cx="12" cy="13.5" rx="2.5" ry="3.5"/>
20
+ <ellipse fill="#664500" cx="24" cy="13.5" rx="2.5" ry="3.5"/>
21
+ <circle fill="#F4900C" cx="18" cy="13" r="2"/>
22
+ </svg>`,
23
+
24
+ '😂': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
25
+ <circle fill="#FFCC4D" cx="18" cy="18" r="18"/>
26
+ <path fill="#664500" d="M10.515 23.621C10.56 23.8 11.683 28 18 28c6.318 0 7.44-4.2 7.485-4.379.055-.222-.025-.447-.204-.571-.18-.124-.403-.115-.571.024C24.629 23.145 22.112 25 18 25s-6.63-1.855-6.71-1.926c-.168-.139-.39-.148-.571-.024-.179.124-.259.349-.204.571z"/>
27
+ <ellipse fill="#664500" cx="12" cy="13.5" rx="2.5" ry="3.5"/>
28
+ <ellipse fill="#664500" cx="24" cy="13.5" rx="2.5" ry="3.5"/>
29
+ <path fill="#55ACEE" d="M5 17c.552 0 1 .447 1 1v1c0 .552-.448 1-1 1s-1-.448-1-1v-1c0-.553.448-1 1-1z"/>
30
+ <path fill="#55ACEE" d="M31 17c.553 0 1 .447 1 1v1c0 .552-.447 1-1 1-.553 0-1-.448-1-1v-1c0-.553.447-1 1-1z"/>
31
+ </svg>`,
32
+
33
+ '😎': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
34
+ <circle fill="#FFCC4D" cx="18" cy="18" r="18"/>
35
+ <path fill="#664500" d="M10.515 23.621C10.56 23.8 11.683 28 18 28c6.318 0 7.44-4.2 7.485-4.379.055-.222-.025-.447-.204-.571-.18-.124-.403-.115-.571.024C24.629 23.145 22.112 25 18 25s-6.63-1.855-6.71-1.926c-.168-.139-.39-.148-.571-.024-.179.124-.259.349-.204.571z"/>
36
+ <path fill="#292F33" d="M31 13c0-3.866-3.134-7-7-7H12c-3.866 0-7 3.134-7 7v1c0 3.866 3.134 7 7 7h12c3.866 0 7-3.134 7-7v-1z"/>
37
+ <circle fill="#F4900C" cx="12" cy="13.5" r="6"/>
38
+ <circle fill="#F4900C" cx="24" cy="13.5" r="6"/>
39
+ </svg>`,
40
+
41
+ '🤔': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
42
+ <circle fill="#FFCC4D" cx="18" cy="18" r="18"/>
43
+ <path fill="#664500" d="M8 19.5c0 1.381 1.119 2.5 2.5 2.5s2.5-1.119 2.5-2.5S11.881 17 10.5 17 8 18.119 8 19.5z"/>
44
+ <ellipse fill="#664500" cx="25" cy="19.5" rx="2.5" ry="1.5"/>
45
+ <path fill="#664500" d="M22.313 12.062c-.511-.478-1.321-.444-1.799.069-.479.512-.444 1.321.068 1.8.718.671 1.359 1.284 1.359 2.069 0 .552.447 1 1 1s1-.448 1-1c0-1.429-.932-2.427-1.628-3.938z"/>
46
+ </svg>`,
47
+
48
+ '👍': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
49
+ <path fill="#EF9645" d="M4.861 9.147c-.629-.628-.63-1.657-.001-2.286l.244-.244c.628-.628 1.656-.63 2.285-.001l1.903 1.902c.628.629.629 1.657.001 2.286l-.244.244c-.628.628-1.656.63-2.285.001L4.861 9.147z"/>
50
+ <path fill="#FFDC5D" d="M3.968 21.892c-.628.629-1.657.628-2.285 0l-.244-.244c-.628-.628-.629-1.656-.001-2.285l1.902-1.903c.629-.628 1.657-.629 2.286-.001l.244.244c.628.628.629 1.656.001 2.285l-1.903 1.904z"/>
51
+ <path fill="#FFAC33" d="M7 11c0 5.522-4.478 10-10 10s-10-4.478-10-10 4.478-10 10-10 10 4.478 10 10z"/>
52
+ </svg>`,
53
+
54
+ '👎': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
55
+ <path fill="#EF9645" d="M31.139 26.853c.629.628.63 1.657.001 2.286l-.244.244c-.628.628-1.656.63-2.285.001l-1.903-1.902c-.628-.629-.629-1.657-.001-2.286l.244-.244c.628-.628 1.656-.63 2.285-.001l1.903 1.902z"/>
56
+ <path fill="#FFDC5D" d="M32.032 14.108c.628-.629 1.657-.628 2.285 0l.244.244c.628.628.629 1.656.001 2.285l-1.902 1.903c-.629.628-1.657.629-2.286.001l-.244-.244c-.628-.628-.629-1.656-.001-2.285l1.903-1.904z"/>
57
+ <path fill="#FFAC33" d="M29 25c0-5.522 4.478-10 10-10s10 4.478 10 10-4.478 10-10 10-10-4.478-10-10z"/>
58
+ </svg>`,
59
+
60
+ '❤️': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
61
+ <path fill="#DD2E44" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.784-2.466 16.249-11.447 17.619-19.96.168-.721.266-1.469.266-2.241z"/>
62
+ </svg>`,
63
+
64
+ '🔥': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
65
+ <path fill="#DD2E44" d="M18 10c-1.105 0-2 .895-2 2v8c0 1.105.895 2 2 2s2-.895 2-2v-8c0-1.105-.895-2-2-2z"/>
66
+ <path fill="#F4900C" d="M18 6c-.553 0-1 .447-1 1v4c0 .553.447 1 1 1s1-.447 1-1V7c0-.553-.447-1-1-1z"/>
67
+ <path fill="#FFAC33" d="M18 26c3.314 0 6-2.686 6-6 0-3.314-2.686-6-6-6s-6 2.686-6 6c0 3.314 2.686 6 6 6z"/>
68
+ </svg>`,
69
+
70
+ '🎉': `<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
71
+ <path fill="#FFCC4D" d="M36 17c0 1.104-.896 2-2 2H2c-1.104 0-2-.896-2-2s.896-2 2-2h32c1.104 0 2 .896 2 2z"/>
72
+ <path fill="#DD2E44" d="M35.5 9c0 .828-.672 1.5-1.5 1.5s-1.5-.672-1.5-1.5.672-1.5 1.5-1.5 1.5.672 1.5 1.5z"/>
73
+ <path fill="#55ACEE" d="M3.5 27c0 .828-.672 1.5-1.5 1.5S.5 27.828.5 27s.672-1.5 1.5-1.5 1.5.672 1.5 1.5z"/>
74
+ <path fill="#F4900C" d="M31 25c.552 0 1 .447 1 1v4c0 .552-.448 1-1 1s-1-.448-1-1v-4c0-.553.448-1 1-1z"/>
75
+ </svg>`
76
+ };
77
+
78
+ /**
79
+ * Конвертирует SVG строку в Data URL для использования с PIXI.Texture
80
+ * @param {string} svgString - SVG код
81
+ * @returns {string} Data URL
82
+ */
83
+ export function svgToDataUrl(svgString) {
84
+ // Очищаем SVG от лишних пробелов и переносов
85
+ const cleanSvg = svgString.replace(/\s+/g, ' ').trim();
86
+
87
+ // Кодируем в base64 или используем URL encoding
88
+ const encoded = encodeURIComponent(cleanSvg);
89
+
90
+ return `data:image/svg+xml,${encoded}`;
91
+ }
92
+
93
+ /**
94
+ * Получает Data URL для эмоджи по символу
95
+ * @param {string} emoji - символ эмоджи
96
+ * @returns {string|null} Data URL или null если эмоджи не найден
97
+ */
98
+ export function getInlineEmojiUrl(emoji) {
99
+ const svgCode = INLINE_SVG_EMOJIS[emoji];
100
+ if (!svgCode) return null;
101
+
102
+ return svgToDataUrl(svgCode);
103
+ }
104
+
105
+ /**
106
+ * Получает список всех доступных встроенных эмоджи
107
+ * @returns {string[]} массив символов эмоджи
108
+ */
109
+ export function getAvailableInlineEmojis() {
110
+ return Object.keys(INLINE_SVG_EMOJIS);
111
+ }
112
+
113
+ /**
114
+ * Проверяет, поддерживается ли эмоджи как встроенный SVG
115
+ * @param {string} emoji - символ эмоджи
116
+ * @returns {boolean}
117
+ */
118
+ export function isInlineSvgEmoji(emoji) {
119
+ return emoji in INLINE_SVG_EMOJIS;
120
+ }
121
+
122
+ /**
123
+ * Добавляет новый SVG эмоджи в коллекцию
124
+ * @param {string} emoji - символ эмоджи
125
+ * @param {string} svgCode - SVG код
126
+ * @returns {boolean} успех операции
127
+ */
128
+ export function addInlineSvgEmoji(emoji, svgCode) {
129
+ try {
130
+ if (!emoji || !svgCode) return false;
131
+ INLINE_SVG_EMOJIS[emoji] = svgCode;
132
+ console.log('✅ Добавлен встроенный SVG эмоджи:', emoji);
133
+ return true;
134
+ } catch (error) {
135
+ console.error('❌ Ошибка добавления SVG эмоджи:', error);
136
+ return false;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * МАССОВОЕ ДОБАВЛЕНИЕ эмоджи из вашего проекта
142
+ * @param {Object} emojiMap - объект {emoji: svgCode, ...}
143
+ * @returns {number} количество добавленных эмоджи
144
+ */
145
+ export function bulkAddInlineSvgEmojis(emojiMap) {
146
+ let added = 0;
147
+ try {
148
+ for (const [emoji, svgCode] of Object.entries(emojiMap)) {
149
+ if (addInlineSvgEmoji(emoji, svgCode)) {
150
+ added++;
151
+ }
152
+ }
153
+ console.log(`✅ Массово добавлено ${added} встроенных SVG эмоджи`);
154
+ return added;
155
+ } catch (error) {
156
+ console.error('❌ Ошибка массового добавления эмоджи:', error);
157
+ return added;
158
+ }
159
+ }