@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.
@@ -4,7 +4,7 @@ alwaysApply: true
4
4
  ---
5
5
 
6
6
  # useVyre Design System — Cursor Rules
7
- # Version: 1.0.0
7
+ # Version: 1.2.0
8
8
 
9
9
  You are working in a project using the useVyre design system (@usevyre/react).
10
10
  Follow these rules strictly when generating any UI code.
@@ -83,13 +83,26 @@ Never do:
83
83
  - ❌ size="icon" without aria-label → ✅ Add aria-label describing the action
84
84
 
85
85
  ## Calendar
86
- Date picker calendar widget for selecting single dates or ranges.
86
+ 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.
87
87
  Import: `import { Calendar } from "@usevyre/react"`
88
88
 
89
89
  Valid props:
90
90
 
91
91
  Never do:
92
- - ❌ Using Calendar for time selection → ✅ Combine with a separate time Input if time selection is needed
92
+ - ❌ Calendar for an input field that opens a popover → ✅ Use <DatePicker /> (single date) or <DateRangePicker /> (range)
93
+ - ❌ value as tuple for mode="single" → ✅ Pass value matching mode; use mode="range" for [start,end]
94
+
95
+ ## DatePicker
96
+ 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.
97
+ Import: `import { DatePicker } from "@usevyre/react"`
98
+
99
+ Valid props:
100
+ - mode: "single" | "range" | "multiple" [default: single]
101
+ - weekStartsOn: "0" | "1" [default: 1]
102
+
103
+ Never do:
104
+ - ❌ DatePicker mode="range" for { from, to } object → ✅ Use <DateRangePicker /> for the { from, to } object API + presets + dual month
105
+ - ❌ DatePicker without value/onChange → ✅ Provide value and onChange (e.g. from useState)
93
106
 
94
107
  ## Card
95
108
  Content container with optional header, body, and footer sections.
@@ -111,6 +124,30 @@ Valid props:
111
124
  Never do:
112
125
  - ❌ size="lg" → ✅ Use size="md"
113
126
 
127
+ ## RadioGroup
128
+ 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.
129
+ Import: `import { RadioGroup, Radio } from "@usevyre/react"`
130
+
131
+ Valid props:
132
+ - size: "sm" | "md" [default: md]
133
+ - orientation: "vertical" | "horizontal" [default: vertical]
134
+
135
+ Never do:
136
+ - ❌ <Radio> used outside a <RadioGroup> → ✅ Always wrap <Radio> in <RadioGroup>
137
+ - ❌ RadioGroup without value/onChange (React) or v-model (Vue) → ✅ Bind value + onChange (React) or v-model (Vue); or defaultValue for uncontrolled in React
138
+ - ❌ Using Checkbox for mutually-exclusive choices → ✅ Use RadioGroup + Radio (or options) for one-of-many
139
+
140
+ ## RichTextEditor
141
+ 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.
142
+ Import: `import { RichTextEditor } from "@usevyre/react"`
143
+
144
+ Valid props:
145
+
146
+ Never do:
147
+ - ❌ RichTextEditor without value/onChange (React) or v-model (Vue) → ✅ Keep the HTML string in state and update it in onChange / v-model
148
+ - ❌ Rendering value as text or with dangerouslySetInnerHTML elsewhere without sanitising → ✅ Sanitise (e.g. DOMPurify) before re-rendering untrusted RTE output
149
+ - ❌ toolbar="bold" (string) → ✅ Pass an array, e.g. toolbar={["bold","italic","link"]}
150
+
114
151
  ## Command
115
152
  Command palette / search dialog. Use for search-first navigation or quick actions.
116
153
  Import: `import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandDialog } from "@usevyre/react"`
@@ -128,7 +165,7 @@ Never do:
128
165
  - ❌ DropdownItem variant="primary" → ✅ Use variant="danger" for destructive items only
129
166
 
130
167
  ## Field
131
- Form field wrapper providing label, hint text, and validation state for Input or Textarea.
168
+ 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.
132
169
  Import: `import { Field, Input, Textarea } from "@usevyre/react"`
