Skip to main content

creating-components

Use when creating new UI components in packages/ui. Covers component structure, tests, stories, and what to avoid.

معلومات المصدر

المستودع
nukeop/asteroid-miner
آخر نشاط في المصدر
٨ مارس ٢٠٢٦ في ٠٣:٠٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
creating-components
description
Use when creating new UI components in packages/ui. Covers component structure, tests, stories, and what to avoid.
# Creating UI Components ## Component Structure ``` packages/ui/src/components/MyComponent/ ├── MyComponent.tsx # Implementation ├── MyComponent.test.tsx # Tests ├── index.ts # Re-exports └── __snapshots__/ # Vitest snapshots (auto-generated) ``` After creating, export from `packages/ui/src/components/index.ts`. ## Implementation Pattern ```tsx import { cva, VariantProps } from 'class-variance-authority'; import { ComponentProps, FC } from 'react'; import { cn } from '../../utils'; const variants = cva('base-classes', { variants: { /* ... */ }, defaultVariants: { /* ... */ }, }); type MyComponentProps = ComponentProps<'div'> & VariantProps<typeof variants>; export const MyComponent: FC<MyComponentProps> = ({ className, variant, ...props }) => ( <div className={cn(variants({ variant, className }))} {...props} /> ); ``` ## Tests **What to test:** - Snapshots (1-2 covering key variants) - User interactions - Behavior (callbacks called with correct args) **What NOT to test:** - CSS classes, attributes (use snapshots instead) - Internal state - Things TypeScript already enforces **Consolidate tests.** One test can cover multiple related assertions. An exception to that is snapshot tests - one snapshot per variant/state. ## Stories Create `packages/storybook/src/MyComponent.stories.tsx`. **One story can show multiple related variants.** For example, it's wasteful to create a story for each variant of a button. Put them all together in one place. Don't create separate stories for each variant: ```tsx import { Meta, StoryObj } from '@storybook/react-vite'; import { useState } from 'react'; import { MyComponent } from '@nuclearplayer/ui'; const meta = { title: 'Components/MyComponent', component: MyComponent, tags: ['autodocs'], } satisfies Meta<typeof MyComponent>; export default meta; type Story = StoryObj<typeof MyComponent>; export const AllVariants: Story = { render: () => { const [state, setState] = useState(initialState); return ( <div className="flex flex-col gap-4"> {/* Show all variants, states, interactions */} </div> ); }, }; ``` This isn't an iron rule, sometimes it will make more sense to have separate stories. Don't run storybook build checks. ## Avoiding Duplication Before creating a new component, check if an existing one can be extended. **Pattern: Discriminated unions for mode variants** Example: Instead of creating `SingleSelect` and `MultiSelect` components: ```tsx type Props = | { multiple?: false; selected: string; onChange: (id: string) => void } | { multiple: true; selected: string[]; onChange: (ids: string[]) => void }; ``` TypeScript enforces correct types based on the `multiple` prop. ## Classes for customization Where it's likely that a component will need custom styling, expose a `className` prop. If there are many parts that may need styling, consider exposing a `classes` prop with specific class names for each part. Define a type for the `classes` prop. Refer to `packages/ui/src/components/TrackTable/types.ts` for an example. ## Strings All user-facing strings go through i18n - no hardcoded UI text. If a new component in the ui package needs labels and other kinds of localized text, it should accept a `labels` prop with the relevant strings. The prop should have its own type defined. Refer to `packages/ui/src/components/QueueItem/types.ts` for an example. ## Accessibility This is a videogame: it needs to be playable on a wide range of computers, and playable with keyboard + mouse, or gamepad. We need to follow accessibility best practices. ## Checklist - [ ] Component in `packages/ui/src/components/MyComponent/` - [ ] Exported from `packages/ui/src/components/index.ts` - [ ] Tests cover behavior, not implementation - [ ] Tests consolidated (not one per variant) - [ ] One story showing all variants - [ ] No CSS class assertions in tests - [ ] No duplicate component when extending existing one works
عرض على GitHub