@usevyre/ai-context 1.1.0 → 1.2.1

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.0",
2
+ "version": "1.2.0",
3
3
  "rules": [
4
4
  {
5
5
  "component": "Accordion",
@@ -101,9 +101,30 @@
101
101
  },
102
102
  {
103
103
  "component": "Calendar",
104
- "pattern": "Using Calendar for time selection",
105
- "reason": "Calendar handles date only, not time",
106
- "fix": "Combine with a separate time Input if time selection is needed",
104
+ "pattern": "Calendar for an input field that opens a popover",
105
+ "reason": "Calendar renders an always-visible grid, not a trigger",
106
+ "fix": "Use <DatePicker /> (single date) or <DateRangePicker /> (range)",
107
+ "severity": "error"
108
+ },
109
+ {
110
+ "component": "Calendar",
111
+ "pattern": "value as tuple for mode=\"single\"",
112
+ "reason": "value type must match mode: Date for single, [Date,Date] for range, Date[] for multiple",
113
+ "fix": "Pass value matching mode; use mode=\"range\" for [start,end]",
114
+ "severity": "error"
115
+ },
116
+ {
117
+ "component": "DatePicker",
118
+ "pattern": "DatePicker mode=\"range\" for { from, to } object",
119
+ "reason": "DatePicker range mode emits a [Date, Date] tuple, not a { from, to } object",
120
+ "fix": "Use <DateRangePicker /> for the { from, to } object API + presets + dual month",
121
+ "severity": "error"
122
+ },
123
+ {
124
+ "component": "DatePicker",
125
+ "pattern": "DatePicker without value/onChange",
126
+ "reason": "DatePicker is controlled — it has no internal selected state",
127
+ "fix": "Provide value and onChange (e.g. from useState)",
107
128
  "severity": "error"
108
129
  },
109
130
  {
@@ -120,6 +141,48 @@
120
141
  "fix": "Use size=\"md\"",
121
142
  "severity": "error"
122
143
  },
144
+ {
145
+ "component": "RadioGroup",
146
+ "pattern": "<Radio> used outside a <RadioGroup>",
147
+ "reason": "Radio reads selection + name from RadioGroup context; it throws without a provider",
148
+ "fix": "Always wrap <Radio> in <RadioGroup>",
149
+ "severity": "error"
150
+ },
151
+ {
152
+ "component": "RadioGroup",
153
+ "pattern": "RadioGroup without value/onChange (React) or v-model (Vue)",
154
+ "reason": "RadioGroup is controlled; selection won't update",
155
+ "fix": "Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React",
156
+ "severity": "error"
157
+ },
158
+ {
159
+ "component": "RadioGroup",
160
+ "pattern": "Using Checkbox for mutually-exclusive choices",
161
+ "reason": "Radio expresses single-choice semantics + keyboard model",
162
+ "fix": "Use RadioGroup + Radio (or options) for one-of-many",
163
+ "severity": "error"
164
+ },
165
+ {
166
+ "component": "RichTextEditor",
167
+ "pattern": "RichTextEditor without value/onChange (React) or v-model (Vue)",
168
+ "reason": "It is fully controlled; edits won't persist",
169
+ "fix": "Keep the HTML string in state and update it in onChange / v-model",
170
+ "severity": "error"
171
+ },
172
+ {
173
+ "component": "RichTextEditor",
174
+ "pattern": "Rendering value as text or with dangerouslySetInnerHTML elsewhere without sanitising",
175
+ "reason": "value is raw HTML the user typed",
176
+ "fix": "Sanitise (e.g. DOMPurify) before re-rendering untrusted RTE output",
177
+ "severity": "error"
178
+ },
179
+ {
180
+ "component": "RichTextEditor",
181
+ "pattern": "toolbar=\"bold\" (string)",
182
+ "reason": "toolbar is an array of tool ids",
183
+ "fix": "Pass an array, e.g. toolbar={[\"bold\",\"italic\",\"link\"]}",
184
+ "severity": "error"
185
+ },
123
186
  {
124
187
  "component": "Command",
125
188
  "pattern": "Using Input type=\"search\" for search UI",
@@ -141,6 +204,13 @@
141
204
  "fix": "Wrap Input in <Field state=\"error\"> to apply validation styling",
142
205
  "severity": "error"
143
206
  },
207
+ {
208
+ "component": "Field",
209
+ "pattern": "Mixing props label/hint AND FieldLabel/FieldError for the same field",
210
+ "reason": "Duplicates the label / message",
211
+ "fix": "Pick one: either props-based (label/hint/state) OR composable parts",
212
+ "severity": "error"
213
+ },
144
214
  {
145
215
  "component": "Input",
146
216
  "pattern": "size=\"icon\"",
@@ -155,6 +225,13 @@
155
225
  "fix": "Import Command from @usevyre/react for search palettes",
156
226
  "severity": "error"
157
227
  },
228
+ {
229
+ "component": "Input",
230
+ "pattern": "Vue: binding Input/Textarea value without v-model",
231
+ "reason": "Vue Input & Textarea support v-model (modelValue); manual :value alone won't update",
232
+ "fix": "Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange",
233
+ "severity": "error"
234
+ },
158
235
  {
159
236
  "component": "Modal",
160
237
  "pattern": "size=\"xl\"",
@@ -183,6 +260,13 @@
183
260
  "fix": "Pass options={[{ value: 'a', label: 'Option A' }]}",
184
261
  "severity": "error"
185
262
  },
263
+ {
264
+ "component": "Sidebar",
265
+ "pattern": "Vue: passing icon/collapsedIcon as props on SidebarTrigger",
266
+ "reason": "Vue SidebarTrigger customises icons via slots, not props (consistent with SidebarItem)",
267
+ "fix": "Use <template #icon> and <template #collapsed-icon>; React uses icon / collapsedIcon props",
268
+ "severity": "error"
269
+ },
186
270
  {
187
271
  "component": "Toast",
188
272
  "pattern": "Rendering <Toast> directly in JSX",
@@ -322,6 +406,104 @@
322
406
  "reason": "TagGroup is display-only",
323
407
  "fix": "Use TagsInput for an editable tag field",
324
408
  "severity": "error"
409
+ },
410
+ {
411
+ "component": "Item",
412
+ "pattern": "Card used for repeated list rows",
413
+ "reason": "Card is a content container; Item is the dense list-row primitive",
414
+ "fix": "Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows",
415
+ "severity": "error"
416
+ },
417
+ {
418
+ "component": "Item",
419
+ "pattern": "Item variant=\"primary\"",
420
+ "reason": "Item has no 'primary' variant",
421
+ "fix": "Use variant=\"default\" | \"outlined\" | \"muted\"",
422
+ "severity": "error"
423
+ },
424
+ {
425
+ "component": "Item",
426
+ "pattern": "raw text directly inside Item",
427
+ "reason": "Item lays out media/content/actions columns; bare text breaks alignment",
428
+ "fix": "Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>",
429
+ "severity": "error"
430
+ },
431
+ {
432
+ "component": "Kanban",
433
+ "pattern": "Kanban without onChange (or ignoring it)",
434
+ "reason": "Kanban holds no internal data state; dropped cards won't move unless you apply onChange",
435
+ "fix": "Store columns in state and setColumns in onChange (v-model in Vue)",
436
+ "severity": "error"
437
+ },
438
+ {
439
+ "component": "Kanban",
440
+ "pattern": "Duplicate card ids across columns",
441
+ "reason": "Card moves are resolved by id; duplicates corrupt the move",
442
+ "fix": "Use globally-unique card ids across the entire board",
443
+ "severity": "error"
444
+ },
445
+ {
446
+ "component": "Kanban",
447
+ "pattern": "Mutating value in place then calling onChange",
448
+ "reason": "React/Vue need a new array reference to re-render reliably",
449
+ "fix": "Pass the new array Kanban gives you straight to setState / v-model",
450
+ "severity": "error"
451
+ },
452
+ {
453
+ "component": "Kanban",
454
+ "pattern": "color=\"blue\" (or any non-semantic value)",
455
+ "reason": "color is a fixed semantic set, not an arbitrary CSS color",
456
+ "fix": "Use one of: \"default\" | \"accent\" | \"teal\" | \"success\" | \"warning\" | \"danger\"",
457
+ "severity": "error"
458
+ },
459
+ {
460
+ "component": "Conversation",
461
+ "pattern": "Conversation without currentUserId",
462
+ "reason": "Alignment (incoming vs outgoing) is decided by authorId === currentUserId",
463
+ "fix": "Always pass currentUserId matching one of the message authorId values",
464
+ "severity": "error"
465
+ },
466
+ {
467
+ "component": "Conversation",
468
+ "pattern": "Expecting Conversation to store/append messages",
469
+ "reason": "Conversation is controlled & stateless for data, like Kanban/DataGrid",
470
+ "fix": "Append to your own state in onSend (or @send) and pass it back via value",
471
+ "severity": "error"
472
+ },
473
+ {
474
+ "component": "Conversation",
475
+ "pattern": "composer without onSend (React) / @send (Vue)",
476
+ "reason": "The built-in composer emits text; nothing happens unless you handle it",
477
+ "fix": "Provide onSend / @send to append the message to value",
478
+ "severity": "error"
479
+ },
480
+ {
481
+ "component": "Conversation",
482
+ "pattern": "Treating onSend as (text) only when using allowAttachments",
483
+ "reason": "With allowAttachments, staged files arrive as the 2nd arg; ignoring it drops attachments",
484
+ "fix": "Handle onSend(text, files) — map files to message attachments and append",
485
+ "severity": "error"
486
+ },
487
+ {
488
+ "component": "DateRangePicker",
489
+ "pattern": "value={[from, to]}",
490
+ "reason": "DateRangePicker uses a { from, to } object, not a [Date, Date] tuple like Calendar mode=range",
491
+ "fix": "Use value={{ from, to }} and read range.from / range.to",
492
+ "severity": "error"
493
+ },
494
+ {
495
+ "component": "DateRangePicker",
496
+ "pattern": "DateRangePicker for a single date",
497
+ "reason": "DateRangePicker always selects a start AND end",
498
+ "fix": "Use <DatePicker /> for a single date",
499
+ "severity": "error"
500
+ },
501
+ {
502
+ "component": "DateRangePicker",
503
+ "pattern": "presets=\"true\" (string)",
504
+ "reason": "presets is a boolean or an array, not a string",
505
+ "fix": "Use the bare prop: presets (or presets={true})",
506
+ "severity": "error"
325
507
  }
326
508
  ]
