@usevyre/ai-context 1.0.1 → 1.1.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- // @usevyre/ai-context v1.0.0
1
+ // @usevyre/ai-context v1.1.0
2
2
  // Auto-generated — do not edit directly. Edit src/schema/components.json instead.
3
3
 
4
- export const version = "1.0.0";
4
+ export const version = "1.1.0";
5
5
 
6
6
  export const fullContext = `# useVyre Design System — AI Context
7
7
  # Version: 0.2.0
@@ -886,6 +886,188 @@ import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
886
886
 
887
887
  ---
888
888
 
889
+ ### ButtonGroup
890
+
891
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
892
+
893
+ \`\`\`tsx
894
+ import { ButtonGroup, Button } from "@usevyre/react"
895
+
896
+ // Props:
897
+ // orientation = "horizontal" | "vertical" (default: horizontal)
898
+ // attached = boolean (default: false)
899
+ // size = "sm" | "md" | "lg" | "icon"
900
+
901
+ // Examples:
902
+ <ButtonGroup attached>
903
+ <Button variant="secondary">Day</Button>
904
+ <Button variant="secondary">Week</Button>
905
+ <Button variant="secondary">Month</Button>
906
+ </ButtonGroup>
907
+ <ButtonGroup orientation="vertical" attached>
908
+ <Button variant="secondary">Top</Button>
909
+ <Button variant="secondary">Bottom</Button>
910
+ </ButtonGroup>
911
+ \`\`\`
912
+
913
+ **Common mistakes:**
914
+ - ❌ \`ButtonGroup variant="..."\` → Set variant on each <Button> inside the group
915
+ - ❌ \`ButtonGroup without Button children\` → Place <Button> elements as direct children
916
+
917
+ ---
918
+
919
+ ### TagsInput
920
+
921
+ Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
922
+
923
+ \`\`\`tsx
924
+ import { TagsInput } from "@usevyre/react"
925
+
926
+ // Props:
927
+ // value = string[]
928
+ // onChange = (tags: string[]) => void
929
+ // placeholder = string
930
+ // disabled = boolean (default: false)
931
+ // max = number
932
+ // size = "sm" | "md" | "lg" (default: md)
933
+
934
+ // Examples:
935
+ const [tags, setTags] = useState<string[]>([]);
936
+ <TagsInput value={tags} onChange={setTags} placeholder="Add a tag…" />
937
+ <TagsInput value={tags} onChange={setTags} max={5} />
938
+ \`\`\`
939
+
940
+ **Common mistakes:**
941
+ - ❌ \`TagsInput value={string}\` → Pass an array: value={['react','vue']}
942
+ - ❌ \`TagsInput without onChange\` → Provide value and onChange (React) or v-model (Vue)
943
+
944
+ ---
945
+
946
+ ### Combobox
947
+
948
+ Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).
949
+
950
+ \`\`\`tsx
951
+ import { Combobox } from "@usevyre/react"
952
+
953
+ // Props:
954
+ // options = { value: string; label: string; disabled?: boolean }[]
955
+ // value = string | null
956
+ // onChange = (value: string | null) => void
957
+ // placeholder = string (default: "Search…")
958
+ // disabled = boolean (default: false)
959
+ // size = "sm" | "md" | "lg" (default: md)
960
+ // emptyText = string (default: "No results")
961
+
962
+ // Examples:
963
+ const [lang, setLang] = useState<string | null>(null);
964
+ <Combobox
965
+ options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
966
+ value={lang}
967
+ onChange={setLang}
968
+ placeholder="Search language…"
969
+ />
970
+ \`\`\`
971
+
972
+ **Common mistakes:**
973
+ - ❌ \`Combobox value=""\` → Use value={null} for no selection
974
+ - ❌ \`Combobox options={string[]}\` → Use [{ value: 'ts', label: 'TypeScript' }]
975
+ - ❌ \`Using Combobox for command palette\` → Use Command for command palettes
976
+
977
+ ---
978
+
979
+ ### DataGrid
980
+
981
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
982
+
983
+ \`\`\`tsx
984
+ import { DataGrid } from "@usevyre/react"
985
+
986
+ // Props:
987
+ // columns = { key: string; label: string; sortable?: boolean; width?: string }[]
988
+ // rows = Record<string, unknown>[]
989
+ // sortKey = string
990
+ // sortDir = "asc" | "desc"
991
+ // onSort = (key: string, dir: 'asc' | 'desc') => void
992
+ // loading = boolean (default: false)
993
+ // emptyText = string (default: "No data")
994
+ // stickyHeader = boolean (default: false)
995
+
996
+ // Examples:
997
+ const cols = [{ key: "name", label: "Name", sortable: true }];
998
+ <DataGrid
999
+ columns={cols}
1000
+ rows={people}
1001
+ sortKey={sortKey}
1002
+ sortDir={sortDir}
1003
+ onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
1004
+ />
1005
+ <DataGrid columns={cols} rows={[]} loading />
1006
+ \`\`\`
1007
+
1008
+ **Common mistakes:**
1009
+ - ❌ \`DataGrid expecting built-in pagination\` → Slice rows yourself and use the Pagination component
1010
+ - ❌ \`DataGrid expecting built-in filtering\` → Filter the rows array before passing it in
1011
+ - ❌ \`sortable without onSort\` → Handle onSort and sort the rows array in your state
1012
+
1013
+ ---
1014
+
1015
+ ### Tag
1016
+
1017
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
1018
+
1019
+ \`\`\`tsx
1020
+ import { Tag } from "@usevyre/react"
1021
+
1022
+ // Props:
1023
+ // variant = "default" | "accent" | "danger" (default: default)
1024
+ // size = "sm" | "md" | "lg" (default: md)
1025
+ // onRemove = () => void
1026
+ // onClick = () => void
1027
+ // disabled = boolean (default: false)
1028
+
1029
+ // Examples:
1030
+ <TagGroup>
1031
+ <Tag>Design</Tag>
1032
+ <Tag variant="accent">Featured</Tag>
1033
+ <Tag>Engineering</Tag>
1034
+ </TagGroup>
1035
+ <Tag onRemove={() => removeFilter("react")}>react</Tag>
1036
+ <Tag onClick={() => toggleFilter("vue")}>vue</Tag>
1037
+ \`\`\`
1038
+
1039
+ **Common mistakes:**
1040
+ - ❌ \`Tag variant="success"\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
1041
+ - ❌ \`Using Tag for tag input\` → Use TagsInput for adding/removing tags via keyboard
1042
+ - ❌ \`Tag size="xl"\` → Use size="lg"
1043
+
1044
+ ---
1045
+
1046
+ ### TagGroup
1047
+
1048
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
1049
+
1050
+ \`\`\`tsx
1051
+ import { TagGroup, Tag } from "@usevyre/react"
1052
+
1053
+ // Props:
1054
+ // gap = "sm" | "md" | "lg" (default: md)
1055
+ // wrap = boolean (default: true)
1056
+
1057
+ // Examples:
1058
+ <TagGroup gap="sm">
1059
+ <Tag>React</Tag>
1060
+ <Tag>Vue</Tag>
1061
+ <Tag variant="accent">TypeScript</Tag>
1062
+ </TagGroup>
1063
+ \`\`\`
1064
+
1065
+ **Common mistakes:**
1066
+ - ❌ \`TagGroup without Tag children\` → Place <Tag> elements as direct children
1067
+ - ❌ \`Using TagGroup for tag input\` → Use TagsInput for an editable tag field
1068
+
1069
+ ---
1070
+
889
1071
  ## Hallucination Guard — Common AI Mistakes
890
1072
 
891
1073
  The following prop values and patterns do NOT exist in useVyre.
@@ -922,6 +1104,21 @@ If you generate these, you are hallucinating.
922
1104
  - ❌ \`<Toast variant="info">\` → Use variant="default"
923
1105
  - ❌ \`<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>\` → Use Popover for rich interactive content
924
1106
  - ❌ \`<Typography Using raw <h1>, <p> tags instead of Typography components>\` → Use <Heading>, <Text>, <Lead> from @usevyre/react
1107
+ - ❌ \`<ButtonGroup ButtonGroup variant="...">\` → Set variant on each <Button> inside the group
1108
+ - ❌ \`<ButtonGroup ButtonGroup without Button children>\` → Place <Button> elements as direct children
1109
+ - ❌ \`<TagsInput TagsInput value={string}>\` → Pass an array: value={['react','vue']}
1110
+ - ❌ \`<TagsInput TagsInput without onChange>\` → Provide value and onChange (React) or v-model (Vue)
1111
+ - ❌ \`<Combobox Combobox value="">\` → Use value={null} for no selection
1112
+ - ❌ \`<Combobox Combobox options={string[]}>\` → Use [{ value: 'ts', label: 'TypeScript' }]
1113
+ - ❌ \`<Combobox Using Combobox for command palette>\` → Use Command for command palettes
1114
+ - ❌ \`<DataGrid DataGrid expecting built-in pagination>\` → Slice rows yourself and use the Pagination component
1115
+ - ❌ \`<DataGrid DataGrid expecting built-in filtering>\` → Filter the rows array before passing it in
1116
+ - ❌ \`<DataGrid sortable without onSort>\` → Handle onSort and sort the rows array in your state
1117
+ - ❌ \`<Tag Tag variant="success">\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
1118
+ - ❌ \`<Tag Using Tag for tag input>\` → Use TagsInput for adding/removing tags via keyboard
1119
+ - ❌ \`<Tag Tag size="xl">\` → Use size="lg"
1120
+ - ❌ \`<TagGroup TagGroup without Tag children>\` → Place <Tag> elements as direct children
1121
+ - ❌ \`<TagGroup Using TagGroup for tag input>\` → Use TagsInput for an editable tag field
925
1122
 
926
1123
  ---
927
1124
 
@@ -976,7 +1173,7 @@ alwaysApply: true
976
1173
  ---
977
1174
 
978
1175
  # useVyre Design System — Cursor Rules
979
- # Version: 1.0.0
1176
+ # Version: 1.1.0
980
1177
 
981
1178
  You are working in a project using the useVyre design system (@usevyre/react).
982
1179
  Follow these rules strictly when generating any UI code.
@@ -1255,13 +1452,84 @@ Import: \`import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
1255
1452
  Never do:
1256
1453
  - ❌ Using raw <h1>, <p> tags instead of Typography components → ✅ Use <Heading>, <Text>, <Lead> from @usevyre/react
1257
1454
 
1455
+ ## ButtonGroup
1456
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
1457
+ Import: \`import { ButtonGroup, Button } from "@usevyre/react"\`
1458
+
1459
+ Valid props:
1460
+ - orientation: "horizontal" | "vertical" [default: horizontal]
1461
+ - size: "sm" | "md" | "lg" | "icon"
1462
+
1463
+ Never do:
1464
+ - ❌ ButtonGroup variant="..." → ✅ Set variant on each <Button> inside the group
1465
+ - ❌ ButtonGroup without Button children → ✅ Place <Button> elements as direct children
1466
+
1467
+ ## TagsInput
1468
+ Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
1469
+ Import: \`import { TagsInput } from "@usevyre/react"\`
1470
+
1471
+ Valid props:
1472
+ - size: "sm" | "md" | "lg" [default: md]
1473
+
1474
+ Never do:
1475
+ - ❌ TagsInput value={string} → ✅ Pass an array: value={['react','vue']}
1476
+ - ❌ TagsInput without onChange → ✅ Provide value and onChange (React) or v-model (Vue)
1477
+
1478
+ ## Combobox
1479
+ Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).
1480
+ Import: \`import { Combobox } from "@usevyre/react"\`
1481
+
1482
+ Valid props:
1483
+ - size: "sm" | "md" | "lg" [default: md]
1484
+
1485
+ Never do:
1486
+ - ❌ Combobox value="" → ✅ Use value={null} for no selection
1487
+ - ❌ Combobox options={string[]} → ✅ Use [{ value: 'ts', label: 'TypeScript' }]
1488
+ - ❌ Using Combobox for command palette → ✅ Use Command for command palettes
1489
+
1490
+ ## DataGrid
1491
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
1492
+ Import: \`import { DataGrid } from "@usevyre/react"\`
1493
+
1494
+ Valid props:
1495
+ - sortDir: "asc" | "desc"
1496
+
1497
+ Never do:
1498
+ - ❌ DataGrid expecting built-in pagination → ✅ Slice rows yourself and use the Pagination component
1499
+ - ❌ DataGrid expecting built-in filtering → ✅ Filter the rows array before passing it in
1500
+ - ❌ sortable without onSort → ✅ Handle onSort and sort the rows array in your state
1501
+
1502
+ ## Tag
1503
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
1504
+ Import: \`import { Tag } from "@usevyre/react"\`
1505
+
1506
+ Valid props:
1507
+ - variant: "default" | "accent" | "danger" [default: default]
1508
+ - size: "sm" | "md" | "lg" [default: md]
1509
+
1510
+ Never do:
1511
+ - ❌ Tag variant="success" → ✅ Use Badge for success/warning/teal status colors; Tag is for categories/filters
1512
+ - ❌ Using Tag for tag input → ✅ Use TagsInput for adding/removing tags via keyboard
1513
+ - ❌ Tag size="xl" → ✅ Use size="lg"
1514
+
1515
+ ## TagGroup
1516
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
1517
+ Import: \`import { TagGroup, Tag } from "@usevyre/react"\`
1518
+
1519
+ Valid props:
1520
+ - gap: "sm" | "md" | "lg" [default: md]
1521
+
1522
+ Never do:
1523
+ - ❌ TagGroup without Tag children → ✅ Place <Tag> elements as direct children
1524
+ - ❌ Using TagGroup for tag input → ✅ Use TagsInput for an editable tag field
1525
+
1258
1526
  ## Token Rules
1259
1527
 
1260
1528
  Use --vyre-color-semantic-* for all colors. Never use primitive tokens.
1261
1529
  Use --vyre-spacing-* for all spacing. Never use raw px in component code.
1262
1530
  Use --vyre-border-radius-* for border radius.`;
