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

@markoradak/folder-card

v0.1.1

Published

Animated folder-style card with FLIP spring expansion, 3D lid rotation, and render props API

Readme

@markoradak/folder-card

Animated folder-style cards for React. FLIP spring expansion, 3D lid rotation, SVG notch masks, and a render props API.

Install

npm install @markoradak/folder-card motion

Quick start

import {
  FolderCardGroup,
  FolderCard,
  FolderCardItem,
} from "@markoradak/folder-card";
import "@markoradak/folder-card/styles.css";

function App() {
  return (
    <FolderCardGroup>
      <FolderCard
        id="example"
        renderLid={() => (
          <div style={{ padding: 24 }}>
            <h3>Project Alpha</h3>
            <p>Click to expand</p>
          </div>
        )}
        renderDetail={(close) => (
          <div style={{ padding: 32 }}>
            <h2>Project Alpha</h2>
            <FolderCardItem>
              <p>Stagger-animated content.</p>
            </FolderCardItem>
            <button onClick={close}>Close</button>
          </div>
        )}
      />
    </FolderCardGroup>
  );
}

Features

  • FLIP spring animation — Cards spring from grid position to centered dialog using Motion physics.
  • 3D lid rotation — Perspective-correct rotation on any edge (bottom, top, left, right, or auto).
  • SVG notch mask — Folder-style tab cutouts at any corner or edge center with configurable radii.
  • Render props API — Full control over card face, detail content, and tab. No opinionated markup.
  • Stagger animationsFolderCardItem wraps content for automatic staggered fade-in.
  • CSS variable theming — Override --fc-* variables for colors, radii, shadows, and transitions.

Components

<FolderCardGroup>

Wraps all cards and manages shared state (which card is open, spring config, etc).

| Prop | Type | Default | Description | |------|------|---------|-------------| | springConfig | { stiffness?: number; damping?: number } | { stiffness: 320, damping: 42 } | Spring physics for position/size and lid rotation | | dialogViewportPadding | number | 32 | Padding (px) between dialog and viewport edge | | contentRevealDelay | number | 200 | Delay (ms) before dialog content fades in | | openAngle | number | per-hinge default | Override the default open angle (deg) for lid rotation | | backdropDuration | number | 0.25 | Duration (s) of backdrop fade | | exitDuration | number | 0.15 | Duration (s) of content fade-out on close | | fadeLid | boolean | false | Fade lid out instead of 3D rotation | | dialogMinWidth | number | 1000 | Minimum target width (px) the dialog tries to reach. Content wider than this grows freely up to the viewport. | | backdropClassName | string | — | Class name for the backdrop element | | dialogClassName | string | — | Class name for the dialog element | | onOpen | (id: string) => void | — | Called when a card opens | | onClose | (id: string) => void | — | Called when a card closes |

<FolderCard>

An individual card with a lid face and expandable detail.

| Prop | Type | Default | Description | |------|------|---------|-------------| | id | string | required | Unique identifier | | renderLid | () => ReactNode | required | Card face / expanded lid content | | renderDetail | (close: () => void) => ReactNode | required | Expanded dialog content. Rendered into two React trees (a hidden measurement tree and the visible dialog) — every component inside mounts twice. Keep side-effect-free; lift data fetching and subscriptions to a parent. | | renderTab | () => ReactNode | — | Tab notch content | | ariaLabel | string | — | Accessible label for the expanded dialog | | className | string | — | Class name for the card button | | style | CSSProperties | — | Inline styles for the card wrapper | | perspective | number | 1800 | Perspective depth (px) for 3D rotation | | hingeSide | 'auto' \| 'bottom' \| 'top' \| 'left' \| 'right' | 'auto' | Which edge the lid hinges on | | notchPosition | NotchPosition | 'top-right' | Where the tab notch sits (8 positions) | | notchOuterRadius | number | card radius | Outer concave radius of the notch cutout | | notchInnerRadius | number | cardRadius * 0.7 | Inner inverted radius of the notch cutout | | liveRadius | boolean | false | Observe --fc-radius changes reactively |

<FolderCardItem>

Wraps content inside renderLid or renderDetail for staggered fade-in animation.

CSS variables

Import the base stylesheet and override variables to theme:

@import "@markoradak/folder-card/styles.css";

:root {
  --fc-radius: 20px;
  --fc-card-bg: #ffffff;
  --fc-foreground: #0a0a0a;
  --fc-border: rgba(0, 0, 0, 0.1);
  --fc-muted: rgba(0, 0, 0, 0.45);
  --fc-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
  --fc-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);
  --fc-backdrop-bg: rgba(0, 0, 0, 0.5);
  --fc-dialog-shadow: 0 25px 60px rgba(0, 0, 0, 0.25);
  --fc-focus-ring: rgba(0, 0, 0, 0.2);
  --fc-lid: color-mix(in srgb, var(--fc-foreground) 6%, var(--fc-card-bg));
  --fc-lid-border: transparent;           /* advanced: fallback only */
  --fc-lid-back: /* gradient */;          /* advanced: fallback only */
  --fc-transition-duration: 300ms;
  --fc-transition-easing: ease-out;
}

Dark mode is applied automatically via @media (prefers-color-scheme: dark). To integrate with a class-based theme switcher (e.g. next-themes), override the variables inside your own .dark selector.

Development

This repository is a pnpm + Turborepo monorepo:

packages/
  react/          @markoradak/folder-card — the published package
apps/
  web/            Next.js demo + documentation site

Requires Node 18+ and pnpm 10+.

pnpm install
pnpm dev          # run the demo site + package in watch mode
pnpm build        # build the package
pnpm typecheck    # typecheck all workspaces

cd packages/react
pnpm test         # run the package test suite

License

MIT