327
509
  }
@@ -1,7 +1,7 @@
1
1
  # Calendar — AI Cheat Sheet
2
2
  > Quick reference for Claude / Cursor / Copilot
3
3
 
4
- **Date picker calendar widget for selecting single dates or ranges.**
4
+ **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.**
5
5
 
6
6
  ```ts
7
7
  import { Calendar } from "@usevyre/react"
@@ -15,8 +15,10 @@ import { Calendar } from "@usevyre/react"
15
15
 
16
16
  ## Common AI Mistakes
17
17
 
18
- - ❌ `Using Calendar for time selection`
19
- Combine with a separate time Input if time selection is needed
18
+ - ❌ `Calendar for an input field that opens a popover`
19
+ Use <DatePicker /> (single date) or <DateRangePicker /> (range)
20
+ - ❌ `value as tuple for mode="single"`
21
+ → Pass value matching mode; use mode="range" for [start,end]
20
22
 
21
23
  ## Examples
22
24
 
@@ -0,0 +1,63 @@
1
+ # Conversation — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { Conversation } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `composer` | `true` \| `false` | `false` |
15
+ | `allowAttachments` | `true` \| `false` | `false` |
16
+
17
+ ## Common AI Mistakes
18
+
19
+ - ❌ `Conversation without currentUserId`
20
+ → Always pass currentUserId matching one of the message authorId values
21
+ - ❌ `Expecting Conversation to store/append messages`
22
+ → Append to your own state in onSend (or @send) and pass it back via value
23
+ - ❌ `composer without onSend (React) / @send (Vue)`
24
+ → Provide onSend / @send to append the message to value
25
+ - ❌ `Treating onSend as (text) only when using allowAttachments`
26
+ → Handle onSend(text, files) — map files to message attachments and append
27
+
28
+ ## Examples
29
+
30
+ **Controlled thread with built-in composer**
31
+ ```tsx
32
+ const [messages, setMessages] = useState([
33
+ { id: "1", authorId: "sam", authorName: "Sam", text: "Hey!" },
34
+ { id: "2", authorId: "me", text: "Hi \ud83d\udc4b", status: "read" },
35
+ ]);
36
+ <Conversation
37
+ value={messages}
38
+ currentUserId="me"
39
+ composer
40
+ onSend={(t) => setMessages((m) => [...m, { id: crypto.randomUUID(), authorId: "me", text: t }])}
41
+ />
42
+ ```
43
+
44
+ **Typing indicator + custom bubble**
45
+ ```tsx
46
+ <Conversation
47
+ value={messages}
48
+ currentUserId="me"
49
+ typing="Sam is typing"
50
+ renderMessage={(m) => <strong>{m.text}</strong>}
51
+ />
52
+ ```
53
+
54
+ **Message with image + file attachments**
55
+ ```tsx
56
+ const messages = [
57
+ { id: "1", authorId: "sam", authorName: "Sam", text: "Moodboard \ud83d\udc47",
58
+ attachments: [{ kind: "image", url: "/board.png", name: "board.png" }] },
59
+ { id: "2", authorId: "me", text: "Specs:", status: "read",
60
+ attachments: [{ kind: "file", url: "/spec.pdf", name: "spec.pdf", size: "2.4 MB" }] },
61
+ ];
62
+ <Conversation value={messages} currentUserId="me" />
63
+ ```
@@ -0,0 +1,36 @@
1
+ # DatePicker — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { DatePicker } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `mode` | `"single"` \| `"range"` \| `"multiple"` | `single` |
15
+ | `weekStartsOn` | `"0"` \| `"1"` | `1` |
16
+ | `showTime` | `true` \| `false` | `false` |
17
+
18
+ ## Common AI Mistakes
19
+
20
+ - ❌ `DatePicker mode="range" for { from, to } object`
21
+ → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
22
+ - ❌ `DatePicker without value/onChange`
23
+ → Provide value and onChange (e.g. from useState)
24
+
25
+ ## Examples
26
+
27
+ **Single date field**
28
+ ```tsx
29
+ const [date, setDate] = useState(null);
30
+ <DatePicker value={date} onChange={setDate} placeholder="Pick a date" />
31
+ ```
32
+
33
+ **Date + time**
34
+ ```tsx
35
+ <DatePicker value={date} onChange={setDate} showTime />
36
+ ```
@@ -0,0 +1,37 @@
1
+ # DateRangePicker — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { DateRangePicker } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `numberOfMonths` | `"1"` \| `"2"` | `2` |
15
+ | `weekStartsOn` | `"0"` \| `"1"` | `1` |
16
+
17
+ ## Common AI Mistakes
18
+
19
+ - ❌ `value={[from, to]}`
20
+ → Use value={{ from, to }} and read range.from / range.to
21
+ - ❌ `DateRangePicker for a single date`
22
+ → Use <DatePicker /> for a single date
23
+ - ❌ `presets="true" (string)`
24
+ → Use the bare prop: presets (or presets={true})
25
+
26
+ ## Examples
27
+
28
+ **Range picker with built-in presets**
29
+ ```tsx
30
+ const [range, setRange] = useState({ from: null, to: null });
31
+ <DateRangePicker value={range} onChange={setRange} presets />
32
+ ```
33
+
34
+ **Single month, no presets**
35
+ ```tsx
36
+ <DateRangePicker value={range} onChange={setRange} numberOfMonths={1} />
37
+ ```
@@ -1,7 +1,7 @@
1
1
  # Field — AI Cheat Sheet
2
2
  > Quick reference for Claude / Cursor / Copilot
3
3
 
4
- **Form field wrapper providing label, hint text, and validation state for Input or Textarea.**
4
+ **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.**
5
5
 
6
6
  ```ts