1263
1531
  export const claudeContext = `# useVyre Design System Context
1264
- # Version: 1.0.0
1532
+ # Version: 1.1.0
1265
1533
 
1266
1534
  You are working in a codebase that uses the useVyre design system.
1267
1535
  Follow the rules below strictly when writing any UI code.
@@ -2149,6 +2417,188 @@ import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
2149
2417
 
2150
2418
  ---
2151
2419
 
2420
+ ### ButtonGroup
2421
+
2422
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
2423
+
2424
+ \`\`\`tsx
2425
+ import { ButtonGroup, Button } from "@usevyre/react"
2426
+
2427
+ // Props:
2428
+ // orientation = "horizontal" | "vertical" (default: horizontal)
2429
+ // attached = boolean (default: false)
2430
+ // size = "sm" | "md" | "lg" | "icon"
2431
+
2432
+ // Examples:
2433
+ <ButtonGroup attached>
2434
+ <Button variant="secondary">Day</Button>
2435
+ <Button variant="secondary">Week</Button>
2436
+ <Button variant="secondary">Month</Button>
2437
+ </ButtonGroup>
2438
+ <ButtonGroup orientation="vertical" attached>
2439
+ <Button variant="secondary">Top</Button>
2440
+ <Button variant="secondary">Bottom</Button>
2441
+ </ButtonGroup>
2442
+ \`\`\`
2443
+
2444
+ **Common mistakes:**
2445
+ - ❌ \`ButtonGroup variant="..."\` → Set variant on each <Button> inside the group
2446
+ - ❌ \`ButtonGroup without Button children\` → Place <Button> elements as direct children
2447
+
2448
+ ---
2449
+
2450
+ ### TagsInput
2451
+
2452
+ Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
2453
+
2454
+ \`\`\`tsx
2455
+ import { TagsInput } from "@usevyre/react"
2456
+
2457
+ // Props:
2458
+ // value = string[]
2459
+ // onChange = (tags: string[]) => void
2460
+ // placeholder = string
2461
+ // disabled = boolean (default: false)
2462
+ // max = number
2463
+ // size = "sm" | "md" | "lg" (default: md)
2464
+
2465
+ // Examples:
2466
+ const [tags, setTags] = useState<string[]>([]);
2467
+ <TagsInput value={tags} onChange={setTags} placeholder="Add a tag…" />
2468
+ <TagsInput value={tags} onChange={setTags} max={5} />
2469
+ \`\`\`
2470
+
2471
+ **Common mistakes:**
2472
+ - ❌ \`TagsInput value={string}\` → Pass an array: value={['react','vue']}
2473
+ - ❌ \`TagsInput without onChange\` → Provide value and onChange (React) or v-model (Vue)
2474
+
2475
+ ---
2476
+
2477
+ ### Combobox
2478
+
2479
+ Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).
2480
+
2481
+ \`\`\`tsx
2482
+ import { Combobox } from "@usevyre/react"
2483
+
2484
+ // Props:
2485
+ // options = { value: string; label: string; disabled?: boolean }[]
2486
+ // value = string | null
2487
+ // onChange = (value: string | null) => void
2488
+ // placeholder = string (default: "Search…")
2489
+ // disabled = boolean (default: false)
2490
+ // size = "sm" | "md" | "lg" (default: md)
2491
+ // emptyText = string (default: "No results")
2492
+
2493
+ // Examples:
2494
+ const [lang, setLang] = useState<string | null>(null);
2495
+ <Combobox
2496
+ options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
2497
+ value={lang}
2498
+ onChange={setLang}
2499
+ placeholder="Search language…"
2500
+ />
2501
+ \`\`\`
2502
+
2503
+ **Common mistakes:**
2504
+ - ❌ \`Combobox value=""\` → Use value={null} for no selection
2505
+ - ❌ \`Combobox options={string[]}\` → Use [{ value: 'ts', label: 'TypeScript' }]
2506
+ - ❌ \`Using Combobox for command palette\` → Use Command for command palettes
2507
+
2508
+ ---
2509
+
2510
+ ### DataGrid
2511
+
2512
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
2513
+
2514
+ \`\`\`tsx
2515
+ import { DataGrid } from "@usevyre/react"
2516
+
2517
+ // Props:
2518
+ // columns = { key: string; label: string; sortable?: boolean; width?: string }[]
2519
+ // rows = Record<string, unknown>[]
2520
+ // sortKey = string
2521
+ // sortDir = "asc" | "desc"
2522
+ // onSort = (key: string, dir: 'asc' | 'desc') => void
2523
+ // loading = boolean (default: false)
2524
+ // emptyText = string (default: "No data")
2525
+ // stickyHeader = boolean (default: false)
2526
+
2527
+ // Examples:
2528
+ const cols = [{ key: "name", label: "Name", sortable: true }];
2529
+ <DataGrid
2530
+ columns={cols}
2531
+ rows={people}
2532
+ sortKey={sortKey}
2533
+ sortDir={sortDir}
2534
+ onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
2535
+ />
2536
+ <DataGrid columns={cols} rows={[]} loading />
2537
+ \`\`\`
2538
+
2539
+ **Common mistakes:**
2540
+ - ❌ \`DataGrid expecting built-in pagination\` → Slice rows yourself and use the Pagination component
2541
+ - ❌ \`DataGrid expecting built-in filtering\` → Filter the rows array before passing it in
2542
+ - ❌ \`sortable without onSort\` → Handle onSort and sort the rows array in your state
2543
+
2544
+ ---
2545
+
2546
+ ### Tag
2547
+
2548
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
2549
+
2550
+ \`\`\`tsx
2551
+ import { Tag } from "@usevyre/react"
2552
+
2553
+ // Props:
2554
+ // variant = "default" | "accent" | "danger" (default: default)
2555
+ // size = "sm" | "md" | "lg" (default: md)
2556
+ // onRemove = () => void
2557
+ // onClick = () => void
2558
+ // disabled = boolean (default: false)
2559
+
2560
+ // Examples:
2561
+ <TagGroup>
2562
+ <Tag>Design</Tag>
2563
+ <Tag variant="accent">Featured</Tag>
2564
+ <Tag>Engineering</Tag>
2565
+ </TagGroup>
2566
+ <Tag onRemove={() => removeFilter("react")}>react</Tag>
2567
+ <Tag onClick={() => toggleFilter("vue")}>vue</Tag>
2568
+ \`\`\`
2569
+
2570
+ **Common mistakes:**
2571
+ - ❌ \`Tag variant="success"\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
2572
+ - ❌ \`Using Tag for tag input\` → Use TagsInput for adding/removing tags via keyboard
2573
+ - ❌ \`Tag size="xl"\` → Use size="lg"
2574
+
2575
+ ---
2576
+
2577
+ ### TagGroup
2578
+
2579
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
2580
+
2581
+ \`\`\`tsx
2582
+ import { TagGroup, Tag } from "@usevyre/react"
2583
+
2584
+ // Props:
2585
+ // gap = "sm" | "md" | "lg" (default: md)
2586
+ // wrap = boolean (default: true)
2587
+
2588
+ // Examples:
2589
+ <TagGroup gap="sm">
2590
+ <Tag>React</Tag>
2591
+ <Tag>Vue</Tag>
2592
+ <Tag variant="accent">TypeScript</Tag>
2593
+ </TagGroup>
2594
+ \`\`\`
2595
+
2596
+ **Common mistakes:**
2597
+ - ❌ \`TagGroup without Tag children\` → Place <Tag> elements as direct children
2598
+ - ❌ \`Using TagGroup for tag input\` → Use TagsInput for an editable tag field
2599
+
2600
+ ---
2601
+
2152
2602
  ## Hallucination Guard — Common AI Mistakes
2153
2603
 
2154
2604
  The following prop values and patterns do NOT exist in useVyre.
@@ -2185,6 +2635,21 @@ If you generate these, you are hallucinating.
2185
2635
  - ❌ \`<Toast variant="info">\` → Use variant="default"
2186
2636
  - ❌ \`<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>\` → Use Popover for rich interactive content
2187
2637
  - ❌ \`<Typography Using raw <h1>, <p> tags instead of Typography components>\` → Use <Heading>, <Text>, <Lead> from @usevyre/react
2638
+ - ❌ \`<ButtonGroup ButtonGroup variant="...">\` → Set variant on each <Button> inside the group
2639
+ - ❌ \`<ButtonGroup ButtonGroup without Button children>\` → Place <Button> elements as direct children
2640
+ - ❌ \`<TagsInput TagsInput value={string}>\` → Pass an array: value={['react','vue']}
2641
+ - ❌ \`<TagsInput TagsInput without onChange>\` → Provide value and onChange (React) or v-model (Vue)
2642
+ - ❌ \`<Combobox Combobox value="">\` → Use value={null} for no selection
2643
+ - ❌ \`<Combobox Combobox options={string[]}>\` → Use [{ value: 'ts', label: 'TypeScript' }]
2644
+ - ❌ \`<Combobox Using Combobox for command palette>\` → Use Command for command palettes
2645
+ - ❌ \`<DataGrid DataGrid expecting built-in pagination>\` → Slice rows yourself and use the Pagination component
2646
+ - ❌ \`<DataGrid DataGrid expecting built-in filtering>\` → Filter the rows array before passing it in
2647
+ - ❌ \`<DataGrid sortable without onSort>\` → Handle onSort and sort the rows array in your state
2648
+ - ❌ \`<Tag Tag variant="success">\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
2649
+ - ❌ \`<Tag Using Tag for tag input>\` → Use TagsInput for adding/removing tags via keyboard
2650
+ - ❌ \`<Tag Tag size="xl">\` → Use size="lg"
2651
+ - ❌ \`<TagGroup TagGroup without Tag children>\` → Place <Tag> elements as direct children
2652
+ - ❌ \`<TagGroup Using TagGroup for tag input>\` → Use TagsInput for an editable tag field
2188
2653
 
2189
2654
  ---
2190
2655
 
@@ -2234,7 +2699,7 @@ If you generate these, you are hallucinating.
2234
2699
  \`\`\`
2235
2700
  `;
