shadcn-phlex 0.1.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.
- checksums.yaml +7 -0
- data/README.md +195 -0
- data/app.css +20 -0
- data/css/shadcn-source.css +3 -0
- data/css/shadcn-tailwind.css +160 -0
- data/css/themes/mauve.css +62 -0
- data/css/themes/mist.css +62 -0
- data/css/themes/neutral.css +74 -0
- data/css/themes/olive.css +62 -0
- data/css/themes/stone.css +62 -0
- data/css/themes/taupe.css +62 -0
- data/css/themes/zinc.css +62 -0
- data/js/controllers/accordion_controller.js +135 -0
- data/js/controllers/checkbox_controller.js +52 -0
- data/js/controllers/collapsible_controller.js +85 -0
- data/js/controllers/combobox_controller.js +168 -0
- data/js/controllers/command_controller.js +171 -0
- data/js/controllers/context_menu_controller.js +132 -0
- data/js/controllers/dark_mode_controller.js +106 -0
- data/js/controllers/dialog_controller.js +205 -0
- data/js/controllers/drawer_controller.js +161 -0
- data/js/controllers/dropdown_menu_controller.js +189 -0
- data/js/controllers/hover_card_controller.js +85 -0
- data/js/controllers/index.js +89 -0
- data/js/controllers/menubar_controller.js +171 -0
- data/js/controllers/navigation_menu_controller.js +160 -0
- data/js/controllers/popover_controller.js +151 -0
- data/js/controllers/radio_group_controller.js +78 -0
- data/js/controllers/scroll_area_controller.js +117 -0
- data/js/controllers/select_controller.js +198 -0
- data/js/controllers/sheet_controller.js +130 -0
- data/js/controllers/slider_controller.js +142 -0
- data/js/controllers/switch_controller.js +40 -0
- data/js/controllers/tabs_controller.js +96 -0
- data/js/controllers/toast_controller.js +206 -0
- data/js/controllers/toggle_controller.js +30 -0
- data/js/controllers/toggle_group_controller.js +73 -0
- data/js/controllers/tooltip_controller.js +146 -0
- data/lib/generators/shadcn_phlex/component_generator.rb +79 -0
- data/lib/generators/shadcn_phlex/install_generator.rb +217 -0
- data/lib/shadcn/base.rb +27 -0
- data/lib/shadcn/engine.rb +24 -0
- data/lib/shadcn/kit.rb +1158 -0
- data/lib/shadcn/themes/accent_colors.rb +106 -0
- data/lib/shadcn/themes/base_colors.rb +313 -0
- data/lib/shadcn/ui/accordion.rb +135 -0
- data/lib/shadcn/ui/alert.rb +79 -0
- data/lib/shadcn/ui/alert_dialog.rb +220 -0
- data/lib/shadcn/ui/aspect_ratio.rb +35 -0
- data/lib/shadcn/ui/avatar.rb +134 -0
- data/lib/shadcn/ui/badge.rb +48 -0
- data/lib/shadcn/ui/breadcrumb.rb +180 -0
- data/lib/shadcn/ui/button.rb +63 -0
- data/lib/shadcn/ui/button_group.rb +58 -0
- data/lib/shadcn/ui/card.rb +133 -0
- data/lib/shadcn/ui/checkbox.rb +72 -0
- data/lib/shadcn/ui/collapsible.rb +76 -0
- data/lib/shadcn/ui/combobox.rb +229 -0
- data/lib/shadcn/ui/command.rb +256 -0
- data/lib/shadcn/ui/context_menu.rb +319 -0
- data/lib/shadcn/ui/dialog.rb +226 -0
- data/lib/shadcn/ui/direction.rb +23 -0
- data/lib/shadcn/ui/drawer.rb +217 -0
- data/lib/shadcn/ui/dropdown_menu.rb +384 -0
- data/lib/shadcn/ui/empty.rb +97 -0
- data/lib/shadcn/ui/field.rb +126 -0
- data/lib/shadcn/ui/hover_card.rb +75 -0
- data/lib/shadcn/ui/input.rb +36 -0
- data/lib/shadcn/ui/input_group.rb +32 -0
- data/lib/shadcn/ui/input_otp.rb +112 -0
- data/lib/shadcn/ui/item.rb +115 -0
- data/lib/shadcn/ui/kbd.rb +45 -0
- data/lib/shadcn/ui/label.rb +28 -0
- data/lib/shadcn/ui/menubar.rb +345 -0
- data/lib/shadcn/ui/native_select.rb +31 -0
- data/lib/shadcn/ui/navigation_menu.rb +238 -0
- data/lib/shadcn/ui/pagination.rb +224 -0
- data/lib/shadcn/ui/popover.rb +147 -0
- data/lib/shadcn/ui/progress.rb +40 -0
- data/lib/shadcn/ui/radio_group.rb +92 -0
- data/lib/shadcn/ui/resizable.rb +108 -0
- data/lib/shadcn/ui/scroll_area.rb +75 -0
- data/lib/shadcn/ui/select.rb +235 -0
- data/lib/shadcn/ui/separator.rb +36 -0
- data/lib/shadcn/ui/sheet.rb +231 -0
- data/lib/shadcn/ui/sidebar.rb +420 -0
- data/lib/shadcn/ui/skeleton.rb +23 -0
- data/lib/shadcn/ui/slider.rb +72 -0
- data/lib/shadcn/ui/sonner.rb +177 -0
- data/lib/shadcn/ui/spinner.rb +58 -0
- data/lib/shadcn/ui/switch.rb +75 -0
- data/lib/shadcn/ui/table.rb +154 -0
- data/lib/shadcn/ui/tabs.rb +154 -0
- data/lib/shadcn/ui/text_field.rb +146 -0
- data/lib/shadcn/ui/textarea.rb +32 -0
- data/lib/shadcn/ui/theme_toggle.rb +74 -0
- data/lib/shadcn/ui/toggle.rb +66 -0
- data/lib/shadcn/ui/toggle_group.rb +75 -0
- data/lib/shadcn/ui/tooltip.rb +78 -0
- data/lib/shadcn/ui/typography.rb +217 -0
- data/lib/shadcn/version.rb +5 -0
- data/lib/shadcn-phlex.rb +6 -0
- data/lib/shadcn.rb +80 -0
- data/package.json +14 -0
- data/skills/shadcn-phlex/SKILL.md +190 -0
- data/skills/shadcn-phlex/evals/evals.json +90 -0
- data/skills/shadcn-phlex/references/component-catalog.md +355 -0
- data/skills/shadcn-phlex/rules/composition.md +235 -0
- data/skills/shadcn-phlex/rules/forms.md +151 -0
- data/skills/shadcn-phlex/rules/helpers.md +54 -0
- data/skills/shadcn-phlex/rules/stimulus.md +61 -0
- data/skills/shadcn-phlex/rules/styling.md +177 -0
- metadata +209 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Forms & Inputs
|
|
2
|
+
|
|
3
|
+
## Use TextField / TextareaField for common fields
|
|
4
|
+
|
|
5
|
+
Always use compound field helpers for standard labeled inputs — never manual Field + Label + Input + FieldError.
|
|
6
|
+
|
|
7
|
+
### Incorrect
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
ui_field do
|
|
11
|
+
ui_label(for: "email") { "Email" }
|
|
12
|
+
ui_input(name: "user[email]", id: "email", type: "email",
|
|
13
|
+
aria_invalid: @user.errors[:email].any? ? "true" : nil)
|
|
14
|
+
if @user.errors[:email].any?
|
|
15
|
+
ui_field_error { @user.errors[:email].first }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Correct
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
ui_text_field(
|
|
24
|
+
label: "Email",
|
|
25
|
+
name: "user[email]",
|
|
26
|
+
type: "email",
|
|
27
|
+
error: @user.errors[:email]&.first
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Form controls need `name:` for submission
|
|
34
|
+
|
|
35
|
+
Custom controls are **purely visual** without `name:`. The hidden `<input>` is only rendered when `name:` is provided.
|
|
36
|
+
|
|
37
|
+
### Incorrect — data won't submit
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
ui_checkbox(checked: @user.terms_accepted)
|
|
41
|
+
ui_switch(checked: @user.notifications)
|
|
42
|
+
ui_select do
|
|
43
|
+
ui_select_trigger { ui_select_value(placeholder: "Role") }
|
|
44
|
+
ui_select_content { ui_select_item(value: "admin") { "Admin" } }
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Correct — data submits
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
ui_checkbox(name: "user[terms_accepted]", checked: @user.terms_accepted)
|
|
52
|
+
ui_switch(name: "user[notifications]", checked: @user.notifications)
|
|
53
|
+
ui_select(name: "user[role]") do
|
|
54
|
+
ui_select_trigger { ui_select_value(placeholder: "Role") }
|
|
55
|
+
ui_select_content { ui_select_item(value: "admin") { "Admin" } }
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Choosing form controls
|
|
62
|
+
|
|
63
|
+
| Situation | Component |
|
|
64
|
+
|-----------|-----------|
|
|
65
|
+
| Simple text input | `TextField` (compound) or `Input` |
|
|
66
|
+
| Dropdown with predefined options | `Select` |
|
|
67
|
+
| Searchable dropdown | `Combobox` |
|
|
68
|
+
| Native HTML select (no JS) | `NativeSelect` |
|
|
69
|
+
| Boolean toggle (settings page) | `Switch` |
|
|
70
|
+
| Boolean agree/accept (forms, T&C) | `Checkbox` |
|
|
71
|
+
| Single choice from few options | `RadioGroup` |
|
|
72
|
+
| Toggle between 2–5 options | `ToggleGroup` |
|
|
73
|
+
| OTP/verification code | `InputOTP` |
|
|
74
|
+
| Multi-line text | `TextareaField` (compound) or `Textarea` |
|
|
75
|
+
| Numeric range | `Slider` |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Option sets (2–7 choices) use ToggleGroup
|
|
80
|
+
|
|
81
|
+
Don't loop Button with manual active state.
|
|
82
|
+
|
|
83
|
+
### Incorrect
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
%w[daily weekly monthly].each do |option|
|
|
87
|
+
ui_button(variant: @selected == option ? :default : :outline) { option }
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Correct
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
ui_toggle_group do
|
|
95
|
+
ui_toggle_group_item(value: "daily") { "Daily" }
|
|
96
|
+
ui_toggle_group_item(value: "weekly") { "Weekly" }
|
|
97
|
+
ui_toggle_group_item(value: "monthly") { "Monthly" }
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Fieldset + FieldsetLegend for grouping related fields
|
|
104
|
+
|
|
105
|
+
Use `Fieldset` + `FieldsetLegend` for related checkboxes, radios, or switches — not a div with a heading.
|
|
106
|
+
|
|
107
|
+
### Incorrect
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
div do
|
|
111
|
+
h3(class: "text-sm font-medium") { "Preferences" }
|
|
112
|
+
ui_checkbox(name: "prefs[dark]")
|
|
113
|
+
ui_label { "Dark mode" }
|
|
114
|
+
end
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Correct
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
ui_fieldset do
|
|
121
|
+
ui_fieldset_legend { "Preferences" }
|
|
122
|
+
ui_field do
|
|
123
|
+
ui_checkbox(name: "prefs[dark]")
|
|
124
|
+
ui_label { "Dark mode" }
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Validation
|
|
132
|
+
|
|
133
|
+
Pass `error:` to compound fields, or use `aria_invalid:` on controls directly.
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
# Compound (recommended)
|
|
137
|
+
ui_text_field(label: "Email", name: "email", error: @errors[:email]&.first)
|
|
138
|
+
|
|
139
|
+
# Manual
|
|
140
|
+
ui_field do
|
|
141
|
+
ui_label { "Email" }
|
|
142
|
+
ui_input(name: "email", aria_invalid: @errors[:email] ? "true" : nil)
|
|
143
|
+
ui_field_error { @errors[:email].first } if @errors[:email]
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Checkbox / Switch values
|
|
148
|
+
|
|
149
|
+
- `checked: true` → hidden input `value="1"`
|
|
150
|
+
- `checked: false` → hidden input `value="0"`
|
|
151
|
+
- The Stimulus controller updates the value on toggle
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Kit Helper Rules
|
|
2
|
+
|
|
3
|
+
When `Shadcn::Kit` is included in a Phlex view, always use the `ui_*` helper methods. They are shorter, compose naturally, and are the idiomatic way to use shadcn-phlex.
|
|
4
|
+
|
|
5
|
+
## Incorrect
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
class MyView < ApplicationView
|
|
9
|
+
include Shadcn::Kit
|
|
10
|
+
|
|
11
|
+
def view_template
|
|
12
|
+
# Don't use render with Kit included
|
|
13
|
+
render Shadcn::UI::Card.new do
|
|
14
|
+
render Shadcn::UI::CardHeader.new do
|
|
15
|
+
render Shadcn::UI::CardTitle.new { "Title" }
|
|
16
|
+
end
|
|
17
|
+
render Shadcn::UI::CardContent.new do
|
|
18
|
+
render Shadcn::UI::Button.new(variant: :default) { "Click" }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Correct
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
class MyView < ApplicationView
|
|
29
|
+
include Shadcn::Kit
|
|
30
|
+
|
|
31
|
+
def view_template
|
|
32
|
+
ui_card do
|
|
33
|
+
ui_card_header do
|
|
34
|
+
ui_card_title { "Title" }
|
|
35
|
+
end
|
|
36
|
+
ui_card_content do
|
|
37
|
+
ui_button { "Click" }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Helper Naming Convention
|
|
45
|
+
|
|
46
|
+
Every component has a `ui_` prefixed snake_case helper:
|
|
47
|
+
|
|
48
|
+
- `Shadcn::UI::Button` → `ui_button`
|
|
49
|
+
- `Shadcn::UI::CardHeader` → `ui_card_header`
|
|
50
|
+
- `Shadcn::UI::DialogContent` → `ui_dialog_content`
|
|
51
|
+
- `Shadcn::UI::DropdownMenuItem` → `ui_dropdown_menu_item`
|
|
52
|
+
- `Shadcn::UI::TextField` → `ui_text_field`
|
|
53
|
+
|
|
54
|
+
The `ui_` prefix exists to avoid collisions with Phlex's built-in HTML methods (`label`, `input`, `button`, `select`, `table`, `p`).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Stimulus Controller Rules
|
|
2
|
+
|
|
3
|
+
All interactive components are **pre-wired** with Stimulus controllers. Never manually add `data-controller`, `data-action`, or `data-*-target` attributes — the Phlex components handle this automatically.
|
|
4
|
+
|
|
5
|
+
## Incorrect — manually adding Stimulus attributes
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
div(data_controller: "shadcn--dialog", data_shadcn__dialog_open_value: false) do
|
|
9
|
+
button(data_action: "click->shadcn--dialog#show") { "Open" }
|
|
10
|
+
div(data_shadcn__dialog_target: "content") { "Content" }
|
|
11
|
+
end
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Correct — use the components, they wire everything
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
ui_dialog do
|
|
18
|
+
ui_dialog_trigger { "Open" }
|
|
19
|
+
ui_dialog_content do
|
|
20
|
+
ui_dialog_title { "Title" }
|
|
21
|
+
# ...
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Pre-wired components
|
|
27
|
+
|
|
28
|
+
These components automatically include Stimulus controller wiring:
|
|
29
|
+
|
|
30
|
+
| Component | Controller | Behavior |
|
|
31
|
+
|-----------|-----------|----------|
|
|
32
|
+
| `Accordion` | `shadcn--accordion` | Expand/collapse, keyboard nav |
|
|
33
|
+
| `Checkbox` | `shadcn--checkbox` | Toggle checked state |
|
|
34
|
+
| `Collapsible` | `shadcn--collapsible` | Animated open/close |
|
|
35
|
+
| `Combobox` | `shadcn--combobox` | Search, filter, select |
|
|
36
|
+
| `Command` | `shadcn--command` | Cmd+K palette, search |
|
|
37
|
+
| `ContextMenu` | `shadcn--context-menu` | Right-click menu |
|
|
38
|
+
| `Dialog` | `shadcn--dialog` | Focus trap, scroll lock, escape |
|
|
39
|
+
| `Drawer` | `shadcn--drawer` | Swipe to dismiss |
|
|
40
|
+
| `DropdownMenu` | `shadcn--dropdown-menu` | Click toggle, keyboard nav |
|
|
41
|
+
| `HoverCard` | `shadcn--hover-card` | Delayed hover show/hide |
|
|
42
|
+
| `Menubar` | `shadcn--menubar` | Horizontal menu, arrow keys |
|
|
43
|
+
| `NavigationMenu` | `shadcn--navigation-menu` | Hover submenus |
|
|
44
|
+
| `Popover` | `shadcn--popover` | Click toggle, positioning |
|
|
45
|
+
| `RadioGroup` | `shadcn--radio-group` | Single selection, arrows |
|
|
46
|
+
| `ScrollArea` | `shadcn--scroll-area` | Custom scrollbar |
|
|
47
|
+
| `Select` | `shadcn--select` | Custom dropdown, keyboard |
|
|
48
|
+
| `Sheet` | `shadcn--sheet` | Slide panel, focus trap |
|
|
49
|
+
| `Slider` | `shadcn--slider` | Drag, arrow keys |
|
|
50
|
+
| `Switch` | `shadcn--switch` | Toggle on/off |
|
|
51
|
+
| `Tabs` | `shadcn--tabs` | Tab switching, arrow keys |
|
|
52
|
+
| `Toggle` | `shadcn--toggle` | Pressed state |
|
|
53
|
+
| `ToggleGroup` | `shadcn--toggle-group` | Single/multi selection |
|
|
54
|
+
| `Tooltip` | `shadcn--tooltip` | Hover with delay |
|
|
55
|
+
| `ThemeToggle` | `shadcn--dark-mode` | Light/dark/system toggle |
|
|
56
|
+
|
|
57
|
+
## Static components (no controller needed)
|
|
58
|
+
|
|
59
|
+
These render pure HTML/CSS with no JavaScript behavior:
|
|
60
|
+
|
|
61
|
+
`Alert`, `Avatar`, `Badge`, `Breadcrumb`, `Button`, `Card`, `Empty`, `Field`, `Input`, `InputGroup`, `Item`, `Kbd`, `Label`, `NativeSelect`, `Pagination`, `Progress`, `Separator`, `Skeleton`, `Spinner`, `Table`, `Textarea`, `Typography*`
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Styling & Tailwind
|
|
2
|
+
|
|
3
|
+
## Semantic colors
|
|
4
|
+
|
|
5
|
+
### Incorrect
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
div(class: "bg-blue-500 text-white") do
|
|
9
|
+
p(class: "text-gray-600") { "Secondary text" }
|
|
10
|
+
end
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Correct
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
div(class: "bg-primary text-primary-foreground") do
|
|
17
|
+
p(class: "text-muted-foreground") { "Secondary text" }
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## No raw color values for status indicators
|
|
24
|
+
|
|
25
|
+
Use Badge variants or semantic tokens — don't reach for raw Tailwind colors.
|
|
26
|
+
|
|
27
|
+
### Incorrect
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
span(class: "text-emerald-600") { "+20.1%" }
|
|
31
|
+
span(class: "text-red-600") { "-3.2%" }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Correct
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
ui_badge(variant: :secondary) { "+20.1%" }
|
|
38
|
+
span(class: "text-destructive") { "-3.2%" }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Built-in variants first
|
|
44
|
+
|
|
45
|
+
### Incorrect
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
ui_button(class: "border border-input bg-transparent hover:bg-accent") { "Click" }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Correct
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
ui_button(variant: :outline) { "Click" }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## `class:` for layout, not styling
|
|
60
|
+
|
|
61
|
+
Use `class:` for layout (`max-w-md`, `mx-auto`, `mt-4`), **not** for overriding component colors or typography.
|
|
62
|
+
|
|
63
|
+
### Incorrect
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
ui_card(class: "bg-blue-100 text-blue-900 font-bold") do
|
|
67
|
+
ui_card_content { "Dashboard" }
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Correct
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
ui_card(class: "max-w-md mx-auto") do
|
|
75
|
+
ui_card_content { "Dashboard" }
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## No `space-x-*` / `space-y-*`
|
|
82
|
+
|
|
83
|
+
Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`.
|
|
84
|
+
|
|
85
|
+
### Incorrect
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
div(class: "space-y-4") do
|
|
89
|
+
ui_input(name: "email")
|
|
90
|
+
ui_input(name: "password")
|
|
91
|
+
ui_button { "Submit" }
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Correct
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
div(class: "flex flex-col gap-4") do
|
|
99
|
+
ui_input(name: "email")
|
|
100
|
+
ui_input(name: "password")
|
|
101
|
+
ui_button { "Submit" }
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Prefer `size-*` over `w-* h-*` when equal
|
|
108
|
+
|
|
109
|
+
`size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Prefer `truncate` shorthand
|
|
114
|
+
|
|
115
|
+
`truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## No manual `dark:` color overrides
|
|
120
|
+
|
|
121
|
+
Use semantic tokens — they handle light/dark via CSS variables.
|
|
122
|
+
|
|
123
|
+
### Incorrect
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
div(class: "bg-white dark:bg-gray-950 text-black dark:text-white") { "Content" }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Correct
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
div(class: "bg-background text-foreground") { "Content" }
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Use `cn()` in custom components
|
|
138
|
+
|
|
139
|
+
When building custom Phlex components that extend shadcn-phlex, inherit from `Shadcn::Base` to get the `cn()` helper for intelligent Tailwind class merging.
|
|
140
|
+
|
|
141
|
+
### Incorrect
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
class MyComponent < Phlex::HTML
|
|
145
|
+
def view_template
|
|
146
|
+
div(class: "#{@base_classes} #{@extra_classes}") { "content" }
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Correct
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
class MyComponent < Shadcn::Base
|
|
155
|
+
def view_template
|
|
156
|
+
div(class: cn("rounded-md border p-4", @attrs.delete(:class))) { "content" }
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## No manual `z-index` on overlay components
|
|
164
|
+
|
|
165
|
+
Dialog, Sheet, Drawer, AlertDialog, DropdownMenu, Popover, Tooltip, HoverCard handle their own stacking. Never add `z-50` or `z-[999]`.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Class merging
|
|
170
|
+
|
|
171
|
+
All components support a `class:` attribute that merges with defaults using `tailwind_merge`. Conflicting classes are resolved — user classes win:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
ui_button(class: "w-full") # adds w-full to button classes
|
|
175
|
+
ui_button(class: "rounded-none") # overrides default rounded-md
|
|
176
|
+
ui_card(class: "max-w-sm") # adds width constraint
|
|
177
|
+
```
|
metadata
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: shadcn-phlex
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- cole-robertson
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-03-17 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: phlex
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: phlex-rails
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.1'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.1'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: class_variants
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: tailwind_merge
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.0'
|
|
68
|
+
description: All shadcn/ui v4 components ported to Phlex with Stimulus controllers,
|
|
69
|
+
7 base color themes, 17 accent colors, and Rails generators.
|
|
70
|
+
executables: []
|
|
71
|
+
extensions: []
|
|
72
|
+
extra_rdoc_files: []
|
|
73
|
+
files:
|
|
74
|
+
- README.md
|
|
75
|
+
- app.css
|
|
76
|
+
- css/shadcn-source.css
|
|
77
|
+
- css/shadcn-tailwind.css
|
|
78
|
+
- css/themes/mauve.css
|
|
79
|
+
- css/themes/mist.css
|
|
80
|
+
- css/themes/neutral.css
|
|
81
|
+
- css/themes/olive.css
|
|
82
|
+
- css/themes/stone.css
|
|
83
|
+
- css/themes/taupe.css
|
|
84
|
+
- css/themes/zinc.css
|
|
85
|
+
- js/controllers/accordion_controller.js
|
|
86
|
+
- js/controllers/checkbox_controller.js
|
|
87
|
+
- js/controllers/collapsible_controller.js
|
|
88
|
+
- js/controllers/combobox_controller.js
|
|
89
|
+
- js/controllers/command_controller.js
|
|
90
|
+
- js/controllers/context_menu_controller.js
|
|
91
|
+
- js/controllers/dark_mode_controller.js
|
|
92
|
+
- js/controllers/dialog_controller.js
|
|
93
|
+
- js/controllers/drawer_controller.js
|
|
94
|
+
- js/controllers/dropdown_menu_controller.js
|
|
95
|
+
- js/controllers/hover_card_controller.js
|
|
96
|
+
- js/controllers/index.js
|
|
97
|
+
- js/controllers/menubar_controller.js
|
|
98
|
+
- js/controllers/navigation_menu_controller.js
|
|
99
|
+
- js/controllers/popover_controller.js
|
|
100
|
+
- js/controllers/radio_group_controller.js
|
|
101
|
+
- js/controllers/scroll_area_controller.js
|
|
102
|
+
- js/controllers/select_controller.js
|
|
103
|
+
- js/controllers/sheet_controller.js
|
|
104
|
+
- js/controllers/slider_controller.js
|
|
105
|
+
- js/controllers/switch_controller.js
|
|
106
|
+
- js/controllers/tabs_controller.js
|
|
107
|
+
- js/controllers/toast_controller.js
|
|
108
|
+
- js/controllers/toggle_controller.js
|
|
109
|
+
- js/controllers/toggle_group_controller.js
|
|
110
|
+
- js/controllers/tooltip_controller.js
|
|
111
|
+
- lib/generators/shadcn_phlex/component_generator.rb
|
|
112
|
+
- lib/generators/shadcn_phlex/install_generator.rb
|
|
113
|
+
- lib/shadcn-phlex.rb
|
|
114
|
+
- lib/shadcn.rb
|
|
115
|
+
- lib/shadcn/base.rb
|
|
116
|
+
- lib/shadcn/engine.rb
|
|
117
|
+
- lib/shadcn/kit.rb
|
|
118
|
+
- lib/shadcn/themes/accent_colors.rb
|
|
119
|
+
- lib/shadcn/themes/base_colors.rb
|
|
120
|
+
- lib/shadcn/ui/accordion.rb
|
|
121
|
+
- lib/shadcn/ui/alert.rb
|
|
122
|
+
- lib/shadcn/ui/alert_dialog.rb
|
|
123
|
+
- lib/shadcn/ui/aspect_ratio.rb
|
|
124
|
+
- lib/shadcn/ui/avatar.rb
|
|
125
|
+
- lib/shadcn/ui/badge.rb
|
|
126
|
+
- lib/shadcn/ui/breadcrumb.rb
|
|
127
|
+
- lib/shadcn/ui/button.rb
|
|
128
|
+
- lib/shadcn/ui/button_group.rb
|
|
129
|
+
- lib/shadcn/ui/card.rb
|
|
130
|
+
- lib/shadcn/ui/checkbox.rb
|
|
131
|
+
- lib/shadcn/ui/collapsible.rb
|
|
132
|
+
- lib/shadcn/ui/combobox.rb
|
|
133
|
+
- lib/shadcn/ui/command.rb
|
|
134
|
+
- lib/shadcn/ui/context_menu.rb
|
|
135
|
+
- lib/shadcn/ui/dialog.rb
|
|
136
|
+
- lib/shadcn/ui/direction.rb
|
|
137
|
+
- lib/shadcn/ui/drawer.rb
|
|
138
|
+
- lib/shadcn/ui/dropdown_menu.rb
|
|
139
|
+
- lib/shadcn/ui/empty.rb
|
|
140
|
+
- lib/shadcn/ui/field.rb
|
|
141
|
+
- lib/shadcn/ui/hover_card.rb
|
|
142
|
+
- lib/shadcn/ui/input.rb
|
|
143
|
+
- lib/shadcn/ui/input_group.rb
|
|
144
|
+
- lib/shadcn/ui/input_otp.rb
|
|
145
|
+
- lib/shadcn/ui/item.rb
|
|
146
|
+
- lib/shadcn/ui/kbd.rb
|
|
147
|
+
- lib/shadcn/ui/label.rb
|
|
148
|
+
- lib/shadcn/ui/menubar.rb
|
|
149
|
+
- lib/shadcn/ui/native_select.rb
|
|
150
|
+
- lib/shadcn/ui/navigation_menu.rb
|
|
151
|
+
- lib/shadcn/ui/pagination.rb
|
|
152
|
+
- lib/shadcn/ui/popover.rb
|
|
153
|
+
- lib/shadcn/ui/progress.rb
|
|
154
|
+
- lib/shadcn/ui/radio_group.rb
|
|
155
|
+
- lib/shadcn/ui/resizable.rb
|
|
156
|
+
- lib/shadcn/ui/scroll_area.rb
|
|
157
|
+
- lib/shadcn/ui/select.rb
|
|
158
|
+
- lib/shadcn/ui/separator.rb
|
|
159
|
+
- lib/shadcn/ui/sheet.rb
|
|
160
|
+
- lib/shadcn/ui/sidebar.rb
|
|
161
|
+
- lib/shadcn/ui/skeleton.rb
|
|
162
|
+
- lib/shadcn/ui/slider.rb
|
|
163
|
+
- lib/shadcn/ui/sonner.rb
|
|
164
|
+
- lib/shadcn/ui/spinner.rb
|
|
165
|
+
- lib/shadcn/ui/switch.rb
|
|
166
|
+
- lib/shadcn/ui/table.rb
|
|
167
|
+
- lib/shadcn/ui/tabs.rb
|
|
168
|
+
- lib/shadcn/ui/text_field.rb
|
|
169
|
+
- lib/shadcn/ui/textarea.rb
|
|
170
|
+
- lib/shadcn/ui/theme_toggle.rb
|
|
171
|
+
- lib/shadcn/ui/toggle.rb
|
|
172
|
+
- lib/shadcn/ui/toggle_group.rb
|
|
173
|
+
- lib/shadcn/ui/tooltip.rb
|
|
174
|
+
- lib/shadcn/ui/typography.rb
|
|
175
|
+
- lib/shadcn/version.rb
|
|
176
|
+
- package.json
|
|
177
|
+
- skills/shadcn-phlex/SKILL.md
|
|
178
|
+
- skills/shadcn-phlex/evals/evals.json
|
|
179
|
+
- skills/shadcn-phlex/references/component-catalog.md
|
|
180
|
+
- skills/shadcn-phlex/rules/composition.md
|
|
181
|
+
- skills/shadcn-phlex/rules/forms.md
|
|
182
|
+
- skills/shadcn-phlex/rules/helpers.md
|
|
183
|
+
- skills/shadcn-phlex/rules/stimulus.md
|
|
184
|
+
- skills/shadcn-phlex/rules/styling.md
|
|
185
|
+
homepage: https://github.com/cole-robertson/shadcn-phlex
|
|
186
|
+
licenses:
|
|
187
|
+
- MIT
|
|
188
|
+
metadata:
|
|
189
|
+
homepage_uri: https://github.com/cole-robertson/shadcn-phlex
|
|
190
|
+
source_code_uri: https://github.com/cole-robertson/shadcn-phlex
|
|
191
|
+
changelog_uri: https://github.com/cole-robertson/shadcn-phlex/commits/master
|
|
192
|
+
rdoc_options: []
|
|
193
|
+
require_paths:
|
|
194
|
+
- lib
|
|
195
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
196
|
+
requirements:
|
|
197
|
+
- - ">="
|
|
198
|
+
- !ruby/object:Gem::Version
|
|
199
|
+
version: 3.1.0
|
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
|
+
requirements:
|
|
202
|
+
- - ">="
|
|
203
|
+
- !ruby/object:Gem::Version
|
|
204
|
+
version: '0'
|
|
205
|
+
requirements: []
|
|
206
|
+
rubygems_version: 3.6.2
|
|
207
|
+
specification_version: 4
|
|
208
|
+
summary: Complete shadcn/ui component library for Phlex Rails
|
|
209
|
+
test_files: []
|