fix: emoji picker
This commit is contained in:
+8
-8
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vocechat-web",
|
||||
"version": "0.7.3",
|
||||
"version": "0.7.4",
|
||||
"homepage": "https://voce.chat",
|
||||
"dependencies": {
|
||||
"@metamask/onboarding": "^1.0.1",
|
||||
@@ -75,7 +75,7 @@
|
||||
"slate-react": "0.102.0",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"style-loader": "^3.3.4",
|
||||
"tailwind-merge": "2.2.1",
|
||||
"tailwind-merge": "2.2.2",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"tippy.js": "^6.3.7",
|
||||
"typescript": "^5.4.2",
|
||||
@@ -116,15 +116,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
|
||||
"@types/masonry-layout": "^4.2.7",
|
||||
"@types/node": "^20.11.28",
|
||||
"@types/react": "18.2.66",
|
||||
"@types/node": "^20.11.29",
|
||||
"@types/react": "18.2.67",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@types/react-helmet": "^6.1.11",
|
||||
"@types/react-syntax-highlighter": "^15.5.11",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-named-asset-import": "^0.3.8",
|
||||
@@ -137,7 +137,7 @@
|
||||
"gh-pages": "^6.1.1",
|
||||
"md5-file": "^5.0.0",
|
||||
"patch-package": "^8.0.0",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss": "^8.4.36",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^3.2.5",
|
||||
|
||||
Generated
+381
-376
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,19 @@
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import {
|
||||
Emoji,
|
||||
EmojiSettings,
|
||||
GridRow,
|
||||
UseEmojiPickerType,
|
||||
} from '@udecode/plate-emoji';
|
||||
import { memo, useCallback } from "react";
|
||||
import { Emoji, EmojiSettings, GridRow, UseEmojiPickerType } from "@udecode/plate-emoji";
|
||||
|
||||
import { cn } from '@/utils';
|
||||
import { cn } from "@/utils";
|
||||
|
||||
export type EmojiPickerContentProps = Pick<
|
||||
UseEmojiPickerType,
|
||||
| 'i18n'
|
||||
| 'onMouseOver'
|
||||
| 'onSelectEmoji'
|
||||
| 'emojiLibrary'
|
||||
| 'isSearching'
|
||||
| 'searchResult'
|
||||
| 'visibleCategories'
|
||||
| 'refs'
|
||||
| 'settings'
|
||||
| "i18n"
|
||||
| "onMouseOver"
|
||||
| "onSelectEmoji"
|
||||
| "emojiLibrary"
|
||||
| "isSearching"
|
||||
| "searchResult"
|
||||
| "visibleCategories"
|
||||
| "refs"
|
||||
| "settings"
|
||||
>;
|
||||
|
||||
export type EmojiButtonProps = {
|
||||
@@ -30,36 +25,34 @@ export type EmojiButtonProps = {
|
||||
|
||||
export type RowOfButtonsProps = Pick<
|
||||
UseEmojiPickerType,
|
||||
'onMouseOver' | 'onSelectEmoji' | 'emojiLibrary'
|
||||
"onMouseOver" | "onSelectEmoji" | "emojiLibrary"
|
||||
> & {
|
||||
row: GridRow;
|
||||
};
|
||||
|
||||
const Button = memo(
|
||||
({ index, emoji, onSelect, onMouseOver }: EmojiButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={emoji.skins[0].native}
|
||||
tabIndex={-1}
|
||||
data-index={index}
|
||||
onClick={() => onSelect(emoji)}
|
||||
onMouseEnter={() => onMouseOver(emoji)}
|
||||
onMouseLeave={() => onMouseOver()}
|
||||
className="group relative flex h-[36px] w-[36px] cursor-pointer items-center justify-center border-none bg-transparent text-2xl leading-none"
|
||||
>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 rounded-full bg-[rgba(0,0,0,0.05)] opacity-0 group-hover:opacity-100"
|
||||
/>
|
||||
<span data-emoji-set="native" style={{ position: 'relative' }}>
|
||||
{emoji.skins[0].native}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
Button.displayName = 'Button';
|
||||
const Button = memo(({ index, emoji, onSelect, onMouseOver }: EmojiButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={emoji.skins[0].native}
|
||||
tabIndex={-1}
|
||||
data-index={index}
|
||||
onClick={() => onSelect(emoji)}
|
||||
onMouseEnter={() => onMouseOver(emoji)}
|
||||
onMouseLeave={() => onMouseOver()}
|
||||
className="group relative flex h-[36px] w-[36px] cursor-pointer items-center justify-center border-none bg-transparent text-2xl leading-none"
|
||||
>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 rounded-full bg-[rgba(0,0,0,0.05)] opacity-0 group-hover:opacity-100"
|
||||
/>
|
||||
<span data-emoji-set="native" style={{ position: "relative" }}>
|
||||
{emoji.skins[0].native}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
Button.displayName = "Button";
|
||||
|
||||
const RowOfButtons = memo(
|
||||
({ row, emojiLibrary, onSelectEmoji, onMouseOver }: RowOfButtonsProps) => (
|
||||
@@ -76,7 +69,7 @@ const RowOfButtons = memo(
|
||||
</div>
|
||||
)
|
||||
);
|
||||
RowOfButtons.displayName = 'RowOfButtons';
|
||||
RowOfButtons.displayName = "RowOfButtons";
|
||||
|
||||
export function EmojiPickerContent({
|
||||
i18n,
|
||||
@@ -87,15 +80,13 @@ export function EmojiPickerContent({
|
||||
searchResult,
|
||||
visibleCategories,
|
||||
refs,
|
||||
settings = EmojiSettings,
|
||||
settings = EmojiSettings
|
||||
}: EmojiPickerContentProps) {
|
||||
const getRowWidth = settings.perLine.value * settings.buttonSize.value;
|
||||
|
||||
const isCategoryVisible = useCallback(
|
||||
(categoryId: any) => {
|
||||
return visibleCategories.has(categoryId)
|
||||
? visibleCategories.get(categoryId)
|
||||
: false;
|
||||
return visibleCategories.has(categoryId) ? visibleCategories.get(categoryId) : false;
|
||||
},
|
||||
[visibleCategories]
|
||||
);
|
||||
@@ -145,7 +136,7 @@ export function EmojiPickerContent({
|
||||
isCategoryVisible,
|
||||
onSelectEmoji,
|
||||
onMouseOver,
|
||||
settings,
|
||||
settings
|
||||
]);
|
||||
|
||||
const SearchList = useCallback(() => {
|
||||
@@ -167,24 +158,17 @@ export function EmojiPickerContent({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}, [
|
||||
emojiLibrary,
|
||||
getRowWidth,
|
||||
i18n.searchResult,
|
||||
searchResult,
|
||||
onSelectEmoji,
|
||||
onMouseOver,
|
||||
]);
|
||||
}, [emojiLibrary, getRowWidth, i18n.searchResult, searchResult, onSelectEmoji, onMouseOver]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'h-full min-h-[50%] overflow-y-auto overflow-x-hidden px-3',
|
||||
'[&::-webkit-scrollbar]:w-4',
|
||||
'[&::-webkit-scrollbar-button]:hidden [&::-webkit-scrollbar-button]:h-0 [&::-webkit-scrollbar-button]:w-0',
|
||||
':hover:[&::-webkit-scrollbar-thumb]:bg-[#f3f4f6]',
|
||||
'[&::-webkit-scrollbar-thumb]:min-h-[65px] [&::-webkit-scrollbar-thumb]:rounded-2xl [&::-webkit-scrollbar-thumb]:border-4 [&::-webkit-scrollbar-thumb]:border-white',
|
||||
'[&::-webkit-scrollbar-track]:border-0'
|
||||
"h-full min-h-[50%] overflow-y-auto overflow-x-hidden px-3",
|
||||
"[&::-webkit-scrollbar]:w-4",
|
||||
"[&::-webkit-scrollbar-button]:hidden [&::-webkit-scrollbar-button]:h-0 [&::-webkit-scrollbar-button]:w-0",
|
||||
":hover:[&::-webkit-scrollbar-thumb]:bg-[#f3f4f6]",
|
||||
"[&::-webkit-scrollbar-thumb]:min-h-[65px] [&::-webkit-scrollbar-thumb]:rounded-2xl [&::-webkit-scrollbar-thumb]:border-4 [&::-webkit-scrollbar-thumb]:border-white",
|
||||
"[&::-webkit-scrollbar-track]:border-0"
|
||||
)}
|
||||
data-id="scroll"
|
||||
ref={refs.current.contentRoot}
|
||||
|
||||
+9
-13
@@ -1,26 +1,22 @@
|
||||
import React from 'react';
|
||||
import { UseEmojiPickerType } from '@udecode/plate-emoji';
|
||||
import IconSearch from '@/assets/icons/search.svg'
|
||||
import IconClose from '@/assets/icons/close.circle.svg'
|
||||
import { cn } from '@/utils';
|
||||
import React from "react";
|
||||
import { UseEmojiPickerType } from "@udecode/plate-emoji";
|
||||
import IconSearch from "@/assets/icons/search.svg";
|
||||
import IconClose from "@/assets/icons/close.circle.svg";
|
||||
import { cn } from "@/utils";
|
||||
|
||||
export type EmojiPickerSearchAndClearProps = Pick<
|
||||
UseEmojiPickerType,
|
||||
'i18n' | 'searchValue' | 'clearSearch'
|
||||
"i18n" | "searchValue" | "clearSearch"
|
||||
>;
|
||||
|
||||
export function EmojiPickerSearchAndClear({
|
||||
i18n,
|
||||
searchValue,
|
||||
clearSearch,
|
||||
clearSearch
|
||||
}: EmojiPickerSearchAndClearProps) {
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
className={cn(
|
||||
'absolute left-2 top-1/2 z-10 flex h-5 w-5 -translate-y-1/2'
|
||||
)}
|
||||
>
|
||||
<span className={cn("absolute left-2 top-1/2 z-10 flex h-5 w-5 -translate-y-1/2")}>
|
||||
<IconSearch className="w-full h-full" />
|
||||
</span>
|
||||
{searchValue && (
|
||||
@@ -29,7 +25,7 @@ export function EmojiPickerSearchAndClear({
|
||||
aria-label="Clear"
|
||||
type="button"
|
||||
className={cn(
|
||||
'absolute right-0 top-1/2 flex h-8 w-8 -translate-y-1/2 cursor-pointer border-none bg-transparent justify-center items-center'
|
||||
"absolute right-0 top-1/2 flex h-8 w-8 -translate-y-1/2 cursor-pointer border-none bg-transparent justify-center items-center"
|
||||
)}
|
||||
onClick={clearSearch}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import * as Popover from '@radix-ui/react-popover';
|
||||
import { ReactNode } from "react";
|
||||
import * as Popover from "@radix-ui/react-popover";
|
||||
|
||||
type EmojiPopupProps = {
|
||||
control: ReactNode;
|
||||
@@ -8,16 +8,10 @@ type EmojiPopupProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export function EmojiPopup({
|
||||
control,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
children,
|
||||
}: EmojiPopupProps) {
|
||||
export function EmojiPopup({ control, isOpen, setIsOpen, children }: EmojiPopupProps) {
|
||||
return (
|
||||
<Popover.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
<Popover.Trigger asChild>{control}</Popover.Trigger>
|
||||
|
||||
<Popover.Portal>
|
||||
<Popover.Content
|
||||
align="start"
|
||||
|
||||
@@ -4,40 +4,55 @@ import { EmojiPopup } from "./emoji-popup";
|
||||
|
||||
import { emojiCategoryIcons, emojiSearchIcons } from "./emoji-icons";
|
||||
import { EmojiPicker } from "./emoji-picker";
|
||||
import { Plate } from "@udecode/plate-common";
|
||||
|
||||
type EmojiDropdownMenuProps = {
|
||||
context?: "markdown" | "plate";
|
||||
options?: EmojiDropdownMenuOptions;
|
||||
} & {
|
||||
onSelectEmoji?: (emoji: Emoji) => void;
|
||||
};
|
||||
|
||||
export function EmojiInputPicker({ options, onSelectEmoji, ...props }: EmojiDropdownMenuProps) {
|
||||
const PickerWrapper = (props: EmojiDropdownMenuProps) => {
|
||||
const { options, onSelectEmoji, ...others } = props;
|
||||
const { isOpen, setIsOpen, emojiPickerState } = useEmojiDropdownMenuState(options);
|
||||
const handleClick = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
const rest = onSelectEmoji ? { onSelectEmoji } : {};
|
||||
return (
|
||||
<EmojiPopup
|
||||
control={
|
||||
<button className="relative h-6 w-6" onClick={handleClick} {...props}>
|
||||
<IconSmile className="w-full h-full" />
|
||||
</button>
|
||||
}
|
||||
isOpen={isOpen}
|
||||
setIsOpen={setIsOpen}
|
||||
>
|
||||
<EmojiPicker
|
||||
{...emojiPickerState}
|
||||
<Plate key={"just_for_emoji_picker"}>
|
||||
<EmojiPopup
|
||||
control={
|
||||
<button className="relative h-6 w-6" onClick={handleClick} {...others}>
|
||||
<IconSmile className="w-full h-full" />
|
||||
</button>
|
||||
}
|
||||
isOpen={isOpen}
|
||||
setIsOpen={setIsOpen}
|
||||
icons={{
|
||||
categories: emojiCategoryIcons,
|
||||
search: emojiSearchIcons
|
||||
}}
|
||||
settings={options?.settings}
|
||||
{...rest}
|
||||
/>
|
||||
</EmojiPopup>
|
||||
>
|
||||
<EmojiPicker
|
||||
{...emojiPickerState}
|
||||
isOpen={isOpen}
|
||||
setIsOpen={setIsOpen}
|
||||
icons={{
|
||||
categories: emojiCategoryIcons,
|
||||
search: emojiSearchIcons
|
||||
}}
|
||||
settings={options?.settings}
|
||||
{...rest}
|
||||
/>
|
||||
</EmojiPopup>
|
||||
</Plate>
|
||||
);
|
||||
};
|
||||
|
||||
export function EmojiInputPicker({ context, ...props }: EmojiDropdownMenuProps) {
|
||||
if (context === "markdown")
|
||||
return (
|
||||
<Plate key={"just_for_emoji_picker"}>
|
||||
<PickerWrapper {...props} />
|
||||
</Plate>
|
||||
);
|
||||
return <PickerWrapper {...props} />;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,11 @@ const Send: FC<IProps> = ({
|
||||
)}
|
||||
>
|
||||
{mode == Modes.markdown && (
|
||||
<EmojiInputPicker options={{ closeOnSelect: false }} onSelectEmoji={insertEmoji} />
|
||||
<EmojiInputPicker
|
||||
context="markdown"
|
||||
options={{ closeOnSelect: false }}
|
||||
onSelectEmoji={insertEmoji}
|
||||
/>
|
||||
)}
|
||||
{mode == Modes.text && (
|
||||
<MessageInput
|
||||
|
||||
Reference in New Issue
Block a user