2236
2701
  export const windsurfRules = `# useVyre Rules for Windsurf
2237
- # Version: 1.0.0
2702
+ # Version: 1.1.0
2238
2703
 
2239
2704
  # useVyre Design System — AI Context
2240
2705
  # Version: 0.2.0
@@ -3119,46 +3584,243 @@ import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
3119
3584
 
3120
3585
  ---
3121
3586
 
3122
- ## Hallucination Guard — Common AI Mistakes
3587
+ ### ButtonGroup
3123
3588
 
3124
- The following prop values and patterns do NOT exist in useVyre.
3125
- If you generate these, you are hallucinating.
3589
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
3126
3590
 
3127
- - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
3128
- - \`<Alert variant="error">\` Use variant="danger"
3129
- - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
3130
- - ❌ \`<Avatar size="xs">\` → Use size="sm"
3131
- - \`<Avatar size="2xl">\` Use size="xl"
3132
- - ❌ \`<Badge variant="primary">\` Use variant="accent" for brand color
3133
- - \`<Badge variant="error">\` Use variant="danger"
3134
- - ❌ \`<Badge variant="info">\` → Use variant="teal" for info-like styling
3135
- - ❌ \`<Breadcrumb Using plain <a> tags inside Breadcrumb>\` → Use BreadcrumbItem > BreadcrumbLink for each crumb
3136
- - ❌ \`<Button variant="blue">\` → Use variant="accent" for brand amber, or variant="teal" for teal
3137
- - ❌ \`<Button size="xl">\` → Use size="lg"
3138
- - ❌ \`<Button color="...">\` → Use variant prop instead
3139
- - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
3140
- - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
3141
- - \`<Calendar Using Calendar for time selection>\` → Combine with a separate time Input if time selection is needed
3142
- - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
3143
- - ❌ \`<Checkbox size="lg">\` → Use size="md"
3144
- - ❌ \`<Command Using Input type="search" for search UI>\` → Use Command + CommandInput + CommandList + CommandItem
3145
- - ❌ \`<DropdownMenu DropdownItem variant="primary">\` → Use variant="danger" for destructive items only
3146
- - ❌ \`<Field Applying state prop directly to Input>\` → Wrap Input in <Field state="error"> to apply validation styling
3147
- - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
3148
- - ❌ \`<Input type="search" for search UI>\` Import Command from @usevyre/react for search palettes
3149
- - ❌ \`<Modal size="xl">\`Use size="lg" or size="full"
3150
- - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
3151
- - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
3152
- - ❌ \`<Select Passing strings directly as children>\` → Pass options={[{ value: 'a', label: 'Option A' }]}
3153
- - ❌ \`<Toast Rendering <Toast> directly in JSX>\` → Use: const { toast } = useToast(); then toast({ title, variant })
3154
- - ❌ \`<Toast variant="error">\` → Use variant="danger"
3155
- - ❌ \`<Toast variant="info">\` → Use variant="default"
3156
- - ❌ \`<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>\` → Use Popover for rich interactive content
3157
- - ❌ \`<Typography Using raw <h1>, <p> tags instead of Typography components>\` → Use <Heading>, <Text>, <Lead> from @usevyre/react
3591
+ \`\`\`tsx
3592
+ import { ButtonGroup, Button } from "@usevyre/react"
3593
+
3594
+ // Props:
3595
+ // orientation = "horizontal" | "vertical" (default: horizontal)
3596
+ // attached = boolean (default: false)
3597
+ // size = "sm" | "md" | "lg" | "icon"
3598
+
3599
+ // Examples:
3600
+ <ButtonGroup attached>
3601
+ <Button variant="secondary">Day</Button>
3602
+ <Button variant="secondary">Week</Button>
3603
+ <Button variant="secondary">Month</Button>
3604
+ </ButtonGroup>
3605
+ <ButtonGroup orientation="vertical" attached>
3606
+ <Button variant="secondary">Top</Button>
3607
+ <Button variant="secondary">Bottom</Button>
3608
+ </ButtonGroup>
3609
+ \`\`\`
3610
+
3611
+ **Common mistakes:**
3612
+ - ❌ \`ButtonGroup variant="..."\` Set variant on each <Button> inside the group
3613
+ - ❌ \`ButtonGroup without Button children\` Place <Button> elements as direct children
3158
3614
 
3159
3615
  ---
3160
3616
 
3161
- ## Styling Rules for AI Agents
3617
+ ### TagsInput
3618
+
3619
+ Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
3620
+
3621
+ \`\`\`tsx
3622
+ import { TagsInput } from "@usevyre/react"
3623
+
3624
+ // Props:
3625
+ // value = string[]
3626
+ // onChange = (tags: string[]) => void
3627
+ // placeholder = string
3628
+ // disabled = boolean (default: false)
3629
+ // max = number
3630
+ // size = "sm" | "md" | "lg" (default: md)
3631
+
3632
+ // Examples:
3633
+ const [tags, setTags] = useState<string[]>([]);
3634
+ <TagsInput value={tags} onChange={setTags} placeholder="Add a tag…" />
3635
+ <TagsInput value={tags} onChange={setTags} max={5} />
3636
+ \`\`\`
3637
+
3638
+ **Common mistakes:**
3639
+ - ❌ \`TagsInput value={string}\` → Pass an array: value={['react','vue']}
3640
+ - ❌ \`TagsInput without onChange\` → Provide value and onChange (React) or v-model (Vue)
3641
+
3642
+ ---
3643
+
3644
+ ### Combobox
3645
+
3646
+ Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).
3647
+
3648
+ \`\`\`tsx
3649
+ import { Combobox } from "@usevyre/react"
3650
+
3651
+ // Props:
3652
+ // options = { value: string; label: string; disabled?: boolean }[]
3653
+ // value = string | null
3654
+ // onChange = (value: string | null) => void
3655
+ // placeholder = string (default: "Search…")
3656
+ // disabled = boolean (default: false)
3657
+ // size = "sm" | "md" | "lg" (default: md)
3658
+ // emptyText = string (default: "No results")
3659
+
3660
+ // Examples:
3661
+ const [lang, setLang] = useState<string | null>(null);
3662
+ <Combobox
3663
+ options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
3664
+ value={lang}
3665
+ onChange={setLang}
3666
+ placeholder="Search language…"
3667
+ />
3668
+ \`\`\`
3669
+
3670
+ **Common mistakes:**
3671
+ - ❌ \`Combobox value=""\` → Use value={null} for no selection
3672
+ - ❌ \`Combobox options={string[]}\` → Use [{ value: 'ts', label: 'TypeScript' }]
3673
+ - ❌ \`Using Combobox for command palette\` → Use Command for command palettes
3674
+
3675
+ ---
3676
+
3677
+ ### DataGrid
3678
+
3679
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
3680
+
3681
+ \`\`\`tsx
3682
+ import { DataGrid } from "@usevyre/react"
3683
+
3684
+ // Props:
3685
+ // columns = { key: string; label: string; sortable?: boolean; width?: string }[]
3686
+ // rows = Record<string, unknown>[]
3687
+ // sortKey = string
3688
+ // sortDir = "asc" | "desc"
3689
+ // onSort = (key: string, dir: 'asc' | 'desc') => void
3690
+ // loading = boolean (default: false)
3691
+ // emptyText = string (default: "No data")
3692
+ // stickyHeader = boolean (default: false)
3693
+
3694
+ // Examples:
3695
+ const cols = [{ key: "name", label: "Name", sortable: true }];
3696
+ <DataGrid
3697
+ columns={cols}
3698
+ rows={people}
3699
+ sortKey={sortKey}
3700
+ sortDir={sortDir}
3701
+ onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
3702
+ />
3703
+ <DataGrid columns={cols} rows={[]} loading />
3704
+ \`\`\`
3705
+
3706
+ **Common mistakes:**
3707
+ - ❌ \`DataGrid expecting built-in pagination\` → Slice rows yourself and use the Pagination component
3708
+ - ❌ \`DataGrid expecting built-in filtering\` → Filter the rows array before passing it in
3709
+ - ❌ \`sortable without onSort\` → Handle onSort and sort the rows array in your state
3710
+
3711
+ ---
3712
+
3713
+ ### Tag
3714
+
3715
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
3716
+
3717
+ \`\`\`tsx
3718
+ import { Tag } from "@usevyre/react"
3719
+
3720
+ // Props:
3721
+ // variant = "default" | "accent" | "danger" (default: default)
3722
+ // size = "sm" | "md" | "lg" (default: md)
3723
+ // onRemove = () => void
3724
+ // onClick = () => void
3725
+ // disabled = boolean (default: false)
3726
+
3727
+ // Examples:
3728
+ <TagGroup>
3729
+ <Tag>Design</Tag>
3730
+ <Tag variant="accent">Featured</Tag>
3731
+ <Tag>Engineering</Tag>
3732
+ </TagGroup>
3733
+ <Tag onRemove={() => removeFilter("react")}>react</Tag>
3734
+ <Tag onClick={() => toggleFilter("vue")}>vue</Tag>
3735
+ \`\`\`
3736
+
3737
+ **Common mistakes:**
3738
+ - ❌ \`Tag variant="success"\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
3739
+ - ❌ \`Using Tag for tag input\` → Use TagsInput for adding/removing tags via keyboard
3740
+ - ❌ \`Tag size="xl"\` → Use size="lg"
3741
+
3742
+ ---
3743
+
3744
+ ### TagGroup
3745
+
3746
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
3747
+
3748
+ \`\`\`tsx
3749
+ import { TagGroup, Tag } from "@usevyre/react"
3750
+
3751
+ // Props:
3752
+ // gap = "sm" | "md" | "lg" (default: md)
3753
+ // wrap = boolean (default: true)
3754
+
3755
+ // Examples:
3756
+ <TagGroup gap="sm">
3757
+ <Tag>React</Tag>
3758
+ <Tag>Vue</Tag>
3759
+ <Tag variant="accent">TypeScript</Tag>
3760
+ </TagGroup>
3761
+ \`\`\`
3762
+
3763
+ **Common mistakes:**
3764
+ - ❌ \`TagGroup without Tag children\` → Place <Tag> elements as direct children
3765
+ - ❌ \`Using TagGroup for tag input\` → Use TagsInput for an editable tag field
3766
+
3767
+ ---
3768
+
3769
+ ## Hallucination Guard — Common AI Mistakes
3770
+
3771
+ The following prop values and patterns do NOT exist in useVyre.
3772
+ If you generate these, you are hallucinating.
3773
+
3774
+ - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
3775
+ - ❌ \`<Alert variant="error">\` → Use variant="danger"
3776
+ - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
3777
+ - ❌ \`<Avatar size="xs">\` → Use size="sm"
3778
+ - ❌ \`<Avatar size="2xl">\` → Use size="xl"
3779
+ - ❌ \`<Badge variant="primary">\` → Use variant="accent" for brand color
3780
+ - ❌ \`<Badge variant="error">\` → Use variant="danger"
3781
+ - ❌ \`<Badge variant="info">\` → Use variant="teal" for info-like styling
3782
+ - ❌ \`<Breadcrumb Using plain <a> tags inside Breadcrumb>\` → Use BreadcrumbItem > BreadcrumbLink for each crumb
3783
+ - ❌ \`<Button variant="blue">\` → Use variant="accent" for brand amber, or variant="teal" for teal
3784
+ - ❌ \`<Button size="xl">\` → Use size="lg"
3785
+ - ❌ \`<Button color="...">\` → Use variant prop instead
3786
+ - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
3787
+ - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
3788
+ - ❌ \`<Calendar Using Calendar for time selection>\` → Combine with a separate time Input if time selection is needed
3789
+ - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
3790
+ - ❌ \`<Checkbox size="lg">\` → Use size="md"
3791
+ - ❌ \`<Command Using Input type="search" for search UI>\` → Use Command + CommandInput + CommandList + CommandItem
3792
+ - ❌ \`<DropdownMenu DropdownItem variant="primary">\` → Use variant="danger" for destructive items only
3793
+ - ❌ \`<Field Applying state prop directly to Input>\` → Wrap Input in <Field state="error"> to apply validation styling
3794
+ - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
3795
+ - ❌ \`<Input type="search" for search UI>\` → Import Command from @usevyre/react for search palettes
3796
+ - ❌ \`<Modal size="xl">\` → Use size="lg" or size="full"
3797
+ - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
3798
+ - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
3799
+ - ❌ \`<Select Passing strings directly as children>\` → Pass options={[{ value: 'a', label: 'Option A' }]}
3800
+ - ❌ \`<Toast Rendering <Toast> directly in JSX>\` → Use: const { toast } = useToast(); then toast({ title, variant })
3801
+ - ❌ \`<Toast variant="error">\` → Use variant="danger"
3802
+ - ❌ \`<Toast variant="info">\` → Use variant="default"
3803
+ - ❌ \`<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>\` → Use Popover for rich interactive content
3804
+ - ❌ \`<Typography Using raw <h1>, <p> tags instead of Typography components>\` → Use <Heading>, <Text>, <Lead> from @usevyre/react
3805
+ - ❌ \`<ButtonGroup ButtonGroup variant="...">\` → Set variant on each <Button> inside the group
3806
+ - ❌ \`<ButtonGroup ButtonGroup without Button children>\` → Place <Button> elements as direct children
3807
+ - ❌ \`<TagsInput TagsInput value={string}>\` → Pass an array: value={['react','vue']}
3808
+ - ❌ \`<TagsInput TagsInput without onChange>\` → Provide value and onChange (React) or v-model (Vue)
3809
+ - ❌ \`<Combobox Combobox value="">\` → Use value={null} for no selection
3810
+ - ❌ \`<Combobox Combobox options={string[]}>\` → Use [{ value: 'ts', label: 'TypeScript' }]
3811
+ - ❌ \`<Combobox Using Combobox for command palette>\` → Use Command for command palettes
3812
+ - ❌ \`<DataGrid DataGrid expecting built-in pagination>\` → Slice rows yourself and use the Pagination component
3813
+ - ❌ \`<DataGrid DataGrid expecting built-in filtering>\` → Filter the rows array before passing it in
3814
+ - ❌ \`<DataGrid sortable without onSort>\` → Handle onSort and sort the rows array in your state
3815
+ - ❌ \`<Tag Tag variant="success">\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
3816
+ - ❌ \`<Tag Using Tag for tag input>\` → Use TagsInput for adding/removing tags via keyboard
3817
+ - ❌ \`<Tag Tag size="xl">\` → Use size="lg"
3818
+ - ❌ \`<TagGroup TagGroup without Tag children>\` → Place <Tag> elements as direct children
3819
+ - ❌ \`<TagGroup Using TagGroup for tag input>\` → Use TagsInput for an editable tag field
3820
+
3821
+ ---
3822
+
3823
+ ## Styling Rules for AI Agents
3162
3824
 
3163
3825
  1. ALWAYS use semantic tokens (\`--vyre-color-semantic-*\`), never primitive tokens
3164
3826
  2. NEVER hardcode colors — every color decision has a semantic token
@@ -3204,7 +3866,7 @@ If you generate these, you are hallucinating.
3204
3866
  \`\`\`
3205
3867
  `;
