maquina-components 0.3.0 → 0.3.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e04564783a082eb56e58395e1de24dc21deb1312c49ebc47e48428a4230e6925
4
- data.tar.gz: 78630e11ca92ae6a964c2bc100a7357722d7618df3a5a0a7d0619bbc48eeb5d3
3
+ metadata.gz: b851df46a3afd618bc81e81319613ac295fb6b09fa5b68a3579f1508d3a07bda
4
+ data.tar.gz: e90010af3a12f9ffd8930201bc5b07a697cafa10da533e4ffeaa546bca8d6ec9
5
5
  SHA512:
6
- metadata.gz: 225bbf4a0100ac2f80a03e3bcf38f6080365db13228fade762fa5c8378631b2f0aa5d45d71654e2ecfa6577fe88f9c317163a8c29b44f003657146870bd3c44f
7
- data.tar.gz: f3b563c5a789cb8039fc5e30e5461114556ca37289bd2b9859b0516973f1c4d7f54204745ad48628271ae24574522784cae4e8865f83e596326b5707d903a4ea
6
+ metadata.gz: 023b264cbe15f2d62aa508a35dc3919827130f1382e795b02a31afdf4c7160218f2f784eaf3c6521f75fce9ab5f3e7a0068b4b6064e9fe28a321b4d105955533
7
+ data.tar.gz: 48606389939ad53c12e519e5d9d95b316cf083b492646c992c5a713eee5de1919fe218a860975350980619c2aba836d364ee10db32cccd75113045f159cdd5f3
data/README.md CHANGED
@@ -152,7 +152,9 @@ bin/rails generate maquina_components:install --skip-helper
152
152
 
153
153
  | Component | Description | Documentation |
154
154
  |-----------|-------------|---------------|
