Skip to content

Commit 1ce417e

Browse files
authored
Merge pull request #3606 from Lenghak/main
feat(emoji-picker): adjust ui emoji picker
2 parents b01d1d2 + e846590 commit 1ce417e

16 files changed

+104
-84
lines changed

apps/www/content/docs/components/changelog.mdx

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Use the [CLI](https://platejs.org/docs/components/cli) to install the latest ver
1111

1212
## October 2024 #15
1313

14+
### October 4 #15.2
15+
16+
- feat `emoji-picker`: adjust ui emoji picker
17+
1418
### October 1 #15.1
1519

1620
- New `block-selection.tsx` component for visual selection feedback

apps/www/src/registry/default/plate-ui/code-line-element.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import React from 'react';
44

55
import { withRef } from '@udecode/cn';
6+
67
import { PlateElement } from './plate-element';
78

89
export const CodeLineElement = withRef<typeof PlateElement>((props, ref) => (

apps/www/src/registry/default/plate-ui/emoji-icons.tsx

+7-15
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@ import {
66
AppleIcon,
77
ClockIcon,
88
CompassIcon,
9-
DeleteIcon,
109
FlagIcon,
1110
LeafIcon,
1211
LightbulbIcon,
1312
MusicIcon,
1413
SearchIcon,
1514
SmileIcon,
1615
StarIcon,
16+
XIcon,
1717
} from 'lucide-react';
1818

1919
export const emojiCategoryIcons: Record<
2020
EmojiCategoryList,
21-
{ outline: React.ReactElement; solid: React.ReactElement }
21+
{
22+
outline: React.ReactElement;
23+
solid: React.ReactElement; // Needed to add another solid variant - outline will be used for now
24+
}
2225
> = {
2326
activity: {
2427
outline: (
@@ -38,7 +41,6 @@ export const emojiCategoryIcons: Record<
3841
<path d="M21.9 10.6a10.1 10.1 0 0 0-11.3 11.3" />
3942
</svg>
4043
),
41-
// Needed to add another solid variant - outline will be used for now
4244
solid: (
4345
<svg
4446
className="size-full"
@@ -60,61 +62,51 @@ export const emojiCategoryIcons: Record<
6062

6163
custom: {
6264
outline: <StarIcon className="size-full" />,
63-
// Needed to add another solid variant - outline will be used for now
6465
solid: <StarIcon className="size-full" />,
6566
},
6667

6768
flags: {
6869
outline: <FlagIcon className="size-full" />,
69-
// Needed to add another solid variant - outline will be used for now
7070
solid: <FlagIcon className="size-full" />,
7171
},
7272

7373
foods: {
7474
outline: <AppleIcon className="size-full" />,
75-
// Needed to add another solid variant - outline will be used for now
7675
solid: <AppleIcon className="size-full" />,
7776
},
7877

7978
frequent: {
8079
outline: <ClockIcon className="size-full" />,
81-
// Needed to add another solid variant - outline will be used for now
8280
solid: <ClockIcon className="size-full" />,
8381
},
8482

8583
nature: {
8684
outline: <LeafIcon className="size-full" />,
87-
// Needed to add another solid variant - outline will be used for now
8885
solid: <LeafIcon className="size-full" />,
8986
},
9087

9188
objects: {
9289
outline: <LightbulbIcon className="size-full" />,
93-
// Needed to add another solid variant - outline will be used for now
9490
solid: <LightbulbIcon className="size-full" />,
9591
},
9692

9793
people: {
9894
outline: <SmileIcon className="size-full" />,
99-
// Needed to add another solid variant - outline will be used for now
10095
solid: <SmileIcon className="size-full" />,
10196
},
10297

10398
places: {
10499
outline: <CompassIcon className="size-full" />,
105-
// Needed to add another solid variant - outline will be used for now
106100
solid: <CompassIcon className="size-full" />,
107101
},
108102

109103
symbols: {
110104
outline: <MusicIcon className="size-full" />,
111-
// Needed to add another solid variant - outline will be used for now
112105
solid: <MusicIcon className="size-full" />,
113106
},
114107
};
115108

116109
export const emojiSearchIcons = {
117-
delete: <DeleteIcon className="size-4" />,
118-
119-
loupe: <SearchIcon className="size-4" />,
110+
delete: <XIcon className="size-4 text-current" />,
111+
loupe: <SearchIcon className="size-4 text-current" />,
120112
};

apps/www/src/registry/default/plate-ui/emoji-input-element.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { useMemo, useState } from 'react';
22

33
import { withRef } from '@udecode/cn';
4-
import { PlateElement } from './plate-element';
54
import { EmojiInlineIndexSearch, insertEmoji } from '@udecode/plate-emoji';
65

76
import { useDebounce } from '@/registry/default/hooks/use-debounce';
@@ -13,6 +12,7 @@ import {
1312
InlineComboboxInput,
1413
InlineComboboxItem,
1514
} from './inline-combobox';
15+
import { PlateElement } from './plate-element';
1616

1717
export const EmojiInputElement = withRef<typeof PlateElement>(
1818
({ className, ...props }, ref) => {

apps/www/src/registry/default/plate-ui/emoji-picker-content.tsx

+5-6
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export function EmojiPickerContent({
109109
style={{ width: getRowWidth }}
110110
data-id={categoryId}
111111
>
112-
<div className="sticky -top-px z-[1] bg-card/90 p-1 py-2 text-sm font-semibold backdrop-blur-sm">
112+
<div className="sticky -top-px z-[1] bg-popover/90 p-1 py-2 text-sm font-semibold backdrop-blur-sm">
113113
{i18n.categories[categoryId]}
114114
</div>
115115
<div
@@ -145,7 +145,7 @@ export function EmojiPickerContent({
145145
const SearchList = useCallback(() => {
146146
return (
147147
<div style={{ width: getRowWidth }} data-id="search">
148-
<div className="sticky -top-px z-[1] bg-card/90 p-1 py-2 font-semibold backdrop-blur-sm">
148+
<div className="sticky -top-px z-[1] bg-popover/90 p-1 py-2 text-sm font-semibold text-card-foreground backdrop-blur-sm">
149149
{i18n.searchResult}
150150
</div>
151151
<div className="relative flex flex-wrap">
@@ -174,12 +174,11 @@ export function EmojiPickerContent({
174174
<div
175175
ref={refs.current.contentRoot}
176176
className={cn(
177-
'h-full min-h-[50%] overflow-y-auto overflow-x-hidden px-3',
177+
'h-full min-h-[50%] overflow-y-auto overflow-x-hidden px-2',
178178
'[&::-webkit-scrollbar]:w-4',
179179
'[&::-webkit-scrollbar-button]:hidden [&::-webkit-scrollbar-button]:size-0',
180-
':hover:[&::-webkit-scrollbar-thumb]:bg-[#f3f4f6]',
181-
'[&::-webkit-scrollbar-thumb]:min-h-[65px] [&::-webkit-scrollbar-thumb]:rounded-2xl [&::-webkit-scrollbar-thumb]:border-4 [&::-webkit-scrollbar-thumb]:border-white',
182-
'[&::-webkit-scrollbar-track]:border-0'
180+
'[&::-webkit-scrollbar-thumb]:min-h-11 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-muted [&::-webkit-scrollbar-thumb]:hover:bg-muted-foreground/25',
181+
'[&::-webkit-scrollbar-thumb]:border-4 [&::-webkit-scrollbar-thumb]:border-solid [&::-webkit-scrollbar-thumb]:border-popover [&::-webkit-scrollbar-thumb]:bg-clip-padding'
183182
)}
184183
data-id="scroll"
185184
>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import { useMemo } from 'react';
22

33
import type { EmojiCategoryList } from '@udecode/plate-emoji';
44
import type {
@@ -9,6 +9,12 @@ import type {
99
import { cn } from '@udecode/cn';
1010

1111
import { Button } from './button';
12+
import {
13+
Tooltip,
14+
TooltipContent,
15+
TooltipProvider,
16+
TooltipTrigger,
17+
} from './tooltip';
1218

1319
export type EmojiPickerNavigationProps = {
1420
onClick: (id: EmojiCategoryList) => void;
@@ -41,44 +47,60 @@ export function EmojiPickerNavigation({
4147
icons,
4248
onClick,
4349
}: EmojiPickerNavigationProps) {
44-
const { position, width } = getBarProperty(emojiLibrary, focusedCategory);
50+
const { position, width } = useMemo(
51+
() => getBarProperty(emojiLibrary, focusedCategory),
52+
[emojiLibrary, focusedCategory]
53+
);
4554

4655
return (
47-
<nav
48-
id="emoji-nav"
49-
className="mb-2.5 border-0 border-b border-solid border-b-border p-3"
50-
>
51-
<div className="relative flex items-center">
52-
{emojiLibrary
53-
.getGrid()
54-
.sections()
55-
.map(({ id }) => (
56-
<Button
57-
key={id}
58-
size="icon"
59-
variant="ghost"
60-
className={cn(
61-
'size-6 grow fill-current text-muted-foreground hover:bg-transparent hover:text-foreground',
62-
id === focusedCategory &&
63-
'pointer-events-none fill-current text-primary'
64-
)}
65-
onClick={() => onClick(id)}
66-
title={i18n.categories[id]}
67-
aria-label={i18n.categories[id]}
68-
type="button"
69-
>
70-
<span className="size-5">{icons.categories[id].outline}</span>
71-
</Button>
72-
))}
73-
<div
74-
className="absolute -bottom-3 left-0 h-0.5 w-full rounded-t-lg bg-primary opacity-100 transition-transform duration-200"
75-
style={{
76-
transform: `translateX(${position}%)`,
77-
visibility: `${focusedCategory ? 'visible' : 'hidden'}`,
78-
width: `${width}%`,
79-
}}
80-
/>
81-
</div>
82-
</nav>
56+
<TooltipProvider delayDuration={500}>
57+
<nav
58+
id="emoji-nav"
59+
className="mb-2.5 border-0 border-b border-solid border-b-border p-1.5"
60+
>
61+
<div className="relative flex items-center justify-evenly">
62+
{emojiLibrary
63+
.getGrid()
64+
.sections()
65+
.map(({ id }) => (
66+
<Tooltip key={id}>
67+
<TooltipTrigger asChild>
68+
<Button
69+
size="sm"
70+
variant="ghost"
71+
className={cn(
72+
'h-fit rounded-full fill-current p-1.5 text-muted-foreground hover:bg-muted hover:text-muted-foreground',
73+
id === focusedCategory &&
74+
'pointer-events-none bg-accent fill-current text-accent-foreground'
75+
)}
76+
onClick={() => {
77+
onClick(id);
78+
}}
79+
aria-label={i18n.categories[id]}
80+
type="button"
81+
>
82+
<span className="size-5">
83+
{icons.categories[id].outline}
84+
</span>
85+
</Button>
86+
</TooltipTrigger>
87+
<TooltipContent side="bottom">
88+
{i18n.categories[id]}
89+
</TooltipContent>
90+
</Tooltip>
91+
))}
92+
<div
93+
className={cn(
94+
'absolute -bottom-1.5 left-0 h-0.5 w-full rounded-t-lg bg-accent opacity-100 transition-transform duration-200'
95+
)}
96+
style={{
97+
transform: `translateX(${position}%)`,
98+
visibility: `${focusedCategory ? 'visible' : 'hidden'}`,
99+
width: `${width}%`,
100+
}}
101+
/>
102+
</div>
103+
</nav>
104+
</TooltipProvider>
83105
);
84106
}

apps/www/src/registry/default/plate-ui/emoji-picker-preview.tsx

+9-9
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,35 @@ export type PickAnEmojiPreviewProps = NoEmojiPreviewProps;
1313

1414
function EmojiPreview({ emoji }: EmojiPreviewProps) {
1515
return (
16-
<div className="flex h-20 items-center border-t border-muted p-2">
16+
<div className="flex h-14 max-h-14 min-h-14 items-center border-t border-muted p-2">
1717
<div className="flex items-center justify-center text-2xl">
1818
{emoji?.skins[0].native}
1919
</div>
2020
<div className="overflow-hidden pl-2">
21-
<div className="truncate text-sm">{emoji?.name}</div>
22-
<div className="truncate text-xs">{`:${emoji?.id}:`}</div>
21+
<div className="truncate text-sm font-semibold">{emoji?.name}</div>
22+
<div className="truncate text-sm">{`:${emoji?.id}:`}</div>
2323
</div>
2424
</div>
2525
);
2626
}
2727

2828
function NoEmoji({ i18n }: NoEmojiPreviewProps) {
2929
return (
30-
<div className="flex h-20 items-center border-t border-muted p-2">
30+
<div className="flex h-14 max-h-14 min-h-14 items-center border-t border-muted p-2">
3131
<div className="flex items-center justify-center text-2xl">😢</div>
3232
<div className="overflow-hidden pl-2">
33-
<div className="truncate text-sm font-semibold text-primary">
33+
<div className="truncate text-sm font-bold">
3434
{i18n.searchNoResultsTitle}
3535
</div>
36-
<div className="truncate text-xs">{i18n.searchNoResultsSubtitle}</div>
36+
<div className="truncate text-sm">{i18n.searchNoResultsSubtitle}</div>
3737
</div>
3838
</div>
3939
);
4040
}
4141

4242
function PickAnEmoji({ i18n }: PickAnEmojiPreviewProps) {
4343
return (
44-
<div className="flex h-20 items-center border-t border-muted p-2">
44+
<div className="flex h-14 max-h-14 min-h-14 items-center border-t border-muted p-2">
4545
<div className="flex items-center justify-center text-2xl">☝️</div>
4646
<div className="overflow-hidden pl-2">
4747
<div className="truncate text-sm font-semibold">{i18n.pick}</div>
@@ -57,9 +57,9 @@ export function EmojiPickerPreview({
5757
isSearching = false,
5858
...props
5959
}: EmojiPickerPreviewProps) {
60-
const showPickEmoji = !emoji && !(isSearching && !hasFound);
60+
const showPickEmoji = !emoji && (!isSearching || hasFound);
6161
const showNoEmoji = isSearching && !hasFound;
62-
const showPreview = emoji;
62+
const showPreview = emoji && !showNoEmoji && !showNoEmoji;
6363

6464
return (
6565
<>

apps/www/src/registry/default/plate-ui/emoji-picker-search-and-clear.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { UseEmojiPickerType } from '@udecode/plate-emoji/react';
22

33
import { cn } from '@udecode/cn';
4-
import { DeleteIcon, SearchIcon } from 'lucide-react';
54

65
import { Button } from './button';
6+
import { emojiSearchIcons } from './emoji-icons';
77

88
export type EmojiPickerSearchAndClearProps = Pick<
99
UseEmojiPickerType,
@@ -16,27 +16,27 @@ export function EmojiPickerSearchAndClear({
1616
searchValue,
1717
}: EmojiPickerSearchAndClearProps) {
1818
return (
19-
<div className="flex items-center">
19+
<div className="flex items-center text-foreground">
2020
<div
2121
className={cn(
22-
'absolute left-3 top-1/2 z-10 flex size-5 -translate-y-1/2 items-center justify-center'
22+
'absolute left-2.5 top-1/2 z-10 flex size-5 -translate-y-1/2 items-center justify-center text-foreground'
2323
)}
2424
>
25-
<SearchIcon className="size-4" />
25+
{emojiSearchIcons.loupe}
2626
</div>
2727
{searchValue && (
2828
<Button
2929
size="icon"
3030
variant="ghost"
3131
className={cn(
32-
'absolute right-1 top-1/2 flex size-8 -translate-y-1/2 cursor-pointer items-center justify-center border-none bg-transparent'
32+
'absolute right-0.5 top-1/2 flex size-8 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full border-none bg-transparent text-popover-foreground hover:bg-transparent'
3333
)}
3434
onClick={clearSearch}
3535
title={i18n.clear}
3636
aria-label="Clear"
3737
type="button"
3838
>
39-
<DeleteIcon className="size-4" />
39+
{emojiSearchIcons.delete}
4040
</Button>
4141
)}
4242
</div>

apps/www/src/registry/default/plate-ui/emoji-picker-search-bar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function EmojiPickerSearchBar({
1616
<div className="flex items-center px-2">
1717
<div className="relative flex grow items-center">
1818
<input
19-
className="block w-full appearance-none rounded-full border-0 bg-accent px-10 py-2 text-sm outline-none placeholder:text-muted-foreground focus-visible:outline-none"
19+
className="block w-full appearance-none rounded-full border-0 bg-muted px-10 py-2 text-sm outline-none placeholder:text-muted-foreground focus-visible:outline-none"
2020
value={searchValue}
2121
onChange={(event) => setSearch(event.target.value)}
2222
placeholder={i18n.search}

apps/www/src/registry/default/plate-ui/emoji-picker.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function EmojiPicker({
3333
return (
3434
<div
3535
className={cn(
36-
'flex flex-col rounded-xl bg-card',
36+
'flex flex-col rounded-xl bg-popover text-popover-foreground',
3737
'h-[23rem] w-80 border shadow-md'
3838
)}
3939
>

0 commit comments

Comments
 (0)