@usevyre/ai-context 1.2.2 → 1.4.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.
Files changed (38) hide show
  1. package/dist/anti-patterns.json +393 -1
  2. package/dist/cheat-sheets/box.md +52 -0
  3. package/dist/cheat-sheets/button.md +2 -0
  4. package/dist/cheat-sheets/card.md +2 -0
  5. package/dist/cheat-sheets/carousel.md +50 -0
  6. package/dist/cheat-sheets/carouselslide.md +22 -0
  7. package/dist/cheat-sheets/emptystate.md +48 -0
  8. package/dist/cheat-sheets/form.md +50 -0
  9. package/dist/cheat-sheets/formfield.md +22 -0
  10. package/dist/cheat-sheets/grid.md +50 -0
  11. package/dist/cheat-sheets/griditem.md +24 -0
  12. package/dist/cheat-sheets/index.md +22 -0
  13. package/dist/cheat-sheets/input.md +2 -0
  14. package/dist/cheat-sheets/numberinput.md +41 -0
  15. package/dist/cheat-sheets/otpinput.md +51 -0
  16. package/dist/cheat-sheets/stack.md +55 -0
  17. package/dist/cheat-sheets/stat.md +41 -0
  18. package/dist/cheat-sheets/statgroup.md +23 -0
  19. package/dist/cheat-sheets/step.md +8 -0
  20. package/dist/cheat-sheets/steppanel.md +8 -0
  21. package/dist/cheat-sheets/stepper.md +59 -0
  22. package/dist/cheat-sheets/steppernav.md +8 -0
  23. package/dist/cheat-sheets/timeline.md +40 -0
  24. package/dist/cheat-sheets/timelineitem.md +28 -0
  25. package/dist/cheat-sheets/togglegroup.md +55 -0
  26. package/dist/cheat-sheets/toggleitem.md +29 -0
  27. package/dist/cheat-sheets/tree.md +48 -0
  28. package/dist/claude-context.md +770 -1
  29. package/dist/copilot-instructions.md +770 -1
  30. package/dist/cursor-rules.md +269 -1
  31. package/dist/full-context.md +769 -0
  32. package/dist/index.js +10427 -4763
  33. package/dist/schema.json +1680 -3
  34. package/dist/tokens.json +1 -1
  35. package/dist/tokens.md +1 -1
  36. package/dist/version-info.json +320 -91
  37. package/dist/windsurf-rules.md +770 -1
  38. package/package.json +1 -1
@@ -339,6 +339,7 @@ import { Button } from "@usevyre/react"
339
339
  - ❌ `color="..."` → Use variant prop instead
340
340
  - ❌ `icon={...}` → Use leftIcon={...} or rightIcon={...}
341
341
  - ❌ `size="icon" without aria-label` → Add aria-label describing the action
342
+ - ❌ `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
342
343
 
343
344
  ---
344
345
 
@@ -424,6 +425,7 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
424
425
 
425
426
  **Common mistakes:**
426
427
  - ❌ `variant="primary"` → Use variant="elevated" | "outlined" | "ghost" | "accent"
428
+ - ❌ `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
427
429
 
428
430
  ---
429
431
 
@@ -635,6 +637,7 @@ import { Input } from "@usevyre/react"
635
637
  - ❌ `size="icon"` → Use size="sm" | "md" | "lg"
636
638
  - ❌ `type="search" for search UI` → Import Command from @usevyre/react for search palettes
637
639
  - ❌ `Vue: binding Input/Textarea value without v-model` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
