원문: https://github.com/facebook/astryx/wiki/Component-Authoring-Guide · 번역 기준: 2026-09-03

새 컴포넌트를 end-to-end로 만드시나요? 전체 lifecycle은 Component Lifecycle을 보세요. 구현과 아키텍처 리뷰는 Architecture Cheat Sheet로 시작하고, 상세한 컨벤션은 이 페이지를 활용하세요.

새로운 Astryx 컴포넌트를 만들기 위한 실용 레퍼런스입니다. 파일 구조, StyleX 패턴, token 사용법, 컨벤션을 다룹니다.


File Structure

모든 컴포넌트는 /packages/core/src/ 아래 자신만의 디렉토리에 존재합니다:

/packages/core/src/Button/
├── Button.tsx                 # Main component implementation
├── index.ts                   # Exports
├── Button.doc.mjs             # Typed documentation (JSDoc + ComponentDoc type)
└── Button.test.tsx            # Tests

story는 컴포넌트와 함께 두지 않습니다. story는 Storybook 앱에 컴포넌트당 하나의 파일로 존재합니다:

/apps/storybook/stories/Button.stories.tsx

디렉토리, 파일, export되는 컴포넌트는 모두 컴포넌트의 이름을 공유합니다 — prefix 없이:

Component Directory File Export
Button Button/ Button.tsx Button
Text Input TextInput/ TextInput.tsx TextInput
Stack Stack/ Stack.tsx Stack

Component Documentation ({Name}.doc.mjs)

모든 컴포넌트 디렉토리에는 typed 문서를 export하는 {Name}.doc.mjs 파일이 있습니다. 이는 예전의 README.md 방식을 대체합니다 — 이제 문서는 CLI가 직접 import하는 구조화된 데이터입니다 (markdown 파싱 없음).

Structure

/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
export const docs = {
  name: 'Button',
  description: 'Primary interactive element for user actions.',
  
  features: [
    "Variants: 'primary', 'secondary', 'ghost', 'destructive'",
    'Sizes: sm (28px), md (32px), lg (36px)',
    'Loading state: Shows spinner, disables interaction',
  ],
  
  props: [
    {
      name: 'label',
      type: 'string',
      description: 'Accessible label; used as aria-label for icon-only buttons.',
      required: true,
    },
    {
      name: 'variant',
      type: "'primary' | 'secondary' | 'ghost' | 'destructive'",
      description: 'Visual style variant.',
      default: "'secondary'",
    },
    // ... more props
  ],
  
  examples: [
    {
      label: 'Basic',
      code: '<Button variant="primary">Save</Button>',
    },
    {
      label: 'With icon',
      code: '<Button icon={PlusIcon} variant="secondary">Add</Button>',
    },
  ],
  
  theming: {
    targets: [
      {className: 'astryx-button', visualProps: ['variant', 'size']},
    ],
    vars: [
      {name: '--button-radius', description: 'Border radius', default: 'var(--radius-element)'},
    ],
  },
  
  accessibility: [
    'Uses native <button> element for correct ARIA semantics.',
    'Icon-only buttons use label prop as aria-label.',
  ],
  
  keyboard: 'Enter/Space activates the button; Tab/Shift+Tab moves focus',
  
  notes: [
    'Hover states use backgroundImage overlay pattern for consistent layering.',
  ],
};

Type Checking

ComponentDoc 타입은 @astryxdesign/cli/authoring에서 옵니다 — 상대 경로가 아니라 패키지 이름으로 import하세요. 타입 체크는 다음으로 실행합니다:

pnpm --filter @astryxdesign/core typecheck:docs

이는 tsc --checkJs를 사용해 모든 .doc.mjs 파일을 ComponentDoc 타입에 대해 검증합니다. CI가 이를 자동으로 실행합니다.