f0-move-component

star 25

Use when moving an F0 component from one Storybook section to another. Covers folder moves, deprecated re-exports for backward compatibility, and bulk import updates across the codebase.

factorialco By factorialco schedule Updated 6/10/2026

name: f0-move-component description: Use when moving an F0 component from one Storybook section to another. Covers folder moves, deprecated re-exports for backward compatibility, and bulk import updates across the codebase.

f0-move-component

PURPOSE: Step-by-step instructions for moving a component between sections in the F0 design system (packages/react/src/), preserving backward compatibility and keeping all imports consistent.


Storybook Sections Reference

All sections are registered in packages/react/.storybook/main.ts via { directory, titlePrefix } entries.

Source folder titlePrefix Notes
src/components Components All public F0 components
src/patterns Patterns
src/kits Kits
src/experimental Experimental Legacy only — do NOT add new components here
src/layouts Layouts Page layout components
src/lib Library Internal utilities and providers
src/hooks Library Public exported hooks
src/sds SDS Satellite design systems
src/examples Examples Full-app example stories
src/ui 🔒 Internal Radix/shadcn primitive wrappers — not public

If the destination section is not in this table, see Adding a new section before continuing.


Workflow

Step 1 — Move the entire folder

Move the component folder as-is. Do not rename anything inside it.

mv packages/react/src/<source>/<ComponentName> packages/react/src/<destination>/<ComponentName>

Example — moving F0Button from components to kits:

mv packages/react/src/components/F0Button packages/react/src/kits/F0Button

Step 2 — Do NOT rename any story's title field

The titlePrefix in main.ts is prepended automatically by Storybook. The title field inside each .stories.tsx file only needs the component-relative path — never the section name.

// BEFORE move — lives in src/components/F0Button/__stories__/F0Button.stories.tsx
// Storybook renders it as: Components/F0Button
const meta: Meta<typeof F0Button> = {
  title: "F0Button",  // ← do not touch this
  ...
}

// AFTER move — now lives in src/kits/F0Button/__stories__/F0Button.stories.tsx
// Storybook renders it as: Kits/F0Button  ← section changes automatically
const meta: Meta<typeof F0Button> = {
  title: "F0Button",  // ← still unchanged
  ...
}

Step 3 — Add a deprecated re-export in the source section's exports.ts

This preserves backward compatibility for any consumer importing from the old path.

Locate (or create) the exports.ts file at the root of the source section folder and add a @deprecated re-export pointing to the new location.

Pattern:

/** @deprecated <ComponentName> has moved to @/<destination>/<ComponentName>. Import from there instead. */
export * from "../<destination>/<ComponentName>"

Example — after moving F0Button from components to kits:

// packages/react/src/components/exports.ts
/** @deprecated F0Button has moved to @/kits/F0Button. Import from there instead. */
export * from "../kits/F0Button"

If exports.ts does not exist in the source section, create it with only the deprecated re-export line above.


Step 4 — Update all imports across the codebase

4a — Update @/ alias imports

Replace every occurrence of the old @/ alias import path with the new canonical path.

Dry-run first (lists affected files without modifying them):

grep -r "@/<source>/<ComponentName>" packages/react/src \
  --include="*.ts" --include="*.tsx" -l

Apply the replacement:

find packages/react/src -type f \( -name "*.ts" -o -name "*.tsx" \) \
  -exec sed -i '' 's|@/<source>/<ComponentName>|@/<destination>/<ComponentName>|g' {} +

Example — updating imports after moving F0Button from components to kits:

# Dry-run
grep -r "@/components/F0Button" packages/react/src --include="*.ts" --include="*.tsx" -l

# Apply
find packages/react/src -type f \( -name "*.ts" -o -name "*.tsx" \) \
  -exec sed -i '' 's|@/components/F0Button|@/kits/F0Button|g' {} +

The deprecated re-export added in Step 3 means existing consumers outside packages/react/src (e.g., the Factorial app) continue to work unchanged until they migrate to the new path.


4b — Check and fix relative imports inside the moved component

Files inside the moved component may use relative imports that point to sibling folders that stayed behind (e.g., ../../../components/Charts/utils/colors). These break silently because sed on @/ paths does not touch relative paths.

Find broken relative imports inside the moved component:

grep -r "\.\." packages/react/src/<destination>/<ComponentName> \
  --include="*.ts" --include="*.tsx" | grep "<source>"

Also check files that were NOT moved but imported FROM the moved component using relative paths:

grep -r "<source>/<ComponentName>" packages/react/src \
  --include="*.ts" --include="*.tsx" | grep "\.\."

Fix by converting broken relative paths to @/ alias paths:

# Example: inside the moved component, relative refs to a sibling that stayed behind
find packages/react/src/<destination>/<ComponentName> -type f \( -name "*.ts" -o -name "*.tsx" \) \
  -exec sed -i '' 's|\.\./\.\./\.\./\.<source>/SiblingFolder|@/<source>/SiblingFolder|g' {} +

Rule of thumb: after moving, all cross-component imports inside the destination folder should use @/ alias paths, never relative paths that cross folder boundaries outside the component itself.


Step 5 — Verify

Run all checks from packages/react/:

pnpm tsc        # type-check — catches broken imports
pnpm lint       # lint
pnpm vitest:ci  # unit tests

Fix any errors before committing.


Checklist

Use this before opening a PR:

  • Component folder moved to destination section
  • No title field modified in any .stories.tsx file
  • @deprecated re-export added to src/<source>/exports.ts
  • Re-export uses export * from "../<destination>/<ComponentName>"
  • All @/<source>/<ComponentName> imports updated to @/<destination>/<ComponentName>
  • Relative imports inside the moved component inspected — broken cross-boundary relative paths converted to @/ alias paths
  • pnpm tsc passes with no errors
  • pnpm lint passes with no errors
  • pnpm vitest:ci passes

Adding a new section

If the destination folder is not registered in main.ts, add an entry to the stories array before moving any component:

// packages/react/.storybook/main.ts
stories: [
  // ... existing entries ...
  {
    directory: "../src/<new-folder>",
    titlePrefix: "<New Section Label>",
  },
],

Create the folder if it does not exist:

mkdir -p packages/react/src/<new-folder>

Then continue from Step 1.


Real-world examples from the codebase

These existing deprecated re-exports follow the same pattern described above and can be used as reference:

// src/components/exports.ts
/** @deprecated UpsellingKit has moved to @/sds/UpsellingKit. Import from there instead. */
export * from "../sds/UpsellingKit/exports"

// src/experimental/exports.ts
/** @deprecated Banners has moved to @/sds/ai/Banners. Import from there instead. */
export * from "../sds/ai/Banners/exports"

// src/ai/exports.ts
/**
 * @deprecated This path is deprecated. Import from '@factorial/f0/sds/ai' instead.
 * This re-export will be removed in a future version.
 */
export * from "../sds/ai/exports"
Install via CLI
npx skills add https://github.com/factorialco/f0 --skill f0-move-component
Repository Details
star Stars 25
call_split Forks 4
navigation Branch main
article Path SKILL.md
More from Creator