maquina-components 0.5.1 → 0.6.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 +76 -2
- data/app/assets/stylesheets/alert.css +169 -135
- data/app/assets/stylesheets/badge.css +143 -138
- data/app/assets/stylesheets/breadcrumbs.css +183 -166
- data/app/assets/stylesheets/calendar.css +219 -206
- data/app/assets/stylesheets/card.css +126 -120
- data/app/assets/stylesheets/combobox.css +208 -191
- data/app/assets/stylesheets/date_picker.css +144 -134
- data/app/assets/stylesheets/drawer.css +158 -125
- data/app/assets/stylesheets/dropdown_menu.css +203 -190
- data/app/assets/stylesheets/empty.css +125 -117
- data/app/assets/stylesheets/form.css +625 -525
- data/app/assets/stylesheets/header.css +63 -47
- data/app/assets/stylesheets/menu_button.css +121 -98
- data/app/assets/stylesheets/pagination.css +130 -125
- data/app/assets/stylesheets/separator.css +23 -11
- data/app/assets/stylesheets/sidebar.css +447 -401
- data/app/assets/stylesheets/stats.css +77 -67
- data/app/assets/stylesheets/table.css +184 -166
- data/app/assets/stylesheets/toast.css +287 -278
- data/app/assets/stylesheets/toggle_group.css +132 -139
- data/app/assets/tailwind/maquina_components_engine/engine.css +54 -15
- data/app/assets/tailwind/maquina_components_engine/tokens.css +101 -0
- data/app/helpers/maquina_components/combobox_helper.rb +32 -24
- data/app/helpers/maquina_components/components_helper.rb +30 -6
- data/app/helpers/maquina_components/dropdown_menu_helper.rb +12 -12
- data/app/helpers/maquina_components/icons_helper.rb +26 -2
- data/app/javascript/controllers/drawer_trigger_controller.js +24 -3
- data/app/views/components/_label.html.erb +14 -0
- data/app/views/components/_table.html.erb +2 -2
- data/app/views/components/calendar/_week.html.erb +4 -12
- data/app/views/components/drawer/_close.html.erb +1 -1
- data/app/views/components/drawer/_description.html.erb +6 -0
- data/app/views/components/drawer/_header.html.erb +1 -1
- data/app/views/components/drawer/_provider.html.erb +13 -4
- data/app/views/components/drawer/_section.html.erb +7 -0
- data/app/views/components/drawer/_separator.html.erb +11 -0
- data/app/views/components/drawer/_title.html.erb +6 -0
- data/app/views/components/drawer/_trigger.html.erb +24 -7
- data/app/views/components/sidebar/_group_action.html.erb +26 -0
- data/app/views/components/sidebar/_menu_action.html.erb +28 -0
- data/app/views/components/sidebar/_menu_badge.html.erb +10 -0
- data/app/views/components/sidebar/_menu_button.html.erb +3 -2
- data/app/views/components/sidebar/_menu_link.html.erb +3 -2
- data/app/views/components/sidebar/_separator.html.erb +12 -0
- data/lib/generators/maquina_components/install/install_generator.rb +36 -1
- data/lib/generators/maquina_components/install/templates/maquina_components_helper.rb.tt +5 -0
- data/lib/generators/maquina_components/install/templates/shape_state_tokens.css.tt +76 -0
- data/lib/generators/maquina_components/install/templates/theme.css.tt +10 -3
- data/lib/maquina-components.rb +29 -1
- data/lib/maquina_components/doctor.rb +280 -0
- data/lib/maquina_components/version.rb +1 -1
- data/lib/tasks/maquina_components_tasks.rake +16 -4
- metadata +14 -2
|
@@ -16,238 +16,255 @@
|
|
|
16
16
|
* - label (section heading)
|
|
17
17
|
* - separator (divider)
|
|
18
18
|
* - empty (no results message)
|
|
19
|
+
*
|
|
20
|
+
* Cascade order in this file (full contract documented in form.css):
|
|
21
|
+
* 1. base [data-component="combobox"], [data-combobox-part="…"]
|
|
22
|
+
* 2. sizes [data-combobox-part="content"]:where([data-width="…"])
|
|
23
|
+
* 3. variants :where([data-align="…"], [data-has-value="false"])
|
|
24
|
+
* 4. states […]:where(:hover, :focus, [data-selected], [aria-disabled], [hidden])
|
|
25
|
+
* 5. dark — none; dark-mode differences are tokens (see tokens.css)
|
|
26
|
+
* Every rule is flattened to 0,1,0 with :where() and lives in
|
|
27
|
+
* @layer components, so a caller's utility class wins and source order is
|
|
28
|
+
* the only tie-breaker. (Rules whose target is a bare element read 0,1,1 — an
|
|
29
|
+
* element selector cannot be zeroed away.) @keyframes sit outside the layer:
|
|
30
|
+
* they take no part in the cascade.
|
|
31
|
+
*
|
|
32
|
+
* The trigger carries data-component="button" (it is where the trigger's
|
|
33
|
+
* justify-content and min-width have to beat the button base), so this file
|
|
34
|
+
* must be imported after form.css. See engine.css.
|
|
19
35
|
*/
|
|
20
36
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 below (anchor CSS) or in JS fallback */
|
|
57
|
-
margin: 0;
|
|
58
|
-
padding: 0;
|
|
59
|
-
inset: unset;
|
|
60
|
-
}
|
|
37
|
+
@layer components {
|
|
38
|
+
/* ===== Root Container ===== */
|
|
39
|
+
[data-component="combobox"] {
|
|
40
|
+
position: relative;
|
|
41
|
+
display: inline-block;
|
|
42
|
+
}
|
|
61
43
|
|
|
62
|
-
/* =====
|
|
63
|
-
/*
|
|
64
|
-
measured fallback when these features are supported. flip-block flips the
|
|
65
|
-
popover above the trigger when there is no room below — something the JS
|
|
66
|
-
fallback never did. */
|
|
67
|
-
@supports (anchor-name: --a) and (position-area: block-end) {
|
|
44
|
+
/* ===== Trigger Button ===== */
|
|
45
|
+
/* Trigger uses button component styles via data-component="button" */
|
|
68
46
|
[data-combobox-part="trigger"] {
|
|
69
|
-
|
|
47
|
+
@apply justify-between gap-2;
|
|
48
|
+
min-width: 200px;
|
|
70
49
|
}
|
|
71
50
|
|
|
72
|
-
[data-combobox-part="
|
|
73
|
-
|
|
74
|
-
position-anchor: --maquina-combobox;
|
|
75
|
-
margin-block-start: 4px;
|
|
76
|
-
position-try-fallbacks: flip-block;
|
|
51
|
+
:where([data-combobox-part="trigger"]) [data-combobox-target="label"] {
|
|
52
|
+
@apply truncate text-left flex-1;
|
|
77
53
|
}
|
|
78
54
|
|
|
79
|
-
|
|
80
|
-
|
|
55
|
+
/* Icon styling */
|
|
56
|
+
:where([data-combobox-part="trigger"]) > svg {
|
|
57
|
+
@apply size-4 shrink-0 opacity-50;
|
|
81
58
|
}
|
|
82
59
|
|
|
83
|
-
|
|
84
|
-
|
|
60
|
+
/* Placeholder state */
|
|
61
|
+
:where([data-combobox-part="trigger"][data-has-value="false"]) [data-combobox-target="label"] {
|
|
62
|
+
color: var(--muted-foreground);
|
|
85
63
|
}
|
|
86
64
|
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
/* ===== Content (Popover) ===== */
|
|
66
|
+
[data-combobox-part="content"] {
|
|
67
|
+
background-color: var(--popover, var(--background));
|
|
68
|
+
color: var(--popover-foreground, var(--foreground));
|
|
69
|
+
border-color: var(--border);
|
|
70
|
+
@apply border p-0 outline-none;
|
|
71
|
+
border-radius: var(--combobox-radius, var(--surface-radius, 0.5rem));
|
|
72
|
+
box-shadow: var(--combobox-shadow, var(--elevation-overlay, var(--shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1))));
|
|
73
|
+
@apply min-w-[200px];
|
|
74
|
+
|
|
75
|
+
/* Reset popover defaults - positioning below (anchor CSS) or in JS fallback */
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
inset: unset;
|
|
89
79
|
}
|
|
90
80
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
/* ===== Anchor Positioning (modern browsers) ===== */
|
|
82
|
+
/* Places the top-layer popover declaratively; combobox_controller skips its
|
|
83
|
+
measured fallback when these features are supported. flip-block flips the
|
|
84
|
+
popover above the trigger when there is no room below — something the JS
|
|
85
|
+
fallback never did. */
|
|
86
|
+
@supports (anchor-name: --a) and (position-area: block-end) {
|
|
87
|
+
[data-combobox-part="trigger"] {
|
|
88
|
+
anchor-name: --maquina-combobox;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
[data-combobox-part="content"] {
|
|
92
|
+
position: fixed;
|
|
93
|
+
position-anchor: --maquina-combobox;
|
|
94
|
+
margin-block-start: 4px;
|
|
95
|
+
position-try-fallbacks: flip-block;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
[data-combobox-part="content"]:where([data-align="start"]) {
|
|
99
|
+
position-area: block-end span-inline-end;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
[data-combobox-part="content"]:where([data-align="center"]) {
|
|
103
|
+
position-area: block-end;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
[data-combobox-part="content"]:where([data-align="end"]) {
|
|
107
|
+
position-area: block-end span-inline-start;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
[data-combobox-part="content"]:where([data-width="default"]) {
|
|
111
|
+
width: auto;
|
|
112
|
+
min-width: max(200px, anchor-size(inline));
|
|
113
|
+
}
|
|
94
114
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/* Width variants */
|
|
98
|
-
[data-combobox-part="content"][data-width="sm"] {
|
|
99
|
-
@apply w-40;
|
|
100
|
-
}
|
|
101
115
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
/* Width variants */
|
|
117
|
+
[data-combobox-part="content"]:where([data-width="sm"]) {
|
|
118
|
+
@apply w-40;
|
|
119
|
+
}
|
|
105
120
|
|
|
106
|
-
[data-combobox-part="content"][data-width="
|
|
107
|
-
|
|
108
|
-
}
|
|
121
|
+
[data-combobox-part="content"]:where([data-width="default"]) {
|
|
122
|
+
@apply w-[200px];
|
|
123
|
+
}
|
|
109
124
|
|
|
110
|
-
[data-combobox-part="content"][data-width="
|
|
111
|
-
|
|
112
|
-
}
|
|
125
|
+
[data-combobox-part="content"]:where([data-width="md"]) {
|
|
126
|
+
@apply w-56;
|
|
127
|
+
}
|
|
113
128
|
|
|
114
|
-
[data-combobox-part="content"][data-width="
|
|
115
|
-
|
|
116
|
-
}
|
|
129
|
+
[data-combobox-part="content"]:where([data-width="lg"]) {
|
|
130
|
+
@apply w-72;
|
|
131
|
+
}
|
|
117
132
|
|
|
118
|
-
|
|
133
|
+
[data-combobox-part="content"]:where([data-width="full"]) {
|
|
134
|
+
@apply w-full;
|
|
135
|
+
}
|
|
119
136
|
|
|
120
|
-
/* Animation */
|
|
121
|
-
[data-combobox-part="content"]:popover-open {
|
|
122
|
-
|
|
123
|
-
}
|
|
137
|
+
/* Animation */
|
|
138
|
+
[data-combobox-part="content"]:where(:popover-open) {
|
|
139
|
+
animation: combobox-in 150ms ease-out;
|
|
140
|
+
}
|
|
124
141
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
142
|
+
/* ===== Search Input ===== */
|
|
143
|
+
[data-combobox-part="input-wrapper"] {
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
border-bottom: 1px solid var(--border);
|
|
147
|
+
@apply px-3 gap-2;
|
|
129
148
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
149
|
+
|
|
150
|
+
:where([data-combobox-part="input-wrapper"]) > svg {
|
|
151
|
+
@apply size-4 shrink-0 opacity-50;
|
|
133
152
|
}
|
|
134
|
-
}
|
|
135
153
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
154
|
+
[data-combobox-part="input"] {
|
|
155
|
+
background-color: transparent;
|
|
156
|
+
color: var(--foreground);
|
|
157
|
+
@apply flex h-10 w-full py-3 text-sm outline-none;
|
|
158
|
+
@apply placeholder:text-muted-foreground;
|
|
159
|
+
@apply disabled:cursor-not-allowed disabled:opacity-50;
|
|
160
|
+
}
|
|
143
161
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
162
|
+
/* ===== Options List ===== */
|
|
163
|
+
[data-combobox-part="list"] {
|
|
164
|
+
@apply max-h-[300px] overflow-y-auto overflow-x-hidden p-1;
|
|
165
|
+
}
|
|
147
166
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
167
|
+
/* ===== Option Item ===== */
|
|
168
|
+
[data-combobox-part="option"] {
|
|
169
|
+
position: relative;
|
|
170
|
+
display: flex;
|
|
171
|
+
align-items: center;
|
|
172
|
+
cursor: default;
|
|
173
|
+
user-select: none;
|
|
174
|
+
color: var(--popover-foreground, var(--foreground));
|
|
175
|
+
@apply gap-2 py-1.5 text-sm outline-none transition-colors;
|
|
176
|
+
border-radius: var(--combobox-item-radius, var(--control-radius, 0.375rem));
|
|
177
|
+
@apply pl-8 pr-2; /* Space for check icon on left */
|
|
178
|
+
}
|
|
155
179
|
|
|
156
|
-
/*
|
|
157
|
-
[data-combobox-part="list"] {
|
|
158
|
-
@apply max-h-[300px] overflow-y-auto overflow-x-hidden p-1;
|
|
159
|
-
}
|
|
180
|
+
/* ----- Option states ----- */
|
|
160
181
|
|
|
161
|
-
/*
|
|
162
|
-
[data-combobox-part="option"] {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
user-select: none;
|
|
168
|
-
color: var(--popover-foreground, var(--foreground));
|
|
169
|
-
@apply gap-2 rounded-sm py-1.5 text-sm outline-none transition-colors;
|
|
170
|
-
@apply pl-8 pr-2; /* Space for check icon on left */
|
|
171
|
-
}
|
|
182
|
+
/* Hover state */
|
|
183
|
+
[data-combobox-part="option"]:where(:hover:not([aria-disabled="true"])) {
|
|
184
|
+
background-color: var(--accent-hover, var(--accent));
|
|
185
|
+
color: var(--accent-foreground);
|
|
186
|
+
cursor: pointer;
|
|
187
|
+
}
|
|
172
188
|
|
|
173
|
-
/*
|
|
174
|
-
[data-combobox-part="option"]:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
189
|
+
/* Focus state (keyboard navigation) */
|
|
190
|
+
[data-combobox-part="option"]:where(:focus) {
|
|
191
|
+
background-color: var(--accent);
|
|
192
|
+
color: var(--accent-foreground);
|
|
193
|
+
}
|
|
179
194
|
|
|
180
|
-
/*
|
|
181
|
-
[data-combobox-part="option"]:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
195
|
+
/* Selected state */
|
|
196
|
+
[data-combobox-part="option"]:where([data-selected="true"]) {
|
|
197
|
+
background-color: var(--accent);
|
|
198
|
+
color: var(--accent-foreground);
|
|
199
|
+
}
|
|
185
200
|
|
|
186
|
-
/*
|
|
187
|
-
[data-combobox-part="option"][
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
201
|
+
/* Disabled state */
|
|
202
|
+
[data-combobox-part="option"]:where([aria-disabled="true"]) {
|
|
203
|
+
@apply opacity-50 cursor-not-allowed pointer-events-none;
|
|
204
|
+
}
|
|
191
205
|
|
|
192
|
-
/*
|
|
193
|
-
[data-combobox-part="option"][
|
|
194
|
-
|
|
195
|
-
}
|
|
206
|
+
/* Hidden state (filtered out) */
|
|
207
|
+
[data-combobox-part="option"]:where([hidden]) {
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
196
210
|
|
|
197
|
-
/*
|
|
198
|
-
[data-combobox-part="
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
/* Check indicator */
|
|
212
|
+
[data-combobox-part="check"] {
|
|
213
|
+
position: absolute;
|
|
214
|
+
left: 8px;
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
justify-content: center;
|
|
218
|
+
@apply size-4;
|
|
219
|
+
}
|
|
201
220
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
left: 8px;
|
|
206
|
-
display: flex;
|
|
207
|
-
align-items: center;
|
|
208
|
-
justify-content: center;
|
|
209
|
-
@apply size-4;
|
|
210
|
-
}
|
|
221
|
+
[data-combobox-part="check"] svg {
|
|
222
|
+
@apply size-4;
|
|
223
|
+
}
|
|
211
224
|
|
|
212
|
-
[data-combobox-part="check"].invisible {
|
|
213
|
-
|
|
214
|
-
}
|
|
225
|
+
[data-combobox-part="check"]:where(.invisible) {
|
|
226
|
+
visibility: hidden;
|
|
227
|
+
}
|
|
215
228
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
229
|
+
/* ===== Empty State ===== */
|
|
230
|
+
[data-combobox-part="empty"] {
|
|
231
|
+
@apply py-6 text-center text-sm;
|
|
232
|
+
color: var(--muted-foreground);
|
|
233
|
+
}
|
|
219
234
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
color: var(--muted-foreground);
|
|
224
|
-
}
|
|
235
|
+
[data-combobox-part="empty"]:where([hidden]) {
|
|
236
|
+
display: none;
|
|
237
|
+
}
|
|
225
238
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
239
|
+
/* ===== Group ===== */
|
|
240
|
+
[data-combobox-part="group"] {
|
|
241
|
+
display: flex;
|
|
242
|
+
flex-direction: column;
|
|
243
|
+
}
|
|
229
244
|
|
|
230
|
-
/* =====
|
|
231
|
-
[data-combobox-part="
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
245
|
+
/* ===== Label ===== */
|
|
246
|
+
[data-combobox-part="label"] {
|
|
247
|
+
@apply px-2 py-1.5 text-xs;
|
|
248
|
+
font-weight: var(--label-weight, 500);
|
|
249
|
+
color: var(--muted-foreground);
|
|
250
|
+
}
|
|
235
251
|
|
|
236
|
-
/* =====
|
|
237
|
-
[data-combobox-part="
|
|
238
|
-
|
|
239
|
-
|
|
252
|
+
/* ===== Separator ===== */
|
|
253
|
+
[data-combobox-part="separator"] {
|
|
254
|
+
@apply -mx-1 my-1 h-px;
|
|
255
|
+
background-color: var(--border);
|
|
256
|
+
}
|
|
240
257
|
}
|
|
241
258
|
|
|
242
|
-
/* =====
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
259
|
+
/* ===== Keyframes ===== */
|
|
260
|
+
/* Outside the layer: @keyframes are not cascade participants. */
|
|
261
|
+
@keyframes combobox-in {
|
|
262
|
+
from {
|
|
263
|
+
opacity: 0;
|
|
264
|
+
transform: scale(0.95) translateY(-4px);
|
|
265
|
+
}
|
|
266
|
+
to {
|
|
267
|
+
opacity: 1;
|
|
268
|
+
transform: scale(1) translateY(0);
|
|
269
|
+
}
|
|
246
270
|
}
|
|
247
|
-
|
|
248
|
-
/* ===== Dark Mode ===== */
|
|
249
|
-
/*
|
|
250
|
-
* Dark mode is handled automatically through CSS variables.
|
|
251
|
-
* The theme variables change based on the .dark class on html/body.
|
|
252
|
-
* No additional dark mode styles needed here.
|
|
253
|
-
*/
|