How Figma Dev Mode shows real @prepared911/ui snippets, where the templates live, and the check that keeps them honest.
@prepared911/ui component and props. The reference file is the Axon 911 Design System in Figma. A Figma component set maps to a code component only when its properties mirror the code props: same names, same values, same defaults.
Each template sits beside the component it maps and is owned by the same team.
| Unit | Template |
|---|---|
| Component | packages/ui/src/components/<id>/<id>.figma.ts |
| Block | packages/ui/src/blocks/<id>/<id>.figma.ts |
figma.code template. It starts with three header lines and ends with a default export that has an id:
pnpm --filter @prepared911/ui code-connect:check runs in ci:gates and check. It fails when:
scripts/code-connect/unmapped-baseline.json;source or component does not resolve, a header line is missing, or the url is outside the Design System file;| Figma property | Template |
|---|---|
BOOLEAN | getBoolean("Loading") |
VARIANT whose options are False and True (boolean as a variant: Disabled, Icon only) | getEnum("Disabled", { False: false, True: true }). getBoolean is for BOOLEAN properties only; the drift check flags it on a variant. The axis is named for the code prop in sentence case. When there is no such prop, the axis picks a branch of a union (Icon only picks icon plus label instead of children) and the template says so in a constant. |
VARIANT with a third option (Toggle: None, Off, On) | getEnum to lowercase words ("none", "off", "on"), then derive the props from the words. |
VARIANT that is an enum in code (Intent, Variant, Size) | getEnum with one entry per Figma option, mapped to the enum member ("ButtonIntent.Accent"). |
TEXT, SLOT | getString, getSlot. Copy is a copy("...") placeholder, never the Figma text (ADR 0009). |
State, Scene, Story) exist so Figma can draw a look the browser makes by itself. Never invent a prop for one. Apply the first rule that fits:
State=Pressed emits active.// line at the top of the snippet that names the pseudo-class, and no prop. Button State=Hover and State=Focus do this.Scene): do not read it, and list it in the header as // story-only=Scene.// retired=Show label,Pressed. The drift check then stops asking for a mapping and reminds you to remove it from Figma. Anything that a snippet cannot express is written down in the component's table below.
2072:3) has these properties: Intent, Variant, Size, Disabled, State, Icon only, Toggle, Loading, Show leading, Show trailing, Label, Leading and Trailing. Show label and Pressed are retired: Icon only and Toggle replace them.
| Figma | Snippet |
|---|---|
Icon only=True | icon={<Leading />} and label={copy(...)}, no children, no leading or trailing |
Icon only=False | children, plus leading and trailing when Show leading and Show trailing are on |
Toggle=On | pressed and onPressedChange={handlePressedChange} |
Toggle=Off | pressed={false} and onPressedChange={handlePressedChange} |
Toggle=None | no toggle props |
State=Rest | nothing |
State=Pressed | active (data-pressed, no aria-pressed), except on a toggle, where active is not defined |
State=Hover | a comment: the browser paints :hover, Button has no prop that forces it |
State=Focus | a comment: the browser paints :focus-visible, Button has no prop that forces it |
Disabled=True | disabled |
Loading on | loading and loadingLabel={copy(...)}, except on a toggle, where loading is not defined |
tooltip, type, pressedIcon, defaultPressed, preventFocusOnPress, className and native attributes have no Figma property. Hover and Focus cannot be set in code at all. handlePressedChange and the copy keys are placeholders the developer fills in.
code-connect:check reads only the repository, so it cannot see Figma change under a template. code-connect:drift closes that gap:
getBoolean on a variant);getEnum map that skips an option the set gained, or names one it lost;// story-only= or // retired=.code-connect-drift workflow runs it every night and on demand with the FIGMA_ACCESS_TOKEN repository secret, and a failed run is the alert. It is not a pull request check and not a required check.
publish --dry-run does need one: it lists the files it would publish, then exits 1 with "Couldn't find a Figma access token". Publishing is a separate, manual step; see the Figma Code Connect decision record in packages/ui/docs/decisions/0030-figma-code-connect.md.