@hokkiai/discord-emoji-selector 1.1.5 → 1.1.7

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/dist/index.js CHANGED
@@ -1,244 +1,263 @@
1
+ import {
2
+ render,
3
+ useSearchValue
4
+ } from "./chunk-DMO3WEXH.js";
5
+
1
6
  // src/index.tsx
2
- import { useRef as useRef2 } from "react";
7
+ import { lazy, Suspense, useCallback, useEffect as useEffect5, useMemo, useRef as useRef2 } from "react";
3
8
 
4
- // src/categoryDisplay.tsx
5
- import { ChevronDown } from "lucide-react";
6
- import { useEffect as useEffect2, useState as useState2 } from "react";
9
+ // src/searchbar.tsx
10
+ import { useEffect, useRef, useState } from "react";
7
11
 
8
- // src/render.tsx
9
- import tw from "@twemoji/api";
10
- function render(txt) {
11
- let twemojiparsed = tw.parse(txt).replaceAll("<img", '<img style="object-fit: cover;" loading="lazy"');
12
- if (txt.startsWith("<:") || txt.startsWith("<a:")) {
13
- const id = txt.split(":")[2].split(">")[0];
14
- const isAnimated = txt.startsWith("<a:");
15
- const url = `https://cdn.discordapp.com/emojis/${id}.${isAnimated ? "gif" : "webp"}`;
16
- twemojiparsed = `<img style="object-fit: cover;" src="${url}" loading="lazy" />`;
17
- }
18
- return twemojiparsed;
19
- }
12
+ // src/icons.tsx
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ var MagniferLinear = (props) => {
15
+ return /* @__PURE__ */ jsxs(
16
+ "svg",
17
+ {
18
+ "aria-hidden": "true",
19
+ fill: "none",
20
+ focusable: "false",
21
+ height: "1em",
22
+ role: "presentation",
23
+ viewBox: "0 0 24 24",
24
+ width: "1em",
25
+ ...props,
26
+ children: [
27
+ /* @__PURE__ */ jsx(
28
+ "circle",
29
+ {
30
+ cx: "11.5",
31
+ cy: "11.5",
32
+ r: "9.5",
33
+ stroke: "currentColor",
34
+ strokeWidth: "1.5"
35
+ }
36
+ ),
37
+ /* @__PURE__ */ jsx(
38
+ "path",
39
+ {
40
+ d: "M18.5 18.5L22 22",
41
+ stroke: "currentColor",
42
+ strokeWidth: "1.5",
43
+ strokeLinecap: "round"
44
+ }
45
+ )
46
+ ]
47
+ }
48
+ );
49
+ };
20
50
 
