@mantine/emoji 0.0.0-stage → 9.8.1
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/LICENSE +21 -0
- package/README.md +20 -2
- package/cjs/adapters/emoji-mart-adapter.cjs +30 -0
- package/cjs/adapters/emoji-mart-adapter.cjs.map +1 -0
- package/cjs/adapters/emojibase-adapter.cjs +76 -0
- package/cjs/adapters/emojibase-adapter.cjs.map +1 -0
- package/cjs/categories.cjs +52 -0
- package/cjs/categories.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiButton.cjs +24 -0
- package/cjs/components/EmojiPicker/EmojiButton.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPicker.cjs +289 -0
- package/cjs/components/EmojiPicker/EmojiPicker.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPicker.context.cjs +7 -0
- package/cjs/components/EmojiPicker/EmojiPicker.context.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPicker.module.cjs +22 -0
- package/cjs/components/EmojiPicker/EmojiPicker.module.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPickerCategoryNav.cjs +38 -0
- package/cjs/components/EmojiPicker/EmojiPickerCategoryNav.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPickerGrid.cjs +131 -0
- package/cjs/components/EmojiPicker/EmojiPickerGrid.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPickerPreview.cjs +24 -0
- package/cjs/components/EmojiPicker/EmojiPickerPreview.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPickerSearch.cjs +57 -0
- package/cjs/components/EmojiPicker/EmojiPickerSearch.cjs.map +1 -0
- package/cjs/components/EmojiPicker/EmojiPickerSkinTone.cjs +63 -0
- package/cjs/components/EmojiPicker/EmojiPickerSkinTone.cjs.map +1 -0
- package/cjs/components/EmojiPickerInput/EmojiPickerInput.cjs +190 -0
- package/cjs/components/EmojiPickerInput/EmojiPickerInput.cjs.map +1 -0
- package/cjs/components/EmojiPickerInput/EmojiPickerInput.module.cjs +11 -0
- package/cjs/components/EmojiPickerInput/EmojiPickerInput.module.cjs.map +1 -0
- package/cjs/components/EmojiPickerPopover/EmojiPickerPopover.cjs +59 -0
- package/cjs/components/EmojiPickerPopover/EmojiPickerPopover.cjs.map +1 -0
- package/cjs/components/EmojiPickerPopover/EmojiPickerPopover.module.cjs +6 -0
- package/cjs/components/EmojiPickerPopover/EmojiPickerPopover.module.cjs.map +1 -0
- package/cjs/hooks/use-emoji-grid-navigation.cjs +70 -0
- package/cjs/hooks/use-emoji-grid-navigation.cjs.map +1 -0
- package/cjs/hooks/use-emoji-search.cjs +21 -0
- package/cjs/hooks/use-emoji-search.cjs.map +1 -0
- package/cjs/index.cjs +22 -0
- package/cjs/types.cjs +20 -0
- package/cjs/types.cjs.map +1 -0
- package/cjs/utils/emoji-grid-utils.cjs +57 -0
- package/cjs/utils/emoji-grid-utils.cjs.map +1 -0
- package/cjs/utils/flatten-emoji-data.cjs +33 -0
- package/cjs/utils/flatten-emoji-data.cjs.map +1 -0
- package/cjs/utils/is-emoji-supported.cjs +64 -0
- package/cjs/utils/is-emoji-supported.cjs.map +1 -0
- package/cjs/utils/search-emojis.cjs +21 -0
- package/cjs/utils/search-emojis.cjs.map +1 -0
- package/esm/adapters/emoji-mart-adapter.mjs +30 -0
- package/esm/adapters/emoji-mart-adapter.mjs.map +1 -0
- package/esm/adapters/emojibase-adapter.mjs +76 -0
- package/esm/adapters/emojibase-adapter.mjs.map +1 -0
- package/esm/categories.mjs +47 -0
- package/esm/categories.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiButton.mjs +24 -0
- package/esm/components/EmojiPicker/EmojiButton.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPicker.context.mjs +7 -0
- package/esm/components/EmojiPicker/EmojiPicker.context.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPicker.mjs +289 -0
- package/esm/components/EmojiPicker/EmojiPicker.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPicker.module.mjs +22 -0
- package/esm/components/EmojiPicker/EmojiPicker.module.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPickerCategoryNav.mjs +38 -0
- package/esm/components/EmojiPicker/EmojiPickerCategoryNav.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPickerGrid.mjs +131 -0
- package/esm/components/EmojiPicker/EmojiPickerGrid.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPickerPreview.mjs +24 -0
- package/esm/components/EmojiPicker/EmojiPickerPreview.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPickerSearch.mjs +57 -0
- package/esm/components/EmojiPicker/EmojiPickerSearch.mjs.map +1 -0
- package/esm/components/EmojiPicker/EmojiPickerSkinTone.mjs +63 -0
- package/esm/components/EmojiPicker/EmojiPickerSkinTone.mjs.map +1 -0
- package/esm/components/EmojiPickerInput/EmojiPickerInput.mjs +190 -0
- package/esm/components/EmojiPickerInput/EmojiPickerInput.mjs.map +1 -0
- package/esm/components/EmojiPickerInput/EmojiPickerInput.module.mjs +11 -0
- package/esm/components/EmojiPickerInput/EmojiPickerInput.module.mjs.map +1 -0
- package/esm/components/EmojiPickerPopover/EmojiPickerPopover.mjs +59 -0
- package/esm/components/EmojiPickerPopover/EmojiPickerPopover.mjs.map +1 -0
- package/esm/components/EmojiPickerPopover/EmojiPickerPopover.module.mjs +6 -0
- package/esm/components/EmojiPickerPopover/EmojiPickerPopover.module.mjs.map +1 -0
- package/esm/hooks/use-emoji-grid-navigation.mjs +70 -0
- package/esm/hooks/use-emoji-grid-navigation.mjs.map +1 -0
- package/esm/hooks/use-emoji-search.mjs +21 -0
- package/esm/hooks/use-emoji-search.mjs.map +1 -0
- package/esm/index.mjs +11 -0
- package/esm/types.mjs +20 -0
- package/esm/types.mjs.map +1 -0
- package/esm/utils/emoji-grid-utils.mjs +54 -0
- package/esm/utils/emoji-grid-utils.mjs.map +1 -0
- package/esm/utils/flatten-emoji-data.mjs +33 -0
- package/esm/utils/flatten-emoji-data.mjs.map +1 -0
- package/esm/utils/is-emoji-supported.mjs +63 -0
- package/esm/utils/is-emoji-supported.mjs.map +1 -0
- package/esm/utils/search-emojis.mjs +21 -0
- package/esm/utils/search-emojis.mjs.map +1 -0
- package/lib/adapters/emoji-mart-adapter.d.ts +23 -0
- package/lib/adapters/emojibase-adapter.d.ts +25 -0
- package/lib/adapters/index.d.ts +2 -0
- package/lib/categories.d.ts +7 -0
- package/lib/components/EmojiPicker/EmojiButton.d.ts +10 -0
- package/lib/components/EmojiPicker/EmojiPicker.context.d.ts +9 -0
- package/lib/components/EmojiPicker/EmojiPicker.d.ts +64 -0
- package/lib/components/EmojiPicker/EmojiPickerCategoryNav.d.ts +10 -0
- package/lib/components/EmojiPicker/EmojiPickerGrid.d.ts +23 -0
- package/lib/components/EmojiPicker/EmojiPickerPreview.d.ts +9 -0
- package/lib/components/EmojiPicker/EmojiPickerSearch.d.ts +14 -0
- package/lib/components/EmojiPicker/EmojiPickerSkinTone.d.ts +6 -0
- package/lib/components/EmojiPicker/index.d.ts +2 -0
- package/lib/components/EmojiPickerInput/EmojiPickerInput.d.ts +54 -0
- package/lib/components/EmojiPickerInput/index.d.ts +2 -0
- package/lib/components/EmojiPickerPopover/EmojiPickerPopover.d.ts +24 -0
- package/lib/components/EmojiPickerPopover/index.d.ts +2 -0
- package/lib/hooks/index.d.ts +2 -0
- package/lib/hooks/use-emoji-grid-navigation.d.ts +18 -0
- package/lib/hooks/use-emoji-search.d.ts +14 -0
- package/lib/index.d.mts +10 -0
- package/lib/index.d.ts +10 -0
- package/lib/types.d.ts +41 -0
- package/lib/utils/emoji-grid-utils.d.ts +17 -0
- package/lib/utils/flatten-emoji-data.d.ts +2 -0
- package/lib/utils/index.d.ts +5 -0
- package/lib/utils/is-emoji-supported.d.ts +4 -0
- package/lib/utils/search-emojis.d.ts +2 -0
- package/package.json +54 -4
- package/styles.css +228 -0
- package/styles.layer.css +229 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// packages/@mantine/emoji/src/utils/emoji-grid-utils.ts
|
|
3
|
+
function createEmojiGridModel(items) {
|
|
4
|
+
const emojis = [];
|
|
5
|
+
const rows = [];
|
|
6
|
+
const emojiRows = [];
|
|
7
|
+
const itemOffsets = [];
|
|
8
|
+
items.forEach((item, itemIndex) => {
|
|
9
|
+
itemOffsets.push(emojis.length);
|
|
10
|
+
if (item.type === "row") {
|
|
11
|
+
rows.push({
|
|
12
|
+
itemIndex,
|
|
13
|
+
start: emojis.length,
|
|
14
|
+
length: item.emojis.length
|
|
15
|
+
});
|
|
16
|
+
for (const emoji of item.emojis) {
|
|
17
|
+
emojis.push(emoji);
|
|
18
|
+
emojiRows.push(rows.length - 1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
emojis,
|
|
24
|
+
rows,
|
|
25
|
+
emojiRows,
|
|
26
|
+
itemOffsets
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getNextEmojiIndex(model, index, direction) {
|
|
30
|
+
const lastIndex = model.emojis.length - 1;
|
|
31
|
+
if (lastIndex < 0) return -1;
|
|
32
|
+
const current = Math.min(Math.max(index, 0), lastIndex);
|
|
33
|
+
if (direction === "left") return Math.max(current - 1, 0);
|
|
34
|
+
if (direction === "right") return Math.min(current + 1, lastIndex);
|
|
35
|
+
const rowPosition = model.emojiRows[current];
|
|
36
|
+
const targetRow = model.rows[rowPosition + (direction === "down" ? 1 : -1)];
|
|
37
|
+
if (!targetRow) return current;
|
|
38
|
+
const column = current - model.rows[rowPosition].start;
|
|
39
|
+
return targetRow.start + Math.min(column, targetRow.length - 1);
|
|
40
|
+
}
|
|
41
|
+
function getEmojiItemIndex(model, index) {
|
|
42
|
+
const row = model.rows[model.emojiRows[index]];
|
|
43
|
+
return row ? row.itemIndex : -1;
|
|
44
|
+
}
|
|
45
|
+
function applySkinTone(emoji, skinTone) {
|
|
46
|
+
if (skinTone > 0 && emoji.skins && emoji.skins[skinTone - 1]) return {
|
|
47
|
+
...emoji,
|
|
48
|
+
emoji: emoji.skins[skinTone - 1]
|
|
49
|
+
};
|
|
50
|
+
return emoji;
|
|
51
|
+
}
|
|
52
|
+
export { applySkinTone, createEmojiGridModel, getEmojiItemIndex, getNextEmojiIndex };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=emoji-grid-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emoji-grid-utils.mjs","names":[],"sources":["../../src/utils/emoji-grid-utils.ts"],"sourcesContent":["import type { EmojiPickerEmoji, FlattenedRowItem } from '../types';\n\nexport interface EmojiGridRow {\n itemIndex: number;\n start: number;\n length: number;\n}\n\nexport interface EmojiGridModel {\n emojis: EmojiPickerEmoji[];\n rows: EmojiGridRow[];\n emojiRows: number[];\n itemOffsets: number[];\n}\n\nexport type EmojiGridDirection = 'left' | 'right' | 'up' | 'down';\n\nexport function createEmojiGridModel(items: FlattenedRowItem[]): EmojiGridModel {\n const emojis: EmojiPickerEmoji[] = [];\n const rows: EmojiGridRow[] = [];\n const emojiRows: number[] = [];\n const itemOffsets: number[] = [];\n\n items.forEach((item, itemIndex) => {\n itemOffsets.push(emojis.length);\n if (item.type === 'row') {\n rows.push({ itemIndex, start: emojis.length, length: item.emojis.length });\n for (const emoji of item.emojis) {\n emojis.push(emoji);\n emojiRows.push(rows.length - 1);\n }\n }\n });\n\n return { emojis, rows, emojiRows, itemOffsets };\n}\n\nexport function getNextEmojiIndex(\n model: EmojiGridModel,\n index: number,\n direction: EmojiGridDirection\n): number {\n const lastIndex = model.emojis.length - 1;\n if (lastIndex < 0) {\n return -1;\n }\n\n const current = Math.min(Math.max(index, 0), lastIndex);\n\n if (direction === 'left') {\n return Math.max(current - 1, 0);\n }\n\n if (direction === 'right') {\n return Math.min(current + 1, lastIndex);\n }\n\n const rowPosition = model.emojiRows[current];\n const targetRow = model.rows[rowPosition + (direction === 'down' ? 1 : -1)];\n if (!targetRow) {\n return current;\n }\n\n const column = current - model.rows[rowPosition].start;\n return targetRow.start + Math.min(column, targetRow.length - 1);\n}\n\nexport function getEmojiItemIndex(model: EmojiGridModel, index: number): number {\n const row = model.rows[model.emojiRows[index]];\n return row ? row.itemIndex : -1;\n}\n\nexport function applySkinTone(emoji: EmojiPickerEmoji, skinTone: number): EmojiPickerEmoji {\n if (skinTone > 0 && emoji.skins && emoji.skins[skinTone - 1]) {\n return { ...emoji, emoji: emoji.skins[skinTone - 1] };\n }\n return emoji;\n}\n"],"mappings":";;AAiBA,SAAgB,qBAAqB,OAA2C;CAC9E,MAAM,SAA6B,CAAC;CACpC,MAAM,OAAuB,CAAC;CAC9B,MAAM,YAAsB,CAAC;CAC7B,MAAM,cAAwB,CAAC;CAE/B,MAAM,SAAS,MAAM,cAAc;EACjC,YAAY,KAAK,OAAO,MAAM;EAC9B,IAAI,KAAK,SAAS,OAAO;GACvB,KAAK,KAAK;IAAE;IAAW,OAAO,OAAO;IAAQ,QAAQ,KAAK,OAAO;GAAO,CAAC;GACzE,KAAK,MAAM,SAAS,KAAK,QAAQ;IAC/B,OAAO,KAAK,KAAK;IACjB,UAAU,KAAK,KAAK,SAAS,CAAC;GAChC;EACF;CACF,CAAC;CAED,OAAO;EAAE;EAAQ;EAAM;EAAW;CAAY;AAChD;AAEA,SAAgB,kBACd,OACA,OACA,WACQ;CACR,MAAM,YAAY,MAAM,OAAO,SAAS;CACxC,IAAI,YAAY,GACd,OAAO;CAGT,MAAM,UAAU,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,SAAS;CAEtD,IAAI,cAAc,QAChB,OAAO,KAAK,IAAI,UAAU,GAAG,CAAC;CAGhC,IAAI,cAAc,SAChB,OAAO,KAAK,IAAI,UAAU,GAAG,SAAS;CAGxC,MAAM,cAAc,MAAM,UAAU;CACpC,MAAM,YAAY,MAAM,KAAK,eAAe,cAAc,SAAS,IAAI;CACvE,IAAI,CAAC,WACH,OAAO;CAGT,MAAM,SAAS,UAAU,MAAM,KAAK,YAAY,CAAC;CACjD,OAAO,UAAU,QAAQ,KAAK,IAAI,QAAQ,UAAU,SAAS,CAAC;AAChE;AAEA,SAAgB,kBAAkB,OAAuB,OAAuB;CAC9E,MAAM,MAAM,MAAM,KAAK,MAAM,UAAU;CACvC,OAAO,MAAM,IAAI,YAAY;AAC/B;AAEA,SAAgB,cAAc,OAAyB,UAAoC;CACzF,IAAI,WAAW,KAAK,MAAM,SAAS,MAAM,MAAM,WAAW,IACxD,OAAO;EAAE,GAAG;EAAO,OAAO,MAAM,MAAM,WAAW;CAAG;CAEtD,OAAO;AACT"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// packages/@mantine/emoji/src/utils/flatten-emoji-data.ts
|
|
3
|
+
function chunkArray(array, size) {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
for (let i = 0; i < array.length; i += size) chunks.push(array.slice(i, i + size));
|
|
6
|
+
return chunks;
|
|
7
|
+
}
|
|
8
|
+
function flattenEmojiData(data, columns, categoryLabels) {
|
|
9
|
+
const items = [];
|
|
10
|
+
for (const category of data.categories) {
|
|
11
|
+
const emojis = [];
|
|
12
|
+
for (const emojiId of category.emojis) {
|
|
13
|
+
const emoji = data.emojis[emojiId];
|
|
14
|
+
if (emoji) emojis.push(emoji);
|
|
15
|
+
}
|
|
16
|
+
if (emojis.length === 0) continue;
|
|
17
|
+
const label = categoryLabels?.[category.id] ?? category.label;
|
|
18
|
+
items.push({
|
|
19
|
+
type: "header",
|
|
20
|
+
categoryId: category.id,
|
|
21
|
+
label
|
|
22
|
+
});
|
|
23
|
+
const rows = chunkArray(emojis, columns);
|
|
24
|
+
for (const row of rows) items.push({
|
|
25
|
+
type: "row",
|
|
26
|
+
emojis: row
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return items;
|
|
30
|
+
}
|
|
31
|
+
export { flattenEmojiData };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=flatten-emoji-data.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten-emoji-data.mjs","names":[],"sources":["../../src/utils/flatten-emoji-data.ts"],"sourcesContent":["import type { EmojiPickerData, EmojiPickerEmoji, FlattenedRowItem } from '../types';\n\nfunction chunkArray<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size));\n }\n return chunks;\n}\n\nexport function flattenEmojiData(\n data: EmojiPickerData,\n columns: number,\n categoryLabels?: Record<string, string>\n): FlattenedRowItem[] {\n const items: FlattenedRowItem[] = [];\n\n for (const category of data.categories) {\n const emojis: EmojiPickerEmoji[] = [];\n for (const emojiId of category.emojis) {\n const emoji = data.emojis[emojiId];\n if (emoji) {\n emojis.push(emoji);\n }\n }\n\n if (emojis.length === 0) {\n continue;\n }\n\n const label = categoryLabels?.[category.id] ?? category.label;\n items.push({ type: 'header', categoryId: category.id, label });\n\n const rows = chunkArray(emojis, columns);\n for (const row of rows) {\n items.push({ type: 'row', emojis: row });\n }\n }\n\n return items;\n}\n"],"mappings":";;AAEA,SAAS,WAAc,OAAY,MAAqB;CACtD,MAAM,SAAgB,CAAC;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,MACrC,OAAO,KAAK,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;CAEtC,OAAO;AACT;AAEA,SAAgB,iBACd,MACA,SACA,gBACoB;CACpB,MAAM,QAA4B,CAAC;CAEnC,KAAK,MAAM,YAAY,KAAK,YAAY;EACtC,MAAM,SAA6B,CAAC;EACpC,KAAK,MAAM,WAAW,SAAS,QAAQ;GACrC,MAAM,QAAQ,KAAK,OAAO;GAC1B,IAAI,OACF,OAAO,KAAK,KAAK;EAErB;EAEA,IAAI,OAAO,WAAW,GACpB;EAGF,MAAM,QAAQ,iBAAiB,SAAS,OAAO,SAAS;EACxD,MAAM,KAAK;GAAE,MAAM;GAAU,YAAY,SAAS;GAAI;EAAM,CAAC;EAE7D,MAAM,OAAO,WAAW,QAAQ,OAAO;EACvC,KAAK,MAAM,OAAO,MAChB,MAAM,KAAK;GAAE,MAAM;GAAO,QAAQ;EAAI,CAAC;CAE3C;CAEA,OAAO;AACT"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// packages/@mantine/emoji/src/utils/is-emoji-supported.ts
|
|
3
|
+
const CANVAS_SIZE = 24;
|
|
4
|
+
const FONT_SIZE = 18;
|
|
5
|
+
const REFERENCE_EMOJI = "😀";
|
|
6
|
+
const VARIATION_SELECTOR = "️";
|
|
7
|
+
const cache = /* @__PURE__ */ new Map();
|
|
8
|
+
let context;
|
|
9
|
+
function getContext() {
|
|
10
|
+
if (context !== void 0) return context;
|
|
11
|
+
if (typeof document === "undefined") return null;
|
|
12
|
+
try {
|
|
13
|
+
const canvas = document.createElement("canvas");
|
|
14
|
+
canvas.width = CANVAS_SIZE;
|
|
15
|
+
canvas.height = CANVAS_SIZE;
|
|
16
|
+
context = canvas.getContext("2d", { willReadFrequently: true }) ?? null;
|
|
17
|
+
if (context) {
|
|
18
|
+
context.font = `${FONT_SIZE}px sans-serif`;
|
|
19
|
+
context.textBaseline = "top";
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
context = null;
|
|
23
|
+
}
|
|
24
|
+
return context ?? null;
|
|
25
|
+
}
|
|
26
|
+
function renderPixels(ctx, emoji, color) {
|
|
27
|
+
ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
|
|
28
|
+
ctx.fillStyle = color;
|
|
29
|
+
ctx.fillText(emoji, 0, 0);
|
|
30
|
+
return ctx.getImageData(0, 0, CANVAS_SIZE, CANVAS_SIZE).data;
|
|
31
|
+
}
|
|
32
|
+
function rendersAsColorGlyph(ctx, emoji) {
|
|
33
|
+
const first = renderPixels(ctx, emoji, "#f00");
|
|
34
|
+
const second = renderPixels(ctx, emoji, "#00f");
|
|
35
|
+
let hasPixels = false;
|
|
36
|
+
for (let i = 0; i < first.length; i += 1) {
|
|
37
|
+
if (first[i] !== second[i]) return false;
|
|
38
|
+
if (!hasPixels && i % 4 === 3 && first[i] > 0) hasPixels = true;
|
|
39
|
+
}
|
|
40
|
+
return hasPixels;
|
|
41
|
+
}
|
|
42
|
+
function rendersAsSingleGlyph(ctx, emoji) {
|
|
43
|
+
if (Array.from(emoji).filter((char) => char !== VARIATION_SELECTOR).length < 2) return true;
|
|
44
|
+
return ctx.measureText(emoji).width < ctx.measureText(REFERENCE_EMOJI).width * 1.5;
|
|
45
|
+
}
|
|
46
|
+
function isEmojiSupported(emoji) {
|
|
47
|
+
const cached = cache.get(emoji);
|
|
48
|
+
if (cached !== void 0) return cached;
|
|
49
|
+
const ctx = getContext();
|
|
50
|
+
if (!ctx) return true;
|
|
51
|
+
const supported = rendersAsSingleGlyph(ctx, emoji) && rendersAsColorGlyph(ctx, emoji);
|
|
52
|
+
cache.set(emoji, supported);
|
|
53
|
+
return supported;
|
|
54
|
+
}
|
|
55
|
+
function filterSupportedEmojis(emojis, emojiIds) {
|
|
56
|
+
return emojiIds.filter((id) => {
|
|
57
|
+
const emoji = emojis[id];
|
|
58
|
+
return emoji ? isEmojiSupported(emoji.emoji) : false;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export { filterSupportedEmojis, isEmojiSupported };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=is-emoji-supported.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-emoji-supported.mjs","names":[],"sources":["../../src/utils/is-emoji-supported.ts"],"sourcesContent":["const CANVAS_SIZE = 24;\nconst FONT_SIZE = 18;\nconst REFERENCE_EMOJI = '😀';\nconst VARIATION_SELECTOR = '️';\n\nconst cache = new Map<string, boolean>();\nlet context: CanvasRenderingContext2D | null | undefined;\n\nfunction getContext(): CanvasRenderingContext2D | null {\n if (context !== undefined) {\n return context;\n }\n\n if (typeof document === 'undefined') {\n return null;\n }\n\n try {\n const canvas = document.createElement('canvas');\n canvas.width = CANVAS_SIZE;\n canvas.height = CANVAS_SIZE;\n context = canvas.getContext('2d', { willReadFrequently: true }) ?? null;\n if (context) {\n context.font = `${FONT_SIZE}px sans-serif`;\n context.textBaseline = 'top';\n }\n } catch {\n context = null;\n }\n\n return context ?? null;\n}\n\nfunction renderPixels(ctx: CanvasRenderingContext2D, emoji: string, color: string) {\n ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);\n ctx.fillStyle = color;\n ctx.fillText(emoji, 0, 0);\n return ctx.getImageData(0, 0, CANVAS_SIZE, CANVAS_SIZE).data;\n}\n\nfunction rendersAsColorGlyph(ctx: CanvasRenderingContext2D, emoji: string) {\n const first = renderPixels(ctx, emoji, '#f00');\n const second = renderPixels(ctx, emoji, '#00f');\n\n let hasPixels = false;\n for (let i = 0; i < first.length; i += 1) {\n if (first[i] !== second[i]) {\n return false;\n }\n\n if (!hasPixels && i % 4 === 3 && first[i] > 0) {\n hasPixels = true;\n }\n }\n\n return hasPixels;\n}\n\nfunction rendersAsSingleGlyph(ctx: CanvasRenderingContext2D, emoji: string) {\n const codePoints = Array.from(emoji).filter((char) => char !== VARIATION_SELECTOR);\n if (codePoints.length < 2) {\n return true;\n }\n\n return ctx.measureText(emoji).width < ctx.measureText(REFERENCE_EMOJI).width * 1.5;\n}\n\nexport function isEmojiSupported(emoji: string): boolean {\n const cached = cache.get(emoji);\n if (cached !== undefined) {\n return cached;\n }\n\n const ctx = getContext();\n if (!ctx) {\n return true;\n }\n\n const supported = rendersAsSingleGlyph(ctx, emoji) && rendersAsColorGlyph(ctx, emoji);\n cache.set(emoji, supported);\n return supported;\n}\n\nexport function filterSupportedEmojis(\n emojis: Record<string, { emoji: string }>,\n emojiIds: string[]\n): string[] {\n return emojiIds.filter((id) => {\n const emoji = emojis[id];\n return emoji ? isEmojiSupported(emoji.emoji) : false;\n });\n}\n"],"mappings":";;AAAA,MAAM,cAAc;AACpB,MAAM,YAAY;AAClB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAE3B,MAAM,wBAAQ,IAAI,IAAqB;AACvC,IAAI;AAEJ,SAAS,aAA8C;CACrD,IAAI,YAAY,KAAA,GACd,OAAO;CAGT,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,IAAI;EACF,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,OAAO,QAAQ;EACf,OAAO,SAAS;EAChB,UAAU,OAAO,WAAW,MAAM,EAAE,oBAAoB,KAAK,CAAC,KAAK;EACnE,IAAI,SAAS;GACX,QAAQ,OAAO,GAAG,UAAU;GAC5B,QAAQ,eAAe;EACzB;CACF,QAAQ;EACN,UAAU;CACZ;CAEA,OAAO,WAAW;AACpB;AAEA,SAAS,aAAa,KAA+B,OAAe,OAAe;CACjF,IAAI,UAAU,GAAG,GAAG,aAAa,WAAW;CAC5C,IAAI,YAAY;CAChB,IAAI,SAAS,OAAO,GAAG,CAAC;CACxB,OAAO,IAAI,aAAa,GAAG,GAAG,aAAa,WAAW,CAAC,CAAC;AAC1D;AAEA,SAAS,oBAAoB,KAA+B,OAAe;CACzE,MAAM,QAAQ,aAAa,KAAK,OAAO,MAAM;CAC7C,MAAM,SAAS,aAAa,KAAK,OAAO,MAAM;CAE9C,IAAI,YAAY;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxC,IAAI,MAAM,OAAO,OAAO,IACtB,OAAO;EAGT,IAAI,CAAC,aAAa,IAAI,MAAM,KAAK,MAAM,KAAK,GAC1C,YAAY;CAEhB;CAEA,OAAO;AACT;AAEA,SAAS,qBAAqB,KAA+B,OAAe;CAE1E,IADmB,MAAM,KAAK,KAAK,CAAC,CAAC,QAAQ,SAAS,SAAS,kBAClD,CAAC,CAAC,SAAS,GACtB,OAAO;CAGT,OAAO,IAAI,YAAY,KAAK,CAAC,CAAC,QAAQ,IAAI,YAAY,eAAe,CAAC,CAAC,QAAQ;AACjF;AAEA,SAAgB,iBAAiB,OAAwB;CACvD,MAAM,SAAS,MAAM,IAAI,KAAK;CAC9B,IAAI,WAAW,KAAA,GACb,OAAO;CAGT,MAAM,MAAM,WAAW;CACvB,IAAI,CAAC,KACH,OAAO;CAGT,MAAM,YAAY,qBAAqB,KAAK,KAAK,KAAK,oBAAoB,KAAK,KAAK;CACpF,MAAM,IAAI,OAAO,SAAS;CAC1B,OAAO;AACT;AAEA,SAAgB,sBACd,QACA,UACU;CACV,OAAO,SAAS,QAAQ,OAAO;EAC7B,MAAM,QAAQ,OAAO;EACrB,OAAO,QAAQ,iBAAiB,MAAM,KAAK,IAAI;CACjD,CAAC;AACH"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// packages/@mantine/emoji/src/utils/search-emojis.ts
|
|
3
|
+
function searchEmojis(data, query) {
|
|
4
|
+
const trimmed = query.trim().toLowerCase();
|
|
5
|
+
if (!trimmed) return [];
|
|
6
|
+
const results = [];
|
|
7
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8
|
+
for (const category of data.categories) for (const emojiId of category.emojis) {
|
|
9
|
+
if (seen.has(emojiId)) continue;
|
|
10
|
+
const emoji = data.emojis[emojiId];
|
|
11
|
+
if (!emoji) continue;
|
|
12
|
+
if (emoji.id === trimmed || emoji.name.toLowerCase().includes(trimmed) || emoji.keywords.some((kw) => kw.toLowerCase().startsWith(trimmed))) {
|
|
13
|
+
results.push(emoji);
|
|
14
|
+
seen.add(emojiId);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return results;
|
|
18
|
+
}
|
|
19
|
+
export { searchEmojis };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=search-emojis.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-emojis.mjs","names":[],"sources":["../../src/utils/search-emojis.ts"],"sourcesContent":["import type { EmojiPickerData, EmojiPickerEmoji } from '../types';\n\nexport function searchEmojis(data: EmojiPickerData, query: string): EmojiPickerEmoji[] {\n const trimmed = query.trim().toLowerCase();\n if (!trimmed) {\n return [];\n }\n\n const results: EmojiPickerEmoji[] = [];\n const seen = new Set<string>();\n\n for (const category of data.categories) {\n for (const emojiId of category.emojis) {\n if (seen.has(emojiId)) {\n continue;\n }\n\n const emoji = data.emojis[emojiId];\n if (!emoji) {\n continue;\n }\n\n const matches =\n emoji.id === trimmed ||\n emoji.name.toLowerCase().includes(trimmed) ||\n emoji.keywords.some((kw) => kw.toLowerCase().startsWith(trimmed));\n\n if (matches) {\n results.push(emoji);\n seen.add(emojiId);\n }\n }\n }\n\n return results;\n}\n"],"mappings":";;AAEA,SAAgB,aAAa,MAAuB,OAAmC;CACrF,MAAM,UAAU,MAAM,KAAK,CAAC,CAAC,YAAY;CACzC,IAAI,CAAC,SACH,OAAO,CAAC;CAGV,MAAM,UAA8B,CAAC;CACrC,MAAM,uBAAO,IAAI,IAAY;CAE7B,KAAK,MAAM,YAAY,KAAK,YAC1B,KAAK,MAAM,WAAW,SAAS,QAAQ;EACrC,IAAI,KAAK,IAAI,OAAO,GAClB;EAGF,MAAM,QAAQ,KAAK,OAAO;EAC1B,IAAI,CAAC,OACH;EAQF,IAJE,MAAM,OAAO,WACb,MAAM,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,KACzC,MAAM,SAAS,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,WAAW,OAAO,CAAC,GAErD;GACX,QAAQ,KAAK,KAAK;GAClB,KAAK,IAAI,OAAO;EAClB;CACF;CAGF,OAAO;AACT"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { EmojiPickerData } from '../types';
|
|
2
|
+
interface EmojiMartSkin {
|
|
3
|
+
unified: string;
|
|
4
|
+
native: string;
|
|
5
|
+
}
|
|
6
|
+
interface EmojiMartEmoji {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
keywords: string[];
|
|
10
|
+
skins: EmojiMartSkin[];
|
|
11
|
+
version: number;
|
|
12
|
+
}
|
|
13
|
+
interface EmojiMartCategory {
|
|
14
|
+
id: string;
|
|
15
|
+
emojis: string[];
|
|
16
|
+
}
|
|
17
|
+
interface EmojiMartData {
|
|
18
|
+
categories: EmojiMartCategory[];
|
|
19
|
+
emojis: Record<string, EmojiMartEmoji>;
|
|
20
|
+
}
|
|
21
|
+
export declare function emojiMartAdapter(data: EmojiMartData): EmojiPickerData;
|
|
22
|
+
export declare function emojiMartAdapter(data: object): EmojiPickerData;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EmojiPickerData } from '../types';
|
|
2
|
+
interface EmojibaseSkin {
|
|
3
|
+
emoji: string;
|
|
4
|
+
tone?: number | number[];
|
|
5
|
+
}
|
|
6
|
+
interface EmojibaseEmoji {
|
|
7
|
+
label: string;
|
|
8
|
+
hexcode: string;
|
|
9
|
+
emoji: string;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
group?: number;
|
|
12
|
+
order?: number;
|
|
13
|
+
version: number;
|
|
14
|
+
skins?: EmojibaseSkin[];
|
|
15
|
+
}
|
|
16
|
+
interface EmojibaseGroupMessage {
|
|
17
|
+
key: string;
|
|
18
|
+
message: string;
|
|
19
|
+
order: number;
|
|
20
|
+
}
|
|
21
|
+
interface EmojibaseMessages {
|
|
22
|
+
groups: EmojibaseGroupMessage[];
|
|
23
|
+
}
|
|
24
|
+
export declare function emojibaseAdapter(data: EmojibaseEmoji[], messages: EmojibaseMessages): EmojiPickerData;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const CANONICAL_CATEGORY_IDS: readonly ["frequent", "people", "nature", "foods", "activity", "places", "objects", "symbols", "flags"];
|
|
2
|
+
export type CanonicalCategoryId = (typeof CANONICAL_CATEGORY_IDS)[number];
|
|
3
|
+
export declare const CANONICAL_CATEGORY_LABELS: Record<CanonicalCategoryId, string>;
|
|
4
|
+
export declare const CANONICAL_CATEGORY_ICONS: Record<CanonicalCategoryId, string>;
|
|
5
|
+
export declare function isCanonicalCategoryId(id: string): id is CanonicalCategoryId;
|
|
6
|
+
export declare function getCanonicalCategoryLabel(id: string): string | undefined;
|
|
7
|
+
export declare function getCanonicalCategoryIcon(id: string): string | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EmojiPickerEmoji } from '../../types';
|
|
2
|
+
interface EmojiButtonProps {
|
|
3
|
+
emoji: EmojiPickerEmoji;
|
|
4
|
+
skinTone: number;
|
|
5
|
+
emojiIndex: number;
|
|
6
|
+
focused: boolean;
|
|
7
|
+
id: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const EmojiButton: import("react").MemoExoticComponent<({ emoji, skinTone, emojiIndex, focused, id, }: EmojiButtonProps) => import("react").JSX.Element>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GetStylesApi, type MantineSize } from '@mantine/core';
|
|
2
|
+
import type { EmojiPickerLabels } from '../../types';
|
|
3
|
+
import type { EmojiPickerFactory } from './EmojiPicker';
|
|
4
|
+
export interface EmojiPickerContextValue {
|
|
5
|
+
getStyles: GetStylesApi<EmojiPickerFactory>;
|
|
6
|
+
labels: Required<EmojiPickerLabels>;
|
|
7
|
+
size: MantineSize | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare const EmojiPickerProvider: import("react").Context<EmojiPickerContextValue | null>, useEmojiPickerContext: () => EmojiPickerContextValue;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BoxProps, ElementProps, Factory, InputProps, MantineSize, ScrollAreaProps, StylesApiProps } from '@mantine/core';
|
|
2
|
+
import { EmojiPickerData, EmojiPickerEmoji, EmojiPickerLabels } from '../../types';
|
|
3
|
+
export type EmojiPickerStylesNames = 'root' | 'search' | 'searchInput' | 'categoryNav' | 'categoryNavButton' | 'content' | 'empty' | 'categoryLabel' | 'grid' | 'emoji' | 'preview' | 'previewEmoji' | 'previewName' | 'skinToneSelector' | 'skinToneDropdown' | 'skinToneButton';
|
|
4
|
+
export type EmojiPickerCssVariables = {
|
|
5
|
+
root: '--ep-columns' | '--ep-emoji-size' | '--ep-emoji-fz' | '--ep-preview-py' | '--ep-skin-tone-size' | '--ep-skin-tone-fz';
|
|
6
|
+
};
|
|
7
|
+
export interface EmojiPickerProps extends BoxProps, StylesApiProps<EmojiPickerFactory>, ElementProps<'div'> {
|
|
8
|
+
/** Emoji data object, use `emojiMartAdapter` or `emojibaseAdapter` to convert data */
|
|
9
|
+
data: EmojiPickerData;
|
|
10
|
+
/** Called when an emoji is selected */
|
|
11
|
+
onEmojiSelect?: (emoji: EmojiPickerEmoji) => void;
|
|
12
|
+
/** Number of emoji columns @default 9 */
|
|
13
|
+
columns?: number;
|
|
14
|
+
/** Custom emoji button size in px, overrides size-based value */
|
|
15
|
+
emojiSize?: number;
|
|
16
|
+
/** Determines whether the search input is displayed @default true */
|
|
17
|
+
withSearch?: boolean;
|
|
18
|
+
/** Determines whether the category navigation bar is displayed @default true */
|
|
19
|
+
withCategoryNav?: boolean;
|
|
20
|
+
/** Determines whether the emoji preview area is displayed @default true */
|
|
21
|
+
withPreview?: boolean;
|
|
22
|
+
/** Determines whether the skin tone selector is displayed @default true */
|
|
23
|
+
withSkinToneSelector?: boolean;
|
|
24
|
+
/** Controlled skin tone value (0–5) */
|
|
25
|
+
skinTone?: number;
|
|
26
|
+
/** Default skin tone value for uncontrolled state @default 0 */
|
|
27
|
+
defaultSkinTone?: number;
|
|
28
|
+
/** Called when skin tone changes */
|
|
29
|
+
onSkinToneChange?: (skinTone: number) => void;
|
|
30
|
+
/** Controlled search input value */
|
|
31
|
+
searchValue?: string;
|
|
32
|
+
/** Called when search value changes */
|
|
33
|
+
onSearchChange?: (value: string) => void;
|
|
34
|
+
/** Search input placeholder */
|
|
35
|
+
searchPlaceholder?: string;
|
|
36
|
+
/** Content displayed when search yields no results */
|
|
37
|
+
emptySearchContent?: React.ReactNode;
|
|
38
|
+
/** Determines whether unsupported emojis are filtered out @default false */
|
|
39
|
+
withUnsupportedDetection?: boolean;
|
|
40
|
+
/** Determines whether the search input is focused on mount @default false */
|
|
41
|
+
autoFocus?: boolean;
|
|
42
|
+
/** Props passed to the internal `ScrollArea` component */
|
|
43
|
+
scrollAreaProps?: ScrollAreaProps;
|
|
44
|
+
/** Override category labels by category id */
|
|
45
|
+
categoryLabels?: Record<string, string>;
|
|
46
|
+
/** Override UI labels (search placeholder, no results text, etc.) */
|
|
47
|
+
labels?: EmojiPickerLabels;
|
|
48
|
+
/** Controls size of all inner elements @default 'sm' */
|
|
49
|
+
size?: MantineSize;
|
|
50
|
+
/** Props passed to the search `Input` component */
|
|
51
|
+
searchInputProps?: InputProps;
|
|
52
|
+
}
|
|
53
|
+
export type EmojiPickerFactory = Factory<{
|
|
54
|
+
props: EmojiPickerProps;
|
|
55
|
+
ref: HTMLDivElement;
|
|
56
|
+
stylesNames: EmojiPickerStylesNames;
|
|
57
|
+
vars: EmojiPickerCssVariables;
|
|
58
|
+
}>;
|
|
59
|
+
export declare const EmojiPicker: import("@mantine/core").MantineComponent<{
|
|
60
|
+
props: EmojiPickerProps;
|
|
61
|
+
ref: HTMLDivElement;
|
|
62
|
+
stylesNames: EmojiPickerStylesNames;
|
|
63
|
+
vars: EmojiPickerCssVariables;
|
|
64
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface EmojiPickerNavCategory {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
interface EmojiPickerCategoryNavProps {
|
|
6
|
+
categories: EmojiPickerNavCategory[];
|
|
7
|
+
onCategoryClick: (categoryId: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const EmojiPickerCategoryNav: import("react").MemoExoticComponent<({ categories, onCategoryClick, }: EmojiPickerCategoryNavProps) => import("react").JSX.Element>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ScrollAreaProps } from '@mantine/core';
|
|
2
|
+
import type { FlattenedRowItem } from '../../types';
|
|
3
|
+
export type EmojiPickerScrollToItem = (itemIndex: number, align: 'auto' | 'start') => void;
|
|
4
|
+
interface EmojiPickerGridProps {
|
|
5
|
+
items: FlattenedRowItem[];
|
|
6
|
+
itemOffsets: number[];
|
|
7
|
+
columns: number;
|
|
8
|
+
skinTone: number;
|
|
9
|
+
focusedIndex: number;
|
|
10
|
+
focusedItemIndex: number;
|
|
11
|
+
idPrefix: string;
|
|
12
|
+
gridId: string;
|
|
13
|
+
onActiveDescendantChange: (id: string | undefined) => void;
|
|
14
|
+
emojiSize: number;
|
|
15
|
+
emptyContent: React.ReactNode;
|
|
16
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
17
|
+
onPointerIndex: (index: number) => void;
|
|
18
|
+
onEmojiClick: (index: number) => void;
|
|
19
|
+
scrollToItemRef: React.RefObject<EmojiPickerScrollToItem | null>;
|
|
20
|
+
scrollAreaProps?: ScrollAreaProps;
|
|
21
|
+
}
|
|
22
|
+
export declare function EmojiPickerGrid({ items, itemOffsets, columns, skinTone, focusedIndex, focusedItemIndex, idPrefix, gridId, onActiveDescendantChange, emojiSize, emptyContent, onKeyDown, onPointerIndex, onEmojiClick, scrollToItemRef, scrollAreaProps, }: EmojiPickerGridProps): import("react").JSX.Element;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EmojiPickerEmoji } from '../../types';
|
|
2
|
+
interface EmojiPickerPreviewProps {
|
|
3
|
+
emoji: EmojiPickerEmoji | null;
|
|
4
|
+
skinTone: number;
|
|
5
|
+
withPreview: boolean;
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function EmojiPickerPreview({ emoji, skinTone, withPreview, children, }: EmojiPickerPreviewProps): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { InputProps } from '@mantine/core';
|
|
2
|
+
interface EmojiPickerSearchProps {
|
|
3
|
+
query: string;
|
|
4
|
+
onQueryChange: (value: string) => void;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
autoFocus?: boolean;
|
|
7
|
+
inputRef?: React.Ref<HTMLInputElement>;
|
|
8
|
+
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
9
|
+
controls?: string;
|
|
10
|
+
activeDescendant?: string;
|
|
11
|
+
searchInputProps?: InputProps;
|
|
12
|
+
}
|
|
13
|
+
export declare function EmojiPickerSearch({ query, onQueryChange, placeholder, autoFocus, inputRef, onKeyDown, controls, activeDescendant, searchInputProps, }: EmojiPickerSearchProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BoxProps, ElementProps, Factory, InputVariant, PopoverProps, StylesApiProps, InputClearButtonProps, __BaseInputProps, __InputStylesNames } from '@mantine/core';
|
|
2
|
+
import { EmojiPickerProps } from '../EmojiPicker';
|
|
3
|
+
export type EmojiPickerInputStylesNames = 'dropdown' | 'inputEmoji' | 'inputEmojiName' | 'inputValue' | __InputStylesNames;
|
|
4
|
+
export type EmojiPickerInputCssVariables = {
|
|
5
|
+
root: never;
|
|
6
|
+
};
|
|
7
|
+
export interface EmojiPickerInputProps extends BoxProps, __BaseInputProps, StylesApiProps<EmojiPickerInputFactory>, ElementProps<'button', 'size' | 'onChange' | 'value' | 'defaultValue'> {
|
|
8
|
+
/** Controlled emoji id value */
|
|
9
|
+
value?: string | null;
|
|
10
|
+
/** Default emoji id value for uncontrolled state */
|
|
11
|
+
defaultValue?: string | null;
|
|
12
|
+
/** Called when value changes */
|
|
13
|
+
onChange?: (value: string | null) => void;
|
|
14
|
+
/** Input placeholder displayed when no emoji is selected */
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
/** Determines whether the clear button is displayed @default false */
|
|
17
|
+
clearable?: boolean;
|
|
18
|
+
/** Props passed down to the clear button */
|
|
19
|
+
clearButtonProps?: InputClearButtonProps;
|
|
20
|
+
/** Props passed to the `Popover` component, use `opened`, `defaultOpened` and `onOpenedChange` props to control opened state */
|
|
21
|
+
popoverProps?: Omit<PopoverProps, 'children' | 'opened' | 'defaultOpened' | 'onChange'>;
|
|
22
|
+
/** Controlled popover opened state */
|
|
23
|
+
opened?: boolean;
|
|
24
|
+
/** Default popover opened state for uncontrolled mode */
|
|
25
|
+
defaultOpened?: boolean;
|
|
26
|
+
/** Called when popover opened state changes */
|
|
27
|
+
onOpenedChange?: (opened: boolean) => void;
|
|
28
|
+
/** Determines whether the popover closes after emoji is selected @default true */
|
|
29
|
+
closeOnSelect?: boolean;
|
|
30
|
+
/** Emoji data object, use `emojiMartAdapter` or `emojibaseAdapter` to convert data */
|
|
31
|
+
data: EmojiPickerProps['data'];
|
|
32
|
+
/** Called when an emoji is selected */
|
|
33
|
+
onEmojiSelect?: EmojiPickerProps['onEmojiSelect'];
|
|
34
|
+
/** Props passed to the `EmojiPicker` component inside the dropdown */
|
|
35
|
+
pickerProps?: Omit<EmojiPickerProps, 'data' | 'onEmojiSelect'>;
|
|
36
|
+
/** Determines whether the input is in read-only mode */
|
|
37
|
+
readOnly?: boolean;
|
|
38
|
+
/** Determines whether the input is disabled */
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export type EmojiPickerInputFactory = Factory<{
|
|
42
|
+
props: EmojiPickerInputProps;
|
|
43
|
+
ref: HTMLButtonElement;
|
|
44
|
+
stylesNames: EmojiPickerInputStylesNames;
|
|
45
|
+
vars: EmojiPickerInputCssVariables;
|
|
46
|
+
variant: InputVariant;
|
|
47
|
+
}>;
|
|
48
|
+
export declare const EmojiPickerInput: import("@mantine/core").MantineComponent<{
|
|
49
|
+
props: EmojiPickerInputProps;
|
|
50
|
+
ref: HTMLButtonElement;
|
|
51
|
+
stylesNames: EmojiPickerInputStylesNames;
|
|
52
|
+
vars: EmojiPickerInputCssVariables;
|
|
53
|
+
variant: InputVariant;
|
|
54
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Factory, PopoverProps } from '@mantine/core';
|
|
2
|
+
import { EmojiPickerProps } from '../EmojiPicker';
|
|
3
|
+
export interface EmojiPickerPopoverProps extends EmojiPickerProps {
|
|
4
|
+
/** Props passed to the `Popover` component, use `opened`, `defaultOpened` and `onOpenedChange` props to control opened state */
|
|
5
|
+
popoverProps?: Omit<PopoverProps, 'children' | 'opened' | 'defaultOpened' | 'onChange'>;
|
|
6
|
+
/** Controlled popover opened state */
|
|
7
|
+
opened?: boolean;
|
|
8
|
+
/** Default popover opened state for uncontrolled mode */
|
|
9
|
+
defaultOpened?: boolean;
|
|
10
|
+
/** Called when popover opened state changes */
|
|
11
|
+
onOpenedChange?: (opened: boolean) => void;
|
|
12
|
+
/** Determines whether the popover closes after emoji is selected @default true */
|
|
13
|
+
closeOnSelect?: boolean;
|
|
14
|
+
/** Popover target element */
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export type EmojiPickerPopoverFactory = Factory<{
|
|
18
|
+
props: EmojiPickerPopoverProps;
|
|
19
|
+
ref: HTMLDivElement;
|
|
20
|
+
}>;
|
|
21
|
+
export declare const EmojiPickerPopover: import("@mantine/core").MantineComponent<{
|
|
22
|
+
props: EmojiPickerPopoverProps;
|
|
23
|
+
ref: HTMLDivElement;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EmojiPickerEmoji, FlattenedRowItem } from '../types';
|
|
2
|
+
interface UseEmojiGridNavigationInput {
|
|
3
|
+
items: FlattenedRowItem[];
|
|
4
|
+
resetKey: string;
|
|
5
|
+
skinTone: number;
|
|
6
|
+
onEmojiSelect: (emoji: EmojiPickerEmoji) => void;
|
|
7
|
+
scrollToItem?: (itemIndex: number) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function useEmojiGridNavigation({ items, resetKey, skinTone, onEmojiSelect, scrollToItem, }: UseEmojiGridNavigationInput): {
|
|
10
|
+
model: import("../utils").EmojiGridModel;
|
|
11
|
+
activeIndex: number;
|
|
12
|
+
activeEmoji: EmojiPickerEmoji | null;
|
|
13
|
+
keyboardActive: boolean;
|
|
14
|
+
handleKeyDown: (event: React.KeyboardEvent) => void;
|
|
15
|
+
setPointerIndex: (index: number) => void;
|
|
16
|
+
setAnchorIndex: (index: number) => void;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EmojiPickerData, EmojiPickerEmoji } from '../types';
|
|
2
|
+
interface UseEmojiSearchInput {
|
|
3
|
+
data: EmojiPickerData;
|
|
4
|
+
searchValue?: string;
|
|
5
|
+
onSearchChange?: (value: string) => void;
|
|
6
|
+
}
|
|
7
|
+
interface UseEmojiSearchResult {
|
|
8
|
+
query: string;
|
|
9
|
+
setQuery: (value: string) => void;
|
|
10
|
+
results: EmojiPickerEmoji[];
|
|
11
|
+
isSearching: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function useEmojiSearch({ data, searchValue, onSearchChange, }: UseEmojiSearchInput): UseEmojiSearchResult;
|
|
14
|
+
export {};
|
package/lib/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { EmojiPickerData, EmojiPickerEmoji, EmojiPickerCategory, EmojiPickerLabels, FlattenedRowItem, } from './types';
|
|
2
|
+
export { DEFAULT_LABELS } from './types';
|
|
3
|
+
export { CANONICAL_CATEGORY_IDS } from './categories';
|
|
4
|
+
export { searchEmojis, flattenEmojiData } from './utils';
|
|
5
|
+
export { isEmojiSupported, filterSupportedEmojis } from './utils';
|
|
6
|
+
export { emojiMartAdapter } from './adapters';
|
|
7
|
+
export { emojibaseAdapter } from './adapters';
|
|
8
|
+
export * from './components/EmojiPicker';
|
|
9
|
+
export * from './components/EmojiPickerPopover';
|
|
10
|
+
export * from './components/EmojiPickerInput';
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { EmojiPickerData, EmojiPickerEmoji, EmojiPickerCategory, EmojiPickerLabels, FlattenedRowItem, } from './types';
|
|
2
|
+
export { DEFAULT_LABELS } from './types';
|
|
3
|
+
export { CANONICAL_CATEGORY_IDS } from './categories';
|
|
4
|
+
export { searchEmojis, flattenEmojiData } from './utils';
|
|
5
|
+
export { isEmojiSupported, filterSupportedEmojis } from './utils';
|
|
6
|
+
export { emojiMartAdapter } from './adapters';
|
|
7
|
+
export { emojibaseAdapter } from './adapters';
|
|
8
|
+
export * from './components/EmojiPicker';
|
|
9
|
+
export * from './components/EmojiPickerPopover';
|
|
10
|
+
export * from './components/EmojiPickerInput';
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface EmojiPickerEmoji {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
keywords: string[];
|
|
5
|
+
emoji: string;
|
|
6
|
+
skins?: string[];
|
|
7
|
+
version?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface EmojiPickerCategory {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
emojis: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface EmojiPickerData {
|
|
15
|
+
categories: EmojiPickerCategory[];
|
|
16
|
+
emojis: Record<string, EmojiPickerEmoji>;
|
|
17
|
+
}
|
|
18
|
+
export interface EmojiPickerLabels {
|
|
19
|
+
search?: string;
|
|
20
|
+
skinTone?: string;
|
|
21
|
+
noResults?: string;
|
|
22
|
+
skinToneLight?: string;
|
|
23
|
+
skinToneMediumLight?: string;
|
|
24
|
+
skinToneMedium?: string;
|
|
25
|
+
skinToneMediumDark?: string;
|
|
26
|
+
skinToneDark?: string;
|
|
27
|
+
skinToneDefault?: string;
|
|
28
|
+
searchResults?: string;
|
|
29
|
+
preview?: string;
|
|
30
|
+
clearSearch?: string;
|
|
31
|
+
emojis?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const DEFAULT_LABELS: Required<EmojiPickerLabels>;
|
|
34
|
+
export type FlattenedRowItem = {
|
|
35
|
+
type: 'header';
|
|
36
|
+
categoryId: string;
|
|
37
|
+
label: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'row';
|
|
40
|
+
emojis: EmojiPickerEmoji[];
|
|
41
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EmojiPickerEmoji, FlattenedRowItem } from '../types';
|
|
2
|
+
export interface EmojiGridRow {
|
|
3
|
+
itemIndex: number;
|
|
4
|
+
start: number;
|
|
5
|
+
length: number;
|
|
6
|
+
}
|
|
7
|
+
export interface EmojiGridModel {
|
|
8
|
+
emojis: EmojiPickerEmoji[];
|
|
9
|
+
rows: EmojiGridRow[];
|
|
10
|
+
emojiRows: number[];
|
|
11
|
+
itemOffsets: number[];
|
|
12
|
+
}
|
|
13
|
+
export type EmojiGridDirection = 'left' | 'right' | 'up' | 'down';
|
|
14
|
+
export declare function createEmojiGridModel(items: FlattenedRowItem[]): EmojiGridModel;
|
|
15
|
+
export declare function getNextEmojiIndex(model: EmojiGridModel, index: number, direction: EmojiGridDirection): number;
|
|
16
|
+
export declare function getEmojiItemIndex(model: EmojiGridModel, index: number): number;
|
|
17
|
+
export declare function applySkinTone(emoji: EmojiPickerEmoji, skinTone: number): EmojiPickerEmoji;
|