@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/anti-patterns.json +127 -1
- package/dist/cheat-sheets/alertdialog.md +41 -0
- package/dist/cheat-sheets/box.md +52 -0
- package/dist/cheat-sheets/button.md +2 -0
- package/dist/cheat-sheets/card.md +2 -0
- package/dist/cheat-sheets/grid.md +50 -0
- package/dist/cheat-sheets/griditem.md +24 -0
- package/dist/cheat-sheets/index.md +5 -0
- package/dist/cheat-sheets/input.md +2 -0
- package/dist/cheat-sheets/stack.md +55 -0
- package/dist/claude-context.md +212 -1
- package/dist/copilot-instructions.md +212 -1
- package/dist/cursor-rules.md +96 -1
- package/dist/full-context.md +211 -0
- package/dist/index.js +2072 -169
- package/dist/schema.json +781 -3
- package/dist/tokens.json +1 -1
- package/dist/tokens.md +1 -1
- package/dist/version-info.json +144 -89
- package/dist/windsurf-rules.md +212 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// @usevyre/ai-context v1.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
###
|
|
7071
|
+
### Stack
|
|
6302
7072
|
|
|
6303
|
-
|
|
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 {
|
|
7076
|
+
import { Stack } from "@usevyre/react"
|
|
6307
7077
|
|
|
6308
7078
|
// Props:
|
|
6309
|
-
//
|
|
6310
|
-
//
|
|
6311
|
-
//
|
|
6312
|
-
//
|
|
6313
|
-
//
|
|
6314
|
-
//
|
|
6315
|
-
//
|
|
6316
|
-
//
|
|
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.
|
|
6461
|
-
"generatedAt": "2026-05-
|
|
7399
|
+
"version": "1.6.0",
|
|
7400
|
+
"generatedAt": "2026-05-18",
|
|
6462
7401
|
"package": "@usevyre/react",
|
|
6463
|
-
"packageVersion": "1.
|
|
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
|
-
"
|
|
8598
|
-
"description": "
|
|
8599
|
-
"import": "import {
|
|
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
|
-
"
|
|
8602
|
-
"type": "
|
|
8603
|
-
"
|
|
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
|
-
"
|
|
8606
|
-
"type": "
|
|
8607
|
-
"
|
|
9659
|
+
"inline": {
|
|
9660
|
+
"type": "boolean",
|
|
9661
|
+
"default": false,
|
|
9662
|
+
"description": "Render as inline-flex instead of flex"
|
|
8608
9663
|
},
|
|
8609
|
-
"
|
|
8610
|
-
"type": "
|
|
8611
|
-
"
|
|
8612
|
-
|
|
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
|
-
"
|
|
9678
|
+
"rowGap": {
|
|
8615
9679
|
"type": "enum",
|
|
8616
9680
|
"values": [
|
|
8617
|
-
|
|
8618
|
-
|
|
9681
|
+
"none",
|
|
9682
|
+
"xs",
|
|
9683
|
+
"sm",
|
|
9684
|
+
"md",
|
|
9685
|
+
"lg",
|
|
9686
|
+
"xl",
|
|
9687
|
+
"2xl"
|
|
8619
9688
|
],
|
|
8620
|
-
"
|
|
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
|
-
"
|
|
8624
|
-
"type": "
|
|
8625
|
-
"
|
|
8626
|
-
|
|
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
|
-
"
|
|
8629
|
-
"type": "
|
|
8630
|
-
"
|
|
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
|
-
"
|
|
8633
|
-
"type": "
|
|
8634
|
-
"
|
|
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
|
-
"
|
|
8637
|
-
"type": "
|
|
8638
|
-
"
|
|
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
|
-
"
|
|
9742
|
+
"alignSelf": {
|
|
8641
9743
|
"type": "enum",
|
|
8642
9744
|
"values": [
|
|
8643
|
-
|
|
8644
|
-
|
|
9745
|
+
"auto",
|
|
9746
|
+
"start",
|
|
9747
|
+
"center",
|
|
9748
|
+
"end",
|
|
9749
|
+
"stretch",
|
|
9750
|
+
"baseline"
|
|
8645
9751
|
],
|
|
8646
|
-
"
|
|
8647
|
-
|
|
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": "
|
|
8653
|
-
"reason": "
|
|
8654
|
-
"fix": "Use
|
|
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": "
|
|
8658
|
-
"reason": "
|
|
8659
|
-
"fix": "Use
|
|
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": "
|
|
8663
|
-
"reason": "
|
|
8664
|
-
"fix": "Use
|
|
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": "
|
|
8670
|
-
"code": "
|
|
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": "
|
|
8674
|
-
"code": "<
|
|
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
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
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.
|
|
9193
|
-
"packageVersion": "1.
|
|
9194
|
-
"generatedAt": "2026-05-
|
|
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.
|
|
9229
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9236
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9243
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9250
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9257
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9264
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9271
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9278
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9285
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9292
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9299
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9306
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9313
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9320
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9327
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9334
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9341
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9348
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9355
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9362
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9369
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9376
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9383
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9390
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9397
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9404
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9411
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9418
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9425
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9432
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9439
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9446
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9453
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9460
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9467
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9474
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9481
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9488
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9495
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9502
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9509
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9516
|
-
"lastUpdated": "2026-05-
|
|
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.
|
|
9523
|
-
"lastUpdated": "2026-05-
|
|
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
|
};
|