@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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.0",
2
+ "version": "1.16.0",
3
3
  "rules": [
4
4
  {
5
5
  "component": "Accordion",
@@ -120,6 +120,13 @@
120
120
  "fix": "Add aria-label describing the action",
121
121
  "severity": "error"
122
122
  },
123
+ {
124
+ "component": "Button",
125
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
126
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
127
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
128
+ "severity": "error"
129
+ },
123
130
  {
124
131
  "component": "Calendar",
125
132
  "pattern": "Calendar for an input field that opens a popover",
@@ -155,6 +162,13 @@
155
162
  "fix": "Use variant=\"elevated\" | \"outlined\" | \"ghost\" | \"accent\"",
156
163
  "severity": "error"
157
164
  },
165
+ {
166
+ "component": "Card",
167
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
168
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
169
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
170
+ "severity": "error"
171
+ },
158
172
  {
159
173
  "component": "Checkbox",
160
174
  "pattern": "size=\"lg\"",
@@ -253,6 +267,13 @@
253
267
  "fix": "Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange",
254
268
  "severity": "error"
255
269
  },
270
+ {
271
+ "component": "Input",
272
+ "pattern": "padding / margin / marginTop (any spacing prop) on a useVyre component",
273
+ "reason": "Components have NO spacing props by design — internal spacing is fixed by tokens for visual consistency",
274
+ "fix": "Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it",
275
+ "severity": "error"
276
+ },
256
277
  {
257
278
  "component": "Modal",
258
279
  "pattern": "size=\"xl\"",
@@ -505,6 +526,377 @@
505
526
  "fix": "Handle onSend(text, files) — map files to message attachments and append",
506
527
  "severity": "error"
507
528
  },
529
+ {
530
+ "component": "Stack",
531
+ "pattern": "<div style={{ display: 'flex', gap: 12 }}>",
532
+ "reason": "Inline flex styles bypass the design system and use magic-number spacing",
533
+ "fix": "Use <Stack gap=\"md\"> — gap is a token",
534
+ "severity": "error"
535
+ },
536
+ {
537
+ "component": "Stack",
538
+ "pattern": "gap={12} or gap=\"12px\"",
539
+ "reason": "Stack gap is a closed token enum",
540
+ "fix": "Use gap=\"none|xs|sm|md|lg|xl|2xl\"",
541
+ "severity": "error"
542
+ },
543
+ {
544
+ "component": "Stack",
545
+ "pattern": "direction=\"vertical\" / \"horizontal\"",
546
+ "reason": "Stack mirrors CSS flex-direction names",
547
+ "fix": "Use direction=\"row\" or \"column\" (also row-reverse / column-reverse)",
548
+ "severity": "error"
549
+ },
550
+ {
551
+ "component": "Stack",
552
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
553
+ "reason": "Inline width/height bypass the design system and use magic numbers",
554
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
555
+ "severity": "error"
556
+ },
557
+ {
558
+ "component": "Grid",
559
+ "pattern": "<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>",
560
+ "reason": "Inline grid styles bypass the design system",
561
+ "fix": "Use <Grid columns={3} gap=\"md\">",
562
+ "severity": "error"
563
+ },
564
+ {
565
+ "component": "Grid",
566
+ "pattern": "columns=\"3\" (string)",
567
+ "reason": "columns is a number or the literal 'auto-fit'",
568
+ "fix": "Use columns={3} or columns=\"auto-fit\"",
569
+ "severity": "error"
570
+ },
571
+ {
572
+ "component": "Grid",
573
+ "pattern": "Nested div with inline grid-column for spanning",
574
+ "reason": "Spanning has a dedicated primitive",
575
+ "fix": "Wrap the cell in <GridItem colSpan={2}>",
576
+ "severity": "error"
577
+ },
578
+ {
579
+ "component": "Grid",
580
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
581
+ "reason": "Inline width/height bypass the design system and use magic numbers",
582
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
583
+ "severity": "error"
584
+ },
585
+ {
586
+ "component": "GridItem",
587
+ "pattern": "GridItem outside a Grid",
588
+ "reason": "GridItem only has effect as a direct child of Grid",
589
+ "fix": "Place <GridItem> directly inside <Grid>",
590
+ "severity": "error"
591
+ },
592
+ {
593
+ "component": "Box",
594
+ "pattern": "<Box style={{ padding: 16 }}>",
595
+ "reason": "padding is a token prop; style is a last resort",
596
+ "fix": "Use <Box padding=\"md\"> (or paddingX/paddingTop/...)",
597
+ "severity": "error"
598
+ },
599
+ {
600
+ "component": "Box",
601
+ "pattern": "Using Box for flex/grid layout",
602
+ "reason": "Box is spacing-only and has no layout props",
603
+ "fix": "Use <Stack> or <Grid>",
604
+ "severity": "error"
605
+ },
606
+ {
607
+ "component": "Box",
608
+ "pattern": "style={{ width: \"100%\" }} / style={{ height: 320 }}",
609
+ "reason": "Inline width/height bypass the design system and use magic numbers",
610
+ "fix": "Use the width / height prop: width=\"full\", width=\"md\", height=\"screen\", etc.",
611
+ "severity": "error"
612
+ },
613
+ {
614
+ "component": "Form",
615
+ "pattern": "Manually tracking each field's error state with useState",
616
+ "reason": "Form already validates and maps errors into Field automatically",
617
+ "fix": "Wrap controls in <FormField name rules> and let Form manage errors",
618
+ "severity": "error"
619
+ },
620
+ {
621
+ "component": "Form",
622
+ "pattern": "Adding a validation library (zod/yup) just for basic rules",
623
+ "reason": "Form ships zero-dependency built-in rules",
624
+ "fix": "Use rules={{ required, minLength, pattern, email, validate }}",
625
+ "severity": "error"
626
+ },
627
+ {
628
+ "component": "Form",
629
+ "pattern": "<FormField> with multiple control children",
630
+ "reason": "FormField clones a single child to inject name/value/onChange",
631
+ "fix": "Use one control per FormField (Input/Textarea/Select/etc.)",
632
+ "severity": "error"
633
+ },
634
+ {
635
+ "component": "Form",
636
+ "pattern": "<FormField> outside a <Form>",
637
+ "reason": "FormField reads form context",
638
+ "fix": "Always nest FormField inside <Form>",
639
+ "severity": "error"
640
+ },
641
+ {
642
+ "component": "FormField",
643
+ "pattern": "Putting onChange/value manually on the control inside FormField",
644
+ "reason": "FormField already injects them; manual props can desync from form state",
645
+ "fix": "Let FormField wire the control; only pass static props (type, placeholder)",
646
+ "severity": "error"
647
+ },
648
+ {
649
+ "component": "NumberInput",
650
+ "pattern": "onChange={(e) => set(e.target.value)}",
651
+ "reason": "NumberInput emits a number, not an event — there is no e.target",
652
+ "fix": "onChange={(value) => set(value)} — value is number | null",
653
+ "severity": "error"
654
+ },
655
+ {
656
+ "component": "NumberInput",
657
+ "pattern": "Using <Input type=\"number\"> for numeric fields",
658
+ "reason": "Native number input has no token-styled stepper, no clamp, returns a string",
659
+ "fix": "Use <NumberInput value onChange min max step />",
660
+ "severity": "error"
661
+ },
662
+ {
663
+ "component": "NumberInput",
664
+ "pattern": "Parsing the value with Number() in form state",
665
+ "reason": "NumberInput already emits a real number (or null)",
666
+ "fix": "Store the value directly; it is already number | null",
667
+ "severity": "error"
668
+ },
669
+ {
670
+ "component": "ToggleGroup",
671
+ "pattern": "onChange={(e) => set(e.target.value)}",
672
+ "reason": "ToggleGroup emits the value, not an event",
673
+ "fix": "onChange={(value) => set(value)} — string|null (single) or string[] (multiple)",
674
+ "severity": "error"
675
+ },
676
+ {
677
+ "component": "ToggleGroup",
678
+ "pattern": "Using ToggleGroup for a single on/off setting",
679
+ "reason": "That is a boolean toggle",
680
+ "fix": "Use <Switch> for on/off; ToggleGroup is for choosing among options",
681
+ "severity": "error"
682
+ },
683
+ {
684
+ "component": "ToggleGroup",
685
+ "pattern": "type=\"multiple\" with a string value",
686
+ "reason": "multiple mode requires an array value",
687
+ "fix": "value={['a','b']} and onChange receives string[]",
688
+ "severity": "error"
689
+ },
690
+ {
691
+ "component": "ToggleGroup",
692
+ "pattern": "<ToggleItem> outside <ToggleGroup>",
693
+ "reason": "ToggleItem reads group context",
694
+ "fix": "Always nest ToggleItem inside ToggleGroup (or use options)",
695
+ "severity": "error"
696
+ },
697
+ {
698
+ "component": "ToggleItem",
699
+ "pattern": "Tracking selected state on ToggleItem yourself",
700
+ "reason": "Selection is owned by ToggleGroup",
701
+ "fix": "Only set value; the group controls selected state",
702
+ "severity": "error"
703
+ },
704
+ {
705
+ "component": "Stepper",
706
+ "pattern": "Using Tabs for a wizard / checkout flow",
707
+ "reason": "Tabs are peer panels; a step flow is ordered with completed/current/upcoming state",
708
+ "fix": "Use <Stepper> with StepperNav + Step + StepPanel",
709
+ "severity": "error"
710
+ },
711
+ {
712
+ "component": "Stepper",
713
+ "pattern": "onChange={(e) => set(e.target.value)}",
714
+ "reason": "Stepper emits the index number, not an event",
715
+ "fix": "onChange={(index) => setStep(index)}",
716
+ "severity": "error"
717
+ },
718
+ {
719
+ "component": "Stepper",
720
+ "pattern": "Manually toggling which panel is visible",
721
+ "reason": "StepPanel renders itself only when its index === active",
722
+ "fix": "Give each StepPanel an index; Stepper shows the active one",
723
+ "severity": "error"
724
+ },
725
+ {
726
+ "component": "Stepper",
727
+ "pattern": "<Step> or <StepPanel> outside <Stepper>",
728
+ "reason": "They read Stepper context",
729
+ "fix": "Nest Step inside StepperNav, StepPanel inside Stepper",
730
+ "severity": "error"
731
+ },
732
+ {
733
+ "component": "EmptyState",
734
+ "pattern": "Building an empty placeholder with a bare <div> + centered text",
735
+ "reason": "Inconsistent spacing/typography; AI reinvents it each time",
736
+ "fix": "Use <EmptyState title description variant>",
737
+ "severity": "error"
738
+ },
739
+ {
740
+ "component": "EmptyState",
741
+ "pattern": "action / cta prop",
742
+ "reason": "There is no action prop; the CTA is composed",
743
+ "fix": "Put the Button as children of EmptyState",
744
+ "severity": "error"
745
+ },
746
+ {
747
+ "component": "EmptyState",
748
+ "pattern": "Using EmptyState for a loading state",
749
+ "reason": "EmptyState is for no-data, not in-progress",
750
+ "fix": "Use <Skeleton> while loading; EmptyState when the result set is empty",
751
+ "severity": "error"
752
+ },
753
+ {
754
+ "component": "Stat",
755
+ "pattern": "Assuming trend flips the arrow direction",
756
+ "reason": "Arrow direction comes from the delta sign; trend only sets color",
757
+ "fix": "delta=\"-0.4%\" always shows a down arrow; trend=\"up\" just colors it green",
758
+ "severity": "error"
759
+ },
760
+ {
761
+ "component": "Stat",
762
+ "pattern": "Building a KPI card with Card + manual layout",
763
+ "reason": "Inconsistent value/label/delta styling; AI reinvents it",
764
+ "fix": "Use <Stat label value delta trend />",
765
+ "severity": "error"
766
+ },
767
+ {
768
+ "component": "Stat",
769
+ "pattern": "Laying out a KPI row with custom flex + dividers",
770
+ "reason": "StatGroup already splits evenly with dividers",
771
+ "fix": "Wrap the Stats in <StatGroup>",
772
+ "severity": "error"
773
+ },
774
+ {
775
+ "component": "StatGroup",
776
+ "pattern": "Putting non-Stat children in StatGroup",
777
+ "reason": "Dividers/equal-split styling target .vyre-stat",
778
+ "fix": "Only place <Stat> elements inside StatGroup",
779
+ "severity": "error"
780
+ },
781
+ {
782
+ "component": "Timeline",
783
+ "pattern": "Building an activity log with a <ul> + manual dots/lines",
784
+ "reason": "Inconsistent markers/spacing; AI reinvents it each time",
785
+ "fix": "Use <Timeline items={[...]} /> or TimelineItem children",
786
+ "severity": "error"
787
+ },
788
+ {
789
+ "component": "Timeline",
790
+ "pattern": "Using Stepper for a history/audit feed",
791
+ "reason": "Stepper is an ordered flow with completed/current/upcoming; a feed is just past events",
792
+ "fix": "Use <Timeline> for logs/history; Stepper for wizards",
793
+ "severity": "error"
794
+ },
795
+ {
796
+ "component": "Timeline",
797
+ "pattern": "Expecting Timeline to sort by time",
798
+ "reason": "Timeline renders items in given order",
799
+ "fix": "Sort the array yourself (newest- or oldest-first)",
800
+ "severity": "error"
801
+ },
802
+ {
803
+ "component": "TimelineItem",
804
+ "pattern": "<TimelineItem> outside <Timeline>",
805
+ "reason": "Marker/connector layout assumes the Timeline list context",
806
+ "fix": "Always nest TimelineItem inside Timeline",
807
+ "severity": "error"
808
+ },
809
+ {
810
+ "component": "Tree",
811
+ "pattern": "Rendering a nested <ul> tree by hand with manual expand state",
812
+ "reason": "Reinvents recursion, keyboard nav, and a11y roles every time",
813
+ "fix": "Pass a nested `data` array to <Tree> and control expandedIds/selectedId",
814
+ "severity": "error"
815
+ },
816
+ {
817
+ "component": "Tree",
818
+ "pattern": "onSelect={(e) => ...}",
819
+ "reason": "Tree emits the node id, not an event",
820
+ "fix": "onSelect={(id) => setSelected(id)}",
821
+ "severity": "error"
822
+ },
823
+ {
824
+ "component": "Tree",
825
+ "pattern": "Mutating the data array to expand/collapse",
826
+ "reason": "Expansion is controlled via expandedIds, not the data",
827
+ "fix": "Track expandedIds in state (or use defaultExpandedIds)",
828
+ "severity": "error"
829
+ },
830
+ {
831
+ "component": "Tree",
832
+ "pattern": "Using DropdownMenu submenus for a file tree",
833
+ "reason": "Submenus are transient menus; a tree is persistent hierarchical content",
834
+ "fix": "Use <Tree> for file explorers / nested nav",
835
+ "severity": "error"
836
+ },
837
+ {
838
+ "component": "OTPInput",
839
+ "pattern": "onChange={(e) => set(e.target.value)}",
840
+ "reason": "OTPInput emits the code string, not an event — there is no e.target",
841
+ "fix": "onChange={(value) => setCode(value)}",
842
+ "severity": "error"
843
+ },
844
+ {
845
+ "component": "OTPInput",
846
+ "pattern": "Six separate <Input> boxes wired by hand",
847
+ "reason": "Reinvents paste, auto-advance, backspace and focus management",
848
+ "fix": "Use <OTPInput length={6} value onChange />",
849
+ "severity": "error"
850
+ },
851
+ {
852
+ "component": "OTPInput",
853
+ "pattern": "Reading completion by comparing length yourself",
854
+ "reason": "onComplete already fires when the code is full",
855
+ "fix": "Use onComplete={(code) => verify(code)}",
856
+ "severity": "error"
857
+ },
858
+ {
859
+ "component": "OTPInput",
860
+ "pattern": "type=\"password\" to hide digits",
861
+ "reason": "There is no type=password; masking is a dedicated prop",
862
+ "fix": "Use mask (type stays numeric/alphanumeric)",
863
+ "severity": "error"
864
+ },
865
+ {
866
+ "component": "Carousel",
867
+ "pattern": "onChange={(e) => set(e.target.value)}",
868
+ "reason": "Carousel emits the slide index number, not an event",
869
+ "fix": "onChange={(index) => setIndex(index)}",
870
+ "severity": "error"
871
+ },
872
+ {
873
+ "component": "Carousel",
874
+ "pattern": "Putting raw elements directly in Carousel",
875
+ "reason": "Slides must be CarouselSlide so snap/indices/aria work",
876
+ "fix": "Wrap each slide in <CarouselSlide>",
877
+ "severity": "error"
878
+ },
879
+ {
880
+ "component": "Carousel",
881
+ "pattern": "Building a slider with manual scroll + dot state",
882
+ "reason": "Reinvents snap, keyboard, autoplay-pause and a11y roles",
883
+ "fix": "Use <Carousel> with CarouselSlide children",
884
+ "severity": "error"
885
+ },
886
+ {
887
+ "component": "Carousel",
888
+ "pattern": "autoPlay without considering reduced motion / pausing",
889
+ "reason": "Autoplay can be an accessibility problem if it never pauses",
890
+ "fix": "Carousel already pauses on hover/focus; keep interval reasonable or omit autoPlay",
891
+ "severity": "error"
892
+ },
893
+ {
894
+ "component": "CarouselSlide",
895
+ "pattern": "<CarouselSlide> outside <Carousel>",
896
+ "reason": "Snap/measurement/aria depend on the Carousel context",
897
+ "fix": "Always nest CarouselSlide inside Carousel",
898
+ "severity": "error"
899
+ },
508
900
  {
509
901
  "component": "DateRangePicker",
510
902
  "pattern": "value={[from, to]}",
@@ -0,0 +1,52 @@
1
+ # Box — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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`).**
5
+
6
+ ```ts
7
+ import { Box } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `padding` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
15
+ | `paddingX` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
16
+ | `paddingY` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
17
+ | `paddingTop` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
18
+ | `paddingRight` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
19
+ | `paddingBottom` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
20
+ | `paddingLeft` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
21
+ | `margin` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
22
+ | `marginX` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
23
+ | `marginY` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
24
+ | `marginTop` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
25
+ | `marginRight` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
26
+ | `marginBottom` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
27
+ | `marginLeft` | `"none"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
28
+ | `width` | `"auto"` \| `"full"` \| `"fit"` \| `"screen"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
29
+ | `height` | `"auto"` \| `"full"` \| `"fit"` \| `"screen"` \| `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` | — |
30
+
31
+ ## Common AI Mistakes
32
+
33
+ - ❌ `<Box style={{ padding: 16 }}>`
34
+ → Use <Box padding="md"> (or paddingX/paddingTop/...)
35
+ - ❌ `Using Box for flex/grid layout`
36
+ → Use <Stack> or <Grid>
37
+ - ❌ `style={{ width: "100%" }} / style={{ height: 320 }}`
38
+ → Use the width / height prop: width="full", width="md", height="screen", etc.
39
+
40
+ ## Examples
41
+
42
+ **Asymmetric padding**
43
+ ```tsx
44
+ <Box as="section" paddingX="lg" paddingY="md">
45
+ <Heading>Settings</Heading>
46
+ </Box>
47
+ ```
48
+
49
+ **Vertical rhythm via margin-top**
50
+ ```tsx
51
+ <Box marginTop="xl"><Separator /></Box>
52
+ ```
@@ -28,6 +28,8 @@ import { Button } from "@usevyre/react"
28
28
  → Use leftIcon={...} or rightIcon={...}
29
29
  - ❌ `size="icon" without aria-label`
30
30
  → Add aria-label describing the action
31
+ - ❌ `padding / margin / marginTop (any spacing prop) on a useVyre component`
32
+ → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
31
33
 
32
34
  ## Examples
33
35
 
@@ -19,6 +19,8 @@ import { Card, CardHeader, CardBody, CardFooter } from "@usevyre/react"
19
19
 
20
20
  - ❌ `variant="primary"`
21
21
  → Use variant="elevated" | "outlined" | "ghost" | "accent"
22
+ - ❌ `padding / margin / marginTop (any spacing prop) on a useVyre component`
23
+ → Space BETWEEN components with <Stack gap> / <Grid gap>; space AROUND a block with <Box padding/margin> wrapping it
22
24
 
23
25
  ## Examples
24
26
 
@@ -0,0 +1,50 @@
1
+ # Carousel — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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).**
5
+
6
+ ```ts
7
+ import { Carousel, CarouselSlide } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `loop` | `true` \| `false` | `false` |
15
+ | `autoPlay` | `true` \| `false` | `false` |
16
+ | `showArrows` | `true` \| `false` | `true` |
17
+ | `showIndicators` | `true` \| `false` | `true` |
18
+
19
+ ## Common AI Mistakes
20
+
21
+ - ❌ `onChange={(e) => set(e.target.value)}`
22
+ → onChange={(index) => setIndex(index)}
23
+ - ❌ `Putting raw elements directly in Carousel`
24
+ → Wrap each slide in <CarouselSlide>
25
+ - ❌ `Building a slider with manual scroll + dot state`
26
+ → Use <Carousel> with CarouselSlide children
27
+ - ❌ `autoPlay without considering reduced motion / pausing`
28
+ → Carousel already pauses on hover/focus; keep interval reasonable or omit autoPlay
29
+
30
+ ## Examples
31
+
32
+ **Image gallery with loop**
33
+ ```tsx
34
+ const [i, setI] = useState(0);
35
+
36
+ <Carousel value={i} onChange={setI} loop>
37
+ <CarouselSlide><img src="/a.jpg" alt="A" /></CarouselSlide>
38
+ <CarouselSlide><img src="/b.jpg" alt="B" /></CarouselSlide>
39
+ <CarouselSlide><img src="/c.jpg" alt="C" /></CarouselSlide>
40
+ </Carousel>
41
+ ```
42
+
43
+ **Onboarding, autoplay, no arrows**
44
+ ```tsx
45
+ <Carousel autoPlay interval={4000} showArrows={false}>
46
+ <CarouselSlide><Welcome /></CarouselSlide>
47
+ <CarouselSlide><Features /></CarouselSlide>
48
+ <CarouselSlide><GetStarted /></CarouselSlide>
49
+ </Carousel>
50
+ ```
@@ -0,0 +1,22 @@
1
+ # CarouselSlide — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **One slide inside <Carousel>. Holds arbitrary content (image, Card, testimonial). Slide order determines its index.**
5
+
6
+ ```ts
7
+ import { Carousel, CarouselSlide } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Common AI Mistakes
11
+
12
+ - ❌ `<CarouselSlide> outside <Carousel>`
13
+ → Always nest CarouselSlide inside Carousel
14
+
15
+ ## Examples
16
+
17
+ **Card slide**
18
+ ```tsx
19
+ <CarouselSlide>
20
+ <Card><CardBody>“Best tool ever.” — Ada</CardBody></Card>
21
+ </CarouselSlide>
22
+ ```
@@ -0,0 +1,48 @@
1
+ # EmptyState — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { EmptyState } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `variant` | `"default"` \| `"search"` \| `"error"` | `default` |
15
+ | `size` | `"sm"` \| `"md"` \| `"lg"` | `md` |
16
+
17
+ ## Common AI Mistakes
18
+
19
+ - ❌ `Building an empty placeholder with a bare <div> + centered text`
20
+ → Use <EmptyState title description variant>
21
+ - ❌ `action / cta prop`
22
+ → Put the Button as children of EmptyState
23
+ - ❌ `Using EmptyState for a loading state`
24
+ → Use <Skeleton> while loading; EmptyState when the result set is empty
25
+
26
+ ## Examples
27
+
28
+ **Empty search results with a reset CTA**
29
+ ```tsx
30
+ <EmptyState
31
+ variant="search"
32
+ title="No results"
33
+ description="Try a different search term."
34
+ >
35
+ <Button variant="secondary" onClick={reset}>Clear filters</Button>
36
+ </EmptyState>
37
+ ```
38
+
39
+ **Full-page empty list**
40
+ ```tsx
41
+ <EmptyState
42
+ size="lg"
43
+ title="No projects yet"
44
+ description="Create your first project to get started."
45
+ >
46
+ <Button variant="primary">New project</Button>
47
+ </EmptyState>
48
+ ```
@@ -0,0 +1,50 @@
1
+ # Form — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { Form, FormField } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Common AI Mistakes
11
+
12
+ - ❌ `Manually tracking each field's error state with useState`
13
+ → Wrap controls in <FormField name rules> and let Form manage errors
14
+ - ❌ `Adding a validation library (zod/yup) just for basic rules`
15
+ → Use rules={{ required, minLength, pattern, email, validate }}
16
+ - ❌ `<FormField> with multiple control children`
17
+ → Use one control per FormField (Input/Textarea/Select/etc.)
18
+ - ❌ `<FormField> outside a <Form>`
19
+ → Always nest FormField inside <Form>
20
+
21
+ ## Examples
22
+
23
+ **Controlled sign-in form with built-in rules**
24
+ ```tsx
25
+ const [values, setValues] = useState({ email: "", password: "" });
26
+
27
+ <Form values={values} onChange={setValues} onSubmit={(v) => signIn(v)}>
28
+ <FormField name="email" label="Email" rules={{ required: true, email: true }}>
29
+ <Input type="email" />
30
+ </FormField>
31
+ <FormField name="password" label="Password" rules={{ required: true, minLength: 8 }}>
32
+ <Input type="password" />
33
+ </FormField>
34
+ <Button type="submit" variant="primary">Sign in</Button>
35
+ </Form>
36
+ ```
37
+
38
+ **Custom cross-field validation**
39
+ ```tsx
40
+ <FormField
41
+ name="confirm"
42
+ label="Confirm password"
43
+ rules={{
44
+ required: true,
45
+ validate: (v, all) => v === all.password ? null : "Passwords do not match",
46
+ }}
47
+ >
48
+ <Input type="password" />
49
+ </FormField>
50
+ ```