- TypeScript 91.2%
- JavaScript 8.8%
|
All checks were successful
ci / check (push) Successful in 12s
Drops the double-quote-JSX-attributes exception (jsx-quotes: prefer-double -> prefer-single) so the whole repo reads as one consistent quoting convention instead of the mixed Prettier-style pairing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Reviewed-on: #9 |
||
|---|---|---|
| .forgejo/workflows | ||
| .storybook | ||
| src | ||
| stories | ||
| .env.example | ||
| .gitignore | ||
| bun.lock | ||
| bunfig.toml | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile.dev | ||
| eslint.config.cjs | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsup.config.ts | ||
@chrisharrington/design-system
Shared design-system package (colors/tokens, form field components) for the budget-tracker/app
and irrigo/app React Native / Expo apps. Not published to a registry — consumers pull it in via
bun's link: protocol against a local checkout of this repo.
Any infrastructure added here (build tooling, packaging, module resolution, native modules, etc.)
must stay Expo-compatible. See CLAUDE.md for the durable constraint.
Status
Core tooling, plus default design tokens — build pipeline, TypeScript config, and a Tailwind
preset (designSystemPreset) exposing the default theme's semantic colors, typography (sizes,
weights, and font family), and radii, all defined in src/tokens.ts. React Hook Form is wired up
(src/form.ts), with Text (src/Text/) as the first field component — see "Component file
structure" in CLAUDE.md for the folder convention future field components follow.
Consuming this package
This package is not published — consumers link to a local checkout instead of installing from a registry.
-
In the consumer app's
package.json, add alink:dependency pointing at a sibling checkout of this repo. Bothbudget-tracker/appandirrigo/appsit one level deeper than their repo root, so the path is../../design-system, not../design-system:{ "dependencies": { "@chrisharrington/design-system": "link:../../design-system" } }Then run
bun installin the consumer app. This package'sdist/is gitignored, so abun installin the consumer runs this package'spreparescript (tsup) via the link, buildingdist/on first install. -
Package-exports resolution (the
exportsmap in this package'spackage.json) is enabled by default in current Expo/Metro (SDK 53+), so nometro.config.jschange should be needed for a consumer on those SDKs. Metro requests areact-nativecondition during resolution, which this package'sexports["."]map lists first — soimport { Text } from "@chrisharrington/design-system"resolves todist/native/under Metro and todist/(the web build) under any other bundler (Vite, webpack, Node, Storybook, Jest/bun test), with no separate import path for consumers to choose between. As a fallback for a consumer whose Metro config predates package-exports support (or has it disabled), the package also sets a root-level"react-native"field pointing atdist/native/index.js— older/non-exports-aware resolvers check that field before falling back to"main"(the web build), so a misconfigured Metro setup still gets the native bundle instead of silently shipping DOM markup into a native app.
This flow is documented but not yet exercised against a real consumer app — that verification is tracked separately.
Storybook
Storybook renders through @storybook/react-vite + react-native-web (not
@storybook/react-native — there's no RN/Expo scaffold, simulator, or device in this repo's
headless dev container). .storybook/main.ts aliases react-native imports to
react-native-web at bundle time, so stories can import RN primitives (View, Text, etc.) the
same way a real component would.
Running it:
docker compose up -d storybook, then openhttp://localhost:${STORYBOOK_PORT}(see.envfor the port on this checkout). This is the only route reachable from the host — thedevservice doesn't publish any ports.- Or, from a shell already inside the
devcontainer (e.g. VS Code's Dev Containers extension):bun run storybookserves on port 6006 inside that container, but isn't reachable from the host sincedevpublishes no ports — use this only when you're also browsing from inside the container.
Adding a story for a new component: co-locate ComponentName.stories.tsx next to the
component under src/ — the glob in .storybook/main.ts already picks up
src/**/*.stories.@(ts|tsx). Use stories/ExampleCard.stories.tsx's Meta/StoryObj shape
(title, component, args) as the copy-paste template for the story file — that part generalizes.
stories/ExampleCard.tsx itself is Storybook-only scaffolding, not a component to build on: it
styles via useTheme() + inline styles for demo purposes only, whereas a real design-system
component styles via NativeWind classNames from designSystemPreset (compile-time) and must
never import useTheme() / .storybook/theme-context.
Theme switcher: the toolbar's "Theme" dropdown (in the Storybook UI) switches between the
themes registered in .storybook/themes.ts, each a full ThemeTokens object (see
src/tokens.ts) applied via a .storybook/theme-context.tsx ThemeProvider decorator. To add a
new theme, add an entry to the themes record in .storybook/themes.ts — no other wiring is
needed. This context is Storybook-only dev tooling; it isn't exported from src/index.ts, since
production theming for consumers stays compile-time-only via the Tailwind preset.