133
170
 
134
171
  Valid props:
@@ -136,6 +173,7 @@ Valid props:
136
173
 
137
174
  Never do:
138
175
  - ❌ Applying state prop directly to Input → ✅ Wrap Input in <Field state="error"> to apply validation styling
176
+ - ❌ Mixing props label/hint AND FieldLabel/FieldError for the same field → ✅ Pick one: either props-based (label/hint/state) OR composable parts
139
177
 
140
178
  ## Input
141
179
  Text input field. Wrap in Field for labels and validation. Use leftElement/rightElement for icons.
@@ -147,6 +185,7 @@ Valid props:
147
185
  Never do:
148
186
  - ❌ size="icon" → ✅ Use size="sm" | "md" | "lg"
149
187
  - ❌ type="search" for search UI → ✅ Import Command from @usevyre/react for search palettes
188
+ - ❌ Vue: binding Input/Textarea value without v-model → ✅ Use v-model on <Input>/<Textarea> in Vue; in React use value + onChange
150
189
 
151
190
  ## Label
152
191
  Accessible form label. Associate with input via htmlFor.
@@ -283,6 +322,127 @@ Import: `import { Text, Heading, Lead, Code, Blockquote } from "@usevyre/react"`
283
322
  Never do:
284
323
  - ❌ Using raw <h1>, <p> tags instead of Typography components → ✅ Use <Heading>, <Text>, <Lead> from @usevyre/react
285
324
 
