Foundations

Contributing

Flatpay Lab ships one design system. Every prototype consumes it. When the system doesn't fit, the path is to contribute back — not fork. Four paths cover every case.

Documented

Overview

The full contributor guide lives in CONTRIBUTING.md on the repo. This page is the cheat-sheet for what to reach for when the system doesn't fit your prototype.

Build with what's there first

Most prototypes ship without ever needing to contribute back — the system is wide enough. Reach for @flatpay-dk/ui components first; reach for tokens (var(--background-accent-orange-subtlest)…) second. Only when neither fits do you start one of the four paths below.

1 · Extend an existing component

You're using a component and need a prop, variant, or behaviour it doesn't have today. Modify the file in packages/ui/src/components/<name>.tsx and add a changeset.

bash

pnpm changeset
# pick @flatpay-dk/ui, choose patch / minor / major, write a one-line summary

# Edit the component:
$EDITOR packages/ui/src/components/banner.tsx

# Update the matching specimen so the doc page picks up the new variant:
$EDITOR apps/portal/components/docs/banner-specimens.tsx

pnpm --filter @flatpay-dk/ui typecheck
pnpm --filter @flatpay-dk/portal typecheck

2 · Promote a prototype-local pattern

You built something in your prototype that turned out to be useful enough that other prototypes will want it. Lift it into the package, replace inline hex with token vars, write the doc page, flip the nav status.

bash

# 1. New file in the package
$EDITOR packages/ui/src/components/<new-name>.tsx

# 2. Export from the index
$EDITOR packages/ui/src/index.ts

# 3. Doc page following the Button-template anatomy
$EDITOR apps/portal/app/docs/components/<group>/<slug>/page.tsx

# 4. Specimen file
$EDITOR apps/portal/components/docs/<slug>-specimens.tsx

# 5. Flip nav status from "unstarted" / "in-progress" → "documented"
$EDITOR apps/portal/lib/docs/nav.ts

# 6. Changeset
pnpm changeset

3 · Add a new token

The token source of truth is the Figma export at apps/portal/lib/docs/figma-color-export.json. Update the JSON, regenerate the CSS, ship.

bash

# 1. Replace the JSON with the latest Figma export.
$EDITOR apps/portal/lib/docs/figma-color-export.json

# 2. Regenerate tokens.css.
pnpm --filter @flatpay-dk/ui tokens:generate

# 3. Verify the new vars resolve cleanly.
pnpm --filter @flatpay-dk/ui typecheck

# 4. Changeset.
pnpm changeset

4 · File debt

Your prototype must ship before the system can absorb the change. The work belongs in @flatpay-dk/ui eventually, but not today. Open an issue, stamp the line, list it on your manifest.

tsx

// In your prototype source — stamp the line with a reason + issue link
// @flatpay-extend Banner — adds 'tide' tone, contribute back via #142
<Banner tone="tide" />

json

// In your prototype's flatpay.json
{
  "designSystem": {
    "uiVersion": "0.4.2",
    "contributions": [
      {
        "type": "debt",
        "target": "Banner",
        "description": "Local override for the critical tone — to be promoted.",
        "issueUrl": "https://github.com/FLATPAY-DK/lab-ui/issues/142"
      }
    ]
  }
}

The portal renders open contributions on the prototype detail page. CI greps the repo for @flatpay-extend markers and posts them on every PR so they don't get forgotten.

What not to do

  • Don't install a parallel design system. ESLint blocks @radix-ui, @headlessui, @mui/* (icons OK), @chakra-ui, @mantine, react-aria-components.
  • Don't add raw hex literals. Inline style hexes and Tailwind arbitrary values like bg-[#fed2a9] are both flagged.
  • Don't ignore the layering rule. Hero opens on subtlest; cards on canvas use subtler; inner highlights use subtle.
  • Don't fork the system. A prototype-local copy of an existing component with one tweak is a contribution waiting to be made. File debt and follow up.

Releases

Five packages are versioned with Changesets: @flatpay-dk/ui, @flatpay-dk/tailwind-preset, @flatpay-dk/manifest, @flatpay-dk/eslint-config, and @flatpay-dk/create-prototype. PRs touching packages/*/src should include a changeset; the release workflow opens a “Version packages” PR on merge that bumps versions and triggers the publish to the private registry.