@usevyre/ai-context 1.2.1 → 1.3.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.2.0
1
+ // @usevyre/ai-context v1.6.0
2
2
  // Auto-generated — do not edit directly. Edit src/schema/components.json instead.
3
3
 
4
- export const version = "1.2.0";
4
+ export const version = "1.6.0";
5
5
 
6
6
  export const fullContext = `# useVyre Design System — AI Context
7
7
  # Version: 0.2.0
@@ -202,6 +202,45 @@ import { Alert } from "@usevyre/react"
202
202
 
203
203
  ---
204
204
 
205
+ ### AlertDialog
206
+
207
+ Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.
208
+
209
+ \`\`\`tsx
210
+ import { AlertDialog } from "@usevyre/react"
211
+
212
+ // Props:
213
+ // open = boolean
214
+ // onOpenChange = function
215
+ // title = string
216
+ // description = string
217
+ // variant = "danger" | "warning" | "info" (default: info)
218
+ // confirmLabel = string (default: Confirm)
219
+ // cancelLabel = string (default: Cancel)
220
+ // onConfirm = function
221
+ // onCancel = function
222
+
223
+ // Examples:
224
+ const [open, setOpen] = useState(false);
225
+ <Button variant="danger" onClick={() => setOpen(true)}>Delete</Button>
226
+ <AlertDialog
227
+ open={open}
228
+ onOpenChange={setOpen}
229
+ variant="danger"
230
+ title="Delete project?"
231
+ description="This cannot be undone."
232
+ confirmLabel="Delete"
233
+ onConfirm={() => deleteProject()}
234
+ />
235
+ \`\`\`
236
+
237
+ **Common mistakes:**
238
+ - ❌ \`AlertDialog without open/onOpenChange (React) or v-model (Vue)\` → Drive open from state; close in onOpenChange / via v-model
239
+ - ❌ \`Using Alert (inline banner) for a confirm/cancel decision\` → Use AlertDialog for blocking confirmation; Alert for passive messages
240
+ - ❌ \`variant="success" or "error"\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
241
+
242
+ ---
243
+
205
244
  ### Avatar
206
245
 
207
246
  User profile image with fallback initials or icon.
@@ -305,6 +344,7 @@ import { Button } from "@usevyre/react"
305
344
  - ❌ \`color="..."\` → Use variant prop instead
306
345
  - ❌ \`icon={...}\` → Use leftIcon={...} or rightIcon={...}
307
346
  - ❌ \`size="icon" without aria-label\` → Add aria-label describing the action
347
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
308
348
 
309
349
  ---
310
350
 
@@ -390,6 +430,7 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
390
430
 
391
431
  **Common mistakes:**
392
432
  - ❌ \`variant="primary"\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
433
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
393
434
 
394
435
  ---
395
436
 
@@ -601,6 +642,7 @@ import { Input } from "@usevyre/react"
601
642
  - ❌ \`size="icon"\` → Use size="sm" | "md" | "lg"
602
643
  - ❌ \`type="search" for search UI\` → Import Command from @usevyre/react for search palettes
603
644
  - ❌ \`Vue: binding Input/Textarea value without v-model\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
645
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
604
646
 
605
647
  ---
606
648
 
@@ -1343,6 +1385,157 @@ const messages = [
1343
1385
 
1344
1386
  ---
1345
1387
 
1388
+ ### Stack
1389
+
1390
+ Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or \`as\`).
1391
+
1392
+ \`\`\`tsx
1393
+ import { Stack } from "@usevyre/react"
1394
+
1395
+ // Props:
1396
+ // direction = "row" | "column" | "row-reverse" | "column-reverse" (default: row)
1397
+ // inline = boolean (default: false)
1398
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
1399
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1400
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1401
+ // align = "start" | "center" | "end" | "stretch" | "baseline" (default: stretch)
1402
+ // justify = "start" | "center" | "end" | "between" | "around" | "evenly" (default: start)
1403
+ // alignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
1404
+ // alignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline"
1405
+ // wrap = "nowrap" | "wrap" | "wrap-reverse" (default: nowrap)
1406
+ // grow = number
1407
+ // shrink = number
1408
+ // basis = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
1409
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1410
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1411
+ // as = string (default: div)
1412
+
1413
+ // Examples:
1414
+ <Stack direction="row" gap="md" align="center" justify="between">
1415
+ <Avatar src={user.avatar} />
1416
+ <Text>{user.name}</Text>
1417
+ <Button>Edit</Button>
1418
+ </Stack>
1419
+ <Stack wrap="wrap" rowGap="lg" columnGap="md">
1420
+ {tags.map((t) => <Tag key={t}>{t}</Tag>)}
1421
+ </Stack>
1422
+ \`\`\`
1423
+
1424
+ **Common mistakes:**
1425
+ - ❌ \`<div style={{ display: 'flex', gap: 12 }}>\` → Use <Stack gap="md"> — gap is a token
1426
+ - ❌ \`gap={12} or gap="12px"\` → Use gap="none|xs|sm|md|lg|xl|2xl"
1427
+ - ❌ \`direction="vertical" / "horizontal"\` → Use direction="row" or "column" (also row-reverse / column-reverse)
1428
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1429
+
1430
+ ---
1431
+
1432
+ ### Grid
1433
+
1434
+ Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or \`as\`).
1435
+
1436
+ \`\`\`tsx
1437
+ import { Grid, GridItem } from "@usevyre/react"
1438
+
1439
+ // Props:
1440
+ // columns = number | "auto-fit" (default: 1)
1441
+ // rows = number | "auto"
1442
+ // flow = "row" | "column" | "dense" | "row-dense" | "column-dense"
1443
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
1444
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1445
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1446
+ // align = "start" | "center" | "end" | "stretch" (default: stretch)
1447
+ // justify = "start" | "center" | "end" | "stretch"
1448
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1449
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1450
+ // as = string (default: div)
1451
+
1452
+ // Examples:
1453
+ <Grid columns={3} gap="lg">
1454
+ <GridItem colSpan={2}><Card>Wide</Card></GridItem>
1455
+ <Card>Two</Card>
1456
+ <Card>Three</Card>
1457
+ </Grid>
1458
+ <Grid columns="auto-fit" gap="md">
1459
+ {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
1460
+ </Grid>
1461
+ \`\`\`
1462
+
1463
+ **Common mistakes:**
1464
+ - ❌ \`<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>\` → Use <Grid columns={3} gap="md">
1465
+ - ❌ \`columns="3" (string)\` → Use columns={3} or columns="auto-fit"
1466
+ - ❌ \`Nested div with inline grid-column for spanning\` → Wrap the cell in <GridItem colSpan={2}>
1467
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1468
+
1469
+ ---
1470
+
1471
+ ### GridItem
1472
+
1473
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or \`as\`).
1474
+
1475
+ \`\`\`tsx
1476
+ import { GridItem } from "@usevyre/react"
1477
+
1478
+ // Props:
1479
+ // colSpan = number
1480
+ // rowSpan = number
1481
+ // colStart = number
1482
+ // rowStart = number
1483
+ // as = string (default: div)
1484
+
1485
+ // Examples:
1486
+ <Grid columns={4} gap="md">
1487
+ <GridItem colSpan={2}>Featured</GridItem>
1488
+ <div>a</div>
1489
+ <div>b</div>
1490
+ </Grid>
1491
+ \`\`\`
1492
+
1493
+ **Common mistakes:**
1494
+ - ❌ \`GridItem outside a Grid\` → Place <GridItem> directly inside <Grid>
1495
+
1496
+ ---
1497
+
1498
+ ### Box
1499
+
1500
+ Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The \`style\` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or \`as\`).
1501
+
1502
+ \`\`\`tsx
1503
+ import { Box } from "@usevyre/react"
1504
+
1505
+ // Props:
1506
+ // padding = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1507
+ // paddingX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1508
+ // paddingY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1509
+ // paddingTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1510
+ // paddingRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1511
+ // paddingBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1512
+ // paddingLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1513
+ // margin = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1514
+ // marginX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1515
+ // marginY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1516
+ // marginTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1517
+ // marginRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1518
+ // marginBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1519
+ // marginLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1520
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1521
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1522
+ // as = string (default: div)
1523
+ // style = React.CSSProperties
1524
+
1525
+ // Examples:
1526
+ <Box as="section" paddingX="lg" paddingY="md">
1527
+ <Heading>Settings</Heading>
1528
+ </Box>
1529
+ <Box marginTop="xl"><Separator /></Box>
1530
+ \`\`\`
1531
+
1532
+ **Common mistakes:**
1533
+ - ❌ \`<Box style={{ padding: 16 }}>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
1534
+ - ❌ \`Using Box for flex/grid layout\` → Use <Stack> or <Grid>
1535
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1536
+
1537
+ ---
1538
+
1346
1539
  ### DateRangePicker
1347
1540
 
1348
1541
  Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
@@ -1382,6 +1575,9 @@ If you generate these, you are hallucinating.
1382
1575
  - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
1383
1576
  - ❌ \`<Alert variant="error">\` → Use variant="danger"
1384
1577
  - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
1578
+ - ❌ \`<AlertDialog AlertDialog without open/onOpenChange (React) or v-model (Vue)>\` → Drive open from state; close in onOpenChange / via v-model
1579
+ - ❌ \`<AlertDialog Using Alert (inline banner) for a confirm/cancel decision>\` → Use AlertDialog for blocking confirmation; Alert for passive messages
1580
+ - ❌ \`<AlertDialog variant="success" or "error">\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
1385
1581
  - ❌ \`<Avatar size="xs">\` → Use size="sm"
1386
1582
  - ❌ \`<Avatar size="2xl">\` → Use size="xl"
1387
1583
  - ❌ \`<Badge variant="primary">\` → Use variant="accent" for brand color
@@ -1393,11 +1589,13 @@ If you generate these, you are hallucinating.
1393
1589
  - ❌ \`<Button color="...">\` → Use variant prop instead
1394
1590
  - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
1395
1591
  - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
1592
+ - ❌ \`<Button padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1396
1593
  - ❌ \`<Calendar Calendar for an input field that opens a popover>\` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
1397
1594
  - ❌ \`<Calendar value as tuple for mode="single">\` → Pass value matching mode; use mode="range" for [start,end]
1398
1595
  - ❌ \`<DatePicker DatePicker mode="range" for { from, to } object>\` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
1399
1596
  - ❌ \`<DatePicker DatePicker without value/onChange>\` → Provide value and onChange (e.g. from useState)
1400
1597
  - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
1598
+ - ❌ \`<Card padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1401
1599
  - ❌ \`<Checkbox size="lg">\` → Use size="md"
1402
1600
  - ❌ \`<RadioGroup <Radio> used outside a <RadioGroup>>\` → Always wrap <Radio> in <RadioGroup>
1403
1601
  - ❌ \`<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>\` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
@@ -1412,6 +1610,7 @@ If you generate these, you are hallucinating.
1412
1610
  - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
1413
1611
  - ❌ \`<Input type="search" for search UI>\` → Import Command from @usevyre/react for search palettes
1414
1612
  - ❌ \`<Input Vue: binding Input/Textarea value without v-model>\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
1613
+ - ❌ \`<Input padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1415
1614
  - ❌ \`<Modal size="xl">\` → Use size="lg" or size="full"
1416
1615
  - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
1417
1616
  - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
@@ -1448,6 +1647,18 @@ If you generate these, you are hallucinating.
1448
1647
  - ❌ \`<Conversation Expecting Conversation to store/append messages>\` → Append to your own state in onSend (or @send) and pass it back via value
1449
1648
  - ❌ \`<Conversation composer without onSend (React) / @send (Vue)>\` → Provide onSend / @send to append the message to value
1450
1649
  - ❌ \`<Conversation Treating onSend as (text) only when using allowAttachments>\` → Handle onSend(text, files) — map files to message attachments and append
1650
+ - ❌ \`<Stack <div style={{ display: 'flex', gap: 12 }}>>\` → Use <Stack gap="md"> — gap is a token
1651
+ - ❌ \`<Stack gap={12} or gap="12px">\` → Use gap="none|xs|sm|md|lg|xl|2xl"
1652
+ - ❌ \`<Stack direction="vertical" / "horizontal">\` → Use direction="row" or "column" (also row-reverse / column-reverse)
1653
+ - ❌ \`<Stack style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1654
+ - ❌ \`<Grid <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>>\` → Use <Grid columns={3} gap="md">
1655
+ - ❌ \`<Grid columns="3" (string)>\` → Use columns={3} or columns="auto-fit"
1656
+ - ❌ \`<Grid Nested div with inline grid-column for spanning>\` → Wrap the cell in <GridItem colSpan={2}>
1657
+ - ❌ \`<Grid style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1658
+ - ❌ \`<GridItem GridItem outside a Grid>\` → Place <GridItem> directly inside <Grid>
1659
+ - ❌ \`<Box <Box style={{ padding: 16 }}>>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
1660
+ - ❌ \`<Box Using Box for flex/grid layout>\` → Use <Stack> or <Grid>
1661
+ - ❌ \`<Box style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
1451
1662
  - ❌ \`<DateRangePicker value={[from, to]}>\` → Use value={{ from, to }} and read range.from / range.to
1452
1663
  - ❌ \`<DateRangePicker DateRangePicker for a single date>\` → Use <DatePicker /> for a single date
1453
1664
  - ❌ \`<DateRangePicker presets="true" (string)>\` → Use the bare prop: presets (or presets={true})
@@ -1505,7 +1716,7 @@ alwaysApply: true
1505
1716
  ---
1506
1717
 
1507
1718
  # useVyre Design System — Cursor Rules
1508
- # Version: 1.2.0
1719
+ # Version: 1.6.0
1509
1720
 
1510
1721
  You are working in a project using the useVyre design system (@usevyre/react).
1511
1722
  Follow these rules strictly when generating any UI code.
@@ -1537,6 +1748,18 @@ Never do:
1537
1748
  - ❌ variant="error" → ✅ Use variant="danger"
1538
1749
  - ❌ variant="primary" → ✅ Use variant="info" | "success" | "warning" | "danger"
1539
1750
 
1751
+ ## AlertDialog
1752
+ Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.
1753
+ Import: \`import { AlertDialog } from "@usevyre/react"\`
1754
+
1755
+ Valid props:
1756
+ - variant: "danger" | "warning" | "info" [default: info]
1757
+
1758
+ Never do:
1759
+ - ❌ AlertDialog without open/onOpenChange (React) or v-model (Vue) → ✅ Drive open from state; close in onOpenChange / via v-model
1760
+ - ❌ Using Alert (inline banner) for a confirm/cancel decision → ✅ Use AlertDialog for blocking confirmation; Alert for passive messages
1761
+ - ❌ variant="success" or "error" → ✅ Use "danger" for destructive, "warning" to caution, "info" otherwise
1762
+
1540
1763
  ## Avatar
1541
1764
  User profile image with fallback initials or icon.
1542
1765
  Import: \`import { Avatar } from "@usevyre/react"\`
@@ -1582,6 +1805,7 @@ Never do:
1582
1805
  - ❌ color="..." → ✅ Use variant prop instead
1583
1806
  - ❌ icon={...} → ✅ Use leftIcon={...} or rightIcon={...}
1584
1807
  - ❌ size="icon" without aria-label → ✅ Add aria-label describing the action
1808
+ - ❌ padding / margin / marginTop (any spacing prop) on a useVyre component → ✅ Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1585
1809
 
1586
1810
  ## Calendar
1587
1811
  Inline date-grid widget (always visible, no input). mode: single | range | multiple, optional time picker. For an input + popover use DatePicker; for start/end ranges with presets use DateRangePicker.
@@ -1614,6 +1838,7 @@ Valid props:
1614
1838
 
1615
1839
  Never do:
1616
1840
  - ❌ variant="primary" → ✅ Use variant="elevated" | "outlined" | "ghost" | "accent"
1841
+ - ❌ padding / margin / marginTop (any spacing prop) on a useVyre component → ✅ Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1617
1842
 
1618
1843
  ## Checkbox
1619
1844
  Binary toggle for boolean form values.
@@ -1687,6 +1912,7 @@ Never do:
1687
1912
  - ❌ size="icon" → ✅ Use size="sm" | "md" | "lg"
1688
1913
  - ❌ type="search" for search UI → ✅ Import Command from @usevyre/react for search palettes
1689
1914
  - ❌ Vue: binding Input/Textarea value without v-model → ✅ Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
1915
+ - ❌ padding / margin / marginTop (any spacing prop) on a useVyre component → ✅ Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
1690
1916
 
1691
1917
  ## Label
1692
1918
  Accessible form label. Associate with input via htmlFor.
@@ -1934,6 +2160,86 @@ Never do:
1934
2160
  - ❌ composer without onSend (React) / @send (Vue) → ✅ Provide onSend / @send to append the message to value
1935
2161
  - ❌ Treating onSend as (text) only when using allowAttachments → ✅ Handle onSend(text, files) — map files to message attachments and append
1936
2162
 
2163
+ ## Stack
2164
+ Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or \`as\`).
2165
+ Import: \`import { Stack } from "@usevyre/react"\`
2166
+
2167
+ Valid props:
2168
+ - direction: "row" | "column" | "row-reverse" | "column-reverse" [default: row]
2169
+ - gap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" [default: md]
2170
+ - rowGap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2171
+ - columnGap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2172
+ - align: "start" | "center" | "end" | "stretch" | "baseline" [default: stretch]
2173
+ - justify: "start" | "center" | "end" | "between" | "around" | "evenly" [default: start]
2174
+ - alignContent: "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
2175
+ - alignSelf: "auto" | "start" | "center" | "end" | "stretch" | "baseline"
2176
+ - wrap: "nowrap" | "wrap" | "wrap-reverse" [default: nowrap]
2177
+ - basis: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
2178
+ - width: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2179
+ - height: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2180
+
2181
+ Never do:
2182
+ - ❌ <div style={{ display: 'flex', gap: 12 }}> → ✅ Use <Stack gap="md"> — gap is a token
2183
+ - ❌ gap={12} or gap="12px" → ✅ Use gap="none|xs|sm|md|lg|xl|2xl"
2184
+ - ❌ direction="vertical" / "horizontal" → ✅ Use direction="row" or "column" (also row-reverse / column-reverse)
2185
+ - ❌ style={{ width: "100%" }} / style={{ height: 320 }} → ✅ Use the width / height prop: width="full", width="md", height="screen", etc.
2186
+
2187
+ ## Grid
2188
+ Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or \`as\`).
2189
+ Import: \`import { Grid, GridItem } from "@usevyre/react"\`
2190
+
2191
+ Valid props:
2192
+ - flow: "row" | "column" | "dense" | "row-dense" | "column-dense"
2193
+ - gap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" [default: md]
2194
+ - rowGap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2195
+ - columnGap: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2196
+ - align: "start" | "center" | "end" | "stretch" [default: stretch]
2197
+ - justify: "start" | "center" | "end" | "stretch"
2198
+ - width: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2199
+ - height: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2200
+
2201
+ Never do:
2202
+ - ❌ <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}> → ✅ Use <Grid columns={3} gap="md">
2203
+ - ❌ columns="3" (string) → ✅ Use columns={3} or columns="auto-fit"
2204
+ - ❌ Nested div with inline grid-column for spanning → ✅ Wrap the cell in <GridItem colSpan={2}>
2205
+ - ❌ style={{ width: "100%" }} / style={{ height: 320 }} → ✅ Use the width / height prop: width="full", width="md", height="screen", etc.
2206
+
2207
+ ## GridItem
2208
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or \`as\`).
2209
+ Import: \`import { GridItem } from "@usevyre/react"\`
2210
+
2211
+ Valid props:
2212
+
2213
+ Never do:
2214
+ - ❌ GridItem outside a Grid → ✅ Place <GridItem> directly inside <Grid>
2215
+
2216
+ ## Box
2217
+ Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The \`style\` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or \`as\`).
2218
+ Import: \`import { Box } from "@usevyre/react"\`
2219
+
2220
+ Valid props:
2221
+ - padding: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2222
+ - paddingX: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2223
+ - paddingY: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2224
+ - paddingTop: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2225
+ - paddingRight: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2226
+ - paddingBottom: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2227
+ - paddingLeft: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2228
+ - margin: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2229
+ - marginX: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2230
+ - marginY: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2231
+ - marginTop: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2232
+ - marginRight: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2233
+ - marginBottom: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2234
+ - marginLeft: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2235
+ - width: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2236
+ - height: "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
2237
+
2238
+ Never do:
2239
+ - ❌ <Box style={{ padding: 16 }}> → ✅ Use <Box padding="md"> (or paddingX/paddingTop/...)
2240
+ - ❌ Using Box for flex/grid layout → ✅ Use <Stack> or <Grid>
2241
+ - ❌ style={{ width: "100%" }} / style={{ height: 320 }} → ✅ Use the width / height prop: width="full", width="md", height="screen", etc.
2242
+
1937
2243
  ## DateRangePicker
1938
2244
  Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
1939
2245
  Import: \`import { DateRangePicker } from "@usevyre/react"\`
@@ -1953,7 +2259,7 @@ Use --vyre-color-semantic-* for all colors. Never use primitive tokens.
1953
2259
  Use --vyre-spacing-* for all spacing. Never use raw px in component code.
1954
2260
  Use --vyre-border-radius-* for border radius.`;
