Skip to content

Latest commit

 

History

History
180 lines (130 loc) · 8.25 KB

File metadata and controls

180 lines (130 loc) · 8.25 KB

unoff-ui — Claude Code Guide

A multi-theme React component library for building plugins and tools targeting Figma, Penpot, Sketch, and Framer. Published as @unoff/ui.


Project structure

src/
  components/         # Component source files (7 categories)
  stories/            # Storybook stories and MDX docs
  styles/             # Global SCSS: layouts, texts, colors, icons, token modules
  types/              # Shared TypeScript types (icon.types.ts, list.types.ts…)
  index.ts            # Single public export entry point

tokens/platforms/     # DTCG-format JSON design tokens per platform theme
terrazzo/             # Terrazzo build configs that compile tokens → SCSS vars
scripts/              # build-scss.js, create-theme.js
docs/                 # Specs — treat each .md as the authoritative spec for its topic (theme generator, Terrazzo pipeline, …)
.claude/skills/       # Claude Code skills → see .claude/skills/
dist/                 # Build output (never edit)

Component categories

Folder Examples
actions Button, Accordion, Card, Knob, Menu, Segmented Control
assets Icon, Avatar, Text, SectionTitle, Thumbnail
dialogs Dialog, Message, Notification, Consent, SemanticMessage
inputs Input, Select, Dropdown, SimpleSlider, MultipleSlider
lists ActionsItem, ColorItem, DraggableItem, Tabs, MembersList
slots Bar, FormItem, Section, Layout, Drawer, PopIn
tags Chip, Tooltip, ColorChip, IconChip

Each component lives in src/components/{category}/{kebab-name}/ and contains at minimum:

  • {ComponentName}.tsx
  • {component-name}.scss

Some components also have a styles/ subfolder and/or a {ComponentName}.figma.tsx Code Connect file.


Key conventions

Components are class-based React

All components use React.Component<Props, State>. Do not introduce function components or hooks in the main component source — use the existing class pattern.

export default class MyComp extends React.Component<MyCompProps> {docs
  static defaultProps: Partial<MyCompProps> = {}
  render() {  }
}

Path aliases (tsconfig + vite)

Alias Resolves to
@components/* src/components/*
@styles/* src/styles/*
@tps/* src/types/*
@stories/* src/stories/*

Never use relative cross-directory imports (../../). Use aliases.

SCSS token system

All visual values come from CSS custom properties generated by Terrazzo from the JSON token files. Naming convention:

--{component-kebab}-{variant}-{property}-{state}

Example: --button-primary-background-color-hover

The SCSS file for each component:

  1. Imports all four platform themes at the top:
    @import 'styles/penpot';
    @import 'styles/sketch';
    @import 'styles/figma';
    @import 'styles/framer';
  2. Uses only CSS variables for every themeable value — no hardcoded colors, spacing, radii, or font values.
  3. Overrides base variables per variant and per interaction state using the pattern in src/components/actions/button/button.scss.

Theme activation (runtime)

Themes are activated via HTML attributes on the root element:

document.documentElement.setAttribute('data-theme', 'figma')
document.documentElement.setAttribute('data-mode', 'figma-dark')

Available themes: figma · penpot · sketch · framer Available modes: {theme}-light · {theme}-dark (plus figjam for figma)

Public exports

All public exports go through src/index.ts. Components are grouped by category. Props interfaces are exported as named types at the bottom of the file. Keep entries in alphabetical order within each group.


Token pipeline

tokens/platforms/{theme}/*.json   (DTCG format)
        ↓  npm run scss:build -- --build theme={theme}
        ↓  Terrazzo (terrazzo/{theme}/*.js configs)
src/styles/tokens/{theme}-colors.scss
src/styles/tokens/{theme}-types.scss
src/styles/tokens/modules/{theme}-colors.module.scss   (re-exported via index.ts)
src/styles/tokens/modules/{theme}-types.module.scss

Token JSON files live in tokens/platforms/{theme}/ — for full pipeline documentation see docs/terrazzo-guide.md:

  • color.json — color palette (DTCG $type: "color")
  • text.json — typography tokens
  • icon.json — icon file paths
  • typography.json — composite typography tokens
  • components/ — per-component tokens

Available npm scripts

Script What it does
npm run storybook Start Storybook dev server on port 6006
npm run build TypeScript check + Vite library build → dist/
npm run test:storybook Run Vitest interaction tests (Storybook play functions)
npm run lint ESLint (TS/TSX)
npm run lint:css Stylelint (CSS/SCSS)
npm run format Prettier check
npm run format:fix Prettier auto-fix
npm run create:theme Interactive new-theme generator — see docs/theme-generator.md
npm run scss:build -- --build theme={name} Compile token JSON → SCSS for a specific theme
npm run figma:publish Publish Code Connect to Figma

Storybook

Stories live in src/stories/{category}/. Each story file exports one named story per meaningful component variant. Every story should include a play function with at least:

  • Presence assertion (toBeInTheDocument)
  • Primary interaction test (click, hover, or keyboard)
  • args.action call count assertion where applicable

MDX documentation files ({CategoryTitle}.mdx) use <DocTabs> / <Tab> from src/stories/_docs/DocTabs.tsx to separate Usage and Accessibility (WCAG 2.2) guidance.


Skills

Three Claude Code skills are available in .claude/skills/:

Skill File Invoke with Purpose
create-component .claude/skills/create-component.md /create-component Scaffold a new component end-to-end
create-theme .claude/skills/create-theme.md /create-theme Create and configure a new brand theme
figma-doc .claude/skills/figma-doc.md /figma-doc Generate a Figma component description

What NOT to do

  • Do not hardcode any color, spacing, radius, or font value in SCSS — use CSS variables only.
  • Do not add imports via relative cross-directory paths — use @components/, @styles/, @tps/.
  • Do not create function components or hooks in component source files.
  • Do not edit files in dist/.
  • Do not commit changes to .storybook/preview.tsx theme arrays manually — the create:theme script handles it.
  • Do not use npm run scss:build without -- --build theme=… — without the flag it only lists files.