maquina-components 0.2.0 → 0.3.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 +4 -4
- data/README.md +51 -0
- data/app/assets/stylesheets/combobox.css +218 -0
- data/app/assets/stylesheets/toast.css +433 -0
- data/app/assets/tailwind/maquina_components_engine/engine.css +2 -0
- data/app/helpers/maquina_components/combobox_helper.rb +300 -0
- data/app/helpers/maquina_components/toast_helper.rb +115 -0
- data/app/javascript/controllers/combobox_controller.js +325 -0
- data/app/javascript/controllers/toast_controller.js +115 -0
- data/app/javascript/controllers/toaster_controller.js +226 -0
- data/app/views/components/_combobox.html.erb +13 -0
- data/app/views/components/_toast.html.erb +53 -0
- data/app/views/components/_toaster.html.erb +17 -0
- data/app/views/components/combobox/_content.html.erb +17 -0
- data/app/views/components/combobox/_empty.html.erb +9 -0
- data/app/views/components/combobox/_group.html.erb +8 -0
- data/app/views/components/combobox/_input.html.erb +18 -0
- data/app/views/components/combobox/_label.html.erb +8 -0
- data/app/views/components/combobox/_list.html.erb +8 -0
- data/app/views/components/combobox/_option.html.erb +24 -0
- data/app/views/components/combobox/_separator.html.erb +6 -0
- data/app/views/components/combobox/_trigger.html.erb +22 -0
- data/app/views/components/toast/_action.html.erb +14 -0
- data/app/views/components/toast/_description.html.erb +8 -0
- data/app/views/components/toast/_title.html.erb +8 -0
- data/lib/maquina_components/version.rb +1 -1
- metadata +24 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e04564783a082eb56e58395e1de24dc21deb1312c49ebc47e48428a4230e6925
|
|
4
|
+
data.tar.gz: 78630e11ca92ae6a964c2bc100a7357722d7618df3a5a0a7d0619bbc48eeb5d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 225bbf4a0100ac2f80a03e3bcf38f6080365db13228fade762fa5c8378631b2f0aa5d45d71654e2ecfa6577fe88f9c317163a8c29b44f003657146870bd3c44f
|
|
7
|
+
data.tar.gz: f3b563c5a789cb8039fc5e30e5461114556ca37289bd2b9859b0516973f1c4d7f54204745ad48628271ae24574522784cae4e8865f83e596326b5707d903a4ea
|
data/README.md
CHANGED
|
@@ -152,8 +152,15 @@ bin/rails generate maquina_components:install --skip-helper
|
|
|
152
152
|
|
|
153
153
|
| Component | Description | Documentation |
|
|
154
154
|
|-----------|-------------|---------------|
|
|
155
|
+
| **Combobox** | Searchable dropdown with keyboard navigation | [Combobox](https://maquina.app/documentation/components/combobox/) |
|
|
155
156
|
| **Toggle Group** | Single/multiple selection button group | [Toggle Group](https://maquina.app/documentation/components/toggle-group/) |
|
|
156
157
|
|
|
158
|
+
### Feedback Components
|
|
159
|
+
|
|
160
|
+
| Component | Description | Documentation |
|
|
161
|
+
|-----------|-------------|---------------|
|
|
162
|
+
| **Toast** | Non-intrusive notifications with auto-dismiss | [Toast](https://maquina.app/documentation/components/toast/) |
|
|
163
|
+
|
|
157
164
|
### Form Components
|
|
158
165
|
|
|
159
166
|
| Component | Data Attribute | Variants |
|
|
@@ -252,6 +259,41 @@ bin/rails generate maquina_components:install --skip-helper
|
|
|
252
259
|
<%= pagination_nav(@pagy, :users_path) %>
|
|
253
260
|
```
|
|
254
261
|
|
|
262
|
+
### Combobox
|
|
263
|
+
|
|
264
|
+
```erb
|
|
265
|
+
<%= render "components/combobox", placeholder: "Select framework..." do |combobox_id| %>
|
|
266
|
+
<%= render "components/combobox/trigger", for_id: combobox_id, placeholder: "Select framework..." %>
|
|
267
|
+
<%= render "components/combobox/content", id: combobox_id do %>
|
|
268
|
+
<%= render "components/combobox/input", placeholder: "Search..." %>
|
|
269
|
+
<%= render "components/combobox/list" do %>
|
|
270
|
+
<%= render "components/combobox/option", value: "rails" do %>Ruby on Rails<% end %>
|
|
271
|
+
<%= render "components/combobox/option", value: "hanami" do %>Hanami<% end %>
|
|
272
|
+
<%= render "components/combobox/option", value: "sinatra" do %>Sinatra<% end %>
|
|
273
|
+
<% end %>
|
|
274
|
+
<%= render "components/combobox/empty" %>
|
|
275
|
+
<% end %>
|
|
276
|
+
<% end %>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Toast Notifications
|
|
280
|
+
|
|
281
|
+
```erb
|
|
282
|
+
<%# Add toaster to your layout %>
|
|
283
|
+
<%= render "components/toaster", position: :bottom_right do %>
|
|
284
|
+
<%= toast_flash_messages %>
|
|
285
|
+
<% end %>
|
|
286
|
+
|
|
287
|
+
<%# In your controller %>
|
|
288
|
+
flash[:success] = "Changes saved successfully!"
|
|
289
|
+
|
|
290
|
+
<%# Or use the JavaScript API %>
|
|
291
|
+
<script>
|
|
292
|
+
Toast.success("Profile updated!")
|
|
293
|
+
Toast.error("Something went wrong", { description: "Please try again." })
|
|
294
|
+
</script>
|
|
295
|
+
```
|
|
296
|
+
|
|
255
297
|
### Tables
|
|
256
298
|
|
|
257
299
|
```erb
|
|
@@ -349,6 +391,10 @@ The install generator adds default theme variables. Customize them in `app/asset
|
|
|
349
391
|
| `sidebar_open?(cookie_name)` | Check if the sidebar is expanded |
|
|
350
392
|
| `pagination_nav(pagy, route)` | Render pagination from Pagy object |
|
|
351
393
|
| `pagination_simple(pagy, route)` | Render simple Previous/Next pagination |
|
|
394
|
+
| `toast_flash_messages` | Render all flash messages as toasts |
|
|
395
|
+
| `toast(variant, title, **options)` | Render a single toast notification |
|
|
396
|
+
| `combobox(placeholder:, **options, &block)` | Builder pattern for combobox |
|
|
397
|
+
| `combobox_simple(options:, **options)` | Data-driven simple combobox |
|
|
352
398
|
|
|
353
399
|
---
|
|
354
400
|
|
|
@@ -379,8 +425,13 @@ The install generator adds default theme variables. Customize them in `app/asset
|
|
|
379
425
|
|
|
380
426
|
### Interactive
|
|
381
427
|
|
|
428
|
+
- **[Combobox](https://maquina.app/documentation/components/combobox/)** — Searchable dropdown selection
|
|
382
429
|
- **[Toggle Group](https://maquina.app/documentation/components/toggle-group/)** — Toggle button groups
|
|
383
430
|
|
|
431
|
+
### Feedback
|
|
432
|
+
|
|
433
|
+
- **[Toast](https://maquina.app/documentation/components/toast/)** — Toast notifications
|
|
434
|
+
|
|
384
435
|
### Forms
|
|
385
436
|
|
|
386
437
|
- **[Form Components](https://maquina.app/documentation/components/form/)** — Buttons, inputs, and form styling
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/* ===== Combobox Component Styles ===== */
|
|
2
|
+
/*
|
|
3
|
+
* Combobox component for autocomplete/search with selection.
|
|
4
|
+
* Uses HTML5 Popover API for positioning and light-dismiss.
|
|
5
|
+
* Uses data attributes for styling to avoid inline utility classes.
|
|
6
|
+
* Fully compatible with dark mode via CSS variables.
|
|
7
|
+
*
|
|
8
|
+
* Structure:
|
|
9
|
+
* - combobox (root with Stimulus controller)
|
|
10
|
+
* - trigger (button that opens popover)
|
|
11
|
+
* - content (popover container)
|
|
12
|
+
* - input (search field)
|
|
13
|
+
* - list (scrollable options)
|
|
14
|
+
* - option (selectable item)
|
|
15
|
+
* - group (logical grouping)
|
|
16
|
+
* - label (section heading)
|
|
17
|
+
* - separator (divider)
|
|
18
|
+
* - empty (no results message)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/* ===== Root Container ===== */
|
|
22
|
+
[data-component="combobox"] {
|
|
23
|
+
position: relative;
|
|
24
|
+
display: inline-block;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* ===== Trigger Button ===== */
|
|
28
|
+
/* Trigger uses button component styles via data-component="button" */
|
|
29
|
+
[data-combobox-part="trigger"] {
|
|
30
|
+
@apply justify-between gap-2;
|
|
31
|
+
min-width: 200px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
[data-combobox-part="trigger"] [data-combobox-target="label"] {
|
|
35
|
+
@apply truncate text-left flex-1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Placeholder state */
|
|
39
|
+
[data-combobox-part="trigger"][data-has-value="false"] [data-combobox-target="label"] {
|
|
40
|
+
color: var(--muted-foreground);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Icon styling */
|
|
44
|
+
[data-combobox-part="trigger"] > svg {
|
|
45
|
+
@apply size-4 shrink-0 opacity-50;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ===== Content (Popover) ===== */
|
|
49
|
+
[data-combobox-part="content"] {
|
|
50
|
+
background-color: var(--popover, var(--background));
|
|
51
|
+
color: var(--popover-foreground, var(--foreground));
|
|
52
|
+
border-color: var(--border);
|
|
53
|
+
@apply rounded-md border p-0 shadow-md outline-none;
|
|
54
|
+
@apply min-w-[200px];
|
|
55
|
+
|
|
56
|
+
/* Reset popover defaults - positioning handled by JS */
|
|
57
|
+
margin: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
inset: unset;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Width variants */
|
|
63
|
+
[data-combobox-part="content"][data-width="sm"] {
|
|
64
|
+
@apply w-40;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[data-combobox-part="content"][data-width="default"] {
|
|
68
|
+
@apply w-[200px];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
[data-combobox-part="content"][data-width="md"] {
|
|
72
|
+
@apply w-56;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
[data-combobox-part="content"][data-width="lg"] {
|
|
76
|
+
@apply w-72;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[data-combobox-part="content"][data-width="full"] {
|
|
80
|
+
@apply w-full;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Alignment is handled by JavaScript for proper popover positioning */
|
|
84
|
+
|
|
85
|
+
/* Animation */
|
|
86
|
+
[data-combobox-part="content"]:popover-open {
|
|
87
|
+
animation: combobox-in 150ms ease-out;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes combobox-in {
|
|
91
|
+
from {
|
|
92
|
+
opacity: 0;
|
|
93
|
+
transform: scale(0.95) translateY(-4px);
|
|
94
|
+
}
|
|
95
|
+
to {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
transform: scale(1) translateY(0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ===== Search Input ===== */
|
|
102
|
+
[data-combobox-part="input-wrapper"] {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
border-bottom: 1px solid var(--border);
|
|
106
|
+
@apply px-3 gap-2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
[data-combobox-part="input-wrapper"] > svg {
|
|
110
|
+
@apply size-4 shrink-0 opacity-50;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
[data-combobox-part="input"] {
|
|
114
|
+
background-color: transparent;
|
|
115
|
+
color: var(--foreground);
|
|
116
|
+
@apply flex h-10 w-full py-3 text-sm outline-none;
|
|
117
|
+
@apply placeholder:text-muted-foreground;
|
|
118
|
+
@apply disabled:cursor-not-allowed disabled:opacity-50;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ===== Options List ===== */
|
|
122
|
+
[data-combobox-part="list"] {
|
|
123
|
+
@apply max-h-[300px] overflow-y-auto overflow-x-hidden p-1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ===== Option Item ===== */
|
|
127
|
+
[data-combobox-part="option"] {
|
|
128
|
+
position: relative;
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
cursor: default;
|
|
132
|
+
user-select: none;
|
|
133
|
+
color: var(--popover-foreground, var(--foreground));
|
|
134
|
+
@apply gap-2 rounded-sm py-1.5 text-sm outline-none transition-colors;
|
|
135
|
+
@apply pl-8 pr-2; /* Space for check icon on left */
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Hover state */
|
|
139
|
+
[data-combobox-part="option"]:hover:not([aria-disabled="true"]) {
|
|
140
|
+
background-color: var(--accent);
|
|
141
|
+
color: var(--accent-foreground);
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Focus state (keyboard navigation) */
|
|
146
|
+
[data-combobox-part="option"]:focus {
|
|
147
|
+
background-color: var(--accent);
|
|
148
|
+
color: var(--accent-foreground);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Selected state */
|
|
152
|
+
[data-combobox-part="option"][data-selected="true"] {
|
|
153
|
+
background-color: var(--accent);
|
|
154
|
+
color: var(--accent-foreground);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Disabled state */
|
|
158
|
+
[data-combobox-part="option"][aria-disabled="true"] {
|
|
159
|
+
@apply opacity-50 cursor-not-allowed pointer-events-none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Hidden state (filtered out) */
|
|
163
|
+
[data-combobox-part="option"][hidden] {
|
|
164
|
+
display: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Check indicator */
|
|
168
|
+
[data-combobox-part="check"] {
|
|
169
|
+
position: absolute;
|
|
170
|
+
left: 8px;
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
@apply size-4;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[data-combobox-part="check"].invisible {
|
|
178
|
+
visibility: hidden;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
[data-combobox-part="check"] svg {
|
|
182
|
+
@apply size-4;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ===== Empty State ===== */
|
|
186
|
+
[data-combobox-part="empty"] {
|
|
187
|
+
@apply py-6 text-center text-sm;
|
|
188
|
+
color: var(--muted-foreground);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
[data-combobox-part="empty"][hidden] {
|
|
192
|
+
display: none;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* ===== Group ===== */
|
|
196
|
+
[data-combobox-part="group"] {
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ===== Label ===== */
|
|
202
|
+
[data-combobox-part="label"] {
|
|
203
|
+
@apply px-2 py-1.5 text-xs font-medium;
|
|
204
|
+
color: var(--muted-foreground);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* ===== Separator ===== */
|
|
208
|
+
[data-combobox-part="separator"] {
|
|
209
|
+
@apply -mx-1 my-1 h-px;
|
|
210
|
+
background-color: var(--border);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* ===== Dark Mode ===== */
|
|
214
|
+
/*
|
|
215
|
+
* Dark mode is handled automatically through CSS variables.
|
|
216
|
+
* The theme variables change based on the .dark class on html/body.
|
|
217
|
+
* No additional dark mode styles needed here.
|
|
218
|
+
*/
|