Skip to content

Commit d6dadd1

Browse files
authored
chore: kickstart vanilla-extract migration
1 parent 2998bd0 commit d6dadd1

37 files changed

+5853
-96
lines changed

.storybook/main.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { StorybookConfig } from '@storybook/react-vite';
2+
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
23

34
const config: StorybookConfig = {
45
stories: [
@@ -30,6 +31,12 @@ const config: StorybookConfig = {
3031
typescript: {
3132
reactDocgen: 'react-docgen-typescript',
3233
},
34+
35+
async viteFinal(config) {
36+
config.plugins = config.plugins || [];
37+
config.plugins.push(vanillaExtractPlugin());
38+
return config;
39+
},
3340
};
3441

3542
export default config;

.storybook/preview.jsx

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,70 @@ export const parameters = {
4141
},
4242
};
4343

44+
export const globalTypes = {};
45+
4446
const globalStyle = globalCss({
4547
body: {
4648
bc: '$contentBg',
4749
},
4850
});
4951

52+
const VanillaProviderWrapper = ({ children, isDark, primaryColor }) => {
53+
const [Provider, setProvider] = React.useState(null);
54+
const [loading, setLoading] = React.useState(true);
55+
56+
React.useEffect(() => {
57+
import('../styles/themeContext')
58+
.then((module) => {
59+
setProvider(() => module.VanillaExtractThemeProvider);
60+
setLoading(false);
61+
})
62+
.catch((err) => {
63+
console.warn('VanillaExtractThemeProvider failed to load:', err);
64+
setLoading(false);
65+
});
66+
}, []);
67+
68+
if (loading) {
69+
return React.createElement('div', { style: { padding: '24px' } }, 'Loading theme system...');
70+
}
71+
72+
if (Provider) {
73+
return React.createElement(
74+
Provider,
75+
{
76+
forcedTheme: isDark ? 'dark' : 'light',
77+
primaryColor,
78+
},
79+
children,
80+
);
81+
}
82+
83+
// If provider failed to load, just return children (Stitches fallback)
84+
return children;
85+
};
86+
5087
export const decorators = [
5188
(renderStory) => {
89+
const [isDark, setDark] = React.useState(false);
90+
91+
React.useEffect(() => {
92+
darkTheme('blue').toString();
93+
lightTheme('blue').toString();
94+
}, []);
95+
5296
React.useEffect(() => {
53-
darkTheme('neon').toString();
54-
lightTheme('neon').toString();
97+
channel.on(DARK_MODE_EVENT_NAME, setDark);
98+
return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark);
5599
}, []);
56100

57101
return (
58-
<FaencyProvider>
59-
{globalStyle()}
60-
{renderStory()}
61-
</FaencyProvider>
102+
<VanillaProviderWrapper isDark={isDark} primaryColor="blue">
103+
<FaencyProvider>
104+
{globalStyle()}
105+
{renderStory()}
106+
</FaencyProvider>
107+
</VanillaProviderWrapper>
62108
);
63109
},
64110
];

