@fr0mpy/component-system 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bin/cli.js +283 -0
  2. package/index.js +12 -0
  3. package/package.json +45 -0
  4. package/templates/commands/component-harness.md +116 -0
  5. package/templates/commands/setup-styling.md +111 -0
  6. package/templates/component-recipes/accordion.md +153 -0
  7. package/templates/component-recipes/alert.md +145 -0
  8. package/templates/component-recipes/avatar.md +165 -0
  9. package/templates/component-recipes/badge.md +126 -0
  10. package/templates/component-recipes/breadcrumb.md +220 -0
  11. package/templates/component-recipes/button.md +90 -0
  12. package/templates/component-recipes/card.md +130 -0
  13. package/templates/component-recipes/carousel.md +277 -0
  14. package/templates/component-recipes/checkbox.md +117 -0
  15. package/templates/component-recipes/collapsible.md +201 -0
  16. package/templates/component-recipes/combobox.md +193 -0
  17. package/templates/component-recipes/context-menu.md +254 -0
  18. package/templates/component-recipes/dialog.md +193 -0
  19. package/templates/component-recipes/drawer.md +196 -0
  20. package/templates/component-recipes/dropdown-menu.md +263 -0
  21. package/templates/component-recipes/hover-card.md +230 -0
  22. package/templates/component-recipes/input.md +113 -0
  23. package/templates/component-recipes/label.md +259 -0
  24. package/templates/component-recipes/modal.md +155 -0
  25. package/templates/component-recipes/navigation-menu.md +310 -0
  26. package/templates/component-recipes/pagination.md +223 -0
  27. package/templates/component-recipes/popover.md +156 -0
  28. package/templates/component-recipes/progress.md +185 -0
  29. package/templates/component-recipes/radio.md +148 -0
  30. package/templates/component-recipes/select.md +154 -0
  31. package/templates/component-recipes/separator.md +124 -0
  32. package/templates/component-recipes/skeleton.md +186 -0
  33. package/templates/component-recipes/slider.md +114 -0
  34. package/templates/component-recipes/spinner.md +225 -0
  35. package/templates/component-recipes/switch.md +100 -0
  36. package/templates/component-recipes/table.md +161 -0
  37. package/templates/component-recipes/tabs.md +145 -0
  38. package/templates/component-recipes/textarea.md +234 -0
  39. package/templates/component-recipes/toast.md +209 -0
  40. package/templates/component-recipes/toggle-group.md +216 -0
  41. package/templates/component-recipes/tooltip.md +115 -0
  42. package/templates/hooks/triggers.d/styling.json +23 -0
  43. package/templates/skills/styling.md +173 -0
