Skip to main content

shade-new-component

Acceptance checklist for adding or editing a Shade component or pattern file — naming, sibling story, className forwarding, cva variants, required states, recipe usage. Trigger when editing files in apps/shade/src/components.

소스 정보

저장소
TryGhost/Ghost
최근 소스 활동
2026년 10월 11일 08:53
감지된 SKILL.md 언어
영어
스타
55,544
포크
11,995

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
Shade new component
description
Acceptance checklist for adding or editing a Shade component or pattern file — naming, sibling story, className forwarding, cva variants, required states, recipe usage. Trigger when editing files in apps/shade/src/components.
autoTrigger
[{"fileEdit":"apps/shade/src/components/**/*.{ts,tsx}"}]
# Shade — new component / pattern checklist Before marking a Shade component or pattern done, this checklist must pass. ## Files and naming - File: **kebab-case** (`dropdown-menu.tsx`) — matches ShadCN CLI output. Don't rename for casing. - Exported identifier: **PascalCase** (`DropdownMenu`). - Hooks, functions, variables: camelCase. - Sibling **`<name>.stories.tsx`** is required (same folder). - A component file exports only components and types, so Fast Refresh can hot-update it (ESLint enforces this). An exported `cva()` config goes in a sibling **`<name>-variants.ts`**; exported hooks, contexts and helpers go in their own sibling module (`sidebar-context.ts`). These siblings belong to the component; they aren't Recipes. - Inside Shade itself, import via the `@/` alias (`@/lib/utils`, `@/components/ui/input-surface`). ## Storybook title prefix | Layer | Title | | ------------- | --------------------- | | Primitive | `Primitives / <Name>` | | Component | `Components / <Name>` | | Recipe | `Recipes / <Name>` | | Pattern | `Patterns / <Name>` | | Token gallery | `Tokens / <Topic>` | Required on every story file: - `tags: ['autodocs']` - `parameters.docs.description.component` — short one-line summary - Per-story `parameters.docs.description.story` — one-liner explaining when to use that variant - One story per important variant/state. Many small focused stories > one prose-heavy story. ## Component shape ```ts // thing-variants.ts import {cva} from 'class-variance-authority'; const thingVariants = cva('base-classes-here', { variants: { variant: {default: '...', destructive: '...'}, size: {default: '...', sm: '...'} }, defaultVariants: {variant: 'default', size: 'default'} }); export {thingVariants}; ``` ```tsx // thing.tsx import * as React from 'react'; import {type VariantProps} from 'class-variance-authority'; import {thingVariants} from '@/components/ui/thing-variants'; import {cn} from '@/lib/utils'; export interface ThingProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof thingVariants> {} const Thing = React.forwardRef<HTMLDivElement, ThingProps>( ({className, variant, size, ...props}, ref) => ( <div ref={ref} className={cn(thingVariants({variant, size, className}))} {...props} /> ) ); Thing.displayName = 'Thing'; export {Thing}; ``` Hard requirements: - `className` forwarded and merged via `cn()` — never overwritten, never dropped. Applies to every component that renders DOM. - Visual/interactive props only (`variant`, `size`, `loading`). **No workflow props** (`isMembersPage`, `layoutMode`) — those mean you actually need a Pattern wrapper. - Multi-region components expose compound subcomponents (`.Title`, `.Actions`, `.Body`) — not a prop bag. When applicable: - **`forwardRef`** — use when the component renders a single DOM element consumers might need a ref to (most UI controls). Skip for: pure provider/context wrappers, Radix root re-exports that don't render DOM themselves, and components whose `ref` semantics are already handled by a child. - **`cva()`** — use when the component has variants or stateful class branches (`variant`, `size`, `tone`). Skip for simple single-style components where a `cn(...)` call is clearer. - **Recipes** (`<name>.ts`, no JSX): no `forwardRef`, no `cva()`, no React. They return class strings. ## Required states (all four) Every interactive component must work in: - **default** - **hover** - **focus-visible** (use `focus-visible:`, never `focus:`) - **disabled** Each state visible in the story. Optional states (active, loading, error, empty) only when they apply. For form controls, drive chrome through the **`inputSurface` recipe** — don't roll your own border/focus ring. See the `shade-input-surface-recipe` skill. ## Tokens - No hex values. No `bg-gray-200`-style raw palette utilities for UI chrome. - No `dark:` variants for colour — semantic tokens handle dark mode. See `shade-tokens-not-hex` and `shade-no-dark-variants`. ## Before marking done - [ ] Lives in the right layer (`shade-component-decision`) - [ ] kebab-case filename, PascalCase export, sibling `<name>.stories.tsx` - [ ] `className` forwarded and merged with `cn()` (always) - [ ] `forwardRef` if the component renders DOM consumers might ref - [ ] `cva()` if the component has variants; `defaultVariants` set - [ ] The component file exports only components and types; exported variants, hooks and contexts live in sibling modules - [ ] All four required states work and are visible in the story - [ ] Semantic tokens only — no hex, no raw greys, no `dark:` colour variants - [ ] No product-specific props on a generic Component - [ ] Story has `tags: ['autodocs']`, component description, and one-line per-story descriptions - [ ] `pnpm lint`, `pnpm test`, and Storybook all clean ## Source of truth Storybook → Overview / Contributing and the component's stories.
GitHub에서 보기