325
+ ## ButtonGroup
326
+ Groups multiple Button components into one visual unit (toolbar, segmented control). Pure layout — no internal state.
327
+ Import: `import { ButtonGroup, Button } from "@usevyre/react"`
328
+
329
+ Valid props:
330
+ - orientation: "horizontal" | "vertical" [default: horizontal]
331
+ - size: "sm" | "md" | "lg" | "icon"
332
+
333
+ Never do:
334
+ - ❌ ButtonGroup variant="..." → ✅ Set variant on each <Button> inside the group
335
+ - ❌ ButtonGroup without Button children → ✅ Place <Button> elements as direct children
336
+
337
+ ## TagsInput
338
+ 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.
339
+ Import: `import { TagsInput } from "@usevyre/react"`
340
+
341
+ Valid props:
342
+ - size: "sm" | "md" | "lg" [default: md]
343
+
344
+ Never do:
345
+ - ❌ TagsInput value={string} → ✅ Pass an array: value={['react','vue']}
346
+ - ❌ TagsInput without onChange → ✅ Provide value and onChange (React) or v-model (Vue)
347
+
348
+ ## Combobox
349
+ 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).
350
+ Import: `import { Combobox } from "@usevyre/react"`
351
+
352
+ Valid props:
353
+ - size: "sm" | "md" | "lg" [default: md]
354
+
355
+ Never do:
356
+ - ❌ Combobox value="" → ✅ Use value={null} for no selection
357
+ - ❌ Combobox options={string[]} → ✅ Use [{ value: 'ts', label: 'TypeScript' }]
358
+ - ❌ Using Combobox for command palette → ✅ Use Command for command palettes
359
+
360
+ ## DataGrid
361
+ Table with built-in column sorting, loading skeletons, and empty state. Filtering and pagination are out of scope — compose with the Pagination component.
362
+ Import: `import { DataGrid } from "@usevyre/react"`
363
+
364
+ Valid props:
365
+ - sortDir: "asc" | "desc"
366
+
367
+ Never do:
368
+ - ❌ DataGrid expecting built-in pagination → ✅ Slice rows yourself and use the Pagination component
369
+ - ❌ DataGrid expecting built-in filtering → ✅ Filter the rows array before passing it in
370
+ - ❌ sortable without onSort → ✅ Handle onSort and sort the rows array in your state
371
+
372
+ ## Tag
373
+ Standalone display tag/chip for categories, labels, or filter chips. NOT an input — for tag input use TagsInput. Group multiple with TagGroup.
374
+ Import: `import { Tag } from "@usevyre/react"`
375
+
376
+ Valid props:
377
+ - variant: "default" | "accent" | "danger" [default: default]
378
+ - size: "sm" | "md" | "lg" [default: md]
379
+
380
+ Never do:
381
+ - ❌ Tag variant="success" → ✅ Use Badge for success/warning/teal status colors; Tag is for categories/filters
382
+ - ❌ Using Tag for tag input → ✅ Use TagsInput for adding/removing tags via keyboard
383
+ - ❌ Tag size="xl" → ✅ Use size="lg"
384
+
385
+ ## TagGroup
386
+ Read-only container that lays out multiple Tag elements with automatic wrapping and consistent spacing. For tag input use TagsInput.
387
+ Import: `import { TagGroup, Tag } from "@usevyre/react"`
388
+
389
+ Valid props:
390
+ - gap: "sm" | "md" | "lg" [default: md]
391
+
392
+ Never do:
393
+ - ❌ TagGroup without Tag children → ✅ Place <Tag> elements as direct children
394
+ - ❌ Using TagGroup for tag input → ✅ Use TagsInput for an editable tag field
395
+
396
+ ## Item
397
+ Layout primitive for list rows, settings rows, and notification rows. Denser than Card — use Item (not Card) for repeated list rows.
398
+ Import: `import { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemGroup } from "@usevyre/react"`
399
+
400
+ Valid props:
401
+ - variant: "default" | "outlined" | "muted" | "plain" [default: default]
402
+ - size: "sm" | "md" | "lg" [default: md]
403
+
404
+ Never do:
405
+ - ❌ Card used for repeated list rows → ✅ Use <Item> (optionally inside <ItemGroup separated>) for list/settings rows
406
+ - ❌ Item variant="primary" → ✅ Use variant="default" | "outlined" | "muted"
407
+ - ❌ raw text directly inside Item → ✅ Wrap text in <ItemContent><ItemTitle>…</ItemTitle></ItemContent>
408
+
409
+ ## Kanban
410
+ 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.
411
+ Import: `import { Kanban } from "@usevyre/react"`
412
+
413
+ Valid props:
414
+
415
+ Never do:
416
+ - ❌ Kanban without onChange (or ignoring it) → ✅ Store columns in state and setColumns in onChange (v-model in Vue)
417
+ - ❌ Duplicate card ids across columns → ✅ Use globally-unique card ids across the entire board
418
+ - ❌ Mutating value in place then calling onChange → ✅ Pass the new array Kanban gives you straight to setState / v-model
419
+ - ❌ color="blue" (or any non-semantic value) → ✅ Use one of: "default" | "accent" | "teal" | "success" | "warning" | "danger"
420
+
421
+ ## Conversation
422
+ 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.
423
+ Import: `import { Conversation } from "@usevyre/react"`
424
+
425
+ Valid props:
426
+
427
+ Never do:
428
+ - ❌ Conversation without currentUserId → ✅ Always pass currentUserId matching one of the message authorId values
429
+ - ❌ Expecting Conversation to store/append messages → ✅ Append to your own state in onSend (or @send) and pass it back via value
430
+ - ❌ composer without onSend (React) / @send (Vue) → ✅ Provide onSend / @send to append the message to value
431
+ - ❌ Treating onSend as (text) only when using allowAttachments → ✅ Handle onSend(text, files) — map files to message attachments and append
432
+
433
+ ## DateRangePicker
434
+ 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.
435
+ Import: `import { DateRangePicker } from "@usevyre/react"`
436
+
437
+ Valid props:
438
+ - numberOfMonths: "1" | "2" [default: 2]
439
+ - weekStartsOn: "0" | "1" [default: 1]
440
+
441
+ Never do:
442
+ - ❌ value={[from, to]} → ✅ Use value={{ from, to }} and read range.from / range.to
443
+ - ❌ DateRangePicker for a single date → ✅ Use <DatePicker /> for a single date
444
+ - ❌ presets="true" (string) → ✅ Use the bare prop: presets (or presets={true})
445
+
286
446
  ## Token Rules
287
447
 
288
448
  Use --vyre-color-semantic-* for all colors. Never use primitive tokens.