frimousse
Version:
A lightweight, unstyled, and composable emoji picker for React.
518 lines (511 loc) • 15.9 kB
TypeScript
import * as react from 'react';
import { ComponentProps, ReactNode, ComponentType } from 'react';
import * as react_jsx_runtime from 'react/jsx-runtime';
type SkinToneKey = 'dark' | 'light' | 'medium-dark' | 'medium-light' | 'medium';
type Locale$1 = 'bn' | 'da' | 'de' | 'en-gb' | 'en' | 'es-mx' | 'es' | 'et' | 'fi' | 'fr' | 'hi' | 'hu' | 'it' | 'ja' | 'ko' | 'lt' | 'ms' | 'nb' | 'nl' | 'pl' | 'pt' | 'ru' | 'sv' | 'th' | 'uk' | 'vi' | 'zh-hant' | 'zh';
type Resolve<T> = T extends (...args: unknown[]) => unknown ? T : {
[K in keyof T]: T[K];
};
type Locale = Resolve<Locale$1>;
type SkinTone = Resolve<"none" | SkinToneKey>;
type SkinToneVariation = {
skinTone: SkinTone;
emoji: string;
};
type Emoji = Resolve<EmojiPickerEmoji>;
type Category = Resolve<EmojiPickerCategory>;
type EmojiPickerEmoji = {
emoji: string;
label: string;
};
type EmojiPickerCategory = {
label: string;
};
type EmojiPickerListComponents = {
/**
* The component used to render a sticky category header in the list.
*
* @details
* All category headers should be of the same size.
*/
CategoryHeader: ComponentType<EmojiPickerListCategoryHeaderProps>;
/**
* The component used to render a row of emojis in the list.
*
* @details
* All rows should be of the same size.
*/
Row: ComponentType<EmojiPickerListRowProps>;
/**
* The component used to render an emoji button in the list.
*
* @details
* All emojis should be of the same size.
*/
Emoji: ComponentType<EmojiPickerListEmojiProps>;
};
type EmojiPickerListRowProps = ComponentProps<"div">;
interface EmojiPickerListCategoryHeaderProps extends Omit<ComponentProps<"div">, "children"> {
/**
* The category for this sticky header.
*/
category: Category;
}
interface EmojiPickerListEmojiProps extends Omit<ComponentProps<"button">, "children"> {
/**
* The emoji for this button, its label, and whether the emoji is currently
* active (either hovered or selected via keyboard navigation).
*/
emoji: Resolve<Emoji & {
isActive: boolean;
}>;
}
interface EmojiPickerListProps extends ComponentProps<"div"> {
/**
* The inner components of the list.
*/
components?: Partial<EmojiPickerListComponents>;
}
interface EmojiPickerRootProps extends ComponentProps<"div"> {
/**
* A callback invoked when an emoji is selected.
*/
onEmojiSelect?: (emoji: Emoji) => void;
/**
* The locale of the emoji picker.
*
* @default "en"
*/
locale?: Locale;
/**
* The skin tone of the emoji picker.
*
* @default "none"
*/
skinTone?: SkinTone;
/**
* The number of columns in the list.
*
* @default 10
*/
columns?: number;
/**
* Which {@link https://emojipedia.org/emoji-versions | Emoji version} to use,
* to manually control which emojis are visible regardless of the current
* browser's supported Emoji versions.
*
* @default The most recent version supported by the current browser
*/
emojiVersion?: number;
/**
* The base URL of where the {@link https://emojibase.dev/docs/datasets/ | Emojibase data}
* should be fetched from, used as follows: `${emojibaseUrl}/${locale}/${file}.json`.
* (e.g. `${emojibaseUrl}/en/data.json`).
*
* The URL can be set to another CDN hosting the {@link https://www.npmjs.com/package/emojibase-data | `emojibase-data`}
* package and its raw JSON files, or to a self-hosted location. When self-hosting
* with a single locale (e.g. `en`), only that locale's directory needs to be hosted
* instead of the entire package.
*
* @example "https://unpkg.com/emojibase-data"
*
* @example "https://example.com/self-hosted-emojibase-data"
*
* @default "https://cdn.jsdelivr.net/npm/emojibase-data"
*/
emojibaseUrl?: string;
/**
* Whether the category headers should be sticky.
*
* @default true
*/
sticky?: boolean;
}
type EmojiPickerViewportProps = ComponentProps<"div">;
type EmojiPickerSearchProps = ComponentProps<"input">;
interface EmojiPickerSkinToneSelectorProps extends Omit<ComponentProps<"button">, "children"> {
/**
* The emoji to use as visual for the skin tone variations.
*
* @default "✋"
*/
emoji?: string;
}
type EmojiPickerLoadingProps = ComponentProps<"span">;
type EmojiPickerEmptyRenderProps = {
/**
* The current search value.
*/
search: string;
};
interface EmojiPickerEmptyProps extends Omit<ComponentProps<"span">, "children"> {
/**
* The content to render when no emoji is found for the current search, or
* a render callback which receives the current search value.
*/
children?: ReactNode | ((props: EmojiPickerEmptyRenderProps) => ReactNode);
}
type EmojiPickerActiveEmojiRenderProps = {
/**
* The currently active emoji (either hovered or selected
* via keyboard navigation).
*/
emoji?: Emoji;
};
type EmojiPickerActiveEmojiProps = {
/**
* A render callback which receives the currently active emoji (either hovered or selected
* via keyboard navigation).
*/
children: (props: EmojiPickerActiveEmojiRenderProps) => ReactNode;
};
type EmojiPickerSkinToneRenderProps = {
/**
* The current skin tone.
*/
skinTone: SkinTone;
/**
* A function to change the current skin tone.
*/
setSkinTone: (skinTone: SkinTone) => void;
/**
* The skin tone variations of the specified emoji.
*/
skinToneVariations: SkinToneVariation[];
};
type EmojiPickerSkinToneProps = {
/**
* The emoji to use as visual for the skin tone variations.
*
* @default "✋"
*/
emoji?: string;
/**
* A render callback which receives the current skin tone and a function
* to change it, as well as the skin tone variations of the specified emoji.
*/
children: (props: EmojiPickerSkinToneRenderProps) => ReactNode;
};
/**
* Surrounds all the emoji picker parts.
*
* @example
* ```tsx
* <EmojiPicker.Root onEmojiSelect={({ emoji }) => console.log(emoji)}>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*
* Options affecting the entire emoji picker are available on this
* component as props.
*
* @example
* ```tsx
* <EmojiPicker.Root locale="fr" columns={10} skinTone="medium">
* {\/* ... *\/}
* </EmojiPicker.Root>
* ```
*/
declare const EmojiPickerRoot: react.ForwardRefExoticComponent<Omit<EmojiPickerRootProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
/**
* A search input to filter the list of emojis.
*
* @example
* ```tsx
* <EmojiPicker.Root>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*
* It can be controlled or uncontrolled.
*
* @example
* ```tsx
* const [search, setSearch] = useState("");
*
* return (
* <EmojiPicker.Root>
* <EmojiPicker.Search
* value={search}
* onChange={(event) => setSearch(event.target.value)}
* />
* {\/* ... *\/}
* </EmojiPicker.Root>
* );
* ```
*/
declare const EmojiPickerSearch: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & react.RefAttributes<HTMLInputElement>>;
/**
* The scrolling container of the emoji picker.
*
* @example
* ```tsx
* <EmojiPicker.Root>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.Loading>Loading…</EmojiPicker.Loading>
* <EmojiPicker.Empty>No emoji found.</EmojiPicker.Empty>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*/
declare const EmojiPickerViewport: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
/**
* The list of emojis.
*
* @example
* ```tsx
* <EmojiPicker.Root>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*
* Inner components within the list can be customized via the `components` prop.
*
* @example
* ```tsx
* <EmojiPicker.List
* components={{
* CategoryHeader: ({ category, ...props }) => (
* <div {...props}>{category.label}</div>
* ),
* Emoji: ({ emoji, ...props }) => (
* <button {...props}>
* {emoji.emoji}
* </button>
* ),
* Row: ({ children, ...props }) => <div {...props}>{children}</div>,
* }}
* />
* ```
*/
declare const EmojiPickerList: react.ForwardRefExoticComponent<Omit<EmojiPickerListProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
/**
* A button to change the current skin tone by cycling through the
* available skin tones.
*
* @example
* ```tsx
* <EmojiPicker.SkinToneSelector />
* ```
*
* The emoji used as visual can be customized (by default, ✋).
*
* @example
* ```tsx
* <EmojiPicker.SkinToneSelector emoji="👋" />
* ```
*
* @see
* If you want to build a custom skin tone selector, you can use the
* {@link EmojiPickerSkinTone|`<EmojiPicker.SkinTone />`} component or
* {@link useSkinTone|`useSkinTone`} hook.
*/
declare const EmojiPickerSkinToneSelector: react.ForwardRefExoticComponent<Omit<EmojiPickerSkinToneSelectorProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
/**
* Only renders when the emoji data is loading.
*
* @example
* ```tsx
* <EmojiPicker.Root>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.Loading>Loading…</EmojiPicker.Loading>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*/
declare function EmojiPickerLoading({ children, ...props }: EmojiPickerLoadingProps): react_jsx_runtime.JSX.Element | null;
declare namespace EmojiPickerLoading {
var displayName: string;
}
/**
* Only renders when no emoji is found for the current search. The content is
* rendered without any surrounding DOM element.
*
* @example
* ```tsx
* <EmojiPicker.Root>
* <EmojiPicker.Search />
* <EmojiPicker.Viewport>
* <EmojiPicker.Empty>No emoji found.</EmojiPicker.Empty>
* <EmojiPicker.List />
* </EmojiPicker.Viewport>
* </EmojiPicker.Root>
* ```
*
* It can also expose the current search via a render callback to build
* a more detailed empty state.
*
* @example
* ```tsx
* <EmojiPicker.Empty>
* {({ search }) => <>No emoji found for "{search}"</>}
* </EmojiPicker.Empty>
* ```
*/
declare function EmojiPickerEmpty({ children, ...props }: EmojiPickerEmptyProps): react_jsx_runtime.JSX.Element | null;
declare namespace EmojiPickerEmpty {
var displayName: string;
}
/**
* Exposes the currently active emoji (either hovered or selected
* via keyboard navigation) via a render callback.
*
* @example
* ```tsx
* <EmojiPicker.ActiveEmoji>
* {({ emoji }) => <span>{emoji}</span>}
* </EmojiPicker.ActiveEmoji>
* ```
*
* It can be used to build a preview area next to the list.
*
* @example
* ```tsx
* <EmojiPicker.ActiveEmoji>
* {({ emoji }) => (
* <div>
* {emoji ? (
* <span>{emoji.emoji} {emoji.label}</span>
* ) : (
* <span>Select an emoji…</span>
* )}
* </div>
* )}
* </EmojiPicker.ActiveEmoji>
* ```
*
* @see
* If you prefer to use a hook rather than a component,
* {@link useActiveEmoji} is also available.
*/
declare function EmojiPickerActiveEmoji({ children }: EmojiPickerActiveEmojiProps): ReactNode;
declare namespace EmojiPickerActiveEmoji {
var displayName: string;
}
/**
* Exposes the current skin tone and a function to change it via a render
* callback.
*
* @example
* ```tsx
* <EmojiPicker.SkinTone>
* {({ skinTone, setSkinTone }) => (
* <div>
* <span>{skinTone}</span>
* <button onClick={() => setSkinTone("none")}>Reset skin tone</button>
* </div>
* )}
* </EmojiPicker.SkinTone>
* ```
*
* It can be used to build a custom skin tone selector: pass an emoji
* you want to use as visual (by default, ✋) and it will return its skin tone
* variations.
*
* @example
* ```tsx
* const [skinTone, setSkinTone, skinToneVariations] = useSkinTone("👋");
*
* // (👋) (👋🏻) (👋🏼) (👋🏽) (👋🏾) (👋🏿)
* <EmojiPicker.SkinTone emoji="👋">
* {({ skinTone, setSkinTone, skinToneVariations }) => (
* skinToneVariations.map(({ skinTone, emoji }) => (
* <button key={skinTone} onClick={() => setSkinTone(skinTone)}>
* {emoji}
* </button>
* ))
* )}
* </EmojiPicker.SkinTone>
* ```
*
* @see
* If you prefer to use a hook rather than a component,
* {@link useSkinTone} is also available.
*
* @see
* An already-built skin tone selector is also available,
* {@link EmojiPicker.SkinToneSelector|`<EmojiPicker.SkinToneSelector />`}.
*/
declare function EmojiPickerSkinTone({ children, emoji }: EmojiPickerSkinToneProps): ReactNode;
declare namespace EmojiPickerSkinTone {
var displayName: string;
}
declare namespace emojiPicker {
export { EmojiPickerActiveEmoji as ActiveEmoji, EmojiPickerEmpty as Empty, EmojiPickerList as List, EmojiPickerLoading as Loading, EmojiPickerRoot as Root, EmojiPickerSearch as Search, EmojiPickerSkinTone as SkinTone, EmojiPickerSkinToneSelector as SkinToneSelector, EmojiPickerViewport as Viewport };
}
/**
* Returns the currently active emoji (either hovered or selected
* via keyboard navigation).
*
* @example
* ```tsx
* const activeEmoji = useActiveEmoji();
* ```
*
* It can be used to build a preview area next to the list.
*
* @example
* ```tsx
* const activeEmoji = useActiveEmoji();
*
* <div>
* {activeEmoji ? (
* <span>{activeEmoji.emoji} {activeEmoji.label}</span>
* ) : (
* <span>Select an emoji…</span>
* )}
* </div>
* ```
*
* @see
* If you prefer to use a component rather than a hook,
* {@link EmojiPicker.ActiveEmoji|`<EmojiPicker.ActiveEmoji />`} is also available.
*/
declare function useActiveEmoji(): Emoji | undefined;
/**
* Returns the current skin tone and a function to change it.
*
* @example
* ```tsx
* const [skinTone, setSkinTone] = useSkinTone();
* ```
*
* It can be used to build a custom skin tone selector: pass an emoji
* you want to use as visual (by default, ✋) and it will return its skin tone
* variations.
*
* @example
* ```tsx
* const [skinTone, setSkinTone, skinToneVariations] = useSkinTone("👋");
*
* // (👋) (👋🏻) (👋🏼) (👋🏽) (👋🏾) (👋🏿)
* skinToneVariations.map(({ skinTone, emoji }) => (
* <button key={skinTone} onClick={() => setSkinTone(skinTone)}>
* {emoji}
* </button>
* ));
* ```
*
* @see
* If you prefer to use a component rather than a hook,
* {@link EmojiPicker.SkinTone|`<EmojiPicker.SkinTone />`} is also available.
*
* @see
* An already-built skin tone selector is also available,
* {@link EmojiPicker.SkinToneSelector|`<EmojiPicker.SkinToneSelector />`}.
*/
declare function useSkinTone(emoji?: string): [SkinTone, (skinTone: SkinTone) => void, SkinToneVariation[]];
export { type Category, type Emoji, emojiPicker as EmojiPicker, type EmojiPickerActiveEmojiProps, type EmojiPickerEmptyProps, type EmojiPickerListCategoryHeaderProps, type EmojiPickerListComponents, type EmojiPickerListEmojiProps, type EmojiPickerListProps, type EmojiPickerListRowProps, type EmojiPickerLoadingProps, type EmojiPickerRootProps, type EmojiPickerSearchProps, type EmojiPickerSkinToneProps, type EmojiPickerSkinToneSelectorProps, type EmojiPickerViewportProps, type Locale, type SkinTone, useActiveEmoji, useSkinTone };