3206
3868
  export const copilotInstructions = `# useVyre Copilot Instructions
3207
- # Version: 1.0.0
3869
+ # Version: 1.1.0
3208
3870
 
3209
3871
  When generating UI code in this project, follow the useVyre design system rules below.
3210
3872
 
@@ -4091,6 +4753,188 @@ import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
4091
4753
 
4092
4754
  ---
4093
4755
 
4756
+ ### ButtonGroup
4757
+
4758
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
4759
+
4760
+ \`\`\`tsx
4761
+ import { ButtonGroup, Button } from "@usevyre/react"
4762
+
4763
+ // Props:
4764
+ // orientation = "horizontal" | "vertical" (default: horizontal)
4765
+ // attached = boolean (default: false)
4766
+ // size = "sm" | "md" | "lg" | "icon"
4767
+
4768
+ // Examples:
4769
+ <ButtonGroup attached>
4770
+ <Button variant="secondary">Day</Button>
4771
+ <Button variant="secondary">Week</Button>
4772
+ <Button variant="secondary">Month</Button>
4773
+ </ButtonGroup>
4774
+ <ButtonGroup orientation="vertical" attached>
4775
+ <Button variant="secondary">Top</Button>
4776
+ <Button variant="secondary">Bottom</Button>
4777
+ </ButtonGroup>
4778
+ \`\`\`
4779
+
4780
+ **Common mistakes:**
4781
+ - ❌ \`ButtonGroup variant="..."\` → Set variant on each <Button> inside the group
4782
+ - ❌ \`ButtonGroup without Button children\` → Place <Button> elements as direct children
4783
+
4784
+ ---
4785
+
4786
+ ### TagsInput
4787
+
4788
+ Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
4789
+
4790
+ \`\`\`tsx
4791
+ import { TagsInput } from "@usevyre/react"
4792
+
4793
+ // Props:
4794
+ // value = string[]
4795
+ // onChange = (tags: string[]) => void
4796
+ // placeholder = string
4797
+ // disabled = boolean (default: false)
4798
+ // max = number
4799
+ // size = "sm" | "md" | "lg" (default: md)
4800
+
4801
+ // Examples:
4802
+ const [tags, setTags] = useState<string[]>([]);
4803
+ <TagsInput value={tags} onChange={setTags} placeholder="Add a tag…" />
4804
+ <TagsInput value={tags} onChange={setTags} max={5} />
4805
+ \`\`\`
4806
+
4807
+ **Common mistakes:**
4808
+ - ❌ \`TagsInput value={string}\` → Pass an array: value={['react','vue']}
4809
+ - ❌ \`TagsInput without onChange\` → Provide value and onChange (React) or v-model (Vue)
4810
+
4811
+ ---
4812
+
4813
+ ### Combobox
4814
+
4815
+ Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).
4816
+
4817
+ \`\`\`tsx
4818
+ import { Combobox } from "@usevyre/react"
4819
+
4820
+ // Props:
4821
+ // options = { value: string; label: string; disabled?: boolean }[]
4822
+ // value = string | null
4823
+ // onChange = (value: string | null) => void
4824
+ // placeholder = string (default: "Search…")
4825
+ // disabled = boolean (default: false)
4826
+ // size = "sm" | "md" | "lg" (default: md)
4827
+ // emptyText = string (default: "No results")
4828
+
4829
+ // Examples:
4830
+ const [lang, setLang] = useState<string | null>(null);
4831
+ <Combobox
4832
+ options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
4833
+ value={lang}
4834
+ onChange={setLang}
4835
+ placeholder="Search language…"
4836
+ />
4837
+ \`\`\`
4838
+
4839
+ **Common mistakes:**
4840
+ - ❌ \`Combobox value=""\` → Use value={null} for no selection
4841
+ - ❌ \`Combobox options={string[]}\` → Use [{ value: 'ts', label: 'TypeScript' }]
4842
+ - ❌ \`Using Combobox for command palette\` → Use Command for command palettes
4843
+
4844
+ ---
4845
+
4846
+ ### DataGrid
4847
+
4848
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
4849
+
4850
+ \`\`\`tsx
4851
+ import { DataGrid } from "@usevyre/react"
4852
+
4853
+ // Props:
4854
+ // columns = { key: string; label: string; sortable?: boolean; width?: string }[]
4855
+ // rows = Record<string, unknown>[]
4856
+ // sortKey = string
4857
+ // sortDir = "asc" | "desc"
4858
+ // onSort = (key: string, dir: 'asc' | 'desc') => void
4859
+ // loading = boolean (default: false)
4860
+ // emptyText = string (default: "No data")
4861
+ // stickyHeader = boolean (default: false)
4862
+
4863
+ // Examples:
4864
+ const cols = [{ key: "name", label: "Name", sortable: true }];
4865
+ <DataGrid
4866
+ columns={cols}
4867
+ rows={people}
4868
+ sortKey={sortKey}
4869
+ sortDir={sortDir}
4870
+ onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
4871
+ />
4872
+ <DataGrid columns={cols} rows={[]} loading />
4873
+ \`\`\`
4874
+
4875
+ **Common mistakes:**
4876
+ - ❌ \`DataGrid expecting built-in pagination\` → Slice rows yourself and use the Pagination component
4877
+ - ❌ \`DataGrid expecting built-in filtering\` → Filter the rows array before passing it in
4878
+ - ❌ \`sortable without onSort\` → Handle onSort and sort the rows array in your state
4879
+
4880
+ ---
4881
+
4882
+ ### Tag
4883
+
4884
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
4885
+
4886
+ \`\`\`tsx
4887
+ import { Tag } from "@usevyre/react"
4888
+
4889
+ // Props:
4890
+ // variant = "default" | "accent" | "danger" (default: default)
4891
+ // size = "sm" | "md" | "lg" (default: md)
4892
+ // onRemove = () => void
4893
+ // onClick = () => void
4894
+ // disabled = boolean (default: false)
4895
+
4896
+ // Examples:
4897
+ <TagGroup>
4898
+ <Tag>Design</Tag>
4899
+ <Tag variant="accent">Featured</Tag>
4900
+ <Tag>Engineering</Tag>
4901
+ </TagGroup>
4902
+ <Tag onRemove={() => removeFilter("react")}>react</Tag>
4903
+ <Tag onClick={() => toggleFilter("vue")}>vue</Tag>
4904
+ \`\`\`
4905
+
4906
+ **Common mistakes:**
4907
+ - ❌ \`Tag variant="success"\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
4908
+ - ❌ \`Using Tag for tag input\` → Use TagsInput for adding/removing tags via keyboard
4909
+ - ❌ \`Tag size="xl"\` → Use size="lg"
4910
+
4911
+ ---
4912
+
4913
+ ### TagGroup
4914
+
4915
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
4916
+
4917
+ \`\`\`tsx
4918
+ import { TagGroup, Tag } from "@usevyre/react"
4919
+
4920
+ // Props:
4921
+ // gap = "sm" | "md" | "lg" (default: md)
4922
+ // wrap = boolean (default: true)
4923
+
4924
+ // Examples:
4925
+ <TagGroup gap="sm">
4926
+ <Tag>React</Tag>
4927
+ <Tag>Vue</Tag>
4928
+ <Tag variant="accent">TypeScript</Tag>
4929
+ </TagGroup>
4930
+ \`\`\`
4931
+
4932
+ **Common mistakes:**
4933
+ - ❌ \`TagGroup without Tag children\` → Place <Tag> elements as direct children
4934
+ - ❌ \`Using TagGroup for tag input\` → Use TagsInput for an editable tag field
4935
+
4936
+ ---
4937
+
4094
4938
  ## Hallucination Guard — Common AI Mistakes
4095
4939
 
4096
4940
  The following prop values and patterns do NOT exist in useVyre.
@@ -4127,6 +4971,21 @@ If you generate these, you are hallucinating.
4127
4971
  - ❌ \`<Toast variant="info">\` → Use variant="default"
4128
4972
  - ❌ \`<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>\` → Use Popover for rich interactive content
4129
4973
  - ❌ \`<Typography Using raw <h1>, <p> tags instead of Typography components>\` → Use <Heading>, <Text>, <Lead> from @usevyre/react
4974
+ - ❌ \`<ButtonGroup ButtonGroup variant="...">\` → Set variant on each <Button> inside the group
4975
+ - ❌ \`<ButtonGroup ButtonGroup without Button children>\` → Place <Button> elements as direct children
4976
+ - ❌ \`<TagsInput TagsInput value={string}>\` → Pass an array: value={['react','vue']}
4977
+ - ❌ \`<TagsInput TagsInput without onChange>\` → Provide value and onChange (React) or v-model (Vue)
4978
+ - ❌ \`<Combobox Combobox value="">\` → Use value={null} for no selection
4979
+ - ❌ \`<Combobox Combobox options={string[]}>\` → Use [{ value: 'ts', label: 'TypeScript' }]
4980
+ - ❌ \`<Combobox Using Combobox for command palette>\` → Use Command for command palettes
4981
+ - ❌ \`<DataGrid DataGrid expecting built-in pagination>\` → Slice rows yourself and use the Pagination component
4982
+ - ❌ \`<DataGrid DataGrid expecting built-in filtering>\` → Filter the rows array before passing it in
4983
+ - ❌ \`<DataGrid sortable without onSort>\` → Handle onSort and sort the rows array in your state
4984
+ - ❌ \`<Tag Tag variant="success">\` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
4985
+ - ❌ \`<Tag Using Tag for tag input>\` → Use TagsInput for adding/removing tags via keyboard
4986
+ - ❌ \`<Tag Tag size="xl">\` → Use size="lg"
4987
+ - ❌ \`<TagGroup TagGroup without Tag children>\` → Place <Tag> elements as direct children
4988
+ - ❌ \`<TagGroup Using TagGroup for tag input>\` → Use TagsInput for an editable tag field
4130
4989
 
4131
4990
  ---
4132
4991
 
@@ -4178,15 +5037,20 @@ If you generate these, you are hallucinating.
4178
5037
 
4179
5038
  export const schema = {
4180
5039
  "$schema": "http://json-schema.org/draft-07/schema#",
4181
- "version": "1.0.0",
4182
- "generatedAt": "2026-05-13",
5040
+ "version": "1.1.0",
5041
+ "generatedAt": "2026-05-15",
4183
5042
  "package": "@usevyre/react",
4184
- "packageVersion": "1.0.0",
5043
+ "packageVersion": "1.1.0",
4185
5044
  "validFor": [
4186
- "@usevyre/react@1.0.0+",
4187
- "@usevyre/vue@1.0.0+"
5045
+ "@usevyre/react@1.1.0+",
5046
+ "@usevyre/vue@1.1.0+"
4188
5047
  ],
4189
5048
  "changelog": {
5049
+ "1.1.0": {
5050
+ "date": "2026-05-15",
5051
+ "breaking": false,
5052
+ "summary": "Added 6 components: ButtonGroup, TagsInput, Combobox, DataGrid, Tag, TagGroup"
5053
+ },
4190
5054
  "1.0.0": {
4191
5055
  "date": "2026-05-13",
4192
5056
  "breaking": true,
@@ -5456,12 +6320,370 @@ export const schema = {
5456
6320
  "code": "<Heading size=\"2xl\" as=\"h1\">Dashboard</Heading>\n<Lead>Welcome back. Here's what's happening today.</Lead>\n<Text size=\"sm\" style={{ color: 'var(--vyre-color-semantic-text-muted)' }}>Last updated 5 minutes ago.</Text>"
5457
6321
  }
5458
6322
  ]
6323
+ },
6324
+ "ButtonGroup": {
6325
+ "description": "Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.",
6326
+ "import": "import { ButtonGroup, Button } from \"@usevyre/react\"",
6327
+ "props": {
6328
+ "orientation": {
6329
+ "type": "enum",
6330
+ "values": [
6331
+ "horizontal",
6332
+ "vertical"
6333
+ ],
6334
+ "default": "horizontal",
6335
+ "description": "Layout direction of grouped buttons"
6336
+ },
6337
+ "attached": {
6338
+ "type": "boolean",
6339
+ "default": false,
6340
+ "description": "Remove gap so buttons share collapsed borders (segmented control look)"
6341
+ },
6342
+ "size": {
6343
+ "type": "enum",
6344
+ "values": [
6345
+ "sm",
6346
+ "md",
6347
+ "lg",
6348
+ "icon"
6349
+ ],
6350
+ "description": "Size forwarded to all child buttons"
6351
+ }
6352
+ },
6353
+ "antiPatterns": [
6354
+ {
6355
+ "pattern": "ButtonGroup variant=\"...\"",
6356
+ "reason": "ButtonGroup has no variant prop — variant goes on each child Button",
6357
+ "fix": "Set variant on each <Button> inside the group"
6358
+ },
6359
+ {
6360
+ "pattern": "ButtonGroup without Button children",
6361
+ "reason": "ButtonGroup is a layout wrapper for Button elements",
6362
+ "fix": "Place <Button> elements as direct children"
6363
+ }
6364
+ ],
6365
+ "examples": [
6366
+ {
6367
+ "description": "Segmented control",
6368
+ "code": "<ButtonGroup attached>\n <Button variant=\"secondary\">Day</Button>\n <Button variant=\"secondary\">Week</Button>\n <Button variant=\"secondary\">Month</Button>\n</ButtonGroup>"
6369
+ },
6370
+ {
6371
+ "description": "Vertical group",
6372
+ "code": "<ButtonGroup orientation=\"vertical\" attached>\n <Button variant=\"secondary\">Top</Button>\n <Button variant=\"secondary\">Bottom</Button>\n</ButtonGroup>"
6373
+ }
6374
+ ]
6375
+ },
6376
+ "TagsInput": {
6377
+ "description": "Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.",
6378
+ "import": "import { TagsInput } from \"@usevyre/react\"",
6379
+ "props": {
6380
+ "value": {
6381
+ "type": "string[]",
6382
+ "description": "Controlled list of tags (required)"
6383
+ },
6384
+ "onChange": {
6385
+ "type": "(tags: string[]) => void",
6386
+ "description": "Called with the new tag array on every change. React only — Vue uses v-model"
6387
+ },
6388
+ "placeholder": {
6389
+ "type": "string",
6390
+ "description": "Input placeholder, hidden when max is reached"
6391
+ },
6392
+ "disabled": {
6393
+ "type": "boolean",
6394
+ "default": false,
6395
+ "description": "Disables all interaction"
6396
+ },
6397
+ "max": {
6398
+ "type": "number",
6399
+ "description": "Maximum number of tags; input is disabled when reached"
6400
+ },
6401
+ "size": {
6402
+ "type": "enum",
6403
+ "values": [
6404
+ "sm",
6405
+ "md",
6406
+ "lg"
6407
+ ],
6408
+ "default": "md",
6409
+ "description": "Size scale"
6410
+ }
6411
+ },
6412
+ "antiPatterns": [
6413
+ {
6414
+ "pattern": "TagsInput value={string}",
6415
+ "reason": "value must be a string array, not a string",
6416
+ "fix": "Pass an array: value={['react','vue']}"
6417
+ },
6418
+ {
6419
+ "pattern": "TagsInput without onChange",
6420
+ "reason": "TagsInput is controlled — it needs onChange to update",
6421
+ "fix": "Provide value and onChange (React) or v-model (Vue)"
6422
+ }
6423
+ ],
6424
+ "examples": [
6425
+ {
6426
+ "description": "Basic tags input",
6427
+ "code": "const [tags, setTags] = useState<string[]>([]);\n<TagsInput value={tags} onChange={setTags} placeholder=\"Add a tag…\" />"
6428
+ },
6429
+ {
6430
+ "description": "Limited to 5 tags",
6431
+ "code": "<TagsInput value={tags} onChange={setTags} max={5} />"
6432
+ }
6433
+ ]
6434
+ },
6435
+ "Combobox": {
6436
+ "description": "Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).",
6437
+ "import": "import { Combobox } from \"@usevyre/react\"",
6438
+ "props": {
6439
+ "options": {
6440
+ "type": "{ value: string; label: string; disabled?: boolean }[]",
6441
+ "description": "Selectable options (required)"
6442
+ },
6443
+ "value": {
6444
+ "type": "string | null",
6445
+ "description": "Controlled selected value; null clears selection (required)"
6446
+ },
6447
+ "onChange": {
6448
+ "type": "(value: string | null) => void",
6449
+ "description": "Called when selection changes. React only — Vue uses v-model"
6450
+ },
6451
+ "placeholder": {
6452
+ "type": "string",
6453
+ "default": "\"Search…\"",
6454
+ "description": "Input placeholder when nothing is selected"
6455
+ },
6456
+ "disabled": {
6457
+ "type": "boolean",
6458
+ "default": false,
6459
+ "description": "Disables the combobox"
6460
+ },
6461
+ "size": {
6462
+ "type": "enum",
6463
+ "values": [
6464
+ "sm",
6465
+ "md",
6466
+ "lg"
6467
+ ],
6468
+ "default": "md",
6469
+ "description": "Height scale"
6470
+ },
6471
+ "emptyText": {
6472
+ "type": "string",
6473
+ "default": "\"No results\"",
6474
+ "description": "Text shown when search matches no options"
6475
+ }
6476
+ },
6477
+ "antiPatterns": [
6478
+ {
6479
+ "pattern": "Combobox value=\"\"",
6480
+ "reason": "Empty selection must be null, not empty string",
6481
+ "fix": "Use value={null} for no selection"
6482
+ },
6483
+ {
6484
+ "pattern": "Combobox options={string[]}",
6485
+ "reason": "options must be objects with value and label",
6486
+ "fix": "Use [{ value: 'ts', label: 'TypeScript' }]"
6487
+ },
6488
+ {
6489
+ "pattern": "Using Combobox for command palette",
6490
+ "reason": "Combobox is single-value select, not an action palette",
6491
+ "fix": "Use Command for command palettes"
6492
+ }
6493
+ ],
6494
+ "examples": [
6495
+ {
6496
+ "description": "Searchable language picker",
6497
+ "code": "const [lang, setLang] = useState<string | null>(null);\n<Combobox\n options={[{ value: \"ts\", label: \"TypeScript\" }, { value: \"go\", label: \"Go\" }]}\n value={lang}\n onChange={setLang}\n placeholder=\"Search language…\"\n/>"
6498
+ }
6499
+ ]
6500
+ },
6501
+ "DataGrid": {
6502
+ "description": "Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.",
6503
+ "import": "import { DataGrid } from \"@usevyre/react\"",
6504
+ "props": {
6505
+ "columns": {
6506
+ "type": "{ key: string; label: string; sortable?: boolean; width?: string }[]",
6507
+ "description": "Column definitions (required)"
6508
+ },
6509
+ "rows": {
6510
+ "type": "Record<string, unknown>[]",
6511
+ "description": "Row data; each object keyed by column key (required)"
6512
+ },
6513
+ "sortKey": {
6514
+ "type": "string",
6515
+ "description": "Controlled active sort column key"
6516
+ },
6517
+ "sortDir": {
6518
+ "type": "enum",
6519
+ "values": [
6520
+ "asc",
6521
+ "desc"
6522
+ ],
6523
+ "description": "Controlled sort direction"
6524
+ },
6525
+ "onSort": {
6526
+ "type": "(key: string, dir: 'asc' | 'desc') => void",
6527
+ "description": "Called when a sortable header is clicked. React only — Vue emits sort + v-model:sortKey/sortDir"
6528
+ },
6529
+ "loading": {
6530
+ "type": "boolean",
6531
+ "default": false,
6532
+ "description": "Show skeleton placeholder rows"
6533
+ },
6534
+ "emptyText": {
6535
+ "type": "string",
6536
+ "default": "\"No data\"",
6537
+ "description": "Message shown when rows is empty"
6538
+ },
6539
+ "stickyHeader": {
6540
+ "type": "boolean",
6541
+ "default": false,
6542
+ "description": "Keep the header visible while scrolling"
6543
+ }
6544
+ },
6545
+ "antiPatterns": [
6546
+ {
6547
+ "pattern": "DataGrid expecting built-in pagination",
6548
+ "reason": "DataGrid does not paginate — it only sorts",
6549
+ "fix": "Slice rows yourself and use the Pagination component"
6550
+ },
6551
+ {
6552
+ "pattern": "DataGrid expecting built-in filtering",
6553
+ "reason": "DataGrid does not filter rows",
6554
+ "fix": "Filter the rows array before passing it in"
6555
+ },
6556
+ {
6557
+ "pattern": "sortable without onSort",
6558
+ "reason": "Sorting is controlled — the grid does not sort data itself",
6559
+ "fix": "Handle onSort and sort the rows array in your state"
6560
+ }
6561
+ ],
6562
+ "examples": [
6563
+ {
6564
+ "description": "Sortable grid",
6565
+ "code": "const cols = [{ key: \"name\", label: \"Name\", sortable: true }];\n<DataGrid\n columns={cols}\n rows={people}\n sortKey={sortKey}\n sortDir={sortDir}\n onSort={(k, d) => { setSortKey(k); setSortDir(d); }}\n/>"
6566
+ },
6567
+ {
6568
+ "description": "Loading state",
6569
+ "code": "<DataGrid columns={cols} rows={[]} loading />"
6570
+ }
6571
+ ]
6572
+ },
6573
+ "Tag": {
6574
+ "description": "Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.",
6575
+ "import": "import { Tag } from \"@usevyre/react\"",
6576
+ "props": {
6577
+ "variant": {
6578
+ "type": "enum",
6579
+ "values": [
6580
+ "default",
6581
+ "accent",
6582
+ "danger"
6583
+ ],
6584
+ "default": "default",
6585
+ "description": "Visual style. default=neutral, accent=brand, danger=destructive/error"
6586
+ },
6587
+ "size": {
6588
+ "type": "enum",
6589
+ "values": [
6590
+ "sm",
6591
+ "md",
6592
+ "lg"
6593
+ ],
6594
+ "default": "md",
6595
+ "description": "Size scale"
6596
+ },
6597
+ "onRemove": {
6598
+ "type": "() => void",
6599
+ "description": "React only. When provided, renders a × remove button. Vue: use `removable` prop + @remove event"
6600
+ },
6601
+ "onClick": {
6602
+ "type": "() => void",
6603
+ "description": "React only. When provided, makes the whole tag interactive (keyboard accessible). Vue: use `clickable` prop + @click event"
6604
+ },
6605
+ "disabled": {
6606
+ "type": "boolean",
6607
+ "default": false,
6608
+ "description": "Disables interaction (only relevant with onClick/onRemove)"
6609
+ }
6610
+ },
6611
+ "antiPatterns": [
6612
+ {
6613
+ "pattern": "Tag variant=\"success\"",
6614
+ "reason": "Tag only has default, accent, danger variants (unlike Badge which has more)",
6615
+ "fix": "Use Badge for success/warning/teal status colors; Tag is for categories/filters"
6616
+ },
6617
+ {
6618
+ "pattern": "Using Tag for tag input",
6619
+ "reason": "Tag is display-only, it does not accept typed input",
6620
+ "fix": "Use TagsInput for adding/removing tags via keyboard"
6621
+ },
6622
+ {
6623
+ "pattern": "Tag size=\"xl\"",
6624
+ "reason": "Maximum size is 'lg'",
6625
+ "fix": "Use size=\"lg\""
6626
+ }
6627
+ ],
6628
+ "examples": [
6629
+ {
6630
+ "description": "Category tags in a group",
6631
+ "code": "<TagGroup>\n <Tag>Design</Tag>\n <Tag variant=\"accent\">Featured</Tag>\n <Tag>Engineering</Tag>\n</TagGroup>"
6632
+ },
6633
+ {
6634
+ "description": "Removable filter chip (React)",
6635
+ "code": "<Tag onRemove={() => removeFilter(\"react\")}>react</Tag>"
6636
+ },
6637
+ {
6638
+ "description": "Clickable toggle tag (React)",
6639
+ "code": "<Tag onClick={() => toggleFilter(\"vue\")}>vue</Tag>"
6640
+ }
6641
+ ]
6642
+ },
6643
+ "TagGroup": {
6644
+ "description": "Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.",
6645
+ "import": "import { TagGroup, Tag } from \"@usevyre/react\"",
6646
+ "props": {
6647
+ "gap": {
6648
+ "type": "enum",
6649
+ "values": [
6650
+ "sm",
6651
+ "md",
6652
+ "lg"
6653
+ ],
6654
+ "default": "md",
6655
+ "description": "Spacing between tags"
6656
+ },
6657
+ "wrap": {
6658
+ "type": "boolean",
6659
+ "default": true,
6660
+ "description": "Wrap tags onto multiple lines when they overflow; set false for single-line scroll"
6661
+ }
6662
+ },
6663
+ "antiPatterns": [
6664
+ {
6665
+ "pattern": "TagGroup without Tag children",
6666
+ "reason": "TagGroup is a layout wrapper for Tag elements",
6667
+ "fix": "Place <Tag> elements as direct children"
6668
+ },
6669
+ {
6670
+ "pattern": "Using TagGroup for tag input",
6671
+ "reason": "TagGroup is display-only",
6672
+ "fix": "Use TagsInput for an editable tag field"
6673
+ }
6674
+ ],
6675
+ "examples": [
6676
+ {
6677
+ "description": "Tag group with mixed variants",
6678
+ "code": "<TagGroup gap=\"sm\">\n <Tag>React</Tag>\n <Tag>Vue</Tag>\n <Tag variant=\"accent\">TypeScript</Tag>\n</TagGroup>"
6679
+ }
6680
+ ]
5459
6681
  }
5460
6682
  }
5461
6683
  };
5462
6684
 
5463
6685
  export const antiPatterns = {
5464
- "version": "1.0.0",
6686
+ "version": "1.1.0",
5465
6687
  "rules": [
5466
6688
  {
5467
6689
  "component": "Accordion",
@@ -5679,19 +6901,129 @@ export const antiPatterns = {
5679
6901
  "reason": "Typography components apply the correct token-based styles",
5680
6902
  "fix": "Use <Heading>, <Text>, <Lead> from @usevyre/react",
5681
6903
  "severity": "error"
6904
+ },
6905
+ {
6906
+ "component": "ButtonGroup",
6907
+ "pattern": "ButtonGroup variant=\"...\"",
6908
+ "reason": "ButtonGroup has no variant prop — variant goes on each child Button",
6909
+ "fix": "Set variant on each <Button> inside the group",
6910
+ "severity": "error"
6911
+ },
6912
+ {
6913
+ "component": "ButtonGroup",
6914
+ "pattern": "ButtonGroup without Button children",
6915
+ "reason": "ButtonGroup is a layout wrapper for Button elements",
6916
+ "fix": "Place <Button> elements as direct children",
6917
+ "severity": "error"
6918
+ },
6919
+ {
6920
+ "component": "TagsInput",
6921
+ "pattern": "TagsInput value={string}",
6922
+ "reason": "value must be a string array, not a string",
6923
+ "fix": "Pass an array: value={['react','vue']}",
6924
+ "severity": "error"
6925
+ },
6926
+ {
6927
+ "component": "TagsInput",
6928
+ "pattern": "TagsInput without onChange",
6929
+ "reason": "TagsInput is controlled — it needs onChange to update",
6930
+ "fix": "Provide value and onChange (React) or v-model (Vue)",
6931
+ "severity": "error"
6932
+ },
6933
+ {
6934
+ "component": "Combobox",
6935
+ "pattern": "Combobox value=\"\"",
6936
+ "reason": "Empty selection must be null, not empty string",
6937
+ "fix": "Use value={null} for no selection",
6938
+ "severity": "error"
6939
+ },
6940
+ {
6941
+ "component": "Combobox",
6942
+ "pattern": "Combobox options={string[]}",
6943
+ "reason": "options must be objects with value and label",
6944
+ "fix": "Use [{ value: 'ts', label: 'TypeScript' }]",
6945
+ "severity": "error"
6946
+ },
6947
+ {
6948
+ "component": "Combobox",
6949
+ "pattern": "Using Combobox for command palette",
6950
+ "reason": "Combobox is single-value select, not an action palette",
6951
+ "fix": "Use Command for command palettes",
6952
+ "severity": "error"
6953
+ },
6954
+ {
6955
+ "component": "DataGrid",
6956
+ "pattern": "DataGrid expecting built-in pagination",
6957
+ "reason": "DataGrid does not paginate — it only sorts",
6958
+ "fix": "Slice rows yourself and use the Pagination component",
6959
+ "severity": "error"
6960
+ },
6961
+ {
6962
+ "component": "DataGrid",
6963
+ "pattern": "DataGrid expecting built-in filtering",
6964
+ "reason": "DataGrid does not filter rows",
6965
+ "fix": "Filter the rows array before passing it in",
6966
+ "severity": "error"
6967
+ },
6968
+ {
6969
+ "component": "DataGrid",
6970
+ "pattern": "sortable without onSort",
6971
+ "reason": "Sorting is controlled — the grid does not sort data itself",
6972
+ "fix": "Handle onSort and sort the rows array in your state",
6973
+ "severity": "error"
6974
+ },
6975
+ {
6976
+ "component": "Tag",
6977
+ "pattern": "Tag variant=\"success\"",
6978
+ "reason": "Tag only has default, accent, danger variants (unlike Badge which has more)",
6979
+ "fix": "Use Badge for success/warning/teal status colors; Tag is for categories/filters",
6980
+ "severity": "error"
6981
+ },
6982
+ {
6983
+ "component": "Tag",
6984
+ "pattern": "Using Tag for tag input",
6985
+ "reason": "Tag is display-only, it does not accept typed input",
6986
+ "fix": "Use TagsInput for adding/removing tags via keyboard",
6987
+ "severity": "error"
6988
+ },
6989
+ {
6990
+ "component": "Tag",
6991
+ "pattern": "Tag size=\"xl\"",
6992
+ "reason": "Maximum size is 'lg'",
6993
+ "fix": "Use size=\"lg\"",
6994
+ "severity": "error"
6995
+ },
6996
+ {
6997
+ "component": "TagGroup",
6998
+ "pattern": "TagGroup without Tag children",
6999
+ "reason": "TagGroup is a layout wrapper for Tag elements",
7000
+ "fix": "Place <Tag> elements as direct children",
7001
+ "severity": "error"
7002
+ },
7003
+ {
7004
+ "component": "TagGroup",
7005
+ "pattern": "Using TagGroup for tag input",
7006
+ "reason": "TagGroup is display-only",
7007
+ "fix": "Use TagsInput for an editable tag field",
7008
+ "severity": "error"
5682
7009
  }
5683
7010
  ]
5684
7011
  };
5685
7012
 
5686
7013
  export const versionInfo = {
5687
- "version": "1.0.0",
5688
- "packageVersion": "1.0.0",
5689
- "generatedAt": "2026-05-13T08:35:50.053Z",
7014
+ "version": "1.1.0",
7015
+ "packageVersion": "1.1.0",
7016
+ "generatedAt": "2026-05-15T15:01:34.101Z",
5690
7017
  "validFor": [
5691
- "@usevyre/react@1.0.0+",
5692
- "@usevyre/vue@1.0.0+"
7018
+ "@usevyre/react@1.1.0+",
7019
+ "@usevyre/vue@1.1.0+"
5693
7020
  ],
5694
7021
  "changelog": {
7022
+ "1.1.0": {
7023
+ "date": "2026-05-15",
7024
+ "breaking": false,
7025
+ "summary": "Added 6 components: ButtonGroup, TagsInput, Combobox, DataGrid, Tag, TagGroup"
7026
+ },
5695
7027
  "1.0.0": {
5696
7028
  "date": "2026-05-13",
5697
7029
  "breaking": true,
@@ -5710,211 +7042,253 @@ export const versionInfo = {
5710
7042
  },
5711
7043
  "components": {
5712
7044
  "Accordion": {
5713
- "version": "1.0.0",
5714
- "lastUpdated": "2026-05-13",
7045
+ "version": "1.1.0",
7046
+ "lastUpdated": "2026-05-15",
5715
7047
  "breaking": false,
5716
7048
  "stable": true,
5717
7049
  "changelog": null
5718
7050
  },
5719
7051
  "Alert": {
5720
- "version": "1.0.0",
5721
- "lastUpdated": "2026-05-13",
7052
+ "version": "1.1.0",
7053
+ "lastUpdated": "2026-05-15",
5722
7054
  "breaking": false,
5723
7055
  "stable": true,
5724
7056
  "changelog": null
5725
7057
  },
5726
7058
  "Avatar": {
5727
- "version": "1.0.0",
5728
- "lastUpdated": "2026-05-13",
7059
+ "version": "1.1.0",
7060
+ "lastUpdated": "2026-05-15",
5729
7061
  "breaking": false,
5730
7062
  "stable": true,
5731
7063
  "changelog": null
5732
7064
  },
5733
7065
  "Badge": {
5734
- "version": "1.0.0",
5735
- "lastUpdated": "2026-05-13",
7066
+ "version": "1.1.0",
7067
+ "lastUpdated": "2026-05-15",
5736
7068
  "breaking": false,
5737
7069
  "stable": true,
5738
7070
  "changelog": null
5739
7071
  },
5740
7072
  "Breadcrumb": {
5741
- "version": "1.0.0",
5742
- "lastUpdated": "2026-05-13",
7073
+ "version": "1.1.0",
7074
+ "lastUpdated": "2026-05-15",
5743
7075
  "breaking": false,
5744
7076
  "stable": true,
5745
7077
  "changelog": null
5746
7078
  },
5747
7079
  "Button": {
5748
- "version": "1.0.0",
5749
- "lastUpdated": "2026-05-13",
7080
+ "version": "1.1.0",
7081
+ "lastUpdated": "2026-05-15",
5750
7082
  "breaking": false,
5751
7083
  "stable": true,
5752
7084
  "changelog": null
5753
7085
  },
5754
7086
  "Calendar": {
5755
- "version": "1.0.0",
5756
- "lastUpdated": "2026-05-13",
7087
+ "version": "1.1.0",
7088
+ "lastUpdated": "2026-05-15",
5757
7089
  "breaking": false,
5758
7090
  "stable": true,
5759
7091
  "changelog": null
5760
7092
  },
5761
7093
  "Card": {
5762
- "version": "1.0.0",
5763
- "lastUpdated": "2026-05-13",
7094
+ "version": "1.1.0",
7095
+ "lastUpdated": "2026-05-15",
5764
7096
  "breaking": false,
5765
7097
  "stable": true,
5766
7098
  "changelog": null
5767
7099
  },
5768
7100
  "Checkbox": {
5769
- "version": "1.0.0",
5770
- "lastUpdated": "2026-05-13",
7101
+ "version": "1.1.0",
7102
+ "lastUpdated": "2026-05-15",
5771
7103
  "breaking": false,
5772
7104
  "stable": true,
5773
7105
  "changelog": null
5774
7106
  },
5775
7107
  "Command": {
5776
- "version": "1.0.0",
5777
- "lastUpdated": "2026-05-13",
7108
+ "version": "1.1.0",
7109
+ "lastUpdated": "2026-05-15",
5778
7110
  "breaking": false,
5779
7111
  "stable": true,
5780
7112
  "changelog": null
5781
7113
  },
5782
7114
  "DropdownMenu": {
5783
- "version": "1.0.0",
5784
- "lastUpdated": "2026-05-13",
7115
+ "version": "1.1.0",
7116
+ "lastUpdated": "2026-05-15",
5785
7117
  "breaking": false,
5786
7118
  "stable": true,
5787
7119
  "changelog": null
5788
7120
  },
5789
7121
  "Field": {
5790
- "version": "1.0.0",
5791
- "lastUpdated": "2026-05-13",
7122
+ "version": "1.1.0",
7123
+ "lastUpdated": "2026-05-15",
5792
7124
  "breaking": false,
5793
7125
  "stable": true,
5794
7126
  "changelog": null
5795
7127
  },
5796
7128
  "Input": {
5797
- "version": "1.0.0",
5798
- "lastUpdated": "2026-05-13",
7129
+ "version": "1.1.0",
7130
+ "lastUpdated": "2026-05-15",
5799
7131
  "breaking": false,
5800
7132
  "stable": true,
5801
7133
  "changelog": null
5802
7134
  },
5803
7135
  "Label": {
5804
- "version": "1.0.0",
5805
- "lastUpdated": "2026-05-13",
7136
+ "version": "1.1.0",
7137
+ "lastUpdated": "2026-05-15",
5806
7138
  "breaking": false,
5807
7139
  "stable": true,
5808
7140
  "changelog": null
5809
7141
  },
5810
7142
  "Modal": {
5811
- "version": "1.0.0",
5812
- "lastUpdated": "2026-05-13",
7143
+ "version": "1.1.0",
7144
+ "lastUpdated": "2026-05-15",
5813
7145
  "breaking": false,
5814
7146
  "stable": true,
5815
7147
  "changelog": null
5816
7148
  },
5817
7149
  "Pagination": {
5818
- "version": "1.0.0",
5819
- "lastUpdated": "2026-05-13",
7150
+ "version": "1.1.0",
7151
+ "lastUpdated": "2026-05-15",
5820
7152
  "breaking": false,
5821
7153
  "stable": true,
5822
7154
  "changelog": null
5823
7155
  },
5824
7156
  "Popover": {
5825
- "version": "1.0.0",
5826
- "lastUpdated": "2026-05-13",
7157
+ "version": "1.1.0",
7158
+ "lastUpdated": "2026-05-15",
5827
7159
  "breaking": false,
5828
7160
  "stable": true,
5829
7161
  "changelog": null
5830
7162
  },
5831
7163
  "Progress": {
5832
- "version": "1.0.0",
5833
- "lastUpdated": "2026-05-13",
7164
+ "version": "1.1.0",
7165
+ "lastUpdated": "2026-05-15",
5834
7166
  "breaking": false,
5835
7167
  "stable": true,
5836
7168
  "changelog": null
5837
7169
  },
5838
7170
  "Select": {
5839
- "version": "1.0.0",
5840
- "lastUpdated": "2026-05-13",
7171
+ "version": "1.1.0",
7172
+ "lastUpdated": "2026-05-15",
5841
7173
  "breaking": false,
5842
7174
  "stable": true,
5843
7175
  "changelog": null
5844
7176
  },
5845
7177
  "Separator": {
5846
- "version": "1.0.0",
5847
- "lastUpdated": "2026-05-13",
7178
+ "version": "1.1.0",
7179
+ "lastUpdated": "2026-05-15",
5848
7180
  "breaking": false,
5849
7181
  "stable": true,
5850
7182
  "changelog": null
5851
7183
  },
5852
7184
  "Sheet": {
5853
- "version": "1.0.0",
5854
- "lastUpdated": "2026-05-13",
7185
+ "version": "1.1.0",
7186
+ "lastUpdated": "2026-05-15",
5855
7187
  "breaking": false,
5856
7188
  "stable": true,
5857
7189
  "changelog": null
5858
7190
  },
5859
7191
  "Sidebar": {
5860
- "version": "1.0.0",
5861
- "lastUpdated": "2026-05-13",
7192
+ "version": "1.1.0",
7193
+ "lastUpdated": "2026-05-15",
5862
7194
  "breaking": false,
5863
7195
  "stable": true,
5864
7196
  "changelog": null
5865
7197
  },
5866
7198
  "Skeleton": {
5867
- "version": "1.0.0",
5868
- "lastUpdated": "2026-05-13",
7199
+ "version": "1.1.0",
7200
+ "lastUpdated": "2026-05-15",
5869
7201
  "breaking": false,
5870
7202
  "stable": true,
5871
7203
  "changelog": null
5872
7204
  },
5873
7205
  "Slider": {
5874
- "version": "1.0.0",
5875
- "lastUpdated": "2026-05-13",
7206
+ "version": "1.1.0",
7207
+ "lastUpdated": "2026-05-15",
5876
7208
  "breaking": false,
5877
7209
  "stable": true,
5878
7210
  "changelog": null
5879
7211
  },
5880
7212
  "Switch": {
5881
- "version": "1.0.0",
5882
- "lastUpdated": "2026-05-13",
7213
+ "version": "1.1.0",
7214
+ "lastUpdated": "2026-05-15",
5883
7215
  "breaking": false,
5884
7216
  "stable": true,
5885
7217
  "changelog": null
5886
7218
  },
5887
7219
  "Table": {
5888
- "version": "1.0.0",
5889
- "lastUpdated": "2026-05-13",
7220
+ "version": "1.1.0",
7221
+ "lastUpdated": "2026-05-15",
5890
7222
  "breaking": false,
5891
7223
  "stable": true,
5892
7224
  "changelog": null
5893
7225
  },
5894
7226
  "Tabs": {
5895
- "version": "1.0.0",
5896
- "lastUpdated": "2026-05-13",
7227
+ "version": "1.1.0",
7228
+ "lastUpdated": "2026-05-15",
5897
7229
  "breaking": false,
5898
7230
  "stable": true,
5899
7231
  "changelog": null
5900
7232
  },
5901
7233
  "Toast": {
5902
- "version": "1.0.0",
5903
- "lastUpdated": "2026-05-13",
7234
+ "version": "1.1.0",
7235
+ "lastUpdated": "2026-05-15",
5904
7236
  "breaking": false,
5905
7237
  "stable": true,
5906
7238
  "changelog": null
5907
7239
  },
5908
7240
  "Tooltip": {
5909
- "version": "1.0.0",
5910
- "lastUpdated": "2026-05-13",
7241
+ "version": "1.1.0",
7242
+ "lastUpdated": "2026-05-15",
5911
7243
  "breaking": false,
5912
7244
  "stable": true,
5913
7245
  "changelog": null
5914
7246
  },
5915
7247
  "Typography": {
5916
- "version": "1.0.0",
5917
- "lastUpdated": "2026-05-13",
7248
+ "version": "1.1.0",
7249
+ "lastUpdated": "2026-05-15",
7250
+ "breaking": false,
7251
+ "stable": true,
7252
+ "changelog": null
7253
+ },
7254
+ "ButtonGroup": {
7255
+ "version": "1.1.0",
7256
+ "lastUpdated": "2026-05-15",
7257
+ "breaking": false,
7258
+ "stable": true,
7259
+ "changelog": null
7260
+ },
7261
+ "TagsInput": {
7262
+ "version": "1.1.0",
7263
+ "lastUpdated": "2026-05-15",
7264
+ "breaking": false,
7265
+ "stable": true,
7266
+ "changelog": null
7267
+ },
7268
+ "Combobox": {
7269
+ "version": "1.1.0",
7270
+ "lastUpdated": "2026-05-15",
7271
+ "breaking": false,
7272
+ "stable": true,
7273
+ "changelog": null
7274
+ },
7275
+ "DataGrid": {
7276
+ "version": "1.1.0",
7277
+ "lastUpdated": "2026-05-15",
7278
+ "breaking": false,
7279
+ "stable": true,
7280
+ "changelog": null
7281
+ },
7282
+ "Tag": {
7283
+ "version": "1.1.0",
7284
+ "lastUpdated": "2026-05-15",
7285
+ "breaking": false,
7286
+ "stable": true,
7287
+ "changelog": null
7288
+ },
7289
+ "TagGroup": {
7290
+ "version": "1.1.0",
7291
+ "lastUpdated": "2026-05-15",
5918
7292
  "breaking": false,
5919
7293
  "stable": true,
5920
7294
  "changelog": null
@@ -5952,5 +7326,11 @@ export const cheatSheets = {
5952
7326
  "Tabs": "# Tabs — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Tabbed navigation for switching between content panels.**\n\n```ts\nimport { Tabs, TabList, Tab, TabPanels, TabPanel } from \"@usevyre/react\"\n```\n\n## Examples\n\n**Basic tabs**\n```tsx\n<Tabs defaultIndex={0}>\n <TabList>\n <Tab>Overview</Tab>\n <Tab>Settings</Tab>\n </TabList>\n <TabPanels>\n <TabPanel>Overview content</TabPanel>\n <TabPanel>Settings content</TabPanel>\n </TabPanels>\n</Tabs>\n```\n",
