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

@a_ng_d/figmug-ui

v1.20.0

Published

Figmug UI is a comprehensive library of UI components designed specifically for building Figma and Penpot plugins. It leverages modern tools and frameworks to ensure a seamless development experience.

Readme

GitHub package.json version GitHub last commit GitHub Actions Workflow Status GitHub Actions Workflow Status GitHub Actions Workflow Status GitHub

Figmug UI

Figmug UI is a comprehensive library of UI components designed specifically for building Figma, Penpot, and Sketch plugins. It leverages modern tools and frameworks to ensure a seamless development experience.

Features

  • Built with React: A popular JavaScript library for building user interfaces
  • Bundled with Vite: Fast and optimized build tool for modern web projects
  • Tested with Vitest: Ensures reliability and robustness of components with interaction tests
  • Exposed with Storybook: Interactive UI component explorer for easy development and testing
  • Design tokens with Terrazzo: Theme management using design tokens for consistent styling across platforms. View Terrazzo Guide
  • Theme Generator: Create custom themes easily with the Theme Generator tool based on Figma theme structure
  • SCSS Builder: Generate theme-specific SCSS files from tokens using the build-scss script, with support for building components across all themes
  • Interaction Testing: Automated interaction tests for all components using Storybook play functions.

Installation

To install Figmug UI, use npm or yarn:

npm install figmug-ui
# or
yarn add figmug-ui

Testing

Figmug UI comes with comprehensive interaction tests for all components:

# Run only Storybook interaction tests
npm run test:storybook

Tests can also be run directly in Storybook UI:

  1. Start Storybook: npm run storybook
  2. Open the Tests panel in the sidebar
  3. Click "Run all" to execute all interaction tests

Theme Development Tools

Figmug UI provides powerful tools for creating and managing custom themes:

Theme Generator

Create new themes based on existing design systems (Sketch, Figma UI, etc.) with a single command:

npm run create:theme

The Theme Generator automates the creation of all necessary files and configurations:

  • Tokens JSON files
  • Terrazzo configuration
  • Storybook integration
  • SCSS imports

Learn more about the Theme Generator

SCSS Builder

Generate theme-specific SCSS files from design tokens with these commands:

# List available themes and components
npm run scss:list

# Build all SCSS files
npm run scss:build

# Build SCSS for a specific theme
npm run scss:build theme=themeName

# Build SCSS for a specific component across all themes
npm run scss:build component=componentName

# Build SCSS for a specific component within a specific theme
npm run scss:build theme=themeName component=componentName

# Build specific token types across all themes
npm run scss:build text
npm run scss:build color
npm run scss:build icon
npm run scss:build type

# Build specific token types for a specific theme
npm run scss:build theme=themeName text
npm run scss:build theme=themeName color

Usage

Slots

Bar

import { Bar } from 'figmug-ui'

function App() {
  return (
    <Bar
      leftPartSlot={<div>Left very long text that may be truncated</div>}
      rightPartSlot={<div>Right very long text that may be truncated</div>}
      truncate={['LEFT', 'RIGHT']}
      padding="12px"
    />
  )
}

Form Item

import { FormItem } from 'figmug-ui'
import { Input } from 'figmug-ui'

function App() {
  return (
    <FormItem
      id="text-input-item"
      label="Type your name"
      helper={{
        type: 'INFO',
        message: 'First name followed by your last name',
      }}
      shouldFill={false}
      isBlocked={false}
      isNew={false}
    >
      <Input
        id="text-input-item"
        type="TEXT"
        value="Jean-Michel Avous"
      />
    </FormItem>
  )
}

Section

import { Section } from 'figmug-ui'

function App() {
  return (
    <Section
      title="Section Title"
      description="Section description goes here"
      isNew={false}
    >
      <div>Section content goes here</div>
    </Section>
  )
}

Drawer

import { Drawer } from 'figmug-ui'

function App() {
  return (
    <Drawer
      title="Drawer Title"
      isOpen={true}
      onClose={() => console.log('Drawer closed')}
    >
      <div>Drawer content goes here</div>
    </Drawer>
  )
}

