@sarunyu/system-one 4.9.36 → 4.9.39
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 +22 -0
- package/DESIGN.md +2 -2
- package/dist/index.cjs +627 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +628 -7
- package/dist/index.js.map +1 -1
- package/dist/src/components/list.d.ts +25 -0
- package/dist/src/components/list.d.ts.map +1 -0
- package/dist/src/components/progress.d.ts +23 -0
- package/dist/src/components/progress.d.ts.map +1 -0
- package/dist/src/components/slider.d.ts +34 -0
- package/dist/src/components/slider.d.ts.map +1 -0
- package/dist/src/components/upload.d.ts +38 -0
- package/dist/src/components/upload.d.ts.map +1 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/llms.txt +126 -5
- package/package.json +1 -1
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sarunyu/system-one — AI usage guide
|
|
2
2
|
|
|
3
|
-
React component library. Tailwind CSS v4 + CSS custom properties.
|
|
3
|
+
React component library. Tailwind CSS v4 + CSS custom properties. 35 components.
|
|
4
4
|
Built for AI-powered UI generation (v0, Lovable, Figma Make, Cursor).
|
|
5
5
|
|
|
6
6
|
**This file is the contract.** Read it top-to-bottom before generating any screen
|
|
@@ -12,14 +12,16 @@ that uses this library. The rules are non-negotiable.
|
|
|
12
12
|
|
|
13
13
|
1. **Use library components for every element it provides.** Never recreate
|
|
14
14
|
Button, Input, Tag, Dropdown, Card, Tab, Checkbox, Toggle, Radio, DateInput, TimeInput,
|
|
15
|
-
Table, SearchInput, TextArea, Chip, Modal, BottomSheet, Alert, Toast, Notification, Badge, Avatar, AvatarStack, Breadcrumb, Pagination, PaginationBanner, PaginationCarousel, Tooltip, Popover
|
|
15
|
+
Table, SearchInput, TextArea, Chip, Modal, BottomSheet, Alert, Toast, Notification, Badge, Avatar, AvatarStack, Breadcrumb, Pagination, PaginationBanner, PaginationCarousel, Tooltip, Popover,
|
|
16
|
+
Slider, UploadArea, UploadItem, List, ListItem as raw HTML.
|
|
16
17
|
2. **Never override a component's built-in styles.** Every library component manages its own colors, shadows, padding, radius, and typography internally. Only use `className` on library components for **layout** (`w-*`, `max-w-*`, `flex`, `grid`, `gap-*`, `m-*`, `col-span-*`). Never pass `bg-*`, `shadow-*`, `text-*`, `p-*`, `rounded-*`, or `border-*` in `className` on a library component.
|
|
17
18
|
3. **Use design-token classes for color and typography.** Never `text-blue-600`,
|
|
18
19
|
`bg-gray-100`, `text-[#3b82f6]`. The token table below is exhaustive — if a
|
|
19
20
|
color you need is not in it, use `text-foreground` / `bg-card`.
|
|
20
21
|
4. **Use `@phosphor-icons/react` for all icons.** Never import from `lucide-react`
|
|
21
22
|
or any other icon library. Install with `npm install @phosphor-icons/react`.
|
|
22
|
-
Import named icons: `import {
|
|
23
|
+
Import named icons: `import { HouseIcon, MagnifyingGlassIcon, CaretDownIcon } from "@phosphor-icons/react"`.
|
|
24
|
+
All icon names use the `Icon` suffix (e.g. `StarIcon`, `TrashIcon`, `ArrowUpIcon`). The un-suffixed names are deprecated.
|
|
23
25
|
Every icon accepts `size`, `weight` (`"regular"` | `"fill"` — no other weights), and `className` props.
|
|
24
26
|
5. **No arbitrary bracket values for spacing / sizing / typography.**
|
|
25
27
|
Use scale utilities, not pixel overrides. The library's shipped stylesheet
|
|
@@ -153,6 +155,8 @@ import {
|
|
|
153
155
|
Dropdown, DropdownMultiple, OptionList,
|
|
154
156
|
Checkbox, Toggle, Radio,
|
|
155
157
|
DateInput, TimeInput,
|
|
158
|
+
Slider,
|
|
159
|
+
UploadArea, UploadItem,
|
|
156
160
|
// Navigation
|
|
157
161
|
Breadcrumb,
|
|
158
162
|
Pagination, PaginationBanner, PaginationCarousel,
|
|
@@ -162,6 +166,7 @@ import {
|
|
|
162
166
|
Tab, TabGroup,
|
|
163
167
|
Card,
|
|
164
168
|
Table, TableRow, TableHeaderCell, TableCell,
|
|
169
|
+
LinearProgress, CircleProgress,
|
|
165
170
|
// Feedback
|
|
166
171
|
Alert,
|
|
167
172
|
Toast, Toaster,
|
|
@@ -169,6 +174,8 @@ import {
|
|
|
169
174
|
Badge,
|
|
170
175
|
// Overlay
|
|
171
176
|
Modal, BottomSheet, Tooltip, Popover,
|
|
177
|
+
// List
|
|
178
|
+
List, ListItem,
|
|
172
179
|
// Utility
|
|
173
180
|
cn, useIsMobile,
|
|
174
181
|
} from "@sarunyu/system-one";
|
|
@@ -1124,6 +1131,24 @@ type BottomSheetRightSide = "icon" | "action" | "none";
|
|
|
1124
1131
|
- `rightSide="action"` — inline text button (e.g., "Save"), fires `onActionClick`.
|
|
1125
1132
|
- `rightSide="none"` — nothing on the right.
|
|
1126
1133
|
|
|
1134
|
+
**CRITICAL — lazy-mount pattern (always required):** Vaul mounts its portal
|
|
1135
|
+
immediately when `<BottomSheet>` enters the React tree, even with `open={false}`.
|
|
1136
|
+
Always guard with an `everOpened` flag so it never mounts until first opened.
|
|
1137
|
+
|
|
1138
|
+
```tsx
|
|
1139
|
+
// button-triggered
|
|
1140
|
+
const [everOpened, setEverOpened] = useState(false);
|
|
1141
|
+
const [open, setOpen] = useState(false);
|
|
1142
|
+
<Button onClick={() => { setEverOpened(true); setOpen(true); }}>Open</Button>
|
|
1143
|
+
{everOpened && <BottomSheet open={open} onOpenChange={setOpen}>…</BottomSheet>}
|
|
1144
|
+
|
|
1145
|
+
// prop-driven (open comes from parent)
|
|
1146
|
+
const [everOpened, setEverOpened] = useState(false);
|
|
1147
|
+
useEffect(() => { if (open) setEverOpened(true); }, [open]);
|
|
1148
|
+
if (!everOpened) return null;
|
|
1149
|
+
return <BottomSheet open={open} onOpenChange={…}>…</BottomSheet>;
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1127
1152
|
`showHandle` (default `true`) shows the grab handle at the top. Hide it only
|
|
1128
1153
|
when you want a fully formal surface. Do not render a `<BottomSheet>` on desktop
|
|
1129
1154
|
layouts — use `<Modal>` instead.
|
|
@@ -1141,7 +1166,7 @@ Dark-bubble contextual hint shown on hover over any trigger element.
|
|
|
1141
1166
|
|
|
1142
1167
|
```tsx
|
|
1143
1168
|
<Tooltip content="Delete this item">
|
|
1144
|
-
<Button variant="outline" size="icon-md" aria-label="Delete"><
|
|
1169
|
+
<Button variant="outline" size="icon-md" aria-label="Delete"><TrashIcon size={16} /></Button>
|
|
1145
1170
|
</Tooltip>
|
|
1146
1171
|
|
|
1147
1172
|
<Tooltip content="This field is required" side="right" align="start">
|
|
@@ -1192,7 +1217,7 @@ Floating panel that opens on **click** over any trigger element. Pass the trigge
|
|
|
1192
1217
|
</div>
|
|
1193
1218
|
}
|
|
1194
1219
|
>
|
|
1195
|
-
<Button variant="outline" size="md" leftIcon={<
|
|
1220
|
+
<Button variant="outline" size="md" leftIcon={<UserIcon size={16} />}>Account</Button>
|
|
1196
1221
|
</Popover>
|
|
1197
1222
|
```
|
|
1198
1223
|
|
|
@@ -1208,6 +1233,102 @@ Props:
|
|
|
1208
1233
|
|
|
1209
1234
|
---
|
|
1210
1235
|
|
|
1236
|
+
### Slider
|
|
1237
|
+
|
|
1238
|
+
Range input with a draggable thumb. Three track heights, single-thumb or two-thumb range. Never use `<input type="range">` directly.
|
|
1239
|
+
|
|
1240
|
+
```tsx
|
|
1241
|
+
// Single thumb (uncontrolled default = 50)
|
|
1242
|
+
const [value, setValue] = useState(50)
|
|
1243
|
+
<Slider value={value} onChange={setValue} />
|
|
1244
|
+
<Slider size="sm" value={value} onChange={setValue} />
|
|
1245
|
+
<Slider size="lg" showSteps value={value} onChange={setValue} />
|
|
1246
|
+
<Slider disabled value={value} onChange={setValue} />
|
|
1247
|
+
|
|
1248
|
+
// Two-thumb range
|
|
1249
|
+
const [range, setRange] = useState<[number, number]>([25, 75])
|
|
1250
|
+
<Slider type="range" rangeValue={range} onRangeChange={setRange} />
|
|
1251
|
+
<Slider type="range" size="lg" showSteps rangeValue={range} onRangeChange={setRange} />
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
Props: `size` (`"sm"` 4px | `"md"` 8px default | `"lg"` 12px), `type` (`"single"` default | `"range"`), `disabled`, `showSteps` (labels at 0 / 25 / 50 / 75 / 100), `min` (default 0), `max` (default 100), `step` (default 1), `value` (controlled single), `rangeValue` (controlled range `[start, end]`), `defaultValue` (50), `defaultRangeValue` ([25, 75]), `onChange(value)`, `onRangeChange([start, end])`, `className`.
|
|
1255
|
+
|
|
1256
|
+
---
|
|
1257
|
+
|
|
1258
|
+
### LinearProgress / CircleProgress
|
|
1259
|
+
|
|
1260
|
+
Deterministic progress indicators. `value` is 0–100 (clamped automatically). Never use `<progress>` HTML element.
|
|
1261
|
+
|
|
1262
|
+
```tsx
|
|
1263
|
+
// Linear bar — typically full-width or constrained by parent
|
|
1264
|
+
<LinearProgress value={65} />
|
|
1265
|
+
<LinearProgress value={30} className="w-64" />
|
|
1266
|
+
|
|
1267
|
+
// Circle — three sizes
|
|
1268
|
+
<CircleProgress value={75} /> // lg (128 px) — default, shows % label
|
|
1269
|
+
<CircleProgress value={50} size="md" /> // md (48 px) — shows % label
|
|
1270
|
+
<CircleProgress value={30} size="sm" /> // sm (24 px) — arc only, no label
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
Props `LinearProgress`: `value`, `className`.
|
|
1274
|
+
Props `CircleProgress`: `value`, `size` (`"sm"` | `"md"` | `"lg"` default), `className`.
|
|
1275
|
+
|
|
1276
|
+
`lg` and `md` sizes display a centred percentage label; `sm` is arc-only. The arc uses a brand cyan-to-navy gradient. At `value={0}`, `lg`/`md` show a placeholder-coloured `0%` label.
|
|
1277
|
+
|
|
1278
|
+
---
|
|
1279
|
+
|
|
1280
|
+
### UploadArea / UploadItem
|
|
1281
|
+
|
|
1282
|
+
Upload dropzone and per-file status rows. Never hand-roll dashed upload areas or custom file progress rows.
|
|
1283
|
+
|
|
1284
|
+
```tsx
|
|
1285
|
+
// Dropzone — wire onClick to open a file input
|
|
1286
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
1287
|
+
<UploadArea onClick={() => inputRef.current?.click()} />
|
|
1288
|
+
<UploadArea disabled />
|
|
1289
|
+
<UploadArea label="Browse files" onClick={() => inputRef.current?.click()} />
|
|
1290
|
+
|
|
1291
|
+
// Text variant — compact row, no card border
|
|
1292
|
+
<UploadItem variant="text" status="loading" fileName="report.pdf" progress={42} />
|
|
1293
|
+
<UploadItem variant="text" status="success" fileName="report.pdf" onDelete={handleDelete} />
|
|
1294
|
+
<UploadItem variant="text" status="error" fileName="report.pdf" errorText="File too large" onDelete={handleDelete} />
|
|
1295
|
+
|
|
1296
|
+
// Card variant — bordered card with file-size column and separate delete button
|
|
1297
|
+
<UploadItem variant="card" status="loading" fileName="photo.png" fileSize="1.66KB" progress={42} />
|
|
1298
|
+
<UploadItem variant="card" status="success" fileName="photo.png" fileSize="1.66KB" onDelete={handleDelete} />
|
|
1299
|
+
<UploadItem variant="card" status="error" fileName="photo.png" fileSize="1.66KB" errorText="Upload failed" onDelete={handleDelete} />
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
Props `UploadArea`: `disabled`, `label` (default `"อัปโหลดไฟล์"`), plus all native `<div>` props (`onClick`, `className`, etc.).
|
|
1303
|
+
Props `UploadItem`: `variant` (`"text"` default | `"card"`), `status` (`"loading"` | `"success"` | `"error"`, default `"loading"`), `fileName`, `fileSize` (card variant — e.g. `"1.66KB"`), `errorText`, `progress` (0–100, shown while `status="loading"`), `onDelete`, `className`.
|
|
1304
|
+
|
|
1305
|
+
---
|
|
1306
|
+
|
|
1307
|
+
### List / ListItem
|
|
1308
|
+
|
|
1309
|
+
Vertical list of rows. Each row has a label, optional leading/trailing slot, and optional action link or click handler. Never hand-roll `<ul>` / `<li>` rows for this pattern.
|
|
1310
|
+
|
|
1311
|
+
```tsx
|
|
1312
|
+
<List>
|
|
1313
|
+
<ListItem label="Settings" />
|
|
1314
|
+
<ListItem label="Profile" leading={<UserIcon size={24} />} />
|
|
1315
|
+
<ListItem label="Documents" trailing={<CaretRightIcon size={24} />} onClick={() => navigate("/docs")} />
|
|
1316
|
+
<ListItem label="Billing" action="Manage" onAction={openBilling} />
|
|
1317
|
+
<ListItem label="Disabled row" highlighted />
|
|
1318
|
+
</List>
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
**Slots:**
|
|
1322
|
+
- `leading` — left slot (icon, avatar, image). Rendered at 24×24 with `text-icon-default`.
|
|
1323
|
+
- `trailing` — right slot (icon, chevron, badge). Same sizing.
|
|
1324
|
+
- `action` — string label for an inline text-button on the right (e.g. "Edit", "View all"). Fires `onAction`.
|
|
1325
|
+
- `onClick` — makes the whole row tappable. Press state (gray background) is applied automatically.
|
|
1326
|
+
|
|
1327
|
+
Props `ListItem`: `label` (required), `leading?`, `trailing?`, `action?`, `onAction?(e)`, `highlighted?`, `onClick?`, `className`.
|
|
1328
|
+
Props `List`: `children`, `className`.
|
|
1329
|
+
|
|
1330
|
+
---
|
|
1331
|
+
|
|
1211
1332
|
### Modal vs BottomSheet — responsive rule
|
|
1212
1333
|
|
|
1213
1334
|
**On mobile (< 768px), content-heavy / action-heavy modals MUST render as
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sarunyu/system-one",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A production-ready React design system built for AI-powered web generation tools (Figma Make, Lovable, V0). Tailwind CSS v4 + CSS custom properties for full theming support.",
|
|
6
6
|
"keywords": [
|