@sarunyu/system-one 1.1.0 → 1.1.2

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/llms.txt ADDED
@@ -0,0 +1,632 @@
1
+ # @sarunyu/system-one
2
+
3
+ React component library. Tailwind CSS v4 + CSS custom properties. 13 production-ready components. Built for AI-powered generation tools (v0, Lovable, Figma Make).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @sarunyu/system-one
9
+ ```
10
+
11
+ ## Setup by Platform
12
+
13
+ ### v0 / Next.js (App Router)
14
+
15
+ ```tsx
16
+ // app/layout.tsx
17
+ import "@sarunyu/system-one/styles.css"
18
+ ```
19
+
20
+ Components are pre-annotated with `"use client"`. Safe to import anywhere — Server Components, Client Components, pages.
21
+
22
+ ### Next.js (Pages Router)
23
+
24
+ ```tsx
25
+ // pages/_app.tsx
26
+ import "@sarunyu/system-one/styles.css"
27
+ ```
28
+
29
+ ### Figma Make / Lovable / Vite
30
+
31
+ ```tsx
32
+ // src/main.tsx
33
+ import "@sarunyu/system-one/styles.css"
34
+ ```
35
+
36
+ ## Import
37
+
38
+ ```tsx
39
+ import {
40
+ Button, Input, TextArea, SearchInput,
41
+ Dropdown, DropdownMultiple, OptionList,
42
+ Tag, StatusTag, Chip,
43
+ Tab, TabGroup,
44
+ Card,
45
+ DateInput, TimeInput,
46
+ cn
47
+ } from "@sarunyu/system-one"
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Components
53
+
54
+ ### Button
55
+
56
+ Variants: `primary` | `outline` | `plain` | `outline-black` | `plain-black`
57
+ Label sizes: `xs` | `sm` | `md` | `lg` | `xl`
58
+ Icon-only sizes: `icon-xs` | `icon-sm` | `icon-md` | `icon-lg` | `icon-xl`
59
+
60
+ ```tsx
61
+ <Button variant="primary" size="md">Submit</Button>
62
+ <Button variant="outline" size="md" onClick={fn}>Cancel</Button>
63
+ <Button variant="plain" size="sm">Learn more</Button>
64
+ <Button variant="primary" size="md" leftIcon={<Icon />}>Add item</Button>
65
+ <Button variant="outline" size="md" rightIcon={<Icon />}>Continue</Button>
66
+ <Button size="icon-md" aria-label="Settings"><GearIcon /></Button>
67
+ ```
68
+
69
+ Props: `variant`, `size`, `leftIcon`, `rightIcon`, `disabled`, `onClick`, `className`, `children`
70
+
71
+ ---
72
+
73
+ ### Input
74
+
75
+ Floating-label text input with validation states.
76
+
77
+ ```tsx
78
+ <Input placeholder="Email" value={email} onChange={setEmail} />
79
+ <Input placeholder="Amount" unit="THB" />
80
+ <Input placeholder="Password" type="password" />
81
+ <Input placeholder="Bio" showCount maxCount={160} />
82
+ <Input forceState="error" errorMessage="This field is required" placeholder="Email" />
83
+ <Input forceState="disabled" placeholder="Read only" />
84
+ ```
85
+
86
+ Props: `placeholder`, `value`, `onChange`, `type`, `unit`, `showCount`, `maxCount`, `forceState` (`"default"` | `"focus"` | `"error"` | `"disabled"`), `errorMessage`, `required`, `className`
87
+
88
+ ---
89
+
90
+ ### TextArea
91
+
92
+ Multi-line input. API mirrors Input.
93
+
94
+ ```tsx
95
+ <TextArea placeholder="Description" value={text} onChange={setText} />
96
+ <TextArea placeholder="Tweet" showCount maxCount={280} />
97
+ <TextArea forceState="error" errorMessage="Required" placeholder="Notes" />
98
+ ```
99
+
100
+ Props: `placeholder`, `value`, `onChange`, `showCount`, `maxCount`, `forceState`, `errorMessage`, `required`, `className`
101
+
102
+ ---
103
+
104
+ ### SearchInput
105
+
106
+ Search field with icon and clear button.
107
+
108
+ ```tsx
109
+ <SearchInput placeholder="Search events..." value={q} onChange={setQ} />
110
+ <SearchInput size="sm" placeholder="Filter by name..." />
111
+ ```
112
+
113
+ Props: `placeholder`, `value`, `onChange`, `size` (`"lg"` | `"sm"`), `className`
114
+
115
+ ---
116
+
117
+ ### Dropdown
118
+
119
+ Single-select dropdown.
120
+
121
+ ```tsx
122
+ <Dropdown
123
+ placeholder="Select category"
124
+ options={[
125
+ { label: "Option A", value: "a" },
126
+ { label: "Option B", value: "b" },
127
+ { label: "Disabled", value: "c", disabled: true },
128
+ ]}
129
+ value={selected}
130
+ onChange={setSelected}
131
+ />
132
+ ```
133
+
134
+ Props: `placeholder`, `options` (`Array<{ label: string, value: string, disabled?: boolean }>`), `value`, `onChange`, `disabled`, `className`
135
+
136
+ ---
137
+
138
+ ### DropdownMultiple
139
+
140
+ Multi-select dropdown with checkboxes.
141
+
142
+ ```tsx
143
+ <DropdownMultiple
144
+ placeholder="Select tags"
145
+ options={options}
146
+ values={selected}
147
+ onChange={setSelected}
148
+ />
149
+ ```
150
+
151
+ Props: `placeholder`, `options`, `values`, `onChange`, `disabled`, `className`
152
+
153
+ ---
154
+
155
+ ### Tag
156
+
157
+ Compact colored label. Use for categories, statuses, filters.
158
+
159
+ Variants: `blue` | `green` | `yellow` | `red` | `gray` | `lime`
160
+ Sizes: `large` (default) | `small`
161
+
162
+ Color semantics: `green` → positive/active, `red` → error/danger, `yellow` → warning/pending, `blue` → informational, `gray` → neutral/inactive
163
+
164
+ ```tsx
165
+ <Tag text="Active" variant="green" />
166
+ <Tag text="Draft" variant="yellow" />
167
+ <Tag text="Error" variant="red" size="small" />
168
+ <Tag text="Filter" close onClose={fn} />
169
+ ```
170
+
171
+ Props: `text`, `variant`, `size`, `close`, `onClose`, `className`
172
+
173
+ ---
174
+
175
+ ### StatusTag
176
+
177
+ Process-flow state indicator with colored dot.
178
+
179
+ Types: `stop` | `success` | `hold` | `processing` | `error`
180
+
181
+ ```tsx
182
+ <StatusTag type="success" />
183
+ <StatusTag type="processing" text="In progress" />
184
+ <StatusTag type="hold" />
185
+ <StatusTag type="error" />
186
+ ```
187
+
188
+ Props: `type`, `text`, `className`
189
+
190
+ Use `StatusTag` for workflow states. Use `Tag` for categorical labels.
191
+
192
+ ---
193
+
194
+ ### Chip
195
+
196
+ Toggleable filter/selection chip. Always use in groups of 2+.
197
+
198
+ Types: `single` (default) | `multiple`
199
+ Sizes: `large` | `medium` | `small`
200
+
201
+ ```tsx
202
+ {/* Single-select group */}
203
+ <div className="flex gap-2">
204
+ <Chip label="All" selected={filter === "all"} onClick={() => setFilter("all")} />
205
+ <Chip label="Active" selected={filter === "active"} onClick={() => setFilter("active")} />
206
+ <Chip label="Archived" selected={filter === "archived"} onClick={() => setFilter("archived")} />
207
+ </div>
208
+
209
+ {/* Multi-select */}
210
+ <Chip label="Design" type="multiple" selected={tags.includes("design")} onClick={() => toggle("design")} />
211
+ ```
212
+
213
+ Props: `label`, `selected`, `onClick`, `type`, `size`, `disabled`, `className`
214
+
215
+ ---
216
+
217
+ ### TabGroup
218
+
219
+ Tabbed navigation. Always use `TabGroup`, not bare `Tab`.
220
+
221
+ Sizes: `lg` | `md` (default) | `sm`
222
+
223
+ ```tsx
224
+ <TabGroup
225
+ items={[
226
+ { id: "overview", title: "Overview" },
227
+ { id: "details", title: "Details", icon: true },
228
+ { id: "history", title: "History", notification: 3 },
229
+ { id: "settings", title: "Settings", disabled: true },
230
+ ]}
231
+ activeId={activeTab}
232
+ onChange={setActiveTab}
233
+ size="md"
234
+ />
235
+ ```
236
+
237
+ Props: `items` (`Array<{ id: string, title: string, icon?: boolean, notification?: number, disabled?: boolean }>`), `activeId`, `onChange`, `size`, `className`
238
+
239
+ ---
240
+
241
+ ### Card
242
+
243
+ Responsive event/content card.
244
+
245
+ Variants: `desktop` (308px wide) | `tablet` (224px wide) | `mobile` (163px wide)
246
+ tagStatus: `not-registered` | `registered` | `full`
247
+
248
+ ```tsx
249
+ <Card
250
+ variant="desktop"
251
+ title="Annual Conference 2024"
252
+ date="Jun 23, 2024"
253
+ time="08:30 - 12:00"
254
+ location="Main Hall, Floor 7"
255
+ count="150/200"
256
+ tagStatus="registered"
257
+ image="/banner.jpg"
258
+ />
259
+ ```
260
+
261
+ Props: `variant`, `title`, `date`, `time`, `location`, `count`, `tagStatus`, `image`, `className`
262
+
263
+ Match variant to viewport: `desktop` on wide layouts, `tablet` / `mobile` on narrow.
264
+
265
+ ---
266
+
267
+ ### DateInput
268
+
269
+ Calendar date picker.
270
+
271
+ Modes: `single` | `range` | `multiple`
272
+ Variants: `popover` (default) | `modal`
273
+
274
+ ```tsx
275
+ <DateInput placeholder="Select date" mode="single" value={date} onChange={setDate} />
276
+ <DateInput mode="range" value={range} onChange={setRange} />
277
+ <DateInput mode="multiple" value={dates} onChange={setDates} />
278
+ ```
279
+
280
+ Props: `placeholder`, `mode`, `value`, `onChange`, `variant`, `disabled`, `className`
281
+
282
+ ---
283
+
284
+ ### TimeInput
285
+
286
+ 24-hour time picker.
287
+
288
+ Modes: `single` | `range`
289
+
290
+ ```tsx
291
+ <TimeInput placeholder="Start time" value={time} onChange={setTime} />
292
+ <TimeInput mode="range" value={timeRange} onChange={setTimeRange} />
293
+ ```
294
+
295
+ Props: `placeholder`, `mode`, `value`, `onChange`, `disabled`, `className`
296
+
297
+ ---
298
+
299
+ ### OptionList
300
+
301
+ Scrollable option list for custom dropdowns.
302
+
303
+ ```tsx
304
+ {/* Single-select */}
305
+ <OptionList
306
+ options={[{ label: "Item A", value: "a" }, { label: "Item B", value: "b" }]}
307
+ selectedValue={value}
308
+ onSelect={setValue}
309
+ />
310
+
311
+ {/* Multi-select */}
312
+ <OptionList
313
+ options={options}
314
+ selectedValues={values}
315
+ onToggle={toggleValue}
316
+ />
317
+ ```
318
+
319
+ Props: `options` (`Array<{ label: string, value: string, disabled?: boolean }>`), `selectedValue`, `onSelect`, `selectedValues`, `onToggle`, `className`
320
+
321
+ ---
322
+
323
+ ## Design Tokens
324
+
325
+ All tokens are CSS custom properties. Override after the stylesheet import:
326
+
327
+ ```css
328
+ :root {
329
+ --primary-action: #7c3aed; /* brand color */
330
+ --primary-action-hover: #6d28d9;
331
+ --primary-action-active: #5b21b6;
332
+ --font-sans: "Inter", sans-serif; /* override library default (Noto Sans Thai) */
333
+ --radius: 8px; /* border radius base */
334
+ }
335
+ ```
336
+
337
+ Key tokens:
338
+ - `--primary-action` — brand color (primary buttons, links, active states)
339
+ - `--background` / `--foreground` — page surface and text
340
+ - `--border` — default border color
341
+ - `--muted-foreground` — placeholder and secondary text
342
+ - `--destructive` — error/danger red
343
+ - `--success` — success green
344
+ - `--font-sans` — font family (default: Noto Sans Thai)
345
+ - `--radius` — base border radius (default: 4px)
346
+
347
+ ---
348
+
349
+ ## Dark Mode
350
+
351
+ Add `.dark` to `<html>` or any ancestor:
352
+
353
+ ```tsx
354
+ // Next.js
355
+ <html className={isDark ? "dark" : ""}>
356
+
357
+ // Vite
358
+ document.documentElement.classList.toggle("dark", isDark)
359
+ ```
360
+
361
+ All components adapt automatically.
362
+
363
+ ---
364
+
365
+ ## TypeScript
366
+
367
+ ```ts
368
+ import type { ButtonVariant, ButtonSize, TagVariant, ChipSize } from "@sarunyu/system-one"
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Page Layout Patterns
374
+
375
+ **Components alone do not make a page.** The library styles components but does **not** style page layout. Without the rules below, AI tools produce pages where everything sits flush against neighbors and the result looks broken. Apply these defaults on every page you generate.
376
+
377
+ ### Spacing scale
378
+
379
+ Use Tailwind spacing (1 unit = 4px). Pick from these standard gaps — do not invent arbitrary values.
380
+
381
+ | Purpose | Class | Pixels |
382
+ |---|---|---|
383
+ | Between label and input | `gap-1` or `gap-2` | 4–8px |
384
+ | Between fields in a form | `gap-4` | 16px |
385
+ | Between related elements (button row, chip row) | `gap-2` or `gap-3` | 8–12px |
386
+ | Between a heading and its content | `mb-4` or `mb-6` | 16–24px |
387
+ | Between paragraphs | `gap-3` or `gap-4` | 12–16px |
388
+ | Between subsections of a page | `gap-8` or `gap-10` | 32–40px |
389
+ | Between top-level page sections | `gap-12` or `gap-16` | 48–64px |
390
+ | Section vertical padding (hero, feature blocks) | `py-16` or `py-20` | 64–80px |
391
+
392
+ ### Page container
393
+
394
+ Every page needs a horizontal container. Default pattern:
395
+
396
+ ```tsx
397
+ <main className="mx-auto w-full max-w-[1200px] px-6 md:px-8 py-10">
398
+ {/* page content */}
399
+ </main>
400
+ ```
401
+
402
+ - `max-w-[1200px]` for wide apps/marketing. Use `max-w-[960px]` for content-heavy, `max-w-[640px]` for forms/auth.
403
+ - Always pair `mx-auto` with a `max-w-*` — otherwise content stretches edge-to-edge on large screens.
404
+ - `px-6 md:px-8` keeps content off the viewport edge on mobile.
405
+
406
+ ### Section rhythm
407
+
408
+ Stack page sections vertically with `flex flex-col gap-12` (or `gap-16` for marketing pages). Never let sections touch.
409
+
410
+ ```tsx
411
+ <main className="mx-auto w-full max-w-[1200px] px-6 py-10 flex flex-col gap-12">
412
+ <section>{/* hero */}</section>
413
+ <section>{/* features */}</section>
414
+ <section>{/* cta */}</section>
415
+ </main>
416
+ ```
417
+
418
+ ### Typography
419
+
420
+ `h1` / `h2` / `h3` / `h4` are already styled by the library (size + weight + line-height). Just use them — do **not** add `text-2xl font-medium` manually.
421
+
422
+ - `h1` = page title (one per page)
423
+ - `h2` = section heading
424
+ - `h3` = subsection heading
425
+ - `h4` = minor heading / card title
426
+ - Body text = default (no class needed) or `text-muted-foreground` for secondary
427
+
428
+ Standard heading + content block:
429
+
430
+ ```tsx
431
+ <section className="flex flex-col gap-6">
432
+ <div className="flex flex-col gap-2">
433
+ <h2>Section title</h2>
434
+ <p className="text-muted-foreground">Short description that explains what this section does.</p>
435
+ </div>
436
+ {/* content */}
437
+ </section>
438
+ ```
439
+
440
+ ### Form layout
441
+
442
+ Vertical stack. Never put inputs side-by-side unless they are logically paired (first/last name, date range).
443
+
444
+ ```tsx
445
+ <form className="flex flex-col gap-4 max-w-[480px]">
446
+ <Input placeholder="Email" value={email} onChange={setEmail} />
447
+ <Input placeholder="Password" type="password" value={pw} onChange={setPw} />
448
+ <div className="flex gap-3 pt-2">
449
+ <Button variant="primary" size="md">Sign in</Button>
450
+ <Button variant="outline" size="md">Cancel</Button>
451
+ </div>
452
+ </form>
453
+ ```
454
+
455
+ Paired inputs:
456
+
457
+ ```tsx
458
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
459
+ <Input placeholder="First name" />
460
+ <Input placeholder="Last name" />
461
+ </div>
462
+ ```
463
+
464
+ ### Card grid
465
+
466
+ Cards in a responsive grid. Always gap at least `gap-6` between cards.
467
+
468
+ ```tsx
469
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
470
+ <Card variant="desktop" title="..." date="..." time="..." location="..." tagStatus="registered" />
471
+ <Card variant="desktop" title="..." date="..." time="..." location="..." tagStatus="not-registered" />
472
+ <Card variant="desktop" title="..." date="..." time="..." location="..." tagStatus="full" />
473
+ </div>
474
+ ```
475
+
476
+ ### Toolbar / filter row
477
+
478
+ Chips, search, dropdowns above a list. Use `flex flex-wrap gap-3 items-center`.
479
+
480
+ ```tsx
481
+ <div className="flex flex-wrap items-center gap-3">
482
+ <SearchInput placeholder="Search..." value={q} onChange={setQ} className="max-w-[320px]" />
483
+ <Chip label="All" selected={f === "all"} onClick={() => setF("all")} />
484
+ <Chip label="Active" selected={f === "active"} onClick={() => setF("active")} />
485
+ <Chip label="Archived" selected={f === "archived"} onClick={() => setF("archived")} />
486
+ </div>
487
+ ```
488
+
489
+ ### Full page template
490
+
491
+ Copy-paste starting point. Replace content, keep the structure.
492
+
493
+ ```tsx
494
+ export default function Page() {
495
+ return (
496
+ <main className="mx-auto w-full max-w-[1200px] px-6 md:px-8 py-10 flex flex-col gap-12">
497
+ {/* Page header */}
498
+ <header className="flex flex-col gap-2">
499
+ <h1>Events</h1>
500
+ <p className="text-muted-foreground">Browse and register for upcoming events.</p>
501
+ </header>
502
+
503
+ {/* Toolbar */}
504
+ <div className="flex flex-wrap items-center gap-3">
505
+ <SearchInput placeholder="Search events..." value={q} onChange={setQ} className="max-w-[320px]" />
506
+ <Chip label="All" selected={filter === "all"} onClick={() => setFilter("all")} />
507
+ <Chip label="This week" selected={filter === "week"} onClick={() => setFilter("week")} />
508
+ </div>
509
+
510
+ {/* Content */}
511
+ <section className="flex flex-col gap-6">
512
+ <h2>Upcoming</h2>
513
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
514
+ {events.map((e) => <Card key={e.id} variant="desktop" {...e} />)}
515
+ </div>
516
+ </section>
517
+ </main>
518
+ );
519
+ }
520
+ ```
521
+
522
+ ### Layout rules (do / don't)
523
+
524
+ - **Do** wrap every page in a `max-w-* mx-auto` container with horizontal padding.
525
+ - **Do** use `flex flex-col gap-*` to stack sections — never rely on default margins.
526
+ - **Do** group a heading with its content in a smaller `gap-2`/`gap-4` block, then separate groups with `gap-8`+.
527
+ - **Don't** place components directly adjacent without a `gap-*` or padding parent.
528
+ - **Don't** mix arbitrary spacing values (`gap-[13px]`, `mt-7`) — stick to `2 / 3 / 4 / 6 / 8 / 10 / 12 / 16`.
529
+ - **Don't** full-bleed text content on desktop — cap reading widths at `max-w-[720px]` for paragraphs.
530
+ - **Don't** override heading sizes with utility classes — `h1`–`h4` are already sized by the library.
531
+
532
+ ---
533
+
534
+ ## Notes
535
+
536
+ - No provider or wrapper needed — just import the stylesheet and use components
537
+ - The library ships pre-built CSS — no Tailwind config required in the consuming project
538
+ - If the project already uses Tailwind and you see font differences, override `--font-sans` in your CSS
539
+ - CSS custom properties can be referenced in Tailwind classes: `bg-[var(--primary-action)]`
540
+
541
+ ---
542
+
543
+ ## Component Usage Guide
544
+
545
+ ### Button
546
+
547
+ Buttons are interactive elements that allow users to click or tap to perform actions — such as submitting a form, saving data, navigating to another page, or opening a popup.
548
+
549
+ Types: `primary` — main CTA, use once per context. `outline` — secondary action, supports primary without affecting main flow. `plain` — no background or border, low-priority actions. `secondary` (outline-black) — same as outline but black, use when blue is not appropriate.
550
+
551
+ Sizes: `base` recommended for Desktop. `xl` recommended for Mobile.
552
+
553
+ States: Default, Hover, Press, Disabled.
554
+
555
+ ### Input
556
+
557
+ Floating Label Input is a single-line or multi-line field with a label that floats inside.
558
+
559
+ Types: `Input` — single-line, general text/numeric. `TextArea` — multi-line, for comments or addresses. `Dropdown` — predefined list selection, displays as OptionList.
560
+
561
+ States: Default, Focus, Error, Disabled.
562
+
563
+ ### Tab
564
+
565
+ Tabs allow users to switch between different content sections within the same page.
566
+
567
+ Types: Default (text only), Icon (with icon), Notification (with badge).
568
+
569
+ States: Default, Active (selected), Disabled.
570
+
571
+ Sizes: `lg` (default), `md`, `sm`. Always use the same size within one tab group.
572
+
573
+ ### Tag
574
+
575
+ Tags display categories, types, or short metadata. Status Tags communicate process state.
576
+
577
+ Tag types: Default (text only), Icon (with icon), Remove (dismissible).
578
+ Tag states: Default, Hover/Press, Disabled.
579
+ Tag sizes: Large, Small.
580
+
581
+ Status Tag variants: `success` — process completed. `processing` — in progress. `hold` — temporarily paused. `stop` — stopped. `error` — failed.
582
+
583
+ ### Chip
584
+
585
+ Chips are toggleable filter/selection elements. Always use in groups of 2+.
586
+
587
+ Types: `single` — one selection at a time. `multiple` — multiple selections simultaneously.
588
+
589
+ States: Default, Active, Disabled (Default), Disabled (Active).
590
+
591
+ Sizes: `large`, `medium`, `small`.
592
+
593
+ ---
594
+
595
+ ## Design Rules
596
+
597
+ ### Button Rules
598
+
599
+ - Maximum width is 343px (`max-w-[343px]`). Never remove or override. Do not detach the component.
600
+ - Do not manually recreate or modify padding (`py-[10px] px-[16px]`) or border-radius (`rounded-[8px]`).
601
+ - Use Primary only once per context. Never place two Primary buttons side-by-side. Use Outline/Secondary for supporting actions.
602
+ - Hug width is correct for short labels only. For long labels, use Fill width or set explicit max-w-[343px].
603
+
604
+ ### Input Rules
605
+
606
+ - Never override input border or background colors manually — use built-in state variants (Default, Focus, Error, Disabled).
607
+ - Do not recreate input styles manually or adjust gap/height outside the component's tokens.
608
+ - Use Dropdown Tags only for multi-select. For single-select, use standard Dropdown.
609
+ - Keep labelText short enough to fit on one line. Long labels break the floating label layout.
610
+ - Do not show Helper Text and Error Message simultaneously. Error state replaces helper text.
611
+ - Use Option List only when there are multiple selectable values.
612
+ - Always follow the system date format (DD MMM YYYY). Do not mix Thai month names with C.E. year or reorder day/month/year.
613
+
614
+ ### Tab Rules
615
+
616
+ - Do not override padding, gap, border-radius, element order, or colors inside the tab bar.
617
+ - All tabs in one group must use the same size prop. Never mix sizes.
618
+ - Do not add extra gap or margin between tabs — use built-in spacing tokens only.
619
+
620
+ ### Tag Rules
621
+
622
+ - Do not override height, padding, or layout of Tag or StatusTag.
623
+ - All tags in the same context must use the same size.
624
+ - Do not reorder internal elements (icon, label, badge) inside Tag or StatusTag.
625
+ - Always use the correct StatusTag variant for its semantic meaning. Never override the color.
626
+
627
+ ### Chip Rules
628
+
629
+ - Keep chip labels short and single-purpose. Long labels cause overflow.
630
+ - Do not override padding, gap, radius, height, element order, or colors.
631
+ - All chips in the same group must share the same size and spacing.
632
+ - Use Chip only for groups with 2+ options. For single options, use a toggle or checkbox instead.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarunyu/system-one",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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": [
@@ -38,7 +38,8 @@
38
38
  "*.css"
39
39
  ],
40
40
  "files": [
41
- "dist"
41
+ "dist",
42
+ "llms.txt"
42
43
  ],
43
44
  "scripts": {
44
45
  "dev": "vite",