1955
2261
  export const claudeContext = `# useVyre Design System Context
1956
- # Version: 1.2.0
2262
+ # Version: 1.6.0
1957
2263
 
1958
2264
  You are working in a codebase that uses the useVyre design system.
1959
2265
  Follow the rules below strictly when writing any UI code.
@@ -2157,6 +2463,45 @@ import { Alert } from "@usevyre/react"
2157
2463
 
2158
2464
  ---
2159
2465
 
2466
+ ### AlertDialog
2467
+
2468
+ Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.
2469
+
2470
+ \`\`\`tsx
2471
+ import { AlertDialog } from "@usevyre/react"
2472
+
2473
+ // Props:
2474
+ // open = boolean
2475
+ // onOpenChange = function
2476
+ // title = string
2477
+ // description = string
2478
+ // variant = "danger" | "warning" | "info" (default: info)
2479
+ // confirmLabel = string (default: Confirm)
2480
+ // cancelLabel = string (default: Cancel)
2481
+ // onConfirm = function
2482
+ // onCancel = function
2483
+
2484
+ // Examples:
2485
+ const [open, setOpen] = useState(false);
2486
+ <Button variant="danger" onClick={() => setOpen(true)}>Delete</Button>
2487
+ <AlertDialog
2488
+ open={open}
2489
+ onOpenChange={setOpen}
2490
+ variant="danger"
2491
+ title="Delete project?"
2492
+ description="This cannot be undone."
2493
+ confirmLabel="Delete"
2494
+ onConfirm={() => deleteProject()}
2495
+ />
2496
+ \`\`\`
2497
+
2498
+ **Common mistakes:**
2499
+ - ❌ \`AlertDialog without open/onOpenChange (React) or v-model (Vue)\` → Drive open from state; close in onOpenChange / via v-model
2500
+ - ❌ \`Using Alert (inline banner) for a confirm/cancel decision\` → Use AlertDialog for blocking confirmation; Alert for passive messages
2501
+ - ❌ \`variant="success" or "error"\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
2502
+
2503
+ ---
2504
+
2160
2505
  ### Avatar
2161
2506
 
2162
2507
  User profile image with fallback initials or icon.
@@ -2260,6 +2605,7 @@ import { Button } from "@usevyre/react"
2260
2605
  - ❌ \`color="..."\` → Use variant prop instead
2261
2606
  - ❌ \`icon={...}\` → Use leftIcon={...} or rightIcon={...}
2262
2607
  - ❌ \`size="icon" without aria-label\` → Add aria-label describing the action
2608
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
2263
2609
 
2264
2610
  ---
2265
2611
 
@@ -2345,6 +2691,7 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
2345
2691
 
2346
2692
  **Common mistakes:**
2347
2693
  - ❌ \`variant="primary"\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
2694
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
2348
2695
 
2349
2696
  ---
2350
2697
 
@@ -2556,6 +2903,7 @@ import { Input } from "@usevyre/react"
2556
2903
  - ❌ \`size="icon"\` → Use size="sm" | "md" | "lg"
2557
2904
  - ❌ \`type="search" for search UI\` → Import Command from @usevyre/react for search palettes
2558
2905
  - ❌ \`Vue: binding Input/Textarea value without v-model\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
2906
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
2559
2907
 
2560
2908
  ---
2561
2909
 
@@ -3298,6 +3646,157 @@ const messages = [
3298
3646
 
3299
3647
  ---
3300
3648
 
3649
+ ### Stack
3650
+
3651
+ Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or \`as\`).
3652
+
3653
+ \`\`\`tsx
3654
+ import { Stack } from "@usevyre/react"
3655
+
3656
+ // Props:
3657
+ // direction = "row" | "column" | "row-reverse" | "column-reverse" (default: row)
3658
+ // inline = boolean (default: false)
3659
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
3660
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3661
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3662
+ // align = "start" | "center" | "end" | "stretch" | "baseline" (default: stretch)
3663
+ // justify = "start" | "center" | "end" | "between" | "around" | "evenly" (default: start)
3664
+ // alignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
3665
+ // alignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline"
3666
+ // wrap = "nowrap" | "wrap" | "wrap-reverse" (default: nowrap)
3667
+ // grow = number
3668
+ // shrink = number
3669
+ // basis = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
3670
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3671
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3672
+ // as = string (default: div)
3673
+
3674
+ // Examples:
3675
+ <Stack direction="row" gap="md" align="center" justify="between">
3676
+ <Avatar src={user.avatar} />
3677
+ <Text>{user.name}</Text>
3678
+ <Button>Edit</Button>
3679
+ </Stack>
3680
+ <Stack wrap="wrap" rowGap="lg" columnGap="md">
3681
+ {tags.map((t) => <Tag key={t}>{t}</Tag>)}
3682
+ </Stack>
3683
+ \`\`\`
3684
+
3685
+ **Common mistakes:**
3686
+ - ❌ \`<div style={{ display: 'flex', gap: 12 }}>\` → Use <Stack gap="md"> — gap is a token
3687
+ - ❌ \`gap={12} or gap="12px"\` → Use gap="none|xs|sm|md|lg|xl|2xl"
3688
+ - ❌ \`direction="vertical" / "horizontal"\` → Use direction="row" or "column" (also row-reverse / column-reverse)
3689
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3690
+
3691
+ ---
3692
+
3693
+ ### Grid
3694
+
3695
+ Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or \`as\`).
3696
+
3697
+ \`\`\`tsx
3698
+ import { Grid, GridItem } from "@usevyre/react"
3699
+
3700
+ // Props:
3701
+ // columns = number | "auto-fit" (default: 1)
3702
+ // rows = number | "auto"
3703
+ // flow = "row" | "column" | "dense" | "row-dense" | "column-dense"
3704
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
3705
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3706
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3707
+ // align = "start" | "center" | "end" | "stretch" (default: stretch)
3708
+ // justify = "start" | "center" | "end" | "stretch"
3709
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3710
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3711
+ // as = string (default: div)
3712
+
3713
+ // Examples:
3714
+ <Grid columns={3} gap="lg">
3715
+ <GridItem colSpan={2}><Card>Wide</Card></GridItem>
3716
+ <Card>Two</Card>
3717
+ <Card>Three</Card>
3718
+ </Grid>
3719
+ <Grid columns="auto-fit" gap="md">
3720
+ {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
3721
+ </Grid>
3722
+ \`\`\`
3723
+
3724
+ **Common mistakes:**
3725
+ - ❌ \`<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>\` → Use <Grid columns={3} gap="md">
3726
+ - ❌ \`columns="3" (string)\` → Use columns={3} or columns="auto-fit"
3727
+ - ❌ \`Nested div with inline grid-column for spanning\` → Wrap the cell in <GridItem colSpan={2}>
3728
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3729
+
3730
+ ---
3731
+
3732
+ ### GridItem
3733
+
3734
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or \`as\`).
3735
+
3736
+ \`\`\`tsx
3737
+ import { GridItem } from "@usevyre/react"
3738
+
3739
+ // Props:
3740
+ // colSpan = number
3741
+ // rowSpan = number
3742
+ // colStart = number
3743
+ // rowStart = number
3744
+ // as = string (default: div)
3745
+
3746
+ // Examples:
3747
+ <Grid columns={4} gap="md">
3748
+ <GridItem colSpan={2}>Featured</GridItem>
3749
+ <div>a</div>
3750
+ <div>b</div>
3751
+ </Grid>
3752
+ \`\`\`
3753
+
3754
+ **Common mistakes:**
3755
+ - ❌ \`GridItem outside a Grid\` → Place <GridItem> directly inside <Grid>
3756
+
3757
+ ---
3758
+
3759
+ ### Box
3760
+
3761
+ Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The \`style\` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or \`as\`).
3762
+
3763
+ \`\`\`tsx
3764
+ import { Box } from "@usevyre/react"
3765
+
3766
+ // Props:
3767
+ // padding = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3768
+ // paddingX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3769
+ // paddingY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3770
+ // paddingTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3771
+ // paddingRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3772
+ // paddingBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3773
+ // paddingLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3774
+ // margin = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3775
+ // marginX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3776
+ // marginY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3777
+ // marginTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3778
+ // marginRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3779
+ // marginBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3780
+ // marginLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3781
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3782
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
3783
+ // as = string (default: div)
3784
+ // style = React.CSSProperties
3785
+
3786
+ // Examples:
3787
+ <Box as="section" paddingX="lg" paddingY="md">
3788
+ <Heading>Settings</Heading>
3789
+ </Box>
3790
+ <Box marginTop="xl"><Separator /></Box>
3791
+ \`\`\`
3792
+
3793
+ **Common mistakes:**
3794
+ - ❌ \`<Box style={{ padding: 16 }}>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
3795
+ - ❌ \`Using Box for flex/grid layout\` → Use <Stack> or <Grid>
3796
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3797
+
3798
+ ---
3799
+
3301
3800
  ### DateRangePicker
3302
3801
 
3303
3802
  Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
@@ -3337,6 +3836,9 @@ If you generate these, you are hallucinating.
3337
3836
  - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
3338
3837
  - ❌ \`<Alert variant="error">\` → Use variant="danger"
3339
3838
  - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
3839
+ - ❌ \`<AlertDialog AlertDialog without open/onOpenChange (React) or v-model (Vue)>\` → Drive open from state; close in onOpenChange / via v-model
3840
+ - ❌ \`<AlertDialog Using Alert (inline banner) for a confirm/cancel decision>\` → Use AlertDialog for blocking confirmation; Alert for passive messages
3841
+ - ❌ \`<AlertDialog variant="success" or "error">\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
3340
3842
  - ❌ \`<Avatar size="xs">\` → Use size="sm"
3341
3843
  - ❌ \`<Avatar size="2xl">\` → Use size="xl"
3342
3844
  - ❌ \`<Badge variant="primary">\` → Use variant="accent" for brand color
@@ -3348,11 +3850,13 @@ If you generate these, you are hallucinating.
3348
3850
  - ❌ \`<Button color="...">\` → Use variant prop instead
3349
3851
  - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
3350
3852
  - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
3853
+ - ❌ \`<Button padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
3351
3854
  - ❌ \`<Calendar Calendar for an input field that opens a popover>\` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
3352
3855
  - ❌ \`<Calendar value as tuple for mode="single">\` → Pass value matching mode; use mode="range" for [start,end]
3353
3856
  - ❌ \`<DatePicker DatePicker mode="range" for { from, to } object>\` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
3354
3857
  - ❌ \`<DatePicker DatePicker without value/onChange>\` → Provide value and onChange (e.g. from useState)
3355
3858
  - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
3859
+ - ❌ \`<Card padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
3356
3860
  - ❌ \`<Checkbox size="lg">\` → Use size="md"
3357
3861
  - ❌ \`<RadioGroup <Radio> used outside a <RadioGroup>>\` → Always wrap <Radio> in <RadioGroup>
3358
3862
  - ❌ \`<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>\` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
@@ -3367,6 +3871,7 @@ If you generate these, you are hallucinating.
3367
3871
  - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
3368
3872
  - ❌ \`<Input type="search" for search UI>\` → Import Command from @usevyre/react for search palettes
3369
3873
  - ❌ \`<Input Vue: binding Input/Textarea value without v-model>\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
3874
+ - ❌ \`<Input padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
3370
3875
  - ❌ \`<Modal size="xl">\` → Use size="lg" or size="full"
3371
3876
  - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
3372
3877
  - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
@@ -3403,6 +3908,18 @@ If you generate these, you are hallucinating.
3403
3908
  - ❌ \`<Conversation Expecting Conversation to store/append messages>\` → Append to your own state in onSend (or @send) and pass it back via value
3404
3909
  - ❌ \`<Conversation composer without onSend (React) / @send (Vue)>\` → Provide onSend / @send to append the message to value
3405
3910
  - ❌ \`<Conversation Treating onSend as (text) only when using allowAttachments>\` → Handle onSend(text, files) — map files to message attachments and append
3911
+ - ❌ \`<Stack <div style={{ display: 'flex', gap: 12 }}>>\` → Use <Stack gap="md"> — gap is a token
3912
+ - ❌ \`<Stack gap={12} or gap="12px">\` → Use gap="none|xs|sm|md|lg|xl|2xl"
3913
+ - ❌ \`<Stack direction="vertical" / "horizontal">\` → Use direction="row" or "column" (also row-reverse / column-reverse)
3914
+ - ❌ \`<Stack style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3915
+ - ❌ \`<Grid <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>>\` → Use <Grid columns={3} gap="md">
3916
+ - ❌ \`<Grid columns="3" (string)>\` → Use columns={3} or columns="auto-fit"
3917
+ - ❌ \`<Grid Nested div with inline grid-column for spanning>\` → Wrap the cell in <GridItem colSpan={2}>
3918
+ - ❌ \`<Grid style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3919
+ - ❌ \`<GridItem GridItem outside a Grid>\` → Place <GridItem> directly inside <Grid>
3920
+ - ❌ \`<Box <Box style={{ padding: 16 }}>>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
3921
+ - ❌ \`<Box Using Box for flex/grid layout>\` → Use <Stack> or <Grid>
3922
+ - ❌ \`<Box style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
3406
3923
  - ❌ \`<DateRangePicker value={[from, to]}>\` → Use value={{ from, to }} and read range.from / range.to
3407
3924
  - ❌ \`<DateRangePicker DateRangePicker for a single date>\` → Use <DatePicker /> for a single date
3408
3925
  - ❌ \`<DateRangePicker presets="true" (string)>\` → Use the bare prop: presets (or presets={true})
@@ -3455,7 +3972,7 @@ If you generate these, you are hallucinating.
3455
3972
  \`\`\`
3456
3973
  `;