@@ -0,0 +1,185 @@
1
+ # Progress Component Recipe
2
+
3
+ ## Structure
4
+ - Track container with filled indicator
5
+ - Support determinate (percentage) and indeterminate (loading)
6
+ - Optional label and value display
7
+ - Circular variant option
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Linear Progress
12
+
13
+ #### Root/Track
14
+ ```
15
+ relative h-2 w-full overflow-hidden rounded-full bg-muted
16
+ ```
17
+
18
+ #### Indicator (filled)
19
+ ```
20
+ h-full w-full flex-1 bg-primary transition-all
21
+ ```
22
+
23
+ #### Indeterminate Animation
24
+ ```
25
+ animate-progress-indeterminate
26
+ @keyframes progress-indeterminate {
27
+ 0% { transform: translateX(-100%); }
28
+ 100% { transform: translateX(100%); }
29
+ }
30
+ ```
31
+
32
+ ### Sizes
33
+ ```
34
+ sm: h-1
35
+ md: h-2 (default)
36
+ lg: h-3
37
+ xl: h-4
38
+ ```
39
+
40
+ ### Variants
41
+ ```
42
+ default: bg-primary
43
+ success: bg-green-500
44
+ warning: bg-yellow-500
45
+ destructive: bg-destructive
46
+ ```
47
+
48
+ ### With Label
49
+ ```
50
+ Container: space-y-2
51
+ Label row: flex justify-between text-sm
52
+ Label: text-muted-foreground
53
+ Value: font-medium
54
+ ```
55
+
56
+ ### Circular Progress
57
+ ```
58
+ Container: relative inline-flex
59
+ SVG: -rotate-90 transform
60
+ Track circle: stroke-muted
61
+ Indicator circle: stroke-primary transition-all
62
+ stroke-dasharray: circumference
63
+ stroke-dashoffset: circumference - (value/100 * circumference)
64
+ ```
65
+
66
+ ## Props Interface
67
+ ```typescript
68
+ interface ProgressProps {
69
+ value?: number // 0-100, undefined = indeterminate
70
+ max?: number
71
+ variant?: 'default' | 'success' | 'warning' | 'destructive'
72
+ size?: 'sm' | 'md' | 'lg' | 'xl'
73
+ showValue?: boolean
74
+ label?: string
75
+ }
76
+
77
+ interface CircularProgressProps extends ProgressProps {
78
+ strokeWidth?: number
79
+ diameter?: number
80
+ }
81
+ ```
82
+
83
+ ## Do
84
+ - Use Radix Progress for accessibility
85
+ - Support both determinate and indeterminate states
86
+ - Include aria-valuenow, aria-valuemin, aria-valuemax
87
+ - Animate smoothly between values
88
+
89
+ ## Don't
90
+ - Hardcode colors
91
+ - Forget accessibility attributes
92
+ - Use jerky animations
93
+ - Skip indeterminate state support
94
+
95
+ ## Example
96
+ ```tsx
97
+ import * as ProgressPrimitive from '@radix-ui/react-progress'
98
+ import { cn } from '@/lib/utils'
99
+
100
+ const progressVariants = {
101
+ default: 'bg-primary',
102
+ success: 'bg-green-500',
103
+ warning: 'bg-yellow-500',
104
+ destructive: 'bg-destructive',
105
+ }
106
+
107
+ const progressSizes = {
108
+ sm: 'h-1',
109
+ md: 'h-2',
110
+ lg: 'h-3',
111
+ xl: 'h-4',
112
+ }
113
+
114
+ const Progress = ({
115
+ value,
116
+ variant = 'default',
117
+ size = 'md',
118
+ className,
119
+ ...props
120
+ }) => (
121
+ <ProgressPrimitive.Root
122
+ className={cn(
123
+ 'relative w-full overflow-hidden rounded-full bg-muted',
124
+ progressSizes[size],
125
+ className
126
+ )}
127
+ {...props}
128
+ >
129
+ <ProgressPrimitive.Indicator
130
+ className={cn(
131
+ 'h-full w-full flex-1 transition-all',
132
+ progressVariants[variant],
133
+ value === undefined && 'animate-progress-indeterminate'
134
+ )}
135
+ style={{ transform: value !== undefined ? `translateX(-${100 - value}%)` : undefined }}
136
+ />
137
+ </ProgressPrimitive.Root>
138
+ )
139
+
140
+ // With label and value
141
+ const ProgressWithLabel = ({ label, value, ...props }) => (
142
+ <div className="space-y-2">
143
+ <div className="flex justify-between text-sm">
144
+ <span className="text-muted-foreground">{label}</span>
145
+ <span className="font-medium">{value}%</span>
146
+ </div>
147
+ <Progress value={value} {...props} />
148
+ </div>
149
+ )
150
+
151
+ // Circular progress
152
+ const CircularProgress = ({ value, size = 40, strokeWidth = 4 }) => {
153
+ const radius = (size - strokeWidth) / 2
154
+ const circumference = radius * 2 * Math.PI
155
+ const offset = value !== undefined
156
+ ? circumference - (value / 100) * circumference
157
+ : 0
158
+
159
+ return (
160
+ <svg width={size} height={size} className="-rotate-90 transform">
161
+ <circle
162
+ cx={size / 2}
163
+ cy={size / 2}
164
+ r={radius}
165
+ fill="none"
166
+ stroke="currentColor"
167
+ strokeWidth={strokeWidth}
168
+ className="text-muted"
169
+ />
170
+ <circle
171
+ cx={size / 2}
172
+ cy={size / 2}
173
+ r={radius}
174
+ fill="none"
175
+ stroke="currentColor"
176
+ strokeWidth={strokeWidth}
177
+ strokeDasharray={circumference}
178
+ strokeDashoffset={offset}
179
+ strokeLinecap="round"
180
+ className="text-primary transition-all"
181
+ />
182
+ </svg>
183
+ )
184
+ }
185
+ ```
@@ -0,0 +1,148 @@
1
+ # Radio Component Recipe
2
+
3
+ ## Structure
4
+ - Radio group container
5
+ - Individual radio items with circular indicator
6
+ - Label for each option
7
+ - Optional description per item
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Radio Group
12
+ ```
13
+ grid gap-2
14
+ ```
15
+
16
+ ### Radio Item
17
+ ```
18
+ aspect-square h-4 w-4 rounded-full border border-border
19
+ ring-offset-background
20
+ focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2
21
+ disabled:cursor-not-allowed disabled:opacity-50
22
+ data-[state=checked]:border-primary
23
+ ```
24
+
25
+ ### Radio Indicator (inner dot)
26
+ ```
27
+ flex items-center justify-center
28
+ after:content-[''] after:block after:h-2 after:w-2 after:rounded-full after:bg-primary
29
+ ```
30
+
31
+ ### Radio Item Wrapper (with label)
32
+ ```
33
+ flex items-center space-x-2
34
+ ```
35
+
36
+ ### Label
37
+ ```
38
+ text-sm font-medium leading-none text-foreground
39
+ peer-disabled:cursor-not-allowed peer-disabled:opacity-70
40
+ ```
41
+
42
+ ### Card Style Variant (selectable cards)
43
+ ```
44
+ flex cursor-pointer items-start space-x-3 {tokens.radius} border border-border p-4
45
+ hover:bg-surface
46
+ data-[state=checked]:border-primary data-[state=checked]:bg-primary/5
47
+ ```
48
+
49
+ ## Props Interface
50
+ ```typescript
51
+ interface RadioGroupProps {
52
+ value?: string
53
+ onValueChange?: (value: string) => void
54
+ disabled?: boolean
55
+ orientation?: 'horizontal' | 'vertical'
56
+ children: React.ReactNode
57
+ }
58
+
59
+ interface RadioGroupItemProps {
60
+ value: string
61
+ disabled?: boolean
62
+ id?: string
63
+ }
64
+
65
+ interface RadioCardProps {
66
+ value: string
67
+ label: string
68
+ description?: string
69
+ disabled?: boolean
70
+ }
71
+ ```
72
+
73
+ ## Do
74
+ - Use Radix RadioGroup for accessibility
75
+ - Support horizontal and vertical layouts
76
+ - Include focus ring
77
+ - Animate indicator appearance
78
+ - Support card-style radio buttons
79
+
80
+ ## Don't
81
+ - Hardcode colors
82
+ - Use actual `<input type="radio">` without styling
83
+ - Forget group semantics
84
+ - Skip disabled state
85
+
86
+ ## Example
87
+ ```tsx
88
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
89
+ import { Circle } from 'lucide-react'
90
+ import { cn } from '@/lib/utils'
91
+
92
+ const RadioGroup = ({ className, ...props }) => (
93
+ <RadioGroupPrimitive.Root className={cn('grid gap-2', className)} {...props} />
94
+ )
95
+
96
+ const RadioGroupItem = ({ className, ...props }) => (
97
+ <RadioGroupPrimitive.Item
98
+ className={cn(
99
+ 'aspect-square h-4 w-4 rounded-full border border-border',
100
+ 'ring-offset-background',
101
+ 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2',
102
+ 'disabled:cursor-not-allowed disabled:opacity-50',
103
+ 'data-[state=checked]:border-primary',
104
+ className
105
+ )}
106
+ {...props}
107
+ >
108
+ <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
109
+ <Circle className="h-2 w-2 fill-primary text-primary" />
110
+ </RadioGroupPrimitive.Indicator>
111
+ </RadioGroupPrimitive.Item>
112
+ )
113
+
114
+ // With label
115
+ const RadioWithLabel = ({ value, label, description, id }) => (
116
+ <div className="flex items-start space-x-2">
117
+ <RadioGroupItem value={value} id={id} />
118
+ <div className="grid gap-1.5 leading-none">
119
+ <label htmlFor={id} className="text-sm font-medium text-foreground">
120
+ {label}
121
+ </label>
122
+ {description && (
123
+ <p className="text-sm text-muted-foreground">{description}</p>
124
+ )}
125
+ </div>
126
+ </div>
127
+ )
128
+
129
+ // Card style variant
130
+ const RadioCard = ({ value, label, description }) => (
131
+ <RadioGroupPrimitive.Item
132
+ value={value}
133
+ className={cn(
134
+ 'flex cursor-pointer items-start space-x-3 rounded-lg border border-border p-4',
135
+ 'hover:bg-surface',
136
+ 'data-[state=checked]:border-primary data-[state=checked]:bg-primary/5'
137
+ )}
138
+ >
139
+ <RadioGroupPrimitive.Indicator className="mt-1">
140
+ <Circle className="h-2 w-2 fill-primary text-primary" />
141
+ </RadioGroupPrimitive.Indicator>
142
+ <div>
143
+ <p className="font-medium text-foreground">{label}</p>
144
+ {description && <p className="text-sm text-muted-foreground">{description}</p>}
145
+ </div>
146
+ </RadioGroupPrimitive.Item>
147
+ )
148
+ ```
@@ -0,0 +1,154 @@
1
+ # Select/Dropdown Component Recipe
2
+
3
+ ## Structure
4
+ - Trigger button that shows current value
5
+ - Dropdown content with scrollable list
6
+ - Option items with optional icons/checkmarks
7
+ - Support for groups and separators
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Trigger
12
+ ```
13
+ flex h-10 w-full items-center justify-between {tokens.radius} border border-border
14
+ bg-background px-3 py-2 text-sm text-foreground
15
+ placeholder:text-muted-foreground
16
+ focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2
17
+ disabled:cursor-not-allowed disabled:opacity-50
18
+ ```
19
+
20
+ ### Content (Dropdown)
21
+ ```
22
+ relative z-50 max-h-96 min-w-[8rem] overflow-hidden {tokens.radius}
23
+ border border-border bg-background text-foreground {tokens.shadow}
24
+ data-[state=open]:animate-in data-[state=closed]:animate-out
25
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0
26
+ data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
27
+ data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2
28
+ ```
29
+
30
+ ### Viewport (scrollable area)
31
+ ```
32
+ p-1 max-h-[300px] overflow-y-auto
33
+ ```
34
+
35
+ ### Item
36
+ ```
37
+ relative flex w-full cursor-pointer select-none items-center {tokens.radius} py-1.5 pl-8 pr-2
38
+ text-sm outline-none
39
+ focus:bg-surface focus:text-foreground
40
+ data-[disabled]:pointer-events-none data-[disabled]:opacity-50
41
+ ```
42
+
43
+ ### Selected Indicator
44
+ ```
45
+ absolute left-2 flex h-3.5 w-3.5 items-center justify-center
46
+ ```
47
+
48
+ ### Separator
49
+ ```
50
+ -mx-1 my-1 h-px bg-border
51
+ ```
52
+
53
+ ### Group Label
54
+ ```
55
+ py-1.5 pl-8 pr-2 text-sm font-semibold text-foreground
56
+ ```
57
+
58
+ ## Props Interface
59
+ ```typescript
60
+ interface SelectProps {
61
+ value?: string
62
+ onValueChange?: (value: string) => void
63
+ placeholder?: string
64
+ disabled?: boolean
65
+ children: React.ReactNode
66
+ }
67
+
68
+ interface SelectItemProps {
69
+ value: string
70
+ disabled?: boolean
71
+ children: React.ReactNode
72
+ }
73
+
74
+ interface SelectGroupProps {
75
+ label: string
76
+ children: React.ReactNode
77
+ }
78
+ ```
79
+
80
+ ## Do
81
+ - Use Radix Select for accessibility
82
+ - Show checkmark for selected item
83
+ - Include chevron icon on trigger
84
+ - Support keyboard navigation
85
+ - Handle long lists with scrolling
86
+
87
+ ## Don't
88
+ - Hardcode colors
89
+ - Forget hover/focus states on items
90
+ - Skip selected state indicator
91
+ - Use custom scroll behavior
92
+
93
+ ## Example
94
+ ```tsx
95
+ import * as SelectPrimitive from '@radix-ui/react-select'
96
+ import { Check, ChevronDown } from 'lucide-react'
97
+ import { cn } from '@/lib/utils'
98
+
99
+ const Select = SelectPrimitive.Root
100
+
101
+ const SelectTrigger = ({ className, children, ...props }) => (
102
+ <SelectPrimitive.Trigger
103
+ className={cn(
104
+ 'flex h-10 w-full items-center justify-between rounded-lg border border-border',
105
+ 'bg-background px-3 py-2 text-sm',
106
+ 'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
107
+ 'disabled:cursor-not-allowed disabled:opacity-50',
108
+ className
109
+ )}
110
+ {...props}
111
+ >
112
+ {children}
113
+ <SelectPrimitive.Icon>
114
+ <ChevronDown className="h-4 w-4 opacity-50" />
115
+ </SelectPrimitive.Icon>
116
+ </SelectPrimitive.Trigger>
117
+ )
118
+
119
+ const SelectContent = ({ className, children, ...props }) => (
120
+ <SelectPrimitive.Portal>
121
+ <SelectPrimitive.Content
122
+ className={cn(
123
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg',
124
+ 'border border-border bg-background shadow-md',
125
+ className
126
+ )}
127
+ {...props}
128
+ >
129
+ <SelectPrimitive.Viewport className="p-1">
130
+ {children}
131
+ </SelectPrimitive.Viewport>
132
+ </SelectPrimitive.Content>
133
+ </SelectPrimitive.Portal>
134
+ )
135
+
136
+ const SelectItem = ({ className, children, ...props }) => (
137
+ <SelectPrimitive.Item
138
+ className={cn(
139
+ 'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm',
140
+ 'outline-none focus:bg-surface',
141
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
142
+ className
143
+ )}
144
+ {...props}
145
+ >
146
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
147
+ <SelectPrimitive.ItemIndicator>
148
+ <Check className="h-4 w-4" />
149
+ </SelectPrimitive.ItemIndicator>
150
+ </span>
151
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
152
+ </SelectPrimitive.Item>
153
+ )
154
+ ```
@@ -0,0 +1,124 @@
1
+ # Separator Component Recipe
2
+
3
+ ## Structure
4
+ - Simple divider line
5
+ - Support horizontal and vertical orientations
6
+ - Decorative by default (not announced by screen readers)
7
+ - Optional label in center
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Base
12
+ ```
13
+ shrink-0 bg-border
14
+ ```
15
+
16
+ ### Horizontal (default)
17
+ ```
18
+ h-px w-full
19
+ ```
20
+
21
+ ### Vertical
22
+ ```
23
+ h-full w-px
24
+ ```
25
+
26
+ ### With Label
27
+ ```
28
+ Container: relative flex items-center
29
+ Line: flex-1 h-px bg-border
30
+ Label: mx-4 text-xs text-muted-foreground uppercase tracking-wider
31
+ ```
32
+
33
+ ### Spacing Variants
34
+ ```
35
+ sm: my-2 (horizontal) / mx-2 (vertical)
36
+ md: my-4 (horizontal) / mx-4 (vertical)
37
+ lg: my-6 (horizontal) / mx-6 (vertical)
38
+ ```
39
+
40
+ ### Style Variants
41
+ ```
42
+ solid: bg-border (default)
43
+ dashed: border-t border-dashed border-border bg-transparent h-0
44
+ dotted: border-t border-dotted border-border bg-transparent h-0
45
+ ```
46
+
47
+ ## Props Interface
48
+ ```typescript
49
+ interface SeparatorProps {
50
+ orientation?: 'horizontal' | 'vertical'
51
+ decorative?: boolean
52
+ className?: string
53
+ }
54
+
55
+ interface SeparatorWithLabelProps extends SeparatorProps {
56
+ label: string
57
+ }
58
+ ```
59
+
60
+ ## Do
61
+ - Use Radix Separator for semantic correctness
62
+ - Set decorative={true} for visual-only separators
63
+ - Use consistent spacing in lists/groups
64
+ - Support both orientations
65
+
66
+ ## Don't
67
+ - Hardcode colors
68
+ - Use <hr> without proper styling
69
+ - Forget to set decorative prop appropriately
70
+ - Over-use separators (whitespace often suffices)
71
+
72
+ ## Example
73
+ ```tsx
74
+ import * as SeparatorPrimitive from '@radix-ui/react-separator'
75
+ import { cn } from '@/lib/utils'
76
+
77
+ const Separator = ({
78
+ className,
79
+ orientation = 'horizontal',
80
+ decorative = true,
81
+ ...props
82
+ }) => (
83
+ <SeparatorPrimitive.Root
84
+ decorative={decorative}
85
+ orientation={orientation}
86
+ className={cn(
87
+ 'shrink-0 bg-border',
88
+ orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ )
94
+
95
+ // With label
96
+ const SeparatorWithLabel = ({ label, className, ...props }) => (
97
+ <div className={cn('relative flex items-center', className)} {...props}>
98
+ <div className="flex-1 h-px bg-border" />
99
+ <span className="mx-4 text-xs text-muted-foreground uppercase tracking-wider">
100
+ {label}
101
+ </span>
102
+ <div className="flex-1 h-px bg-border" />
103
+ </div>
104
+ )
105
+
106
+ // Usage examples
107
+ <div className="space-y-4">
108
+ <div>Content above</div>
109
+ <Separator />
110
+ <div>Content below</div>
111
+ </div>
112
+
113
+ // Vertical in flex container
114
+ <div className="flex h-5 items-center space-x-4 text-sm">
115
+ <div>Blog</div>
116
+ <Separator orientation="vertical" />
117
+ <div>Docs</div>
118
+ <Separator orientation="vertical" />
119
+ <div>Source</div>
120
+ </div>
121
+
122
+ // With label
123
+ <SeparatorWithLabel label="Or continue with" />
124
+ ```