7
7
  import { Field, Input, Textarea } from "@usevyre/react"
@@ -18,6 +18,8 @@ import { Field, Input, Textarea } from "@usevyre/react"
18
18
 
19
19
  - ❌ `Applying state prop directly to Input`
20
20
  → Wrap Input in <Field state="error"> to apply validation styling
21
+ - ❌ `Mixing props label/hint AND FieldLabel/FieldError for the same field`
22
+ → Pick one: either props-based (label/hint/state) OR composable parts
21
23
 
22
24
  ## Examples
23
25
 
@@ -34,3 +36,19 @@ import { Field, Input, Textarea } from "@usevyre/react"
34
36
  <Input leftElement={<SearchIcon />} placeholder="Search..." />
35
37
  </Field>
36
38
  ```
39
+
40
+ **Composable field with explicit parts**
41
+ ```tsx
42
+ <Field>
43
+ <FieldLabel required htmlFor="email">Email</FieldLabel>
44
+ <Input id="email" type="email" />
45
+ <FieldDescription>We\u2019ll never share it.</FieldDescription>
46
+ <FieldError>{errors.email}</FieldError>
47
+ </Field>
48
+
49
+ // Two controls side by side
50
+ <FieldGroup orientation="horizontal">
51
+ <Field label="First name"><Input /></Field>
52
+ <Field label="Last name"><Input /></Field>
53
+ </FieldGroup>
54
+ ```
@@ -8,12 +8,15 @@ Quick reference for AI agents — one file per component.
8
8
  - [Badge](badge.md) — Small label for status, category, or count. Use dot prop for live status indicator.
9
9
  - [Breadcrumb](breadcrumb.md) — Navigation trail showing current page location in hierarchy.
10
10
  - [Button](button.md) — Triggers actions and navigation. The most commonly used interactive element.
11
- - [Calendar](calendar.md) — Date picker calendar widget for selecting single dates or ranges.
11
+ - [Calendar](calendar.md) — 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.
12
+ - [DatePicker](datepicker.md) — 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.
12
13
  - [Card](card.md) — Content container with optional header, body, and footer sections.
13
14
  - [Checkbox](checkbox.md) — Binary toggle for boolean form values.
15
+ - [RadioGroup](radiogroup.md) — 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.
16
+ - [RichTextEditor](richtexteditor.md) — 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.
14
17
  - [Command](command.md) — Command palette / search dialog. Use for search-first navigation or quick actions.
15
18
  - [DropdownMenu](dropdownmenu.md) — Contextual menu triggered by a button. Supports items, separators, checkbox items, radio groups, and sub-menus.
16
- - [Field](field.md) — Form field wrapper providing label, hint text, and validation state for Input or Textarea.
19
+ - [Field](field.md) — 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.
17
20
  - [Input](input.md) — Text input field. Wrap in Field for labels and validation. Use leftElement/rightElement for icons.
18
21
  - [Label](label.md) — Accessible form label. Associate with input via htmlFor.
19
22
  - [Modal](modal.md) — Dialog overlay for confirmations, forms, or focused content.
@@ -38,3 +41,7 @@ Quick reference for AI agents — one file per component.
38
41
  - [DataGrid](datagrid.md) — Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
39
42
  - [Tag](tag.md) — Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
40
43
  - [TagGroup](taggroup.md) — Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
44
+ - [Item](item.md) — Layout primitive for list rows, settings rows, and notification rows. Denser than Card — use Item (not Card) for repeated list rows.
45
+ - [Kanban](kanban.md) — 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.
46
+ - [Conversation](conversation.md) — 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.
47
+ - [DateRangePicker](daterangepicker.md) — 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.
@@ -19,6 +19,8 @@ import { Input } from "@usevyre/react"
19
19
  → Use size="sm" | "md" | "lg"
20
20
  - ❌ `type="search" for search UI`
21
21
  → Import Command from @usevyre/react for search palettes
22
+ - ❌ `Vue: binding Input/Textarea value without v-model`
23
+ → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
22
24
 
23
25
  ## Examples
24
26
 
@@ -0,0 +1,53 @@
1
+ # Item — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **Layout primitive for list rows, settings rows, and notification rows. Denser than Card — use Item (not Card) for repeated list rows.**
5
+
6
+ ```ts
7
+ import { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemGroup } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `variant` | `"default"` \| `"outlined"` \| `"muted"` \| `"plain"` | `default` |
15
+ | `size` | `"sm"` \| `"md"` \| `"lg"` | `md` |
16
+ | `clickable` | `true` \| `false` | `false` |
17
+
18
+ ## Common AI Mistakes
19
+
20
+ - ❌ `Card used for repeated list rows`
21
+ → Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows
22
+ - ❌ `Item variant="primary"`
23
+ → Use variant="default" | "outlined" | "muted"
24
+ - ❌ `raw text directly inside Item`
25
+ → Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>
26
+
27
+ ## Examples
28
+
29
+ **Settings row with media, content and a trailing switch**
30
+ ```tsx
31
+ <Item>
32
+ <ItemMedia><BellIcon /></ItemMedia>
33
+ <ItemContent>
34
+ <ItemTitle>Notifications</ItemTitle>
35
+ <ItemDescription>Receive an email when someone mentions you.</ItemDescription>
36
+ </ItemContent>
37
+ <ItemActions>
38
+ <Switch defaultChecked />
39
+ </ItemActions>
40
+ </Item>
41
+ ```
42
+
43
+ **Grouped clickable list with dividers**
44
+ ```tsx
45
+ <ItemGroup separated>
46
+ <Item clickable>
47
+ <ItemContent><ItemTitle>Profile</ItemTitle></ItemContent>
48
+ </Item>
49
+ <Item clickable>
50
+ <ItemContent><ItemTitle>Billing</ItemTitle></ItemContent>
51
+ </Item>
52
+ </ItemGroup>
53
+ ```
@@ -0,0 +1,59 @@
1
+ # Kanban — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { Kanban } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Common AI Mistakes
11
+
12
+ - ❌ `Kanban without onChange (or ignoring it)`
13
+ → Store columns in state and setColumns in onChange (v-model in Vue)
14
+ - ❌ `Duplicate card ids across columns`
15
+ → Use globally-unique card ids across the entire board
16
+ - ❌ `Mutating value in place then calling onChange`
17
+ → Pass the new array Kanban gives you straight to setState / v-model
18
+ - ❌ `color="blue" (or any non-semantic value)`
19
+ → Use one of: "default" | "accent" | "teal" | "success" | "warning" | "danger"
20
+
21
+ ## Examples
22
+
23
+ **Controlled board**
24
+ ```tsx
25
+ const [columns, setColumns] = useState([
26
+ { id: "todo", title: "To Do", cards: [{ id: "1", title: "Spec API" }] },
27
+ { id: "doing", title: "In Progress", cards: [] },
28
+ { id: "done", title: "Done", cards: [{ id: "2", title: "Kickoff" }] },
29
+ ]);
30
+ <Kanban value={columns} onChange={setColumns} />
31
+ ```
32
+
33
+ **Custom card body + click handler**
34
+ ```tsx
35
+ <Kanban
36
+ value={columns}
37
+ onChange={setColumns}
38
+ onCardClick={(card) => openDetail(card.id)}
39
+ renderCard={(card) => (
40
+ <><strong>{card.title}</strong><Badge>{card.id}</Badge></>
41
+ )}
42
+ />
43
+ ```
44
+
45
+ **Tinted columns/cards + complex card content**
46
+ ```tsx
47
+ const [cols, setCols] = useState([
48
+ { id: "doing", title: "In Progress", color: "teal", cards: [
49
+ { id: "t1", title: "OAuth", assignee: "AK", progress: 60, color: "warning" },
50
+ ]},
51
+ ]);
52
+ <Kanban
53
+ value={cols}
54
+ onChange={setCols}
55
+ renderCard={(card) => (
56
+ <><strong>{card.title}</strong><Progress value={card.progress} /></>
57
+ )}
58
+ />
59
+ ```
@@ -0,0 +1,47 @@
1
+ # RadioGroup — AI Cheat Sheet
2
+ > Quick reference for Claude / Cursor / Copilot
3
+
4
+ **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.**
5
+
6
+ ```ts
7
+ import { RadioGroup, Radio } from "@usevyre/react"
8
+ ```
9
+
10
+ ## Valid Props
11
+
12
+ | Prop | Values | Default |
13
+ |------|--------|---------|
14
+ | `size` | `"sm"` \| `"md"` | `md` |
15
+ | `orientation` | `"vertical"` \| `"horizontal"` | `vertical` |
16
+ | `disabled` | `true` \| `false` | `false` |
17
+
18
+ ## Common AI Mistakes
19
+
20
+ - ❌ `<Radio> used outside a <RadioGroup>`
21
+ → Always wrap <Radio> in <RadioGroup>
22
+ - ❌ `RadioGroup without value/onChange (React) or v-model (Vue)`
23
+ → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
24
+ - ❌ `Using Checkbox for mutually-exclusive choices`
25
+ → Use RadioGroup + Radio (or options) for one-of-many
26
+
27
+ ## Examples
28
+
29
+ **Data-driven**
30
+ ```tsx
31
+ <RadioGroup
32
+ value={plan}
33
+ onChange={setPlan}
34
+ options={[
35
+ { value: "free", label: "Free", description: "For hobby projects" },
36
+ { value: "pro", label: "Pro", description: "For teams" },
37
+ ]}
38
+ />
39
+ ```
40
+
41
+ **Composable children**
42
+ ```tsx
43
+ <RadioGroup value={plan} onChange={setPlan} orientation="horizontal">
44
+ <Radio value="free" label="Free" />
45
+ <Radio value="pro" label="Pro" />
46
+ </RadioGroup>
47
+ ```