Actions

Primary Button

import { Button } from 'figmug-ui'

function App() {
  return (
    <Button
      type="primary"
      size="default"
      label="Primary action button"
      preview={{
        image: 'https://placehold.co/96x96',
        text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
      }}
      feature="PRIMARY_ACTION"
      action={() => console.log('Primary button clicked')}
    />
  )
}

Secondary Button

import { Button } from 'figmug-ui'

function App() {
  return (
    <Button
      type="secondary"
      size="default"
      label="Secondary action button"
      feature="SECONDARY_ACTION"
      action={() => console.log('Secondary button clicked')}
    />
  )
}

Tertiary Button

import { Button } from 'figmug-ui'

function App() {
  return (
    <Button
      type="tertiary"
      label="Tertiary action button"
      feature="TERTIARY_ACTION"
      isLink={true}
      url="https://example.com"
      action={() => console.log('Tertiary button clicked')}
    />
  )
}

Destructive Button

import { Button } from 'figmug-ui'

function App() {
  return (
    <Button
      type="destructive"
      size="default"
      label="Destructive action button"
      feature="DESTRUCTIVE_ACTION"
      action={() => console.log('Destructive button clicked')}
    />
  )
}

Icon Button

import { Button } from 'figmug-ui'

function App() {
  return (
    <Button
      type="icon"
      size="default"
      state="default"
      icon="adjust"
      helper={{
        label: 'Adjust',
        type: 'SINGLE_LINE',
      }}
      action={() => console.log('Icon button clicked')}
    />
  )
}

Inputs

Short Text Input

import { Input } from 'figmug-ui'

function App() {
  return (
    <Input
      id="short-text-typing"
      type="TEXT"
      placeholder="Type something (64 characters max.)…"
      value=""
      charactersLimit={64}
      feature="TYPE_SHORT_TEXT"
      state="DEFAULT"
      isAutoFocus={false}
      isClearable={false}
      isFramed={true}
      onChange={(e) => console.log(e.target.value)}
    />
  )
}

Long Text Input

import { Input } from 'figmug-ui'

function App() {
  return (
    <Input
      id="long-text-typing"
      type="LONG_TEXT"
      placeholder="Type something"
      value=""
      feature="TYPE_LONG_TEXT"
      state="DEFAULT"
      isGrowing={false}
      onChange={(e) => console.log(e.target.value)}
    />
  )
}

Color Picker

import { Input } from 'figmug-ui'

function App() {
  return (
    <Input
      id="color-picker"
      type="COLOR"
      value="#87ebe7"
      feature="PICK_COLOR"
      onChange={(e) => console.log(e.target.value)}
    />
  )
}

Numeric Stepper

import { Input } from 'figmug-ui'

function App() {
  return (
    <Input
      id="numeric-stepper"
      type="NUMBER"
      icon={{
        type: 'LETTER',
        value: 'H',
      }}
      value="20"
      min="0"
      max="100"
      step="1"
      feature="ADJUST_NUMBER"
      onChange={(e) => console.log(e.target.value)}
    />
  )
}

Dropdown

Single Selection

import { Dropdown } from 'figmug-ui'

function App() {
  return (
    <Dropdown
      id="dropdown-button"
      options={[
        {
          label: 'Option 1',
          value: 'OPTION_1',
          type: 'OPTION',
        },
        {
          label: 'Option 2',
          value: 'OPTION_2',
          type: 'OPTION',
          children: [
            {
              label: 'Option 2.1',
              value: 'OPTION_2.1',
              type: 'OPTION',
            },
            {
              label: 'Option 2.2',
              value: 'OPTION_2.2',
              type: 'OPTION',
            },
          ],
        },
        {
          type: 'SEPARATOR',
        },
        {
          label: 'Title',
          type: 'TITLE',
        },
        {
          label: 'Option 3',
          value: 'OPTION_3',
          type: 'OPTION',
        },
      ]}
      selected="OPTION_1"
      alignment="LEFT"
      onChange={(value) => console.log(value)}
    />
  )
}

