Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/core/dist/TextIgniter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import PopupToolbarView from './view/popupToolbarView';
import LinkPopupView from './view/linkPopupView';
import EventEmitter from './utils/events';
import { SpeechToTextHandler } from './handlers/speechToText';
import EmojiPickerView from './view/emojiPickerView';
export interface CurrentAttributeDTO {
bold: boolean;
italic: boolean;
Expand Down Expand Up @@ -46,6 +47,7 @@ declare class TextIgniter extends EventEmitter {
} | null;
debounceTimer: NodeJS.Timeout | null;
undoRedoManager: UndoRedoManager;
emojiPickerView: EmojiPickerView;
constructor(editorId: string, config: EditorConfig);
getSelectionRange(): [number, number];
applyFontColor(color: string): void;
Expand Down
1 change: 1 addition & 0 deletions packages/core/dist/assets/icons.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export declare const icons: {
image: string;
stop_microphone: string;
start_microphone: string;
emoji: string;
};
9 changes: 9 additions & 0 deletions packages/core/dist/assets/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,13 @@ export const icons = {
<path d="M224 160C224 107 267 64 320 64C370.3 64 411.6 102.7 415.7 152L360 152C346.7 152 336 162.7 336 176C336 189.3 346.7 200 360 200L416 200L416 248L360 248C346.7 248 336 258.7 336 272C336 285.3 346.7 296 360 296L415.7 296C411.6 345.3 370.4 384 320 384C267 384 224 341 224 288L224 160zM152 224C165.3 224 176 234.7 176 248L176 288C176 367.5 240.5 432 320 432C399.5 432 464 367.5 464 288L464 248C464 234.7 474.7 224 488 224C501.3 224 512 234.7 512 248L512 288C512 385.9 438.7 466.7 344 478.5L344 528L392 528C405.3 528 416 538.7 416 552C416 565.3 405.3 576 392 576L248 576C234.7 576 224 565.3 224 552C224 538.7 234.7 528 248 528L296 528L296 478.5C201.3 466.7 128 385.9 128 288L128 248C128 234.7 138.7 224 152 224z"/>
</svg>
`,

emoji: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<title>Emoji</title>
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>`,
};

20 changes: 19 additions & 1 deletion packages/core/dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,24 @@ declare class SpeechToTextHandler {
toggleRecording(): void;
private startRecording;
private stopRecording;
private resetSilenceTimer;
}

declare class EmojiPickerView {
private popup;
private gridArea;
private searchInput;
private onSelectCallback?;
private isOpen;
constructor();
onSelect(cb: (char: string) => void): void;
open(element: HTMLElement): void;
close(): void;
getIsOpen(): boolean;
private buildPopup;
private getRecentEmojis;
private saveRecentEmoji;
private resolveChar;
private renderGrid;
}

interface CurrentAttributeDTO {
Expand Down Expand Up @@ -300,6 +317,7 @@ declare class TextIgniter extends EventEmitter {
} | null;
debounceTimer: NodeJS.Timeout | null;
undoRedoManager: UndoRedoManager;
emojiPickerView: EmojiPickerView;
constructor(editorId: string, config: EditorConfig);
getSelectionRange(): [number, number];
applyFontColor(color: string): void;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/dist/index.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/core/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ <h3>Real-time Content Preview:</h3>
'bgColor',
'getHtmlContent',
'loadHtmlContent',
'speechtotext'
'speechtotext',
'emoji'
// "subscript",
// "superscript",
// "insert_table",
Expand Down
51 changes: 51 additions & 0 deletions packages/core/src/TextIgniter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { detectUrlsInText } from './utils/urlDetector';
import EventEmitter from './utils/events';
import { SpeechToTextHandler } from './handlers/speechToText';
import { icons } from './assets/icons';
import EmojiPickerView from './view/emojiPickerView';
// Link functionality imports

export interface CurrentAttributeDTO {
Expand Down Expand Up @@ -52,6 +53,7 @@ class TextIgniter extends EventEmitter {
savedSelection: { start: number; end: number } | null = null;
debounceTimer: NodeJS.Timeout | null = null;
undoRedoManager: UndoRedoManager;
emojiPickerView: EmojiPickerView;

constructor(editorId: string, config: EditorConfig) {
super();
Expand Down Expand Up @@ -138,6 +140,42 @@ class TextIgniter extends EventEmitter {
btn.insertAdjacentHTML('afterbegin', icons.start_microphone);
btn.dataset.tooltip = 'start';
}

this.emojiPickerView = new EmojiPickerView();
this.emojiPickerView.onSelect((char: string) => {
if (this.savedSelection) {
this.setCursorPosition(this.savedSelection.start);
}

const [start, end] = this.getSelectionRange();

if (end > start) {
this.document.deleteRange(
start,
end,
this.document.selectedBlockId,
this.document.currentOffset,
false
);
}

this.document.insertAt(
char,
{ ...this.currentAttributes },
start,
this.document.selectedBlockId,
0,
'',
'batch'
);

const newPos = start + char.length;

this.savedSelection = { start: newPos, end: newPos };

this.setCursorPosition(newPos);
});

this.currentAttributes = {
bold: false,
italic: false,
Expand Down Expand Up @@ -745,6 +783,19 @@ class TextIgniter extends EventEmitter {
case 'speechtotext':
this.speechToTextHandler.toggleRecording();
break;
case 'emoji':
this.savedSelection = saveSelection(this.editorView.container);

const emojiBtn = document.querySelector(
'[data-action="emoji"]'
) as HTMLElement;
emojiBtn.addEventListener('mousedown', e => {
e.preventDefault();
});
if (emojiBtn) {
this.emojiPickerView.open(emojiBtn);
}
break;
default:
if (start < end) {
this.undoRedoManager.saveUndoSnapshot();
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/assets/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,12 @@ export const icons = {
<path d="M224 160C224 107 267 64 320 64C370.3 64 411.6 102.7 415.7 152L360 152C346.7 152 336 162.7 336 176C336 189.3 346.7 200 360 200L416 200L416 248L360 248C346.7 248 336 258.7 336 272C336 285.3 346.7 296 360 296L415.7 296C411.6 345.3 370.4 384 320 384C267 384 224 341 224 288L224 160zM152 224C165.3 224 176 234.7 176 248L176 288C176 367.5 240.5 432 320 432C399.5 432 464 367.5 464 288L464 248C464 234.7 474.7 224 488 224C501.3 224 512 234.7 512 248L512 288C512 385.9 438.7 466.7 344 478.5L344 528L392 528C405.3 528 416 538.7 416 552C416 565.3 405.3 576 392 576L248 576C234.7 576 224 565.3 224 552C224 538.7 234.7 528 248 528L296 528L296 478.5C201.3 466.7 128 385.9 128 288L128 248C128 234.7 138.7 224 152 224z"/>
</svg>
`,

emoji: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<title>Emoji</title>
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>`,
};
4 changes: 3 additions & 1 deletion packages/core/src/config/editorConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const featureGroups = {
formatting: ['bold', 'italic', 'underline', 'strikethrough'],
alignment: ['alignLeft', 'alignCenter', 'alignRight'],
lists: ['unorderedList', 'orderedList'],
media: ['hyperlink', 'image'],
media: ['hyperlink', 'image', 'emoji'],
utility: ['getHtmlContent', 'loadHtmlContent'],
};

Expand Down Expand Up @@ -100,6 +100,7 @@ export function createEditor(
fontColor: 'Text Color',
bgColor: 'Highlight Color',
image: 'Insert Image',
emoji: 'Emoji',
getHtmlContent: 'Get HTML',
loadHtmlContent: 'Load HTML',
};
Expand All @@ -111,6 +112,7 @@ export function createEditor(
{ feature: 'unorderedList', id: 'unorderedList', icon: icons.bullet_list },
{ feature: 'orderedList', id: 'orderedList', icon: icons.numbered_list },
{ feature: 'hyperlink', id: 'hyperlink', icon: icons.hyperlink },
{ feature: 'emoji', id: 'emoji', icon: icons.emoji },
{
feature: 'strikethrough',
id: 'strikethrough',
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/constants/emojis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { EmojiCategory } from '../types/emoji.type';

export const EMOJI_CATEGORIES: EmojiCategory[] = [
{
label: 'Smileys & People',
items: [
{ char: '😀', name: 'grinning face', shortcode: ':grinning:' },
{ char: '😃', name: 'big eyes smile', shortcode: ':smiley:' },
{ char: '😄', name: 'smiling eyes grin', shortcode: ':smile:' },
{ char: '😁', name: 'beaming grin', shortcode: ':grin:' },
{ char: '😆', name: 'squinting laugh', shortcode: ':laughing:' },
{ char: '😅', name: 'sweat smile', shortcode: ':sweat_smile:' },
{ char: '🤣', name: 'rolling floor laughing', shortcode: ':rofl:' },
{ char: '😂', name: 'tears of joy', shortcode: ':joy:' },
{
char: '🙂',
name: 'slightly smiling',
shortcode: ':slightly_smiling_face:',
},
{ char: '😊', name: 'smiling eyes blush', shortcode: ':blush:' },
],
},
];
10 changes: 10 additions & 0 deletions packages/core/src/types/emoji.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface EmojiItem {
char: string;
name: string;
shortcode: string;
}

export interface EmojiCategory {
label: string;
items: EmojiItem[];
}
Loading