5953
7327
  "Toast": "# Toast — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Transient notification. Use the useToast hook to trigger toasts imperatively. React: wrap app in <ToastProvider>. Vue: place <ToastViewport /> once in app root.**\n\n```ts\nimport { useToast, ToastProvider } from \"@usevyre/react\" // Vue: import { useToast, ToastViewport } from \"@usevyre/vue\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"success\"` \\| `\"warning\"` \\| `\"danger\"` | `default` |\n\n## Common AI Mistakes\n\n- ❌ `Rendering <Toast> directly in JSX`\n → Use: const { toast } = useToast(); then toast({ title, variant })\n- ❌ `variant=\"error\"`\n → Use variant=\"danger\"\n- ❌ `variant=\"info\"`\n → Use variant=\"default\"\n\n## Examples\n\n**Trigger a success toast**\n```tsx\nconst { toast } = useToast();\n\n<Button onClick={() => toast({ title: 'Saved!', variant: 'success', duration: 3000 })}>\n Save\n</Button>\n```\n\n**Setup: wrap app with ToastProvider**\n```tsx\n<ToastProvider>\n <App />\n</ToastProvider>\n```\n",
5954
7328
  "Tooltip": "# Tooltip — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Short label that appears on hover/focus. For rich content use Popover instead.**\n\n```ts\nimport { Tooltip } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `placement` | `\"top\"` \\| `\"bottom\"` \\| `\"left\"` \\| `\"right\"` | `top` |\n\n## Common AI Mistakes\n\n- ❌ `Using Tooltip for rich content (forms, buttons, etc.)`\n → Use Popover for rich interactive content\n\n## Examples\n\n**Tooltip on an icon button**\n```tsx\n<Tooltip content=\"Close dialog\" placement=\"bottom\">\n <Button variant=\"ghost\" size=\"icon\" aria-label=\"Close\">\n <X size={16} />\n </Button>\n</Tooltip>\n```\n",
