npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tandyleo110/memos-emotes

v1.0.6

Published

Lightweight React emoji picker component for Memos — built-in Chinese emoji packs with dynamic loading

Readme

@tandyleo110/memos-emotes

Lightweight React emoji picker component for Memos — built-in Chinese emoji packs with dynamic loading and code splitting.

Features

  • Zero runtime dependencies (except React)
  • Tree-shakeable ES modules
  • Dynamic pack loading with code splitting
  • Built-in search across all emotes
  • CSS Modules with dark mode support
  • TypeScript types included
  • Responsive size presets (sm / md / lg)
  • Customizable via CSS variables

Installation

npm install @tandyleo110/memos-emotes

Quick Start

import { EmotePicker } from "@tandyleo110/memos-emotes";

// Import emote data packs (each is a separate JSON data file for code splitting)
import joyData from "@tandyleo110/memos-emotes/dist/emotes/JOY.json";
import tvData from "@tandyleo110/memos-emotes/dist/emotes/TV.json";

function App() {
  const handleSelect = (shortcode: string, dataUri: string) => {
    // Insert the emote into your editor
    console.log(shortcode); // e.g. "[joy_1]"
    console.log(dataUri);   // e.g. "data:image/png;base64,..."
  };

  return (
    <EmotePicker
      packs={[joyData, tvData]}
      onSelect={handleSelect}
      packNames={["JOY日常", "小电视"]}
      size="md"
    />
  );
}

Available Emote Packs

| Pack ID | Name | Shortcode Format | Example | |---------|------|-----------------|---------| | JOY | JOY日常 | [joy_*] | [joy_1] | | TV | 小电视 | [tv_*] | [tv_doge] | | YellowFace | 黄脸 | [*] | [OK] | | dy | 抖音 | [dy_*] | [dy_666] | | xhs | 小红书 | [xhs_*] | [xhs_love] | | weixin | 微信 | [wx_*] | [wx_smile] | | weibo | 微博 | [wb_*] | [wb_doge] | | qq2015 | QQ2015 | [q2015_*] | [q2015_cry] | | qqn | QQ新 | [qnew_*] | [qnew_smile] | | bear | 熊熊 | [bear_*] | [bear_happy] | | pig1 | 小猪1 | [pig1_*] | [pig1_cry] | | pig2 | 小猪2 | [pig2_*] | [pig2_happy] | | my | 自定义 | [my_*] | [my_custom] |

API Reference

<EmotePicker>

Full-featured picker component with tabs, search, and grid.

<EmotePicker
  packs={[joyData, tvData]}
  onSelect={(shortcode, dataUri) => insertText(shortcode)}
  packNames={["JOY日常", "小电视"]}
  size="md"
  layout="grid"
  searchable={true}
  defaultEmoteSize={2}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | packs | EmotePackData[] | required | Array of emote pack data modules | | onSelect | (shortcode: string, dataUri: string) => void | required | Called when an emote is selected | | packNames | string[] | undefined | Display names for each pack tab | | size | "sm" \| "md" \| "lg" | "md" | Preset size of the picker | | layout | "grid" \| "list" | "grid" | Layout mode for emotes | | searchable | boolean | true | Whether to show the search bar | | defaultEmoteSize | EmoteSize | 2 | Default size multiplier (1-9) |

<Emote>

Single emote image component.

<Emote src={dataUri} alt="[joy_1]" size={3} interactive onClick={handleClick} />

| Prop | Type | Default | Description | |------|------|---------|-------------| | src | string | required | Base64 data URI | | alt | string | "" | Alt text | | size | EmoteSize | 2 | Size multiplier (1-9) | | interactive | boolean | false | Enable hover/click effects | | onClick | () => void | undefined | Click handler |

<EmoteGrid>

Grid layout for displaying emotes.

<EmoteGrid
  emotes={pack.emotes}
  imageData={pack.data}
  emoteSize={3}
  onSelect={(code, file) => console.log(code)}
/>

<EmoteSearch>

Search input for filtering emotes.

<EmoteSearch value={query} onChange={setQuery} placeholder="Search..." />

<EmoteTab>

Tab button for switching between packs.

<EmoteTab label="JOY日常" active onClick={() => setActive(0)} />

<EmoteTooltip>

Hover tooltip showing emote preview and shortcode.

<EmoteTooltip shortcode="[joy_1]" dataUri={dataUri}>
  <button>Hover me</button>
</EmoteTooltip>

<EmoteCategory>

Section header for grouping emotes.

<EmoteCategory name="JOY日常" count={15} />

Hooks

useEmoteData(url)

Dynamically load an emote pack from a URL.

const { data, loading, error, reload } = useEmoteData(
  "https://unpkg.com/@tandyleo110/[email protected]/dist/emotes/JOY.json"
);

useEmoteSearch(emotes)

Filter emotes by shortcode search query.

const { query, setQuery, filtered, isSearching } = useEmoteSearch(emotes);

useEmotePicker(packs)

Manage picker tab state and emote selection.

const { activeTabIndex, setActiveTab, activeEmotes, handleSelect } = useEmotePicker(packs);

useEmoteSize(defaultSize)

Manage emote display size with responsive controls.

const { size, increase, decrease, pixelSize } = useEmoteSize(2);

Utilities

import {
  loadEmotePack,        // Dynamic pack loading
  parseShortcodes,      // Parse text for shortcodes
  replaceShortcodesWithImages, // Replace shortcodes with <img> tags
  isValidShortcode,     // Validate shortcode format
  getAllPacks,          // Get all registered packs
  getPackById,          // Find pack by ID
} from "@tandyleo110/memos-emotes";

Styling

The component uses CSS Modules by default. You can override styles using CSS variables:

:root {
  --emote-picker-bg: #ffffff;
  --emote-picker-border: #e5e7eb;
  --emote-tab-active-bg: #eff6ff;
  --emote-tab-active-color: #2563eb;
  --emote-search-bg: #f9fafb;
  --emote-hover-bg: #f3f4f6;
}

Dark mode is automatically supported via prefers-color-scheme: dark.

Loading Packs Dynamically

For code splitting, load packs on demand:

import { useEmoteData } from "@tandyleo110/memos-emotes";

function LazyPicker() {
  const { data, loading } = useEmoteData(
    "https://unpkg.com/@tandyleo110/[email protected]/dist/emotes/JOY.json"
  );

  if (loading) return <div>Loading...</div>;
  if (!data) return null;

  return <EmotePicker packs={[data]} onSelect={handleSelect} />;
}

License

MIT