3457
3974
  export const windsurfRules = `# useVyre Rules for Windsurf
3458
- # Version: 1.2.0
3975
+ # Version: 1.6.0
3459
3976
 
3460
3977
  # useVyre Design System — AI Context
3461
3978
  # Version: 0.2.0
@@ -3656,6 +4173,45 @@ import { Alert } from "@usevyre/react"
3656
4173
 
3657
4174
  ---
3658
4175
 
4176
+ ### AlertDialog
4177
+
4178
+ Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.
4179
+
4180
+ \`\`\`tsx
4181
+ import { AlertDialog } from "@usevyre/react"
4182
+
4183
+ // Props:
4184
+ // open = boolean
4185
+ // onOpenChange = function
4186
+ // title = string
4187
+ // description = string
4188
+ // variant = "danger" | "warning" | "info" (default: info)
4189
+ // confirmLabel = string (default: Confirm)
4190
+ // cancelLabel = string (default: Cancel)
4191
+ // onConfirm = function
4192
+ // onCancel = function
4193
+
4194
+ // Examples:
4195
+ const [open, setOpen] = useState(false);
4196
+ <Button variant="danger" onClick={() => setOpen(true)}>Delete</Button>
4197
+ <AlertDialog
4198
+ open={open}
4199
+ onOpenChange={setOpen}
4200
+ variant="danger"
4201
+ title="Delete project?"
4202
+ description="This cannot be undone."
4203
+ confirmLabel="Delete"
4204
+ onConfirm={() => deleteProject()}
4205
+ />
4206
+ \`\`\`
4207
+
4208
+ **Common mistakes:**
4209
+ - ❌ \`AlertDialog without open/onOpenChange (React) or v-model (Vue)\` → Drive open from state; close in onOpenChange / via v-model
4210
+ - ❌ \`Using Alert (inline banner) for a confirm/cancel decision\` → Use AlertDialog for blocking confirmation; Alert for passive messages
4211
+ - ❌ \`variant="success" or "error"\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
4212
+
4213
+ ---
4214
+
3659
4215
  ### Avatar
3660
4216
 
3661
4217
  User profile image with fallback initials or icon.
@@ -3759,6 +4315,7 @@ import { Button } from "@usevyre/react"
3759
4315
  - ❌ \`color="..."\` → Use variant prop instead
3760
4316
  - ❌ \`icon={...}\` → Use leftIcon={...} or rightIcon={...}
3761
4317
  - ❌ \`size="icon" without aria-label\` → Add aria-label describing the action
4318
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
3762
4319
 
3763
4320
  ---
3764
4321
 
@@ -3844,6 +4401,7 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
3844
4401
 
3845
4402
  **Common mistakes:**
3846
4403
  - ❌ \`variant="primary"\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
4404
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
3847
4405
 
3848
4406
  ---
3849
4407
 
@@ -4055,6 +4613,7 @@ import { Input } from "@usevyre/react"
4055
4613
  - ❌ \`size="icon"\` → Use size="sm" | "md" | "lg"
4056
4614
  - ❌ \`type="search" for search UI\` → Import Command from @usevyre/react for search palettes
4057
4615
  - ❌ \`Vue: binding Input/Textarea value without v-model\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
4616
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
4058
4617
 
4059
4618
  ---
4060
4619
 
@@ -4797,6 +5356,157 @@ const messages = [
4797
5356
 
4798
5357
  ---
4799
5358
 
5359
+ ### Stack
5360
+
5361
+ Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or \`as\`).
5362
+
5363
+ \`\`\`tsx
5364
+ import { Stack } from "@usevyre/react"
5365
+
5366
+ // Props:
5367
+ // direction = "row" | "column" | "row-reverse" | "column-reverse" (default: row)
5368
+ // inline = boolean (default: false)
5369
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
5370
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5371
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5372
+ // align = "start" | "center" | "end" | "stretch" | "baseline" (default: stretch)
5373
+ // justify = "start" | "center" | "end" | "between" | "around" | "evenly" (default: start)
5374
+ // alignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
5375
+ // alignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline"
5376
+ // wrap = "nowrap" | "wrap" | "wrap-reverse" (default: nowrap)
5377
+ // grow = number
5378
+ // shrink = number
5379
+ // basis = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
5380
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5381
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5382
+ // as = string (default: div)
5383
+
5384
+ // Examples:
5385
+ <Stack direction="row" gap="md" align="center" justify="between">
5386
+ <Avatar src={user.avatar} />
5387
+ <Text>{user.name}</Text>
5388
+ <Button>Edit</Button>
5389
+ </Stack>
5390
+ <Stack wrap="wrap" rowGap="lg" columnGap="md">
5391
+ {tags.map((t) => <Tag key={t}>{t}</Tag>)}
5392
+ </Stack>
5393
+ \`\`\`
5394
+
5395
+ **Common mistakes:**
5396
+ - ❌ \`<div style={{ display: 'flex', gap: 12 }}>\` → Use <Stack gap="md"> — gap is a token
5397
+ - ❌ \`gap={12} or gap="12px"\` → Use gap="none|xs|sm|md|lg|xl|2xl"
5398
+ - ❌ \`direction="vertical" / "horizontal"\` → Use direction="row" or "column" (also row-reverse / column-reverse)
5399
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
5400
+
5401
+ ---
5402
+
5403
+ ### Grid
5404
+
5405
+ Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or \`as\`).
5406
+
5407
+ \`\`\`tsx
5408
+ import { Grid, GridItem } from "@usevyre/react"
5409
+
5410
+ // Props:
5411
+ // columns = number | "auto-fit" (default: 1)
5412
+ // rows = number | "auto"
5413
+ // flow = "row" | "column" | "dense" | "row-dense" | "column-dense"
5414
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
5415
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5416
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5417
+ // align = "start" | "center" | "end" | "stretch" (default: stretch)
5418
+ // justify = "start" | "center" | "end" | "stretch"
5419
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5420
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5421
+ // as = string (default: div)
5422
+
5423
+ // Examples:
5424
+ <Grid columns={3} gap="lg">
5425
+ <GridItem colSpan={2}><Card>Wide</Card></GridItem>
5426
+ <Card>Two</Card>
5427
+ <Card>Three</Card>
5428
+ </Grid>
5429
+ <Grid columns="auto-fit" gap="md">
5430
+ {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
5431
+ </Grid>
5432
+ \`\`\`
5433
+
5434
+ **Common mistakes:**
5435
+ - ❌ \`<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>\` → Use <Grid columns={3} gap="md">
5436
+ - ❌ \`columns="3" (string)\` → Use columns={3} or columns="auto-fit"
5437
+ - ❌ \`Nested div with inline grid-column for spanning\` → Wrap the cell in <GridItem colSpan={2}>
5438
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
5439
+
5440
+ ---
5441
+
5442
+ ### GridItem
5443
+
5444
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or \`as\`).
5445
+
5446
+ \`\`\`tsx
5447
+ import { GridItem } from "@usevyre/react"
5448
+
5449
+ // Props:
5450
+ // colSpan = number
5451
+ // rowSpan = number
5452
+ // colStart = number
5453
+ // rowStart = number
5454
+ // as = string (default: div)
5455
+
5456
+ // Examples:
5457
+ <Grid columns={4} gap="md">
5458
+ <GridItem colSpan={2}>Featured</GridItem>
5459
+ <div>a</div>
5460
+ <div>b</div>
5461
+ </Grid>
5462
+ \`\`\`
5463
+
5464
+ **Common mistakes:**
5465
+ - ❌ \`GridItem outside a Grid\` → Place <GridItem> directly inside <Grid>
5466
+
5467
+ ---
5468
+
5469
+ ### Box
5470
+
5471
+ Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The \`style\` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or \`as\`).
5472
+
5473
+ \`\`\`tsx
5474
+ import { Box } from "@usevyre/react"
5475
+
5476
+ // Props:
5477
+ // padding = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5478
+ // paddingX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5479
+ // paddingY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5480
+ // paddingTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5481
+ // paddingRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5482
+ // paddingBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5483
+ // paddingLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5484
+ // margin = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5485
+ // marginX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5486
+ // marginY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5487
+ // marginTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5488
+ // marginRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5489
+ // marginBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5490
+ // marginLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5491
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5492
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
5493
+ // as = string (default: div)
5494
+ // style = React.CSSProperties
5495
+
5496
+ // Examples:
5497
+ <Box as="section" paddingX="lg" paddingY="md">
5498
+ <Heading>Settings</Heading>
5499
+ </Box>
5500
+ <Box marginTop="xl"><Separator /></Box>
5501
+ \`\`\`
5502
+
5503
+ **Common mistakes:**
5504
+ - ❌ \`<Box style={{ padding: 16 }}>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
5505
+ - ❌ \`Using Box for flex/grid layout\` → Use <Stack> or <Grid>
5506
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
5507
+
5508
+ ---
5509
+
4800
5510
  ### DateRangePicker
4801
5511
 
4802
5512
  Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
@@ -4836,6 +5546,9 @@ If you generate these, you are hallucinating.
4836
5546
  - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
4837
5547
  - ❌ \`<Alert variant="error">\` → Use variant="danger"
4838
5548
  - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
5549
+ - ❌ \`<AlertDialog AlertDialog without open/onOpenChange (React) or v-model (Vue)>\` → Drive open from state; close in onOpenChange / via v-model
5550
+ - ❌ \`<AlertDialog Using Alert (inline banner) for a confirm/cancel decision>\` → Use AlertDialog for blocking confirmation; Alert for passive messages
5551
+ - ❌ \`<AlertDialog variant="success" or "error">\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
4839
5552
  - ❌ \`<Avatar size="xs">\` → Use size="sm"
4840
5553
  - ❌ \`<Avatar size="2xl">\` → Use size="xl"
4841
5554
  - ❌ \`<Badge variant="primary">\` → Use variant="accent" for brand color
@@ -4847,11 +5560,13 @@ If you generate these, you are hallucinating.
4847
5560
  - ❌ \`<Button color="...">\` → Use variant prop instead
4848
5561
  - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
4849
5562
  - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
5563
+ - ❌ \`<Button padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
4850
5564
  - ❌ \`<Calendar Calendar for an input field that opens a popover>\` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
4851
5565
  - ❌ \`<Calendar value as tuple for mode="single">\` → Pass value matching mode; use mode="range" for [start,end]
4852
5566
  - ❌ \`<DatePicker DatePicker mode="range" for { from, to } object>\` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
4853
5567
  - ❌ \`<DatePicker DatePicker without value/onChange>\` → Provide value and onChange (e.g. from useState)
4854
5568
  - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
5569
+ - ❌ \`<Card padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
4855
5570
  - ❌ \`<Checkbox size="lg">\` → Use size="md"
4856
5571
  - ❌ \`<RadioGroup <Radio> used outside a <RadioGroup>>\` → Always wrap <Radio> in <RadioGroup>
4857
5572
  - ❌ \`<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>\` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
@@ -4866,6 +5581,7 @@ If you generate these, you are hallucinating.
4866
5581
  - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
4867
5582
  - ❌ \`<Input type="search" for search UI>\` → Import Command from @usevyre/react for search palettes
4868
5583
  - ❌ \`<Input Vue: binding Input/Textarea value without v-model>\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
5584
+ - ❌ \`<Input padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
4869
5585
  - ❌ \`<Modal size="xl">\` → Use size="lg" or size="full"
4870
5586
  - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
4871
5587
  - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
@@ -4902,6 +5618,18 @@ If you generate these, you are hallucinating.
4902
5618
  - ❌ \`<Conversation Expecting Conversation to store/append messages>\` → Append to your own state in onSend (or @send) and pass it back via value
4903
5619
  - ❌ \`<Conversation composer without onSend (React) / @send (Vue)>\` → Provide onSend / @send to append the message to value
4904
5620
  - ❌ \`<Conversation Treating onSend as (text) only when using allowAttachments>\` → Handle onSend(text, files) — map files to message attachments and append
5621
+ - ❌ \`<Stack <div style={{ display: 'flex', gap: 12 }}>>\` → Use <Stack gap="md"> — gap is a token
5622
+ - ❌ \`<Stack gap={12} or gap="12px">\` → Use gap="none|xs|sm|md|lg|xl|2xl"
5623
+ - ❌ \`<Stack direction="vertical" / "horizontal">\` → Use direction="row" or "column" (also row-reverse / column-reverse)
5624
+ - ❌ \`<Stack style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
5625
+ - ❌ \`<Grid <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>>\` → Use <Grid columns={3} gap="md">
5626
+ - ❌ \`<Grid columns="3" (string)>\` → Use columns={3} or columns="auto-fit"
5627
+ - ❌ \`<Grid Nested div with inline grid-column for spanning>\` → Wrap the cell in <GridItem colSpan={2}>
5628
+ - ❌ \`<Grid style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
5629
+ - ❌ \`<GridItem GridItem outside a Grid>\` → Place <GridItem> directly inside <Grid>
5630
+ - ❌ \`<Box <Box style={{ padding: 16 }}>>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
5631
+ - ❌ \`<Box Using Box for flex/grid layout>\` → Use <Stack> or <Grid>
5632
+ - ❌ \`<Box style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
4905
5633
  - ❌ \`<DateRangePicker value={[from, to]}>\` → Use value={{ from, to }} and read range.from / range.to
4906
5634
  - ❌ \`<DateRangePicker DateRangePicker for a single date>\` → Use <DatePicker /> for a single date
4907
5635
  - ❌ \`<DateRangePicker presets="true" (string)>\` → Use the bare prop: presets (or presets={true})
@@ -4954,7 +5682,7 @@ If you generate these, you are hallucinating.
4954
5682
  \`\`\`
4955
5683
  `;
