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

@ensnif/design-system

v0.2.0

Published

Multi-style, multi-palette design system: tokens, themes, React provider, and 50+ components for the lanime ecosystem.

Downloads

236

Readme

@ensnif/design-system

lanime 생태계용 디자인 시스템. 토큰 + 테마 + Provider + React 컴포넌트를 한 패키지에 제공합니다. 시각 스타일(Variant), 팔레트(Palette), 모드(Mode)를 서로 독립적으로 조합할 수 있도록 설계되어 있습니다.

핵심 개념

세 축이 모두 독립적으로 조합 됩니다.

[Palette]   ×   [Variant]            ×   [Mode]
lavender         minimal                  light
blue             neumorphism              dark
green            glassmorphism
red              brutalism
mono             retro
orange
pink
teal
yellow
indigo
  • Palette (10): lavender, blue, green, red, mono, orange, pink, teal, yellow, indigo
  • Variant (5): minimal, neumorphism, glassmorphism, brutalism, retro
  • Mode (2): light, dark

| Variant | 어울리는 상황 | | --- | --- | | minimal | SaaS, 관리/설정 페이지, 컨텐츠 중심 — 모든 케이스의 안전한 기본값 | | neumorphism | 컨트롤 패널, 위젯, 부드러운 입체감 강조 | | glassmorphism | 비디오 오버레이, 랜딩 hero, macOS·iOS 풍 | | brutalism | 패션, 아트, 포트폴리오, 브랜드 캠페인 — 강한 정체성 | | retro | Y2K, 이벤트·캠페인 페이지, 힙한 브랜딩 |

더 둥근 느낌이 필요하면 minimal + tokenOverrides={{ radius: { md: '16px', lg: '20px' } }}로 즉시 적용 가능합니다.

조합은 모두 CSS 변수로 풀어져 <DesignSystemProvider> 가 적용된 범위에 자동 주입됩니다.

설치

pnpm add @ensnif/design-system

빠른 시작

import { DesignSystemProvider, themeTokens } from '@ensnif/design-system'

function App() {
  return (
    <DesignSystemProvider palette="lavender" variant="minimal" mode="light">
      <YourApp />
    </DesignSystemProvider>
  )
}

const styles = {
  card: {
    background: themeTokens.surface.card.background,
    border: themeTokens.surface.card.border,
    borderRadius: themeTokens.surface.card.radius,
    boxShadow: themeTokens.surface.card.shadow,
    color: themeTokens.surface.card.color,
    padding: themeTokens.spacing[6],
  },
  button: {
    background: themeTokens.color.accent.background,
    color: themeTokens.color.accent.color,
    borderRadius: themeTokens.radius.md,
    padding: `${themeTokens.spacing[2]} ${themeTokens.spacing[4]}`,
    transition: `all ${themeTokens.motion.duration.normal} ${themeTokens.motion.easing.easeOut}`,
  },
}

테마 전환

import { useDesignSystem } from '@ensnif/design-system'

function ThemeSwitcher() {
  const { theme, setPalette, setVariant, toggleMode } = useDesignSystem()
  return (
    <>
      <button onClick={() => setPalette('blue')}>Blue</button>
      <button onClick={() => setVariant('glassmorphism')}>Glass</button>
      <button onClick={toggleMode}>{theme.mode}</button>
    </>
  )
}

커스텀 팔레트

기본 10개에 없는 색을 쓰려면 객체로 직접 주입할 수 있습니다.

<DesignSystemProvider
  palette={{
    name: 'brand',
    label: 'Brand',
    primary: {
      50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc',
      400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1',
      800: '#075985', 900: '#0c4a6e',
    },
  }}
  variant="rounded"
  mode="light"
/>

기본 팔레트의 일부 step만 덮어쓰려면 paletteOverrides 사용.

<DesignSystemProvider
  palette="lavender"
  paletteOverrides={{ primary: { 500: '#a45cff' } }}
/>

토큰 오버라이드

특정 token group(radius, shadow 등)만 바꾸고 싶을 때.

<DesignSystemProvider
  variant="minimal"
  tokenOverrides={{
    radius: { md: '20px', lg: '28px' },
    typography: { fontFamily: { sans: '"Pretendard", sans-serif' } },
  }}
/>

적용 범위

  • applyTo="root" (기본): document.documentElement에 CSS 변수 적용. 앱 전체 테마 변경.
  • applyTo="scope": 자식만 감싸는 <div>에 적용. 페이지 일부에 다른 테마 미리보기 등.
<DesignSystemProvider applyTo="scope" variant="brutalism">
  <PreviewArea />
</DesignSystemProvider>

SSR (FOUC 방지)

서버 렌더링 시 첫 페인트에 CSS 변수가 없으면 깜빡임이 생깁니다. 두 가지 방법으로 해결할 수 있습니다.

1. HTML 문자열에 직접 주입 (Express/Vite SSR 등)