Multiple Selection

import { Dropdown } from 'figmug-ui'

function App() {
  return (
    <Dropdown
      id="dropdown-button"
      options={[
        {
          label: 'All',
          value: 'ANY',
          type: 'OPTION',
        },
        {
          label: 'Option 1',
          value: 'OPTION_1',
          type: 'OPTION',
        },
        {
          label: 'Option 2',
          value: 'OPTION_2',
          type: 'OPTION',
        },
      ]}
      selected={['ANY']}
      alignment="LEFT"
      onChange={(values) => console.log(values)}
    />
  )
}

Sliders

Simple Slider

import { SimpleSlider } from 'figmug-ui'

function App() {
  return (
    <SimpleSlider
      id="simple-slider"
      label="Simple Slider"
      value={50}
      min={0}
      max={100}
      colors={{
        min: 'white',
        max: 'black',
      }}
      feature="ADJUST_VALUE"
      onChange={(feature, type, value) => console.log(value)}
    />
  )
}

Multiple Slider

import { MultipleSlider } from 'figmug-ui'

function App() {
  return (
    <MultipleSlider
      id="multiple-slider"
      label="Multiple Slider"
      stops={[
        { id: 'stop-1', value: 20 },
        { id: 'stop-2', value: 50 },
        { id: 'stop-3', value: 80 },
      ]}
      min={0}
      max={100}
      colors={{
        min: 'white',
        max: 'black',
      }}
      feature="ADJUST_VALUES"
      onChange={(feature, type, value) => console.log(value)}
    />
  )
}

Dialogs

Simple Dialog

import { Dialog } from 'figmug-ui'

function App() {
  return (
    <Dialog
      title="Are you sure to delete?"
      actions={{
        destructive: {
          label: 'Delete',
          action: () => console.log('Delete action'),
        },
        secondary: {
          label: 'Cancel',
          action: () => console.log('Cancel action'),
        },
      }}
      pin="CENTER"
      onClose={() => console.log('Dialog closed')}
    >
      <div className="dialog__text">
        <p>Deleting this item will remove it permanently.</p>
      </div>
    </Dialog>
  )
}

Form Dialog

import { Dialog } from 'figmug-ui'
import { Input } from 'figmug-ui'
import { FormItem } from 'figmug-ui'

function App() {
  return (
    <Dialog
      title="What do you want to say?"
      actions={{
        primary: {
          label: 'Submit',
          action: () => console.log('Submit action'),
        },
      }}
      pin="CENTER"
      onClose={() => console.log('Dialog closed')}
    >
      <div className="dialog__form">
        <div className="dialog__form__item">
          <FormItem
            label="Full Name"
            id="type-fullname"
            shouldFill
          >
            <Input type="TEXT" />
          </FormItem>
        </div>
        <div className="dialog__form__item">
          <FormItem
            label="Email"
            id="type-email"
            shouldFill
          >
            <Input type="TEXT" />
          </FormItem>
        </div>
        <div className="dialog__form__item">
          <FormItem
            label="Message"
            id="type-message"
            shouldFill
          >
            <Input
              type="LONG_TEXT"
              placeholder="Type your message here"
            />
          </FormItem>
        </div>
      </div>
    </Dialog>
  )
}

Loading Dialog

import { Dialog } from 'figmug-ui'

function App() {
  return (
    <Dialog
      title="Loading…"
      pin="CENTER"
      isLoading={true}
      onClose={() => console.log('Dialog closed')}
    />
  )
}

Lists

Simple List

import { ActionsList } from 'figmug-ui'