4956
5684
  export const copilotInstructions = `# useVyre Copilot Instructions
4957
- # Version: 1.2.0
5685
+ # Version: 1.6.0
4958
5686
 
4959
5687
  When generating UI code in this project, follow the useVyre design system rules below.
4960
5688
 
@@ -5157,6 +5885,45 @@ import { Alert } from "@usevyre/react"
5157
5885
 
5158
5886
  ---
5159
5887
 
5888
+ ### AlertDialog
5889
+
5890
+ Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.
5891
+
5892
+ \`\`\`tsx
5893
+ import { AlertDialog } from "@usevyre/react"
5894
+
5895
+ // Props:
5896
+ // open = boolean
5897
+ // onOpenChange = function
5898
+ // title = string
5899
+ // description = string
5900
+ // variant = "danger" | "warning" | "info" (default: info)
5901
+ // confirmLabel = string (default: Confirm)
5902
+ // cancelLabel = string (default: Cancel)
5903
+ // onConfirm = function
5904
+ // onCancel = function
5905
+
5906
+ // Examples:
5907
+ const [open, setOpen] = useState(false);
5908
+ <Button variant="danger" onClick={() => setOpen(true)}>Delete</Button>
5909
+ <AlertDialog
5910
+ open={open}
5911
+ onOpenChange={setOpen}
5912
+ variant="danger"
5913
+ title="Delete project?"
5914
+ description="This cannot be undone."
5915
+ confirmLabel="Delete"
5916
+ onConfirm={() => deleteProject()}
5917
+ />
5918
+ \`\`\`
5919
+
5920
+ **Common mistakes:**
5921
+ - ❌ \`AlertDialog without open/onOpenChange (React) or v-model (Vue)\` → Drive open from state; close in onOpenChange / via v-model
5922
+ - ❌ \`Using Alert (inline banner) for a confirm/cancel decision\` → Use AlertDialog for blocking confirmation; Alert for passive messages
5923
+ - ❌ \`variant="success" or "error"\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
5924
+
5925
+ ---
5926
+
5160
5927
  ### Avatar
5161
5928
 
5162
5929
  User profile image with fallback initials or icon.
@@ -5260,6 +6027,7 @@ import { Button } from "@usevyre/react"
5260
6027
  - ❌ \`color="..."\` → Use variant prop instead
5261
6028
  - ❌ \`icon={...}\` → Use leftIcon={...} or rightIcon={...}
5262
6029
  - ❌ \`size="icon" without aria-label\` → Add aria-label describing the action
6030
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
5263
6031
 
5264
6032
  ---
5265
6033
 
@@ -5345,6 +6113,7 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
5345
6113
 
5346
6114
  **Common mistakes:**
5347
6115
  - ❌ \`variant="primary"\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
6116
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
5348
6117
 
5349
6118
  ---
5350
6119
 
@@ -5556,6 +6325,7 @@ import { Input } from "@usevyre/react"
5556
6325
  - ❌ \`size="icon"\` → Use size="sm" | "md" | "lg"
5557
6326
  - ❌ \`type="search" for search UI\` → Import Command from @usevyre/react for search palettes
5558
6327
  - ❌ \`Vue: binding Input/Textarea value without v-model\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
6328
+ - ❌ \`padding / margin / marginTop (any spacing prop) on a useVyre component\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
5559
6329
 
5560
6330
  ---
5561
6331
 
@@ -6298,22 +7068,173 @@ const messages = [
6298
7068
 
6299
7069
  ---
6300
7070
 
6301
- ### DateRangePicker
7071
+ ### Stack
6302
7072
 
6303
- Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
7073
+ Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or \`as\`).
6304
7074
 
6305
7075
  \`\`\`tsx
6306
- import { DateRangePicker } from "@usevyre/react"
7076
+ import { Stack } from "@usevyre/react"
6307
7077
 
6308
7078
  // Props:
6309
- // value = { from: Date | null; to: Date | null } | null
6310
- // onChange = function
6311
- // placeholder = string (default: Pick a date range)
6312
- // numberOfMonths = "1" | "2" (default: 2)
6313
- // presets = boolean | DateRangePreset[] (default: false)
6314
- // minDate = Date
6315
- // maxDate = Date
6316
- // disabled = function
7079
+ // direction = "row" | "column" | "row-reverse" | "column-reverse" (default: row)
7080
+ // inline = boolean (default: false)
7081
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
7082
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7083
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7084
+ // align = "start" | "center" | "end" | "stretch" | "baseline" (default: stretch)
7085
+ // justify = "start" | "center" | "end" | "between" | "around" | "evenly" (default: start)
7086
+ // alignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
7087
+ // alignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline"
7088
+ // wrap = "nowrap" | "wrap" | "wrap-reverse" (default: nowrap)
7089
+ // grow = number
7090
+ // shrink = number
7091
+ // basis = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
7092
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7093
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7094
+ // as = string (default: div)
7095
+
7096
+ // Examples:
7097
+ <Stack direction="row" gap="md" align="center" justify="between">
7098
+ <Avatar src={user.avatar} />
7099
+ <Text>{user.name}</Text>
7100
+ <Button>Edit</Button>
7101
+ </Stack>
7102
+ <Stack wrap="wrap" rowGap="lg" columnGap="md">
7103
+ {tags.map((t) => <Tag key={t}>{t}</Tag>)}
7104
+ </Stack>
7105
+ \`\`\`
7106
+
7107
+ **Common mistakes:**
7108
+ - ❌ \`<div style={{ display: 'flex', gap: 12 }}>\` → Use <Stack gap="md"> — gap is a token
7109
+ - ❌ \`gap={12} or gap="12px"\` → Use gap="none|xs|sm|md|lg|xl|2xl"
7110
+ - ❌ \`direction="vertical" / "horizontal"\` → Use direction="row" or "column" (also row-reverse / column-reverse)
7111
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
7112
+
7113
+ ---
7114
+
7115
+ ### Grid
7116
+
7117
+ Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or \`as\`).
7118
+
7119
+ \`\`\`tsx
7120
+ import { Grid, GridItem } from "@usevyre/react"
7121
+
7122
+ // Props:
7123
+ // columns = number | "auto-fit" (default: 1)
7124
+ // rows = number | "auto"
7125
+ // flow = "row" | "column" | "dense" | "row-dense" | "column-dense"
7126
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
7127
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7128
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7129
+ // align = "start" | "center" | "end" | "stretch" (default: stretch)
7130
+ // justify = "start" | "center" | "end" | "stretch"
7131
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7132
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7133
+ // as = string (default: div)
7134
+
7135
+ // Examples:
7136
+ <Grid columns={3} gap="lg">
7137
+ <GridItem colSpan={2}><Card>Wide</Card></GridItem>
7138
+ <Card>Two</Card>
7139
+ <Card>Three</Card>
7140
+ </Grid>
7141
+ <Grid columns="auto-fit" gap="md">
7142
+ {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
7143
+ </Grid>
7144
+ \`\`\`
7145
+
7146
+ **Common mistakes:**
7147
+ - ❌ \`<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>\` → Use <Grid columns={3} gap="md">
7148
+ - ❌ \`columns="3" (string)\` → Use columns={3} or columns="auto-fit"
7149
+ - ❌ \`Nested div with inline grid-column for spanning\` → Wrap the cell in <GridItem colSpan={2}>
7150
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
7151
+
7152
+ ---
7153
+
7154
+ ### GridItem
7155
+
7156
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or \`as\`).
7157
+
7158
+ \`\`\`tsx
7159
+ import { GridItem } from "@usevyre/react"
7160
+
7161
+ // Props:
7162
+ // colSpan = number
7163
+ // rowSpan = number
7164
+ // colStart = number
7165
+ // rowStart = number
7166
+ // as = string (default: div)
7167
+
7168
+ // Examples:
7169
+ <Grid columns={4} gap="md">
7170
+ <GridItem colSpan={2}>Featured</GridItem>
7171
+ <div>a</div>
7172
+ <div>b</div>
7173
+ </Grid>
7174
+ \`\`\`
7175
+
7176
+ **Common mistakes:**
7177
+ - ❌ \`GridItem outside a Grid\` → Place <GridItem> directly inside <Grid>
7178
+
7179
+ ---
7180
+
7181
+ ### Box
7182
+
7183
+ Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The \`style\` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or \`as\`).
7184
+
7185
+ \`\`\`tsx
7186
+ import { Box } from "@usevyre/react"
7187
+
7188
+ // Props:
7189
+ // padding = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7190
+ // paddingX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7191
+ // paddingY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7192
+ // paddingTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7193
+ // paddingRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7194
+ // paddingBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7195
+ // paddingLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7196
+ // margin = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7197
+ // marginX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7198
+ // marginY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7199
+ // marginTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7200
+ // marginRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7201
+ // marginBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7202
+ // marginLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7203
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7204
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
7205
+ // as = string (default: div)
7206
+ // style = React.CSSProperties
7207
+
7208
+ // Examples:
7209
+ <Box as="section" paddingX="lg" paddingY="md">
7210
+ <Heading>Settings</Heading>
7211
+ </Box>
7212
+ <Box marginTop="xl"><Separator /></Box>
7213
+ \`\`\`
7214
+
7215
+ **Common mistakes:**
7216
+ - ❌ \`<Box style={{ padding: 16 }}>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
7217
+ - ❌ \`Using Box for flex/grid layout\` → Use <Stack> or <Grid>
7218
+ - ❌ \`style={{ width: "100%" }} / style={{ height: 320 }}\` → Use the width / height prop: width="full", width="md", height="screen", etc.
7219
+
7220
+ ---
7221
+
7222
+ ### DateRangePicker
7223
+
7224
+ Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.
7225
+
7226
+ \`\`\`tsx
7227
+ import { DateRangePicker } from "@usevyre/react"
7228
+
7229
+ // Props:
7230
+ // value = { from: Date | null; to: Date | null } | null
7231
+ // onChange = function
7232
+ // placeholder = string (default: Pick a date range)
7233
+ // numberOfMonths = "1" | "2" (default: 2)
7234
+ // presets = boolean | DateRangePreset[] (default: false)
7235
+ // minDate = Date
7236
+ // maxDate = Date
7237
+ // disabled = function
6317
7238
  // weekStartsOn = "0" | "1" (default: 1)
6318
7239
 
6319
7240
  // Examples:
@@ -6337,6 +7258,9 @@ If you generate these, you are hallucinating.
6337
7258
  - ❌ \`<Accordion Accordion without AccordionItem>\` → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent
6338
7259
  - ❌ \`<Alert variant="error">\` → Use variant="danger"
6339
7260
  - ❌ \`<Alert variant="primary">\` → Use variant="info" | "success" | "warning" | "danger"
7261
+ - ❌ \`<AlertDialog AlertDialog without open/onOpenChange (React) or v-model (Vue)>\` → Drive open from state; close in onOpenChange / via v-model
7262
+ - ❌ \`<AlertDialog Using Alert (inline banner) for a confirm/cancel decision>\` → Use AlertDialog for blocking confirmation; Alert for passive messages
7263
+ - ❌ \`<AlertDialog variant="success" or "error">\` → Use "danger" for destructive, "warning" to caution, "info" otherwise
6340
7264
  - ❌ \`<Avatar size="xs">\` → Use size="sm"
6341
7265
  - ❌ \`<Avatar size="2xl">\` → Use size="xl"
6342
7266
  - ❌ \`<Badge variant="primary">\` → Use variant="accent" for brand color
@@ -6348,11 +7272,13 @@ If you generate these, you are hallucinating.
6348
7272
  - ❌ \`<Button color="...">\` → Use variant prop instead
6349
7273
  - ❌ \`<Button icon={...}>\` → Use leftIcon={...} or rightIcon={...}
6350
7274
  - ❌ \`<Button size="icon" without aria-label>\` → Add aria-label describing the action
7275
+ - ❌ \`<Button padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
6351
7276
  - ❌ \`<Calendar Calendar for an input field that opens a popover>\` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
6352
7277
  - ❌ \`<Calendar value as tuple for mode="single">\` → Pass value matching mode; use mode="range" for [start,end]
6353
7278
  - ❌ \`<DatePicker DatePicker mode="range" for { from, to } object>\` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
6354
7279
  - ❌ \`<DatePicker DatePicker without value/onChange>\` → Provide value and onChange (e.g. from useState)
6355
7280
  - ❌ \`<Card variant="primary">\` → Use variant="elevated" | "outlined" | "ghost" | "accent"
7281
+ - ❌ \`<Card padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
6356
7282
  - ❌ \`<Checkbox size="lg">\` → Use size="md"
6357
7283
  - ❌ \`<RadioGroup <Radio> used outside a <RadioGroup>>\` → Always wrap <Radio> in <RadioGroup>
6358
7284
  - ❌ \`<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>\` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
@@ -6367,6 +7293,7 @@ If you generate these, you are hallucinating.
6367
7293
  - ❌ \`<Input size="icon">\` → Use size="sm" | "md" | "lg"
6368
7294
  - ❌ \`<Input type="search" for search UI>\` → Import Command from @usevyre/react for search palettes
6369
7295
  - ❌ \`<Input Vue: binding Input/Textarea value without v-model>\` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
7296
+ - ❌ \`<Input padding / margin / marginTop (any spacing prop) on a useVyre component>\` → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
6370
7297
  - ❌ \`<Modal size="xl">\` → Use size="lg" or size="full"
6371
7298
  - ❌ \`<Popover placement="top-center">\` → Use placement="top" for centered placement
6372
7299
  - ❌ \`<Progress value > 100>\` → Normalize your value to 0–100 range before passing
@@ -6403,6 +7330,18 @@ If you generate these, you are hallucinating.
6403
7330
  - ❌ \`<Conversation Expecting Conversation to store/append messages>\` → Append to your own state in onSend (or @send) and pass it back via value
6404
7331
  - ❌ \`<Conversation composer without onSend (React) / @send (Vue)>\` → Provide onSend / @send to append the message to value
6405
7332
  - ❌ \`<Conversation Treating onSend as (text) only when using allowAttachments>\` → Handle onSend(text, files) — map files to message attachments and append
7333
+ - ❌ \`<Stack <div style={{ display: 'flex', gap: 12 }}>>\` → Use <Stack gap="md"> — gap is a token
7334
+ - ❌ \`<Stack gap={12} or gap="12px">\` → Use gap="none|xs|sm|md|lg|xl|2xl"
7335
+ - ❌ \`<Stack direction="vertical" / "horizontal">\` → Use direction="row" or "column" (also row-reverse / column-reverse)
7336
+ - ❌ \`<Stack style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
7337
+ - ❌ \`<Grid <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>>\` → Use <Grid columns={3} gap="md">
7338
+ - ❌ \`<Grid columns="3" (string)>\` → Use columns={3} or columns="auto-fit"
7339
+ - ❌ \`<Grid Nested div with inline grid-column for spanning>\` → Wrap the cell in <GridItem colSpan={2}>
7340
+ - ❌ \`<Grid style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
7341
+ - ❌ \`<GridItem GridItem outside a Grid>\` → Place <GridItem> directly inside <Grid>
7342
+ - ❌ \`<Box <Box style={{ padding: 16 }}>>\` → Use <Box padding="md"> (or paddingX/paddingTop/...)
7343
+ - ❌ \`<Box Using Box for flex/grid layout>\` → Use <Stack> or <Grid>
7344
+ - ❌ \`<Box style={{ width: "100%" }} / style={{ height: 320 }}>\` → Use the width / height prop: width="full", width="md", height="screen", etc.
6406
7345
  - ❌ \`<DateRangePicker value={[from, to]}>\` → Use value={{ from, to }} and read range.from / range.to
6407
7346
  - ❌ \`<DateRangePicker DateRangePicker for a single date>\` → Use <DatePicker /> for a single date
6408
7347
  - ❌ \`<DateRangePicker presets="true" (string)>\` → Use the bare prop: presets (or presets={true})
@@ -6457,15 +7396,35 @@ If you generate these, you are hallucinating.
6457
7396
 
6458
7397
  export const schema = {
6459
7398
  "$schema": "http://json-schema.org/draft-07/schema#",
6460
- "version": "1.2.0",
6461
- "generatedAt": "2026-05-16",
7399
+ "version": "1.6.0",
7400
+ "generatedAt": "2026-05-18",
6462
7401
  "package": "@usevyre/react",
6463
- "packageVersion": "1.1.0",
7402
+ "packageVersion": "1.6.0",
6464
7403
  "validFor": [
6465
7404
  "@usevyre/react@1.1.0+",
6466
7405
  "@usevyre/vue@1.1.0+"
6467
7406
  ],
6468
7407
  "changelog": {
7408
+ "1.6.0": {
7409
+ "date": "2026-05-18",
7410
+ "breaking": false,
7411
+ "summary": "Documented the spacing model as an explicit anti-pattern on representative components (Button, Card, Input): useVyre components take no padding/margin props — use Stack/Grid gap or a Box wrapper. No API change."
7412
+ },
7413
+ "1.5.0": {
7414
+ "date": "2026-05-18",
7415
+ "breaking": false,
7416
+ "summary": "Stack, Grid and Box gain token-locked width / height props (keywords auto/full/fit/screen + fixed-rem token sizes xs–2xl), removing the need for an inline width/height style for common layout sizing."
7417
+ },
7418
+ "1.4.0": {
7419
+ "date": "2026-05-18",
7420
+ "breaking": false,
7421
+ "summary": "Layout primitives expanded: Stack now covers the full CSS flexbox surface (reverse directions, wrap modes, alignContent/alignSelf, grow/shrink/basis, per-axis gap); Grid gains rows/flow/justify + a new GridItem subcomponent for span/placement; Box gains per-axis (X/Y) and per-side (Top/Right/Bottom/Left) token padding/margin. Fixes Grid columns being overwritten when a user style prop was passed."
7422
+ },
7423
+ "1.3.0": {
7424
+ "date": "2026-05-18",
7425
+ "breaking": false,
7426
+ "summary": "Added Stack, Grid and Box layout primitives. Token-locked spacing (no raw px/rem) to eliminate hallucinated inline flex/grid styles; Box exposes a documented style escape hatch flagged as an anti-pattern."
7427
+ },
6469
7428
  "1.2.0": {
6470
7429
  "date": "2026-05-16",
6471
7430
  "breaking": false,
@@ -6563,6 +7522,79 @@ export const schema = {
6563
7522
  }
6564
7523
  ]
6565
7524
  },
7525
+ "AlertDialog": {
7526
+ "description": "Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.",
7527
+ "import": "import { AlertDialog } from \"@usevyre/react\"",
7528
+ "props": {
7529
+ "open": {
7530
+ "type": "boolean",
7531
+ "description": "Controlled visibility. Vue: v-model."
7532
+ },
7533
+ "onOpenChange": {
7534
+ "type": "function",
7535
+ "description": "(open: boolean) => void — called when the dialog requests to close (backdrop, Esc, cancel). Vue: update:modelValue / v-model."
7536
+ },
7537
+ "title": {
7538
+ "type": "string",
7539
+ "description": "Dialog heading (required)."
7540
+ },
7541
+ "description": {
7542
+ "type": "string",
7543
+ "description": "Supporting body text."
7544
+ },
7545
+ "variant": {
7546
+ "type": "enum",
7547
+ "values": [
7548
+ "danger",
7549
+ "warning",
7550
+ "info"
7551
+ ],
7552
+ "default": "info",
7553
+ "description": "Visual tone of the confirm action / icon."
7554
+ },
7555
+ "confirmLabel": {
7556
+ "type": "string",
7557
+ "default": "Confirm",
7558
+ "description": "Confirm button text."
7559
+ },
7560
+ "cancelLabel": {
7561
+ "type": "string",
7562
+ "default": "Cancel",
7563
+ "description": "Cancel button text."
7564
+ },
7565
+ "onConfirm": {
7566
+ "type": "function",
7567
+ "description": "Called when the confirm button is pressed."
7568
+ },
7569
+ "onCancel": {
7570
+ "type": "function",
7571
+ "description": "Called when cancelled (button, Esc, backdrop)."
7572
+ }
7573
+ },
7574
+ "antiPatterns": [
7575
+ {
7576
+ "pattern": "AlertDialog without open/onOpenChange (React) or v-model (Vue)",
7577
+ "reason": "It is controlled; it never shows/closes without state",
7578
+ "fix": "Drive open from state; close in onOpenChange / via v-model"
7579
+ },
7580
+ {
7581
+ "pattern": "Using Alert (inline banner) for a confirm/cancel decision",
7582
+ "reason": "Alert is non-blocking inline feedback, has no confirm flow",
7583
+ "fix": "Use AlertDialog for blocking confirmation; Alert for passive messages"
7584
+ },
7585
+ {
7586
+ "pattern": "variant=\"success\" or \"error\"",
7587
+ "reason": "AlertDialog variant is \"danger\" | \"warning\" | \"info\" only",
7588
+ "fix": "Use \"danger\" for destructive, \"warning\" to caution, \"info\" otherwise"
7589
+ }
7590
+ ],
7591
+ "examples": [
7592
+ {
7593
+ "description": "Destructive confirmation",
7594
+ "code": "const [open, setOpen] = useState(false);\n<Button variant=\"danger\" onClick={() => setOpen(true)}>Delete</Button>\n<AlertDialog\n open={open}\n onOpenChange={setOpen}\n variant=\"danger\"\n title=\"Delete project?\"\n description=\"This cannot be undone.\"\n confirmLabel=\"Delete\"\n onConfirm={() => deleteProject()}\n/>"
7595
+ }
7596
+ ]
7597
+ },
6566
7598
  "Avatar": {
6567
7599
  "description": "User profile image with fallback initials or icon.",
6568
7600
  "import": "import { Avatar } from \"@usevyre/react\"",
@@ -6785,6 +7817,11 @@ export const schema = {
6785
7817
  "pattern": "size=\"icon\" without aria-label",
6786
7818
  "reason": "Icon-only buttons have no visible text — screen readers need aria-label",
6787
7819
  "fix": "Add aria-label describing the action"
7820
+ },
7821
+ {
7822
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
7823
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
7824
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it"
6788
7825
  }
6789
7826
  ],
6790
7827
  "examples": [
@@ -6968,6 +8005,11 @@ export const schema = {
6968
8005
  "pattern": "variant=\"primary\"",
6969
8006
  "reason": "Card has no 'primary' variant",
6970
8007
  "fix": "Use variant=\"elevated\" | \"outlined\" | \"ghost\" | \"accent\""
8008
+ },
8009
+ {
8010
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
8011
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
8012
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it"
6971
8013
  }
6972
8014
  ],
6973
8015
  "examples": [
@@ -7338,6 +8380,11 @@ export const schema = {
7338
8380
  "pattern": "Vue: binding Input/Textarea value without v-model",
7339
8381
  "reason": "Vue Input & Textarea support v-model (modelValue); manual :value alone won't update",
7340
8382
  "fix": "Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange"
8383
+ },
8384
+ {
8385
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
8386
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
8387
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it"
7341
8388
  }
7342
8389
  ],
7343
8390
  "examples": [
@@ -8594,94 +9641,764 @@ export const schema = {
8594
9641
  }
8595
9642
  ]
8596
9643
  },
8597
- "DateRangePicker": {
8598
- "description": "Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.",
8599
- "import": "import { DateRangePicker } from \"@usevyre/react\"",
9644
+ "Stack": {
9645
+ "description": "Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or `as`).",
9646
+ "import": "import { Stack } from \"@usevyre/react\"",
8600
9647
  "props": {
8601
- "value": {
8602
- "type": "{ from: Date | null; to: Date | null } | null",
8603
- "description": "Selected range (controlled). Pass an OBJECT, not a tuple."
9648
+ "direction": {
9649
+ "type": "enum",
9650
+ "values": [
9651
+ "row",
9652
+ "column",
9653
+ "row-reverse",
9654
+ "column-reverse"
9655
+ ],
9656
+ "default": "row",
9657
+ "description": "flex-direction"
8604
9658
  },
8605
- "onChange": {
8606
- "type": "function",
8607
- "description": "Callback (range: { from, to }) => void when the range changes"
9659
+ "inline": {
9660
+ "type": "boolean",
9661
+ "default": false,
9662
+ "description": "Render as inline-flex instead of flex"
8608
9663
  },
8609
- "placeholder": {
8610
- "type": "string",
8611
- "default": "Pick a date range",
8612
- "description": "Trigger text when no range is selected"
9664
+ "gap": {
9665
+ "type": "enum",
9666
+ "values": [
9667
+ "none",
9668
+ "xs",
9669
+ "sm",
9670
+ "md",
9671
+ "lg",
9672
+ "xl",
9673
+ "2xl"
9674
+ ],
9675
+ "default": "md",
9676
+ "description": "Space between children. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
8613
9677
  },
8614
- "numberOfMonths": {
9678
+ "rowGap": {
8615
9679
  "type": "enum",
8616
9680
  "values": [
8617
- 1,
8618
- 2
9681
+ "none",
9682
+ "xs",
9683
+ "sm",
9684
+ "md",
9685
+ "lg",
9686
+ "xl",
9687
+ "2xl"
8619
9688
  ],
8620
- "default": 2,
8621
- "description": "How many month calendars to show side-by-side"
9689
+ "description": "Row-gap override. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
8622
9690
  },
8623
- "presets": {
8624
- "type": "boolean | DateRangePreset[]",
8625
- "default": false,
8626
- "description": "true shows built-in presets (Today, Yesterday, Last 7/30 days, This/Last month); or pass a custom array of { label, range() }"
9691
+ "columnGap": {
9692
+ "type": "enum",
9693
+ "values": [
9694
+ "none",
9695
+ "xs",
9696
+ "sm",
9697
+ "md",
9698
+ "lg",
9699
+ "xl",
9700
+ "2xl"
9701
+ ],
9702
+ "description": "Column-gap override. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
8627
9703
  },
8628
- "minDate": {
8629
- "type": "Date",
8630
- "description": "Earliest selectable date"
9704
+ "align": {
9705
+ "type": "enum",
9706
+ "values": [
9707
+ "start",
9708
+ "center",
9709
+ "end",
9710
+ "stretch",
9711
+ "baseline"
9712
+ ],
9713
+ "default": "stretch",
9714
+ "description": "align-items (cross axis)"
8631
9715
  },
8632
- "maxDate": {
8633
- "type": "Date",
8634
- "description": "Latest selectable date"
9716
+ "justify": {
9717
+ "type": "enum",
9718
+ "values": [
9719
+ "start",
9720
+ "center",
9721
+ "end",
9722
+ "between",
9723
+ "around",
9724
+ "evenly"
9725
+ ],
9726
+ "default": "start",
9727
+ "description": "justify-content (main axis)"
8635
9728
  },
8636
- "disabled": {
8637
- "type": "function",
8638
- "description": "(date: Date) => boolean — disable specific dates"
9729
+ "alignContent": {
9730
+ "type": "enum",
9731
+ "values": [
9732
+ "start",
9733
+ "center",
9734
+ "end",
9735
+ "stretch",
9736
+ "between",
9737
+ "around",
9738
+ "evenly"
9739
+ ],
9740
+ "description": "align-content (multi-line cross axis)"
8639
9741
  },
8640
- "weekStartsOn": {
9742
+ "alignSelf": {
8641
9743
  "type": "enum",
8642
9744
  "values": [
8643
- 0,
8644
- 1
9745
+ "auto",
9746
+ "start",
9747
+ "center",
9748
+ "end",
9749
+ "stretch",
9750
+ "baseline"
8645
9751
  ],
8646
- "default": 1,
8647
- "description": "0 = Sunday, 1 = Monday"
9752
+ "description": "align-self for this element"
9753
+ },
9754
+ "wrap": {
9755
+ "type": "enum",
9756
+ "values": [
9757
+ "nowrap",
9758
+ "wrap",
9759
+ "wrap-reverse"
9760
+ ],
9761
+ "default": "nowrap",
9762
+ "description": "flex-wrap"
9763
+ },
9764
+ "grow": {
9765
+ "type": "number",
9766
+ "description": "flex-grow"
9767
+ },
9768
+ "shrink": {
9769
+ "type": "number",
9770
+ "description": "flex-shrink"
9771
+ },
9772
+ "basis": {
9773
+ "type": "enum",
9774
+ "values": [
9775
+ "none",
9776
+ "xs",
9777
+ "sm",
9778
+ "md",
9779
+ "lg",
9780
+ "xl",
9781
+ "2xl",
9782
+ "auto",
9783
+ "content",
9784
+ "0"
9785
+ ],
9786
+ "description": "flex-basis — token, 'auto', 'content', or '0'"
9787
+ },
9788
+ "width": {
9789
+ "type": "enum",
9790
+ "values": [
9791
+ "auto",
9792
+ "full",
9793
+ "fit",
9794
+ "screen",
9795
+ "xs",
9796
+ "sm",
9797
+ "md",
9798
+ "lg",
9799
+ "xl",
9800
+ "2xl"
9801
+ ],
9802
+ "description": "Width — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline width style."
9803
+ },
9804
+ "height": {
9805
+ "type": "enum",
9806
+ "values": [
9807
+ "auto",
9808
+ "full",
9809
+ "fit",
9810
+ "screen",
9811
+ "xs",
9812
+ "sm",
9813
+ "md",
9814
+ "lg",
9815
+ "xl",
9816
+ "2xl"
9817
+ ],
9818
+ "description": "Height — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline height style."
9819
+ },
9820
+ "as": {
9821
+ "type": "string",
9822
+ "default": "div",
9823
+ "description": "HTML tag to render"
8648
9824
  }
8649
9825
  },
8650
9826
  "antiPatterns": [
8651
9827
  {
8652
- "pattern": "value={[from, to]}",
8653
- "reason": "DateRangePicker uses a { from, to } object, not a [Date, Date] tuple like Calendar mode=range",
8654
- "fix": "Use value={{ from, to }} and read range.from / range.to"
9828
+ "pattern": "<div style={{ display: 'flex', gap: 12 }}>",
9829
+ "reason": "Inline flex styles bypass the design system and use magic-number spacing",
9830
+ "fix": "Use <Stack gap=\"md\"> gap is a token"
8655
9831
  },
8656
9832
  {
8657
- "pattern": "DateRangePicker for a single date",
8658
- "reason": "DateRangePicker always selects a start AND end",
8659
- "fix": "Use <DatePicker /> for a single date"
9833
+ "pattern": "gap={12} or gap=\"12px\"",
9834
+ "reason": "Stack gap is a closed token enum",
9835
+ "fix": "Use gap=\"none|xs|sm|md|lg|xl|2xl\""
8660
9836
  },
8661
9837
  {
8662
- "pattern": "presets=\"true\" (string)",
8663
- "reason": "presets is a boolean or an array, not a string",
8664
- "fix": "Use the bare prop: presets (or presets={true})"
9838
+ "pattern": "direction=\"vertical\" / \"horizontal\"",
9839
+ "reason": "Stack mirrors CSS flex-direction names",
9840
+ "fix": "Use direction=\"row\" or \"column\" (also row-reverse / column-reverse)"
9841
+ },
9842
+ {
9843
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
9844
+ "reason": "Inline width/height bypass the design system and use magic numbers",
9845
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc."
8665
9846
  }
8666
9847
  ],
8667
9848
  "examples": [
8668
9849
  {
8669
- "description": "Range picker with built-in presets",
8670
- "code": "const [range, setRange] = useState({ from: null, to: null });\n<DateRangePicker value={range} onChange={setRange} presets />"
9850
+ "description": "Row, vertically centered, spaced apart",
9851
+ "code": "<Stack direction=\"row\" gap=\"md\" align=\"center\" justify=\"between\">\n <Avatar src={user.avatar} />\n <Text>{user.name}</Text>\n <Button>Edit</Button>\n</Stack>"
8671
9852
  },
8672
9853
  {
8673
- "description": "Single month, no presets",
8674
- "code": "<DateRangePicker value={range} onChange={setRange} numberOfMonths={1} />"
9854
+ "description": "Wrapping grid-ish gallery with per-axis gap",
9855
+ "code": "<Stack wrap=\"wrap\" rowGap=\"lg\" columnGap=\"md\">\n {tags.map((t) => <Tag key={t}>{t}</Tag>)}\n</Stack>"
8675
9856
  }
8676
9857
  ]
8677
- }
8678
- }
8679
- };
8680
-
8681
- export const antiPatterns = {
8682
- "version": "1.2.0",
8683
- "rules": [
8684
- {
9858
+ },
9859
+ "Grid": {
9860
+ "description": "Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or `as`).",
9861
+ "import": "import { Grid, GridItem } from \"@usevyre/react\"",
9862
+ "subcomponents": [
9863
+ "GridItem"
9864
+ ],
9865
+ "props": {
9866
+ "columns": {
9867
+ "type": "number | \"auto-fit\"",
9868
+ "default": 1,
9869
+ "description": "Equal-width column count (1-12), or 'auto-fit' for responsive wrapping"
9870
+ },
9871
+ "rows": {
9872
+ "type": "number | \"auto\"",
9873
+ "description": "Explicit row count, or 'auto'"
9874
+ },
9875
+ "flow": {
9876
+ "type": "enum",
9877
+ "values": [
9878
+ "row",
9879
+ "column",
9880
+ "dense",
9881
+ "row-dense",
9882
+ "column-dense"
9883
+ ],
9884
+ "description": "grid-auto-flow"
9885
+ },
9886
+ "gap": {
9887
+ "type": "enum",
9888
+ "values": [
9889
+ "none",
9890
+ "xs",
9891
+ "sm",
9892
+ "md",
9893
+ "lg",
9894
+ "xl",
9895
+ "2xl"
9896
+ ],
9897
+ "default": "md",
9898
+ "description": "Space between cells. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
9899
+ },
9900
+ "rowGap": {
9901
+ "type": "enum",
9902
+ "values": [
9903
+ "none",
9904
+ "xs",
9905
+ "sm",
9906
+ "md",
9907
+ "lg",
9908
+ "xl",
9909
+ "2xl"
9910
+ ],
9911
+ "description": "Row-gap override. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
9912
+ },
9913
+ "columnGap": {
9914
+ "type": "enum",
9915
+ "values": [
9916
+ "none",
9917
+ "xs",
9918
+ "sm",
9919
+ "md",
9920
+ "lg",
9921
+ "xl",
9922
+ "2xl"
9923
+ ],
9924
+ "description": "Column-gap override. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
9925
+ },
9926
+ "align": {
9927
+ "type": "enum",
9928
+ "values": [
9929
+ "start",
9930
+ "center",
9931
+ "end",
9932
+ "stretch"
9933
+ ],
9934
+ "default": "stretch",
9935
+ "description": "align-items"
9936
+ },
9937
+ "justify": {
9938
+ "type": "enum",
9939
+ "values": [
9940
+ "start",
9941
+ "center",
9942
+ "end",
9943
+ "stretch"
9944
+ ],
9945
+ "description": "justify-items"
9946
+ },
9947
+ "width": {
9948
+ "type": "enum",
9949
+ "values": [
9950
+ "auto",
9951
+ "full",
9952
+ "fit",
9953
+ "screen",
9954
+ "xs",
9955
+ "sm",
9956
+ "md",
9957
+ "lg",
9958
+ "xl",
9959
+ "2xl"
9960
+ ],
9961
+ "description": "Width — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline width style."
9962
+ },
9963
+ "height": {
9964
+ "type": "enum",
9965
+ "values": [
9966
+ "auto",
9967
+ "full",
9968
+ "fit",
9969
+ "screen",
9970
+ "xs",
9971
+ "sm",
9972
+ "md",
9973
+ "lg",
9974
+ "xl",
9975
+ "2xl"
9976
+ ],
9977
+ "description": "Height — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline height style."
9978
+ },
9979
+ "as": {
9980
+ "type": "string",
9981
+ "default": "div",
9982
+ "description": "HTML tag to render"
9983
+ }
9984
+ },
9985
+ "antiPatterns": [
9986
+ {
9987
+ "pattern": "<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>",
9988
+ "reason": "Inline grid styles bypass the design system",
9989
+ "fix": "Use <Grid columns={3} gap=\"md\">"
9990
+ },
9991
+ {
9992
+ "pattern": "columns=\"3\" (string)",
9993
+ "reason": "columns is a number or the literal 'auto-fit'",
9994
+ "fix": "Use columns={3} or columns=\"auto-fit\""
9995
+ },
9996
+ {
9997
+ "pattern": "Nested div with inline grid-column for spanning",
9998
+ "reason": "Spanning has a dedicated primitive",
9999
+ "fix": "Wrap the cell in <GridItem colSpan={2}>"
10000
+ },
10001
+ {
10002
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
10003
+ "reason": "Inline width/height bypass the design system and use magic numbers",
10004
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc."
10005
+ }
10006
+ ],
10007
+ "examples": [
10008
+ {
10009
+ "description": "Three-column grid with a wide first cell",
10010
+ "code": "<Grid columns={3} gap=\"lg\">\n <GridItem colSpan={2}><Card>Wide</Card></GridItem>\n <Card>Two</Card>\n <Card>Three</Card>\n</Grid>"
10011
+ },
10012
+ {
10013
+ "description": "Responsive auto-fit grid",
10014
+ "code": "<Grid columns=\"auto-fit\" gap=\"md\">\n {items.map((i) => <Card key={i.id}>{i.title}</Card>)}\n</Grid>"
10015
+ }
10016
+ ]
10017
+ },
10018
+ "GridItem": {
10019
+ "description": "Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or `as`).",
10020
+ "import": "import { GridItem } from \"@usevyre/react\"",
10021
+ "props": {
10022
+ "colSpan": {
10023
+ "type": "number",
10024
+ "description": "Number of columns this item spans"
10025
+ },
10026
+ "rowSpan": {
10027
+ "type": "number",
10028
+ "description": "Number of rows this item spans"
10029
+ },
10030
+ "colStart": {
10031
+ "type": "number",
10032
+ "description": "1-based column line to start at"
10033
+ },
10034
+ "rowStart": {
10035
+ "type": "number",
10036
+ "description": "1-based row line to start at"
10037
+ },
10038
+ "as": {
10039
+ "type": "string",
10040
+ "default": "div",
10041
+ "description": "HTML tag to render"
10042
+ }
10043
+ },
10044
+ "antiPatterns": [
10045
+ {
10046
+ "pattern": "GridItem outside a Grid",
10047
+ "reason": "GridItem only has effect as a direct child of Grid",
10048
+ "fix": "Place <GridItem> directly inside <Grid>"
10049
+ }
10050
+ ],
10051
+ "examples": [
10052
+ {
10053
+ "description": "Span two columns",
10054
+ "code": "<Grid columns={4} gap=\"md\">\n <GridItem colSpan={2}>Featured</GridItem>\n <div>a</div>\n <div>b</div>\n</Grid>"
10055
+ }
10056
+ ]
10057
+ },
10058
+ "Box": {
10059
+ "description": "Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The `style` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or `as`).",
10060
+ "import": "import { Box } from \"@usevyre/react\"",
10061
+ "props": {
10062
+ "padding": {
10063
+ "type": "enum",
10064
+ "values": [
10065
+ "none",
10066
+ "xs",
10067
+ "sm",
10068
+ "md",
10069
+ "lg",
10070
+ "xl",
10071
+ "2xl"
10072
+ ],
10073
+ "description": "Inner spacing, all sides. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10074
+ },
10075
+ "paddingX": {
10076
+ "type": "enum",
10077
+ "values": [
10078
+ "none",
10079
+ "xs",
10080
+ "sm",
10081
+ "md",
10082
+ "lg",
10083
+ "xl",
10084
+ "2xl"
10085
+ ],
10086
+ "description": "Inner spacing, left + right. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10087
+ },
10088
+ "paddingY": {
10089
+ "type": "enum",
10090
+ "values": [
10091
+ "none",
10092
+ "xs",
10093
+ "sm",
10094
+ "md",
10095
+ "lg",
10096
+ "xl",
10097
+ "2xl"
10098
+ ],
10099
+ "description": "Inner spacing, top + bottom. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10100
+ },
10101
+ "paddingTop": {
10102
+ "type": "enum",
10103
+ "values": [
10104
+ "none",
10105
+ "xs",
10106
+ "sm",
10107
+ "md",
10108
+ "lg",
10109
+ "xl",
10110
+ "2xl"
10111
+ ],
10112
+ "description": "Inner spacing, top. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10113
+ },
10114
+ "paddingRight": {
10115
+ "type": "enum",
10116
+ "values": [
10117
+ "none",
10118
+ "xs",
10119
+ "sm",
10120
+ "md",
10121
+ "lg",
10122
+ "xl",
10123
+ "2xl"
10124
+ ],
10125
+ "description": "Inner spacing, right. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10126
+ },
10127
+ "paddingBottom": {
10128
+ "type": "enum",
10129
+ "values": [
10130
+ "none",
10131
+ "xs",
10132
+ "sm",
10133
+ "md",
10134
+ "lg",
10135
+ "xl",
10136
+ "2xl"
10137
+ ],
10138
+ "description": "Inner spacing, bottom. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10139
+ },
10140
+ "paddingLeft": {
10141
+ "type": "enum",
10142
+ "values": [
10143
+ "none",
10144
+ "xs",
10145
+ "sm",
10146
+ "md",
10147
+ "lg",
10148
+ "xl",
10149
+ "2xl"
10150
+ ],
10151
+ "description": "Inner spacing, left. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10152
+ },
10153
+ "margin": {
10154
+ "type": "enum",
10155
+ "values": [
10156
+ "none",
10157
+ "xs",
10158
+ "sm",
10159
+ "md",
10160
+ "lg",
10161
+ "xl",
10162
+ "2xl"
10163
+ ],
10164
+ "description": "Outer spacing, all sides. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10165
+ },
10166
+ "marginX": {
10167
+ "type": "enum",
10168
+ "values": [
10169
+ "none",
10170
+ "xs",
10171
+ "sm",
10172
+ "md",
10173
+ "lg",
10174
+ "xl",
10175
+ "2xl"
10176
+ ],
10177
+ "description": "Outer spacing, left + right. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10178
+ },
10179
+ "marginY": {
10180
+ "type": "enum",
10181
+ "values": [
10182
+ "none",
10183
+ "xs",
10184
+ "sm",
10185
+ "md",
10186
+ "lg",
10187
+ "xl",
10188
+ "2xl"
10189
+ ],
10190
+ "description": "Outer spacing, top + bottom. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10191
+ },
10192
+ "marginTop": {
10193
+ "type": "enum",
10194
+ "values": [
10195
+ "none",
10196
+ "xs",
10197
+ "sm",
10198
+ "md",
10199
+ "lg",
10200
+ "xl",
10201
+ "2xl"
10202
+ ],
10203
+ "description": "Outer spacing, top. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10204
+ },
10205
+ "marginRight": {
10206
+ "type": "enum",
10207
+ "values": [
10208
+ "none",
10209
+ "xs",
10210
+ "sm",
10211
+ "md",
10212
+ "lg",
10213
+ "xl",
10214
+ "2xl"
10215
+ ],
10216
+ "description": "Outer spacing, right. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10217
+ },
10218
+ "marginBottom": {
10219
+ "type": "enum",
10220
+ "values": [
10221
+ "none",
10222
+ "xs",
10223
+ "sm",
10224
+ "md",
10225
+ "lg",
10226
+ "xl",
10227
+ "2xl"
10228
+ ],
10229
+ "description": "Outer spacing, bottom. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10230
+ },
10231
+ "marginLeft": {
10232
+ "type": "enum",
10233
+ "values": [
10234
+ "none",
10235
+ "xs",
10236
+ "sm",
10237
+ "md",
10238
+ "lg",
10239
+ "xl",
10240
+ "2xl"
10241
+ ],
10242
+ "description": "Outer spacing, left. Maps to --vyre-spacing tokens. NEVER a raw px/rem value."
10243
+ },
10244
+ "width": {
10245
+ "type": "enum",
10246
+ "values": [
10247
+ "auto",
10248
+ "full",
10249
+ "fit",
10250
+ "screen",
10251
+ "xs",
10252
+ "sm",
10253
+ "md",
10254
+ "lg",
10255
+ "xl",
10256
+ "2xl"
10257
+ ],
10258
+ "description": "Width — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline width style."
10259
+ },
10260
+ "height": {
10261
+ "type": "enum",
10262
+ "values": [
10263
+ "auto",
10264
+ "full",
10265
+ "fit",
10266
+ "screen",
10267
+ "xs",
10268
+ "sm",
10269
+ "md",
10270
+ "lg",
10271
+ "xl",
10272
+ "2xl"
10273
+ ],
10274
+ "description": "Height — keyword (auto/full=100%/fit=fit-content/screen) or a fixed-rem token size (xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42). Avoids an inline height style."
10275
+ },
10276
+ "as": {
10277
+ "type": "string",
10278
+ "default": "div",
10279
+ "description": "HTML tag to render"
10280
+ },
10281
+ "style": {
10282
+ "type": "React.CSSProperties",
10283
+ "description": "ANTI-PATTERN escape hatch. Only for values the design system cannot express. Flagged by @usevyre/eslint-plugin."
10284
+ }
10285
+ },
10286
+ "antiPatterns": [
10287
+ {
10288
+ "pattern": "<Box style={{ padding: 16 }}>",
10289
+ "reason": "padding is a token prop; style is a last resort",
10290
+ "fix": "Use <Box padding=\"md\"> (or paddingX/paddingTop/...)"
10291
+ },
10292
+ {
10293
+ "pattern": "Using Box for flex/grid layout",
10294
+ "reason": "Box is spacing-only and has no layout props",
10295
+ "fix": "Use <Stack> or <Grid>"
10296
+ },
10297
+ {
10298
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
10299
+ "reason": "Inline width/height bypass the design system and use magic numbers",
10300
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc."
10301
+ }
10302
+ ],
10303
+ "examples": [
10304
+ {
10305
+ "description": "Asymmetric padding",
10306
+ "code": "<Box as=\"section\" paddingX=\"lg\" paddingY=\"md\">\n <Heading>Settings</Heading>\n</Box>"
10307
+ },
10308
+ {
10309
+ "description": "Vertical rhythm via margin-top",
10310
+ "code": "<Box marginTop=\"xl\"><Separator /></Box>"
10311
+ }
10312
+ ]
10313
+ },
10314
+ "DateRangePicker": {
10315
+ "description": "Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.",
10316
+ "import": "import { DateRangePicker } from \"@usevyre/react\"",
10317
+ "props": {
10318
+ "value": {
10319
+ "type": "{ from: Date | null; to: Date | null } | null",
10320
+ "description": "Selected range (controlled). Pass an OBJECT, not a tuple."
10321
+ },
10322
+ "onChange": {
10323
+ "type": "function",
10324
+ "description": "Callback (range: { from, to }) => void when the range changes"
10325
+ },
10326
+ "placeholder": {
10327
+ "type": "string",
10328
+ "default": "Pick a date range",
10329
+ "description": "Trigger text when no range is selected"
10330
+ },
10331
+ "numberOfMonths": {
10332
+ "type": "enum",
10333
+ "values": [
10334
+ 1,
10335
+ 2
10336
+ ],
10337
+ "default": 2,
10338
+ "description": "How many month calendars to show side-by-side"
10339
+ },
10340
+ "presets": {
10341
+ "type": "boolean | DateRangePreset[]",
10342
+ "default": false,
10343
+ "description": "true shows built-in presets (Today, Yesterday, Last 7/30 days, This/Last month); or pass a custom array of { label, range() }"
10344
+ },
10345
+ "minDate": {
10346
+ "type": "Date",
10347
+ "description": "Earliest selectable date"
10348
+ },
10349
+ "maxDate": {
10350
+ "type": "Date",
10351
+ "description": "Latest selectable date"
10352
+ },
10353
+ "disabled": {
10354
+ "type": "function",
10355
+ "description": "(date: Date) => boolean — disable specific dates"
10356
+ },
10357
+ "weekStartsOn": {
10358
+ "type": "enum",
10359
+ "values": [
10360
+ 0,
10361
+ 1
10362
+ ],
10363
+ "default": 1,
10364
+ "description": "0 = Sunday, 1 = Monday"
10365
+ }
10366
+ },
10367
+ "antiPatterns": [
10368
+ {
10369
+ "pattern": "value={[from, to]}",
10370
+ "reason": "DateRangePicker uses a { from, to } object, not a [Date, Date] tuple like Calendar mode=range",
10371
+ "fix": "Use value={{ from, to }} and read range.from / range.to"
10372
+ },
10373
+ {
10374
+ "pattern": "DateRangePicker for a single date",
10375
+ "reason": "DateRangePicker always selects a start AND end",
10376
+ "fix": "Use <DatePicker /> for a single date"
10377
+ },
10378
+ {
10379
+ "pattern": "presets=\"true\" (string)",
10380
+ "reason": "presets is a boolean or an array, not a string",
10381
+ "fix": "Use the bare prop: presets (or presets={true})"
10382
+ }
10383
+ ],
10384
+ "examples": [
10385
+ {
10386
+ "description": "Range picker with built-in presets",
10387
+ "code": "const [range, setRange] = useState({ from: null, to: null });\n<DateRangePicker value={range} onChange={setRange} presets />"
10388
+ },
10389
+ {
10390
+ "description": "Single month, no presets",
10391
+ "code": "<DateRangePicker value={range} onChange={setRange} numberOfMonths={1} />"
10392
+ }
10393
+ ]
10394
+ }
10395
+ }
10396
+ };
10397
+
10398
+ export const antiPatterns = {
10399
+ "version": "1.6.0",
10400
+ "rules": [
10401
+ {
8685
10402
  "component": "Accordion",
8686
10403
  "pattern": "Accordion without AccordionItem",
8687
10404
  "reason": "Accordion requires AccordionItem as direct child",
@@ -8702,6 +10419,27 @@ export const antiPatterns = {
8702
10419
  "fix": "Use variant=\"info\" | \"success\" | \"warning\" | \"danger\"",
8703
10420
  "severity": "error"
8704
10421
  },
10422
+ {
10423
+ "component": "AlertDialog",
10424
+ "pattern": "AlertDialog without open/onOpenChange (React) or v-model (Vue)",
10425
+ "reason": "It is controlled; it never shows/closes without state",
10426
+ "fix": "Drive open from state; close in onOpenChange / via v-model",
10427
+ "severity": "error"
10428
+ },
10429
+ {
10430
+ "component": "AlertDialog",
10431
+ "pattern": "Using Alert (inline banner) for a confirm/cancel decision",
10432
+ "reason": "Alert is non-blocking inline feedback, has no confirm flow",
10433
+ "fix": "Use AlertDialog for blocking confirmation; Alert for passive messages",
10434
+ "severity": "error"
10435
+ },
10436
+ {
10437
+ "component": "AlertDialog",
10438
+ "pattern": "variant=\"success\" or \"error\"",
10439
+ "reason": "AlertDialog variant is \"danger\" | \"warning\" | \"info\" only",
10440
+ "fix": "Use \"danger\" for destructive, \"warning\" to caution, \"info\" otherwise",
10441
+ "severity": "error"
10442
+ },
8705
10443
  {
8706
10444
  "component": "Avatar",
8707
10445
  "pattern": "size=\"xs\"",
@@ -8779,6 +10517,13 @@ export const antiPatterns = {
8779
10517
  "fix": "Add aria-label describing the action",
8780
10518
  "severity": "error"
8781
10519
  },
10520
+ {
10521
+ "component": "Button",
10522
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
10523
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
10524
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
10525
+ "severity": "error"
10526
+ },
8782
10527
  {
8783
10528
  "component": "Calendar",
8784
10529
  "pattern": "Calendar for an input field that opens a popover",
@@ -8814,6 +10559,13 @@ export const antiPatterns = {
8814
10559
  "fix": "Use variant=\"elevated\" | \"outlined\" | \"ghost\" | \"accent\"",
8815
10560
  "severity": "error"
8816
10561
  },
10562
+ {
10563
+ "component": "Card",
10564
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
10565
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
10566
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
10567
+ "severity": "error"
10568
+ },
8817
10569
  {
8818
10570
  "component": "Checkbox",
8819
10571
  "pattern": "size=\"lg\"",
@@ -8912,6 +10664,13 @@ export const antiPatterns = {
8912
10664
  "fix": "Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange",
8913
10665
  "severity": "error"
8914
10666
  },
10667
+ {
10668
+ "component": "Input",
10669
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
10670
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
10671
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
10672
+ "severity": "error"
10673
+ },
8915
10674
  {
8916
10675
  "component": "Modal",
8917
10676
  "pattern": "size=\"xl\"",
@@ -9164,6 +10923,90 @@ export const antiPatterns = {
9164
10923
  "fix": "Handle onSend(text, files) — map files to message attachments and append",
9165
10924
  "severity": "error"
9166
10925
  },
10926
+ {
10927
+ "component": "Stack",
10928
+ "pattern": "<div style={{ display: 'flex', gap: 12 }}>",
10929
+ "reason": "Inline flex styles bypass the design system and use magic-number spacing",
10930
+ "fix": "Use <Stack gap=\"md\"> — gap is a token",
10931
+ "severity": "error"
10932
+ },
10933
+ {
10934
+ "component": "Stack",
10935
+ "pattern": "gap={12} or gap=\"12px\"",
10936
+ "reason": "Stack gap is a closed token enum",
10937
+ "fix": "Use gap=\"none|xs|sm|md|lg|xl|2xl\"",
10938
+ "severity": "error"
10939
+ },
10940
+ {
10941
+ "component": "Stack",
10942
+ "pattern": "direction=\"vertical\" / \"horizontal\"",
10943
+ "reason": "Stack mirrors CSS flex-direction names",
10944
+ "fix": "Use direction=\"row\" or \"column\" (also row-reverse / column-reverse)",
10945
+ "severity": "error"
10946
+ },
10947
+ {
10948
+ "component": "Stack",
10949
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
10950
+ "reason": "Inline width/height bypass the design system and use magic numbers",
10951
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
10952
+ "severity": "error"
10953
+ },
10954
+ {
10955
+ "component": "Grid",
10956
+ "pattern": "<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>",
10957
+ "reason": "Inline grid styles bypass the design system",
10958
+ "fix": "Use <Grid columns={3} gap=\"md\">",
10959
+ "severity": "error"
10960
+ },
10961
+ {
10962
+ "component": "Grid",
10963
+ "pattern": "columns=\"3\" (string)",
10964
+ "reason": "columns is a number or the literal 'auto-fit'",
10965
+ "fix": "Use columns={3} or columns=\"auto-fit\"",
10966
+ "severity": "error"
10967
+ },
10968
+ {
10969
+ "component": "Grid",
10970
+ "pattern": "Nested div with inline grid-column for spanning",
10971
+ "reason": "Spanning has a dedicated primitive",
10972
+ "fix": "Wrap the cell in <GridItem colSpan={2}>",
10973
+ "severity": "error"
10974
+ },
10975
+ {
10976
+ "component": "Grid",
10977
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
10978
+ "reason": "Inline width/height bypass the design system and use magic numbers",
10979
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
10980
+ "severity": "error"
10981
+ },
10982
+ {
10983
+ "component": "GridItem",
10984
+ "pattern": "GridItem outside a Grid",
10985
+ "reason": "GridItem only has effect as a direct child of Grid",
10986
+ "fix": "Place <GridItem> directly inside <Grid>",
10987
+ "severity": "error"
10988
+ },
10989
+ {
10990
+ "component": "Box",
10991
+ "pattern": "<Box style={{ padding: 16 }}>",
10992
+ "reason": "padding is a token prop; style is a last resort",
10993
+ "fix": "Use <Box padding=\"md\"> (or paddingX/paddingTop/...)",
10994
+ "severity": "error"
10995
+ },
10996
+ {
10997
+ "component": "Box",
10998
+ "pattern": "Using Box for flex/grid layout",
10999
+ "reason": "Box is spacing-only and has no layout props",
11000
+ "fix": "Use <Stack> or <Grid>",
11001
+ "severity": "error"
11002
+ },
11003
+ {
11004
+ "component": "Box",
11005
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
11006
+ "reason": "Inline width/height bypass the design system and use magic numbers",
11007
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
11008
+ "severity": "error"
11009
+ },
9167
11010
  {
9168
11011
  "component": "DateRangePicker",
9169
11012
  "pattern": "value={[from, to]}",
@@ -9189,14 +11032,34 @@ export const antiPatterns = {
9189
11032
  };
9190
11033
 
9191
11034
  export const versionInfo = {
9192
- "version": "1.2.0",
9193
- "packageVersion": "1.1.0",
9194
- "generatedAt": "2026-05-17T13:24:18.828Z",
11035
+ "version": "1.6.0",
11036
+ "packageVersion": "1.6.0",
11037
+ "generatedAt": "2026-05-18T02:16:10.599Z",
9195
11038
  "validFor": [
9196
11039
  "@usevyre/react@1.1.0+",
9197
11040
  "@usevyre/vue@1.1.0+"
9198
11041
  ],
9199
11042
  "changelog": {
11043
+ "1.6.0": {
11044
+ "date": "2026-05-18",
11045
+ "breaking": false,
11046
+ "summary": "Documented the spacing model as an explicit anti-pattern on representative components (Button, Card, Input): useVyre components take no padding/margin props — use Stack/Grid gap or a Box wrapper. No API change."
11047
+ },
11048
+ "1.5.0": {
11049
+ "date": "2026-05-18",
11050
+ "breaking": false,
11051
+ "summary": "Stack, Grid and Box gain token-locked width / height props (keywords auto/full/fit/screen + fixed-rem token sizes xs–2xl), removing the need for an inline width/height style for common layout sizing."
11052
+ },
11053
+ "1.4.0": {
11054
+ "date": "2026-05-18",
11055
+ "breaking": false,
11056
+ "summary": "Layout primitives expanded: Stack now covers the full CSS flexbox surface (reverse directions, wrap modes, alignContent/alignSelf, grow/shrink/basis, per-axis gap); Grid gains rows/flow/justify + a new GridItem subcomponent for span/placement; Box gains per-axis (X/Y) and per-side (Top/Right/Bottom/Left) token padding/margin. Fixes Grid columns being overwritten when a user style prop was passed."
11057
+ },
11058
+ "1.3.0": {
11059
+ "date": "2026-05-18",
11060
+ "breaking": false,
11061
+ "summary": "Added Stack, Grid and Box layout primitives. Token-locked spacing (no raw px/rem) to eliminate hallucinated inline flex/grid styles; Box exposes a documented style escape hatch flagged as an anti-pattern."
11062
+ },
9200
11063
  "1.2.0": {
9201
11064
  "date": "2026-05-16",
9202
11065
  "breaking": false,
@@ -9225,302 +11088,337 @@ export const versionInfo = {
9225
11088
  },
9226
11089
  "components": {
9227
11090
  "Accordion": {
9228
- "version": "1.1.0",
9229
- "lastUpdated": "2026-05-16",
11091
+ "version": "1.6.0",
11092
+ "lastUpdated": "2026-05-18",
9230
11093
  "breaking": false,
9231
11094
  "stable": true,
9232
11095
  "changelog": null
9233
11096
  },
9234
11097
  "Alert": {
9235
- "version": "1.1.0",
9236
- "lastUpdated": "2026-05-16",
11098
+ "version": "1.6.0",
11099
+ "lastUpdated": "2026-05-18",
11100
+ "breaking": false,
11101
+ "stable": true,
11102
+ "changelog": null
11103
+ },
11104
+ "AlertDialog": {
11105
+ "version": "1.6.0",
11106
+ "lastUpdated": "2026-05-18",
9237
11107
  "breaking": false,
9238
11108
  "stable": true,
9239
11109
  "changelog": null
9240
11110
  },
9241
11111
  "Avatar": {
9242
- "version": "1.1.0",
9243
- "lastUpdated": "2026-05-16",
11112
+ "version": "1.6.0",
11113
+ "lastUpdated": "2026-05-18",
9244
11114
  "breaking": false,
9245
11115
  "stable": true,
9246
11116
  "changelog": null
9247
11117
  },
9248
11118
  "Badge": {
9249
- "version": "1.1.0",
9250
- "lastUpdated": "2026-05-16",
11119
+ "version": "1.6.0",
11120
+ "lastUpdated": "2026-05-18",
9251
11121
  "breaking": false,
9252
11122
  "stable": true,
9253
11123
  "changelog": null
9254
11124
  },
9255
11125
  "Breadcrumb": {
9256
- "version": "1.1.0",
9257
- "lastUpdated": "2026-05-16",
11126
+ "version": "1.6.0",
11127
+ "lastUpdated": "2026-05-18",
9258
11128
  "breaking": false,
9259
11129
  "stable": true,
9260
11130
  "changelog": null
9261
11131
  },
9262
11132
  "Button": {
9263
- "version": "1.1.0",
9264
- "lastUpdated": "2026-05-16",
11133
+ "version": "1.6.0",
11134
+ "lastUpdated": "2026-05-18",
9265
11135
  "breaking": false,
9266
11136
  "stable": true,
9267
11137
  "changelog": null
9268
11138
  },
9269
11139
  "Calendar": {
9270
- "version": "1.1.0",
9271
- "lastUpdated": "2026-05-16",
11140
+ "version": "1.6.0",
11141
+ "lastUpdated": "2026-05-18",
9272
11142
  "breaking": false,
9273
11143
  "stable": true,
9274
11144
  "changelog": null
9275
11145
  },
9276
11146
  "DatePicker": {
9277
- "version": "1.1.0",
9278
- "lastUpdated": "2026-05-16",
11147
+ "version": "1.6.0",
11148
+ "lastUpdated": "2026-05-18",
9279
11149
  "breaking": false,
9280
11150
  "stable": true,
9281
11151
  "changelog": null
9282
11152
  },
9283
11153
  "Card": {
9284
- "version": "1.1.0",
9285
- "lastUpdated": "2026-05-16",
11154
+ "version": "1.6.0",
11155
+ "lastUpdated": "2026-05-18",
9286
11156
  "breaking": false,
9287
11157
  "stable": true,
9288
11158
  "changelog": null
9289
11159
  },
9290
11160
  "Checkbox": {
9291
- "version": "1.1.0",
9292
- "lastUpdated": "2026-05-16",
11161
+ "version": "1.6.0",
11162
+ "lastUpdated": "2026-05-18",
9293
11163
  "breaking": false,
9294
11164
  "stable": true,
9295
11165
  "changelog": null
9296
11166
  },
9297
11167
  "RadioGroup": {
9298
- "version": "1.1.0",
9299
- "lastUpdated": "2026-05-16",
11168
+ "version": "1.6.0",
11169
+ "lastUpdated": "2026-05-18",
9300
11170
  "breaking": false,
9301
11171
  "stable": true,
9302
11172
  "changelog": null
9303
11173
  },
9304
11174
  "RichTextEditor": {
9305
- "version": "1.1.0",
9306
- "lastUpdated": "2026-05-16",
11175
+ "version": "1.6.0",
11176
+ "lastUpdated": "2026-05-18",
9307
11177
  "breaking": false,
9308
11178
  "stable": true,
9309
11179
  "changelog": null
9310
11180
  },
9311
11181
  "Command": {
9312
- "version": "1.1.0",
9313
- "lastUpdated": "2026-05-16",
11182
+ "version": "1.6.0",
11183
+ "lastUpdated": "2026-05-18",
9314
11184
  "breaking": false,
9315
11185
  "stable": true,
9316
11186
  "changelog": null
9317
11187
  },
9318
11188
  "DropdownMenu": {
9319
- "version": "1.1.0",
9320
- "lastUpdated": "2026-05-16",
11189
+ "version": "1.6.0",
11190
+ "lastUpdated": "2026-05-18",
9321
11191
  "breaking": false,
9322
11192
  "stable": true,
9323
11193
  "changelog": null
9324
11194
  },
9325
11195
  "Field": {
9326
- "version": "1.1.0",
9327
- "lastUpdated": "2026-05-16",
11196
+ "version": "1.6.0",
11197
+ "lastUpdated": "2026-05-18",
9328
11198
  "breaking": false,
9329
11199
  "stable": true,
9330
11200
  "changelog": null
9331
11201
  },
9332
11202
  "Input": {
9333
- "version": "1.1.0",
9334
- "lastUpdated": "2026-05-16",
11203
+ "version": "1.6.0",
11204
+ "lastUpdated": "2026-05-18",
9335
11205
  "breaking": false,
9336
11206
  "stable": true,
9337
11207
  "changelog": null
9338
11208
  },
9339
11209
  "Label": {
9340
- "version": "1.1.0",
9341
- "lastUpdated": "2026-05-16",
11210
+ "version": "1.6.0",
11211
+ "lastUpdated": "2026-05-18",
9342
11212
  "breaking": false,
9343
11213
  "stable": true,
9344
11214
  "changelog": null
9345
11215
  },
9346
11216
  "Modal": {
9347
- "version": "1.1.0",
9348
- "lastUpdated": "2026-05-16",
11217
+ "version": "1.6.0",
11218
+ "lastUpdated": "2026-05-18",
9349
11219
  "breaking": false,
9350
11220
  "stable": true,
9351
11221
  "changelog": null
9352
11222
  },
9353
11223
  "Pagination": {
9354
- "version": "1.1.0",
9355
- "lastUpdated": "2026-05-16",
11224
+ "version": "1.6.0",
11225
+ "lastUpdated": "2026-05-18",
9356
11226
  "breaking": false,
9357
11227
  "stable": true,
9358
11228
  "changelog": null
9359
11229
  },
9360
11230
  "Popover": {
9361
- "version": "1.1.0",
9362
- "lastUpdated": "2026-05-16",
11231
+ "version": "1.6.0",
11232
+ "lastUpdated": "2026-05-18",
9363
11233
  "breaking": false,
9364
11234
  "stable": true,
9365
11235
  "changelog": null
9366
11236
  },
9367
11237
  "Progress": {
9368
- "version": "1.1.0",
9369
- "lastUpdated": "2026-05-16",
11238
+ "version": "1.6.0",
11239
+ "lastUpdated": "2026-05-18",
9370
11240
  "breaking": false,
9371
11241
  "stable": true,
9372
11242
  "changelog": null
9373
11243
  },
9374
11244
  "Select": {
9375
- "version": "1.1.0",
9376
- "lastUpdated": "2026-05-16",
11245
+ "version": "1.6.0",
11246
+ "lastUpdated": "2026-05-18",
9377
11247
  "breaking": false,
9378
11248
  "stable": true,
9379
11249
  "changelog": null
9380
11250
  },
9381
11251
  "Separator": {
9382
- "version": "1.1.0",
9383
- "lastUpdated": "2026-05-16",
11252
+ "version": "1.6.0",
11253
+ "lastUpdated": "2026-05-18",
9384
11254
  "breaking": false,
9385
11255
  "stable": true,
9386
11256
  "changelog": null
9387
11257
  },
9388
11258
  "Sheet": {
9389
- "version": "1.1.0",
9390
- "lastUpdated": "2026-05-16",
11259
+ "version": "1.6.0",
11260
+ "lastUpdated": "2026-05-18",
9391
11261
  "breaking": false,
9392
11262
  "stable": true,
9393
11263
  "changelog": null
9394
11264
  },
9395
11265
  "Sidebar": {
9396
- "version": "1.1.0",
9397
- "lastUpdated": "2026-05-16",
11266
+ "version": "1.6.0",
11267
+ "lastUpdated": "2026-05-18",
9398
11268
  "breaking": false,
9399
11269
  "stable": true,
9400
11270
  "changelog": null
9401
11271
  },
9402
11272
  "Skeleton": {
9403
- "version": "1.1.0",
9404
- "lastUpdated": "2026-05-16",
11273
+ "version": "1.6.0",
11274
+ "lastUpdated": "2026-05-18",
9405
11275
  "breaking": false,
9406
11276
  "stable": true,
9407
11277
  "changelog": null
9408
11278
  },
9409
11279
  "Slider": {
9410
- "version": "1.1.0",
9411
- "lastUpdated": "2026-05-16",
11280
+ "version": "1.6.0",
11281
+ "lastUpdated": "2026-05-18",
9412
11282
  "breaking": false,
9413
11283
  "stable": true,
9414
11284
  "changelog": null
9415
11285
  },
9416
11286
  "Switch": {
9417
- "version": "1.1.0",
9418
- "lastUpdated": "2026-05-16",
11287
+ "version": "1.6.0",
11288
+ "lastUpdated": "2026-05-18",
9419
11289
  "breaking": false,
9420
11290
  "stable": true,
9421
11291
  "changelog": null
9422
11292
  },
9423
11293
  "Table": {
9424
- "version": "1.1.0",
9425
- "lastUpdated": "2026-05-16",
11294
+ "version": "1.6.0",
11295
+ "lastUpdated": "2026-05-18",
9426
11296
  "breaking": false,
9427
11297
  "stable": true,
9428
11298
  "changelog": null
9429
11299
  },
9430
11300
  "Tabs": {
9431
- "version": "1.1.0",
9432
- "lastUpdated": "2026-05-16",
11301
+ "version": "1.6.0",
11302
+ "lastUpdated": "2026-05-18",
9433
11303
  "breaking": false,
9434
11304
  "stable": true,
9435
11305
  "changelog": null
9436
11306
  },
9437
11307
  "Toast": {
9438
- "version": "1.1.0",
9439
- "lastUpdated": "2026-05-16",
11308
+ "version": "1.6.0",
11309
+ "lastUpdated": "2026-05-18",
9440
11310
  "breaking": false,
9441
11311
  "stable": true,
9442
11312
  "changelog": null
9443
11313
  },
9444
11314
  "Tooltip": {
9445
- "version": "1.1.0",
9446
- "lastUpdated": "2026-05-16",
11315
+ "version": "1.6.0",
11316
+ "lastUpdated": "2026-05-18",
9447
11317
  "breaking": false,
9448
11318
  "stable": true,
9449
11319
  "changelog": null
9450
11320
  },
9451
11321
  "Typography": {
9452
- "version": "1.1.0",
9453
- "lastUpdated": "2026-05-16",
11322
+ "version": "1.6.0",
11323
+ "lastUpdated": "2026-05-18",
9454
11324
  "breaking": false,
9455
11325
  "stable": true,
9456
11326
  "changelog": null
9457
11327
  },
9458
11328
  "ButtonGroup": {
9459
- "version": "1.1.0",
9460
- "lastUpdated": "2026-05-16",
11329
+ "version": "1.6.0",
11330
+ "lastUpdated": "2026-05-18",
9461
11331
  "breaking": false,
9462
11332
  "stable": true,
9463
11333
  "changelog": null
9464
11334
  },
9465
11335
  "TagsInput": {
9466
- "version": "1.1.0",
9467
- "lastUpdated": "2026-05-16",
11336
+ "version": "1.6.0",
11337
+ "lastUpdated": "2026-05-18",
9468
11338
  "breaking": false,
9469
11339
  "stable": true,
9470
11340
  "changelog": null
9471
11341
  },
9472
11342
  "Combobox": {
9473
- "version": "1.1.0",
9474
- "lastUpdated": "2026-05-16",
11343
+ "version": "1.6.0",
11344
+ "lastUpdated": "2026-05-18",
9475
11345
  "breaking": false,
9476
11346
  "stable": true,
9477
11347
  "changelog": null
9478
11348
  },
9479
11349
  "DataGrid": {
9480
- "version": "1.1.0",
9481
- "lastUpdated": "2026-05-16",
11350
+ "version": "1.6.0",
11351
+ "lastUpdated": "2026-05-18",
9482
11352
  "breaking": false,
9483
11353
  "stable": true,
9484
11354
  "changelog": null
9485
11355
  },
9486
11356
  "Tag": {
9487
- "version": "1.1.0",
9488
- "lastUpdated": "2026-05-16",
11357
+ "version": "1.6.0",
11358
+ "lastUpdated": "2026-05-18",
9489
11359
  "breaking": false,
9490
11360
  "stable": true,
9491
11361
  "changelog": null
9492
11362
  },
9493
11363
  "TagGroup": {
9494
- "version": "1.1.0",
9495
- "lastUpdated": "2026-05-16",
11364
+ "version": "1.6.0",
11365
+ "lastUpdated": "2026-05-18",
9496
11366
  "breaking": false,
9497
11367
  "stable": true,
9498
11368
  "changelog": null
9499
11369
  },
9500
11370
  "Item": {
9501
- "version": "1.1.0",
9502
- "lastUpdated": "2026-05-16",
11371
+ "version": "1.6.0",
11372
+ "lastUpdated": "2026-05-18",
9503
11373
  "breaking": false,
9504
11374
  "stable": true,
9505
11375
  "changelog": null
9506
11376
  },
9507
11377
  "Kanban": {
9508
- "version": "1.1.0",
9509
- "lastUpdated": "2026-05-16",
11378
+ "version": "1.6.0",
11379
+ "lastUpdated": "2026-05-18",
9510
11380
  "breaking": false,
9511
11381
  "stable": true,
9512
11382
  "changelog": null
9513
11383
  },
9514
11384
  "Conversation": {
9515
- "version": "1.1.0",
9516
- "lastUpdated": "2026-05-16",
11385
+ "version": "1.6.0",
11386
+ "lastUpdated": "2026-05-18",
11387
+ "breaking": false,
11388
+ "stable": true,
11389
+ "changelog": null
11390
+ },
11391
+ "Stack": {
11392
+ "version": "1.6.0",
11393
+ "lastUpdated": "2026-05-18",
11394
+ "breaking": false,
11395
+ "stable": true,
11396
+ "changelog": null
11397
+ },
11398
+ "Grid": {
11399
+ "version": "1.6.0",
11400
+ "lastUpdated": "2026-05-18",
11401
+ "breaking": false,
11402
+ "stable": true,
11403
+ "changelog": null
11404
+ },
11405
+ "GridItem": {
11406
+ "version": "1.6.0",
11407
+ "lastUpdated": "2026-05-18",
11408
+ "breaking": false,
11409
+ "stable": true,
11410
+ "changelog": null
11411
+ },
11412
+ "Box": {
11413
+ "version": "1.6.0",
11414
+ "lastUpdated": "2026-05-18",
9517
11415
  "breaking": false,
9518
11416
  "stable": true,
9519
11417
  "changelog": null
9520
11418
  },
9521
11419
  "DateRangePicker": {
9522
- "version": "1.1.0",
9523
- "lastUpdated": "2026-05-16",
11420
+ "version": "1.6.0",
11421
+ "lastUpdated": "2026-05-18",
9524
11422
  "breaking": false,
9525
11423
  "stable": true,
9526
11424
  "changelog": null
@@ -9531,20 +11429,21 @@ export const versionInfo = {
9531
11429
  export const cheatSheets = {
9532
11430
  "Accordion": "# Accordion — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Vertically stacked collapsible sections. Compose with AccordionItem, AccordionTrigger, AccordionContent.**\n\n```ts\nimport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Accordion without AccordionItem`\n → Always compose: Accordion > AccordionItem > AccordionTrigger + AccordionContent\n\n## Examples\n\n**Basic accordion**\n```tsx\n<Accordion>\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Section Title</AccordionTrigger>\n <AccordionContent>Content goes here.</AccordionContent>\n </AccordionItem>\n</Accordion>\n```\n",
9533
11431
  "Alert": "# Alert — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Inline feedback message for info, success, warning, or danger states.**\n\n```ts\nimport { Alert } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"info\"` \\| `\"success\"` \\| `\"warning\"` \\| `\"danger\"` | `info` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"error\"`\n → Use variant=\"danger\"\n- ❌ `variant=\"primary\"`\n → Use variant=\"info\" | \"success\" | \"warning\" | \"danger\"\n\n## Examples\n\n**Warning with close button**\n```tsx\n<Alert variant=\"warning\" title=\"Heads up\" onClose={() => setOpen(false)}>\n This action cannot be undone.\n</Alert>\n```\n\n**Success state**\n```tsx\n<Alert variant=\"success\" title=\"Saved!\">Your changes have been saved.</Alert>\n```\n",