CLAUDE.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Overview
6+
7+
Faency is a React component library and design system for Traefik Labs, built with React, TypeScript, Stitches CSS-in-JS, and Radix UI Primitives. It provides accessible, themed components with light/dark mode support.
8+
9+
## Development Commands
10+
11+
### Core Development
12+
13+
- `yarn install` - Install dependencies
14+
- `yarn patch-package` - Apply necessary patches to Stitches after installation
15+
- `yarn storybook` - Start Storybook development server at http://localhost:6006
16+
- `yarn build` - Build the library for production
17+
- `yarn lint` - Lint TypeScript/React files in components directory
18+
- `yarn lint:fix` - Auto-fix linting issues
19+
- `yarn test` - Run Jest tests in watch mode
20+
- `yarn test:ci` - Run tests in CI mode (silent, non-watch)
21+
22+
### Release
23+
24+
- `yarn release` - Build and publish using semantic-release
25+
26+
## Architecture
27+
28+
### Styling System
29+
30+
- **Stitches CSS-in-JS**: Core styling system with design tokens and utilities
31+
- **Design Tokens**: Defined in `stitches.config.ts` with semantic color system
32+
- **Theme Support**: Light/dark themes with customizable primary colors
33+
- **Component Themes**: Each component has its own theme file (e.g., `Button.themes.ts`)
34+
35+
### Component Structure
36+
37+
Components follow a consistent pattern:
38+
39+
- `ComponentName.tsx` - Main component implementation
40+
- `ComponentName.stories.tsx` - Storybook stories
41+
- `ComponentName.test.tsx` - Jest tests (where applicable)
42+
- `ComponentName.themes.ts` - Theme definitions for light/dark modes
43+
- `index.ts` - Exports
44+
45+
### Key Files
46+
47+
- `stitches.config.ts` - Stitches configuration with design tokens, utilities, and theme setup
48+
- `colors/` - Color palette definitions (light/dark variants)
49+
- `index.ts` - Main library exports
50+
- `components/FaencyProvider.tsx` - Root provider component
51+
52+
### Colors and Theming
53+
54+
- Primary colors: `neon`, `blue`, `orange`, `red`, `green`, `deepBlue`, `grayBlue`
55+
- Dynamic theme generation based on primary color selection
56+
- Component themes support both light and dark variants
57+
- Colors are defined in `/colors/` with systematic naming
58+
59+
### Component Dependencies
60+
61+
- Built on Radix UI Primitives for accessibility
62+
- Uses Stitches for styling with CSS-in-JS
63+
- React 18+ and TypeScript 5+ required
64+
65+
## Development Workflow
66+
67+
### Code Style
68+
69+
- **No Unnecessary Comments**: Do not add obvious or redundant comments. Code should be self-explanatory through clear naming and structure. Only add comments when explaining complex logic, non-obvious decisions, or documenting public APIs.
70+
- **No Unnecessary Emojis**: OK for console warnings/errors, but avoid in code comments or commit messages.
71+
72+
### Adding New Components
73+
74+
1. Create component directory in `/components/`
75+
2. Implement main component with Stitches styling
76+
3. Create theme file with `getLight()` and `getDark()` functions
77+
4. Add Storybook stories with all variants
78+
5. Write Jest tests for critical functionality
79+
6. Export from main `index.ts`
80+
81+
### Working with Themes
82+
83+
- Theme objects must have `getLight(primaryColor)` and `getDark(primaryColor)` methods
84+
- Register new themes in `stitches.config.ts` in both light and dark theme functions
85+
- Use semantic color tokens for consistency
86+
87+
### Testing Strategy
88+
89+
- Jest with React Testing Library setup
90+
- jsdom environment for DOM testing
91+
- Focus on accessibility and component behavior
92+
- Run tests before submitting changes
93+
94+
## Important Notes
95+
96+
- **Patch Required**: Run `yarn patch-package` after installing dependencies to fix Stitches TypeScript 5 compatibility
97+
- **Node Version**: Requires Node.js 20+
98+
- **Conventional Commits**: Follow conventional commit format for semantic releases
99+
- **Accessibility**: All components must be accessible and support keyboard navigation
100+
- **Storybook**: Every component requires comprehensive stories showing all variants

README.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ npm install @traefiklabs/faency@next
2020
yarn add @traefiklabs/faency@next
2121
```
2222

23-
Then you need to wire up the FaencyProvider which will hold the context with the Theme configuration and everything global that the components will need to work well.
23+
#### Using Stitches Components (Current)
24+
25+
Wire up the FaencyProvider which will hold the context with the Theme configuration:
2426

2527
> The provider accepts one parameter besides the `children`, which is the `primaryColor`, that will be used to build the colors used on the Theme. This color can be one of the colors exported by the `Stitches` config, just by adding `$` as a prefix, or can be any string that represents a CSS color.
2628
@@ -44,9 +46,36 @@ const Container = styled(Flex, {
4446
const MyComponent = () => <Container>{children}</Container>;
4547
```
4648

49+
#### Using Vanilla Extract Components (New - Recommended)
50+
51+
For better performance with static CSS, use the new Vanilla Extract components:
52+
53+
1. Import the CSS file in your app's entry point:
54+
55+
```jsx
56+
import '@traefiklabs/faency/dist/style.css';
57+
```
58+
59+
2. Wrap your app with the VanillaExtractThemeProvider:
60+
61+
```jsx
62+
import { VanillaExtractThemeProvider } from '@traefiklabs/faency';
63+
import { BoxVanilla, BadgeVanilla } from '@traefiklabs/faency';
64+
65+
const App = () => (
66+
<VanillaExtractThemeProvider defaultTheme="light" primaryColor="blue">
67+
<BoxVanilla css={{ p: '$4' }}>
68+
<BadgeVanilla variant="blue">Hello Faency!</BadgeVanilla>
69+
</BoxVanilla>
70+
</VanillaExtractThemeProvider>
71+
);
72+
```
73+
74+
> **Note**: Vanilla Extract components use static CSS generated at build time, providing better performance than runtime CSS-in-JS. Components with the `Vanilla` suffix (e.g., `BadgeVanilla`, `BoxVanilla`) require the CSS import above.
75+
4776
## How to contribute
4877

49-
- Make sure you have Node 12+, or if you prefer, you can work in a Docker container:
78+
- Make sure you have Node 18+, or if you prefer, you can work in a Docker container:
5079

5180
```sh
5281
docker run -it -v $(pwd):/usr/local/src/ -w /usr/local/src/ -p 3000:3000 node:latest bash

0 commit comments

Comments
 (0)