function App() {
  return (
    <ActionsList
      options={[
        {
          label: 'Option 1',
          value: 'OPTION_1',
          type: 'OPTION',
          action: () => console.log('Option 1 clicked'),
        },
        {
          label: 'Option 2',
          value: 'OPTION_2',
          type: 'OPTION',
          action: () => console.log('Option 2 clicked'),
        },
        {
          label: 'Option 3',
          value: 'OPTION_3',
          type: 'OPTION',
          action: () => console.log('Option 3 clicked'),
        },
        {
          label: 'Option 4',
          value: 'OPTION_4',
          type: 'OPTION',
          action: () => console.log('Option 4 clicked'),
        },
      ]}
      selected="OPTION_1"
    />
  )
}

Grouped List

import { ActionsList } from 'figmug-ui'

function App() {
  return (
    <ActionsList
      options={[
        {
          label: 'Group 1',
          type: 'TITLE',
        },
        {
          label: 'Option 1',
          value: 'OPTION_1',
          type: 'OPTION',
          action: () => console.log('Option 1 clicked'),
        },
        {
          label: 'Option 2',
          value: 'OPTION_2',
          type: 'OPTION',
          action: () => console.log('Option 2 clicked'),
        },
        {
          type: 'SEPARATOR',
        },
        {
          label: 'Group 2',
          type: 'TITLE',
        },
        {
          label: 'Option 3',
          value: 'OPTION_3',
          type: 'OPTION',
          action: () => console.log('Option 3 clicked'),
        },
        {
          label: 'Option 4',
          value: 'OPTION_4',
          type: 'OPTION',
          action: () => console.log('Option 4 clicked'),
        },
      ]}
    />
  )
}

Nested List

import { ActionsList } from 'figmug-ui'

function App() {
  return (
    <ActionsList
      options={[
        {
          label: 'Group 1',
          value: 'GROUP_1',
          type: 'OPTION',
          children: [
            {
              label: 'Option 1',
              value: 'OPTION_A_1',
              type: 'OPTION',
              action: () => console.log('Option A.1 clicked'),
            },
            {
              label: 'Option 2',
              value: 'OPTION_A_2',
              type: 'OPTION',
              action: () => console.log('Option A.2 clicked'),
            },
          ],
        },
        {
          label: 'Group 2',
          value: 'GROUP_2',
          type: 'OPTION',
          children: [
            {
              label: 'Option 1',
              value: 'OPTION_B_1',
              type: 'OPTION',
              action: () => console.log('Option B.1 clicked'),
            },
            {
              label: 'Option 2',
              value: 'OPTION_B_2',
              type: 'OPTION',
              action: () => console.log('Option B.2 clicked'),
            },
          ],
        },
      ]}
    />
  )
}

Tags

Basic Chip

import { Chip } from 'figmug-ui'

function App() {
  return <Chip state="ACTIVE">New</Chip>
}

Chip with Color Indicator

import { Chip, ColorChip } from 'figmug-ui'

function App() {
  return (
    <Chip
      state="ON_BACKGROUND"
      leftSlot={
        <ColorChip
          color="blue"
          width="8px"
          height="8px"
          isRounded={true}
        />
      }
      rightSlot={<div style={{ fontSize: '11px' }}>✔︎</div>}
    >
      AA
    </Chip>
  )
}

Assets

Icon

import { Icon } from 'figmug-ui'

function App() {
  return (
    <>
      {/* Pictogram Icon */}
      <Icon
        type="PICTO"
        iconName="adjust"
      />

      {/* Letter Icon */}
      <Icon
        type="LETTER"
        iconLetter="L"
      />
    </>
  )
}

Avatar

import { Avatar } from 'figmug-ui'

function App() {
  return (
    <>
      {/* Avatar with Image */}
      <Avatar
        avatar="https://example.com/avatar.jpg"
        fullName="John Doe"
        isInverted={false}
      />

      {/* Default Avatar */}
      <Avatar isInverted={false} />
    </>
  )
}

Thumbnail

import { Thumbnail } from 'figmug-ui'

function App() {
  return (
    <Thumbnail
      src="https://example.com/image.jpg"
      width="300px"
      height="200px"
    />
  )
}

Testing

To run tests:

npm test
# or
yarn test

License

This project is licensed under the MIT License. See the LICENSE file for more information.