11432
+ "AlertDialog": "# AlertDialog — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Blocking confirmation modal (focus-trapped). Controlled via open + onOpenChange (React) / v-model (Vue). Use for destructive or irreversible actions that need explicit confirm/cancel. For non-blocking inline feedback use Alert; for general dialogs use Modal.**\n\n```ts\nimport { AlertDialog } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"danger\"` \\| `\"warning\"` \\| `\"info\"` | `info` |\n| `open` | `true` \\| `false` | — |\n\n## Common AI Mistakes\n\n- ❌ `AlertDialog without open/onOpenChange (React) or v-model (Vue)`\n → Drive open from state; close in onOpenChange / via v-model\n- ❌ `Using Alert (inline banner) for a confirm/cancel decision`\n → Use AlertDialog for blocking confirmation; Alert for passive messages\n- ❌ `variant=\"success\" or \"error\"`\n → Use \"danger\" for destructive, \"warning\" to caution, \"info\" otherwise\n\n## Examples\n\n**Destructive confirmation**\n```tsx\nconst [open, setOpen] = useState(false);\n<Button variant=\"danger\" onClick={() => setOpen(true)}>Delete</Button>\n<AlertDialog\n open={open}\n onOpenChange={setOpen}\n variant=\"danger\"\n title=\"Delete project?\"\n description=\"This cannot be undone.\"\n confirmLabel=\"Delete\"\n onConfirm={() => deleteProject()}\n/>\n```\n",
9534
11433
  "Avatar": "# Avatar — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**User profile image with fallback initials or icon.**\n\n```ts\nimport { Avatar } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` | `md` |\n| `status` | `\"online\"` \\| `\"offline\"` \\| `\"busy\"` \\| `\"away\"` | — |\n\n## Common AI Mistakes\n\n- ❌ `size=\"xs\"`\n → Use size=\"sm\"\n- ❌ `size=\"2xl\"`\n → Use size=\"xl\"\n\n## Examples\n\n**Avatar with image and online status**\n```tsx\n<Avatar src=\"/user.png\" alt=\"Jane Doe\" size=\"lg\" status=\"online\" />\n```\n\n**Fallback initials**\n```tsx\n<Avatar fallback=\"JD\" size=\"md\" />\n```\n",
