@usevyre/ai-context 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anti-patterns.json +284 -4
- package/dist/cheat-sheets/buttongroup.md +42 -0
- package/dist/cheat-sheets/calendar.md +5 -3
- package/dist/cheat-sheets/combobox.md +37 -0
- package/dist/cheat-sheets/conversation.md +63 -0
- package/dist/cheat-sheets/datagrid.md +44 -0
- package/dist/cheat-sheets/datepicker.md +36 -0
- package/dist/cheat-sheets/daterangepicker.md +37 -0
- package/dist/cheat-sheets/field.md +19 -1
- package/dist/cheat-sheets/index.md +15 -2
- package/dist/cheat-sheets/input.md +2 -0
- package/dist/cheat-sheets/item.md +53 -0
- package/dist/cheat-sheets/kanban.md +59 -0
- package/dist/cheat-sheets/radiogroup.md +47 -0
- package/dist/cheat-sheets/richtexteditor.md +41 -0
- package/dist/cheat-sheets/tag.md +46 -0
- package/dist/cheat-sheets/taggroup.md +33 -0
- package/dist/cheat-sheets/tagsinput.md +35 -0
- package/dist/claude-context.md +521 -5
- package/dist/copilot-instructions.md +521 -5
- package/dist/cursor-rules.md +164 -4
- package/dist/full-context.md +520 -4
- package/dist/index.js +3862 -325
- package/dist/schema.json +929 -10
- package/dist/tokens.json +1 -1
- package/dist/tokens.md +1 -1
- package/dist/version-info.json +166 -65
- package/dist/windsurf-rules.md +521 -5
- package/package.json +1 -1
package/dist/anti-patterns.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
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": "
|
|
105
|
-
"reason": "Calendar
|
|
106
|
-
"fix": "
|
|
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\"",
|
|
@@ -217,6 +294,209 @@
|
|
|
217
294
|
"reason": "Typography components apply the correct token-based styles",
|
|
218
295
|
"fix": "Use <Heading>, <Text>, <Lead> from @usevyre/react",
|
|
219
296
|
"severity": "error"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"component": "ButtonGroup",
|
|
300
|
+
"pattern": "ButtonGroup variant=\"...\"",
|
|
301
|
+
"reason": "ButtonGroup has no variant prop — variant goes on each child Button",
|
|
302
|
+
"fix": "Set variant on each <Button> inside the group",
|
|
303
|
+
"severity": "error"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"component": "ButtonGroup",
|
|
307
|
+
"pattern": "ButtonGroup without Button children",
|
|
308
|
+
"reason": "ButtonGroup is a layout wrapper for Button elements",
|
|
309
|
+
"fix": "Place <Button> elements as direct children",
|
|
310
|
+
"severity": "error"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"component": "TagsInput",
|
|
314
|
+
"pattern": "TagsInput value={string}",
|
|
315
|
+
"reason": "value must be a string array, not a string",
|
|
316
|
+
"fix": "Pass an array: value={['react','vue']}",
|
|
317
|
+
"severity": "error"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"component": "TagsInput",
|
|
321
|
+
"pattern": "TagsInput without onChange",
|
|
322
|
+
"reason": "TagsInput is controlled — it needs onChange to update",
|
|
323
|
+
"fix": "Provide value and onChange (React) or v-model (Vue)",
|
|
324
|
+
"severity": "error"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"component": "Combobox",
|
|
328
|
+
"pattern": "Combobox value=\"\"",
|
|
329
|
+
"reason": "Empty selection must be null, not empty string",
|
|
330
|
+
"fix": "Use value={null} for no selection",
|
|
331
|
+
"severity": "error"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"component": "Combobox",
|
|
335
|
+
"pattern": "Combobox options={string[]}",
|
|
336
|
+
"reason": "options must be objects with value and label",
|
|
337
|
+
"fix": "Use [{ value: 'ts', label: 'TypeScript' }]",
|
|
338
|
+
"severity": "error"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"component": "Combobox",
|
|
342
|
+
"pattern": "Using Combobox for command palette",
|
|
343
|
+
"reason": "Combobox is single-value select, not an action palette",
|
|
344
|
+
"fix": "Use Command for command palettes",
|
|
345
|
+
"severity": "error"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"component": "DataGrid",
|
|
349
|
+
"pattern": "DataGrid expecting built-in pagination",
|
|
350
|
+
"reason": "DataGrid does not paginate — it only sorts",
|
|
351
|
+
"fix": "Slice rows yourself and use the Pagination component",
|
|
352
|
+
"severity": "error"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"component": "DataGrid",
|
|
356
|
+
"pattern": "DataGrid expecting built-in filtering",
|
|
357
|
+
"reason": "DataGrid does not filter rows",
|
|
358
|
+
"fix": "Filter the rows array before passing it in",
|
|
359
|
+
"severity": "error"
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"component": "DataGrid",
|
|
363
|
+
"pattern": "sortable without onSort",
|
|
364
|
+
"reason": "Sorting is controlled — the grid does not sort data itself",
|
|
365
|
+
"fix": "Handle onSort and sort the rows array in your state",
|
|
366
|
+
"severity": "error"
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"component": "Tag",
|
|
370
|
+
"pattern": "Tag variant=\"success\"",
|
|
371
|
+
"reason": "Tag only has default, accent, danger variants (unlike Badge which has more)",
|
|
372
|
+
"fix": "Use Badge for success/warning/teal status colors; Tag is for categories/filters",
|
|
373
|
+
"severity": "error"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"component": "Tag",
|
|
377
|
+
"pattern": "Using Tag for tag input",
|
|
378
|
+
"reason": "Tag is display-only, it does not accept typed input",
|
|
379
|
+
"fix": "Use TagsInput for adding/removing tags via keyboard",
|
|
380
|
+
"severity": "error"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"component": "Tag",
|
|
384
|
+
"pattern": "Tag size=\"xl\"",
|
|
385
|
+
"reason": "Maximum size is 'lg'",
|
|
386
|
+
"fix": "Use size=\"lg\"",
|
|
387
|
+
"severity": "error"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"component": "TagGroup",
|
|
391
|
+
"pattern": "TagGroup without Tag children",
|
|
392
|
+
"reason": "TagGroup is a layout wrapper for Tag elements",
|
|
393
|
+
"fix": "Place <Tag> elements as direct children",
|
|
394
|
+
"severity": "error"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"component": "TagGroup",
|
|
398
|
+
"pattern": "Using TagGroup for tag input",
|
|
399
|
+
"reason": "TagGroup is display-only",
|
|
400
|
+
"fix": "Use TagsInput for an editable tag field",
|
|
401
|
+
"severity": "error"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"component": "Item",
|
|
405
|
+
"pattern": "Card used for repeated list rows",
|
|
406
|
+
"reason": "Card is a content container; Item is the dense list-row primitive",
|
|
407
|
+
"fix": "Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows",
|
|
408
|
+
"severity": "error"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"component": "Item",
|
|
412
|
+
"pattern": "Item variant=\"primary\"",
|
|
413
|
+
"reason": "Item has no 'primary' variant",
|
|
414
|
+
"fix": "Use variant=\"default\" | \"outlined\" | \"muted\"",
|
|
415
|
+
"severity": "error"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"component": "Item",
|
|
419
|
+
"pattern": "raw text directly inside Item",
|
|
420
|
+
"reason": "Item lays out media/content/actions columns; bare text breaks alignment",
|
|
421
|
+
"fix": "Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>",
|
|
422
|
+
"severity": "error"
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"component": "Kanban",
|
|
426
|
+
"pattern": "Kanban without onChange (or ignoring it)",
|
|
427
|
+
"reason": "Kanban holds no internal data state; dropped cards won't move unless you apply onChange",
|
|
428
|
+
"fix": "Store columns in state and setColumns in onChange (v-model in Vue)",
|
|
429
|
+
"severity": "error"
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"component": "Kanban",
|
|
433
|
+
"pattern": "Duplicate card ids across columns",
|
|
434
|
+
"reason": "Card moves are resolved by id; duplicates corrupt the move",
|
|
435
|
+
"fix": "Use globally-unique card ids across the entire board",
|
|
436
|
+
"severity": "error"
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"component": "Kanban",
|
|
440
|
+
"pattern": "Mutating value in place then calling onChange",
|
|
441
|
+
"reason": "React/Vue need a new array reference to re-render reliably",
|
|
442
|
+
"fix": "Pass the new array Kanban gives you straight to setState / v-model",
|
|
443
|
+
"severity": "error"
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"component": "Kanban",
|
|
447
|
+
"pattern": "color=\"blue\" (or any non-semantic value)",
|
|
448
|
+
"reason": "color is a fixed semantic set, not an arbitrary CSS color",
|
|
449
|
+
"fix": "Use one of: \"default\" | \"accent\" | \"teal\" | \"success\" | \"warning\" | \"danger\"",
|
|
450
|
+
"severity": "error"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"component": "Conversation",
|
|
454
|
+
"pattern": "Conversation without currentUserId",
|
|
455
|
+
"reason": "Alignment (incoming vs outgoing) is decided by authorId === currentUserId",
|
|
456
|
+
"fix": "Always pass currentUserId matching one of the message authorId values",
|
|
457
|
+
"severity": "error"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"component": "Conversation",
|
|
461
|
+
"pattern": "Expecting Conversation to store/append messages",
|
|
462
|
+
"reason": "Conversation is controlled & stateless for data, like Kanban/DataGrid",
|
|
463
|
+
"fix": "Append to your own state in onSend (or @send) and pass it back via value",
|
|
464
|
+
"severity": "error"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"component": "Conversation",
|
|
468
|
+
"pattern": "composer without onSend (React) / @send (Vue)",
|
|
469
|
+
"reason": "The built-in composer emits text; nothing happens unless you handle it",
|
|
470
|
+
"fix": "Provide onSend / @send to append the message to value",
|
|
471
|
+
"severity": "error"
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"component": "Conversation",
|
|
475
|
+
"pattern": "Treating onSend as (text) only when using allowAttachments",
|
|
476
|
+
"reason": "With allowAttachments, staged files arrive as the 2nd arg; ignoring it drops attachments",
|
|
477
|
+
"fix": "Handle onSend(text, files) — map files to message attachments and append",
|
|
478
|
+
"severity": "error"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"component": "DateRangePicker",
|
|
482
|
+
"pattern": "value={[from, to]}",
|
|
483
|
+
"reason": "DateRangePicker uses a { from, to } object, not a [Date, Date] tuple like Calendar mode=range",
|
|
484
|
+
"fix": "Use value={{ from, to }} and read range.from / range.to",
|
|
485
|
+
"severity": "error"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"component": "DateRangePicker",
|
|
489
|
+
"pattern": "DateRangePicker for a single date",
|
|
490
|
+
"reason": "DateRangePicker always selects a start AND end",
|
|
491
|
+
"fix": "Use <DatePicker /> for a single date",
|
|
492
|
+
"severity": "error"
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"component": "DateRangePicker",
|
|
496
|
+
"pattern": "presets=\"true\" (string)",
|
|
497
|
+
"reason": "presets is a boolean or an array, not a string",
|
|
498
|
+
"fix": "Use the bare prop: presets (or presets={true})",
|
|
499
|
+
"severity": "error"
|
|
220
500
|
}
|
|
221
501
|
]
|
|
222
502
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# ButtonGroup — AI Cheat Sheet
|
|
2
|
+
> Quick reference for Claude / Cursor / Copilot
|
|
3
|
+
|
|
4
|
+
**Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.**
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { ButtonGroup, Button } from "@usevyre/react"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Valid Props
|
|
11
|
+
|
|
12
|
+
| Prop | Values | Default |
|
|
13
|
+
|------|--------|---------|
|
|
14
|
+
| `orientation` | `"horizontal"` \| `"vertical"` | `horizontal` |
|
|
15
|
+
| `size` | `"sm"` \| `"md"` \| `"lg"` \| `"icon"` | — |
|
|
16
|
+
| `attached` | `true` \| `false` | `false` |
|
|
17
|
+
|
|
18
|
+
## Common AI Mistakes
|
|
19
|
+
|
|
20
|
+
- ❌ `ButtonGroup variant="..."`
|
|
21
|
+
→ Set variant on each <Button> inside the group
|
|
22
|
+
- ❌ `ButtonGroup without Button children`
|
|
23
|
+
→ Place <Button> elements as direct children
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
**Segmented control**
|
|
28
|
+
```tsx
|
|
29
|
+
<ButtonGroup attached>
|
|
30
|
+
<Button variant="secondary">Day</Button>
|
|
31
|
+
<Button variant="secondary">Week</Button>
|
|
32
|
+
<Button variant="secondary">Month</Button>
|
|
33
|
+
</ButtonGroup>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Vertical group**
|
|
37
|
+
```tsx
|
|
38
|
+
<ButtonGroup orientation="vertical" attached>
|
|
39
|
+
<Button variant="secondary">Top</Button>
|
|
40
|
+
<Button variant="secondary">Bottom</Button>
|
|
41
|
+
</ButtonGroup>
|
|
42
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Calendar — AI Cheat Sheet
|
|
2
2
|
> Quick reference for Claude / Cursor / Copilot
|
|
3
3
|
|
|
4
|
-
**
|
|
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
|
-
- ❌ `
|
|
19
|
-
→
|
|
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,37 @@
|
|
|
1
|
+
# Combobox — AI Cheat Sheet
|
|
2
|
+
> Quick reference for Claude / Cursor / Copilot
|
|
3
|
+
|
|
4
|
+
**Searchable single-select dropdown with typeahead filtering and keyboard navigation. Use when the list is long enough to need search. Differs from Select (no search) and Command (palette).**
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { Combobox } from "@usevyre/react"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Valid Props
|
|
11
|
+
|
|
12
|
+
| Prop | Values | Default |
|
|
13
|
+
|------|--------|---------|
|
|
14
|
+
| `size` | `"sm"` \| `"md"` \| `"lg"` | `md` |
|
|
15
|
+
| `disabled` | `true` \| `false` | `false` |
|
|
16
|
+
|
|
17
|
+
## Common AI Mistakes
|
|
18
|
+
|
|
19
|
+
- ❌ `Combobox value=""`
|
|
20
|
+
→ Use value={null} for no selection
|
|
21
|
+
- ❌ `Combobox options={string[]}`
|
|
22
|
+
→ Use [{ value: 'ts', label: 'TypeScript' }]
|
|
23
|
+
- ❌ `Using Combobox for command palette`
|
|
24
|
+
→ Use Command for command palettes
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
**Searchable language picker**
|
|
29
|
+
```tsx
|
|
30
|
+
const [lang, setLang] = useState<string | null>(null);
|
|
31
|
+
<Combobox
|
|
32
|
+
options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
|
|
33
|
+
value={lang}
|
|
34
|
+
onChange={setLang}
|
|
35
|
+
placeholder="Search language…"
|
|
36
|
+
/>
|
|
37
|
+
```
|
|
@@ -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,44 @@
|
|
|
1
|
+
# DataGrid — AI Cheat Sheet
|
|
2
|
+
> Quick reference for Claude / Cursor / Copilot
|
|
3
|
+
|
|
4
|
+
**Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.**
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { DataGrid } from "@usevyre/react"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Valid Props
|
|
11
|
+
|
|
12
|
+
| Prop | Values | Default |
|
|
13
|
+
|------|--------|---------|
|
|
14
|
+
| `sortDir` | `"asc"` \| `"desc"` | — |
|
|
15
|
+
| `loading` | `true` \| `false` | `false` |
|
|
16
|
+
| `stickyHeader` | `true` \| `false` | `false` |
|
|
17
|
+
|
|
18
|
+
## Common AI Mistakes
|
|
19
|
+
|
|
20
|
+
- ❌ `DataGrid expecting built-in pagination`
|
|
21
|
+
→ Slice rows yourself and use the Pagination component
|
|
22
|
+
- ❌ `DataGrid expecting built-in filtering`
|
|
23
|
+
→ Filter the rows array before passing it in
|
|
24
|
+
- ❌ `sortable without onSort`
|
|
25
|
+
→ Handle onSort and sort the rows array in your state
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
**Sortable grid**
|
|
30
|
+
```tsx
|
|
31
|
+
const cols = [{ key: "name", label: "Name", sortable: true }];
|
|
32
|
+
<DataGrid
|
|
33
|
+
columns={cols}
|
|
34
|
+
rows={people}
|
|
35
|
+
sortKey={sortKey}
|
|
36
|
+
sortDir={sortDir}
|
|
37
|
+
onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
|
|
38
|
+
/>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Loading state**
|
|
42
|
+
```tsx
|
|
43
|
+
<DataGrid columns={cols} rows={[]} loading />
|
|
44
|
+
```
|
|
@@ -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
|
|
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
|
+
```
|