21
- // src/hooks.tsx
22
- import { useEffect, useState } from "react";
23
- function useSkin({ pickerId }) {
24
- const [skin, setSkin] = useState(0);
25
- useEffect(() => {
26
- let raf;
27
- const loop = () => {
28
- const newSkin = window["emojipicker-" + pickerId]?.skin;
29
- setSkin(newSkin || 0);
30
- raf = requestAnimationFrame(loop);
31
- };
32
- raf = requestAnimationFrame(loop);
33
- return () => {
34
- cancelAnimationFrame(raf);
35
- };
36
- }, [pickerId]);
37
- return skin;
38
- }
39
- function useSearchValue({ pickerId }) {
40
- const [searchValue, setSearchValue] = useState("");
51
+ // src/searchbar.tsx
52
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
53
+ function SearchBar({
54
+ searchPlaceholder,
55
+ id
56
+ }) {
57
+ const [isFocused, setIsFocused] = useState(false);
58
+ const inputRef = useRef(null);
59
+ const [inputPlaceholder, setInputPlaceholder] = useState(searchPlaceholder);
41
60
  useEffect(() => {
42
- let raf;
43
- const loop = () => {
44
- const newSearchValue = window["emojipicker-" + pickerId]?.searchValue || "";
45
- setSearchValue(newSearchValue);
46
- raf = requestAnimationFrame(loop);
61
+ window["emojipicker-" + id].changeSearchbarPlaceholder = (emoji) => {
62
+ setInputPlaceholder(emoji);
47
63
  };
48
- raf = requestAnimationFrame(loop);
49
- return () => {
50
- cancelAnimationFrame(raf);
64
+ window["emojipicker-" + id].setSearchValue = (value) => {
65
+ inputRef.current.value = value;
66
+ window["emojipicker-" + id].searchValue = value;
51
67
  };
52
- }, [pickerId]);
53
- return searchValue;
54
- }
55
-
56
- // src/categoryDisplay.tsx
57
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
58
- function Emoji({
59
- pickerId,
60
- emoji,
61
- onEmojiMouseEnter,
62
- onEmojiMouseLeave,
63
- onEmojiSelect,
64
- key
65
- }) {
66
- return /* @__PURE__ */ jsx(
68
+ }, []);
69
+ return /* @__PURE__ */ jsxs2(
67
70
  "div",
68
71
  {
69
- onMouseEnter: () => {
70
- window["emojipicker-" + pickerId].changeFooterEmoji(emoji);
71
- window["emojipicker-" + pickerId].changeSearchbarPlaceholder(
72
- emoji.name
73
- );
74
- onEmojiMouseEnter(emoji);
75
- },
76
- onMouseLeave: () => {
77
- onEmojiMouseLeave(emoji);
78
- },
79
- onClick: () => {
80
- onEmojiSelect(emoji);
81
- },
82
- className: "HOKKIEMOJIPICKER-emoji text-4xl p-1 cursor-pointer hover:bg-white/15 rounded-sm size-12.5 flex items-center justify-center overflow-hidden",
83
- dangerouslySetInnerHTML: {
84
- __html: render(emoji.char)
85
- }
72
+ "data-focused": isFocused ? "true" : "false",
73
+ className: "bg-[#121214] items-center w-full border-1 border-[#323337] p-2 px-3 flex rounded-md data-[focused=true]:border-[#3687E9]",
74
+ children: [
75
+ /* @__PURE__ */ jsx2(
76
+ "input",
77
+ {
78
+ ref: inputRef,
79
+ onChange: (e) => window["emojipicker-" + id].searchValue = e.target.value,
80
+ className: "!outline-0 text-lg w-full",
81
+ onFocus: () => setIsFocused(true),
82
+ onBlur: () => setIsFocused(false),
83
+ placeholder: inputPlaceholder
84
+ }
85
+ ),
86
+ /* @__PURE__ */ jsx2(MagniferLinear, { className: "size-5 opacity-50" })
87
+ ]
86
88
  }
87
89
  );
88
90
  }
89
- function SkinEmoji({
90
- pickerId,
91
- emoji,
92
- onEmojiSelect,
93
- onEmojiMouseEnter,
94
- onEmojiMouseLeave,
95
- key
91
+
92
+ // src/footer.tsx
93
+ import { useEffect as useEffect2, useState as useState2 } from "react";
94
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
95
+ function Footer({
96
+ id,
97
+ firstEmoji
98
+ }) {
99
+ const [footerEmoji, setFooterEmoji] = useState2(firstEmoji);
100
+ useEffect2(() => {
101
+ window["emojipicker-" + id].changeFooterEmoji = (emoji) => {
102
+ setFooterEmoji(emoji);
103
+ };
104
+ }, []);
105
+ return /* @__PURE__ */ jsxs3("div", { className: "HOKKIEMOJIPICKER-footer mt-auto flex gap-2 items-center border-t-1 px-4 py-3 border-[#363639] bg-[#070709]", children: [
106
+ /* @__PURE__ */ jsx3(
107
+ "div",
108
+ {
109
+ className: "*:size-9 *:min-w-9 *:max-w-9",
110
+ dangerouslySetInnerHTML: { __html: render(footerEmoji.char) }
111
+ }
112
+ ),
113
+ /* @__PURE__ */ jsx3("p", { className: "text-lg whitespace-nowrap overflow-hidden text-ellipsis font-gg font-semibold", children: (footerEmoji.name || "").split(" ").map((e) => `:${e || ""}:`).join(" ") })
114
+ ] });
115
+ }
116
+
117
+ // src/sidebarCategory.tsx
118
+ import { useEffect as useEffect3, useState as useState3 } from "react";
119
+ import { jsx as jsx4 } from "react/jsx-runtime";
120
+ function SidebarCategory({
121
+ categoryName,
122
+ picker,
123
+ icon,
124
+ id
96
125
  }) {
97
- const skin = useSkin({ pickerId });
98
- const grabEmoji = () => [1, 2, 3, 4, 5].includes(skin) ? emoji.tones.find((a) => a.tone.find((b) => b === skin) === skin)?.char : emoji.char;
99
- const fakeEmoji = {
100
- ...emoji,
101
- char: grabEmoji(),
102
- preRendered: true,
103
- tones: [
104
- {
105
- name: emoji.tones[0].name.replaceAll("1", "0"),
106
- tone: [0],
107
- char: emoji.char
108
- },
109
- ...emoji.tones
110
- ]
111
- };
112
- return /* @__PURE__ */ jsx(
113
- "div",
126
+ const searchValue = useSearchValue({ pickerId: id });
127
+ const [isActive, setIsActive] = useState3(false);
128
+ useEffect3(() => {
129
+ if ((searchValue || "").length > 0) {
130
+ setIsActive(false);
131
+ return;
132
+ }
133
+ const elem = picker.current;
134
+ const updateActive = () => {
135
+ if (!elem) return;
136
+ const header = elem.querySelector(
137
+ ".HOKKIEMOJIPICKER-categoryHeader." + categoryName
138
+ );
139
+ if (!header) return;
140
+ const categoryContainer = header.parentElement;
141
+ const scrollElem = elem.querySelector(
142
+ ".HOKKIEMOJIPICKER-emojidisplay"
143
+ );
144
+ if (!scrollElem) return;
145
+ const containerRect = scrollElem.getBoundingClientRect();
146
+ const categoryRect = categoryContainer.getBoundingClientRect();
147
+ const headerHeight = header.offsetHeight;
148
+ const categoryTop = categoryRect.top - containerRect.top + scrollElem.scrollTop;
149
+ const categoryBottom = categoryTop + categoryContainer.offsetHeight;
150
+ const sTop = scrollElem.scrollTop;
151
+ const inView = sTop >= categoryTop - headerHeight && sTop < categoryBottom - headerHeight;
152
+ setIsActive(inView);
153
+ };
154
+ elem.querySelector(".HOKKIEMOJIPICKER-emojidisplay").addEventListener("scroll", updateActive);
155
+ updateActive();
156
+ return () => {
157
+ elem.querySelector(".HOKKIEMOJIPICKER-emojidisplay").removeEventListener("scroll", updateActive);
158
+ };
159
+ }, [picker, searchValue]);
160
+ return /* @__PURE__ */ jsx4(
161
+ "button",
114
162
  {
115
- onMouseEnter: () => {
116
- window["emojipicker-" + pickerId].changeFooterEmoji(fakeEmoji);
117
- window["emojipicker-" + pickerId].changeSearchbarPlaceholder(
118
- emoji.name
119
- );
120
- onEmojiMouseEnter(fakeEmoji);
121
- },
122
- onMouseLeave: () => {
123
- onEmojiMouseLeave(fakeEmoji);
124
- },
125
163
  onClick: () => {
126
- onEmojiSelect(fakeEmoji);
164
+ const elem = picker.current;
165
+ if (!elem) return;
166
+ const doScroll = () => {
167
+ const header = elem.querySelector(
168
+ ".HOKKIEMOJIPICKER-categoryHeader." + categoryName
169
+ );
170
+ if (!header) return;
171
+ const categoryContainer = header.parentElement;
172
+ const scrollElem = elem.querySelector(
173
+ ".HOKKIEMOJIPICKER-emojidisplay"
174
+ );
175
+ if (!scrollElem) return;
176
+ const containerRect = scrollElem.getBoundingClientRect();
177
+ const categoryRect = categoryContainer.getBoundingClientRect();
178
+ const headerHeight = header.offsetHeight;
179
+ const targetTop = categoryRect.top - containerRect.top + scrollElem.scrollTop - headerHeight;
180
+ scrollElem.scrollTo({
181
+ top: Math.max(0, targetTop),
182
+ behavior: "smooth"
183
+ });
184
+ };
185
+ if ((searchValue || "").length > 0) {
186
+ window["emojipicker-" + id].setSearchValue("");
187
+ setTimeout(doScroll, 50);
188
+ } else {
189
+ doScroll();
190
+ }
127
191
  },
128
- className: "HOKKIEMOJIPICKER-skinemoji text-4xl p-1 cursor-pointer hover:bg-white/15 rounded-sm size-12.5 flex items-center justify-center overflow-hidden",
129
- dangerouslySetInnerHTML: {
130
- __html: render(fakeEmoji.char)
131
- }
192
+ "data-active": isActive ? "true" : "false",
193
+ className: "!outline-0 HOKKIEMOJIPICKER-sidebarButton cursor-pointer size-8 data-[active=true]:bg-white/5 hover:bg-white/10 overflow-hidden *:!size-6.5 transition-all hover:*:!opacity-85 data-[active=true]:*:!opacity-100 flex items-center justify-center rounded-sm *:opacity-50",
194
+ children: icon
132
195
  }
133
196
  );
134
197
  }
135
- function CategoryDisplay({
136
- category,
137
- categoryInfo,
138
- isToneSelectorEnabled,
139
- onEmojiSelect,
140
- onEmojiMouseEnter,
141
- onEmojiMouseLeave,
142
- pickerId
143
- }) {
144
- const [isOpen, setIsOpen] = useState2(true);
145
- const searchValue = useSearchValue({ pickerId });
146
- useEffect2(() => {
147
- setIsOpen(
148
- (localStorage.getItem(
149
- "hokkiemojipicker-category-" + category.name + "-open"
150
- ) || "true") === "true"
198
+
199
+ // src/skinselector.tsx
200
+ import { useEffect as useEffect4, useState as useState4 } from "react";
201
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
202
+ function SkinSelector({ id }) {
203
+ const skins = ["\u{1F44F}", "\u{1F44F}\u{1F3FB}", "\u{1F44F}\u{1F3FC}", "\u{1F44F}\u{1F3FD}", "\u{1F44F}\u{1F3FE}", "\u{1F44F}\u{1F3FF}"];
204
+ const [selectedTone, setSelectedTone] = useState4(0);
205
+ const [open, setOpen] = useState4(false);
206
+ useEffect4(() => {
207
+ setSelectedTone(
208
+ parseInt(localStorage.getItem("hokkiemojipicker-skin") || "0")
151
209
  );
152
210
  }, []);
153
- if ((searchValue || "").length > 0) {
154
- if (category.name === "recentlyUsed")
155
- return /* @__PURE__ */ jsx("div", { className: "h-1.5 w-full " });
156
- return /* @__PURE__ */ jsx(Fragment, { children: category.emojis.map((emoji) => {
157
- if (!emoji.name.toLowerCase().replace(/_/g, " ").includes(searchValue.toLowerCase().replace(/_/g, " ")))
158
- return /* @__PURE__ */ jsx(Fragment, {});
159
- if (emoji.hasTone && !emoji.preRendered) {
160
- return /* @__PURE__ */ jsx(
161
- SkinEmoji,
162
- {
163
- onEmojiSelect,
164
- pickerId,
165
- onEmojiMouseEnter,
166
- onEmojiMouseLeave,
167
- emoji
168
- },
169
- emoji.name
170
- );
171
- }
172
- return /* @__PURE__ */ jsx(
173
- Emoji,
174
- {
175
- onEmojiSelect,
176
- pickerId,
177
- emoji,
178
- onEmojiMouseEnter,
179
- onEmojiMouseLeave
180
- },
181
- emoji.name
182
- );
183
- }) });
184
- }
185
- return /* @__PURE__ */ jsxs("div", { className: "HOKKIEMOJIPICKER-categorydisplay flex flex-col relative w-full pt-2", children: [
186
- /* @__PURE__ */ jsx(
211
+ useEffect4(() => {
212
+ window["emojipicker-" + id].skin = selectedTone;
213
+ }, [selectedTone]);
214
+ return /* @__PURE__ */ jsxs4("div", { className: "relative mr-1", children: [
215
+ /* @__PURE__ */ jsx5(
187
216
  "div",
188
217
  {
189
- className: "HOKKIEMOJIPICKER-categoryHeader sticky top-0 pt-2 cursor-pointer text-white px-2 flex bg-[#131416] p-1 pb-2 " + category.name,
218
+ className: "HOKKIEMOJIPICKER-skinselector-trigger opacity-75 hover:opacity-100 cursor-pointer *:size-7 *:min-w-7",
190
219
  onClick: () => {
191
- const newOpen = !isOpen;
192
- setIsOpen(newOpen);
193
- localStorage.setItem(
194
- "hokkiemojipicker-category-" + category.name + "-open",
195
- newOpen ? "true" : "false"
196
- );
220
+ setOpen(!open);
197
221
  },
198
- children: /* @__PURE__ */ jsxs("span", { className: "flex gap-1.5 items-center opacity-75 hover:opacity-100", children: [
199
- /* @__PURE__ */ jsx("span", { className: "*:size-4.5", children: categoryInfo.icon }),
200
- " ",
201
- /* @__PURE__ */ jsx("span", { className: "text-md font-semibold font-gg", children: categoryInfo.name }),
202
- /* @__PURE__ */ jsx(
203
- ChevronDown,
204
- {
205
- strokeWidth: 2,
206
- className: "transition-all size-5 data-[open=false]:-rotate-90",
207
- "data-open": isOpen ? "true" : "false"
208
- }
209
- )
210
- ] })
222
+ dangerouslySetInnerHTML: { __html: render(skins[selectedTone]) }
211
223
  }
212
224
  ),
213
- isOpen && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-y-0.5", children: category.emojis.map((emoji) => {
214
- if (emoji.hasTone && !emoji.preRendered && isToneSelectorEnabled) {
215
- return /* @__PURE__ */ jsx(
216
- SkinEmoji,
217
- {
218
- onEmojiSelect,
219
- pickerId,
220
- emoji,
221
- onEmojiMouseEnter,
222
- onEmojiMouseLeave
223
- },
224
- emoji.name
225
- );
226
- }
227
- return /* @__PURE__ */ jsx(
228
- Emoji,
229
- {
230
- onEmojiSelect,
231
- pickerId,
232
- onEmojiMouseEnter,
233
- onEmojiMouseLeave,
234
- emoji
225
+ /* @__PURE__ */ jsx5(
226
+ "div",
227
+ {
228
+ style: {
229
+ opacity: open ? 1 : 0,
230
+ pointerEvents: open ? "all" : "none"
235
231
  },
236
- emoji.name
237
- );
238
- }) })
232
+ className: "absolute flex transition-all flex-col cursor-pointer top-full translate-y-2 overflow-hidden -left-2 rounded-sm border-1 bg-neutral-900",
233
+ children: skins.filter((a) => a !== skins[selectedTone]).map((skin, i) => {
234
+ return /* @__PURE__ */ jsx5(
235
+ "div",
236
+ {
237
+ className: "HOKKIEMOJIPICKER-skinselector-skinoption *:size-7 *:min-w-7 hover:bg-white/5 p-2 transition-all",
238
+ onClick: () => {
239
+ setOpen(!open);
240
+ setSelectedTone(i);
241
+ localStorage.setItem("hokkiemojipicker-skin", i + "");
242
+ },
243
+ dangerouslySetInnerHTML: {
244
+ __html: render(skin)
245
+ }
246
+ }
247
+ );
248
+ })
249
+ }
250
+ )
239
251
  ] });
240
252
  }
241
253
 
254
+ // src/cn.ts
255
+ import { clsx } from "clsx";
256
+ import { twMerge } from "tailwind-merge";
257
+ var cn = (...inputs) => {
258
+ return twMerge(clsx(inputs));
259
+ };
260
+
242
261
  // src/emojilib.json
243
262
  var emojilib_default = [
244
263
  {
@@ -16969,257 +16988,9 @@ var emojilib_default = [
16969
16988
  }
16970
16989
  ];
16971
16990
 
16972
- // src/searchbar.tsx
16973
- import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
16974
-
16975
- // src/icons.tsx
16976
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
16977
- var MagniferLinear = (props) => {
16978
- return /* @__PURE__ */ jsxs2(
16979
- "svg",
16980
- {
16981
- "aria-hidden": "true",
16982
- fill: "none",
16983
- focusable: "false",
16984
- height: "1em",
16985
- role: "presentation",
16986
- viewBox: "0 0 24 24",
16987
- width: "1em",
16988
- ...props,
16989
- children: [
16990
- /* @__PURE__ */ jsx2(
16991
- "circle",
16992
- {
16993
- cx: "11.5",
16994
- cy: "11.5",
16995
- r: "9.5",
16996
- stroke: "currentColor",
16997
- strokeWidth: "1.5"
16998
- }
16999
- ),
17000
- /* @__PURE__ */ jsx2(
17001
- "path",
17002
- {
17003
- d: "M18.5 18.5L22 22",
17004
- stroke: "currentColor",
17005
- strokeWidth: "1.5",
17006
- strokeLinecap: "round"
17007
- }
17008
- )
17009
- ]
17010
- }
17011
- );
17012
- };
17013
-
17014
- // src/searchbar.tsx
17015
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
17016
- function SearchBar({
17017
- searchPlaceholder,
17018
- id
17019
- }) {
17020
- const [isFocused, setIsFocused] = useState3(false);
17021
- const inputRef = useRef(null);
17022
- const [inputPlaceholder, setInputPlaceholder] = useState3(searchPlaceholder);
17023
- useEffect3(() => {
17024
- window["emojipicker-" + id].changeSearchbarPlaceholder = (emoji) => {
17025
- setInputPlaceholder(emoji);
17026
- };
17027
- window["emojipicker-" + id].setSearchValue = (value) => {
17028
- inputRef.current.value = value;
17029
- window["emojipicker-" + id].searchValue = value;
17030
- };
17031
- }, []);
17032
- return /* @__PURE__ */ jsxs3(
17033
- "div",
17034
- {
17035
- "data-focused": isFocused ? "true" : "false",
17036
- className: "bg-[#121214] items-center w-full border-1 border-[#323337] p-2 px-3 flex rounded-md data-[focused=true]:border-[#3687E9]",
17037
- children: [
17038
- /* @__PURE__ */ jsx3(
17039
- "input",
17040
- {
17041
- ref: inputRef,
17042
- onChange: (e) => window["emojipicker-" + id].searchValue = e.target.value,
17043
- className: "!outline-0 text-lg w-full",
17044
- onFocus: () => setIsFocused(true),
17045
- onBlur: () => setIsFocused(false),
17046
- placeholder: inputPlaceholder
17047
- }
17048
- ),
17049
- /* @__PURE__ */ jsx3(MagniferLinear, { className: "size-5 opacity-50" })
17050
- ]
17051
- }
17052
- );
17053
- }
17054
-
17055
- // src/footer.tsx
17056
- import { useEffect as useEffect4, useState as useState4 } from "react";
17057
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
17058
- function Footer({
17059
- id,
17060
- firstEmoji
17061
- }) {
17062
- const [footerEmoji, setFooterEmoji] = useState4(firstEmoji);
17063
- useEffect4(() => {
17064
- window["emojipicker-" + id].changeFooterEmoji = (emoji) => {
17065
- setFooterEmoji(emoji);
17066
- };
17067
- }, []);
17068
- return /* @__PURE__ */ jsxs4("div", { className: "HOKKIEMOJIPICKER-footer mt-auto flex gap-2 items-center border-t-1 px-4 py-3 border-[#363639] bg-[#070709]", children: [
17069
- /* @__PURE__ */ jsx4(
17070
- "div",
17071
- {
17072
- className: "*:size-9 *:min-w-9 *:max-w-9",
17073
- dangerouslySetInnerHTML: { __html: render(footerEmoji.char) }
17074
- }
17075
- ),
17076
- /* @__PURE__ */ jsx4("p", { className: "text-lg whitespace-nowrap overflow-hidden text-ellipsis font-gg font-semibold", children: (footerEmoji.name || "").split(" ").map((e) => `:${e || ""}:`).join(" ") })
17077
- ] });
17078
- }
17079
-
17080
- // src/sidebarCategory.tsx
17081
- import { useEffect as useEffect5, useState as useState5 } from "react";
17082
- import { jsx as jsx5 } from "react/jsx-runtime";
17083
- function SidebarCategory({
17084
- categoryName,
17085
- picker,
17086
- icon,
17087
- id
17088
- }) {
17089
- const searchValue = useSearchValue({ pickerId: id });
17090
- const [isActive, setIsActive] = useState5(false);
17091
- useEffect5(() => {
17092
- if ((searchValue || "").length > 0) {
17093
- setIsActive(false);
17094
- return;
17095
- }
17096
- const elem = picker.current;
17097
- const updateActive = () => {
17098
- if (!elem) return;
17099
- const header = elem.querySelector(
17100
- ".HOKKIEMOJIPICKER-categoryHeader." + categoryName
17101
- );
17102
- if (!header) return;
17103
- const categoryContainer = header.parentElement;
17104
- const scrollElem = elem.querySelector(
17105
- ".HOKKIEMOJIPICKER-emojidisplay"
17106
- );
17107
- if (!scrollElem) return;
17108
- const containerRect = scrollElem.getBoundingClientRect();
17109
- const categoryRect = categoryContainer.getBoundingClientRect();
17110
- const headerHeight = header.offsetHeight;
17111
- const categoryTop = categoryRect.top - containerRect.top + scrollElem.scrollTop;
17112
- const categoryBottom = categoryTop + categoryContainer.offsetHeight;
17113
- const sTop = scrollElem.scrollTop;
17114
- const inView = sTop >= categoryTop - headerHeight && sTop < categoryBottom - headerHeight;
17115
- setIsActive(inView);
17116
- };
17117
- elem.querySelector(".HOKKIEMOJIPICKER-emojidisplay").addEventListener("scroll", updateActive);
17118
- updateActive();
17119
- return () => {
17120
- elem.querySelector(".HOKKIEMOJIPICKER-emojidisplay").removeEventListener("scroll", updateActive);
17121
- };
17122
- }, [picker, searchValue]);
17123
- return /* @__PURE__ */ jsx5(
17124
- "button",
17125
- {
17126
- onClick: () => {
17127
- const elem = picker.current;
17128
- if (!elem) return;
17129
- const doScroll = () => {
17130
- const header = elem.querySelector(
17131
- ".HOKKIEMOJIPICKER-categoryHeader." + categoryName
17132
- );
17133
- if (!header) return;
17134
- const categoryContainer = header.parentElement;
17135
- const scrollElem = elem.querySelector(
17136
- ".HOKKIEMOJIPICKER-emojidisplay"
17137
- );
17138
- if (!scrollElem) return;
17139
- const containerRect = scrollElem.getBoundingClientRect();
17140
- const categoryRect = categoryContainer.getBoundingClientRect();
17141
- const headerHeight = header.offsetHeight;
17142
- const targetTop = categoryRect.top - containerRect.top + scrollElem.scrollTop - headerHeight;
17143
- scrollElem.scrollTo({ top: Math.max(0, targetTop), behavior: "smooth" });
17144
- };
17145
- if ((searchValue || "").length > 0) {
17146
- window["emojipicker-" + id].setSearchValue("");
17147
- setTimeout(doScroll, 50);
17148
- } else {
17149
- doScroll();
17150
- }
17151
- },
17152
- "data-active": isActive ? "true" : "false",
17153
- className: "!outline-0 HOKKIEMOJIPICKER-sidebarButton cursor-pointer size-8 data-[active=true]:bg-white/5 hover:bg-white/10 overflow-hidden *:!size-6.5 transition-all hover:*:!opacity-85 data-[active=true]:*:!opacity-100 flex items-center justify-center rounded-sm *:opacity-50",
17154
- children: icon
17155
- }
17156
- );
17157
- }
17158
-
17159
- // src/skinselector.tsx
17160
- import { useEffect as useEffect6, useState as useState6 } from "react";
17161
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
17162
- function SkinSelector({ id }) {
17163
- const skins = ["\u{1F44F}", "\u{1F44F}\u{1F3FB}", "\u{1F44F}\u{1F3FC}", "\u{1F44F}\u{1F3FD}", "\u{1F44F}\u{1F3FE}", "\u{1F44F}\u{1F3FF}"];
17164
- const [selectedTone, setSelectedTone] = useState6(0);
17165
- const [open, setOpen] = useState6(false);
17166
- useEffect6(() => {
17167
- setSelectedTone(
17168
- parseInt(localStorage.getItem("hokkiemojipicker-skin") || "0")
17169
- );
17170
- }, []);
17171
- useEffect6(() => {
17172
- window["emojipicker-" + id].skin = selectedTone;
17173
- }, [selectedTone]);
17174
- return /* @__PURE__ */ jsxs5("div", { className: "relative mr-1", children: [
17175
- /* @__PURE__ */ jsx6(
17176
- "div",
17177
- {
17178
- className: "HOKKIEMOJIPICKER-skinselector-trigger opacity-75 hover:opacity-100 cursor-pointer *:size-7 *:min-w-7",
17179
- onClick: () => {
17180
- setOpen(!open);
17181
- },
17182
- dangerouslySetInnerHTML: { __html: render(skins[selectedTone]) }
17183
- }
17184
- ),
17185
- /* @__PURE__ */ jsx6(
17186
- "div",
17187
- {
17188
- style: {
17189
- opacity: open ? 1 : 0,
17190
- pointerEvents: open ? "all" : "none"
17191
- },
17192
- className: "absolute flex transition-all flex-col cursor-pointer top-full translate-y-2 overflow-hidden -left-2 rounded-sm border-1 bg-neutral-900",
17193
- children: skins.filter((a) => a !== skins[selectedTone]).map((skin, i) => {
17194
- return /* @__PURE__ */ jsx6(
17195
- "div",
17196
- {
17197
- className: "HOKKIEMOJIPICKER-skinselector-skinoption *:size-7 *:min-w-7 hover:bg-white/5 p-2 transition-all",
17198
- onClick: () => {
17199
- setOpen(!open);
17200
- setSelectedTone(i);
17201
- localStorage.setItem("hokkiemojipicker-skin", i + "");
17202
- },
17203
- dangerouslySetInnerHTML: {
17204
- __html: render(skin)
17205
- }
17206
- }
17207
- );
17208
- })
17209
- }
17210
- )
17211
- ] });
17212
- }
17213
-
17214
- // src/cn.ts
17215
- import { clsx } from "clsx";
17216
- import { twMerge } from "tailwind-merge";
17217
- var cn = (...inputs) => {
17218
- return twMerge(clsx(inputs));
17219
- };
17220
-
17221
16991
  // src/index.tsx
17222
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
16992
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
16993
+ var CategoryDisplay = lazy(() => import("./categoryDisplay-BV7OPJVG.js"));
17223
16994
  function EmojiSelector({
17224
16995
  categories = {},
17225
16996
  customEmojis = {},
@@ -17238,15 +17009,18 @@ function EmojiSelector({
17238
17009
  height = 500,
17239
17010
  width = 520
17240
17011
  }) {
17241
- let recentlyUsed = JSON.parse(
17242
- (localStorage || { getItem: (a) => "[]" }).getItem(
17243
- "hokkiemojipicker-recentlyused"
17244
- ) || "[]"
17012
+ const recentlyUsed = useMemo(
17013
+ () => JSON.parse(
17014
+ (localStorage || { getItem: (a) => "[]" }).getItem(
17015
+ "hokkiemojipicker-recentlyused"
17016
+ ) || "[]"
17017
+ ),
17018
+ []
17245
17019
  );
17246
17020
  const categoryData = {
17247
17021
  recentlyUsed: recentlyUsed.length > 0 ? {
17248
17022
  name: "Recently Used",
17249
- icon: /* @__PURE__ */ jsx7(
17023
+ icon: /* @__PURE__ */ jsx6(
17250
17024
  "svg",
17251
17025
  {
17252
17026
  "aria-hidden": "true",
@@ -17256,7 +17030,7 @@ function EmojiSelector({
17256
17030
  height: "24",
17257
17031
  fill: "none",
17258
17032
  viewBox: "0 0 24 24",
17259
- children: /* @__PURE__ */ jsx7(
17033
+ children: /* @__PURE__ */ jsx6(
17260
17034
  "path",
17261
17035
  {
17262
17036
  fill: "currentColor",
@@ -17270,7 +17044,7 @@ function EmojiSelector({
17270
17044
  } : false,
17271
17045
  customServerIcons: (customEmojis.emojis || []).length > 0 ? {
17272
17046
  name: customEmojis.serverName,
17273
- icon: /* @__PURE__ */ jsx7("div", { className: "relative rounded-full overflow-hidden", children: /* @__PURE__ */ jsx7(
17047
+ icon: /* @__PURE__ */ jsx6("div", { className: "relative rounded-full overflow-hidden", children: /* @__PURE__ */ jsx6(
17274
17048
  "img",
17275
17049
  {
17276
17050
  src: customEmojis.serverIconURL,
@@ -17281,7 +17055,7 @@ function EmojiSelector({
17281
17055
  separator: true,
17282
17056
  people: {
17283
17057
  name: "People",
17284
- icon: /* @__PURE__ */ jsx7(
17058
+ icon: /* @__PURE__ */ jsx6(
17285
17059
  "svg",
17286
17060
  {
17287
17061
  "aria-hidden": "true",
@@ -17291,7 +17065,7 @@ function EmojiSelector({
17291
17065
  height: "24",
17292
17066
  fill: "none",
17293
17067
  viewBox: "0 0 24 24",
17294
- children: /* @__PURE__ */ jsx7(
17068
+ children: /* @__PURE__ */ jsx6(
17295
17069
  "path",
17296
17070
  {
17297
17071
  fill: "currentColor",
@@ -17306,7 +17080,7 @@ function EmojiSelector({
17306
17080
  },
17307
17081
  nature: {
17308
17082
  name: "Nature",
17309
- icon: /* @__PURE__ */ jsx7(
17083
+ icon: /* @__PURE__ */ jsx6(
17310
17084
  "svg",
17311
17085
  {
17312
17086
  "aria-hidden": "true",
@@ -17316,7 +17090,7 @@ function EmojiSelector({
17316
17090
  height: "24",
17317
17091
  fill: "none",
17318
17092
  viewBox: "0 0 24 24",
17319
- children: /* @__PURE__ */ jsx7(
17093
+ children: /* @__PURE__ */ jsx6(
17320
17094
  "path",
17321
17095
  {
17322
17096
  fill: "currentColor",
@@ -17329,7 +17103,7 @@ function EmojiSelector({
17329
17103
  },
17330
17104
  food: {
17331
17105
  name: "Food",
17332
- icon: /* @__PURE__ */ jsx7(
17106
+ icon: /* @__PURE__ */ jsx6(
17333
17107
  "svg",
17334
17108
  {
17335
17109
  "aria-hidden": "true",
@@ -17339,7 +17113,7 @@ function EmojiSelector({
17339
17113
  height: "24",
17340
17114
  fill: "none",
17341
17115
  viewBox: "0 0 24 24",
17342
- children: /* @__PURE__ */ jsx7(
17116
+ children: /* @__PURE__ */ jsx6(
17343
17117
  "path",
17344
17118
  {
17345
17119
  fill: "currentColor",
@@ -17352,7 +17126,7 @@ function EmojiSelector({
17352
17126
  },
17353
17127
  activities: {
17354
17128
  name: "Activities",
17355
- icon: /* @__PURE__ */ jsx7(
17129
+ icon: /* @__PURE__ */ jsx6(
17356
17130
  "svg",
17357
17131
  {
17358
17132
  "aria-hidden": "true",
@@ -17362,7 +17136,7 @@ function EmojiSelector({
17362
17136
  height: "24",
17363
17137
  fill: "none",
17364
17138
  viewBox: "0 0 24 24",
17365
- children: /* @__PURE__ */ jsx7(
17139
+ children: /* @__PURE__ */ jsx6(
17366
17140
  "path",
17367
17141
  {
17368
17142
  fill: "currentColor",
@@ -17377,7 +17151,7 @@ function EmojiSelector({
17377
17151
  },
17378
17152
  travel: {
17379
17153
  name: "Travel",
17380
- icon: /* @__PURE__ */ jsx7(
17154
+ icon: /* @__PURE__ */ jsx6(
17381
17155
  "svg",
17382
17156
  {
17383
17157
  "aria-hidden": "true",
@@ -17387,7 +17161,7 @@ function EmojiSelector({
17387
17161
  height: "24",
17388
17162
  fill: "none",
17389
17163
  viewBox: "0 0 24 24",
17390
- children: /* @__PURE__ */ jsx7(
17164
+ children: /* @__PURE__ */ jsx6(
17391
17165
  "path",
17392
17166
  {
17393
17167
  fill: "currentColor",
@@ -17402,7 +17176,7 @@ function EmojiSelector({
17402
17176
  },
17403
17177
  objects: {
17404
17178
  name: "Objects",
17405
- icon: /* @__PURE__ */ jsxs6(
17179
+ icon: /* @__PURE__ */ jsxs5(
17406
17180
  "svg",
17407
17181
  {
17408
17182
  "aria-hidden": "true",
@@ -17413,14 +17187,14 @@ function EmojiSelector({
17413
17187
  fill: "none",
17414
17188
  viewBox: "0 0 24 24",
17415
17189
  children: [
17416
- /* @__PURE__ */ jsx7(
17190
+ /* @__PURE__ */ jsx6(
17417
17191
  "path",
17418
17192
  {
17419
17193
  fill: "currentColor",
17420
17194
  d: "M10.41 3.59 11.6 2.4a2 2 0 0 1 2.82 0l1.3 1.3a1 1 0 0 0 .7.29h4.18a1.41 1.41 0 0 1 1 2.41L14.4 13.6a1.41 1.41 0 0 1-2.41-1V8.4l-3.11 3.12a2 2 0 0 0-.53 1.87L9.9 20H15a1 1 0 1 1 0 2H3a1 1 0 1 1 0-2h4.86L6.4 13.86a4 4 0 0 1 1.06-3.75L10.8 6.8l-.38-.38a2 2 0 0 1 0-2.82Z"
17421
17195
  }
17422
17196
  ),
17423
- /* @__PURE__ */ jsx7(
17197
+ /* @__PURE__ */ jsx6(
17424
17198
  "path",
17425
17199
  {
17426
17200
  fill: "currentColor",
@@ -17434,7 +17208,7 @@ function EmojiSelector({
17434
17208
  },
17435
17209
  symbols: {
17436
17210
  name: "Symbols",
17437
- icon: /* @__PURE__ */ jsx7(
17211
+ icon: /* @__PURE__ */ jsx6(
17438
17212
  "svg",
17439
17213
  {
17440
17214
  "aria-hidden": "true",
@@ -17444,7 +17218,7 @@ function EmojiSelector({
17444
17218
  height: "24",
17445
17219
  fill: "none",
17446
17220
  viewBox: "0 0 24 24",
17447
- children: /* @__PURE__ */ jsx7(
17221
+ children: /* @__PURE__ */ jsx6(
17448
17222
  "path",
17449
17223
  {
17450
17224
  fill: "currentColor",
@@ -17457,7 +17231,7 @@ function EmojiSelector({
17457
17231
  },
17458
17232
  flags: {
17459
17233
  name: "Flags",
17460
- icon: /* @__PURE__ */ jsx7(
17234
+ icon: /* @__PURE__ */ jsx6(
17461
17235
  "svg",
17462
17236
  {
17463
17237
  "aria-hidden": "true",
@@ -17467,7 +17241,7 @@ function EmojiSelector({
17467
17241
  height: "24",
17468
17242
  fill: "none",
17469
17243
  viewBox: "0 0 24 24",
17470
- children: /* @__PURE__ */ jsx7(
17244
+ children: /* @__PURE__ */ jsx6(
17471
17245
  "path",
17472
17246
  {
17473
17247
  fill: "currentColor",
@@ -17479,23 +17253,40 @@ function EmojiSelector({
17479
17253
  ...categories.flags
17480
17254
  }
17481
17255
  };
17482
- const emojis = [
17483
- recentlyUsed.length > 0 ? {
17484
- name: "recentlyUsed",
17485
- emojis: recentlyUsed
17486
- } : void 0,
17487
- (customEmojis?.emojis || []).length > 0 ? {
17488
- name: "customServerIcons",
17489
- emojis: customEmojis.emojis.map((a) => {
17490
- return { name: a.split(":")[1].split(":")[0], char: a };
17491
- })
17492
- } : void 0,
17493
- ...emojilib_default
17494
- ].filter((a) => a !== void 0);
17256
+ const emojis = useMemo(() => {
17257
+ return [
17258
+ recentlyUsed.length > 0 ? {
17259
+ name: "recentlyUsed",
17260
+ emojis: recentlyUsed
17261
+ } : void 0,
17262
+ (customEmojis?.emojis || []).length > 0 ? {
17263
+ name: "customServerIcons",
17264
+ emojis: customEmojis.emojis.map((a) => {
17265
+ return { name: a.split(":")[1].split(":")[0], char: a };
17266
+ })
17267
+ } : void 0,
17268
+ ...emojilib_default
17269
+ ].filter((a) => a !== void 0);
17270
+ }, [recentlyUsed, customEmojis]);
17495
17271
  const navHeight = showNav ? Math.floor(height / 7) : 0;
17496
- const id = Math.random().toString(36).substring(2, 15);
17272
+ const id = useMemo(() => Math.random().toString(36).substring(2, 15), []);
17497
17273
  const picker = useRef2(null);
17498
- return /* @__PURE__ */ jsx7("div", { className: "HOKKIEMOJIPICKER-emojiContainer", children: /* @__PURE__ */ jsxs6(
17274
+ const scrollRef = useRef2(null);
17275
+ const handleWheel = useCallback((e) => {
17276
+ const el = scrollRef.current;
17277
+ if (!el) return;
17278
+ e.preventDefault();
17279
+ el.scrollTop += e.deltaY;
17280
+ }, []);
17281
+ useEffect5(() => {
17282
+ const el = scrollRef.current;
17283
+ if (!el) return;
17284
+ el.addEventListener("wheel", handleWheel, { passive: false });
17285
+ return () => {
17286
+ el.removeEventListener("wheel", handleWheel);
17287
+ };
17288
+ }, [handleWheel]);
17289
+ return /* @__PURE__ */ jsx6("div", { className: "HOKKIEMOJIPICKER-emojiContainer", children: /* @__PURE__ */ jsxs5(
17499
17290
  "div",
17500
17291
  {
17501
17292
  ref: picker,
@@ -17513,7 +17304,7 @@ function EmojiSelector({
17513
17304
  minWidth: width
17514
17305
  },
17515
17306
  children: [
17516
- showNav && /* @__PURE__ */ jsxs6(
17307
+ showNav && /* @__PURE__ */ jsxs5(
17517
17308
  "div",
17518
17309
  {
17519
17310
  className: "HOKKIEMOJIPICKER-nav border-[#363639] flex items-center gap-4 border-b-1 p-3 relative z-50",
@@ -17523,20 +17314,20 @@ function EmojiSelector({
17523
17314
  minHeight: navHeight
17524
17315
  },
17525
17316
  children: [
17526
- /* @__PURE__ */ jsx7(SearchBar, { id, searchPlaceholder }),
17527
- toneSelector && /* @__PURE__ */ jsx7(SkinSelector, { id })
17317
+ /* @__PURE__ */ jsx6(SearchBar, { id, searchPlaceholder }),
17318
+ toneSelector && /* @__PURE__ */ jsx6(SkinSelector, { id })
17528
17319
  ]
17529
17320
  }
17530
17321
  ),
17531
- /* @__PURE__ */ jsxs6("div", { className: "flex h-full", children: [
17532
- showSidebar && /* @__PURE__ */ jsxs6("div", { className: "HOKKIEMOJIPICKER-sidebar bg-[#070709] flex p-2 gap-1 flex-col", children: [
17322
+ /* @__PURE__ */ jsxs5("div", { className: "flex h-full", children: [
17323
+ showSidebar && /* @__PURE__ */ jsxs5("div", { className: "HOKKIEMOJIPICKER-sidebar bg-[#070709] flex p-2 gap-1 flex-col", children: [
17533
17324
  Object.keys(categoryData).filter((categoryName) => categoryData[categoryName] !== false).map((categoryName) => {
17534
17325
  const category = categoryData[categoryName];
17535
17326
  if (category === true) {
17536
- return /* @__PURE__ */ jsx7("div", { className: "w-full h-0 border-b-1 my-2" });
17327
+ return /* @__PURE__ */ jsx6("div", { className: "w-full h-0 border-b-1 my-2" });
17537
17328
  }
17538
17329
  const icon = category.icon;
17539
- return /* @__PURE__ */ jsx7(
17330
+ return /* @__PURE__ */ jsx6(
17540
17331
  SidebarCategory,
17541
17332
  {
17542
17333
  id,
@@ -17547,9 +17338,9 @@ function EmojiSelector({
17547
17338
  categoryName
17548
17339
  );
17549
17340
  }),
17550
- /* @__PURE__ */ jsx7("div", { className: "h-24" })
17341
+ /* @__PURE__ */ jsx6("div", { className: "h-24" })
17551
17342
  ] }),
17552
- /* @__PURE__ */ jsxs6(
17343
+ /* @__PURE__ */ jsxs5(
17553
17344
  "div",
17554
17345
  {
17555
17346
  style: {
@@ -17559,17 +17350,18 @@ function EmojiSelector({
17559
17350
  },
17560
17351
  className: "HOKKIEMOJIPICKER-emojidisplaycontainer overflow-hidden flex flex-col w-full",
17561
17352
  children: [
17562
- /* @__PURE__ */ jsx7(
17353
+ /* @__PURE__ */ jsx6(
17563
17354
  "div",
17564
17355
  {
17356
+ ref: scrollRef,
17565
17357
  style: {
17566
17358
  flexBasis: "fit-content"
17567
17359
  },
17568
17360
  className: "HOKKIEMOJIPICKER-emojidisplay overflow-y-scroll bg-[#131416] h-full w-full flex flex-wrap px-2 items-start justfy-start justify-self-start gap-y-0.5",
17569
- children: emojis.map((category) => {
17361
+ children: /* @__PURE__ */ jsx6(Suspense, { fallback: /* @__PURE__ */ jsx6("div", {}), children: emojis.map((category) => {
17570
17362
  if (!category) return;
17571
17363
  const categoryInfo = categoryData[category.name];
17572
- return /* @__PURE__ */ jsx7(
17364
+ return /* @__PURE__ */ jsx6(
17573
17365
  CategoryDisplay,
17574
17366
  {
17575
17367
  onEmojiMouseEnter,
@@ -17597,10 +17389,10 @@ function EmojiSelector({
17597
17389
  },
17598
17390
  category.name
17599
17391
  );
17600
- })
17392
+ }) })
17601
17393
  }
17602
17394
  ),
17603
- showFooter && /* @__PURE__ */ jsx7(Footer, { id, firstEmoji: emojis[0].emojis[0] })
17395
+ showFooter && /* @__PURE__ */ jsx6(Footer, { id, firstEmoji: emojis[0].emojis[0] })
17604
17396
  ]
17605
17397
  }
17606
17398
  )