@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,209 @@
1
+ # Toast/Notification Component Recipe
2
+
3
+ ## Structure
4
+ - Viewport container (fixed position, stacks toasts)
5
+ - Individual toast with title, description, action
6
+ - Auto-dismiss with progress indicator (optional)
7
+ - Support variants: default, success, error, warning
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Viewport (container for all toasts)
12
+ ```
13
+ fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4
14
+ sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]
15
+ ```
16
+
17
+ ### Toast
18
+ ```
19
+ group pointer-events-auto relative flex w-full items-center justify-between space-x-2
20
+ overflow-hidden {tokens.radius} border border-border p-4 pr-6 {tokens.shadow}
21
+ transition-all
22
+ data-[swipe=cancel]:translate-x-0
23
+ data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)]
24
+ data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]
25
+ data-[swipe=move]:transition-none
26
+ data-[state=open]:animate-in data-[state=closed]:animate-out
27
+ data-[swipe=end]:animate-out
28
+ data-[state=closed]:fade-out-80
29
+ data-[state=closed]:slide-out-to-right-full
30
+ data-[state=open]:slide-in-from-top-full
31
+ data-[state=open]:sm:slide-in-from-bottom-full
32
+ ```
33
+
34
+ ### Variants
35
+ ```
36
+ default: bg-background text-foreground
37
+ success: bg-green-500 text-white border-green-600
38
+ error: bg-destructive text-destructive-foreground border-destructive
39
+ warning: bg-yellow-500 text-white border-yellow-600
40
+ ```
41
+
42
+ ### Title
43
+ ```
44
+ text-sm font-semibold [&+div]:text-xs
45
+ ```
46
+
47
+ ### Description
48
+ ```
49
+ text-sm opacity-90
50
+ ```
51
+
52
+ ### Action Button
53
+ ```
54
+ inline-flex h-8 shrink-0 items-center justify-center {tokens.radius}
55
+ border border-border bg-transparent px-3 text-sm font-medium
56
+ transition-colors hover:bg-secondary
57
+ focus:outline-none focus:ring-1 focus:ring-ring
58
+ disabled:pointer-events-none disabled:opacity-50
59
+ group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30
60
+ group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground
61
+ group-[.destructive]:focus:ring-destructive
62
+ ```
63
+
64
+ ### Close Button
65
+ ```
66
+ absolute right-1 top-1 rounded-md p-1 text-foreground/50
67
+ opacity-0 transition-opacity hover:text-foreground
68
+ focus:opacity-100 focus:outline-none focus:ring-1
69
+ group-hover:opacity-100
70
+ group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50
71
+ group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600
72
+ ```
73
+
74
+ ## Props Interface
75
+ ```typescript
76
+ interface ToastProps {
77
+ id: string
78
+ title?: string
79
+ description?: string
80
+ action?: React.ReactNode
81
+ variant?: 'default' | 'success' | 'error' | 'warning'
82
+ duration?: number
83
+ onOpenChange?: (open: boolean) => void
84
+ }
85
+
86
+ interface ToastActionProps {
87
+ altText: string
88
+ onClick: () => void
89
+ children: React.ReactNode
90
+ }
91
+
92
+ // Hook interface
93
+ function useToast(): {
94
+ toast: (props: Omit<ToastProps, 'id'>) => void
95
+ dismiss: (id?: string) => void
96
+ toasts: ToastProps[]
97
+ }
98
+ ```
99
+
100
+ ## Do
101
+ - Use a toast provider at app root
102
+ - Support swipe-to-dismiss on mobile
103
+ - Include close button
104
+ - Use appropriate variant for context
105
+ - Limit visible toasts (3-5 max)
106
+
107
+ ## Don't
108
+ - Hardcode colors
109
+ - Skip auto-dismiss (except for errors)
110
+ - Use for critical information (use Alert)
111
+ - Stack too many toasts
112
+
113
+ ## Example
114
+ ```tsx
115
+ import * as ToastPrimitives from '@radix-ui/react-toast'
116
+ import { X } from 'lucide-react'
117
+ import { cn } from '@/lib/utils'
118
+
119
+ const ToastProvider = ToastPrimitives.Provider
120
+
121
+ const ToastViewport = ({ className, ...props }) => (
122
+ <ToastPrimitives.Viewport
123
+ className={cn(
124
+ 'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4',
125
+ 'sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
126
+ className
127
+ )}
128
+ {...props}
129
+ />
130
+ )
131
+
132
+ const toastVariants = {
133
+ default: 'bg-background text-foreground border-border',
134
+ success: 'bg-green-500 text-white border-green-600',
135
+ error: 'bg-destructive text-destructive-foreground border-destructive',
136
+ warning: 'bg-yellow-500 text-white border-yellow-600',
137
+ }
138
+
139
+ const Toast = ({ className, variant = 'default', ...props }) => (
140
+ <ToastPrimitives.Root
141
+ className={cn(
142
+ 'group pointer-events-auto relative flex w-full items-center justify-between space-x-2',
143
+ 'overflow-hidden rounded-lg border p-4 pr-6 shadow-lg transition-all',
144
+ 'data-[swipe=cancel]:translate-x-0',
145
+ 'data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)]',
146
+ 'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]',
147
+ 'data-[swipe=move]:transition-none',
148
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
149
+ 'data-[swipe=end]:animate-out data-[state=closed]:fade-out-80',
150
+ 'data-[state=closed]:slide-out-to-right-full',
151
+ 'data-[state=open]:slide-in-from-top-full',
152
+ 'data-[state=open]:sm:slide-in-from-bottom-full',
153
+ toastVariants[variant],
154
+ className
155
+ )}
156
+ {...props}
157
+ />
158
+ )
159
+
160
+ const ToastAction = ({ className, ...props }) => (
161
+ <ToastPrimitives.Action
162
+ className={cn(
163
+ 'inline-flex h-8 shrink-0 items-center justify-center rounded-md',
164
+ 'border bg-transparent px-3 text-sm font-medium',
165
+ 'hover:bg-secondary focus:outline-none focus:ring-1',
166
+ className
167
+ )}
168
+ {...props}
169
+ />
170
+ )
171
+
172
+ const ToastClose = ({ className, ...props }) => (
173
+ <ToastPrimitives.Close
174
+ className={cn(
175
+ 'absolute right-1 top-1 rounded-md p-1 text-foreground/50',
176
+ 'opacity-0 transition-opacity hover:text-foreground',
177
+ 'focus:opacity-100 focus:outline-none group-hover:opacity-100',
178
+ className
179
+ )}
180
+ {...props}
181
+ >
182
+ <X className="h-4 w-4" />
183
+ </ToastPrimitives.Close>
184
+ )
185
+
186
+ const ToastTitle = ({ className, ...props }) => (
187
+ <ToastPrimitives.Title className={cn('text-sm font-semibold', className)} {...props} />
188
+ )
189
+
190
+ const ToastDescription = ({ className, ...props }) => (
191
+ <ToastPrimitives.Description className={cn('text-sm opacity-90', className)} {...props} />
192
+ )
193
+
194
+ // Usage with hook
195
+ const { toast } = useToast()
196
+
197
+ toast({
198
+ title: 'Success!',
199
+ description: 'Your changes have been saved.',
200
+ variant: 'success',
201
+ })
202
+
203
+ toast({
204
+ title: 'Error',
205
+ description: 'Something went wrong.',
206
+ variant: 'error',
207
+ action: <ToastAction altText="Try again" onClick={retry}>Try again</ToastAction>,
208
+ })
209
+ ```
@@ -0,0 +1,216 @@
1
+ # Toggle Group Component Recipe
2
+
3
+ ## Structure
4
+ - Group of toggle buttons
5
+ - Single or multiple selection modes
6
+ - Mutually exclusive options (single) or multi-select (multiple)
7
+ - Often used for view switchers, formatting options, filters
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Container
12
+ ```
13
+ inline-flex items-center justify-center {tokens.radius} bg-muted p-1
14
+ ```
15
+
16
+ ### Item (Base)
17
+ ```
18
+ inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5
19
+ text-sm font-medium ring-offset-background transition-all
20
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2
21
+ disabled:pointer-events-none disabled:opacity-50
22
+ ```
23
+
24
+ ### Item States
25
+ ```
26
+ Default: text-muted-foreground hover:bg-background/50 hover:text-foreground
27
+ Active: bg-background text-foreground shadow-sm
28
+ ```
29
+
30
+ ### Variant: Outline
31
+ ```
32
+ Container: inline-flex items-center rounded-lg border border-border
33
+ Item: border-r border-border last:border-r-0
34
+ Item Active: bg-muted
35
+ ```
36
+
37
+ ### Sizes
38
+ ```
39
+ sm: h-8 px-2.5 text-xs
40
+ md: h-9 px-3 text-sm (default)
41
+ lg: h-10 px-4 text-sm
42
+ ```
43
+
44
+ ### With Icons
45
+ ```
46
+ Item: gap-2
47
+ Icon: h-4 w-4
48
+ ```
49
+
50
+ ### Full Width
51
+ ```
52
+ Container: flex w-full
53
+ Item: flex-1
54
+ ```
55
+
56
+ ## Props Interface
57
+ ```typescript
58
+ interface ToggleGroupProps {
59
+ type: 'single' | 'multiple'
60
+ value?: string | string[]
61
+ defaultValue?: string | string[]
62
+ onValueChange?: (value: string | string[]) => void
63
+ disabled?: boolean
64
+ className?: string
65
+ children: React.ReactNode
66
+ }
67
+
68
+ interface ToggleGroupItemProps {
69
+ value: string
70
+ disabled?: boolean
71
+ className?: string
72
+ children: React.ReactNode
73
+ }
74
+
75
+ // Single selection
76
+ interface ToggleGroupSingleProps {
77
+ type: 'single'
78
+ value?: string
79
+ defaultValue?: string
80
+ onValueChange?: (value: string) => void
81
+ }
82
+
83
+ // Multiple selection
84
+ interface ToggleGroupMultipleProps {
85
+ type: 'multiple'
86
+ value?: string[]
87
+ defaultValue?: string[]
88
+ onValueChange?: (value: string[]) => void
89
+ }
90
+ ```
91
+
92
+ ## Do
93
+ - Use Radix ToggleGroup primitive
94
+ - Clearly indicate selected state
95
+ - Support keyboard navigation
96
+ - Include proper ARIA attributes
97
+ - Group related options logically
98
+
99
+ ## Don't
100
+ - Hardcode colors or dimensions
101
+ - Mix toggle group with regular buttons
102
+ - Use for navigation (use tabs or nav)
103
+ - Forget disabled states
104
+
105
+ ## Example
106
+ ```tsx
107
+ import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group'
108
+ import { cn } from '@/lib/utils'
109
+
110
+ const ToggleGroup = ({ className, variant = 'default', size = 'md', ...props }) => (
111
+ <ToggleGroupPrimitive.Root
112
+ className={cn(
113
+ 'inline-flex items-center justify-center rounded-lg',
114
+ variant === 'default' && 'bg-muted p-1',
115
+ variant === 'outline' && 'border border-border',
116
+ className
117
+ )}
118
+ {...props}
119
+ />
120
+ )
121
+
122
+ const toggleGroupItemSizes = {
123
+ sm: 'h-8 px-2.5 text-xs',
124
+ md: 'h-9 px-3 text-sm',
125
+ lg: 'h-10 px-4 text-sm',
126
+ }
127
+
128
+ const ToggleGroupItem = ({ className, variant = 'default', size = 'md', ...props }) => (
129
+ <ToggleGroupPrimitive.Item
130
+ className={cn(
131
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-md',
132
+ 'font-medium ring-offset-background transition-all',
133
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2',
134
+ 'disabled:pointer-events-none disabled:opacity-50',
135
+ variant === 'default' && [
136
+ 'text-muted-foreground hover:bg-background/50 hover:text-foreground',
137
+ 'data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-sm',
138
+ ],
139
+ variant === 'outline' && [
140
+ 'border-r border-border last:border-r-0',
141
+ 'text-muted-foreground hover:bg-muted hover:text-foreground',
142
+ 'data-[state=on]:bg-muted data-[state=on]:text-foreground',
143
+ ],
144
+ toggleGroupItemSizes[size],
145
+ className
146
+ )}
147
+ {...props}
148
+ />
149
+ )
150
+
151
+ // Usage examples
152
+
153
+ // View switcher (single selection)
154
+ import { LayoutGrid, List, Rows } from 'lucide-react'
155
+
156
+ const ViewToggle = ({ value, onChange }) => (
157
+ <ToggleGroup type="single" value={value} onValueChange={onChange}>
158
+ <ToggleGroupItem value="grid" aria-label="Grid view">
159
+ <LayoutGrid className="h-4 w-4" />
160
+ </ToggleGroupItem>
161
+ <ToggleGroupItem value="list" aria-label="List view">
162
+ <List className="h-4 w-4" />
163
+ </ToggleGroupItem>
164
+ <ToggleGroupItem value="rows" aria-label="Rows view">
165
+ <Rows className="h-4 w-4" />
166
+ </ToggleGroupItem>
167
+ </ToggleGroup>
168
+ )
169
+
170
+ // Text formatting (multiple selection)
171
+ import { Bold, Italic, Underline, Strikethrough } from 'lucide-react'
172
+
173
+ const TextFormatting = ({ value, onChange }) => (
174
+ <ToggleGroup type="multiple" value={value} onValueChange={onChange}>
175
+ <ToggleGroupItem value="bold" aria-label="Bold">
176
+ <Bold className="h-4 w-4" />
177
+ </ToggleGroupItem>
178
+ <ToggleGroupItem value="italic" aria-label="Italic">
179
+ <Italic className="h-4 w-4" />
180
+ </ToggleGroupItem>
181
+ <ToggleGroupItem value="underline" aria-label="Underline">
182
+ <Underline className="h-4 w-4" />
183
+ </ToggleGroupItem>
184
+ <ToggleGroupItem value="strikethrough" aria-label="Strikethrough">
185
+ <Strikethrough className="h-4 w-4" />
186
+ </ToggleGroupItem>
187
+ </ToggleGroup>
188
+ )
189
+
190
+ // Filter options with text
191
+ const FilterToggle = ({ value, onChange }) => (
192
+ <ToggleGroup type="single" value={value} onValueChange={onChange} variant="outline">
193
+ <ToggleGroupItem value="all">All</ToggleGroupItem>
194
+ <ToggleGroupItem value="active">Active</ToggleGroupItem>
195
+ <ToggleGroupItem value="completed">Completed</ToggleGroupItem>
196
+ </ToggleGroup>
197
+ )
198
+
199
+ // Full width toggle
200
+ const PlanToggle = ({ value, onChange }) => (
201
+ <ToggleGroup type="single" value={value} onValueChange={onChange} className="w-full">
202
+ <ToggleGroupItem value="monthly" className="flex-1">Monthly</ToggleGroupItem>
203
+ <ToggleGroupItem value="yearly" className="flex-1">
204
+ Yearly
205
+ <span className="ml-1 text-xs text-primary">Save 20%</span>
206
+ </ToggleGroupItem>
207
+ </ToggleGroup>
208
+ )
209
+
210
+ // With controlled state
211
+ const [view, setView] = useState('grid')
212
+ const [formatting, setFormatting] = useState<string[]>([])
213
+
214
+ <ViewToggle value={view} onChange={setView} />
215
+ <TextFormatting value={formatting} onChange={setFormatting} />
216
+ ```
@@ -0,0 +1,115 @@
1
+ # Tooltip Component Recipe
2
+
3
+ ## Structure
4
+ - Trigger element (wraps any interactive element)
5
+ - Content popup with arrow
6
+ - Support multiple positions
7
+ - Delay on hover before showing
8
+
9
+ ## Tailwind Classes
10
+
11
+ ### Content
12
+ ```
13
+ z-50 overflow-hidden {tokens.radius} bg-foreground px-3 py-1.5 text-xs text-background
14
+ animate-in fade-in-0 zoom-in-95
15
+ data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95
16
+ data-[side=bottom]:slide-in-from-top-2
17
+ data-[side=left]:slide-in-from-right-2
18
+ data-[side=right]:slide-in-from-left-2
19
+ data-[side=top]:slide-in-from-bottom-2
20
+ ```
21
+
22
+ ### Arrow
23
+ ```
24
+ fill-foreground
25
+ ```
26
+
27
+ ### Alternative Light Style
28
+ ```
29
+ bg-background border border-border text-foreground {tokens.shadow}
30
+ Arrow: fill-background stroke-border
31
+ ```
32
+
33
+ ## Props Interface
34
+ ```typescript
35
+ interface TooltipProps {
36
+ content: React.ReactNode
37
+ side?: 'top' | 'right' | 'bottom' | 'left'
38
+ align?: 'start' | 'center' | 'end'
39
+ delayDuration?: number
40
+ children: React.ReactNode
41
+ }
42
+ ```
43
+
44
+ ## Configuration
45
+ - Default delay: 200ms (adjust based on UX needs)
46
+ - Default side: 'top'
47
+ - Skip delay on hover when moving between tooltips
48
+
49
+ ## Do
50
+ - Use Radix Tooltip for accessibility
51
+ - Include enter/exit animations
52
+ - Support arrow pointing to trigger
53
+ - Use inverted colors (dark bg, light text) for contrast
54
+
55
+ ## Don't
56
+ - Show tooltip on disabled elements without wrapper
57
+ - Use too long delay (frustrating UX)
58
+ - Put interactive content in tooltips (use popover instead)
59
+ - Hardcode colors
60
+
61
+ ## Example
62
+ ```tsx
63
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip'
64
+ import { cn } from '@/lib/utils'
65
+
66
+ const TooltipProvider = TooltipPrimitive.Provider
67
+
68
+ const Tooltip = TooltipPrimitive.Root
69
+
70
+ const TooltipTrigger = TooltipPrimitive.Trigger
71
+
72
+ const TooltipContent = ({ className, sideOffset = 4, ...props }) => (
73
+ <TooltipPrimitive.Content
74
+ sideOffset={sideOffset}
75
+ className={cn(
76
+ 'z-50 overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background',
77
+ 'animate-in fade-in-0 zoom-in-95',
78
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
79
+ 'data-[side=bottom]:slide-in-from-top-2',
80
+ 'data-[side=left]:slide-in-from-right-2',
81
+ 'data-[side=right]:slide-in-from-left-2',
82
+ 'data-[side=top]:slide-in-from-bottom-2',
83
+ className
84
+ )}
85
+ {...props}
86
+ />
87
+ )
88
+
89
+ const TooltipArrow = ({ className, ...props }) => (
90
+ <TooltipPrimitive.Arrow
91
+ className={cn('fill-foreground', className)}
92
+ {...props}
93
+ />
94
+ )
95
+
96
+ // Simplified wrapper component
97
+ const SimpleTooltip = ({ content, side = 'top', delayDuration = 200, children }) => (
98
+ <TooltipProvider>
99
+ <Tooltip delayDuration={delayDuration}>
100
+ <TooltipTrigger asChild>{children}</TooltipTrigger>
101
+ <TooltipContent side={side}>
102
+ {content}
103
+ <TooltipArrow />
104
+ </TooltipContent>
105
+ </Tooltip>
106
+ </TooltipProvider>
107
+ )
108
+
109
+ // Usage
110
+ <SimpleTooltip content="Add to library">
111
+ <Button variant="ghost" size="icon">
112
+ <Plus className="h-4 w-4" />
113
+ </Button>
114
+ </SimpleTooltip>
115
+ ```
@@ -0,0 +1,23 @@
1
+ {
2
+ "styling": [
3
+ "style",
4
+ "styling",
5
+ "css",
6
+ "tailwind",
7
+ "theme",
8
+ "color",
9
+ "colours",
10
+ "spacing",
11
+ "design system",
12
+ "design tokens",
13
+ "dark mode",
14
+ "light mode",
15
+ "ui component",
16
+ "component library",
17
+ "className",
18
+ "aesthetic",
19
+ "visual",
20
+ "look and feel"
21
+ ],
22
+ "_comment": "Styling trigger extension for @claude-tools/component-system"
23
+ }