Skip to content

Commit cc8f10f

Browse files
anth-volkclaude
andcommitted
Initial release: @policyengine/ui-kit component library
Self-contained React 19 + Tailwind CSS v4 component library with 24 components across 6 categories (primitives, layout, inputs, display, charts, tokens). Includes all PE design tokens copied from design-system, Recharts chart components with PE branding, and CVA-based variant system mirroring app-v2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0 parents  commit cc8f10f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2996
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules/
2+
dist/
3+
*.tsbuildinfo
4+
.env
5+
.env.*
6+
!.env.example
7+
bun.lock

CLAUDE.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# @policyengine/ui-kit
2+
3+
PolicyEngine UI kit — design tokens, Tailwind CSS v4 theme, and React 19 components for dashboards and calculators.
4+
5+
## Commands
6+
7+
- Install: `bun install`
8+
- Build: `bun run build`
9+
- Test: `bun run test`
10+
- Type check: `bun run typecheck`
11+
12+
## Architecture
13+
14+
- **Vite library mode** — builds ESM + CJS + types + styles.css
15+
- **Tailwind CSS v4** with `tw:` prefix (mirrors policyengine-app-v2)
16+
- **CVA** (class-variance-authority) for component variants
17+
- **Recharts** for chart components (peer dependency)
18+
19+
## Design tokens
20+
21+
Tokens are in `src/tokens/` — colors, typography, spacing, charts. These are the source of truth for all PolicyEngine applications. The same values appear as CSS custom properties in `src/app.css` via the `@theme` block.
22+
23+
## Styling rules
24+
25+
- All Tailwind classes use `tw:` prefix (e.g. `tw:bg-primary-500`)
26+
- Use `cn()` from `src/utils/cn.ts` for class merging
27+
- Never hardcode hex colors — use token classes or imports
28+
- Sentence case for all UI text
29+
- Every component accepts `className` and `styles` props

package.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"name": "@policyengine/ui-kit",
3+
"version": "0.1.0",
4+
"type": "module",
5+
"main": "dist/index.cjs",
6+
"module": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"exports": {
9+
".": {
10+
"types": "./dist/index.d.ts",
11+
"import": "./dist/index.js",
12+
"require": "./dist/index.cjs"
13+
},
14+
"./styles.css": "./dist/styles.css"
15+
},
16+
"files": [
17+
"dist"
18+
],
19+
"scripts": {
20+
"dev": "vite",
21+
"build": "vite build && mv dist/ui-kit.css dist/styles.css && tsc -p tsconfig.build.json --emitDeclarationOnly",
22+
"test": "vitest run",
23+
"test:watch": "vitest",
24+
"typecheck": "tsc --noEmit",
25+
"lint": "tsc --noEmit"
26+
},
27+
"peerDependencies": {
28+
"react": ">=19",
29+
"react-dom": ">=19",
30+
"recharts": ">=2.12"
31+
},
32+
"dependencies": {
33+
"class-variance-authority": "^0.7.1",
34+
"clsx": "^2.1.1",
35+
"tailwind-merge": "^3.5.0"
36+
},
37+
"devDependencies": {
38+
"@tailwindcss/vite": "^4.2.0",
39+
"@testing-library/jest-dom": "^6.6.3",
40+
"@testing-library/react": "^16.3.0",
41+
"@types/react": "^19.0.0",
42+
"@types/react-dom": "^19.0.0",
43+
"@vitejs/plugin-react": "^4.3.4",
44+
"jsdom": "^25.0.1",
45+
"react": "^19.0.0",
46+
"react-dom": "^19.0.0",
47+
"recharts": "^2.15.0",
48+
"tailwindcss": "^4.2.0",
49+
"typescript": "^5.7.0",
50+
"vite": "^6.3.0",
51+
"vitest": "^3.1.0"
52+
},
53+
"publishConfig": {
54+
"access": "public"
55+
},
56+
"license": "MIT",
57+
"repository": {
58+
"type": "git",
59+
"url": "https://github.com/PolicyEngine/policyengine-ui-kit.git"
60+
}
61+
}