9535
11434
  "Badge": "# Badge — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Small label for status, category, or count. Use dot prop for live status indicator.**\n\n```ts\nimport { Badge } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"accent\"` \\| `\"teal\"` \\| `\"success\"` \\| `\"warning\"` \\| `\"danger\"` | `default` |\n| `dot` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"primary\"`\n → Use variant=\"accent\" for brand color\n- ❌ `variant=\"error\"`\n → Use variant=\"danger\"\n- ❌ `variant=\"info\"`\n → Use variant=\"teal\" for info-like styling\n\n## Examples\n\n**Live status with dot**\n```tsx\n<Badge variant=\"success\" dot>Online</Badge>\n```\n\n**Warning badge**\n```tsx\n<Badge variant=\"warning\">Beta</Badge>\n```\n\n**Danger badge**\n```tsx\n<Badge variant=\"danger\">Error</Badge>\n```\n",
9536
11435
  "Breadcrumb": "# Breadcrumb — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Navigation trail showing current page location in hierarchy.**\n\n```ts\nimport { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbSeparator } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Using plain <a> tags inside Breadcrumb`\n → Use BreadcrumbItem > BreadcrumbLink for each crumb\n\n## Examples\n\n**Basic breadcrumb**\n```tsx\n<Breadcrumb>\n <BreadcrumbItem><BreadcrumbLink href=\"/\">Home</BreadcrumbLink></BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem><BreadcrumbLink href=\"/docs\">Docs</BreadcrumbLink></BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem aria-current=\"page\">Button</BreadcrumbItem>\n</Breadcrumb>\n```\n",
