@domternal/extension-emoji 0.2.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.
@@ -0,0 +1,211 @@
1
+ import { CommandSpec, Node } from '@domternal/core';
2
+ import { Plugin, PluginKey } from '@domternal/pm/state';
3
+ import { NodeType } from '@domternal/pm/model';
4
+
5
+ /**
6
+ * Built-in emoji datasets for @domternal/extension-emoji.
7
+ *
8
+ * Two exports:
9
+ * - `emojis` — ~200 most popular emoji (~8KB gzipped)
10
+ * - `allEmojis` — Full ~1,800 emoji Unicode 15.1 set (~40KB gzipped)
11
+ *
12
+ * Users can import either or provide their own custom data.
13
+ */
14
+ /**
15
+ * A single emoji entry in the dataset.
16
+ */
17
+ interface EmojiItem {
18
+ /** Native Unicode emoji character (e.g., "😄") */
19
+ emoji: string;
20
+ /** Unique name used as node attribute (e.g., "smile") */
21
+ name: string;
22
+ /** Shortcodes without colons (e.g., ["smile", "grinning"]) */
23
+ shortcodes: string[];
24
+ /** Search tags (e.g., ["happy", "face"]) */
25
+ tags: string[];
26
+ /** Category group (e.g., "Smileys & Emotion") */
27
+ group: string;
28
+ /** Optional fallback image URL for unsupported emoji */
29
+ fallbackImage?: string;
30
+ }
31
+ /** Curated set of ~200 most commonly used emoji. */
32
+ declare const emojis: EmojiItem[];
33
+ /**
34
+ * Full Unicode 15.1 emoji dataset.
35
+ * Includes the popular set plus all remaining Unicode emoji.
36
+ * Use `emojis` for a lighter bundle, or `allEmojis` for full coverage.
37
+ */
38
+ declare const allEmojis: EmojiItem[];
39
+
40
+ /**
41
+ * Suggestion Plugin for Emoji Autocomplete
42
+ *
43
+ * Headless ProseMirror plugin that watches for a trigger character (default: ':'),
44
+ * tracks the query, and calls render callbacks so framework wrappers can display
45
+ * a dropdown picker.
46
+ *
47
+ * This is a zero-dependency implementation — no external suggestion library needed.
48
+ */
49
+
50
+ /** Plugin key for external access to suggestion state. */
51
+ declare const emojiSuggestionPluginKey: PluginKey<SuggestionState>;
52
+ interface SuggestionProps {
53
+ /** Current query string (text after trigger char). */
54
+ query: string;
55
+ /** Document range of the trigger + query (for replacement). */
56
+ range: {
57
+ from: number;
58
+ to: number;
59
+ };
60
+ /** Filtered emoji items matching the query. */
61
+ items: EmojiItem[];
62
+ /** Call to insert an emoji and close the suggestion. */
63
+ command: (item: EmojiItem) => void;
64
+ /** Returns the client rect of the cursor for positioning the popup. */
65
+ clientRect: (() => DOMRect | null) | null;
66
+ /** The ProseMirror editor DOM element (for appending popups inside the editor tree). */
67
+ element: HTMLElement;
68
+ }
69
+ interface SuggestionRenderer {
70
+ /** Called when suggestion is first activated. */
71
+ onStart: (props: SuggestionProps) => void;
72
+ /** Called when query or items change. */
73
+ onUpdate: (props: SuggestionProps) => void;
74
+ /** Called when suggestion is deactivated. */
75
+ onExit: () => void;
76
+ /** Called on keydown — return true to prevent default editor handling. */
77
+ onKeyDown: (event: KeyboardEvent) => boolean;
78
+ }
79
+ interface SuggestionOptions {
80
+ /** Trigger character. Default: ':' */
81
+ char?: string;
82
+ /** Minimum query length before showing suggestions. Default: 0 */
83
+ minQueryLength?: number;
84
+ /** Filter/sort items for a given query. */
85
+ items?: (props: {
86
+ query: string;
87
+ }) => EmojiItem[];
88
+ /** Render callbacks for the suggestion popup. */
89
+ render?: () => SuggestionRenderer;
90
+ /** Allow spaces in query. Default: false */
91
+ allowSpaces?: boolean;
92
+ }
93
+ interface SuggestionPluginOptions extends SuggestionOptions {
94
+ editor: unknown;
95
+ nodeType: NodeType | null;
96
+ storage: EmojiStorage;
97
+ plainText: boolean;
98
+ }
99
+ interface SuggestionState {
100
+ active: boolean;
101
+ query: string;
102
+ range: {
103
+ from: number;
104
+ to: number;
105
+ } | null;
106
+ }
107
+ /**
108
+ * Creates a ProseMirror plugin for emoji suggestion/autocomplete.
109
+ */
110
+ declare function createSuggestionPlugin(options: SuggestionPluginOptions): Plugin;
111
+
112
+ /**
113
+ * Emoji Node Extension
114
+ *
115
+ * Inline atom node for emoji with shortcode input rules, emoticon support,
116
+ * and a headless suggestion plugin for autocomplete pickers.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { Emoji, emojis } from '@domternal/extension-emoji';
121
+ *
122
+ * const editor = new Editor({
123
+ * extensions: [
124
+ * Emoji.configure({
125
+ * emojis,
126
+ * enableEmoticons: true,
127
+ * }),
128
+ * ],
129
+ * });
130
+ *
131
+ * // Insert emoji by name
132
+ * editor.commands.insertEmoji('smile');
133
+ *
134
+ * // Programmatically open suggestion picker
135
+ * editor.commands.suggestEmoji();
136
+ * ```
137
+ */
138
+
139
+ declare module '@domternal/core' {
140
+ interface RawCommands {
141
+ insertEmoji: CommandSpec<[name: string]>;
142
+ suggestEmoji: CommandSpec;
143
+ }
144
+ }
145
+ interface EmojiOptions {
146
+ /** Emoji dataset. Default: built-in ~200 popular emoji. */
147
+ emojis: EmojiItem[];
148
+ /** Enable emoticon shortcuts like :) and <3. Default: false. */
149
+ enableEmoticons: boolean;
150
+ /** Render emoji as plain text instead of atom nodes. Default: false. */
151
+ plainText: boolean;
152
+ /** HTML attributes for the emoji span element. */
153
+ HTMLAttributes: Record<string, unknown>;
154
+ /** Suggestion plugin config for autocomplete picker. Default: null (disabled). */
155
+ suggestion: SuggestionOptions | null;
156
+ }
157
+ interface EmojiStorage {
158
+ /** Get frequently used emoji names, sorted by usage count descending. */
159
+ getFrequentlyUsed: () => string[];
160
+ /** Record a usage of an emoji name. */
161
+ addFrequentlyUsed: (name: string) => void;
162
+ /** Find an emoji item by name. */
163
+ findEmoji: (name: string) => EmojiItem | undefined;
164
+ /** Search emoji by query (matches name, shortcodes, and tags). */
165
+ searchEmoji: (query: string) => EmojiItem[];
166
+ /** @internal Name → EmojiItem lookup map (set in onCreate). */
167
+ _nameMap?: Map<string, EmojiItem>;
168
+ /** @internal Shortcode → EmojiItem lookup map (set in onCreate). */
169
+ _shortcodeMap?: Map<string, EmojiItem>;
170
+ }
171
+ declare const Emoji: Node<EmojiOptions, EmojiStorage>;
172
+
173
+ /**
174
+ * Emoticon to emoji name mappings.
175
+ * Used when `enableEmoticons: true` to convert text shortcuts to emoji.
176
+ *
177
+ * Each key is the emoticon text, value is the emoji `name` from the dataset.
178
+ * The emoticon is matched at the end of input (after a space or at line start).
179
+ */
180
+ declare const emoticons: Record<string, string>;
181
+
182
+ /**
183
+ * Default emoji suggestion renderer — vanilla DOM dropdown.
184
+ *
185
+ * Framework-agnostic: creates a positioned dropdown near the cursor
186
+ * that displays matching emoji items with keyboard navigation.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * import { Emoji, emojis, createEmojiSuggestionRenderer } from '@domternal/extension-emoji';
191
+ *
192
+ * const editor = new Editor({
193
+ * extensions: [
194
+ * Emoji.configure({
195
+ * emojis,
196
+ * suggestion: {
197
+ * render: createEmojiSuggestionRenderer(),
198
+ * },
199
+ * }),
200
+ * ],
201
+ * });
202
+ * ```
203
+ */
204
+
205
+ /**
206
+ * Creates a render factory for the emoji suggestion plugin.
207
+ * Returns a function that produces a `SuggestionRenderer` instance.
208
+ */
209
+ declare function createEmojiSuggestionRenderer(): () => SuggestionRenderer;
210
+
211
+ export { Emoji, type EmojiItem, type EmojiOptions, type EmojiStorage, type SuggestionOptions, type SuggestionProps, type SuggestionRenderer, allEmojis, createEmojiSuggestionRenderer, createSuggestionPlugin, Emoji as default, emojiSuggestionPluginKey, emojis, emoticons };
@@ -0,0 +1,211 @@
1
+ import { CommandSpec, Node } from '@domternal/core';
2
+ import { Plugin, PluginKey } from '@domternal/pm/state';
3
+ import { NodeType } from '@domternal/pm/model';
4
+
5
+ /**
6
+ * Built-in emoji datasets for @domternal/extension-emoji.
7
+ *
8
+ * Two exports:
9
+ * - `emojis` — ~200 most popular emoji (~8KB gzipped)
10
+ * - `allEmojis` — Full ~1,800 emoji Unicode 15.1 set (~40KB gzipped)
11
+ *
12
+ * Users can import either or provide their own custom data.
13
+ */
14
+ /**
15
+ * A single emoji entry in the dataset.
16
+ */
17
+ interface EmojiItem {
18
+ /** Native Unicode emoji character (e.g., "😄") */
19
+ emoji: string;
20
+ /** Unique name used as node attribute (e.g., "smile") */
21
+ name: string;
22
+ /** Shortcodes without colons (e.g., ["smile", "grinning"]) */
23
+ shortcodes: string[];
24
+ /** Search tags (e.g., ["happy", "face"]) */
25
+ tags: string[];
26
+ /** Category group (e.g., "Smileys & Emotion") */
27
+ group: string;
28
+ /** Optional fallback image URL for unsupported emoji */
29
+ fallbackImage?: string;
30
+ }
31
+ /** Curated set of ~200 most commonly used emoji. */
32
+ declare const emojis: EmojiItem[];
33
+ /**
34
+ * Full Unicode 15.1 emoji dataset.
35
+ * Includes the popular set plus all remaining Unicode emoji.
36
+ * Use `emojis` for a lighter bundle, or `allEmojis` for full coverage.
37
+ */
38
+ declare const allEmojis: EmojiItem[];
39
+
40
+ /**
41
+ * Suggestion Plugin for Emoji Autocomplete
42
+ *
43
+ * Headless ProseMirror plugin that watches for a trigger character (default: ':'),
44
+ * tracks the query, and calls render callbacks so framework wrappers can display
45
+ * a dropdown picker.
46
+ *
47
+ * This is a zero-dependency implementation — no external suggestion library needed.
48
+ */
49
+
50
+ /** Plugin key for external access to suggestion state. */
51
+ declare const emojiSuggestionPluginKey: PluginKey<SuggestionState>;
52
+ interface SuggestionProps {
53
+ /** Current query string (text after trigger char). */
54
+ query: string;
55
+ /** Document range of the trigger + query (for replacement). */
56
+ range: {
57
+ from: number;
58
+ to: number;
59
+ };
60
+ /** Filtered emoji items matching the query. */
61
+ items: EmojiItem[];
62
+ /** Call to insert an emoji and close the suggestion. */
63
+ command: (item: EmojiItem) => void;
64
+ /** Returns the client rect of the cursor for positioning the popup. */
65
+ clientRect: (() => DOMRect | null) | null;
66
+ /** The ProseMirror editor DOM element (for appending popups inside the editor tree). */
67
+ element: HTMLElement;
68
+ }
69
+ interface SuggestionRenderer {
70
+ /** Called when suggestion is first activated. */
71
+ onStart: (props: SuggestionProps) => void;
72
+ /** Called when query or items change. */
73
+ onUpdate: (props: SuggestionProps) => void;
74
+ /** Called when suggestion is deactivated. */
75
+ onExit: () => void;
76
+ /** Called on keydown — return true to prevent default editor handling. */
77
+ onKeyDown: (event: KeyboardEvent) => boolean;
78
+ }
79
+ interface SuggestionOptions {
80
+ /** Trigger character. Default: ':' */
81
+ char?: string;
82
+ /** Minimum query length before showing suggestions. Default: 0 */
83
+ minQueryLength?: number;
84
+ /** Filter/sort items for a given query. */
85
+ items?: (props: {
86
+ query: string;
87
+ }) => EmojiItem[];
88
+ /** Render callbacks for the suggestion popup. */
89
+ render?: () => SuggestionRenderer;
90
+ /** Allow spaces in query. Default: false */
91
+ allowSpaces?: boolean;
92
+ }
93
+ interface SuggestionPluginOptions extends SuggestionOptions {
94
+ editor: unknown;
95
+ nodeType: NodeType | null;
96
+ storage: EmojiStorage;
97
+ plainText: boolean;
98
+ }
99
+ interface SuggestionState {
100
+ active: boolean;
101
+ query: string;
102
+ range: {
103
+ from: number;
104
+ to: number;
105
+ } | null;
106
+ }
107
+ /**
108
+ * Creates a ProseMirror plugin for emoji suggestion/autocomplete.
109
+ */
110
+ declare function createSuggestionPlugin(options: SuggestionPluginOptions): Plugin;
111
+
112
+ /**
113
+ * Emoji Node Extension
114
+ *
115
+ * Inline atom node for emoji with shortcode input rules, emoticon support,
116
+ * and a headless suggestion plugin for autocomplete pickers.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { Emoji, emojis } from '@domternal/extension-emoji';
121
+ *
122
+ * const editor = new Editor({
123
+ * extensions: [
124
+ * Emoji.configure({
125
+ * emojis,
126
+ * enableEmoticons: true,
127
+ * }),
128
+ * ],
129
+ * });
130
+ *
131
+ * // Insert emoji by name
132
+ * editor.commands.insertEmoji('smile');
133
+ *
134
+ * // Programmatically open suggestion picker
135
+ * editor.commands.suggestEmoji();
136
+ * ```
137
+ */
138
+
139
+ declare module '@domternal/core' {
140
+ interface RawCommands {
141
+ insertEmoji: CommandSpec<[name: string]>;
142
+ suggestEmoji: CommandSpec;
143
+ }
144
+ }
145
+ interface EmojiOptions {
146
+ /** Emoji dataset. Default: built-in ~200 popular emoji. */
147
+ emojis: EmojiItem[];
148
+ /** Enable emoticon shortcuts like :) and <3. Default: false. */
149
+ enableEmoticons: boolean;
150
+ /** Render emoji as plain text instead of atom nodes. Default: false. */
151
+ plainText: boolean;
152
+ /** HTML attributes for the emoji span element. */
153
+ HTMLAttributes: Record<string, unknown>;
154
+ /** Suggestion plugin config for autocomplete picker. Default: null (disabled). */
155
+ suggestion: SuggestionOptions | null;
156
+ }
157
+ interface EmojiStorage {
158
+ /** Get frequently used emoji names, sorted by usage count descending. */
159
+ getFrequentlyUsed: () => string[];
160
+ /** Record a usage of an emoji name. */
161
+ addFrequentlyUsed: (name: string) => void;
162
+ /** Find an emoji item by name. */
163
+ findEmoji: (name: string) => EmojiItem | undefined;
164
+ /** Search emoji by query (matches name, shortcodes, and tags). */
165
+ searchEmoji: (query: string) => EmojiItem[];
166
+ /** @internal Name → EmojiItem lookup map (set in onCreate). */
167
+ _nameMap?: Map<string, EmojiItem>;
168
+ /** @internal Shortcode → EmojiItem lookup map (set in onCreate). */
169
+ _shortcodeMap?: Map<string, EmojiItem>;
170
+ }
171
+ declare const Emoji: Node<EmojiOptions, EmojiStorage>;
172
+
173
+ /**
174
+ * Emoticon to emoji name mappings.
175
+ * Used when `enableEmoticons: true` to convert text shortcuts to emoji.
176
+ *
177
+ * Each key is the emoticon text, value is the emoji `name` from the dataset.
178
+ * The emoticon is matched at the end of input (after a space or at line start).
179
+ */
180
+ declare const emoticons: Record<string, string>;
181
+
182
+ /**
183
+ * Default emoji suggestion renderer — vanilla DOM dropdown.
184
+ *
185
+ * Framework-agnostic: creates a positioned dropdown near the cursor
186
+ * that displays matching emoji items with keyboard navigation.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * import { Emoji, emojis, createEmojiSuggestionRenderer } from '@domternal/extension-emoji';
191
+ *
192
+ * const editor = new Editor({
193
+ * extensions: [
194
+ * Emoji.configure({
195
+ * emojis,
196
+ * suggestion: {
197
+ * render: createEmojiSuggestionRenderer(),
198
+ * },
199
+ * }),
200
+ * ],
201
+ * });
202
+ * ```
203
+ */
204
+
205
+ /**
206
+ * Creates a render factory for the emoji suggestion plugin.
207
+ * Returns a function that produces a `SuggestionRenderer` instance.
208
+ */
209
+ declare function createEmojiSuggestionRenderer(): () => SuggestionRenderer;
210
+
211
+ export { Emoji, type EmojiItem, type EmojiOptions, type EmojiStorage, type SuggestionOptions, type SuggestionProps, type SuggestionRenderer, allEmojis, createEmojiSuggestionRenderer, createSuggestionPlugin, Emoji as default, emojiSuggestionPluginKey, emojis, emoticons };