640
+ - ❌ `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
638
641
 
639
642
  ---
640
643
 
@@ -1377,6 +1380,716 @@ const messages = [
1377
1380
 
1378
1381
  ---
1379
1382
 
1383
+ ### Stack
1384
+
1385
+ 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`).
1386
+
1387
+ ```tsx
1388
+ import { Stack } from "@usevyre/react"
1389
+
1390
+ // Props:
1391
+ // direction = "row" | "column" | "row-reverse" | "column-reverse" (default: row)
1392
+ // inline = boolean (default: false)
1393
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
1394
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1395
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1396
+ // align = "start" | "center" | "end" | "stretch" | "baseline" (default: stretch)
1397
+ // justify = "start" | "center" | "end" | "between" | "around" | "evenly" (default: start)
1398
+ // alignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly"
1399
+ // alignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline"
1400
+ // wrap = "nowrap" | "wrap" | "wrap-reverse" (default: nowrap)
1401
+ // grow = number
1402
+ // shrink = number
1403
+ // basis = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "auto" | "content" | "0"
1404
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1405
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1406
+ // as = string (default: div)
1407
+
1408
+ // Examples:
1409
+ <Stack direction="row" gap="md" align="center" justify="between">
1410
+ <Avatar src={user.avatar} />
1411
+ <Text>{user.name}</Text>
1412
+ <Button>Edit</Button>
1413
+ </Stack>
1414
+ <Stack wrap="wrap" rowGap="lg" columnGap="md">
1415
+ {tags.map((t) => <Tag key={t}>{t}</Tag>)}
1416
+ </Stack>
1417
+ ```
1418
+
1419
+ **Common mistakes:**
1420
+ - ❌ `<div style={{ display: 'flex', gap: 12 }}>` → Use <Stack gap="md"> — gap is a token
1421
+ - ❌ `gap={12} or gap="12px"` → Use gap="none|xs|sm|md|lg|xl|2xl"
1422
+ - ❌ `direction="vertical" / "horizontal"` → Use direction="row" or "column" (also row-reverse / column-reverse)
1423
+ - ❌ `style={{ width: "100%" }} / style={{ height: 320 }}` → Use the width / height prop: width="full", width="md", height="screen", etc.
1424
+
1425
+ ---
1426
+
1427
+ ### Grid
1428
+
1429
+ 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`).
1430
+
1431
+ ```tsx
1432
+ import { Grid, GridItem } from "@usevyre/react"
1433
+
1434
+ // Props:
1435
+ // columns = number | "auto-fit" (default: 1)
1436
+ // rows = number | "auto"
1437
+ // flow = "row" | "column" | "dense" | "row-dense" | "column-dense"
1438
+ // gap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default: md)
1439
+ // rowGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1440
+ // columnGap = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1441
+ // align = "start" | "center" | "end" | "stretch" (default: stretch)
1442
+ // justify = "start" | "center" | "end" | "stretch"
1443
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1444
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1445
+ // as = string (default: div)
1446
+
1447
+ // Examples:
1448
+ <Grid columns={3} gap="lg">
1449
+ <GridItem colSpan={2}><Card>Wide</Card></GridItem>
1450
+ <Card>Two</Card>
1451
+ <Card>Three</Card>
1452
+ </Grid>
1453
+ <Grid columns="auto-fit" gap="md">
1454
+ {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
1455
+ </Grid>
1456
+ ```
1457
+
1458
+ **Common mistakes:**
1459
+ - ❌ `<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>` → Use <Grid columns={3} gap="md">
1460
+ - ❌ `columns="3" (string)` → Use columns={3} or columns="auto-fit"
1461
+ - ❌ `Nested div with inline grid-column for spanning` → Wrap the cell in <GridItem colSpan={2}>
1462
+ - ❌ `style={{ width: "100%" }} / style={{ height: 320 }}` → Use the width / height prop: width="full", width="md", height="screen", etc.
1463
+
1464
+ ---
1465
+
1466
+ ### GridItem
1467
+
1468
+ Child placement inside <Grid>. Sets column/row span and start lines. Renders a plain <div> (or `as`).
1469
+
1470
+ ```tsx
1471
+ import { GridItem } from "@usevyre/react"
1472
+
1473
+ // Props:
1474
+ // colSpan = number
1475
+ // rowSpan = number
1476
+ // colStart = number
1477
+ // rowStart = number
1478
+ // as = string (default: div)
1479
+
1480
+ // Examples:
1481
+ <Grid columns={4} gap="md">
1482
+ <GridItem colSpan={2}>Featured</GridItem>
1483
+ <div>a</div>
1484
+ <div>b</div>
1485
+ </Grid>
1486
+ ```
1487
+
1488
+ **Common mistakes:**
1489
+ - ❌ `GridItem outside a Grid` → Place <GridItem> directly inside <Grid>
1490
+
1491
+ ---
1492
+
1493
+ ### Box
1494
+
1495
+ 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`).
1496
+
1497
+ ```tsx
1498
+ import { Box } from "@usevyre/react"
1499
+
1500
+ // Props:
1501
+ // padding = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1502
+ // paddingX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1503
+ // paddingY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1504
+ // paddingTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1505
+ // paddingRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1506
+ // paddingBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1507
+ // paddingLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1508
+ // margin = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1509
+ // marginX = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1510
+ // marginY = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1511
+ // marginTop = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1512
+ // marginRight = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1513
+ // marginBottom = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1514
+ // marginLeft = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1515
+ // width = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1516
+ // height = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"
1517
+ // as = string (default: div)
1518
+ // style = React.CSSProperties
1519
+
1520
+ // Examples:
1521
+ <Box as="section" paddingX="lg" paddingY="md">
1522
+ <Heading>Settings</Heading>
1523
+ </Box>
1524
+ <Box marginTop="xl"><Separator /></Box>
1525
+ ```
1526
+
1527
+ **Common mistakes:**
1528
+ - ❌ `<Box style={{ padding: 16 }}>` → Use <Box padding="md"> (or paddingX/paddingTop/...)
1529
+ - ❌ `Using Box for flex/grid layout` → Use <Stack> or <Grid>
1530
+ - ❌ `style={{ width: "100%" }} / style={{ height: 320 }}` → Use the width / height prop: width="full", width="md", height="screen", etc.
1531
+
1532
+ ---
1533
+
1534
+ ### Form
1535
+
1536
+ Controlled, data-driven form. Zero dependencies. Validation runs on submit and (after the first submit) on blur. Errors map into the wrapped Field automatically (state=error + hint=message). Compose with FormField, which wires name/value/onChange/onBlur into a single control child.
1537
+
1538
+ ```tsx
1539
+ import { Form, FormField } from "@usevyre/react"
1540
+
1541
+ // Props:
1542
+ // values = Record<string, any>
1543
+ // defaultValues = Record<string, any>
1544
+ // onChange = function
1545
+ // onSubmit = function
1546
+ // onInvalid = function
1547
+
1548
+ // Examples:
1549
+ const [values, setValues] = useState({ email: "", password: "" });
1550
+
1551
+ <Form values={values} onChange={setValues} onSubmit={(v) => signIn(v)}>
1552
+ <FormField name="email" label="Email" rules={{ required: true, email: true }}>
1553
+ <Input type="email" />
1554
+ </FormField>
1555
+ <FormField name="password" label="Password" rules={{ required: true, minLength: 8 }}>
1556
+ <Input type="password" />
1557
+ </FormField>
1558
+ <Button type="submit" variant="primary">Sign in</Button>
1559
+ </Form>
1560
+ <FormField
1561
+ name="confirm"
1562
+ label="Confirm password"
1563
+ rules={{
1564
+ required: true,
1565
+ validate: (v, all) => v === all.password ? null : "Passwords do not match",
1566
+ }}
1567
+ >
1568
+ <Input type="password" />
1569
+ </FormField>
1570
+ ```
1571
+
1572
+ **Common mistakes:**
1573
+ - ❌ `Manually tracking each field's error state with useState` → Wrap controls in <FormField name rules> and let Form manage errors
1574
+ - ❌ `Adding a validation library (zod/yup) just for basic rules` → Use rules={{ required, minLength, pattern, email, validate }}
1575
+ - ❌ `<FormField> with multiple control children` → Use one control per FormField (Input/Textarea/Select/etc.)
1576
+ - ❌ `<FormField> outside a <Form>` → Always nest FormField inside <Form>
1577
+
1578
+ ---
1579
+
1580
+ ### FormField
1581
+
1582
+ A single labelled, validated field inside <Form>. Injects name/value/onChange/onBlur into its one control child and wraps it in <Field> (label + error state + hint).
1583
+
1584
+ ```tsx
1585
+ import { FormField } from "@usevyre/react"
1586
+
1587
+ // Props:
1588
+ // name = string
1589
+ // label = string
1590
+ // hint = string
1591
+ // rules = object
1592
+
1593
+ // Examples:
1594
+ <FormField name="bio" label="Bio" hint="Max 200 characters" rules={{ maxLength: 200 }}>
1595
+ <Textarea />
1596
+ </FormField>
1597
+ ```
1598
+
1599
+ **Common mistakes:**
1600
+ - ❌ `Putting onChange/value manually on the control inside FormField` → Let FormField wire the control; only pass static props (type, placeholder)
1601
+
1602
+ ---
1603
+
1604
+ ### NumberInput
1605
+
1606
+ Controlled numeric input with −/+ stepper buttons. onChange emits a NUMBER (or null when empty) — NOT an event. Drops straight into <FormField> (Form handles the non-event value). Clamps to min/max on blur; keyboard ArrowUp/Down ±step, Shift+Arrow ±step×10.
1607
+
1608
+ ```tsx
1609
+ import { NumberInput } from "@usevyre/react"
1610
+
1611
+ // Props:
1612
+ // value = number | null
1613
+ // defaultValue = number | null (default: null)
1614
+ // onChange = function
1615
+ // min = number
1616
+ // max = number
1617
+ // step = number (default: 1)
1618
+ // precision = number
1619
+ // size = "sm" | "md" | "lg" (default: md)
1620
+ // disabled = boolean (default: false)
1621
+ // readOnly = boolean (default: false)
1622
+
1623
+ // Examples:
1624
+ const [qty, setQty] = useState<number | null>(1);
1625
+
1626
+ <NumberInput value={qty} onChange={setQty} min={1} max={99} />
1627
+ <FormField name="age" label="Age" rules={{ required: true, min: 18 }}>
1628
+ <NumberInput min={0} max={120} />
1629
+ </FormField>
1630
+ ```
1631
+
1632
+ **Common mistakes:**
1633
+ - ❌ `onChange={(e) => set(e.target.value)}` → onChange={(value) => set(value)} — value is number | null
1634
+ - ❌ `Using <Input type="number"> for numeric fields` → Use <NumberInput value onChange min max step />
1635
+ - ❌ `Parsing the value with Number() in form state` → Store the value directly; it is already number | null
1636
+
1637
+ ---
1638
+
1639
+ ### ToggleGroup
1640
+
1641
+ Segmented control. CONTROLLED — the group owns the value. onChange emits the VALUE (not an event). type=single → value:string|null; type=multiple → value:string[]. Provide options[] for simple lists or <ToggleItem value> children for custom content. Distinct from Switch (boolean), ButtonGroup (layout only), RadioGroup (form radios, single only).
1642
+
1643
+ ```tsx
1644
+ import { ToggleGroup, ToggleItem } from "@usevyre/react"
1645
+
1646
+ // Props:
1647
+ // type = "single" | "multiple" (default: single)
1648
+ // value = string | null | string[]
1649
+ // onChange = function
1650
+ // options = array
1651
+ // size = "sm" | "md" | "lg" (default: md)
1652
+ // orientation = "horizontal" | "vertical" (default: horizontal)
1653
+ // disabled = boolean (default: false)
1654
+
1655
+ // Examples:
1656
+ const [view, setView] = useState<string | null>("grid");
1657
+
1658
+ <ToggleGroup
1659
+ value={view}
1660
+ onChange={setView}
1661
+ options={[
1662
+ { value: "grid", label: "Grid" },
1663
+ { value: "list", label: "List" },
1664
+ ]}
1665
+ />
1666
+ const [fmt, setFmt] = useState<string[]>(["bold"]);
1667
+
1668
+ <ToggleGroup type="multiple" value={fmt} onChange={setFmt}>
1669
+ <ToggleItem value="bold">B</ToggleItem>
1670
+ <ToggleItem value="italic">I</ToggleItem>
1671
+ <ToggleItem value="underline">U</ToggleItem>
1672
+ </ToggleGroup>
1673
+ ```
1674
+
1675
+ **Common mistakes:**
1676
+ - ❌ `onChange={(e) => set(e.target.value)}` → onChange={(value) => set(value)} — string|null (single) or string[] (multiple)
1677
+ - ❌ `Using ToggleGroup for a single on/off setting` → Use <Switch> for on/off; ToggleGroup is for choosing among options
1678
+ - ❌ `type="multiple" with a string value` → value={['a','b']} and onChange receives string[]
1679
+ - ❌ `<ToggleItem> outside <ToggleGroup>` → Always nest ToggleItem inside ToggleGroup (or use options)
1680
+
1681
+ ---
1682
+
1683
+ ### ToggleItem
1684
+
1685
+ A single toggle button inside <ToggleGroup>. Reads selection state from the group via context.
1686
+
1687
+ ```tsx
1688
+ import { ToggleItem } from "@usevyre/react"
1689
+
1690
+ // Props:
1691
+ // value = string
1692
+ // icon = ReactNode
1693
+ // disabled = boolean (default: false)
1694
+
1695
+ // Examples:
1696
+ <ToggleGroup value={v} onChange={setV}>
1697
+ <ToggleItem value="left">Left</ToggleItem>
1698
+ <ToggleItem value="center">Center</ToggleItem>
1699
+ </ToggleGroup>
1700
+ ```
1701
+
1702
+ **Common mistakes:**
1703
+ - ❌ `Tracking selected state on ToggleItem yourself` → Only set value; the group controls selected state
1704
+
1705
+ ---
1706
+
1707
+ ### Stepper
1708
+
1709
+ Multi-step flow indicator + controller (onboarding/checkout/wizard). CONTROLLED by a 0-based index. Compose StepperNav (with Step indicators) and StepPanel (content shown when its index == active). Step/StepPanel take an explicit 0-based `index`. Not Tabs — Stepper is an ORDERED linear flow with completed/current/upcoming states.
1710
+
1711
+ ```tsx
1712
+ import { Stepper, StepperNav, Step, StepPanel } from "@usevyre/react"
1713
+
1714
+ // Props:
1715
+ // value = number
1716
+ // defaultValue = number (default: 0)
1717
+ // onChange = function
1718
+ // orientation = "horizontal" | "vertical" (default: horizontal)
1719
+ // clickable = boolean (default: false)
1720
+
1721
+ // Examples:
1722
+ const [step, setStep] = useState(0);
1723
+
1724
+ <Stepper value={step} onChange={setStep}>
1725
+ <StepperNav>
1726
+ <Step index={0} label="Account" />
1727
+ <Step index={1} label="Profile" />
1728
+ <Step index={2} label="Done" />
1729
+ </StepperNav>
1730
+ <StepPanel index={0}><AccountForm /></StepPanel>
1731
+ <StepPanel index={1}><ProfileForm /></StepPanel>
1732
+ <StepPanel index={2}><Summary /></StepPanel>
1733
+ <Stack direction="row" gap="sm" justify="between">
1734
+ <Button onClick={() => setStep((s) => s - 1)} disabled={step === 0}>Back</Button>
1735
+ <Button variant="primary" onClick={() => setStep((s) => s + 1)}>Next</Button>
1736
+ </Stack>
1737
+ </Stepper>
1738
+ <Stepper orientation="vertical" defaultValue={1}>
1739
+ <StepperNav>
1740
+ <Step index={0} label="Cart" description="2 items" />
1741
+ <Step index={1} label="Shipping" description="Enter address" />
1742
+ <Step index={2} label="Payment" />
1743
+ </StepperNav>
1744
+ </Stepper>
1745
+ ```
1746
+
1747
+ **Common mistakes:**
1748
+ - ❌ `Using Tabs for a wizard / checkout flow` → Use <Stepper> with StepperNav + Step + StepPanel
1749
+ - ❌ `onChange={(e) => set(e.target.value)}` → onChange={(index) => setStep(index)}
1750
+ - ❌ `Manually toggling which panel is visible` → Give each StepPanel an index; Stepper shows the active one
1751
+ - ❌ `<Step> or <StepPanel> outside <Stepper>` → Nest Step inside StepperNav, StepPanel inside Stepper
1752
+
1753
+ ---
1754
+
1755
+ ### StepperNav
1756
+
1757
+ Container for Step indicators inside <Stepper>. Lays them out per the Stepper's orientation.
1758
+
1759
+ ```tsx
1760
+ import { Stepper, StepperNav, Step, StepPanel } from "@usevyre/react"
1761
+
1762
+ ```
1763
+
1764
+ ---
1765
+
1766
+ ### Step
1767
+
1768
+ One step indicator inside <StepperNav>. State (completed/current/upcoming) derives from the Stepper's active index automatically.
1769
+
1770
+ ```tsx
1771
+ import { Stepper, StepperNav, Step, StepPanel } from "@usevyre/react"
1772
+
1773
+ // Props:
1774
+ // index = number
1775
+ // label = ReactNode
1776
+ // description = ReactNode
1777
+ // icon = ReactNode
1778
+
1779
+ ```
1780
+
1781
+ ---
1782
+
1783
+ ### StepPanel
1784
+
1785
+ Content for one step. Renders its children only when its index equals the Stepper's active step.
1786
+
1787
+ ```tsx
1788
+ import { Stepper, StepperNav, Step, StepPanel } from "@usevyre/react"
1789
+
1790
+ // Props:
1791
+ // index = number
1792
+
1793
+ ```
1794
+
1795
+ ---
1796
+
1797
+ ### EmptyState
1798
+
1799
+ Presentational placeholder for empty lists, tables, and search results. No state. title/description/variant/size are props; the optional call-to-action goes in children (React) or the default slot (Vue). variant picks a preset icon (default=box, search=magnifier, error=warning); pass `icon` (or #icon slot) to override.
1800
+
1801
+ ```tsx
1802
+ import { EmptyState } from "@usevyre/react"
1803
+
1804
+ // Props:
1805
+ // title = string
1806
+ // description = string
1807
+ // variant = "default" | "search" | "error" (default: default)
1808
+ // icon = ReactNode
1809
+ // size = "sm" | "md" | "lg" (default: md)
1810
+ // children = ReactNode
1811
+
1812
+ // Examples:
1813
+ <EmptyState
1814
+ variant="search"
1815
+ title="No results"
1816
+ description="Try a different search term."
1817
+ >
1818
+ <Button variant="secondary" onClick={reset}>Clear filters</Button>
1819
+ </EmptyState>
1820
+ <EmptyState
1821
+ size="lg"
1822
+ title="No projects yet"
1823
+ description="Create your first project to get started."
1824
+ >
1825
+ <Button variant="primary">New project</Button>
1826
+ </EmptyState>
1827
+ ```
1828
+
1829
+ **Common mistakes:**
1830
+ - ❌ `Building an empty placeholder with a bare <div> + centered text` → Use <EmptyState title description variant>
1831
+ - ❌ `action / cta prop` → Put the Button as children of EmptyState
1832
+ - ❌ `Using EmptyState for a loading state` → Use <Skeleton> while loading; EmptyState when the result set is empty
1833
+
1834
+ ---
1835
+
1836
+ ### Stat
1837
+
1838
+ Presentational dashboard KPI. No state. The arrow DIRECTION follows the sign of `delta` (the actual change: -0.4% → down arrow). The arrow/delta COLOR is set explicitly by `trend` (up=success, down=danger, neutral=muted) — so 'churn -0.4%, trend=up' shows a green DOWN arrow. Wrap several in StatGroup for an evenly-split row with dividers.
1839
+
1840
+ ```tsx
1841
+ import { Stat, StatGroup } from "@usevyre/react"
1842
+
1843
+ // Props:
1844
+ // label = string
1845
+ // value = string | number
1846
+ // delta = string | number
1847
+ // trend = "up" | "down" | "neutral" (default: neutral)
1848
+ // deltaLabel = string
1849
+ // icon = ReactNode
1850
+ // size = "sm" | "md" | "lg" (default: md)
1851
+
1852
+ // Examples:
1853
+ <StatGroup>
1854
+ <Stat label="Revenue" value="$48.2k" delta="+12%" trend="up" deltaLabel="vs last month" />
1855
+ <Stat label="Churn" value="2.1%" delta="-0.4%" trend="up" deltaLabel="lower is better" />
1856
+ <Stat label="Orders" value="1,204" delta="0%" trend="neutral" />
1857
+ </StatGroup>
1858
+ <Stat label="Active users" value="12,840" delta="+3.2%" trend="up"
1859
+ icon={<UsersIcon />} size="lg" />
1860
+ ```
1861
+
1862
+ **Common mistakes:**
1863
+ - ❌ `Assuming trend flips the arrow direction` → delta="-0.4%" always shows a down arrow; trend="up" just colors it green
1864
+ - ❌ `Building a KPI card with Card + manual layout` → Use <Stat label value delta trend />
1865
+ - ❌ `Laying out a KPI row with custom flex + dividers` → Wrap the Stats in <StatGroup>
1866
+
1867
+ ---
1868
+
1869
+ ### StatGroup
1870
+
1871
+ Evenly-split row of <Stat> with subtle dividers between items. Each Stat flexes to equal width.
1872
+
1873
+ ```tsx
1874
+ import { Stat, StatGroup } from "@usevyre/react"
1875
+
1876
+ // Examples:
1877
+ <StatGroup>
1878
+ <Stat label="MRR" value="$9.6k" delta="+5%" trend="up" />
1879
+ <Stat label="Refunds" value="32" delta="+8" trend="down" />
1880
+ </StatGroup>
1881
+ ```
1882
+
1883
+ **Common mistakes:**
1884
+ - ❌ `Putting non-Stat children in StatGroup` → Only place <Stat> elements inside StatGroup
1885
+
1886
+ ---
1887
+
1888
+ ### Timeline
1889
+
1890
+ Vertical activity feed for audit logs and history. Presentational — a status dot per item plus a connector line. Pass `items` for plain logs, or TimelineItem children for rich per-item content. Timeline does NOT reorder; pass items in the order you want shown.
1891
+
1892
+ ```tsx
1893
+ import { Timeline, TimelineItem } from "@usevyre/react"
1894
+
1895
+ // Props:
1896
+ // items = array
1897
+ // children = ReactNode
1898
+
1899
+ // Examples:
1900
+ <Timeline
1901
+ items={[
1902
+ { title: "Deployed v2.1", time: "2m ago", status: "success" },
1903
+ { title: "Build started", time: "5m ago", status: "info" },
1904
+ { title: "Push to main", time: "6m ago" },
1905
+ ]}
1906
+ />
1907
+ <Timeline>
1908
+ <TimelineItem title="Invoice paid" time="Apr 2" status="success">
1909
+ <Text size="sm">$1,200 — <a href="#">view receipt</a></Text>
1910
+ </TimelineItem>
1911
+ <TimelineItem title="Invoice sent" time="Mar 28" status="info" />
1912
+ </Timeline>
1913
+ ```
1914
+
1915
+ **Common mistakes:**
1916
+ - ❌ `Building an activity log with a <ul> + manual dots/lines` → Use <Timeline items={[...]} /> or TimelineItem children
1917
+ - ❌ `Using Stepper for a history/audit feed` → Use <Timeline> for logs/history; Stepper for wizards
1918
+ - ❌ `Expecting Timeline to sort by time` → Sort the array yourself (newest- or oldest-first)
1919
+
1920
+ ---
1921
+
1922
+ ### TimelineItem
1923
+
1924
+ One entry in a <Timeline>. Renders a status-colored dot (or a custom icon), a title, an optional time, and optional rich content.
1925
+
1926
+ ```tsx
1927
+ import { Timeline, TimelineItem } from "@usevyre/react"
1928
+
1929
+ // Props:
1930
+ // title = ReactNode
1931
+ // time = ReactNode
1932
+ // status = "default" | "success" | "warning" | "danger" | "info" (default: default)
1933
+ // icon = ReactNode
1934
+ // children = ReactNode
1935
+
1936
+ // Examples:
1937
+ <TimelineItem title="Comment added" time="1h ago" status="default">
1938
+ <Text size="sm">“Looks good to me 👍”</Text>
1939
+ </TimelineItem>
1940
+ ```
1941
+
1942
+ **Common mistakes:**
1943
+ - ❌ `<TimelineItem> outside <Timeline>` → Always nest TimelineItem inside Timeline
1944
+
1945
+ ---
1946
+
1947
+ ### Tree
1948
+
1949
+ Hierarchical tree view for file explorers and nested navigation. DATA-DRIVEN and CONTROLLED — pass a nested `data` array; the Tree renders recursively. Single selection. A node WITH children is a folder (click toggles expand); a leaf fires onSelect. Keyboard: ArrowUp/Down move, ArrowRight/Left expand/collapse, Enter/Space select.
1950
+
1951
+ ```tsx
1952
+ import { Tree } from "@usevyre/react"
1953
+
1954
+ // Props:
1955
+ // data = TreeNode[]
1956
+ // expandedIds = string[]
1957
+ // defaultExpandedIds = string[] (default: [])
1958
+ // onExpandedChange = function
1959
+ // selectedId = string | null
1960
+ // defaultSelectedId = string | null (default: null)
1961
+ // onSelect = function
1962
+
1963
+ // Examples:
1964
+ const [sel, setSel] = useState<string | null>("src/a.ts");
1965
+
1966
+ <Tree
1967
+ data={[
1968
+ { id: "src", label: "src", children: [
1969
+ { id: "src/a.ts", label: "a.ts" },
1970
+ { id: "src/b", label: "b", children: [
1971
+ { id: "src/b/c.ts", label: "c.ts" },
1972
+ ]},
1973
+ ]},
1974
+ { id: "README.md", label: "README.md" },
1975
+ ]}
1976
+ selectedId={sel}
1977
+ onSelect={setSel}
1978
+ defaultExpandedIds={["src"]}
1979
+ />
1980
+ const [open, setOpen] = useState<string[]>(["root"]);
1981
+
1982
+ <Tree data={tree} expandedIds={open} onExpandedChange={setOpen} />
1983
+ ```
1984
+
1985
+ **Common mistakes:**
1986
+ - ❌ `Rendering a nested <ul> tree by hand with manual expand state` → Pass a nested `data` array to <Tree> and control expandedIds/selectedId
1987
+ - ❌ `onSelect={(e) => ...}` → onSelect={(id) => setSelected(id)}
1988
+ - ❌ `Mutating the data array to expand/collapse` → Track expandedIds in state (or use defaultExpandedIds)
1989
+ - ❌ `Using DropdownMenu submenus for a file tree` → Use <Tree> for file explorers / nested nav
1990
+
1991
+ ---
1992
+
1993
+ ### OTPInput
1994
+
1995
+ Segmented one-time-code input for verification / 2FA. CONTROLLED. onChange emits the STRING value (not an event), and onComplete fires once when every slot is filled. Paste-aware (pasting a full code fills all slots), auto-advance on input, backspace moves to the previous slot, arrow keys navigate. Drops straight into <FormField>.
1996
+
1997
+ ```tsx
1998
+ import { OTPInput } from "@usevyre/react"
1999
+
2000
+ // Props:
2001
+ // value = string
2002
+ // defaultValue = string (default: "")
2003
+ // onChange = function
2004
+ // onComplete = function
2005
+ // length = number (default: 6)
2006
+ // type = "numeric" | "alphanumeric" (default: numeric)
2007
+ // mask = boolean (default: false)
2008
+ // size = "sm" | "md" | "lg" (default: md)
2009
+ // disabled = boolean (default: false)
2010
+ // autoFocus = boolean (default: false)
2011
+
2012
+ // Examples:
2013
+ const [code, setCode] = useState("");
2014
+
2015
+ <OTPInput
2016
+ value={code}
2017
+ onChange={setCode}
2018
+ onComplete={(c) => verify(c)}
2019
+ autoFocus
2020
+ />
2021
+ <FormField name="otp" label="Verification code"
2022
+ rules={{ required: true, minLength: 6 }}>
2023
+ <OTPInput length={6} />
2024
+ </FormField>
2025
+ ```
2026
+
2027
+ **Common mistakes:**
2028
+ - ❌ `onChange={(e) => set(e.target.value)}` → onChange={(value) => setCode(value)}
2029
+ - ❌ `Six separate <Input> boxes wired by hand` → Use <OTPInput length={6} value onChange />
2030
+ - ❌ `Reading completion by comparing length yourself` → Use onComplete={(code) => verify(code)}
2031
+ - ❌ `type="password" to hide digits` → Use mask (type stays numeric/alphanumeric)
2032
+
2033
+ ---
2034
+
2035
+ ### Carousel
2036
+
2037
+ Accessible content slider for galleries, onboarding, and testimonials. CONTROLLED by a 0-based slide index. Compose CarouselSlide children (slide order = index). Snap scrolling, clickable dot indicators, prev/next arrows, ArrowLeft/Right keyboard, optional loop and autoPlay (autoplay pauses on hover/focus). onChange emits the index (not an event).
2038
+
2039
+ ```tsx
2040
+ import { Carousel, CarouselSlide } from "@usevyre/react"
2041
+
2042
+ // Props:
2043
+ // value = number
2044
+ // defaultValue = number (default: 0)
2045
+ // onChange = function
2046
+ // loop = boolean (default: false)
2047
+ // autoPlay = boolean (default: false)
2048
+ // interval = number (default: 5000)
2049
+ // showArrows = boolean (default: true)
2050
+ // showIndicators = boolean (default: true)
2051
+
2052
+ // Examples:
2053
+ const [i, setI] = useState(0);
2054
+
2055
+ <Carousel value={i} onChange={setI} loop>
2056
+ <CarouselSlide><img src="/a.jpg" alt="A" /></CarouselSlide>
2057
+ <CarouselSlide><img src="/b.jpg" alt="B" /></CarouselSlide>
2058
+ <CarouselSlide><img src="/c.jpg" alt="C" /></CarouselSlide>
2059
+ </Carousel>
2060
+ <Carousel autoPlay interval={4000} showArrows={false}>
2061
+ <CarouselSlide><Welcome /></CarouselSlide>
2062
+ <CarouselSlide><Features /></CarouselSlide>
2063
+ <CarouselSlide><GetStarted /></CarouselSlide>
2064
+ </Carousel>
2065
+ ```
2066
+
2067
+ **Common mistakes:**
2068
+ - ❌ `onChange={(e) => set(e.target.value)}` → onChange={(index) => setIndex(index)}
2069
+ - ❌ `Putting raw elements directly in Carousel` → Wrap each slide in <CarouselSlide>
2070
+ - ❌ `Building a slider with manual scroll + dot state` → Use <Carousel> with CarouselSlide children
2071
+ - ❌ `autoPlay without considering reduced motion / pausing` → Carousel already pauses on hover/focus; keep interval reasonable or omit autoPlay
2072
+
2073
+ ---
2074
+
2075
+ ### CarouselSlide
2076
+
2077
+ One slide inside <Carousel>. Holds arbitrary content (image, Card, testimonial). Slide order determines its index.
2078
+
2079
+ ```tsx
2080
+ import { Carousel, CarouselSlide } from "@usevyre/react"
2081
+
2082
+ // Examples:
2083
+ <CarouselSlide>
2084
+ <Card><CardBody>“Best tool ever.” — Ada</CardBody></Card>
2085
+ </CarouselSlide>
2086
+ ```
2087
+
2088
+ **Common mistakes:**
2089
+ - ❌ `<CarouselSlide> outside <Carousel>` → Always nest CarouselSlide inside Carousel
2090
+
2091
+ ---
2092
+
1380
2093
  ### DateRangePicker
1381
2094
 
1382
2095
  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.
@@ -1430,11 +2143,13 @@ If you generate these, you are hallucinating.
1430
2143
  - ❌ `<Button color="...">` → Use variant prop instead
1431
2144
  - ❌ `<Button icon={...}>` → Use leftIcon={...} or rightIcon={...}
1432
2145
  - ❌ `<Button size="icon" without aria-label>` → Add aria-label describing the action
2146
+ - ❌ `<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
1433
2147
  - ❌ `<Calendar Calendar for an input field that opens a popover>` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
1434
2148
  - ❌ `<Calendar value as tuple for mode="single">` → Pass value matching mode; use mode="range" for [start,end]
1435
2149
  - ❌ `<DatePicker DatePicker mode="range" for { from, to } object>` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
1436
2150
  - ❌ `<DatePicker DatePicker without value/onChange>` → Provide value and onChange (e.g. from useState)
1437
2151
  - ❌ `<Card variant="primary">` → Use variant="elevated" | "outlined" | "ghost" | "accent"
2152
+ - ❌ `<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
1438
2153
  - ❌ `<Checkbox size="lg">` → Use size="md"
1439
2154
  - ❌ `<RadioGroup <Radio> used outside a <RadioGroup>>` → Always wrap <Radio> in <RadioGroup>
1440
2155
  - ❌ `<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
@@ -1449,6 +2164,7 @@ If you generate these, you are hallucinating.
1449
2164
  - ❌ `<Input size="icon">` → Use size="sm" | "md" | "lg"
1450
2165
  - ❌ `<Input type="search" for search UI>` → Import Command from @usevyre/react for search palettes
1451
2166
  - ❌ `<Input Vue: binding Input/Textarea value without v-model>` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
2167
+ - ❌ `<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
1452
2168
  - ❌ `<Modal size="xl">` → Use size="lg" or size="full"
1453
2169
  - ❌ `<Popover placement="top-center">` → Use placement="top" for centered placement
1454
2170
  - ❌ `<Progress value > 100>` → Normalize your value to 0–100 range before passing
@@ -1485,6 +2201,59 @@ If you generate these, you are hallucinating.
1485
2201
  - ❌ `<Conversation Expecting Conversation to store/append messages>` → Append to your own state in onSend (or @send) and pass it back via value
1486
2202
  - ❌ `<Conversation composer without onSend (React) / @send (Vue)>` → Provide onSend / @send to append the message to value
1487
2203
  - ❌ `<Conversation Treating onSend as (text) only when using allowAttachments>` → Handle onSend(text, files) — map files to message attachments and append
2204
+ - ❌ `<Stack <div style={{ display: 'flex', gap: 12 }}>>` → Use <Stack gap="md"> — gap is a token
2205
+ - ❌ `<Stack gap={12} or gap="12px">` → Use gap="none|xs|sm|md|lg|xl|2xl"
2206
+ - ❌ `<Stack direction="vertical" / "horizontal">` → Use direction="row" or "column" (also row-reverse / column-reverse)
2207
+ - ❌ `<Stack style={{ width: "100%" }} / style={{ height: 320 }}>` → Use the width / height prop: width="full", width="md", height="screen", etc.
2208
+ - ❌ `<Grid <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>>` → Use <Grid columns={3} gap="md">
2209
+ - ❌ `<Grid columns="3" (string)>` → Use columns={3} or columns="auto-fit"
2210
+ - ❌ `<Grid Nested div with inline grid-column for spanning>` → Wrap the cell in <GridItem colSpan={2}>
2211
+ - ❌ `<Grid style={{ width: "100%" }} / style={{ height: 320 }}>` → Use the width / height prop: width="full", width="md", height="screen", etc.
2212
+ - ❌ `<GridItem GridItem outside a Grid>` → Place <GridItem> directly inside <Grid>
2213
+ - ❌ `<Box <Box style={{ padding: 16 }}>>` → Use <Box padding="md"> (or paddingX/paddingTop/...)
2214
+ - ❌ `<Box Using Box for flex/grid layout>` → Use <Stack> or <Grid>
2215
+ - ❌ `<Box style={{ width: "100%" }} / style={{ height: 320 }}>` → Use the width / height prop: width="full", width="md", height="screen", etc.
2216
+ - ❌ `<Form Manually tracking each field's error state with useState>` → Wrap controls in <FormField name rules> and let Form manage errors
2217
+ - ❌ `<Form Adding a validation library (zod/yup) just for basic rules>` → Use rules={{ required, minLength, pattern, email, validate }}
2218
+ - ❌ `<Form <FormField> with multiple control children>` → Use one control per FormField (Input/Textarea/Select/etc.)
2219
+ - ❌ `<Form <FormField> outside a <Form>>` → Always nest FormField inside <Form>
2220
+ - ❌ `<FormField Putting onChange/value manually on the control inside FormField>` → Let FormField wire the control; only pass static props (type, placeholder)
2221
+ - ❌ `<NumberInput onChange={(e) => set(e.target.value)}>` → onChange={(value) => set(value)} — value is number | null
2222
+ - ❌ `<NumberInput Using <Input type="number"> for numeric fields>` → Use <NumberInput value onChange min max step />
2223
+ - ❌ `<NumberInput Parsing the value with Number() in form state>` → Store the value directly; it is already number | null
2224
+ - ❌ `<ToggleGroup onChange={(e) => set(e.target.value)}>` → onChange={(value) => set(value)} — string|null (single) or string[] (multiple)
2225
+ - ❌ `<ToggleGroup Using ToggleGroup for a single on/off setting>` → Use <Switch> for on/off; ToggleGroup is for choosing among options
2226
+ - ❌ `<ToggleGroup type="multiple" with a string value>` → value={['a','b']} and onChange receives string[]
2227
+ - ❌ `<ToggleGroup <ToggleItem> outside <ToggleGroup>>` → Always nest ToggleItem inside ToggleGroup (or use options)
2228
+ - ❌ `<ToggleItem Tracking selected state on ToggleItem yourself>` → Only set value; the group controls selected state
2229
+ - ❌ `<Stepper Using Tabs for a wizard / checkout flow>` → Use <Stepper> with StepperNav + Step + StepPanel
2230
+ - ❌ `<Stepper onChange={(e) => set(e.target.value)}>` → onChange={(index) => setStep(index)}
2231
+ - ❌ `<Stepper Manually toggling which panel is visible>` → Give each StepPanel an index; Stepper shows the active one
2232
+ - ❌ `<Stepper <Step> or <StepPanel> outside <Stepper>>` → Nest Step inside StepperNav, StepPanel inside Stepper
2233
+ - ❌ `<EmptyState Building an empty placeholder with a bare <div> + centered text>` → Use <EmptyState title description variant>
2234
+ - ❌ `<EmptyState action / cta prop>` → Put the Button as children of EmptyState
2235
+ - ❌ `<EmptyState Using EmptyState for a loading state>` → Use <Skeleton> while loading; EmptyState when the result set is empty
2236
+ - ❌ `<Stat Assuming trend flips the arrow direction>` → delta="-0.4%" always shows a down arrow; trend="up" just colors it green
2237
+ - ❌ `<Stat Building a KPI card with Card + manual layout>` → Use <Stat label value delta trend />
2238
+ - ❌ `<Stat Laying out a KPI row with custom flex + dividers>` → Wrap the Stats in <StatGroup>
2239
+ - ❌ `<StatGroup Putting non-Stat children in StatGroup>` → Only place <Stat> elements inside StatGroup
2240
+ - ❌ `<Timeline Building an activity log with a <ul> + manual dots/lines>` → Use <Timeline items={[...]} /> or TimelineItem children
2241
+ - ❌ `<Timeline Using Stepper for a history/audit feed>` → Use <Timeline> for logs/history; Stepper for wizards
2242
+ - ❌ `<Timeline Expecting Timeline to sort by time>` → Sort the array yourself (newest- or oldest-first)
2243
+ - ❌ `<TimelineItem <TimelineItem> outside <Timeline>>` → Always nest TimelineItem inside Timeline
2244
+ - ❌ `<Tree Rendering a nested <ul> tree by hand with manual expand state>` → Pass a nested `data` array to <Tree> and control expandedIds/selectedId
2245
+ - ❌ `<Tree onSelect={(e) => ...}>` → onSelect={(id) => setSelected(id)}
2246
+ - ❌ `<Tree Mutating the data array to expand/collapse>` → Track expandedIds in state (or use defaultExpandedIds)
2247
+ - ❌ `<Tree Using DropdownMenu submenus for a file tree>` → Use <Tree> for file explorers / nested nav
2248
+ - ❌ `<OTPInput onChange={(e) => set(e.target.value)}>` → onChange={(value) => setCode(value)}
2249
+ - ❌ `<OTPInput Six separate <Input> boxes wired by hand>` → Use <OTPInput length={6} value onChange />
2250
+ - ❌ `<OTPInput Reading completion by comparing length yourself>` → Use onComplete={(code) => verify(code)}
2251
+ - ❌ `<OTPInput type="password" to hide digits>` → Use mask (type stays numeric/alphanumeric)
2252
+ - ❌ `<Carousel onChange={(e) => set(e.target.value)}>` → onChange={(index) => setIndex(index)}
2253
+ - ❌ `<Carousel Putting raw elements directly in Carousel>` → Wrap each slide in <CarouselSlide>
2254
+ - ❌ `<Carousel Building a slider with manual scroll + dot state>` → Use <Carousel> with CarouselSlide children
2255
+ - ❌ `<Carousel autoPlay without considering reduced motion / pausing>` → Carousel already pauses on hover/focus; keep interval reasonable or omit autoPlay
2256
+ - ❌ `<CarouselSlide <CarouselSlide> outside <Carousel>>` → Always nest CarouselSlide inside Carousel
1488
2257
  - ❌ `<DateRangePicker value={[from, to]}>` → Use value={{ from, to }} and read range.from / range.to
1489
2258
  - ❌ `<DateRangePicker DateRangePicker for a single date>` → Use <DatePicker /> for a single date
1490
2259
  - ❌ `<DateRangePicker presets="true" (string)>` → Use the bare prop: presets (or presets={true})