9537
- "Button": "# Button — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Triggers actions and navigation. The most commonly used interactive element.**\n\n```ts\nimport { Button } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"primary\"` \\| `\"secondary\"` \\| `\"ghost\"` \\| `\"accent\"` \\| `\"teal\"` \\| `\"danger\"` | `secondary` |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"icon\"` | `md` |\n| `loading` | `true` \\| `false` | `false` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"blue\"`\n → Use variant=\"accent\" for brand amber, or variant=\"teal\" for teal\n- ❌ `size=\"xl\"`\n → Use size=\"lg\"\n- ❌ `color=\"...\"`\n → Use variant prop instead\n- ❌ `icon={...}`\n → Use leftIcon={...} or rightIcon={...}\n- ❌ `size=\"icon\" without aria-label`\n → Add aria-label describing the action\n\n## Examples\n\n**Primary CTA**\n```tsx\n<Button variant=\"primary\">Get Started</Button>\n```\n\n**Large accent button**\n```tsx\n<Button variant=\"accent\" size=\"lg\">Launch App</Button>\n```\n\n**Loading state**\n```tsx\n<Button variant=\"danger\" loading>Deleting...</Button>\n```\n\n**Link button**\n```tsx\n<Button as=\"a\" href=\"/docs\" variant=\"secondary\">Read Docs</Button>\n```\n\n**Icon-only button**\n```tsx\n<Button variant=\"ghost\" size=\"icon\" aria-label=\"Close\">\n <X size={16} />\n</Button>\n```\n\n## Accessibility\n\n- Always add aria-label when using size='icon' (no visible text)\n",
11436
+ "Button": "# Button — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Triggers actions and navigation. The most commonly used interactive element.**\n\n```ts\nimport { Button } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"primary\"` \\| `\"secondary\"` \\| `\"ghost\"` \\| `\"accent\"` \\| `\"teal\"` \\| `\"danger\"` | `secondary` |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"icon\"` | `md` |\n| `loading` | `true` \\| `false` | `false` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"blue\"`\n → Use variant=\"accent\" for brand amber, or variant=\"teal\" for teal\n- ❌ `size=\"xl\"`\n → Use size=\"lg\"\n- ❌ `color=\"...\"`\n → Use variant prop instead\n- ❌ `icon={...}`\n → Use leftIcon={...} or rightIcon={...}\n- ❌ `size=\"icon\" without aria-label`\n → Add aria-label describing the action\n- ❌ `padding / margin / marginTop (any spacing prop) on a useVyre component`\n → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it\n\n## Examples\n\n**Primary CTA**\n```tsx\n<Button variant=\"primary\">Get Started</Button>\n```\n\n**Large accent button**\n```tsx\n<Button variant=\"accent\" size=\"lg\">Launch App</Button>\n```\n\n**Loading state**\n```tsx\n<Button variant=\"danger\" loading>Deleting...</Button>\n```\n\n**Link button**\n```tsx\n<Button as=\"a\" href=\"/docs\" variant=\"secondary\">Read Docs</Button>\n```\n\n**Icon-only button**\n```tsx\n<Button variant=\"ghost\" size=\"icon\" aria-label=\"Close\">\n <X size={16} />\n</Button>\n```\n\n## Accessibility\n\n- Always add aria-label when using size='icon' (no visible text)\n",
9538
11437
  "Calendar": "# Calendar — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Inline date-grid widget (always visible, no input). mode: single | range | multiple, optional time picker. For an input + popover use DatePicker; for start/end ranges with presets use DateRangePicker.**\n\n```ts\nimport { Calendar } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Calendar for an input field that opens a popover`\n → Use <DatePicker /> (single date) or <DateRangePicker /> (range)\n- ❌ `value as tuple for mode=\"single\"`\n → Pass value matching mode; use mode=\"range\" for [start,end]\n\n## Examples\n\n**Controlled date picker**\n```tsx\nconst [date, setDate] = useState(null);\n<Calendar value={date} onChange={setDate} />\n```\n",
9539
11438
  "DatePicker": "# DatePicker — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Input trigger that opens a Calendar in a popover. Same modes as Calendar (single | range | multiple) plus a placeholder. Use this for a compact date field; use Calendar for an always-visible grid, or DateRangePicker for start/end ranges with presets.**\n\n```ts\nimport { DatePicker } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `mode` | `\"single\"` \\| `\"range\"` \\| `\"multiple\"` | `single` |\n| `weekStartsOn` | `\"0\"` \\| `\"1\"` | `1` |\n| `showTime` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `DatePicker mode=\"range\" for { from, to } object`\n → Use <DateRangePicker /> for the { from, to } object API + presets + dual month\n- ❌ `DatePicker without value/onChange`\n → Provide value and onChange (e.g. from useState)\n\n## Examples\n\n**Single date field**\n```tsx\nconst [date, setDate] = useState(null);\n<DatePicker value={date} onChange={setDate} placeholder=\"Pick a date\" />\n```\n\n**Date + time**\n```tsx\n<DatePicker value={date} onChange={setDate} showTime />\n```\n",
9540
- "Card": "# Card — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Content container with optional header, body, and footer sections.**\n\n```ts\nimport { Card, CardHeader, CardBody, CardFooter } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"elevated\"` \\| `\"outlined\"` \\| `\"ghost\"` \\| `\"accent\"` | `default` |\n| `hoverable` | `true` \\| `false` | `false` |\n| `clickable` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"primary\"`\n → Use variant=\"elevated\" | \"outlined\" | \"ghost\" | \"accent\"\n\n## Examples\n\n**Elevated card with sections**\n```tsx\n<Card variant=\"elevated\">\n <CardHeader><Badge variant=\"teal\">New</Badge></CardHeader>\n <CardBody>\n <h3>Card Title</h3>\n <p>Description text.</p>\n </CardBody>\n <CardFooter>\n <Button variant=\"ghost\" size=\"sm\">Learn more</Button>\n </CardFooter>\n</Card>\n```\n",
11439
+ "Card": "# Card — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Content container with optional header, body, and footer sections.**\n\n```ts\nimport { Card, CardHeader, CardBody, CardFooter } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"elevated\"` \\| `\"outlined\"` \\| `\"ghost\"` \\| `\"accent\"` | `default` |\n| `hoverable` | `true` \\| `false` | `false` |\n| `clickable` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `variant=\"primary\"`\n → Use variant=\"elevated\" | \"outlined\" | \"ghost\" | \"accent\"\n- ❌ `padding / margin / marginTop (any spacing prop) on a useVyre component`\n → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it\n\n## Examples\n\n**Elevated card with sections**\n```tsx\n<Card variant=\"elevated\">\n <CardHeader><Badge variant=\"teal\">New</Badge></CardHeader>\n <CardBody>\n <h3>Card Title</h3>\n <p>Description text.</p>\n </CardBody>\n <CardFooter>\n <Button variant=\"ghost\" size=\"sm\">Learn more</Button>\n </CardFooter>\n</Card>\n```\n",
9541
11440
  "Checkbox": "# Checkbox — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Binary toggle for boolean form values.**\n\n```ts\nimport { Checkbox } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` | `md` |\n| `checked` | `true` \\| `false` | — |\n| `disabled` | `true` \\| `false` | `false` |\n| `indeterminate` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `size=\"lg\"`\n → Use size=\"md\"\n\n## Examples\n\n**Labeled checkbox**\n```tsx\n<label style={{ display: 'flex', alignItems: 'center', gap: 'var(--vyre-spacing-2)' }}>\n <Checkbox checked={agreed} onChange={e => setAgreed(e.target.checked)} />\n I agree to the terms\n</label>\n```\n",
9542
11441
  "RadioGroup": "# RadioGroup — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Controlled single-choice group. RadioGroup owns the selected value; render it data-driven via the options array OR with composable <Radio> children for custom content. role=radiogroup with proper labelling. For multi-select use Checkbox; for a compact dropdown use Select.**\n\n```ts\nimport { RadioGroup, Radio } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` | `md` |\n| `orientation` | `\"vertical\"` \\| `\"horizontal\"` | `vertical` |\n| `disabled` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `<Radio> used outside a <RadioGroup>`\n → Always wrap <Radio> in <RadioGroup>\n- ❌ `RadioGroup without value/onChange (React) or v-model (Vue)`\n → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React\n- ❌ `Using Checkbox for mutually-exclusive choices`\n → Use RadioGroup + Radio (or options) for one-of-many\n\n## Examples\n\n**Data-driven**\n```tsx\n<RadioGroup\n value={plan}\n onChange={setPlan}\n options={[\n { value: \"free\", label: \"Free\", description: \"For hobby projects\" },\n { value: \"pro\", label: \"Pro\", description: \"For teams\" },\n ]}\n/>\n```\n\n**Composable children**\n```tsx\n<RadioGroup value={plan} onChange={setPlan} orientation=\"horizontal\">\n <Radio value=\"free\" label=\"Free\" />\n <Radio value=\"pro\" label=\"Pro\" />\n</RadioGroup>\n```\n",
9543
11442
  "RichTextEditor": "# RichTextEditor — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Controlled WYSIWYG editor. value is an HTML string; you own it in state and set it in onChange (React) / v-model (Vue). Native contentEditable + execCommand — zero dependencies. Toolbar: bold, italic, underline, strike, h1-h3, ordered/unordered lists, quote, code block, link, clear formatting.**\n\n```ts\nimport { RichTextEditor } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `disabled` | `true` \\| `false` | `false` |\n| `readOnly` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `RichTextEditor without value/onChange (React) or v-model (Vue)`\n → Keep the HTML string in state and update it in onChange / v-model\n- ❌ `Rendering value as text or with dangerouslySetInnerHTML elsewhere without sanitising`\n → Sanitise (e.g. DOMPurify) before re-rendering untrusted RTE output\n- ❌ `toolbar=\"bold\" (string)`\n → Pass an array, e.g. toolbar={[\"bold\",\"italic\",\"link\"]}\n\n## Examples\n\n**Controlled editor**\n```tsx\nconst [html, setHtml] = useState(\"<p>Hello <strong>world</strong></p>\");\n<RichTextEditor value={html} onChange={setHtml} placeholder=\"Write…\" />\n```\n\n**Minimal toolbar**\n```tsx\n<RichTextEditor\n value={html}\n onChange={setHtml}\n toolbar={[\"bold\", \"italic\", \"link\"]}\n/>\n```\n",