5955
- "Typography": "# Typography — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Text rendering components with semantic scale. Includes Text, Heading, Lead, Code, Blockquote.**\n\n```ts\nimport { Text, Heading, Lead, Code, Blockquote } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Using raw <h1>, <p> tags instead of Typography components`\n → Use <Heading>, <Text>, <Lead> from @usevyre/react\n\n## Examples\n\n**Page heading and body text**\n```tsx\n<Heading size=\"2xl\" as=\"h1\">Dashboard</Heading>\n<Lead>Welcome back. Here's what's happening today.</Lead>\n<Text size=\"sm\" style={{ color: 'var(--vyre-color-semantic-text-muted)' }}>Last updated 5 minutes ago.</Text>\n```\n"
7329
+ "Typography": "# Typography — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Text rendering components with semantic scale. Includes Text, Heading, Lead, Code, Blockquote.**\n\n```ts\nimport { Text, Heading, Lead, Code, Blockquote } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Using raw <h1>, <p> tags instead of Typography components`\n → Use <Heading>, <Text>, <Lead> from @usevyre/react\n\n## Examples\n\n**Page heading and body text**\n```tsx\n<Heading size=\"2xl\" as=\"h1\">Dashboard</Heading>\n<Lead>Welcome back. Here's what's happening today.</Lead>\n<Text size=\"sm\" style={{ color: 'var(--vyre-color-semantic-text-muted)' }}>Last updated 5 minutes ago.</Text>\n```\n",
7330
+ "ButtonGroup": "# ButtonGroup — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.**\n\n```ts\nimport { ButtonGroup, Button } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `orientation` | `\"horizontal\"` \\| `\"vertical\"` | `horizontal` |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"icon\"` | — |\n| `attached` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `ButtonGroup variant=\"...\"`\n → Set variant on each <Button> inside the group\n- ❌ `ButtonGroup without Button children`\n → Place <Button> elements as direct children\n\n## Examples\n\n**Segmented control**\n```tsx\n<ButtonGroup attached>\n <Button variant=\"secondary\">Day</Button>\n <Button variant=\"secondary\">Week</Button>\n <Button variant=\"secondary\">Month</Button>\n</ButtonGroup>\n```\n\n**Vertical group**\n```tsx\n<ButtonGroup orientation=\"vertical\" attached>\n <Button variant=\"secondary\">Top</Button>\n <Button variant=\"secondary\">Bottom</Button>\n</ButtonGroup>\n```\n",
7331
+ "TagsInput": "# TagsInput — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.**\n\n```ts\nimport { TagsInput } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `TagsInput value={string}`\n → Pass an array: value={['react','vue']}\n- ❌ `TagsInput without onChange`\n → Provide value and onChange (React) or v-model (Vue)\n\n## Examples\n\n**Basic tags input**\n```tsx\nconst [tags, setTags] = useState<string[]>([]);\n<TagsInput value={tags} onChange={setTags} placeholder=\"Add a tag…\" />\n```\n\n**Limited to 5 tags**\n```tsx\n<TagsInput value={tags} onChange={setTags} max={5} />\n```\n",
7332
+ "Combobox": "# Combobox — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).**\n\n```ts\nimport { Combobox } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Combobox value=\"\"`\n → Use value={null} for no selection\n- ❌ `Combobox options={string[]}`\n → Use [{ value: 'ts', label: 'TypeScript' }]\n- ❌ `Using Combobox for command palette`\n → Use Command for command palettes\n\n## Examples\n\n**Searchable language picker**\n```tsx\nconst [lang, setLang] = useState<string | null>(null);\n<Combobox\n options={[{ value: \"ts\", label: \"TypeScript\" }, { value: \"go\", label: \"Go\" }]}\n value={lang}\n onChange={setLang}\n placeholder=\"Search language…\"\n/>\n```\n",
7333
+ "DataGrid": "# DataGrid — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.**\n\n```ts\nimport { DataGrid } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `sortDir` | `\"asc\"` \\| `\"desc\"` | — |\n| `loading` | `true` \\| `false` | `false` |\n| `stickyHeader` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `DataGrid expecting built-in pagination`\n → Slice rows yourself and use the Pagination component\n- ❌ `DataGrid expecting built-in filtering`\n → Filter the rows array before passing it in\n- ❌ `sortable without onSort`\n → Handle onSort and sort the rows array in your state\n\n## Examples\n\n**Sortable grid**\n```tsx\nconst cols = [{ key: \"name\", label: \"Name\", sortable: true }];\n<DataGrid\n columns={cols}\n rows={people}\n sortKey={sortKey}\n sortDir={sortDir}\n onSort={(k, d) => { setSortKey(k); setSortDir(d); }}\n/>\n```\n\n**Loading state**\n```tsx\n<DataGrid columns={cols} rows={[]} loading />\n```\n",
7334
+ "Tag": "# Tag — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.**\n\n```ts\nimport { Tag } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"accent\"` \\| `\"danger\"` | `default` |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Tag variant=\"success\"`\n → Use Badge for success/warning/teal status colors; Tag is for categories/filters\n- ❌ `Using Tag for tag input`\n → Use TagsInput for adding/removing tags via keyboard\n- ❌ `Tag size=\"xl\"`\n → Use size=\"lg\"\n\n## Examples\n\n**Category tags in a group**\n```tsx\n<TagGroup>\n <Tag>Design</Tag>\n <Tag variant=\"accent\">Featured</Tag>\n <Tag>Engineering</Tag>\n</TagGroup>\n```\n\n**Removable filter chip (React)**\n```tsx\n<Tag onRemove={() => removeFilter(\"react\")}>react</Tag>\n```\n\n**Clickable toggle tag (React)**\n```tsx\n<Tag onClick={() => toggleFilter(\"vue\")}>vue</Tag>\n```\n",
7335
+ "TagGroup": "# TagGroup — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.**\n\n```ts\nimport { TagGroup, Tag } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `gap` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n| `wrap` | `true` \\| `false` | `true` |\n\n## Common AI Mistakes\n\n- ❌ `TagGroup without Tag children`\n → Place <Tag> elements as direct children\n- ❌ `Using TagGroup for tag input`\n → Use TagsInput for an editable tag field\n\n## Examples\n\n**Tag group with mixed variants**\n```tsx\n<TagGroup gap=\"sm\">\n <Tag>React</Tag>\n <Tag>Vue</Tag>\n <Tag variant=\"accent\">TypeScript</Tag>\n</TagGroup>\n```\n"
5956
7336
  };