pf-component

$ARGUMENTS 이름으로 컴포넌트를 생성합니다.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pf-component" with this command: npx skills add pluxity/pf-frontend/pluxity-pf-frontend-pf-component

PF 컴포넌트 생성기

$ARGUMENTS 이름으로 컴포넌트를 생성합니다.

컴포넌트 유형 판단

packages/ui 컴포넌트 - 재사용 가능한 공통 UI

  • atoms: 기본 컴포넌트 (Button, Input, Select 등)

  • molecules: 복합 컴포넌트 (Carousel, Widget 등)

  • organisms: 복잡한 컴포넌트 (Sidebar, DataTable 등)

앱 전용 컴포넌트 - 특정 앱에서만 사용

  • apps/앱이름/src/components/

packages/ui 컴포넌트 구조

packages/ui/src/atoms/ComponentName/ ├── ComponentName.tsx # 메인 컴포넌트 ├── index.ts # export ├── types.ts # Props 타입 ├── variants.ts # CVA 스타일 (필요시) └── ComponentName.stories.tsx # Storybook (선택)

types.ts 템플릿

import type { VariantProps } from "class-variance-authority"; import { componentVariants } from "./variants";

export interface ComponentNameProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof componentVariants> { /** 컴포넌트 설명 / children?: React.ReactNode; /* ref 전달 (React 19) */ ref?: React.Ref<HTMLDivElement>; }

variants.ts 템플릿 (CVA)

import { cva } from "class-variance-authority";

export const componentVariants = cva( // Base styles "inline-flex items-center justify-center", { variants: { variant: { default: "bg-white text-gray-900", primary: "bg-brand text-white", secondary: "bg-neutral-100 text-gray-700", }, size: { sm: "h-8 px-3 text-sm", md: "h-10 px-4 text-base", lg: "h-12 px-6 text-lg", }, }, defaultVariants: { variant: "default", size: "md", }, } );

ComponentName.tsx 템플릿

import { cn } from "../../utils"; import { componentVariants } from "./variants"; import type { ComponentNameProps } from "./types";

/**

  • ComponentName 컴포넌트
  • @example
  • <ComponentName variant="primary" size="md">
  • Content
  • </ComponentName> */ function ComponentName({ className, variant, size, children, ref, ...props }: ComponentNameProps) { return ( <div ref={ref} className={cn(componentVariants({ variant, size, className }))} {...props}> {children} </div> ); }

export { ComponentName };

index.ts 템플릿

export { ComponentName } from "./ComponentName"; export type { ComponentNameProps } from "./types";

Composition Pattern (Organism 컴포넌트)

복잡한 컴포넌트는 Context + 서브 컴포넌트 패턴 사용:

// Context 생성 import { createContext, useContext, useState } from "react";

interface ComponentContextValue { expanded: boolean; setExpanded: (value: boolean) => void; }

const ComponentContext = createContext<ComponentContextValue | null>(null);

function useComponentContext() { const context = useContext(ComponentContext); if (!context) { throw new Error("Component 컨텍스트 내에서 사용해야 합니다"); } return context; }

// 메인 컴포넌트 interface ComponentNameProps { children: React.ReactNode; defaultExpanded?: boolean; }

function ComponentName({ children, defaultExpanded = false }: ComponentNameProps) { const [expanded, setExpanded] = useState(defaultExpanded);

return ( <ComponentContext.Provider value={{ expanded, setExpanded }}> <div className="component-wrapper">{children}</div> </ComponentContext.Provider> ); }

// 서브 컴포넌트 function ComponentHeader({ children }: { children: React.ReactNode }) { const { expanded, setExpanded } = useComponentContext(); return ( <div className="component-header" onClick={() => setExpanded(!expanded)}> {children} </div> ); }

function ComponentContent({ children }: { children: React.ReactNode }) { const { expanded } = useComponentContext(); if (!expanded) return null; return <div className="component-content">{children}</div>; }

// 서브 컴포넌트 연결 ComponentName.Header = ComponentHeader; ComponentName.Content = ComponentContent;

export { ComponentName, useComponentContext };

사용:

<ComponentName defaultExpanded> <ComponentName.Header>제목</ComponentName.Header> <ComponentName.Content>내용</ComponentName.Content> </ComponentName>

앱 전용 컴포넌트

앱 전용 컴포넌트는 더 간단하게:

// apps/앱이름/src/components/FeatureCard.tsx

interface FeatureCardProps { title: string; description: string; icon: React.ReactNode; onClick?: () => void; }

export function FeatureCard({ title, description, icon, onClick }: FeatureCardProps) { return ( <div className="rounded-lg border p-4 hover:shadow-md transition-shadow cursor-pointer" onClick={onClick} > <div className="flex items-center gap-3"> {icon} <h3 className="font-semibold">{title}</h3> </div> <p className="mt-2 text-sm text-gray-600">{description}</p> </div> ); }

중요 규칙

React 19 패턴

  • forwardRef 사용하지 않음

  • ref를 props로 직접 받음

  • 불필요한 memo/useMemo/useCallback 피함

TypeScript

  • Props 인터페이스 필수

  • any 사용 금지

스타일링

  • Tailwind CSS 사용

  • cn() 유틸리티로 클래스 병합

  • CVA로 variant 관리

Export

  • named export만 사용 (default export 금지)

  • 타입도 함께 export

문서화

  • JSDoc 주석 추가

  • @example 포함

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

cesium-expert

No summary provided by upstream source.

Repository SourceNeeds Review
General

streaming-expert

No summary provided by upstream source.

Repository SourceNeeds Review
General

three-expert

No summary provided by upstream source.

Repository SourceNeeds Review
General

image-gen

Generate AI images from text prompts. Triggers on: "生成图片", "画一张", "AI图", "generate image", "配图", "create picture", "draw", "visualize", "generate an image".

Archived SourceRecently Updated