155
+ | **Calendar** | Inline date picker with single/range selection | [Calendar](https://maquina.app/documentation/components/calendar/) |
155
156
  | **Combobox** | Searchable dropdown with keyboard navigation | [Combobox](https://maquina.app/documentation/components/combobox/) |
157
+ | **Date Picker** | Popover-based date selection | [Date Picker](https://maquina.app/documentation/components/date-picker/) |
156
158
  | **Toggle Group** | Single/multiple selection button group | [Toggle Group](https://maquina.app/documentation/components/toggle-group/) |
157
159
 
158
160
  ### Feedback Components
@@ -425,7 +427,9 @@ The install generator adds default theme variables. Customize them in `app/asset
425
427
 
426
428
  ### Interactive
427
429
 
430
+ - **[Calendar](https://maquina.app/documentation/components/calendar/)** — Inline date picker
428
431
  - **[Combobox](https://maquina.app/documentation/components/combobox/)** — Searchable dropdown selection
432
+ - **[Date Picker](https://maquina.app/documentation/components/date-picker/)** — Popover date selection
429
433
  - **[Toggle Group](https://maquina.app/documentation/components/toggle-group/)** — Toggle button groups
430
434
 
431
435
  ### Feedback
@@ -455,6 +459,28 @@ bin/rails test
455
459
 
456
460
  ---
457
461
 
462
+ ## Claude Code Skill
463
+
464
+ This repository includes a Claude Code skill that teaches Claude how to build consistent, accessible UIs using maquina_components. The skill provides:
465
+
466
+ - **Component catalog** — Complete reference for all components with ERB examples
467
+ - **Form patterns** — Validation, error handling, and complex form structures
468
+ - **Layout patterns** — Sidebar navigation, page structure, responsive design
469
+ - **Turbo integration** — Turbo Frames, Streams, and component updates
470
+ - **Spec checklist** — Review criteria for UI implementation quality
471
+
472
+ ### Installation
473
+
474
+ Copy the `skill/` directory to your Rails project:
475
+
476
+ ```bash
477
+ cp -r /path/to/maquina_components/skill .claude/skills/maquina-ui-standards
478
+ ```
479
+
480
+ See the [Skill README](skill/README.md) for detailed installation and usage instructions.
481
+
482
+ ---
483
+
458
484
  ## Contributing
459
485
 
460
486
  Bug reports and pull requests are welcome on GitHub at [github.com/maquina-app/maquina_components](https://github.com/maquina-app/maquina_components).
@@ -56,8 +56,8 @@
56
56
 
57
57
  /* Primary variant - brand color */
58
58
  [data-component="badge"][data-variant="primary"] {
59
- background-color: var(--primary-color);
60
- color: var(--primary-foreground-color);
59
+ background-color: var(--primary);
60
+ color: var(--primary-foreground);
61
61
  }
62
62
 
63
63
  [data-component="badge"][data-variant="primary"]:hover {
@@ -0,0 +1,222 @@
1
+ /* ===== Calendar Component Styles ===== */
2
+ /*
3
+ * A date picker calendar with single and range selection.
4
+ * Uses data attributes for styling to avoid inline utility classes.
5
+ * Fully compatible with dark mode via CSS variables.
6
+ *
7
+ * Structure:
8
+ * - calendar (root container)
9
+ * - header (navigation)
10
+ * - weekdays (day name headers)
11
+ * - grid (day buttons grid)
12
+ * - week (row)
13
+ * - day (button)
14
+ */
15
+
16
+ /* ===== Root Container ===== */
17
+ [data-component="calendar"] {
18
+ --cell-size: 2rem;
19
+
20
+ @apply p-3 w-fit rounded-lg border;
21
+ background-color: var(--background);
22
+ border-color: var(--border);
23
+ }
24
+
25
+ /* ===== Header (Navigation) ===== */
26
+ [data-calendar-part="header"] {
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: space-between;
30
+ @apply mb-4;
31
+ }
32
+
33
+ [data-calendar-part="header"] button {
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ width: var(--cell-size);
38
+ height: var(--cell-size);
39
+ @apply rounded-md;
40
+ border: none;
41
+ cursor: pointer;
42
+ background-color: transparent;
43
+ color: var(--foreground);
44
+ @apply transition-colors duration-150;
45
+ }
46
+
47
+ [data-calendar-part="header"] button:hover:not(:disabled) {
48
+ background-color: var(--accent);
49
+ color: var(--accent-foreground);
50
+ }
51
+
52
+ [data-calendar-part="header"] button:focus-visible {
53
+ @apply outline-none;
54
+ box-shadow: 0 0 0 2px var(--background),
55
+ 0 0 0 4px var(--ring);
56
+ }
57
+
58
+ [data-calendar-part="header"] button:disabled {
59
+ @apply opacity-50 cursor-not-allowed;
60
+ }
61
+
62
+ [data-calendar-part="header"] button svg {
63
+ @apply size-4 shrink-0;
64
+ }
65
+
66
+ [data-calendar-part="caption"] {
67
+ @apply text-sm font-medium select-none;
68
+ color: var(--foreground);
69
+ }
70
+
71
+ /* ===== Weekday Headers ===== */
72
+ [data-calendar-part="weekdays"] {
73
+ display: grid;
74
+ grid-template-columns: repeat(7, var(--cell-size));
75
+ @apply mb-1;
76
+ }
77
+
78
+ [data-calendar-part="weekday"] {
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ width: var(--cell-size);
83
+ height: var(--cell-size);
84
+ @apply text-xs font-normal select-none;
85
+ color: var(--muted-foreground);
86
+ }
87
+
88
+ /* ===== Calendar Grid ===== */
89
+ [data-calendar-part="grid"] {
90
+ display: flex;
91
+ flex-direction: column;
92
+ @apply gap-1;
93
+ }
94
+
95
+ [data-calendar-part="week"] {
96
+ display: grid;
97
+ grid-template-columns: repeat(7, var(--cell-size));
98
+ }
99
+
100
+ /* ===== Day Button Base ===== */
101
+ [data-calendar-part="day"] {
102
+ display: inline-flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+ width: var(--cell-size);
106
+ height: var(--cell-size);
107
+ @apply text-sm font-normal rounded-md;
108
+ border: none;
109
+ cursor: pointer;
110
+ background-color: transparent;
111
+ color: var(--foreground);
112
+ @apply transition-colors duration-150;
113
+ }
114
+
115
+ /* ===== Day States ===== */
116
+
117
+ /* Hover */
118
+ [data-calendar-part="day"]:hover:not(:disabled):not([data-state]) {
119
+ background-color: var(--accent);
120
+ color: var(--accent-foreground);
121
+ }
122
+
123
+ /* Today */
124
+ [data-calendar-part="day"][data-today] {
125
+ background-color: var(--accent);
126
+ color: var(--accent-foreground);
127
+ }
128
+
129
+ /* Selected (single mode) */
130
+ [data-calendar-part="day"][data-state="selected"] {
131
+ background-color: var(--primary);
132
+ color: var(--primary-foreground);
133
+ @apply rounded-md;
134
+ }
135
+
136
+ [data-calendar-part="day"][data-state="selected"]:hover {
137
+ background-color: var(--primary);
138
+ color: var(--primary-foreground);
139
+ }
140
+
141
+ /* Range Start */
142
+ [data-calendar-part="day"][data-state="range-start"] {
143
+ background-color: var(--primary);
144
+ color: var(--primary-foreground);
145
+ @apply rounded-l-md rounded-r-none;
146
+ }
147
+
148
+ /* Range End */
149
+ [data-calendar-part="day"][data-state="range-end"] {
150
+ background-color: var(--primary);
151
+ color: var(--primary-foreground);
152
+ @apply rounded-r-md rounded-l-none;
153
+ }
154
+
155
+ /* Range Middle */
156
+ [data-calendar-part="day"][data-state="range-middle"] {
157
+ background-color: var(--accent);
158
+ color: var(--accent-foreground);
159
+ @apply rounded-none;
160
+ }
161
+
162
+ /* Today within selection - override background */
163
+ [data-calendar-part="day"][data-today][data-state="selected"],
164
+ [data-calendar-part="day"][data-today][data-state="range-start"],
165
+ [data-calendar-part="day"][data-today][data-state="range-end"] {
166
+ background-color: var(--primary);
167
+ color: var(--primary-foreground);
168
+ }
169
+
170
+ [data-calendar-part="day"][data-today][data-state="range-middle"] {
171
+ background-color: var(--accent);
172
+ color: var(--accent-foreground);
173
+ }
174
+
175
+ /* Outside days (previous/next month) */
176
+ [data-calendar-part="day"][data-outside] {
177
+ color: var(--muted-foreground);
178
+ @apply opacity-50;
179
+ }
180
+
181
+ [data-calendar-part="day"][data-outside][data-state="selected"],
182
+ [data-calendar-part="day"][data-outside][data-state="range-start"],
183
+ [data-calendar-part="day"][data-outside][data-state="range-end"] {
184
+ color: var(--primary-foreground);
185
+ @apply opacity-30;
186
+ }
187
+
188
+ [data-calendar-part="day"][data-outside][data-state="range-middle"] {
189
+ color: var(--accent-foreground);
190
+ @apply opacity-30;
191
+ }
192
+
193
+ /* Disabled */
194
+ [data-calendar-part="day"]:disabled {
195
+ color: var(--muted-foreground);
196
+ @apply opacity-50 cursor-not-allowed;
197
+ }
198
+
199
+ /* Focus */
200
+ [data-calendar-part="day"]:focus-visible {
201
+ @apply outline-none;
202
+ position: relative;
203
+ z-index: 10;
204
+ box-shadow: 0 0 0 2px var(--background),
205
+ 0 0 0 4px var(--ring);
206
+ }
207
+
208
+ /* ===== Responsive Cell Sizes ===== */
209
+ /*
210
+ * Custom cell sizes can be set via --cell-size CSS variable:
211
+ * style="--cell-size: 2.5rem;"
212
+ *
213
+ * Or with Tailwind classes:
214
+ * css_classes: "[--cell-size:2.5rem] md:[--cell-size:3rem]"
215
+ */
216
+
217
+ /* ===== Dark Mode ===== */
218
+ /*
219
+ * Dark mode is handled automatically through CSS variables.
220
+ * The theme variables change based on the .dark class on html/body.
221
+ * No additional dark mode styles needed here.
222
+ */
@@ -0,0 +1,172 @@
1
+ /* ===== DatePicker Component Styles ===== */
2
+ /*
3
+ * A date picker with trigger button and popover calendar.
4
+ * Uses native Popover API for open/close without JavaScript.
5
+ * Supports single and range selection modes.
6
+ *
7
+ * Structure:
8
+ * - date-picker (root container)
9
+ * - trigger (button with popovertarget)
10
+ * - popover (native popover with calendar)
11
+ */
12
+
13
+ /* ===== Root Container ===== */
14
+ [data-component="date-picker"] {
15
+ position: relative;
16
+ display: inline-block;
17
+ }
18
+
19
+ /* ===== Trigger Button ===== */
20
+ [data-date-picker-part="trigger"] {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ justify-content: flex-start;
24
+ gap: 0.5rem;
25
+ width: 100%;
26
+ min-width: 200px;
27
+ @apply h-9 px-3 py-2 text-sm rounded-md;
28
+ border: 1px solid var(--input);
29
+ background-color: var(--background);
30
+ color: var(--foreground);
31
+ cursor: pointer;
32
+ text-align: left;
33
+ @apply transition-colors duration-150;
34
+ }
35
+
36
+ [data-date-picker-part="trigger"]:hover:not(:disabled) {
37
+ background-color: var(--accent);
38
+ }
39
+
40
+ [data-date-picker-part="trigger"]:focus-visible {
41
+ @apply outline-none;
42
+ border-color: var(--ring);
43
+ box-shadow: 0 0 0 2px var(--background),
44
+ 0 0 0 4px var(--ring);
45
+ }
46
+
47
+ [data-date-picker-part="trigger"]:disabled {
48
+ @apply opacity-50 cursor-not-allowed;
49
+ }
50
+
51
+ [data-date-picker-part="trigger"] svg {
52
+ @apply size-4 shrink-0;
53
+ color: var(--muted-foreground);
54
+ }
55
+
56
+ /* Placeholder state */
57
+ [data-date-picker-part="trigger"]:has([data-date-picker-part="placeholder-indicator"]) {
58
+ color: var(--muted-foreground);
59
+ }
60
+
61
+ /* ===== Popover ===== */
62
+ [data-date-picker-part="popover"] {
63
+ @apply p-0 rounded-lg border;
64
+ background-color: var(--background);
65
+ border-color: var(--border);
66
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
67
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
68
+
69
+ /* Reset default popover styles */
70
+ margin: 0;
71
+ overflow: visible;
72
+
73
+ /* Position below trigger */
74
+ position-area: bottom span-right;
75
+ position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
76
+ margin-top: 0.25rem;
77
+
78
+ /* Entry animation */
79
+ opacity: 1;
80
+ transform: translateY(0) scale(1);
81
+ transition: opacity 150ms ease-out,
82
+ transform 150ms ease-out;
83
+ }
84
+
85
+ /* Closed state - for exit animation */
86
+ [data-date-picker-part="popover"]:not(:popover-open) {
87
+ opacity: 0;
88
+ transform: translateY(-0.5rem) scale(0.95);
89
+ }
90
+
91
+ /* Entry animation starting state */
92
+ @starting-style {
93
+ [data-date-picker-part="popover"]:popover-open {
94
+ opacity: 0;
95
+ transform: translateY(-0.5rem) scale(0.95);
96
+ }
97
+ }
98
+
99
+ /* Backdrop */
100
+ [data-date-picker-part="popover"]::backdrop {
101
+ background-color: transparent;
102
+ }
103
+
104
+ /* ===== Calendar inside popover adjustments ===== */
105
+ [data-date-picker-part="popover"] [data-component="calendar"] {
106
+ border: none;
107
+ box-shadow: none;
108
+ }
109
+
110
+ /* ===== Trigger aria-expanded state ===== */
111
+ [data-date-picker-part="trigger"][aria-expanded="true"] {
112
+ border-color: var(--ring);
113
+ }
114
+
115
+ /* ===== Size Variants ===== */
116
+ [data-component="date-picker"][data-size="sm"] [data-date-picker-part="trigger"] {
117
+ @apply h-8 px-2 py-1 text-xs;
118
+ min-width: 160px;
119
+ }
120
+
121
+ [data-component="date-picker"][data-size="sm"] [data-date-picker-part="trigger"] svg {
122
+ @apply size-3.5;
123
+ }
124
+
125
+ [data-component="date-picker"][data-size="lg"] [data-date-picker-part="trigger"] {
126
+ @apply h-11 px-4 py-3 text-base;
127
+ min-width: 240px;
128
+ }
129
+
130
+ [data-component="date-picker"][data-size="lg"] [data-date-picker-part="trigger"] svg {
131
+ @apply size-5;
132
+ }
133
+
134
+ /* ===== Full width variant ===== */
135
+ [data-component="date-picker"][data-full-width] {
136
+ display: block;
137
+ width: 100%;
138
+ }
139
+
140
+ [data-component="date-picker"][data-full-width] [data-date-picker-part="trigger"] {
141
+ width: 100%;
142
+ }
143
+
144
+ /* ===== Error state ===== */
145
+ [data-component="date-picker"]:has(input:invalid),
146
+ [data-component="date-picker"]:has(input[aria-invalid="true"]) {
147
+ [data-date-picker-part="trigger"] {
148
+ border-color: var(--destructive);
149
+ }
150
+
151
+ [data-date-picker-part="trigger"]:focus-visible {
152
+ box-shadow: 0 0 0 2px var(--background),
153
+ 0 0 0 4px var(--destructive);
154
+ }
155
+ }
156
+
157
+ /* ===== Fallback for browsers without anchor positioning ===== */
158
+ @supports not (position-area: bottom) {
159
+ [data-date-picker-part="popover"] {
160
+ position: absolute;
161
+ top: 100%;
162
+ left: 0;
163
+ margin-top: 0.25rem;
164
+ }
165
+ }
166
+
167
+ /* ===== Dark Mode ===== */
168
+ /*
169
+ * Dark mode is handled automatically through CSS variables.
170
+ * The theme variables change based on the .dark class on html/body.
171
+ * No additional dark mode styles needed here.
172
+ */
@@ -532,7 +532,7 @@
532
532
  =================================================================== */
533
533
  [data-form-part="error"] {
534
534
  @apply text-sm font-medium;
535
- color: var(--destructive);
535
+ color: var(--destructive-foreground);
536
536
  }
537
537
 
538
538
  /* Rails error wrapper compatibility */
@@ -1,18 +1,18 @@
1
1
  @source "../../../views/";
2
2
 
3
- @layer components {
4
- @import "../../stylesheets/alert.css";
5
- @import "../../stylesheets/badge.css";
6
- @import "../../stylesheets/breadcrumbs.css";
7
- @import "../../stylesheets/card.css";
8
- @import "../../stylesheets/combobox.css";
9
- @import "../../stylesheets/dropdown_menu.css";
10
- @import "../../stylesheets/empty.css";
11
- @import "../../stylesheets/form.css";
12
- @import "../../stylesheets/header.css";
13
- @import "../../stylesheets/pagination.css";
14
- @import "../../stylesheets/sidebar.css";
15
- @import "../../stylesheets/table.css";
16
- @import "../../stylesheets/toast.css";
17
- @import "../../stylesheets/toggle_group.css";
18
- }
3
+ @import "../../stylesheets/alert.css";
4
+ @import "../../stylesheets/badge.css";
5
+ @import "../../stylesheets/breadcrumbs.css";
6
+ @import "../../stylesheets/calendar.css";
7
+ @import "../../stylesheets/card.css";
8
+ @import "../../stylesheets/combobox.css";
9
+ @import "../../stylesheets/date_picker.css";
10
+ @import "../../stylesheets/dropdown_menu.css";
11
+ @import "../../stylesheets/empty.css";
12
+ @import "../../stylesheets/form.css";
13
+ @import "../../stylesheets/header.css";
14
+ @import "../../stylesheets/pagination.css";
15
+ @import "../../stylesheets/sidebar.css";
16
+ @import "../../stylesheets/table.css";
17
+ @import "../../stylesheets/toast.css";
18
+ @import "../../stylesheets/toggle_group.css";