235 lines
5.9 KiB
TypeScript
235 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
// import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
|
import {
|
|
type EmojiPickerListCategoryHeaderProps,
|
|
type EmojiPickerListEmojiProps,
|
|
type EmojiPickerListRowProps,
|
|
EmojiPicker as EmojiPickerPrimitive,
|
|
// type SkinTone,
|
|
// useActiveEmoji,
|
|
// useSkinTone,
|
|
} from "frimousse";
|
|
import { LoaderIcon, SearchIcon } from "lucide-react";
|
|
import type * as React from "react";
|
|
|
|
// import { Button } from "~/components/ui/button";
|
|
// import {
|
|
// Popover,
|
|
// PopoverContent,
|
|
// PopoverTrigger,
|
|
// } from "~/components/ui/popover";
|
|
import { cn } from "~/lib/utils";
|
|
|
|
// from https://ui-x.junwen-k.dev/docs/components/emoji-picker
|
|
|
|
function EmojiPicker({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof EmojiPickerPrimitive.Root>) {
|
|
return (
|
|
<EmojiPickerPrimitive.Root
|
|
className={cn(
|
|
"isolate flex h-full w-fit flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
|
className,
|
|
)}
|
|
data-slot="emoji-picker"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerSearch({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof EmojiPickerPrimitive.Search>) {
|
|
return (
|
|
<div
|
|
className={cn("flex h-10 items-center gap-2 border-b px-3", className)}
|
|
data-slot="emoji-picker-search-wrapper"
|
|
>
|
|
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
|
<EmojiPickerPrimitive.Search
|
|
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground focus:border-accent-foreground focus:ring-0 disabled:cursor-not-allowed disabled:opacity-50"
|
|
data-slot="emoji-picker-search"
|
|
{...props}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerRow({ children, ...props }: EmojiPickerListRowProps) {
|
|
return (
|
|
<div className="scroll-my-1 px-1" data-slot="emoji-picker-row" {...props}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerEmoji({
|
|
emoji,
|
|
className,
|
|
...props
|
|
}: EmojiPickerListEmojiProps) {
|
|
return (
|
|
<button
|
|
className={cn(
|
|
"flex size-7 items-center justify-center rounded-xs text-base data-[active]:bg-accent",
|
|
className,
|
|
)}
|
|
data-slot="emoji-picker-emoji"
|
|
{...props}
|
|
>
|
|
{emoji.emoji}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerCategoryHeader({
|
|
category,
|
|
...props
|
|
}: EmojiPickerListCategoryHeaderProps) {
|
|
return (
|
|
<div
|
|
className="bg-popover px-3 pt-3.5 pb-2 text-muted-foreground text-xs leading-none"
|
|
data-slot="emoji-picker-category-header"
|
|
{...props}
|
|
>
|
|
{category.label}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerContent({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof EmojiPickerPrimitive.Viewport>) {
|
|
return (
|
|
<EmojiPickerPrimitive.Viewport
|
|
className={cn("relative flex-1 outline-hidden", className)}
|
|
data-slot="emoji-picker-viewport"
|
|
{...props}
|
|
>
|
|
<EmojiPickerPrimitive.Loading
|
|
className="absolute inset-0 flex items-center justify-center text-muted-foreground"
|
|
data-slot="emoji-picker-loading"
|
|
>
|
|
<LoaderIcon className="size-4 animate-spin" />
|
|
</EmojiPickerPrimitive.Loading>
|
|
<EmojiPickerPrimitive.Empty
|
|
className="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm"
|
|
data-slot="emoji-picker-empty"
|
|
>
|
|
No emoji found.
|
|
</EmojiPickerPrimitive.Empty>
|
|
<EmojiPickerPrimitive.List
|
|
className="select-none pb-1"
|
|
components={{
|
|
CategoryHeader: EmojiPickerCategoryHeader,
|
|
Emoji: EmojiPickerEmoji,
|
|
Row: EmojiPickerRow,
|
|
}}
|
|
data-slot="emoji-picker-list"
|
|
/>
|
|
</EmojiPickerPrimitive.Viewport>
|
|
);
|
|
}
|
|
|
|
/*function EmojiPickerFooter({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"div">) {
|
|
return (
|
|
<div
|
|
data-slot="emoji-picker-footer"
|
|
className={cn(
|
|
"flex w-full max-w-(--frimousse-viewport-width) min-w-0 items-center justify-between gap-1 border-t p-2",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<EmojiPickerActiveEmojiPreview />
|
|
<EmojiPickerSkinToneSelector />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerActiveEmojiPreview({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"div">) {
|
|
const emoji = useActiveEmoji();
|
|
|
|
if (!emoji) {
|
|
return (
|
|
<div
|
|
className="text-muted-foreground ml-1.5 flex h-7 items-center truncate text-xs"
|
|
{...props}
|
|
>
|
|
Select an emoji…
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={cn("flex items-center gap-1", className)} {...props}>
|
|
<div className="flex items-center gap-1">
|
|
<div className="flex size-7 flex-none items-center justify-center text-lg">
|
|
{emoji.emoji}
|
|
</div>
|
|
<span className="text-secondary-foreground truncate text-xs">
|
|
{emoji.label}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmojiPickerSkinToneSelector() {
|
|
const [skinTone, setSkinTone, skinToneVariations] = useSkinTone();
|
|
|
|
return (
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="outline" size="icon" className="size-7">
|
|
{
|
|
skinToneVariations.find(
|
|
(variation) => variation.skinTone === skinTone,
|
|
)?.emoji
|
|
}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent
|
|
side="left"
|
|
align="center"
|
|
className="w-fit overflow-hidden p-0"
|
|
>
|
|
<ToggleGroupPrimitive.Root
|
|
type="single"
|
|
value={skinTone}
|
|
onValueChange={(value) => value && setSkinTone(value as SkinTone)}
|
|
aria-label="Select skin tone"
|
|
orientation="horizontal"
|
|
>
|
|
{skinToneVariations.map((variation) => (
|
|
<ToggleGroupPrimitive.Item
|
|
key={variation.skinTone}
|
|
aria-label={`${variation.skinTone} skin tone`}
|
|
value={variation.skinTone}
|
|
className="data-[state=on]:bg-accent data-[state=on]:text-accent-foreground hover:bg-muted focus-visible:ring-ring size-7"
|
|
>
|
|
{variation.emoji}
|
|
</ToggleGroupPrimitive.Item>
|
|
))}
|
|
</ToggleGroupPrimitive.Root>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
}
|
|
*/
|
|
export {
|
|
EmojiPicker,
|
|
EmojiPickerSearch,
|
|
EmojiPickerContent,
|
|
//EmojiPickerFooter,
|
|
};
|