@sarunyu/system-one 4.5.1 → 4.6.0
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/AGENTS.md +25 -4
- package/DESIGN.md +263 -0
- package/dist/index.cjs +166 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +167 -115
- package/dist/index.js.map +1 -1
- package/dist/src/components/badge.d.ts.map +1 -1
- package/dist/src/components/card.d.ts +1 -1
- package/dist/src/components/card.d.ts.map +1 -1
- package/dist/src/components/checkbox.d.ts +4 -0
- package/dist/src/components/checkbox.d.ts.map +1 -1
- package/dist/src/components/notification.d.ts +6 -1
- package/dist/src/components/notification.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/llms.txt +21 -5
- package/package.json +5 -1
package/AGENTS.md
CHANGED
|
@@ -32,14 +32,35 @@ in this package.** This file is the short version: the rules you must follow.
|
|
|
32
32
|
`bg-background`, `bg-card`, `bg-muted`, `bg-primary-action`,
|
|
33
33
|
`border-border`, `border-divider`, etc. See `llms.txt` for the full table.
|
|
34
34
|
|
|
35
|
-
3. **
|
|
35
|
+
3. **No arbitrary bracket values for spacing/sizing/typography.** Use scale utilities only.
|
|
36
|
+
- **Forbidden**: `max-w-[1100px]`, `h-[317px]`, `min-h-[calc(100vh-64px)]`,
|
|
37
|
+
`w-[272px]`, `gap-[14px]`, `p-[10px]`, `text-[13px]`, `leading-[22px]`,
|
|
38
|
+
`rounded-[10px]`, `top-[7px]`.
|
|
39
|
+
- **Allowed**: scale values — `max-w-5xl` / `max-w-2xl`, `h-80` (=320px),
|
|
40
|
+
`w-64` (=256px), `gap-4`, `p-6`, `text-sm`, `leading-6`, `rounded-lg`,
|
|
41
|
+
`top-2`. The spacing scale is 4px-based: `0.5` (2px), `1` (4px), `2` (8px),
|
|
42
|
+
`3` (12px), `4` (16px), `5` (20px), `6` (24px), `8` (32px), `10` (40px),
|
|
43
|
+
`12` (48px), `16` (64px), `20` (80px), `24` (96px).
|
|
44
|
+
- **Exception — container widths only**: these specific arbitrary widths are
|
|
45
|
+
safelisted and may be used: `max-w-[480px]`, `max-w-[640px]`, `max-w-[720px]`,
|
|
46
|
+
`max-w-[800px]`, `max-w-[960px]`, `max-w-[1024px]`, `max-w-[1200px]`,
|
|
47
|
+
`max-w-[1280px]`, `max-w-[1440px]`. For other widths, pick the nearest
|
|
48
|
+
`max-w-{xs,sm,md,lg,xl,2xl,3xl,4xl,5xl,6xl,7xl}`.
|
|
49
|
+
- **Why**: the library's shipped `styles.css` only contains scale utilities
|
|
50
|
+
+ the safelisted arbitrary container widths. Any other `[...]` value needs
|
|
51
|
+
host-side Tailwind to compile — in a plain host (e.g. Claude Code / Cursor
|
|
52
|
+
vibe-coded Vite project without Tailwind setup) the class is a no-op and
|
|
53
|
+
layout collapses. If a design truly requires an odd value, snap to the
|
|
54
|
+
nearest scale step.
|
|
55
|
+
|
|
56
|
+
4. **Do not add text/font utility classes to `<h1>`–`<h4>`.** They are pre-styled.
|
|
36
57
|
Use them as-is.
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
5. **Layout is your job, with plain Tailwind.** The library has NO layout primitives.
|
|
39
60
|
Do not import `Page`, `Section`, `Stack`, `CardGrid`, `Toolbar` — they do not exist.
|
|
40
61
|
Build structure with `<div>` + `flex` / `grid` / `max-w-*` / `gap-*` / `p-*`.
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
6. **Component props are documented in `llms.txt` and in the `.d.ts` files.**
|
|
43
64
|
- `Input.onChange` receives `(value: string)`, not an event.
|
|
44
65
|
- `placeholder` IS the label (floats up on fill). Don't add a separate `<label>`.
|
|
45
66
|
- Checkbox/Radio take their `label` as a prop. Don't wrap them in `<label>`.
|
|
@@ -53,7 +74,7 @@ in this package.** This file is the short version: the rules you must follow.
|
|
|
53
74
|
- `Badge variant="notification"` — internal to `<Notification>`; never use standalone or attach your own `onClick` to it.
|
|
54
75
|
- `Notification` manages its own popover; pass `groups` (array of `{ label, items }`). It renders both the bell trigger and the panel. This is the only correct way to show a notification list.
|
|
55
76
|
|
|
56
|
-
|
|
77
|
+
7. **Mobile forms and action-heavy modals MUST use `<BottomSheet>`, not `<Modal>`.**
|
|
57
78
|
Login, signup, settings panels, profile editors, any multi-field form,
|
|
58
79
|
multi-step flow, long picker list, or action menu — on mobile (< 768px)
|
|
59
80
|
these render as `<BottomSheet>`. Only simple `variant="alert"` and short
|
package/DESIGN.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# DESIGN.md — @sarunyu/system-one
|
|
2
|
+
|
|
3
|
+
Visual identity guide for AI coding tools (Figma Make, Lovable, v0, Claude).
|
|
4
|
+
Read this before generating any UI. For component API and token class names, read `AGENTS.md` and `llms.txt`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
**Personality:** Corporate — structured, trustworthy, data-dense, professional.
|
|
11
|
+
**Feel:** Clean surfaces, strong hierarchy, controlled whitespace. Never playful, never decorative.
|
|
12
|
+
**Target context:** Enterprise web applications — dashboards, data tables, form-heavy workflows, financial UIs.
|
|
13
|
+
|
|
14
|
+
Design decisions lean toward clarity over expression. Every element earns its space.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Colors
|
|
19
|
+
|
|
20
|
+
### Brand palette
|
|
21
|
+
|
|
22
|
+
| Role | Light mode | Dark mode | Tailwind class |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| Primary action (buttons, links, active) | `#0a6ee7` | `#4792ed` | `bg-primary-action` / `text-primary-action` |
|
|
25
|
+
| Primary hover | `#095ec4` | `#91bef4` | `bg-primary-action-hover` |
|
|
26
|
+
| Primary active/pressed | `#074ea4` | — | `bg-primary-action-active` |
|
|
27
|
+
| Primary light tint | `#dae9fb` | — | `bg-primary-action-light` |
|
|
28
|
+
| Secondary accent (highlights, badges) | `#eb6101` | — | use `bg-visual-orange` |
|
|
29
|
+
|
|
30
|
+
### Surfaces
|
|
31
|
+
|
|
32
|
+
| Role | Value | Tailwind class |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| Page background | `#ffffff` (light) / `#0f172a` (dark) | `bg-background` |
|
|
35
|
+
| Card / panel | `#ffffff` (light) / `#1e293b` (dark) | `bg-card` |
|
|
36
|
+
| Subtle secondary surface | `#f9fafb` | `bg-default-secondary` |
|
|
37
|
+
| Input background | `#f9fafb` | `bg-muted` |
|
|
38
|
+
| Hover state | `#f3f4f6` | `bg-hover-bg` |
|
|
39
|
+
| Disabled | `#f3f4f6` | `bg-disabled-bg` |
|
|
40
|
+
|
|
41
|
+
### Status colors
|
|
42
|
+
|
|
43
|
+
| Status | Fill | Light surface | Tailwind class |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| Danger / error | `#fb2c36` | `#fef2f2` | `bg-destructive` / `bg-error-bg` |
|
|
46
|
+
| Warning | `#f0b100` | `#fefce8` | `bg-warning` / `bg-warning-light` |
|
|
47
|
+
| Success | `#00c951` | `#f0fdf4` | `bg-success` / `bg-success-bg` |
|
|
48
|
+
| Info | blue-500 | blue-50 | `bg-info` / `bg-info-light` |
|
|
49
|
+
|
|
50
|
+
### Borders
|
|
51
|
+
|
|
52
|
+
Default border: `1px solid` — `border-border` (`#e5e7eb` light).
|
|
53
|
+
Dividers between sections: `border-divider` (lighter than border).
|
|
54
|
+
Never hard-code border colors.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Typography
|
|
59
|
+
|
|
60
|
+
**Font family:** `Noto Sans Thai`, sans-serif — loaded via Google Fonts (wght 400 / 500 / 600).
|
|
61
|
+
Override globally: `--font-sans: "Your Font", sans-serif;`
|
|
62
|
+
|
|
63
|
+
### Heading scale (pre-styled — do NOT add Tailwind text-* overrides)
|
|
64
|
+
|
|
65
|
+
| Tag | Size | Weight | Use for |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `<h1>` | 24px | 600 | Page title |
|
|
68
|
+
| `<h2>` | 20px | 600 | Section title |
|
|
69
|
+
| `<h3>` | 18px | 600 | Card / panel heading |
|
|
70
|
+
| `<h4>` | 16px | 500 | Sub-section, field group label |
|
|
71
|
+
|
|
72
|
+
### Body scale
|
|
73
|
+
|
|
74
|
+
| Class | Size | Use for |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| (default, no class) | 16px | Body text, form values |
|
|
77
|
+
| `text-sm` | 14px | Secondary labels, table cells, helper text |
|
|
78
|
+
| `text-xs` | 12px | Captions, timestamps, fine print |
|
|
79
|
+
|
|
80
|
+
### Color rules
|
|
81
|
+
|
|
82
|
+
- Body / headings: `text-foreground`
|
|
83
|
+
- Secondary labels: `text-muted-foreground`
|
|
84
|
+
- Disabled: `text-disabled`
|
|
85
|
+
- Brand / link: `text-primary-action`
|
|
86
|
+
- Error: `text-destructive`
|
|
87
|
+
|
|
88
|
+
Never use `text-gray-*`, `text-blue-*`, or hex colors for text.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Spacing
|
|
93
|
+
|
|
94
|
+
**Base unit:** 4px. All spacing values are multiples of 4px.
|
|
95
|
+
|
|
96
|
+
### Layout spacing
|
|
97
|
+
|
|
98
|
+
| Context | Value | Tailwind |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| Page horizontal padding | 24px (desktop) / 16px (mobile) | `px-6 md:px-8` |
|
|
101
|
+
| Page vertical padding | 40px | `py-10` |
|
|
102
|
+
| Between major page sections | 48px | `gap-12` |
|
|
103
|
+
| Between related content blocks | 24px | `gap-6` |
|
|
104
|
+
| Between items in a cluster | 16px | `gap-4` |
|
|
105
|
+
| Inside a card / panel | 24px | `p-6` |
|
|
106
|
+
| Dense toolbar / header row | 12–16px | `gap-3` or `gap-4` |
|
|
107
|
+
|
|
108
|
+
### Content width
|
|
109
|
+
|
|
110
|
+
| Layout | Max-width |
|
|
111
|
+
|---|---|
|
|
112
|
+
| Dashboard / wide content | `max-w-[1200px]` |
|
|
113
|
+
| Standard content page | `max-w-[960px]` |
|
|
114
|
+
| Form / narrow content | `max-w-[640px]` |
|
|
115
|
+
| Dialog / modal body | `max-w-[480px]` |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Border radius
|
|
120
|
+
|
|
121
|
+
Default: **4px** (`rounded`). Corporate contexts use tight radius — avoid large curves.
|
|
122
|
+
|
|
123
|
+
| Usage | Value | Tailwind |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| Default (inputs, cards, buttons) | 4px | `rounded` |
|
|
126
|
+
| Tags, badges, chips | 6px | `rounded-md` |
|
|
127
|
+
| Pills | 999px | `rounded-full` |
|
|
128
|
+
| Modals, large panels | 8px | `rounded-lg` |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Elevation / shadow
|
|
133
|
+
|
|
134
|
+
Use sparingly. Corporate UIs prefer border separation over heavy elevation.
|
|
135
|
+
|
|
136
|
+
| Level | Usage | Tailwind |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| None | Flat cards separated by border | — |
|
|
139
|
+
| Subtle | Floating cards, content panels | `shadow-sm` |
|
|
140
|
+
| Card | Event cards, interactive tiles | `shadow-card` |
|
|
141
|
+
| Popover | Dropdowns, menus, tooltips | `shadow-popover` |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Layout patterns
|
|
146
|
+
|
|
147
|
+
### Standard dashboard page
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<main className="mx-auto w-full max-w-[1200px] px-6 md:px-8 py-10 flex flex-col gap-12">
|
|
151
|
+
<header className="flex items-start justify-between gap-4">
|
|
152
|
+
<div className="flex flex-col gap-1">
|
|
153
|
+
<h1>Page Title</h1>
|
|
154
|
+
<p className="text-sm text-muted-foreground">Supporting description</p>
|
|
155
|
+
</div>
|
|
156
|
+
<Button variant="primary" size="md">Primary action</Button>
|
|
157
|
+
</header>
|
|
158
|
+
|
|
159
|
+
<section className="flex flex-col gap-6">
|
|
160
|
+
<h2>Section</h2>
|
|
161
|
+
{/* content */}
|
|
162
|
+
</section>
|
|
163
|
+
</main>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Sidebar + content
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<div className="flex min-h-screen bg-background">
|
|
170
|
+
<aside className="w-64 shrink-0 border-r border-divider bg-card p-6 flex flex-col gap-2">
|
|
171
|
+
{/* navigation items */}
|
|
172
|
+
</aside>
|
|
173
|
+
<main className="flex-1 px-8 py-10 flex flex-col gap-12">
|
|
174
|
+
{/* page content */}
|
|
175
|
+
</main>
|
|
176
|
+
</div>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Card grid (data tiles)
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
183
|
+
{items.map(item => (
|
|
184
|
+
<Card key={item.id} title={item.title} description={item.description} />
|
|
185
|
+
))}
|
|
186
|
+
</div>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Form page
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
<main className="mx-auto w-full max-w-[640px] px-6 py-10 flex flex-col gap-8">
|
|
193
|
+
<h1>Form Title</h1>
|
|
194
|
+
<section className="flex flex-col gap-4">
|
|
195
|
+
<Input placeholder="Field label" value={v} onChange={setV} />
|
|
196
|
+
<Input placeholder="Another field" value={v2} onChange={setV2} />
|
|
197
|
+
<Dropdown placeholder="Select option" options={opts} value={sel} onChange={setSel} />
|
|
198
|
+
</section>
|
|
199
|
+
<div className="flex justify-end gap-3">
|
|
200
|
+
<Button variant="outline" size="md">Cancel</Button>
|
|
201
|
+
<Button variant="primary" size="md">Submit</Button>
|
|
202
|
+
</div>
|
|
203
|
+
</main>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Data table page
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<main className="mx-auto w-full max-w-[1200px] px-6 md:px-8 py-10 flex flex-col gap-6">
|
|
210
|
+
<header className="flex items-center justify-between gap-4">
|
|
211
|
+
<h1>Table Title</h1>
|
|
212
|
+
<div className="flex items-center gap-3">
|
|
213
|
+
<SearchInput placeholder="Search..." value={q} onChange={setQ} />
|
|
214
|
+
<Button variant="primary" size="md">Add new</Button>
|
|
215
|
+
</div>
|
|
216
|
+
</header>
|
|
217
|
+
<Table>
|
|
218
|
+
<TableRow header>
|
|
219
|
+
<TableHeaderCell>Column A</TableHeaderCell>
|
|
220
|
+
<TableHeaderCell>Column B</TableHeaderCell>
|
|
221
|
+
</TableRow>
|
|
222
|
+
{rows.map(row => (
|
|
223
|
+
<TableRow key={row.id}>
|
|
224
|
+
<TableCell>{row.a}</TableCell>
|
|
225
|
+
<TableCell>{row.b}</TableCell>
|
|
226
|
+
</TableRow>
|
|
227
|
+
))}
|
|
228
|
+
</Table>
|
|
229
|
+
</main>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Visual do / don't
|
|
235
|
+
|
|
236
|
+
| Do | Don't |
|
|
237
|
+
|---|---|
|
|
238
|
+
| Use `bg-background`, `bg-card` for surfaces | Hard-code `#ffffff` or `bg-white` |
|
|
239
|
+
| Use `text-foreground` for body text | Use `text-gray-900` or `text-black` |
|
|
240
|
+
| Use `border-border` for dividers | Use `border-gray-200` |
|
|
241
|
+
| Use `rounded` (4px) by default | Use `rounded-xl` or `rounded-2xl` on data elements |
|
|
242
|
+
| Keep whitespace controlled: `gap-4`–`gap-6` inside sections | Over-pad with `gap-10`+ inside cards |
|
|
243
|
+
| One `variant="primary"` Button per context | Two or more primary buttons side by side |
|
|
244
|
+
| Separate sections with `gap-12` or a `border-divider` line | Use heavy drop shadows to separate sections |
|
|
245
|
+
| Use scale values — `max-w-5xl`, `h-80`, `w-64`, `gap-4`, `p-6`, `text-sm` | Use arbitrary brackets — `max-w-[1100px]`, `h-[317px]`, `gap-[14px]`, `text-[13px]` (won't compile in hosts without Tailwind; see AGENTS.md rule 3) |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Component library
|
|
250
|
+
|
|
251
|
+
This design system ships 24 pre-built components. **Always use them — never recreate with raw HTML.**
|
|
252
|
+
|
|
253
|
+
Key components: `Button`, `Input`, `TextArea`, `SearchInput`, `Dropdown`, `DropdownMultiple`, `Checkbox`, `Radio`, `Toggle`, `DateInput`, `TimeInput`, `Tag`, `StatusTag`, `Chip`, `TabGroup`, `Card`, `Table` + `TableRow` + `TableHeaderCell` + `TableCell`, `Modal`, `BottomSheet`, `Alert`, `Toast`, `ToastStack`, `Notification`, `Badge`.
|
|
254
|
+
|
|
255
|
+
For props, variants, and usage rules → read `AGENTS.md` and `llms.txt` in this package.
|
|
256
|
+
|
|
257
|
+
### Setup (required)
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import "@sarunyu/system-one/styles.css";
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
If the screen looks unstyled, this import is missing.
|