import { injectThemeIntoHtml } from '@ensnif/design-system'

app.get('*', (req, res) => {
  const theme = { palette: 'lavender', variant: 'minimal', mode: 'light' }
  let html = template
  html = injectThemeIntoHtml(html, theme)
  res.send(html)
})

injectThemeIntoHtml은:

  • <head> 안에 <style data-ds-init="true">:root { --ds-... }</style> 삽입
  • <html> 태그에 data-ds-palette="..." data-ds-variant="..." data-ds-mode="..." 부착

클라이언트에서 <DesignSystemProvider> 가 마운트되면 SSR style 태그를 자동 제거하고 inline style로 인계받습니다 (값이 동일하므로 깜빡임 없음).

2. React 트리 안에서 컴포넌트로

<head> 직접 제어가 어려운 환경(ex. Helmet 미사용)에서:

import { DesignSystemStyle, DesignSystemProvider } from '@ensnif/design-system'

const theme = { palette: 'lavender', variant: 'minimal', mode: 'light' } as const

function Document() {
  return (
    <html>
      <head>
        <DesignSystemStyle {...theme} />
      </head>
      <body>
        <DesignSystemProvider {...theme}>
          <App />
        </DesignSystemProvider>
      </body>
    </html>
  )
}

3. 저수준 helper

import { renderThemeStyle, renderThemeCss, renderHtmlAttrs } from '@ensnif/design-system'

const { css, styleTag, dataAttrs, vars } = renderThemeStyle(theme, { nonce: cspNonce })
const cssOnly = renderThemeCss(theme)
const htmlAttrs = renderHtmlAttrs(theme)  // 'data-ds-palette="..." data-ds-variant="..." ...'

CSP nonce 옵션, 커스텀 selector (예: :root.ds-scope), indent 모두 지원.

빌드된 토큰 직접 사용

Provider 없이 정적 CSS를 생성하려면:

import { buildTheme, themeToCssVars, cssVarsToString } from '@ensnif/design-system'

const theme = buildTheme({ palette: 'mono', variant: 'card', mode: 'dark' })
const vars = themeToCssVars(theme)
const cssText = cssVarsToString(vars)

API 요약

| 항목 | 설명 | | --- | --- | | DesignSystemProvider | 전역/scope 테마 적용 | | useDesignSystem() | { theme, setPalette, setVariant, setMode, toggleMode } | | useTheme() | 현재 ResolvedTheme 반환 | | themeTokens | CSS 변수 참조 토큰. 컴포넌트 스타일에서 직접 사용 | | buildTheme(input) | 팔레트×variant×mode → ResolvedTheme | | themeToCssVars(theme) | ResolvedTheme → { '--ds-...': '값' } | | palettes, paletteNames | 모든 프리셋 | | variants, variantNames | 모든 variant 정의 |

CSS 변수 네임스페이스

모든 변수는 --ds- 접두사 사용. 주요 그룹:

  • --ds-palette-primary-50 ~ 900, --ds-palette-neutral-50 ~ 900
  • --ds-color-background-{page,panel,card,overlay,inset,muted}
  • --ds-color-foreground-{primary,secondary,tertiary,muted,onAccent}
  • --ds-color-accent-{background,color,border,shadow,hoverBackground,activeBackground}
  • --ds-color-state-{success,warning,danger,info,disabled}
  • --ds-surface-{page,panel,card,overlay,inset}-{background,border,radius,shadow,color,backdrop-filter}
  • --ds-radius-*, --ds-shadow-*, --ds-spacing-*, --ds-typography-*, --ds-motion-*, --ds-blur-*, --ds-borderWidth-*

구조

src/
├── tokens/        radius, shadow, spacing, typography, motion, blur, borderWidth
├── palettes/      10개 컬러 프리셋 + neutral + semantic(success/warning/danger/info)
├── variants/      5개 시각 스타일 (각 mode/palette 컨텍스트로 surface, accent 빌드)
├── themes/        buildTheme, themeToCssVars, themeTokens (CSS 변수 참조)
├── provider/      DesignSystemProvider, useDesignSystem
├── components/    Button, Input, Card, Dialog, Drawer, Tabs, Table, DataTable,
│                  LineChart, BarChart, AreaChart, PieChart, RadarChart,
│                  RadialChart, DatePicker, ComboBox, ColorPicker, Toast 등 50+
└── utils/         cssVar, deepMerge, flattenTokens

컴포넌트 사용 예

import {
  DesignSystemProvider,
  Button,
  Card,
  CardHeader,
  CardTitle,
  CardBody,
} from '@ensnif/design-system'

function App() {
  return (
    <DesignSystemProvider palette="lavender" variant="minimal" mode="light">
      <Card>
        <CardHeader>
          <CardTitle>안녕하세요</CardTitle>
        </CardHeader>
        <CardBody>
          <Button variant="primary">시작</Button>
        </CardBody>
      </Card>
    </DesignSystemProvider>
  )
}