src/app.css

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
@import 'tailwindcss' prefix(tw);
2+
3+
@theme {
4+
/* Primary brand colors - teal */
5+
--color-primary-50: #e6fffa;
6+
--color-primary-100: #b2f5ea;
7+
--color-primary-200: #81e6d9;
8+
--color-primary-300: #4fd1c5;
9+
--color-primary-400: #38b2ac;
10+
--color-primary-500: #319795;
11+
--color-primary-600: #2c7a7b;
12+
--color-primary-700: #285e61;
13+
--color-primary-800: #234e52;
14+
--color-primary-900: #1d4044;
15+
16+
/* Secondary colors - gray scale */
17+
--color-secondary-50: #f0f9ff;
18+
--color-secondary-100: #f2f4f7;
19+
--color-secondary-200: #e2e8f0;
20+
--color-secondary-300: #cbd5e1;
21+
--color-secondary-400: #94a3b8;
22+
--color-secondary-500: #64748b;
23+
--color-secondary-600: #475569;
24+
--color-secondary-700: #344054;
25+
--color-secondary-800: #1e293b;
26+
--color-secondary-900: #101828;
27+
28+
/* Blue accent colors */
29+
--color-blue-50: #f0f9ff;
30+
--color-blue-100: #e0f2fe;
31+
--color-blue-200: #bae6fd;
32+
--color-blue-300: #7dd3fc;
33+
--color-blue-400: #38bdf8;
34+
--color-blue-500: #0ea5e9;
35+
--color-blue-600: #0284c7;
36+
--color-blue-700: #026aa2;
37+
--color-blue-800: #075985;
38+
--color-blue-900: #0c4a6e;
39+
40+
/* Gray scale */
41+
--color-gray-50: #f9fafb;
42+
--color-gray-100: #f2f4f7;
43+
--color-gray-200: #e2e8f0;
44+
--color-gray-300: #d1d5db;
45+
--color-gray-400: #9ca3af;
46+
--color-gray-500: #6b7280;
47+
--color-gray-600: #4b5563;
48+
--color-gray-700: #344054;
49+
--color-gray-800: #1f2937;
50+
--color-gray-900: #101828;
51+
52+
/* Semantic colors */
53+
--color-success: #22c55e;
54+
--color-warning: #fec601;
55+
--color-error: #ef4444;
56+
--color-info: #1890ff;
57+
58+
/* Background colors */
59+
--color-bg-primary: #fff;
60+
--color-bg-secondary: #f5f9ff;
61+
--color-bg-tertiary: #f1f5f9;
62+
63+
/* Text colors */
64+
--color-text-primary: #000;
65+
--color-text-secondary: #5a5a5a;
66+
--color-text-tertiary: #9ca3af;
67+
--color-text-inverse: #fff;
68+
69+
/* Border colors */
70+
--color-border-light: #e2e8f0;
71+
--color-border-medium: #cbd5e1;
72+
--color-border-dark: #94a3b8;
73+
74+
/*
75+
* =========================================================
76+
* shadcn/ui semantic color tokens
77+
* =========================================================
78+
* These are REQUIRED by all shadcn/ui components (Button,
79+
* Badge, Table, Input, Dialog, etc.). They use classes like
80+
* tw:bg-primary, tw:text-foreground, tw:border-border which
81+
* resolve to these CSS variables.
82+
* =========================================================
83+
*/
84+
85+
/* Core foreground/background */
86+
--color-background: #fff;
87+
--color-foreground: #101828;
88+
89+
/* Primary action color (buttons, links, badges) */
90+
--color-primary: #2c7a7b;
91+
--color-primary-foreground: #fff;
92+
93+
/* Secondary (muted buttons, secondary badges) */
94+
--color-secondary: #f2f4f7;
95+
--color-secondary-foreground: #101828;
96+
97+
/* Muted (subtle backgrounds, disabled states) */
98+
--color-muted: #f2f4f7;
99+
--color-muted-foreground: #6b7280;
100+
101+
/* Accent (hover highlights, active states) */
102+
--color-accent: #f2f4f7;
103+
--color-accent-foreground: #101828;
104+
105+
/* Destructive (delete buttons, error states) */
106+
--color-destructive: #ef4444;
107+
108+
/* Popover/dropdown backgrounds */
109+
--color-popover: #fff;
110+
--color-popover-foreground: #101828;
111+
112+
/* Card backgrounds */
113+
--color-card: #fff;
114+
--color-card-foreground: #101828;
115+
116+
/* Border, input, ring (form controls) */
117+
--color-border: #e2e8f0;
118+
--color-input: #e2e8f0;
119+
--color-ring: #319795;
120+
121+
/* Typography */
122+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
123+
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
124+
125+
--font-size-xs: 12px;
126+
--font-size-sm: 14px;
127+
--font-size-base: 16px;
128+
--font-size-lg: 18px;
129+
--font-size-xl: 20px;
130+
--font-size-2xl: 24px;
131+
--font-size-3xl: 28px;
132+
--font-size-4xl: 32px;
133+
134+
/* Spacing */
135+
--spacing-xs: 4px;
136+
--spacing-sm: 8px;
137+
--spacing-md: 12px;
138+
--spacing-lg: 16px;
139+
--spacing-xl: 20px;
140+
--spacing-2xl: 24px;
141+
--spacing-3xl: 32px;
142+
--spacing-4xl: 48px;
143+
--spacing-5xl: 64px;
144+
145+
/* Border radius - semantic scale */
146+
--radius-chip: 2px;
147+
--radius-element: 4px;
148+
--radius-container: 8px;
149+
--radius-feature: 12px;
150+
151+
/* shadcn radius tokens */
152+
--radius-sm: 4px;
153+
--radius-md: 6px;
154+
--radius-lg: 8px;
155+
--radius-xl: 12px;
156+
157+
/* Breakpoints */
158+
--breakpoint-xs: 36rem;
159+
--breakpoint-sm: 48rem;
160+
--breakpoint-md: 62rem;
161+
--breakpoint-lg: 75rem;
162+
--breakpoint-xl: 88rem;
163+
--breakpoint-2xl: 96rem;
164+
165+
/* Layout */
166+
--spacing-sidebar: 79px;
167+
--spacing-sidebar-width: 280px;
168+
--spacing-header: 58px;
169+
--spacing-content: 1361px;
170+
--spacing-container: 976px;
171+
}
172+
173+
/*
174+
* =========================================================
175+
* Base styles
176+
* =========================================================
177+
* Tailwind Preflight resets all HTML elements to a blank
178+
* slate. These base styles restore sensible defaults.
179+
* =========================================================
180+
*/
181+
/*
182+
* IMPORTANT: prefix(tw) causes all @theme variables to be prefixed
183+
* with --tw-. So --font-sans becomes --tw-font-sans, etc.
184+
* All var() references in hand-written CSS must use --tw- prefix.
185+
*/
186+
@layer base {
187+
/* Default border color */
188+
*,
189+
::before,
190+
::after {
191+
border-color: var(--tw-color-border);
192+
}
193+
194+
html {
195+
font-family: var(--tw-font-sans);
196+
font-size: var(--tw-font-size-base);
197+
line-height: 1.55;
198+
color: var(--tw-color-foreground);
199+
-webkit-font-smoothing: antialiased;
200+
-moz-osx-font-smoothing: grayscale;
201+
}
202+
203+
body {
204+
font-family: var(--tw-font-sans);
205+
color: var(--tw-color-foreground);
206+
background-color: var(--tw-color-background);
207+
}
208+
209+
a {
210+
color: inherit;
211+
text-decoration: inherit;
212+
}
213+
214+
table {
215+
border-collapse: collapse;
216+
width: 100%;
217+
}
218+
219+
[data-slot='table-container'],
220+
tr {
221+
background-color: var(--tw-color-bg-primary);
222+
}
223+
224+
th {
225+
text-align: left;
226+
font-weight: 600;
227+
}
228+
229+
button,
230+
input,
231+
select,
232+
textarea {
233+
font-family: inherit;
234+
font-size: inherit;
235+
background-color: var(--tw-color-bg-primary);
236+
}
237+
238+
input[type='number']::-webkit-inner-spin-button,
239+
input[type='number']::-webkit-outer-spin-button {
240+
-webkit-appearance: none;
241+
margin: 0;
242+
}
243+
244+
input[type='number'] {
245+
-moz-appearance: textfield;
246+
}
247+
}

0 commit comments

Comments
 (0)