@layoutdesign/context 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +57 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/cli/import-zip.d.ts +2 -0
- package/dist/src/cli/import-zip.d.ts.map +1 -0
- package/dist/src/cli/import-zip.js +156 -0
- package/dist/src/cli/import-zip.js.map +1 -0
- package/dist/src/cli/init.d.ts +4 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +104 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/install.d.ts +5 -0
- package/dist/src/cli/install.d.ts.map +1 -0
- package/dist/src/cli/install.js +192 -0
- package/dist/src/cli/install.js.map +1 -0
- package/dist/src/cli/list.d.ts +2 -0
- package/dist/src/cli/list.d.ts.map +1 -0
- package/dist/src/cli/list.js +36 -0
- package/dist/src/cli/list.js.map +1 -0
- package/dist/src/cli/serve.d.ts +2 -0
- package/dist/src/cli/serve.d.ts.map +1 -0
- package/dist/src/cli/serve.js +9 -0
- package/dist/src/cli/serve.js.map +1 -0
- package/dist/src/cli/use.d.ts +2 -0
- package/dist/src/cli/use.d.ts.map +1 -0
- package/dist/src/cli/use.js +54 -0
- package/dist/src/cli/use.js.map +1 -0
- package/dist/src/compliance/checker.d.ts +23 -0
- package/dist/src/compliance/checker.d.ts.map +1 -0
- package/dist/src/compliance/checker.js +31 -0
- package/dist/src/compliance/checker.js.map +1 -0
- package/dist/src/compliance/rules.d.ts +11 -0
- package/dist/src/compliance/rules.d.ts.map +1 -0
- package/dist/src/compliance/rules.js +147 -0
- package/dist/src/compliance/rules.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/kit/loader.d.ts +16 -0
- package/dist/src/kit/loader.d.ts.map +1 -0
- package/dist/src/kit/loader.js +98 -0
- package/dist/src/kit/loader.js.map +1 -0
- package/dist/src/kit/parser.d.ts +21 -0
- package/dist/src/kit/parser.d.ts.map +1 -0
- package/dist/src/kit/parser.js +98 -0
- package/dist/src/kit/parser.js.map +1 -0
- package/dist/src/kit/registry.d.ts +4 -0
- package/dist/src/kit/registry.d.ts.map +1 -0
- package/dist/src/kit/registry.js +91 -0
- package/dist/src/kit/registry.js.map +1 -0
- package/dist/src/kit/types.d.ts +51 -0
- package/dist/src/kit/types.d.ts.map +1 -0
- package/dist/src/kit/types.js +11 -0
- package/dist/src/kit/types.js.map +1 -0
- package/dist/src/mcp/server.d.ts +6 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +56 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/check-compliance.d.ts +16 -0
- package/dist/src/mcp/tools/check-compliance.d.ts.map +1 -0
- package/dist/src/mcp/tools/check-compliance.js +44 -0
- package/dist/src/mcp/tools/check-compliance.js.map +1 -0
- package/dist/src/mcp/tools/design-in-figma.d.ts +24 -0
- package/dist/src/mcp/tools/design-in-figma.d.ts.map +1 -0
- package/dist/src/mcp/tools/design-in-figma.js +202 -0
- package/dist/src/mcp/tools/design-in-figma.js.map +1 -0
- package/dist/src/mcp/tools/get-component.d.ts +16 -0
- package/dist/src/mcp/tools/get-component.d.ts.map +1 -0
- package/dist/src/mcp/tools/get-component.js +52 -0
- package/dist/src/mcp/tools/get-component.js.map +1 -0
- package/dist/src/mcp/tools/get-design-system.d.ts +16 -0
- package/dist/src/mcp/tools/get-design-system.d.ts.map +1 -0
- package/dist/src/mcp/tools/get-design-system.js +51 -0
- package/dist/src/mcp/tools/get-design-system.js.map +1 -0
- package/dist/src/mcp/tools/get-screenshots.d.ts +23 -0
- package/dist/src/mcp/tools/get-screenshots.d.ts.map +1 -0
- package/dist/src/mcp/tools/get-screenshots.js +78 -0
- package/dist/src/mcp/tools/get-screenshots.js.map +1 -0
- package/dist/src/mcp/tools/get-tokens.d.ts +20 -0
- package/dist/src/mcp/tools/get-tokens.d.ts.map +1 -0
- package/dist/src/mcp/tools/get-tokens.js +50 -0
- package/dist/src/mcp/tools/get-tokens.js.map +1 -0
- package/dist/src/mcp/tools/list-components.d.ts +11 -0
- package/dist/src/mcp/tools/list-components.d.ts.map +1 -0
- package/dist/src/mcp/tools/list-components.js +38 -0
- package/dist/src/mcp/tools/list-components.js.map +1 -0
- package/dist/src/mcp/tools/preview.d.ts +21 -0
- package/dist/src/mcp/tools/preview.d.ts.map +1 -0
- package/dist/src/mcp/tools/preview.js +63 -0
- package/dist/src/mcp/tools/preview.js.map +1 -0
- package/dist/src/mcp/tools/push-to-figma.d.ts +24 -0
- package/dist/src/mcp/tools/push-to-figma.d.ts.map +1 -0
- package/dist/src/mcp/tools/push-to-figma.js +101 -0
- package/dist/src/mcp/tools/push-to-figma.js.map +1 -0
- package/dist/src/mcp/tools/update-tokens.d.ts +21 -0
- package/dist/src/mcp/tools/update-tokens.d.ts.map +1 -0
- package/dist/src/mcp/tools/update-tokens.js +187 -0
- package/dist/src/mcp/tools/update-tokens.js.map +1 -0
- package/dist/src/mcp/tools/url-to-figma.d.ts +29 -0
- package/dist/src/mcp/tools/url-to-figma.d.ts.map +1 -0
- package/dist/src/mcp/tools/url-to-figma.js +103 -0
- package/dist/src/mcp/tools/url-to-figma.js.map +1 -0
- package/dist/src/preview/server.d.ts +15 -0
- package/dist/src/preview/server.d.ts.map +1 -0
- package/dist/src/preview/server.js +146 -0
- package/dist/src/preview/server.js.map +1 -0
- package/dist/src/preview/static/index.html +493 -0
- package/dist/src/preview/transpile.d.ts +10 -0
- package/dist/src/preview/transpile.d.ts.map +1 -0
- package/dist/src/preview/transpile.js +40 -0
- package/dist/src/preview/transpile.js.map +1 -0
- package/dist/src/preview/ws.d.ts +17 -0
- package/dist/src/preview/ws.d.ts.map +1 -0
- package/dist/src/preview/ws.js +66 -0
- package/dist/src/preview/ws.js.map +1 -0
- package/kits/linear-lite/DESIGN.md +421 -0
- package/kits/linear-lite/kit.json +12 -0
- package/kits/linear-lite/tokens.css +46 -0
- package/kits/linear-lite/tokens.json +47 -0
- package/kits/notion-lite/DESIGN.md +528 -0
- package/kits/notion-lite/kit.json +12 -0
- package/kits/notion-lite/tokens.css +50 -0
- package/kits/notion-lite/tokens.json +51 -0
- package/kits/stripe-lite/DESIGN.md +539 -0
- package/kits/stripe-lite/kit.json +12 -0
- package/kits/stripe-lite/tokens.css +57 -0
- package/kits/stripe-lite/tokens.json +58 -0
- package/package.json +63 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# Stripe — Design System
|
|
2
|
+
|
|
3
|
+
> Light, clean, high-trust. Precision that converts.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
**Aesthetic:** Clean whites and cool grays communicate reliability. Purple accent is used only where action is required. Typography is native system stack for maximum legibility. Layouts are generous — plenty of breathing room to reduce cognitive load at critical moments.
|
|
10
|
+
|
|
11
|
+
### Colour Palette
|
|
12
|
+
| Role | Token | Value |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| App background | `--stripe-bg-app` | `#F6F9FC` |
|
|
15
|
+
| Card/surface | `--stripe-bg-surface` | `#FFFFFF` |
|
|
16
|
+
| Hover background | `--stripe-bg-hover` | `#F6F9FC` |
|
|
17
|
+
| Border (default) | `--stripe-border` | `#E3E8EE` |
|
|
18
|
+
| Border (strong) | `--stripe-border-strong` | `#C1C9D2` |
|
|
19
|
+
| Border (focus) | `--stripe-border-focus` | `#635BFF` |
|
|
20
|
+
| Primary text | `--stripe-text-primary` | `#1A1F36` |
|
|
21
|
+
| Secondary text | `--stripe-text-secondary` | `#3C4257` |
|
|
22
|
+
| Muted text | `--stripe-text-muted` | `#697386` |
|
|
23
|
+
| Accent | `--stripe-accent` | `#635BFF` |
|
|
24
|
+
| Accent hover | `--stripe-accent-hover` | `#5145E5` |
|
|
25
|
+
| Accent subtle | `--stripe-accent-subtle` | `rgba(99,91,255,0.08)` |
|
|
26
|
+
| Success | `--stripe-success` | `#09825D` |
|
|
27
|
+
| Success bg | `--stripe-success-bg` | `#EBFAF4` |
|
|
28
|
+
| Warning | `--stripe-warning` | `#8D6A00` |
|
|
29
|
+
| Warning bg | `--stripe-warning-bg` | `#FFFAEB` |
|
|
30
|
+
| Error | `--stripe-error` | `#C0123C` |
|
|
31
|
+
| Error bg | `--stripe-error-bg` | `#FFF0F3` |
|
|
32
|
+
| Info | `--stripe-info` | `#0A5494` |
|
|
33
|
+
| Info bg | `--stripe-info-bg` | `#EFF8FF` |
|
|
34
|
+
|
|
35
|
+
### Typography
|
|
36
|
+
- **UI font:** `-apple-system`, BlinkMacSystemFont, Segoe UI, Roboto — via `--stripe-font-sans`
|
|
37
|
+
- **Mono font:** `SF Mono`, Fira Code — via `--stripe-font-mono`
|
|
38
|
+
- Body: 14px / 1.6 line-height, `--stripe-text-secondary`
|
|
39
|
+
- Headings: 18–24px, `--stripe-text-primary`, font-weight 600–700
|
|
40
|
+
- Labels: 13px, `--stripe-text-muted`, font-weight 500
|
|
41
|
+
- Table headers: 12px, uppercase, letter-spacing 0.04em, `--stripe-text-muted`
|
|
42
|
+
|
|
43
|
+
### Spacing Scale
|
|
44
|
+
`4 / 8 / 12 / 16 / 24 / 32 / 48px` — tokens `xs / sm / md / lg / xl / 2xl / 3xl`
|
|
45
|
+
|
|
46
|
+
### Border Radius
|
|
47
|
+
`4px (sm) / 6px (md) / 8px (lg)`
|
|
48
|
+
|
|
49
|
+
### Key Design Rules
|
|
50
|
+
1. **White is the surface colour.** `--stripe-bg-surface` is pure white.
|
|
51
|
+
2. **App background is `#F6F9FC`** — a barely-there blue-gray that makes white cards pop.
|
|
52
|
+
3. **Borders use real colour** (not opacity-based) for consistent rendering on all backgrounds.
|
|
53
|
+
4. **Shadows are used sparingly** — cards get `--stripe-shadow-sm`, modals get `--stripe-shadow-md`.
|
|
54
|
+
5. **Accent (purple) is for primary CTA only.** Never use it for decoration.
|
|
55
|
+
6. **Focus rings:** `--stripe-border-focus` border + `rgba(99,91,255,0.15)` box-shadow.
|
|
56
|
+
7. **Feedback colours** pair a text colour with a tinted background — always use both.
|
|
57
|
+
8. **Transitions:** 150ms ease-out on interactive elements.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Design Tokens
|
|
62
|
+
|
|
63
|
+
### Backgrounds
|
|
64
|
+
```
|
|
65
|
+
--stripe-bg-app: #F6F9FC
|
|
66
|
+
--stripe-bg-surface: #FFFFFF
|
|
67
|
+
--stripe-bg-elevated: #FFFFFF
|
|
68
|
+
--stripe-bg-hover: #F6F9FC
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Borders
|
|
72
|
+
```
|
|
73
|
+
--stripe-border: #E3E8EE
|
|
74
|
+
--stripe-border-strong: #C1C9D2
|
|
75
|
+
--stripe-border-focus: #635BFF
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Text
|
|
79
|
+
```
|
|
80
|
+
--stripe-text-primary: #1A1F36
|
|
81
|
+
--stripe-text-secondary: #3C4257
|
|
82
|
+
--stripe-text-muted: #697386
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Accent
|
|
86
|
+
```
|
|
87
|
+
--stripe-accent: #635BFF
|
|
88
|
+
--stripe-accent-hover: #5145E5
|
|
89
|
+
--stripe-accent-subtle: rgba(99, 91, 255, 0.08)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Feedback
|
|
93
|
+
```
|
|
94
|
+
--stripe-success: #09825D --stripe-success-bg: #EBFAF4
|
|
95
|
+
--stripe-warning: #8D6A00 --stripe-warning-bg: #FFFAEB
|
|
96
|
+
--stripe-error: #C0123C --stripe-error-bg: #FFF0F3
|
|
97
|
+
--stripe-info: #0A5494 --stripe-info-bg: #EFF8FF
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Typography
|
|
101
|
+
```
|
|
102
|
+
--stripe-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif
|
|
103
|
+
--stripe-font-mono: 'SF Mono', 'Fira Code', monospace
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Spacing
|
|
107
|
+
```
|
|
108
|
+
--stripe-space-xs: 4px
|
|
109
|
+
--stripe-space-sm: 8px
|
|
110
|
+
--stripe-space-md: 12px
|
|
111
|
+
--stripe-space-lg: 16px
|
|
112
|
+
--stripe-space-xl: 24px
|
|
113
|
+
--stripe-space-2xl: 32px
|
|
114
|
+
--stripe-space-3xl: 48px
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Border Radius
|
|
118
|
+
```
|
|
119
|
+
--stripe-radius-sm: 4px
|
|
120
|
+
--stripe-radius-md: 6px
|
|
121
|
+
--stripe-radius-lg: 8px
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Shadows
|
|
125
|
+
```
|
|
126
|
+
--stripe-shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.06)
|
|
127
|
+
--stripe-shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Components
|
|
133
|
+
|
|
134
|
+
### Button
|
|
135
|
+
|
|
136
|
+
Primary (solid purple), secondary (white + border), and ghost variants. Includes loading state with spinner. Height 36px. Uses native font stack.
|
|
137
|
+
|
|
138
|
+
**Tokens used:** `--stripe-accent`, `--stripe-accent-hover`, `--stripe-bg-surface`, `--stripe-border`, `--stripe-text-primary`, `--stripe-text-muted`, `--stripe-radius-md`, `--stripe-shadow-sm`
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
type ButtonVariant = 'primary' | 'secondary' | 'ghost';
|
|
142
|
+
|
|
143
|
+
interface ButtonProps {
|
|
144
|
+
variant?: ButtonVariant;
|
|
145
|
+
children: React.ReactNode;
|
|
146
|
+
onClick?: () => void;
|
|
147
|
+
disabled?: boolean;
|
|
148
|
+
loading?: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function Button({
|
|
152
|
+
variant = 'primary',
|
|
153
|
+
children,
|
|
154
|
+
onClick,
|
|
155
|
+
disabled,
|
|
156
|
+
loading,
|
|
157
|
+
}: ButtonProps) {
|
|
158
|
+
const isDisabled = disabled || loading;
|
|
159
|
+
|
|
160
|
+
const base: React.CSSProperties = {
|
|
161
|
+
display: 'inline-flex',
|
|
162
|
+
alignItems: 'center',
|
|
163
|
+
justifyContent: 'center',
|
|
164
|
+
gap: '6px',
|
|
165
|
+
height: '36px',
|
|
166
|
+
padding: '0 16px',
|
|
167
|
+
borderRadius: 'var(--stripe-radius-md)',
|
|
168
|
+
fontSize: '14px',
|
|
169
|
+
fontWeight: 600,
|
|
170
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
171
|
+
cursor: isDisabled ? 'not-allowed' : 'pointer',
|
|
172
|
+
opacity: isDisabled ? 0.55 : 1,
|
|
173
|
+
border: '1px solid transparent',
|
|
174
|
+
transition: 'background 150ms ease-out, border-color 150ms ease-out, box-shadow 150ms ease-out',
|
|
175
|
+
textDecoration: 'none',
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const variants: Record<ButtonVariant, React.CSSProperties> = {
|
|
179
|
+
primary: {
|
|
180
|
+
background: 'var(--stripe-accent)',
|
|
181
|
+
color: '#fff',
|
|
182
|
+
},
|
|
183
|
+
secondary: {
|
|
184
|
+
background: 'var(--stripe-bg-surface)',
|
|
185
|
+
color: 'var(--stripe-text-primary)',
|
|
186
|
+
borderColor: 'var(--stripe-border-strong)',
|
|
187
|
+
boxShadow: 'var(--stripe-shadow-sm)',
|
|
188
|
+
},
|
|
189
|
+
ghost: {
|
|
190
|
+
background: 'transparent',
|
|
191
|
+
color: 'var(--stripe-text-secondary)',
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<button
|
|
197
|
+
style={{ ...base, ...variants[variant] }}
|
|
198
|
+
onClick={onClick}
|
|
199
|
+
disabled={isDisabled}
|
|
200
|
+
onMouseEnter={e => {
|
|
201
|
+
if (isDisabled) return;
|
|
202
|
+
if (variant === 'primary') (e.currentTarget as HTMLButtonElement).style.background = 'var(--stripe-accent-hover)';
|
|
203
|
+
if (variant === 'secondary') (e.currentTarget as HTMLButtonElement).style.background = 'var(--stripe-bg-hover)';
|
|
204
|
+
if (variant === 'ghost') (e.currentTarget as HTMLButtonElement).style.background = 'var(--stripe-accent-subtle)';
|
|
205
|
+
}}
|
|
206
|
+
onMouseLeave={e => {
|
|
207
|
+
if (variant === 'primary') (e.currentTarget as HTMLButtonElement).style.background = 'var(--stripe-accent)';
|
|
208
|
+
if (variant === 'secondary') (e.currentTarget as HTMLButtonElement).style.background = 'var(--stripe-bg-surface)';
|
|
209
|
+
if (variant === 'ghost') (e.currentTarget as HTMLButtonElement).style.background = 'transparent';
|
|
210
|
+
}}
|
|
211
|
+
>
|
|
212
|
+
{loading && (
|
|
213
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" style={{ animation: 'spin 0.7s linear infinite' }}>
|
|
214
|
+
<circle cx="7" cy="7" r="5.5" stroke="currentColor" strokeOpacity="0.3" strokeWidth="1.5" />
|
|
215
|
+
<path d="M7 1.5A5.5 5.5 0 0 1 12.5 7" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
216
|
+
</svg>
|
|
217
|
+
)}
|
|
218
|
+
{children}
|
|
219
|
+
</button>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### Input
|
|
227
|
+
|
|
228
|
+
Text input with optional label, helper text, and error state. Clean border at rest, purple focus ring. Height 36px.
|
|
229
|
+
|
|
230
|
+
**Tokens used:** `--stripe-bg-surface`, `--stripe-border`, `--stripe-border-strong`, `--stripe-border-focus`, `--stripe-text-primary`, `--stripe-text-muted`, `--stripe-error`, `--stripe-radius-md`
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
interface InputProps {
|
|
234
|
+
label?: string;
|
|
235
|
+
placeholder?: string;
|
|
236
|
+
value?: string;
|
|
237
|
+
onChange?: (value: string) => void;
|
|
238
|
+
helperText?: string;
|
|
239
|
+
error?: string;
|
|
240
|
+
type?: string;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function Input({
|
|
244
|
+
label,
|
|
245
|
+
placeholder,
|
|
246
|
+
value,
|
|
247
|
+
onChange,
|
|
248
|
+
helperText,
|
|
249
|
+
error,
|
|
250
|
+
type = 'text',
|
|
251
|
+
}: InputProps) {
|
|
252
|
+
return (
|
|
253
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px', width: '100%' }}>
|
|
254
|
+
{label && (
|
|
255
|
+
<label style={{
|
|
256
|
+
fontSize: '13px',
|
|
257
|
+
fontWeight: 500,
|
|
258
|
+
color: 'var(--stripe-text-secondary)',
|
|
259
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
260
|
+
}}>
|
|
261
|
+
{label}
|
|
262
|
+
</label>
|
|
263
|
+
)}
|
|
264
|
+
<input
|
|
265
|
+
type={type}
|
|
266
|
+
value={value}
|
|
267
|
+
onChange={e => onChange?.(e.target.value)}
|
|
268
|
+
placeholder={placeholder}
|
|
269
|
+
style={{
|
|
270
|
+
height: '36px',
|
|
271
|
+
padding: '0 12px',
|
|
272
|
+
background: 'var(--stripe-bg-surface)',
|
|
273
|
+
border: `1px solid ${error ? 'var(--stripe-error)' : 'var(--stripe-border-strong)'}`,
|
|
274
|
+
borderRadius: 'var(--stripe-radius-md)',
|
|
275
|
+
color: 'var(--stripe-text-primary)',
|
|
276
|
+
fontSize: '14px',
|
|
277
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
278
|
+
outline: 'none',
|
|
279
|
+
width: '100%',
|
|
280
|
+
boxSizing: 'border-box',
|
|
281
|
+
transition: 'border-color 150ms ease-out, box-shadow 150ms ease-out',
|
|
282
|
+
}}
|
|
283
|
+
onFocus={e => {
|
|
284
|
+
e.currentTarget.style.borderColor = error ? 'var(--stripe-error)' : 'var(--stripe-border-focus)';
|
|
285
|
+
e.currentTarget.style.boxShadow = error
|
|
286
|
+
? '0 0 0 3px rgba(192, 18, 60, 0.15)'
|
|
287
|
+
: '0 0 0 3px rgba(99, 91, 255, 0.15)';
|
|
288
|
+
}}
|
|
289
|
+
onBlur={e => {
|
|
290
|
+
e.currentTarget.style.borderColor = error ? 'var(--stripe-error)' : 'var(--stripe-border-strong)';
|
|
291
|
+
e.currentTarget.style.boxShadow = 'none';
|
|
292
|
+
}}
|
|
293
|
+
/>
|
|
294
|
+
{(helperText || error) && (
|
|
295
|
+
<span style={{
|
|
296
|
+
fontSize: '12px',
|
|
297
|
+
color: error ? 'var(--stripe-error)' : 'var(--stripe-text-muted)',
|
|
298
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
299
|
+
}}>
|
|
300
|
+
{error ?? helperText}
|
|
301
|
+
</span>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### Card
|
|
311
|
+
|
|
312
|
+
White surface container with subtle shadow and border. Optional header slot with title and actions. Padding is generous.
|
|
313
|
+
|
|
314
|
+
**Tokens used:** `--stripe-bg-surface`, `--stripe-border`, `--stripe-shadow-sm`, `--stripe-shadow-md`, `--stripe-radius-lg`, `--stripe-text-primary`, `--stripe-text-muted`
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
interface CardProps {
|
|
318
|
+
title?: string;
|
|
319
|
+
actions?: React.ReactNode;
|
|
320
|
+
children: React.ReactNode;
|
|
321
|
+
elevated?: boolean;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function Card({ title, actions, children, elevated }: CardProps) {
|
|
325
|
+
return (
|
|
326
|
+
<div
|
|
327
|
+
style={{
|
|
328
|
+
background: 'var(--stripe-bg-surface)',
|
|
329
|
+
border: '1px solid var(--stripe-border)',
|
|
330
|
+
borderRadius: 'var(--stripe-radius-lg)',
|
|
331
|
+
boxShadow: elevated ? 'var(--stripe-shadow-md)' : 'var(--stripe-shadow-sm)',
|
|
332
|
+
overflow: 'hidden',
|
|
333
|
+
}}
|
|
334
|
+
>
|
|
335
|
+
{title && (
|
|
336
|
+
<div
|
|
337
|
+
style={{
|
|
338
|
+
display: 'flex',
|
|
339
|
+
alignItems: 'center',
|
|
340
|
+
justifyContent: 'space-between',
|
|
341
|
+
padding: '16px 24px',
|
|
342
|
+
borderBottom: '1px solid var(--stripe-border)',
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
345
|
+
<h3 style={{
|
|
346
|
+
margin: 0,
|
|
347
|
+
fontSize: '16px',
|
|
348
|
+
fontWeight: 600,
|
|
349
|
+
color: 'var(--stripe-text-primary)',
|
|
350
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
351
|
+
}}>
|
|
352
|
+
{title}
|
|
353
|
+
</h3>
|
|
354
|
+
{actions && <div>{actions}</div>}
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
<div style={{ padding: '24px' }}>
|
|
358
|
+
{children}
|
|
359
|
+
</div>
|
|
360
|
+
</div>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
### Table
|
|
368
|
+
|
|
369
|
+
Clean data table with styled header row and hover states on body rows. For financial/data-heavy UIs.
|
|
370
|
+
|
|
371
|
+
**Tokens used:** `--stripe-bg-surface`, `--stripe-bg-hover`, `--stripe-border`, `--stripe-text-primary`, `--stripe-text-muted`, `--stripe-font-sans`, `--stripe-font-mono`
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
interface Column<T> {
|
|
375
|
+
key: keyof T;
|
|
376
|
+
header: string;
|
|
377
|
+
align?: 'left' | 'right' | 'center';
|
|
378
|
+
mono?: boolean;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
interface TableProps<T extends Record<string, unknown>> {
|
|
382
|
+
columns: Column<T>[];
|
|
383
|
+
rows: T[];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function Table<T extends Record<string, unknown>>({ columns, rows }: TableProps<T>) {
|
|
387
|
+
const cellStyle = (align: string = 'left', mono = false): React.CSSProperties => ({
|
|
388
|
+
padding: '12px 16px',
|
|
389
|
+
textAlign: align as 'left' | 'right' | 'center',
|
|
390
|
+
fontFamily: mono ? 'var(--stripe-font-mono)' : 'var(--stripe-font-sans)',
|
|
391
|
+
fontSize: mono ? '13px' : '14px',
|
|
392
|
+
color: 'var(--stripe-text-primary)',
|
|
393
|
+
borderBottom: '1px solid var(--stripe-border)',
|
|
394
|
+
whiteSpace: 'nowrap',
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
return (
|
|
398
|
+
<div style={{ overflow: 'hidden', borderRadius: 'var(--stripe-radius-lg)', border: '1px solid var(--stripe-border)' }}>
|
|
399
|
+
<table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: 'var(--stripe-font-sans)' }}>
|
|
400
|
+
<thead>
|
|
401
|
+
<tr style={{ background: 'var(--stripe-bg-hover)' }}>
|
|
402
|
+
{columns.map(col => (
|
|
403
|
+
<th
|
|
404
|
+
key={String(col.key)}
|
|
405
|
+
style={{
|
|
406
|
+
padding: '10px 16px',
|
|
407
|
+
textAlign: col.align ?? 'left',
|
|
408
|
+
fontSize: '12px',
|
|
409
|
+
fontWeight: 600,
|
|
410
|
+
color: 'var(--stripe-text-muted)',
|
|
411
|
+
textTransform: 'uppercase',
|
|
412
|
+
letterSpacing: '0.04em',
|
|
413
|
+
borderBottom: '1px solid var(--stripe-border)',
|
|
414
|
+
}}
|
|
415
|
+
>
|
|
416
|
+
{col.header}
|
|
417
|
+
</th>
|
|
418
|
+
))}
|
|
419
|
+
</tr>
|
|
420
|
+
</thead>
|
|
421
|
+
<tbody>
|
|
422
|
+
{rows.map((row, i) => (
|
|
423
|
+
<tr
|
|
424
|
+
key={i}
|
|
425
|
+
style={{ background: 'var(--stripe-bg-surface)', transition: 'background 100ms ease-out' }}
|
|
426
|
+
onMouseEnter={e => (e.currentTarget.style.background = 'var(--stripe-bg-hover)')}
|
|
427
|
+
onMouseLeave={e => (e.currentTarget.style.background = 'var(--stripe-bg-surface)')}
|
|
428
|
+
>
|
|
429
|
+
{columns.map(col => (
|
|
430
|
+
<td key={String(col.key)} style={cellStyle(col.align, col.mono)}>
|
|
431
|
+
{String(row[col.key] ?? '')}
|
|
432
|
+
</td>
|
|
433
|
+
))}
|
|
434
|
+
</tr>
|
|
435
|
+
))}
|
|
436
|
+
</tbody>
|
|
437
|
+
</table>
|
|
438
|
+
</div>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
### Alert
|
|
446
|
+
|
|
447
|
+
Contextual feedback strip with four semantic variants (info/success/warning/error). Always shows an icon and message. Can include an optional action link.
|
|
448
|
+
|
|
449
|
+
**Tokens used:** `--stripe-info`, `--stripe-info-bg`, `--stripe-success`, `--stripe-success-bg`, `--stripe-warning`, `--stripe-warning-bg`, `--stripe-error`, `--stripe-error-bg`, `--stripe-radius-md`
|
|
450
|
+
|
|
451
|
+
```tsx
|
|
452
|
+
type AlertVariant = 'info' | 'success' | 'warning' | 'error';
|
|
453
|
+
|
|
454
|
+
interface AlertProps {
|
|
455
|
+
variant?: AlertVariant;
|
|
456
|
+
title?: string;
|
|
457
|
+
children: React.ReactNode;
|
|
458
|
+
action?: { label: string; onClick: () => void };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const alertConfig: Record<AlertVariant, { bg: string; color: string; icon: string }> = {
|
|
462
|
+
info: { bg: 'var(--stripe-info-bg)', color: 'var(--stripe-info)', icon: 'ℹ' },
|
|
463
|
+
success: { bg: 'var(--stripe-success-bg)', color: 'var(--stripe-success)', icon: '✓' },
|
|
464
|
+
warning: { bg: 'var(--stripe-warning-bg)', color: 'var(--stripe-warning)', icon: '⚠' },
|
|
465
|
+
error: { bg: 'var(--stripe-error-bg)', color: 'var(--stripe-error)', icon: '✕' },
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
export function Alert({ variant = 'info', title, children, action }: AlertProps) {
|
|
469
|
+
const config = alertConfig[variant];
|
|
470
|
+
|
|
471
|
+
return (
|
|
472
|
+
<div
|
|
473
|
+
role="alert"
|
|
474
|
+
style={{
|
|
475
|
+
display: 'flex',
|
|
476
|
+
gap: '12px',
|
|
477
|
+
padding: '12px 16px',
|
|
478
|
+
background: config.bg,
|
|
479
|
+
borderRadius: 'var(--stripe-radius-md)',
|
|
480
|
+
border: `1px solid ${config.color}22`,
|
|
481
|
+
}}
|
|
482
|
+
>
|
|
483
|
+
<span style={{
|
|
484
|
+
color: config.color,
|
|
485
|
+
fontSize: '16px',
|
|
486
|
+
fontWeight: 700,
|
|
487
|
+
lineHeight: '20px',
|
|
488
|
+
flexShrink: 0,
|
|
489
|
+
}}>
|
|
490
|
+
{config.icon}
|
|
491
|
+
</span>
|
|
492
|
+
<div style={{ flex: 1 }}>
|
|
493
|
+
{title && (
|
|
494
|
+
<div style={{
|
|
495
|
+
fontSize: '14px',
|
|
496
|
+
fontWeight: 600,
|
|
497
|
+
color: config.color,
|
|
498
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
499
|
+
marginBottom: '2px',
|
|
500
|
+
}}>
|
|
501
|
+
{title}
|
|
502
|
+
</div>
|
|
503
|
+
)}
|
|
504
|
+
<div style={{
|
|
505
|
+
fontSize: '13px',
|
|
506
|
+
color: config.color,
|
|
507
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
508
|
+
opacity: 0.85,
|
|
509
|
+
}}>
|
|
510
|
+
{children}
|
|
511
|
+
</div>
|
|
512
|
+
{action && (
|
|
513
|
+
<button
|
|
514
|
+
onClick={action.onClick}
|
|
515
|
+
style={{
|
|
516
|
+
marginTop: '6px',
|
|
517
|
+
fontSize: '13px',
|
|
518
|
+
fontWeight: 600,
|
|
519
|
+
color: config.color,
|
|
520
|
+
background: 'none',
|
|
521
|
+
border: 'none',
|
|
522
|
+
padding: 0,
|
|
523
|
+
cursor: 'pointer',
|
|
524
|
+
textDecoration: 'underline',
|
|
525
|
+
fontFamily: 'var(--stripe-font-sans)',
|
|
526
|
+
}}
|
|
527
|
+
>
|
|
528
|
+
{action.label}
|
|
529
|
+
</button>
|
|
530
|
+
)}
|
|
531
|
+
</div>
|
|
532
|
+
</div>
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
<!-- Generated by Layout — layout.design -->
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stripe-lite",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"displayName": "Stripe",
|
|
5
|
+
"description": "Financial product, light-mode design system inspired by Stripe",
|
|
6
|
+
"source": "website-extraction",
|
|
7
|
+
"tier": "free",
|
|
8
|
+
"tokenCount": 26,
|
|
9
|
+
"componentCount": 5,
|
|
10
|
+
"aesthetic": "Light, clean, high-trust",
|
|
11
|
+
"layoutUrl": "https://layout.design/kits/stripe"
|
|
12
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* Stripe Lite — Design Tokens */
|
|
2
|
+
/* Generated by Layout — layout.design */
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
/* Backgrounds */
|
|
6
|
+
--stripe-bg-app: #F6F9FC;
|
|
7
|
+
--stripe-bg-surface: #FFFFFF;
|
|
8
|
+
--stripe-bg-elevated: #FFFFFF;
|
|
9
|
+
--stripe-bg-hover: #F6F9FC;
|
|
10
|
+
|
|
11
|
+
/* Borders */
|
|
12
|
+
--stripe-border: #E3E8EE;
|
|
13
|
+
--stripe-border-strong: #C1C9D2;
|
|
14
|
+
--stripe-border-focus: #635BFF;
|
|
15
|
+
|
|
16
|
+
/* Text */
|
|
17
|
+
--stripe-text-primary: #1A1F36;
|
|
18
|
+
--stripe-text-secondary: #3C4257;
|
|
19
|
+
--stripe-text-muted: #697386;
|
|
20
|
+
|
|
21
|
+
/* Accent (Stripe purple) */
|
|
22
|
+
--stripe-accent: #635BFF;
|
|
23
|
+
--stripe-accent-hover: #5145E5;
|
|
24
|
+
--stripe-accent-subtle: rgba(99, 91, 255, 0.08);
|
|
25
|
+
|
|
26
|
+
/* Feedback */
|
|
27
|
+
--stripe-success: #09825D;
|
|
28
|
+
--stripe-success-bg: #EBFAF4;
|
|
29
|
+
--stripe-warning: #8D6A00;
|
|
30
|
+
--stripe-warning-bg: #FFFAEB;
|
|
31
|
+
--stripe-error: #C0123C;
|
|
32
|
+
--stripe-error-bg: #FFF0F3;
|
|
33
|
+
--stripe-info: #0A5494;
|
|
34
|
+
--stripe-info-bg: #EFF8FF;
|
|
35
|
+
|
|
36
|
+
/* Typography */
|
|
37
|
+
--stripe-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
38
|
+
--stripe-font-mono: 'SF Mono', 'Fira Code', monospace;
|
|
39
|
+
|
|
40
|
+
/* Spacing */
|
|
41
|
+
--stripe-space-xs: 4px;
|
|
42
|
+
--stripe-space-sm: 8px;
|
|
43
|
+
--stripe-space-md: 12px;
|
|
44
|
+
--stripe-space-lg: 16px;
|
|
45
|
+
--stripe-space-xl: 24px;
|
|
46
|
+
--stripe-space-2xl: 32px;
|
|
47
|
+
--stripe-space-3xl: 48px;
|
|
48
|
+
|
|
49
|
+
/* Radius */
|
|
50
|
+
--stripe-radius-sm: 4px;
|
|
51
|
+
--stripe-radius-md: 6px;
|
|
52
|
+
--stripe-radius-lg: 8px;
|
|
53
|
+
|
|
54
|
+
/* Shadows */
|
|
55
|
+
--stripe-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
56
|
+
--stripe-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
57
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://tr.designtokens.org/format/",
|
|
3
|
+
"color": {
|
|
4
|
+
"bg": {
|
|
5
|
+
"app": { "$type": "color", "$value": "#F6F9FC" },
|
|
6
|
+
"surface": { "$type": "color", "$value": "#FFFFFF" },
|
|
7
|
+
"elevated": { "$type": "color", "$value": "#FFFFFF" },
|
|
8
|
+
"hover": { "$type": "color", "$value": "#F6F9FC" }
|
|
9
|
+
},
|
|
10
|
+
"border": {
|
|
11
|
+
"default": { "$type": "color", "$value": "#E3E8EE" },
|
|
12
|
+
"strong": { "$type": "color", "$value": "#C1C9D2" },
|
|
13
|
+
"focus": { "$type": "color", "$value": "#635BFF" }
|
|
14
|
+
},
|
|
15
|
+
"text": {
|
|
16
|
+
"primary": { "$type": "color", "$value": "#1A1F36" },
|
|
17
|
+
"secondary": { "$type": "color", "$value": "#3C4257" },
|
|
18
|
+
"muted": { "$type": "color", "$value": "#697386" }
|
|
19
|
+
},
|
|
20
|
+
"accent": {
|
|
21
|
+
"default": { "$type": "color", "$value": "#635BFF" },
|
|
22
|
+
"hover": { "$type": "color", "$value": "#5145E5" },
|
|
23
|
+
"subtle": { "$type": "color", "$value": "rgba(99, 91, 255, 0.08)" }
|
|
24
|
+
},
|
|
25
|
+
"feedback": {
|
|
26
|
+
"success": { "$type": "color", "$value": "#09825D" },
|
|
27
|
+
"successBg": { "$type": "color", "$value": "#EBFAF4" },
|
|
28
|
+
"warning": { "$type": "color", "$value": "#8D6A00" },
|
|
29
|
+
"warningBg": { "$type": "color", "$value": "#FFFAEB" },
|
|
30
|
+
"error": { "$type": "color", "$value": "#C0123C" },
|
|
31
|
+
"errorBg": { "$type": "color", "$value": "#FFF0F3" },
|
|
32
|
+
"info": { "$type": "color", "$value": "#0A5494" },
|
|
33
|
+
"infoBg": { "$type": "color", "$value": "#EFF8FF" }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"font": {
|
|
37
|
+
"sans": { "$type": "fontFamily", "$value": ["-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "sans-serif"] },
|
|
38
|
+
"mono": { "$type": "fontFamily", "$value": ["SF Mono", "Fira Code", "monospace"] }
|
|
39
|
+
},
|
|
40
|
+
"spacing": {
|
|
41
|
+
"xs": { "$type": "dimension", "$value": "4px" },
|
|
42
|
+
"sm": { "$type": "dimension", "$value": "8px" },
|
|
43
|
+
"md": { "$type": "dimension", "$value": "12px" },
|
|
44
|
+
"lg": { "$type": "dimension", "$value": "16px" },
|
|
45
|
+
"xl": { "$type": "dimension", "$value": "24px" },
|
|
46
|
+
"2xl": { "$type": "dimension", "$value": "32px" },
|
|
47
|
+
"3xl": { "$type": "dimension", "$value": "48px" }
|
|
48
|
+
},
|
|
49
|
+
"borderRadius": {
|
|
50
|
+
"sm": { "$type": "dimension", "$value": "4px" },
|
|
51
|
+
"md": { "$type": "dimension", "$value": "6px" },
|
|
52
|
+
"lg": { "$type": "dimension", "$value": "8px" }
|
|
53
|
+
},
|
|
54
|
+
"shadow": {
|
|
55
|
+
"sm": { "$type": "shadow", "$value": "0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.06)" },
|
|
56
|
+
"md": { "$type": "shadow", "$value": "0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06)" }
|
|
57
|
+
}
|
|
58
|
+
}
|