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.

Informations de source

Dépôt
TryGhost/Ghost
Dernière activité de la source
11 octobre 2026 à 08:53
Langue détectée de SKILL.md
anglais
Étoiles
55 544
Forks
11 995

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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.
Voir sur GitHub