@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/claude-context.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# useVyre Design System Context
|
|
2
|
-
# Version: 1.
|
|
2
|
+
# Version: 1.2.0
|
|
3
3
|
|
|
4
4
|
You are working in a codebase that uses the useVyre design system.
|
|
5
5
|
Follow the rules below strictly when writing any UI code.
|
|
@@ -311,7 +311,7 @@ import { Button } from "@usevyre/react"
|
|
|
311
311
|
|
|
312
312
|
### Calendar
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
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.
|
|
315
315
|
|
|
316
316
|
```tsx
|
|
317
317
|
import { Calendar } from "@usevyre/react"
|
|
@@ -320,6 +320,7 @@ import { Calendar } from "@usevyre/react"
|
|
|
320
320
|
// value = Date | null
|
|
321
321
|
// onChange = function
|
|
322
322
|
// disabled = boolean (default: false)
|
|
323
|
+
// defaultMonth = Date
|
|
323
324
|
|
|
324
325
|
// Examples:
|
|
325
326
|
const [date, setDate] = useState(null);
|
|
@@ -327,7 +328,39 @@ const [date, setDate] = useState(null);
|
|
|
327
328
|
```
|
|
328
329
|
|
|
329
330
|
**Common mistakes:**
|
|
330
|
-
- ❌ `
|
|
331
|
+
- ❌ `Calendar for an input field that opens a popover` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
|
|
332
|
+
- ❌ `value as tuple for mode="single"` → Pass value matching mode; use mode="range" for [start,end]
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### DatePicker
|
|
337
|
+
|
|
338
|
+
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.
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import { DatePicker } from "@usevyre/react"
|
|
342
|
+
|
|
343
|
+
// Props:
|
|
344
|
+
// value = Date | [Date, Date] | Date[] | null
|
|
345
|
+
// onChange = function
|
|
346
|
+
// mode = "single" | "range" | "multiple" (default: single)
|
|
347
|
+
// placeholder = string (default: Pick a date)
|
|
348
|
+
// showTime = boolean (default: false)
|
|
349
|
+
// minDate = Date
|
|
350
|
+
// maxDate = Date
|
|
351
|
+
// disabled = function
|
|
352
|
+
// weekStartsOn = "0" | "1" (default: 1)
|
|
353
|
+
// inputClassName = string
|
|
354
|
+
|
|
355
|
+
// Examples:
|
|
356
|
+
const [date, setDate] = useState(null);
|
|
357
|
+
<DatePicker value={date} onChange={setDate} placeholder="Pick a date" />
|
|
358
|
+
<DatePicker value={date} onChange={setDate} showTime />
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Common mistakes:**
|
|
362
|
+
- ❌ `DatePicker mode="range" for { from, to } object` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
|
|
363
|
+
- ❌ `DatePicker without value/onChange` → Provide value and onChange (e.g. from useState)
|
|
331
364
|
|
|
332
365
|
---
|
|
333
366
|
|
|
@@ -387,6 +420,78 @@ import { Checkbox } from "@usevyre/react"
|
|
|
387
420
|
|
|
388
421
|
---
|
|
389
422
|
|
|
423
|
+
### RadioGroup
|
|
424
|
+
|
|
425
|
+
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.
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
import { RadioGroup, Radio } from "@usevyre/react"
|
|
429
|
+
|
|
430
|
+
// Props:
|
|
431
|
+
// value = string
|
|
432
|
+
// defaultValue = string
|
|
433
|
+
// onChange = function
|
|
434
|
+
// name = string
|
|
435
|
+
// disabled = boolean (default: false)
|
|
436
|
+
// size = "sm" | "md" (default: md)
|
|
437
|
+
// orientation = "vertical" | "horizontal" (default: vertical)
|
|
438
|
+
// options = { value: string; label?: string; description?: string; disabled?: boolean }[]
|
|
439
|
+
|
|
440
|
+
// Examples:
|
|
441
|
+
<RadioGroup
|
|
442
|
+
value={plan}
|
|
443
|
+
onChange={setPlan}
|
|
444
|
+
options={[
|
|
445
|
+
{ value: "free", label: "Free", description: "For hobby projects" },
|
|
446
|
+
{ value: "pro", label: "Pro", description: "For teams" },
|
|
447
|
+
]}
|
|
448
|
+
/>
|
|
449
|
+
<RadioGroup value={plan} onChange={setPlan} orientation="horizontal">
|
|
450
|
+
<Radio value="free" label="Free" />
|
|
451
|
+
<Radio value="pro" label="Pro" />
|
|
452
|
+
</RadioGroup>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Common mistakes:**
|
|
456
|
+
- ❌ `<Radio> used outside a <RadioGroup>` → Always wrap <Radio> in <RadioGroup>
|
|
457
|
+
- ❌ `RadioGroup without value/onChange (React) or v-model (Vue)` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
|
|
458
|
+
- ❌ `Using Checkbox for mutually-exclusive choices` → Use RadioGroup + Radio (or options) for one-of-many
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
### RichTextEditor
|
|
463
|
+
|
|
464
|
+
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.
|
|
465
|
+
|
|
466
|
+
```tsx
|
|
467
|
+
import { RichTextEditor } from "@usevyre/react"
|
|
468
|
+
|
|
469
|
+
// Props:
|
|
470
|
+
// value = string
|
|
471
|
+
// onChange = function
|
|
472
|
+
// placeholder = string (default: Write something…)
|
|
473
|
+
// disabled = boolean (default: false)
|
|
474
|
+
// readOnly = boolean (default: false)
|
|
475
|
+
// toolbar = RichTextTool[]
|
|
476
|
+
// minHeight = string (default: 10rem)
|
|
477
|
+
|
|
478
|
+
// Examples:
|
|
479
|
+
const [html, setHtml] = useState("<p>Hello <strong>world</strong></p>");
|
|
480
|
+
<RichTextEditor value={html} onChange={setHtml} placeholder="Write…" />
|
|
481
|
+
<RichTextEditor
|
|
482
|
+
value={html}
|
|
483
|
+
onChange={setHtml}
|
|
484
|
+
toolbar={["bold", "italic", "link"]}
|
|
485
|
+
/>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Common mistakes:**
|
|
489
|
+
- ❌ `RichTextEditor without value/onChange (React) or v-model (Vue)` → Keep the HTML string in state and update it in onChange / v-model
|
|
490
|
+
- ❌ `Rendering value as text or with dangerouslySetInnerHTML elsewhere without sanitising` → Sanitise (e.g. DOMPurify) before re-rendering untrusted RTE output
|
|
491
|
+
- ❌ `toolbar="bold" (string)` → Pass an array, e.g. toolbar={["bold","italic","link"]}
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
390
495
|
### Command
|
|
391
496
|
|
|
392
497
|
Command palette / search dialog. Use for search-first navigation or quick actions.
|
|
@@ -438,7 +543,7 @@ import { DropdownMenu, DropdownItem, DropdownSeparator, DropdownCheckboxItem, Dr
|
|
|
438
543
|
|
|
439
544
|
### Field
|
|
440
545
|
|
|
441
|
-
Form field wrapper
|
|
546
|
+
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.
|
|
442
547
|
|
|
443
548
|
```tsx
|
|
444
549
|
import { Field, Input, Textarea } from "@usevyre/react"
|
|
@@ -456,10 +561,23 @@ import { Field, Input, Textarea } from "@usevyre/react"
|
|
|
456
561
|
<Field label="Search">
|
|
457
562
|
<Input leftElement={<SearchIcon />} placeholder="Search..." />
|
|
458
563
|
</Field>
|
|
564
|
+
<Field>
|
|
565
|
+
<FieldLabel required htmlFor="email">Email</FieldLabel>
|
|
566
|
+
<Input id="email" type="email" />
|
|
567
|
+
<FieldDescription>We\u2019ll never share it.</FieldDescription>
|
|
568
|
+
<FieldError>{errors.email}</FieldError>
|
|
569
|
+
</Field>
|
|
570
|
+
|
|
571
|
+
// Two controls side by side
|
|
572
|
+
<FieldGroup orientation="horizontal">
|
|
573
|
+
<Field label="First name"><Input /></Field>
|
|
574
|
+
<Field label="Last name"><Input /></Field>
|
|
575
|
+
</FieldGroup>
|
|
459
576
|
```
|
|
460
577
|
|
|
461
578
|
**Common mistakes:**
|
|
462
579
|
- ❌ `Applying state prop directly to Input` → Wrap Input in <Field state="error"> to apply validation styling
|
|
580
|
+
- ❌ `Mixing props label/hint AND FieldLabel/FieldError for the same field` → Pick one: either props-based (label/hint/state) OR composable parts
|
|
463
581
|
|
|
464
582
|
---
|
|
465
583
|
|
|
@@ -471,6 +589,7 @@ Text input field. Wrap in Field for labels and validation. Use leftElement/right
|
|
|
471
589
|
import { Input } from "@usevyre/react"
|
|
472
590
|
|
|
473
591
|
// Props:
|
|
592
|
+
// modelValue = string | number
|
|
474
593
|
// size = "sm" | "md" | "lg" (default: md)
|
|
475
594
|
// leftElement = ReactNode
|
|
476
595
|
// rightElement = ReactNode
|
|
@@ -482,6 +601,7 @@ import { Input } from "@usevyre/react"
|
|
|
482
601
|
**Common mistakes:**
|
|
483
602
|
- ❌ `size="icon"` → Use size="sm" | "md" | "lg"
|
|
484
603
|
- ❌ `type="search" for search UI` → Import Command from @usevyre/react for search palettes
|
|
604
|
+
- ❌ `Vue: binding Input/Textarea value without v-model` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
|
|
485
605
|
|
|
486
606
|
---
|
|
487
607
|
|
|
@@ -887,6 +1007,362 @@ import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"
|
|
|
887
1007
|
|
|
888
1008
|
---
|
|
889
1009
|
|
|
1010
|
+
### ButtonGroup
|
|
1011
|
+
|
|
1012
|
+
Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
|
|
1013
|
+
|
|
1014
|
+
```tsx
|
|
1015
|
+
import { ButtonGroup, Button } from "@usevyre/react"
|
|
1016
|
+
|
|
1017
|
+
// Props:
|
|
1018
|
+
// orientation = "horizontal" | "vertical" (default: horizontal)
|
|
1019
|
+
// attached = boolean (default: false)
|
|
1020
|
+
// size = "sm" | "md" | "lg" | "icon"
|
|
1021
|
+
|
|
1022
|
+
// Examples:
|
|
1023
|
+
<ButtonGroup attached>
|
|
1024
|
+
<Button variant="secondary">Day</Button>
|
|
1025
|
+
<Button variant="secondary">Week</Button>
|
|
1026
|
+
<Button variant="secondary">Month</Button>
|
|
1027
|
+
</ButtonGroup>
|
|
1028
|
+
<ButtonGroup orientation="vertical" attached>
|
|
1029
|
+
<Button variant="secondary">Top</Button>
|
|
1030
|
+
<Button variant="secondary">Bottom</Button>
|
|
1031
|
+
</ButtonGroup>
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
**Common mistakes:**
|
|
1035
|
+
- ❌ `ButtonGroup variant="..."` → Set variant on each <Button> inside the group
|
|
1036
|
+
- ❌ `ButtonGroup without Button children` → Place <Button> elements as direct children
|
|
1037
|
+
|
|
1038
|
+
---
|
|
1039
|
+
|
|
1040
|
+
### TagsInput
|
|
1041
|
+
|
|
1042
|
+
Multi-tag input. Type and press Enter or comma to add a tag, click x to remove, Backspace on empty input removes the last tag. Controlled.
|
|
1043
|
+
|
|
1044
|
+
```tsx
|
|
1045
|
+
import { TagsInput } from "@usevyre/react"
|
|
1046
|
+
|
|
1047
|
+
// Props:
|
|
1048
|
+
// value = string[]
|
|
1049
|
+
// onChange = (tags: string[]) => void
|
|
1050
|
+
// placeholder = string
|
|
1051
|
+
// disabled = boolean (default: false)
|
|
1052
|
+
// max = number
|
|
1053
|
+
// size = "sm" | "md" | "lg" (default: md)
|
|
1054
|
+
|
|
1055
|
+
// Examples:
|
|
1056
|
+
const [tags, setTags] = useState<string[]>([]);
|
|
1057
|
+
<TagsInput value={tags} onChange={setTags} placeholder="Add a tag…" />
|
|
1058
|
+
<TagsInput value={tags} onChange={setTags} max={5} />
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
**Common mistakes:**
|
|
1062
|
+
- ❌ `TagsInput value={string}` → Pass an array: value={['react','vue']}
|
|
1063
|
+
- ❌ `TagsInput without onChange` → Provide value and onChange (React) or v-model (Vue)
|
|
1064
|
+
|
|
1065
|
+
---
|
|
1066
|
+
|
|
1067
|
+
### Combobox
|
|
1068
|
+
|
|
1069
|
+
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).
|
|
1070
|
+
|
|
1071
|
+
```tsx
|
|
1072
|
+
import { Combobox } from "@usevyre/react"
|
|
1073
|
+
|
|
1074
|
+
// Props:
|
|
1075
|
+
// options = { value: string; label: string; disabled?: boolean }[]
|
|
1076
|
+
// value = string | null
|
|
1077
|
+
// onChange = (value: string | null) => void
|
|
1078
|
+
// placeholder = string (default: "Search…")
|
|
1079
|
+
// disabled = boolean (default: false)
|
|
1080
|
+
// size = "sm" | "md" | "lg" (default: md)
|
|
1081
|
+
// emptyText = string (default: "No results")
|
|
1082
|
+
|
|
1083
|
+
// Examples:
|
|
1084
|
+
const [lang, setLang] = useState<string | null>(null);
|
|
1085
|
+
<Combobox
|
|
1086
|
+
options={[{ value: "ts", label: "TypeScript" }, { value: "go", label: "Go" }]}
|
|
1087
|
+
value={lang}
|
|
1088
|
+
onChange={setLang}
|
|
1089
|
+
placeholder="Search language…"
|
|
1090
|
+
/>
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
**Common mistakes:**
|
|
1094
|
+
- ❌ `Combobox value=""` → Use value={null} for no selection
|
|
1095
|
+
- ❌ `Combobox options={string[]}` → Use [{ value: 'ts', label: 'TypeScript' }]
|
|
1096
|
+
- ❌ `Using Combobox for command palette` → Use Command for command palettes
|
|
1097
|
+
|
|
1098
|
+
---
|
|
1099
|
+
|
|
1100
|
+
### DataGrid
|
|
1101
|
+
|
|
1102
|
+
Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
|
|
1103
|
+
|
|
1104
|
+
```tsx
|
|
1105
|
+
import { DataGrid } from "@usevyre/react"
|
|
1106
|
+
|
|
1107
|
+
// Props:
|
|
1108
|
+
// columns = { key: string; label: string; sortable?: boolean; width?: string }[]
|
|
1109
|
+
// rows = Record<string, unknown>[]
|
|
1110
|
+
// sortKey = string
|
|
1111
|
+
// sortDir = "asc" | "desc"
|
|
1112
|
+
// onSort = (key: string, dir: 'asc' | 'desc') => void
|
|
1113
|
+
// loading = boolean (default: false)
|
|
1114
|
+
// emptyText = string (default: "No data")
|
|
1115
|
+
// stickyHeader = boolean (default: false)
|
|
1116
|
+
|
|
1117
|
+
// Examples:
|
|
1118
|
+
const cols = [{ key: "name", label: "Name", sortable: true }];
|
|
1119
|
+
<DataGrid
|
|
1120
|
+
columns={cols}
|
|
1121
|
+
rows={people}
|
|
1122
|
+
sortKey={sortKey}
|
|
1123
|
+
sortDir={sortDir}
|
|
1124
|
+
onSort={(k, d) => { setSortKey(k); setSortDir(d); }}
|
|
1125
|
+
/>
|
|
1126
|
+
<DataGrid columns={cols} rows={[]} loading />
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
**Common mistakes:**
|
|
1130
|
+
- ❌ `DataGrid expecting built-in pagination` → Slice rows yourself and use the Pagination component
|
|
1131
|
+
- ❌ `DataGrid expecting built-in filtering` → Filter the rows array before passing it in
|
|
1132
|
+
- ❌ `sortable without onSort` → Handle onSort and sort the rows array in your state
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
### Tag
|
|
1137
|
+
|
|
1138
|
+
Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
|
|
1139
|
+
|
|
1140
|
+
```tsx
|
|
1141
|
+
import { Tag } from "@usevyre/react"
|
|
1142
|
+
|
|
1143
|
+
// Props:
|
|
1144
|
+
// variant = "default" | "accent" | "danger" (default: default)
|
|
1145
|
+
// size = "sm" | "md" | "lg" (default: md)
|
|
1146
|
+
// onRemove = () => void
|
|
1147
|
+
// onClick = () => void
|
|
1148
|
+
// disabled = boolean (default: false)
|
|
1149
|
+
|
|
1150
|
+
// Examples:
|
|
1151
|
+
<TagGroup>
|
|
1152
|
+
<Tag>Design</Tag>
|
|
1153
|
+
<Tag variant="accent">Featured</Tag>
|
|
1154
|
+
<Tag>Engineering</Tag>
|
|
1155
|
+
</TagGroup>
|
|
1156
|
+
<Tag onRemove={() => removeFilter("react")}>react</Tag>
|
|
1157
|
+
<Tag onClick={() => toggleFilter("vue")}>vue</Tag>
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
**Common mistakes:**
|
|
1161
|
+
- ❌ `Tag variant="success"` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
|
|
1162
|
+
- ❌ `Using Tag for tag input` → Use TagsInput for adding/removing tags via keyboard
|
|
1163
|
+
- ❌ `Tag size="xl"` → Use size="lg"
|
|
1164
|
+
|
|
1165
|
+
---
|
|
1166
|
+
|
|
1167
|
+
### TagGroup
|
|
1168
|
+
|
|
1169
|
+
Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
|
|
1170
|
+
|
|
1171
|
+
```tsx
|
|
1172
|
+
import { TagGroup, Tag } from "@usevyre/react"
|
|
1173
|
+
|
|
1174
|
+
// Props:
|
|
1175
|
+
// gap = "sm" | "md" | "lg" (default: md)
|
|
1176
|
+
// wrap = boolean (default: true)
|
|
1177
|
+
|
|
1178
|
+
// Examples:
|
|
1179
|
+
<TagGroup gap="sm">
|
|
1180
|
+
<Tag>React</Tag>
|
|
1181
|
+
<Tag>Vue</Tag>
|
|
1182
|
+
<Tag variant="accent">TypeScript</Tag>
|
|
1183
|
+
</TagGroup>
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
**Common mistakes:**
|
|
1187
|
+
- ❌ `TagGroup without Tag children` → Place <Tag> elements as direct children
|
|
1188
|
+
- ❌ `Using TagGroup for tag input` → Use TagsInput for an editable tag field
|
|
1189
|
+
|
|
1190
|
+
---
|
|
1191
|
+
|
|
1192
|
+
### Item
|
|
1193
|
+
|
|
1194
|
+
Layout primitive for list rows, settings rows, and notification rows. Denser than Card — use Item (not Card) for repeated list rows.
|
|
1195
|
+
|
|
1196
|
+
```tsx
|
|
1197
|
+
import { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemGroup } from "@usevyre/react"
|
|
1198
|
+
|
|
1199
|
+
// Props:
|
|
1200
|
+
// variant = "default" | "outlined" | "muted" | "plain" (default: default)
|
|
1201
|
+
// size = "sm" | "md" | "lg" (default: md)
|
|
1202
|
+
// clickable = boolean (default: false)
|
|
1203
|
+
|
|
1204
|
+
// Examples:
|
|
1205
|
+
<Item>
|
|
1206
|
+
<ItemMedia><BellIcon /></ItemMedia>
|
|
1207
|
+
<ItemContent>
|
|
1208
|
+
<ItemTitle>Notifications</ItemTitle>
|
|
1209
|
+
<ItemDescription>Receive an email when someone mentions you.</ItemDescription>
|
|
1210
|
+
</ItemContent>
|
|
1211
|
+
<ItemActions>
|
|
1212
|
+
<Switch defaultChecked />
|
|
1213
|
+
</ItemActions>
|
|
1214
|
+
</Item>
|
|
1215
|
+
<ItemGroup separated>
|
|
1216
|
+
<Item clickable>
|
|
1217
|
+
<ItemContent><ItemTitle>Profile</ItemTitle></ItemContent>
|
|
1218
|
+
</Item>
|
|
1219
|
+
<Item clickable>
|
|
1220
|
+
<ItemContent><ItemTitle>Billing</ItemTitle></ItemContent>
|
|
1221
|
+
</Item>
|
|
1222
|
+
</ItemGroup>
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
**Common mistakes:**
|
|
1226
|
+
- ❌ `Card used for repeated list rows` → Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows
|
|
1227
|
+
- ❌ `Item variant="primary"` → Use variant="default" | "outlined" | "muted"
|
|
1228
|
+
- ❌ `raw text directly inside Item` → Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>
|
|
1229
|
+
|
|
1230
|
+
---
|
|
1231
|
+
|
|
1232
|
+
### Kanban
|
|
1233
|
+
|
|
1234
|
+
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.
|
|
1235
|
+
|
|
1236
|
+
```tsx
|
|
1237
|
+
import { Kanban } from "@usevyre/react"
|
|
1238
|
+
|
|
1239
|
+
// Props:
|
|
1240
|
+
// value = KanbanColumn[]
|
|
1241
|
+
// onChange = function
|
|
1242
|
+
// renderCard = function
|
|
1243
|
+
// onCardClick = function
|
|
1244
|
+
|
|
1245
|
+
// Examples:
|
|
1246
|
+
const [columns, setColumns] = useState([
|
|
1247
|
+
{ id: "todo", title: "To Do", cards: [{ id: "1", title: "Spec API" }] },
|
|
1248
|
+
{ id: "doing", title: "In Progress", cards: [] },
|
|
1249
|
+
{ id: "done", title: "Done", cards: [{ id: "2", title: "Kickoff" }] },
|
|
1250
|
+
]);
|
|
1251
|
+
<Kanban value={columns} onChange={setColumns} />
|
|
1252
|
+
<Kanban
|
|
1253
|
+
value={columns}
|
|
1254
|
+
onChange={setColumns}
|
|
1255
|
+
onCardClick={(card) => openDetail(card.id)}
|
|
1256
|
+
renderCard={(card) => (
|
|
1257
|
+
<><strong>{card.title}</strong><Badge>{card.id}</Badge></>
|
|
1258
|
+
)}
|
|
1259
|
+
/>
|
|
1260
|
+
const [cols, setCols] = useState([
|
|
1261
|
+
{ id: "doing", title: "In Progress", color: "teal", cards: [
|
|
1262
|
+
{ id: "t1", title: "OAuth", assignee: "AK", progress: 60, color: "warning" },
|
|
1263
|
+
]},
|
|
1264
|
+
]);
|
|
1265
|
+
<Kanban
|
|
1266
|
+
value={cols}
|
|
1267
|
+
onChange={setCols}
|
|
1268
|
+
renderCard={(card) => (
|
|
1269
|
+
<><strong>{card.title}</strong><Progress value={card.progress} /></>
|
|
1270
|
+
)}
|
|
1271
|
+
/>
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
**Common mistakes:**
|
|
1275
|
+
- ❌ `Kanban without onChange (or ignoring it)` → Store columns in state and setColumns in onChange (v-model in Vue)
|
|
1276
|
+
- ❌ `Duplicate card ids across columns` → Use globally-unique card ids across the entire board
|
|
1277
|
+
- ❌ `Mutating value in place then calling onChange` → Pass the new array Kanban gives you straight to setState / v-model
|
|
1278
|
+
- ❌ `color="blue" (or any non-semantic value)` → Use one of: "default" | "accent" | "teal" | "success" | "warning" | "danger"
|
|
1279
|
+
|
|
1280
|
+
---
|
|
1281
|
+
|
|
1282
|
+
### Conversation
|
|
1283
|
+
|
|
1284
|
+
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.
|
|
1285
|
+
|
|
1286
|
+
```tsx
|
|
1287
|
+
import { Conversation } from "@usevyre/react"
|
|
1288
|
+
|
|
1289
|
+
// Props:
|
|
1290
|
+
// value = ConversationMessage[]
|
|
1291
|
+
// currentUserId = string
|
|
1292
|
+
// composer = boolean (default: false)
|
|
1293
|
+
// onSend = function
|
|
1294
|
+
// placeholder = string (default: Write a message…)
|
|
1295
|
+
// typing = boolean | string (default: false)
|
|
1296
|
+
// allowAttachments = boolean (default: false)
|
|
1297
|
+
// accept = string
|
|
1298
|
+
// renderMessage = function
|
|
1299
|
+
// renderComposer = function
|
|
1300
|
+
|
|
1301
|
+
// Examples:
|
|
1302
|
+
const [messages, setMessages] = useState([
|
|
1303
|
+
{ id: "1", authorId: "sam", authorName: "Sam", text: "Hey!" },
|
|
1304
|
+
{ id: "2", authorId: "me", text: "Hi \ud83d\udc4b", status: "read" },
|
|
1305
|
+
]);
|
|
1306
|
+
<Conversation
|
|
1307
|
+
value={messages}
|
|
1308
|
+
currentUserId="me"
|
|
1309
|
+
composer
|
|
1310
|
+
onSend={(t) => setMessages((m) => [...m, { id: crypto.randomUUID(), authorId: "me", text: t }])}
|
|
1311
|
+
/>
|
|
1312
|
+
<Conversation
|
|
1313
|
+
value={messages}
|
|
1314
|
+
currentUserId="me"
|
|
1315
|
+
typing="Sam is typing"
|
|
1316
|
+
renderMessage={(m) => <strong>{m.text}</strong>}
|
|
1317
|
+
/>
|
|
1318
|
+
const messages = [
|
|
1319
|
+
{ id: "1", authorId: "sam", authorName: "Sam", text: "Moodboard \ud83d\udc47",
|
|
1320
|
+
attachments: [{ kind: "image", url: "/board.png", name: "board.png" }] },
|
|
1321
|
+
{ id: "2", authorId: "me", text: "Specs:", status: "read",
|
|
1322
|
+
attachments: [{ kind: "file", url: "/spec.pdf", name: "spec.pdf", size: "2.4 MB" }] },
|
|
1323
|
+
];
|
|
1324
|
+
<Conversation value={messages} currentUserId="me" />
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
**Common mistakes:**
|
|
1328
|
+
- ❌ `Conversation without currentUserId` → Always pass currentUserId matching one of the message authorId values
|
|
1329
|
+
- ❌ `Expecting Conversation to store/append messages` → Append to your own state in onSend (or @send) and pass it back via value
|
|
1330
|
+
- ❌ `composer without onSend (React) / @send (Vue)` → Provide onSend / @send to append the message to value
|
|
1331
|
+
- ❌ `Treating onSend as (text) only when using allowAttachments` → Handle onSend(text, files) — map files to message attachments and append
|
|
1332
|
+
|
|
1333
|
+
---
|
|
1334
|
+
|
|
1335
|
+
### DateRangePicker
|
|
1336
|
+
|
|
1337
|
+
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.
|
|
1338
|
+
|
|
1339
|
+
```tsx
|
|
1340
|
+
import { DateRangePicker } from "@usevyre/react"
|
|
1341
|
+
|
|
1342
|
+
// Props:
|
|
1343
|
+
// value = { from: Date | null; to: Date | null } | null
|
|
1344
|
+
// onChange = function
|
|
1345
|
+
// placeholder = string (default: Pick a date range)
|
|
1346
|
+
// numberOfMonths = "1" | "2" (default: 2)
|
|
1347
|
+
// presets = boolean | DateRangePreset[] (default: false)
|
|
1348
|
+
// minDate = Date
|
|
1349
|
+
// maxDate = Date
|
|
1350
|
+
// disabled = function
|
|
1351
|
+
// weekStartsOn = "0" | "1" (default: 1)
|
|
1352
|
+
|
|
1353
|
+
// Examples:
|
|
1354
|
+
const [range, setRange] = useState({ from: null, to: null });
|
|
1355
|
+
<DateRangePicker value={range} onChange={setRange} presets />
|
|
1356
|
+
<DateRangePicker value={range} onChange={setRange} numberOfMonths={1} />
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
**Common mistakes:**
|
|
1360
|
+
- ❌ `value={[from, to]}` → Use value={{ from, to }} and read range.from / range.to
|
|
1361
|
+
- ❌ `DateRangePicker for a single date` → Use <DatePicker /> for a single date
|
|
1362
|
+
- ❌ `presets="true" (string)` → Use the bare prop: presets (or presets={true})
|
|
1363
|
+
|
|
1364
|
+
---
|
|
1365
|
+
|
|
890
1366
|
## Hallucination Guard — Common AI Mistakes
|
|
891
1367
|
|
|
892
1368
|
The following prop values and patterns do NOT exist in useVyre.
|
|
@@ -906,14 +1382,25 @@ If you generate these, you are hallucinating.
|
|
|
906
1382
|
- ❌ `<Button color="...">` → Use variant prop instead
|
|
907
1383
|
- ❌ `<Button icon={...}>` → Use leftIcon={...} or rightIcon={...}
|
|
908
1384
|
- ❌ `<Button size="icon" without aria-label>` → Add aria-label describing the action
|
|
909
|
-
- ❌ `<Calendar
|
|
1385
|
+
- ❌ `<Calendar Calendar for an input field that opens a popover>` → Use <DatePicker /> (single date) or <DateRangePicker /> (range)
|
|
1386
|
+
- ❌ `<Calendar value as tuple for mode="single">` → Pass value matching mode; use mode="range" for [start,end]
|
|
1387
|
+
- ❌ `<DatePicker DatePicker mode="range" for { from, to } object>` → Use <DateRangePicker /> for the { from, to } object API + presets + dual month
|
|
1388
|
+
- ❌ `<DatePicker DatePicker without value/onChange>` → Provide value and onChange (e.g. from useState)
|
|
910
1389
|
- ❌ `<Card variant="primary">` → Use variant="elevated" | "outlined" | "ghost" | "accent"
|
|
911
1390
|
- ❌ `<Checkbox size="lg">` → Use size="md"
|
|
1391
|
+
- ❌ `<RadioGroup <Radio> used outside a <RadioGroup>>` → Always wrap <Radio> in <RadioGroup>
|
|
1392
|
+
- ❌ `<RadioGroup RadioGroup without value/onChange (React) or v-model (Vue)>` → Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
|
|
1393
|
+
- ❌ `<RadioGroup Using Checkbox for mutually-exclusive choices>` → Use RadioGroup + Radio (or options) for one-of-many
|
|
1394
|
+
- ❌ `<RichTextEditor RichTextEditor without value/onChange (React) or v-model (Vue)>` → Keep the HTML string in state and update it in onChange / v-model
|
|
1395
|
+
- ❌ `<RichTextEditor Rendering value as text or with dangerouslySetInnerHTML elsewhere without sanitising>` → Sanitise (e.g. DOMPurify) before re-rendering untrusted RTE output
|
|
1396
|
+
- ❌ `<RichTextEditor toolbar="bold" (string)>` → Pass an array, e.g. toolbar={["bold","italic","link"]}
|
|
912
1397
|
- ❌ `<Command Using Input type="search" for search UI>` → Use Command + CommandInput + CommandList + CommandItem
|
|
913
1398
|
- ❌ `<DropdownMenu DropdownItem variant="primary">` → Use variant="danger" for destructive items only
|
|
914
1399
|
- ❌ `<Field Applying state prop directly to Input>` → Wrap Input in <Field state="error"> to apply validation styling
|
|
1400
|
+
- ❌ `<Field Mixing props label/hint AND FieldLabel/FieldError for the same field>` → Pick one: either props-based (label/hint/state) OR composable parts
|
|
915
1401
|
- ❌ `<Input size="icon">` → Use size="sm" | "md" | "lg"
|
|
916
1402
|
- ❌ `<Input type="search" for search UI>` → Import Command from @usevyre/react for search palettes
|
|
1403
|
+
- ❌ `<Input Vue: binding Input/Textarea value without v-model>` → Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
|
|
917
1404
|
- ❌ `<Modal size="xl">` → Use size="lg" or size="full"
|
|
918
1405
|
- ❌ `<Popover placement="top-center">` → Use placement="top" for centered placement
|
|
919
1406
|
- ❌ `<Progress value > 100>` → Normalize your value to 0–100 range before passing
|
|
@@ -923,6 +1410,35 @@ If you generate these, you are hallucinating.
|
|
|
923
1410
|
- ❌ `<Toast variant="info">` → Use variant="default"
|
|
924
1411
|
- ❌ `<Tooltip Using Tooltip for rich content (forms, buttons, etc.)>` → Use Popover for rich interactive content
|
|
925
1412
|
- ❌ `<Typography Using raw <h1>, <p> tags instead of Typography components>` → Use <Heading>, <Text>, <Lead> from @usevyre/react
|
|
1413
|
+
- ❌ `<ButtonGroup ButtonGroup variant="...">` → Set variant on each <Button> inside the group
|
|
1414
|
+
- ❌ `<ButtonGroup ButtonGroup without Button children>` → Place <Button> elements as direct children
|
|
1415
|
+
- ❌ `<TagsInput TagsInput value={string}>` → Pass an array: value={['react','vue']}
|
|
1416
|
+
- ❌ `<TagsInput TagsInput without onChange>` → Provide value and onChange (React) or v-model (Vue)
|
|
1417
|
+
- ❌ `<Combobox Combobox value="">` → Use value={null} for no selection
|
|
1418
|
+
- ❌ `<Combobox Combobox options={string[]}>` → Use [{ value: 'ts', label: 'TypeScript' }]
|
|
1419
|
+
- ❌ `<Combobox Using Combobox for command palette>` → Use Command for command palettes
|
|
1420
|
+
- ❌ `<DataGrid DataGrid expecting built-in pagination>` → Slice rows yourself and use the Pagination component
|
|
1421
|
+
- ❌ `<DataGrid DataGrid expecting built-in filtering>` → Filter the rows array before passing it in
|
|
1422
|
+
- ❌ `<DataGrid sortable without onSort>` → Handle onSort and sort the rows array in your state
|
|
1423
|
+
- ❌ `<Tag Tag variant="success">` → Use Badge for success/warning/teal status colors; Tag is for categories/filters
|
|
1424
|
+
- ❌ `<Tag Using Tag for tag input>` → Use TagsInput for adding/removing tags via keyboard
|
|
1425
|
+
- ❌ `<Tag Tag size="xl">` → Use size="lg"
|
|
1426
|
+
- ❌ `<TagGroup TagGroup without Tag children>` → Place <Tag> elements as direct children
|
|
1427
|
+
- ❌ `<TagGroup Using TagGroup for tag input>` → Use TagsInput for an editable tag field
|
|
1428
|
+
- ❌ `<Item Card used for repeated list rows>` → Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows
|
|
1429
|
+
- ❌ `<Item Item variant="primary">` → Use variant="default" | "outlined" | "muted"
|
|
1430
|
+
- ❌ `<Item raw text directly inside Item>` → Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>
|
|
1431
|
+
- ❌ `<Kanban Kanban without onChange (or ignoring it)>` → Store columns in state and setColumns in onChange (v-model in Vue)
|
|
1432
|
+
- ❌ `<Kanban Duplicate card ids across columns>` → Use globally-unique card ids across the entire board
|
|
1433
|
+
- ❌ `<Kanban Mutating value in place then calling onChange>` → Pass the new array Kanban gives you straight to setState / v-model
|
|
1434
|
+
- ❌ `<Kanban color="blue" (or any non-semantic value)>` → Use one of: "default" | "accent" | "teal" | "success" | "warning" | "danger"
|
|
1435
|
+
- ❌ `<Conversation Conversation without currentUserId>` → Always pass currentUserId matching one of the message authorId values
|
|
1436
|
+
- ❌ `<Conversation Expecting Conversation to store/append messages>` → Append to your own state in onSend (or @send) and pass it back via value
|
|
1437
|
+
- ❌ `<Conversation composer without onSend (React) / @send (Vue)>` → Provide onSend / @send to append the message to value
|
|
1438
|
+
- ❌ `<Conversation Treating onSend as (text) only when using allowAttachments>` → Handle onSend(text, files) — map files to message attachments and append
|
|
1439
|
+
- ❌ `<DateRangePicker value={[from, to]}>` → Use value={{ from, to }} and read range.from / range.to
|
|
1440
|
+
- ❌ `<DateRangePicker DateRangePicker for a single date>` → Use <DatePicker /> for a single date
|
|
1441
|
+
- ❌ `<DateRangePicker presets="true" (string)>` → Use the bare prop: presets (or presets={true})
|
|
926
1442
|
|
|
927
1443
|
---
|
|
928
1444
|
|