9544
11443
  "Command": "# Command — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Command palette / search dialog. Use for search-first navigation or quick actions.**\n\n```ts\nimport { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandDialog } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Using Input type=\"search\" for search UI`\n → Use Command + CommandInput + CommandList + CommandItem\n\n## Examples\n\n**Basic command palette**\n```tsx\n<Command>\n <CommandInput placeholder=\"Search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem onSelect={() => handleSelect('dashboard')}>Dashboard</CommandItem>\n <CommandItem onSelect={() => handleSelect('settings')}>Settings</CommandItem>\n </CommandGroup>\n </CommandList>\n</Command>\n```\n",
9545
11444
  "DropdownMenu": "# DropdownMenu — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Contextual menu triggered by a button. Supports items, separators, checkbox items, radio groups, and sub-menus.**\n\n```ts\nimport { DropdownMenu, DropdownItem, DropdownSeparator, DropdownCheckboxItem, DropdownRadioGroup, DropdownRadioItem, DropdownSub } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `DropdownItem variant=\"primary\"`\n → Use variant=\"danger\" for destructive items only\n\n## Examples\n\n**Dropdown with danger item**\n```tsx\n<DropdownMenu trigger={<Button variant=\"secondary\">Options</Button>}>\n <DropdownItem onSelect={() => handleEdit()}>Edit</DropdownItem>\n <DropdownItem onSelect={() => handleDuplicate()}>Duplicate</DropdownItem>\n <DropdownSeparator />\n <DropdownItem variant=\"danger\" onSelect={() => handleDelete()}>Delete</DropdownItem>\n</DropdownMenu>\n```\n",
9546
11445
  "Field": "# Field — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Form field wrapper. Two ways to use it (both supported): (1) props-based — pass label/hint/state/required for the common case; (2) composable — use the parts FieldLabel, FieldDescription, FieldError, FieldGroup, FieldSet for richer layouts (multiple controls, custom error placement). The props-based API is unchanged and still works.**\n\n```ts\nimport { Field, Input, Textarea } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `state` | `\"idle\"` \\| `\"error\"` \\| `\"success\"` \\| `\"warning\"` | `idle` |\n| `required` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Applying state prop directly to Input`\n → Wrap Input in <Field state=\"error\"> to apply validation styling\n- ❌ `Mixing props label/hint AND FieldLabel/FieldError for the same field`\n → Pick one: either props-based (label/hint/state) OR composable parts\n\n## Examples\n\n**Error state field**\n```tsx\n<Field label=\"Email\" state=\"error\" hint=\"Invalid email format\">\n <Input type=\"email\" placeholder=\"you@example.com\" />\n</Field>\n```\n\n**Search field with left icon**\n```tsx\n<Field label=\"Search\">\n <Input leftElement={<SearchIcon />} placeholder=\"Search...\" />\n</Field>\n```\n\n**Composable field with explicit parts**\n```tsx\n<Field>\n <FieldLabel required htmlFor=\"email\">Email</FieldLabel>\n <Input id=\"email\" type=\"email\" />\n <FieldDescription>We\\u2019ll never share it.</FieldDescription>\n <FieldError>{errors.email}</FieldError>\n</Field>\n\n// Two controls side by side\n<FieldGroup orientation=\"horizontal\">\n <Field label=\"First name\"><Input /></Field>\n <Field label=\"Last name\"><Input /></Field>\n</FieldGroup>\n```\n",
9547
- "Input": "# Input — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Text input field. Wrap in Field for labels and validation. Use leftElement/rightElement for icons.**\n\n```ts\nimport { Input } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n\n## Common AI Mistakes\n\n- ❌ `size=\"icon\"`\n → Use size=\"sm\" | \"md\" | \"lg\"\n- ❌ `type=\"search\" for search UI`\n → Import Command from @usevyre/react for search palettes\n- ❌ `Vue: binding Input/Textarea value without v-model`\n → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange\n\n## Examples\n\n**Password input with icon**\n```tsx\n<Input type=\"password\" rightElement={<EyeIcon />} placeholder=\"Password\" />\n```\n",
11446
+ "Input": "# Input — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Text input field. Wrap in Field for labels and validation. Use leftElement/rightElement for icons.**\n\n```ts\nimport { Input } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n\n## Common AI Mistakes\n\n- ❌ `size=\"icon\"`\n → Use size=\"sm\" | \"md\" | \"lg\"\n- ❌ `type=\"search\" for search UI`\n → Import Command from @usevyre/react for search palettes\n- ❌ `Vue: binding Input/Textarea value without v-model`\n → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange\n- ❌ `padding / margin / marginTop (any spacing prop) on a useVyre component`\n → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it\n\n## Examples\n\n**Password input with icon**\n```tsx\n<Input type=\"password\" rightElement={<EyeIcon />} placeholder=\"Password\" />\n```\n",
9548
11447
  "Label": "# Label — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Accessible form label. Associate with input via htmlFor.**\n\n```ts\nimport { Label } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `required` | `true` \\| `false` | `false` |\n\n## Examples\n\n**Label with input**\n```tsx\n<Label htmlFor=\"email\">Email address</Label>\n<Input id=\"email\" type=\"email\" />\n```\n",
9549
11448
  "Modal": "# Modal — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Dialog overlay for confirmations, forms, or focused content.**\n\n```ts\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"full\"` | `md` |\n| `open` | `true` \\| `false` | — |\n\n## Common AI Mistakes\n\n- ❌ `size=\"xl\"`\n → Use size=\"lg\" or size=\"full\"\n\n## Examples\n\n**Confirmation modal**\n```tsx\n<Modal open={isOpen} onClose={() => setIsOpen(false)} title=\"Confirm Delete\" size=\"sm\">\n <ModalBody>Are you sure you want to delete this item?</ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setIsOpen(false)}>Cancel</Button>\n <Button variant=\"danger\" onClick={handleDelete}>Delete</Button>\n </ModalFooter>\n</Modal>\n```\n",
9550
11449
  "Pagination": "# Pagination — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Page navigation for paginated lists or tables.**\n\n```ts\nimport { Pagination } from \"@usevyre/react\"\n```\n\n## Examples\n\n**Basic pagination**\n```tsx\n<Pagination page={currentPage} total={totalPages} onChange={setCurrentPage} />\n```\n",
@@ -9571,5 +11470,9 @@ export const cheatSheets = {
9571
11470
  "Item": "# Item — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Layout primitive for list rows, settings rows, and notification rows. Denser than Card — use Item (not Card) for repeated list rows.**\n\n```ts\nimport { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemGroup } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `variant` | `\"default\"` \\| `\"outlined\"` \\| `\"muted\"` \\| `\"plain\"` | `default` |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `md` |\n| `clickable` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Card used for repeated list rows`\n → Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows\n- ❌ `Item variant=\"primary\"`\n → Use variant=\"default\" | \"outlined\" | \"muted\"\n- ❌ `raw text directly inside Item`\n → Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>\n\n## Examples\n\n**Settings row with media, content and a trailing switch**\n```tsx\n<Item>\n <ItemMedia><BellIcon /></ItemMedia>\n <ItemContent>\n <ItemTitle>Notifications</ItemTitle>\n <ItemDescription>Receive an email when someone mentions you.</ItemDescription>\n </ItemContent>\n <ItemActions>\n <Switch defaultChecked />\n </ItemActions>\n</Item>\n```\n\n**Grouped clickable list with dividers**\n```tsx\n<ItemGroup separated>\n <Item clickable>\n <ItemContent><ItemTitle>Profile</ItemTitle></ItemContent>\n </Item>\n <Item clickable>\n <ItemContent><ItemTitle>Billing</ItemTitle></ItemContent>\n </Item>\n</ItemGroup>\n```\n",
9572
11471
  "Kanban": "# Kanban — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Drag-and-drop board: cards move between columns (or reorder within a column). CONTROLLED & data-driven like DataGrid. While dragging, a placeholder shows the exact drop position. Each card is wrapped in a Card (variant=\"outlined\"); renderCard (React) / #card slot (Vue) can render ANY content incl. complex components (Avatar/Badge/Progress). Columns and cards accept an optional semantic color tint. Native HTML5 DnD, zero deps.**\n\n```ts\nimport { Kanban } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `Kanban without onChange (or ignoring it)`\n → Store columns in state and setColumns in onChange (v-model in Vue)\n- ❌ `Duplicate card ids across columns`\n → Use globally-unique card ids across the entire board\n- ❌ `Mutating value in place then calling onChange`\n → Pass the new array Kanban gives you straight to setState / v-model\n- ❌ `color=\"blue\" (or any non-semantic value)`\n → Use one of: \"default\" | \"accent\" | \"teal\" | \"success\" | \"warning\" | \"danger\"\n\n## Examples\n\n**Controlled board**\n```tsx\nconst [columns, setColumns] = useState([\n { id: \"todo\", title: \"To Do\", cards: [{ id: \"1\", title: \"Spec API\" }] },\n { id: \"doing\", title: \"In Progress\", cards: [] },\n { id: \"done\", title: \"Done\", cards: [{ id: \"2\", title: \"Kickoff\" }] },\n]);\n<Kanban value={columns} onChange={setColumns} />\n```\n\n**Custom card body + click handler**\n```tsx\n<Kanban\n value={columns}\n onChange={setColumns}\n onCardClick={(card) => openDetail(card.id)}\n renderCard={(card) => (\n <><strong>{card.title}</strong><Badge>{card.id}</Badge></>\n )}\n/>\n```\n\n**Tinted columns/cards + complex card content**\n```tsx\nconst [cols, setCols] = useState([\n { id: \"doing\", title: \"In Progress\", color: \"teal\", cards: [\n { id: \"t1\", title: \"OAuth\", assignee: \"AK\", progress: 60, color: \"warning\" },\n ]},\n]);\n<Kanban\n value={cols}\n onChange={setCols}\n renderCard={(card) => (\n <><strong>{card.title}</strong><Progress value={card.progress} /></>\n )}\n/>\n```\n",
9573
11472
  "Conversation": "# Conversation — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Chat / inbox message thread. CONTROLLED & data-driven like Kanban — you own `value` (messages array) and append in your own send handler; Conversation holds no message state. Consecutive messages from the same author are grouped (avatar + name shown once), day separators are inserted on date change, and outgoing messages (authorId === currentUserId) align right.**\n\n```ts\nimport { Conversation } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `composer` | `true` \\| `false` | `false` |\n| `allowAttachments` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `Conversation without currentUserId`\n → Always pass currentUserId matching one of the message authorId values\n- ❌ `Expecting Conversation to store/append messages`\n → Append to your own state in onSend (or @send) and pass it back via value\n- ❌ `composer without onSend (React) / @send (Vue)`\n → Provide onSend / @send to append the message to value\n- ❌ `Treating onSend as (text) only when using allowAttachments`\n → Handle onSend(text, files) — map files to message attachments and append\n\n## Examples\n\n**Controlled thread with built-in composer**\n```tsx\nconst [messages, setMessages] = useState([\n { id: \"1\", authorId: \"sam\", authorName: \"Sam\", text: \"Hey!\" },\n { id: \"2\", authorId: \"me\", text: \"Hi \\ud83d\\udc4b\", status: \"read\" },\n]);\n<Conversation\n value={messages}\n currentUserId=\"me\"\n composer\n onSend={(t) => setMessages((m) => [...m, { id: crypto.randomUUID(), authorId: \"me\", text: t }])}\n/>\n```\n\n**Typing indicator + custom bubble**\n```tsx\n<Conversation\n value={messages}\n currentUserId=\"me\"\n typing=\"Sam is typing\"\n renderMessage={(m) => <strong>{m.text}</strong>}\n/>\n```\n\n**Message with image + file attachments**\n```tsx\nconst messages = [\n { id: \"1\", authorId: \"sam\", authorName: \"Sam\", text: \"Moodboard \\ud83d\\udc47\",\n attachments: [{ kind: \"image\", url: \"/board.png\", name: \"board.png\" }] },\n { id: \"2\", authorId: \"me\", text: \"Specs:\", status: \"read\",\n attachments: [{ kind: \"file\", url: \"/spec.pdf\", name: \"spec.pdf\", size: \"2.4 MB\" }] },\n];\n<Conversation value={messages} currentUserId=\"me\" />\n```\n",
11473
+ "Stack": "# Stack — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Full one-dimensional flex layout primitive. USE INSTEAD OF <div style={{display:'flex'}}>. Covers the whole CSS flexbox surface (direction incl. reverse, wrap, align/justify/alignContent/alignSelf, grow/shrink/basis, per-axis gap) with token-locked spacing. Renders a plain <div> (or `as`).**\n\n```ts\nimport { Stack } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `direction` | `\"row\"` \\| `\"column\"` \\| `\"row-reverse\"` \\| `\"column-reverse\"` | `row` |\n| `gap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | `md` |\n| `rowGap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `columnGap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `align` | `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"stretch\"` \\| `\"baseline\"` | `stretch` |\n| `justify` | `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"between\"` \\| `\"around\"` \\| `\"evenly\"` | `start` |\n| `alignContent` | `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"stretch\"` \\| `\"between\"` \\| `\"around\"` \\| `\"evenly\"` | — |\n| `alignSelf` | `\"auto\"` \\| `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"stretch\"` \\| `\"baseline\"` | — |\n| `wrap` | `\"nowrap\"` \\| `\"wrap\"` \\| `\"wrap-reverse\"` | `nowrap` |\n| `basis` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` \\| `\"auto\"` \\| `\"content\"` \\| `\"0\"` | — |\n| `width` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `height` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `inline` | `true` \\| `false` | `false` |\n\n## Common AI Mistakes\n\n- ❌ `<div style={{ display: 'flex', gap: 12 }}>`\n → Use <Stack gap=\"md\"> — gap is a token\n- ❌ `gap={12} or gap=\"12px\"`\n → Use gap=\"none|xs|sm|md|lg|xl|2xl\"\n- ❌ `direction=\"vertical\" / \"horizontal\"`\n → Use direction=\"row\" or \"column\" (also row-reverse / column-reverse)\n- ❌ `style={{ width: \"100%\" }} / style={{ height: 320 }}`\n → Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.\n\n## Examples\n\n**Row, vertically centered, spaced apart**\n```tsx\n<Stack direction=\"row\" gap=\"md\" align=\"center\" justify=\"between\">\n <Avatar src={user.avatar} />\n <Text>{user.name}</Text>\n <Button>Edit</Button>\n</Stack>\n```\n\n**Wrapping grid-ish gallery with per-axis gap**\n```tsx\n<Stack wrap=\"wrap\" rowGap=\"lg\" columnGap=\"md\">\n {tags.map((t) => <Tag key={t}>{t}</Tag>)}\n</Stack>\n```\n",
11474
+ "Grid": "# Grid — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Two-dimensional CSS grid primitive. Explicit column/row counts (or auto-fit), auto-flow control, token gap. Pair with GridItem for cell spanning/placement. Renders a plain <div> (or `as`).**\n\n```ts\nimport { Grid, GridItem } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `flow` | `\"row\"` \\| `\"column\"` \\| `\"dense\"` \\| `\"row-dense\"` \\| `\"column-dense\"` | — |\n| `gap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | `md` |\n| `rowGap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `columnGap` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `align` | `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"stretch\"` | `stretch` |\n| `justify` | `\"start\"` \\| `\"center\"` \\| `\"end\"` \\| `\"stretch\"` | — |\n| `width` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `height` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n\n## Common AI Mistakes\n\n- ❌ `<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>`\n → Use <Grid columns={3} gap=\"md\">\n- ❌ `columns=\"3\" (string)`\n → Use columns={3} or columns=\"auto-fit\"\n- ❌ `Nested div with inline grid-column for spanning`\n → Wrap the cell in <GridItem colSpan={2}>\n- ❌ `style={{ width: \"100%\" }} / style={{ height: 320 }}`\n → Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.\n\n## Examples\n\n**Three-column grid with a wide first cell**\n```tsx\n<Grid columns={3} gap=\"lg\">\n <GridItem colSpan={2}><Card>Wide</Card></GridItem>\n <Card>Two</Card>\n <Card>Three</Card>\n</Grid>\n```\n\n**Responsive auto-fit grid**\n```tsx\n<Grid columns=\"auto-fit\" gap=\"md\">\n {items.map((i) => <Card key={i.id}>{i.title}</Card>)}\n</Grid>\n```\n",
11475
+ "GridItem": "# GridItem — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or `as`).**\n\n```ts\nimport { GridItem } from \"@usevyre/react\"\n```\n\n## Common AI Mistakes\n\n- ❌ `GridItem outside a Grid`\n → Place <GridItem> directly inside <Grid>\n\n## Examples\n\n**Span two columns**\n```tsx\n<Grid columns={4} gap=\"md\">\n <GridItem colSpan={2}>Featured</GridItem>\n <div>a</div>\n <div>b</div>\n</Grid>\n```\n",
11476
+ "Box": "# Box — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Spacing-only container plus a controlled escape hatch. Token padding/margin with shorthand, per-axis (X/Y) and per-side (Top/Right/Bottom/Left) overrides. The `style` prop is an explicit anti-pattern escape hatch. Renders a plain <div> (or `as`).**\n\n```ts\nimport { Box } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `padding` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingX` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingY` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingTop` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingRight` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingBottom` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `paddingLeft` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `margin` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginX` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginY` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginTop` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginRight` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginBottom` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `marginLeft` | `\"none\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `width` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n| `height` | `\"auto\"` \\| `\"full\"` \\| `\"fit\"` \\| `\"screen\"` \\| `\"xs\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` \\| `\"2xl\"` | — |\n\n## Common AI Mistakes\n\n- ❌ `<Box style={{ padding: 16 }}>`\n → Use <Box padding=\"md\"> (or paddingX/paddingTop/...)\n- ❌ `Using Box for flex/grid layout`\n → Use <Stack> or <Grid>\n- ❌ `style={{ width: \"100%\" }} / style={{ height: 320 }}`\n → Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.\n\n## Examples\n\n**Asymmetric padding**\n```tsx\n<Box as=\"section\" paddingX=\"lg\" paddingY=\"md\">\n <Heading>Settings</Heading>\n</Box>\n```\n\n**Vertical rhythm via margin-top**\n```tsx\n<Box marginTop=\"xl\"><Separator /></Box>\n```\n",
9574
11477
  "DateRangePicker": "# DateRangePicker — AI Cheat Sheet\n> Quick reference for Claude / Cursor / Copilot\n\n**Start/end date range picker. Built on Calendar (mode=range) with a friendlier { from, to } object API, a two-month side-by-side view, and preset shortcuts. Use this for report/filter date ranges; use DatePicker for a single date.**\n\n```ts\nimport { DateRangePicker } from \"@usevyre/react\"\n```\n\n## Valid Props\n\n| Prop | Values | Default |\n|------|--------|---------|\n| `numberOfMonths` | `\"1\"` \\| `\"2\"` | `2` |\n| `weekStartsOn` | `\"0\"` \\| `\"1\"` | `1` |\n\n## Common AI Mistakes\n\n- ❌ `value={[from, to]}`\n → Use value={{ from, to }} and read range.from / range.to\n- ❌ `DateRangePicker for a single date`\n → Use <DatePicker /> for a single date\n- ❌ `presets=\"true\" (string)`\n → Use the bare prop: presets (or presets={true})\n\n## Examples\n\n**Range picker with built-in presets**\n```tsx\nconst [range, setRange] = useState({ from: null, to: null });\n<DateRangePicker value={range} onChange={setRange} presets />\n```\n\n**Single month, no presets**\n```tsx\n<DateRangePicker value={range} onChange={setRange} numberOfMonths={1} />\n```\n"
9575
11478
  };