nanoui 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/CHANGELOG.md +18 -0
- data/README.md +189 -199
- data/lib/generators/nanoui/component_generator.rb +0 -52
- data/lib/generators/nanoui/install_generator.rb +0 -18
- data/lib/generators/nanoui/templates/css/components/alert.css +1 -1
- data/lib/generators/nanoui/templates/css/components/button.css +36 -7
- data/lib/generators/nanoui/templates/css/components/card.css +2 -1
- data/lib/generators/nanoui/templates/css/components/dialog.css +1 -1
- data/lib/generators/nanoui/templates/css/components/input.css +62 -8
- data/lib/generators/nanoui/templates/css/components/label.css +2 -1
- data/lib/generators/nanoui/templates/css/components/select.css +12 -7
- data/lib/nanoui/version.rb +1 -1
- metadata +1 -22
- data/lib/generators/nanoui/templates/css/nanoui.css +0 -33
- data/lib/generators/nanoui/templates/css/nanoui.install.css +0 -15
- data/lib/generators/nanoui/templates/views/components/_accordion.html.erb +0 -40
- data/lib/generators/nanoui/templates/views/components/_alert.html.erb +0 -33
- data/lib/generators/nanoui/templates/views/components/_badge.html.erb +0 -18
- data/lib/generators/nanoui/templates/views/components/_button.html.erb +0 -27
- data/lib/generators/nanoui/templates/views/components/_card.html.erb +0 -43
- data/lib/generators/nanoui/templates/views/components/_checkbox.html.erb +0 -36
- data/lib/generators/nanoui/templates/views/components/_dialog.html.erb +0 -65
- data/lib/generators/nanoui/templates/views/components/_dropdown.html.erb +0 -29
- data/lib/generators/nanoui/templates/views/components/_input.html.erb +0 -42
- data/lib/generators/nanoui/templates/views/components/_label.html.erb +0 -20
- data/lib/generators/nanoui/templates/views/components/_progress.html.erb +0 -29
- data/lib/generators/nanoui/templates/views/components/_radio_group.html.erb +0 -46
- data/lib/generators/nanoui/templates/views/components/_select.html.erb +0 -67
- data/lib/generators/nanoui/templates/views/components/_switch.html.erb +0 -32
- data/lib/generators/nanoui/templates/views/components/_table.html.erb +0 -41
- data/lib/generators/nanoui/templates/views/components/_tabs.html.erb +0 -46
- data/lib/generators/nanoui/templates/views/components/_toast.html.erb +0 -33
- data/lib/generators/nanoui/templates/views/components/_toast_container.html.erb +0 -17
- data/lib/generators/nanoui/templates/views/components/_tooltip.html.erb +0 -28
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ee0efe5f709d40b9486a2becffafaebc490c770ff33b2ecc5b10133626bc37d
|
|
4
|
+
data.tar.gz: 873b05607d941e5515a5a699947ce4b03b70a18d21bde51b71f0b8ea1f8e3586
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 38d72d4d339a553ce778d211b7bea7cf323205126de29307a6aac578457197b5042e243779c6aa874cf772ef8c58be14d1589a0079b42528deddfc43e7f26a44
|
|
7
|
+
data.tar.gz: bb3401e429e2c28f4e6e416988ac37822572afdc466140cdab8648b361f10c185fd1261372d85ac10ff138ac9c73b2acd3aed2332dae17e3420e7a8f1447811e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 (2026-03-12)
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- Removed `@import`-based CSS entry point (incompatible with Propshaft)
|
|
8
|
+
- Removed ERB view partials
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Native HTML element styling (button, input, select, label styled without classes)
|
|
13
|
+
- GitHub Pages documentation site with live component previews
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Simplified generators (no more import management)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
3
21
|
## 0.1.0 (2026-03-09)
|
|
4
22
|
|
|
5
23
|
### Initial release
|
data/README.md
CHANGED
|
@@ -4,6 +4,14 @@ Vanilla CSS + Stimulus component library for Rails. Zero runtime dependencies.
|
|
|
4
4
|
|
|
5
5
|
18 components. Semantic HTML. Accessible by default. No build step.
|
|
6
6
|
|
|
7
|
+
**[Documentation & Live Previews](https://chille1987.github.io/nanoui/)** — Browse all 18 components with interactive examples.
|
|
8
|
+
|
|
9
|
+
## What's New in v0.3.0
|
|
10
|
+
|
|
11
|
+
- **Native element styling** — Bare `<button>`, `<input>`, `<select>`, and `<label>` elements are styled out of the box. No `.nano-*` classes needed for default styling. Classes still work for variants.
|
|
12
|
+
- **No @import needed** — Propshaft auto-loads all CSS files. Just run the generators and go.
|
|
13
|
+
- **HTML-only components** — No ERB partials. Use plain HTML with CSS classes directly.
|
|
14
|
+
|
|
7
15
|
## Installation
|
|
8
16
|
|
|
9
17
|
### Option A: Rubygem with Generators (recommended)
|
|
@@ -19,46 +27,28 @@ rails generate nanoui:install # Base styles and fonts
|
|
|
19
27
|
rails generate nanoui:component --all # All components
|
|
20
28
|
```
|
|
21
29
|
|
|
30
|
+
Propshaft auto-loads the CSS files — no imports or entry points to manage.
|
|
31
|
+
|
|
22
32
|
### Option B: Manual Installation
|
|
23
33
|
|
|
24
34
|
Copy files directly into your Rails 8 app:
|
|
25
35
|
|
|
26
36
|
```bash
|
|
27
|
-
# 1. CSS (base, components,
|
|
37
|
+
# 1. CSS (base, components, Inter Variable font)
|
|
28
38
|
mkdir -p app/assets/stylesheets/nanoui
|
|
29
39
|
cp -r lib/generators/nanoui/templates/css/base app/assets/stylesheets/nanoui/
|
|
30
40
|
cp -r lib/generators/nanoui/templates/css/components app/assets/stylesheets/nanoui/
|
|
31
41
|
cp -r lib/generators/nanoui/templates/css/fonts app/assets/stylesheets/nanoui/
|
|
32
|
-
cp lib/generators/nanoui/templates/css/nanoui.css app/assets/stylesheets/nanoui/
|
|
33
42
|
|
|
34
43
|
# 2. Stimulus controllers
|
|
35
44
|
cp lib/generators/nanoui/templates/js/controllers/*_controller.js \
|
|
36
45
|
app/javascript/controllers/
|
|
37
|
-
|
|
38
|
-
# 3. ERB partials (optional — you can use CSS classes directly)
|
|
39
|
-
cp lib/generators/nanoui/templates/views/components/ app/views/components/
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Import CSS
|
|
43
|
-
|
|
44
|
-
Add to `app/assets/stylesheets/application.css`:
|
|
45
|
-
|
|
46
|
-
```css
|
|
47
|
-
@import "nanoui/nanoui.css";
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
`rails generate nanoui:install` now creates a foundation-only `nanoui.css`, and each `nanoui:component` run rewrites the component imports so the file only references CSS that actually exists.
|
|
51
|
-
|
|
52
|
-
NanoUI ships with Inter Variable and expects it at `app/assets/stylesheets/nanoui/fonts/inter-variable.ttf`, which `rails generate nanoui:install` now copies automatically.
|
|
53
|
-
|
|
54
|
-
Or if using Propshaft, add the import to your layout:
|
|
55
|
-
|
|
56
|
-
```erb
|
|
57
|
-
<%= stylesheet_link_tag "nanoui/nanoui.css" %>
|
|
58
46
|
```
|
|
59
47
|
|
|
60
48
|
### Troubleshooting Fonts
|
|
61
49
|
|
|
50
|
+
NanoUI ships with Inter Variable and expects it at `app/assets/stylesheets/nanoui/fonts/inter-variable.ttf`, which `rails generate nanoui:install` copies automatically.
|
|
51
|
+
|
|
62
52
|
If NanoUI falls back to system fonts instead of Inter:
|
|
63
53
|
|
|
64
54
|
- Confirm the font file exists at `app/assets/stylesheets/nanoui/fonts/inter-variable.ttf`
|
|
@@ -93,9 +83,8 @@ application.register("nanoui-dialog", DialogController)
|
|
|
93
83
|
|
|
94
84
|
Add the `.dark` class to `<html>` to toggle dark mode. All color tokens swap automatically.
|
|
95
85
|
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
<html class="<%= "dark" if user_prefers_dark? %>">
|
|
86
|
+
```html
|
|
87
|
+
<html class="dark">
|
|
99
88
|
```
|
|
100
89
|
|
|
101
90
|
Or toggle via JavaScript:
|
|
@@ -106,94 +95,98 @@ document.documentElement.classList.toggle("dark")
|
|
|
106
95
|
|
|
107
96
|
---
|
|
108
97
|
|
|
109
|
-
##
|
|
110
|
-
|
|
111
|
-
### Essentials
|
|
112
|
-
|
|
113
|
-
#### Button
|
|
98
|
+
## Native Element Styling
|
|
114
99
|
|
|
115
|
-
|
|
100
|
+
NanoUI styles bare HTML elements automatically. No classes required for the defaults:
|
|
116
101
|
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<% end %>
|
|
102
|
+
```html
|
|
103
|
+
<!-- Renders as a styled primary button -->
|
|
104
|
+
<button>Save Changes</button>
|
|
121
105
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<% end %>
|
|
106
|
+
<!-- Renders with input styling -->
|
|
107
|
+
<input type="text" placeholder="Enter your name">
|
|
125
108
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
<!-- Renders with select styling -->
|
|
110
|
+
<select>
|
|
111
|
+
<option>Option 1</option>
|
|
112
|
+
<option>Option 2</option>
|
|
113
|
+
</select>
|
|
129
114
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Learn More
|
|
133
|
-
<% end %>
|
|
115
|
+
<!-- Renders with label styling -->
|
|
116
|
+
<label for="name">Name</label>
|
|
134
117
|
```
|
|
135
118
|
|
|
136
|
-
|
|
119
|
+
Use `.nano-*` classes when you need variants:
|
|
137
120
|
|
|
138
121
|
```html
|
|
139
|
-
<button class="nano-btn
|
|
140
|
-
<button class="nano-btn
|
|
141
|
-
<button class="nano-btn
|
|
122
|
+
<button class="nano-btn--outline">Cancel</button>
|
|
123
|
+
<button class="nano-btn--destructive">Delete</button>
|
|
124
|
+
<button class="nano-btn--sm">Small</button>
|
|
142
125
|
```
|
|
143
126
|
|
|
144
|
-
|
|
127
|
+
---
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
## Component Reference
|
|
147
130
|
|
|
148
|
-
|
|
131
|
+
### Essentials
|
|
149
132
|
|
|
150
|
-
|
|
151
|
-
<%= render "components/input", label: "Email", type: "email", required: true,
|
|
152
|
-
html: { placeholder: "you@example.com" } %>
|
|
133
|
+
#### Button
|
|
153
134
|
|
|
154
|
-
|
|
135
|
+
6 variants, 3 sizes, icon-only, loading state. Bare `<button>` renders as a primary button.
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<button>Save Changes</button>
|
|
139
|
+
<button class="nano-btn--outline nano-btn--sm">Cancel</button>
|
|
140
|
+
<button class="nano-btn--destructive">Delete</button>
|
|
141
|
+
<a href="/about" class="nano-btn nano-btn--ghost">Learn More</a>
|
|
142
|
+
<button disabled>Disabled</button>
|
|
155
143
|
```
|
|
156
144
|
|
|
145
|
+
**Variants:** primary (default), secondary, destructive, outline, ghost, link
|
|
146
|
+
**Sizes:** sm, lg, icon
|
|
147
|
+
|
|
148
|
+
#### Input
|
|
149
|
+
|
|
150
|
+
Text fields wrapped in `.nano-field` with label and error support. Bare `<input>` gets input styling automatically.
|
|
151
|
+
|
|
157
152
|
```html
|
|
158
153
|
<div class="nano-field">
|
|
159
|
-
<label for="email"
|
|
160
|
-
<input id="email" type="email"
|
|
154
|
+
<label for="email">Email</label>
|
|
155
|
+
<input id="email" type="email" placeholder="you@example.com" required>
|
|
161
156
|
</div>
|
|
162
|
-
```
|
|
163
157
|
|
|
164
|
-
|
|
158
|
+
<div class="nano-field nano-field--error">
|
|
159
|
+
<label for="name">Name</label>
|
|
160
|
+
<input id="name" type="text">
|
|
161
|
+
<p class="nano-field__error">Name is required</p>
|
|
162
|
+
</div>
|
|
163
|
+
```
|
|
165
164
|
|
|
166
165
|
#### Label
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
<%= render "components/label", for: "name", required: true do %>Name<% end %>
|
|
170
|
-
```
|
|
167
|
+
Bare `<label>` gets label styling. Add `nano-label--required` for the required indicator.
|
|
171
168
|
|
|
172
169
|
```html
|
|
173
|
-
<label for="name"
|
|
170
|
+
<label for="name">Name</label>
|
|
171
|
+
<label for="email" class="nano-label--required">Email</label>
|
|
174
172
|
```
|
|
175
173
|
|
|
176
174
|
#### Card
|
|
177
175
|
|
|
178
176
|
Container with header, content, and footer sections.
|
|
179
177
|
|
|
180
|
-
```erb
|
|
181
|
-
<%= render "components/card",
|
|
182
|
-
title: "Settings",
|
|
183
|
-
description: "Manage your account.",
|
|
184
|
-
footer: render("components/button", variant: "primary") { "Save" } do %>
|
|
185
|
-
<p>Card body content here.</p>
|
|
186
|
-
<% end %>
|
|
187
|
-
```
|
|
188
|
-
|
|
189
178
|
```html
|
|
190
179
|
<article class="nano-card">
|
|
191
180
|
<div class="nano-card__header">
|
|
192
181
|
<h3 class="nano-card__title">Settings</h3>
|
|
193
182
|
<p class="nano-card__description">Manage your account.</p>
|
|
194
183
|
</div>
|
|
195
|
-
<div class="nano-card__content"
|
|
196
|
-
|
|
184
|
+
<div class="nano-card__content">
|
|
185
|
+
<p>Card body content here.</p>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="nano-card__footer">
|
|
188
|
+
<button>Save</button>
|
|
189
|
+
</div>
|
|
197
190
|
</article>
|
|
198
191
|
```
|
|
199
192
|
|
|
@@ -203,13 +196,9 @@ Container with header, content, and footer sections.
|
|
|
203
196
|
|
|
204
197
|
Inline status indicators.
|
|
205
198
|
|
|
206
|
-
```erb
|
|
207
|
-
<%= render "components/badge", variant: "success" do %>Active<% end %>
|
|
208
|
-
<%= render "components/badge", variant: "warning" do %>Pending<% end %>
|
|
209
|
-
```
|
|
210
|
-
|
|
211
199
|
```html
|
|
212
200
|
<span class="nano-badge nano-badge--success">Active</span>
|
|
201
|
+
<span class="nano-badge nano-badge--warning">Pending</span>
|
|
213
202
|
<span class="nano-badge nano-badge--destructive">Failed</span>
|
|
214
203
|
```
|
|
215
204
|
|
|
@@ -219,12 +208,6 @@ Inline status indicators.
|
|
|
219
208
|
|
|
220
209
|
Contextual feedback with icon, title, and description.
|
|
221
210
|
|
|
222
|
-
```erb
|
|
223
|
-
<%= render "components/alert", variant: "success", title: "Saved!" do %>
|
|
224
|
-
Your changes have been saved successfully.
|
|
225
|
-
<% end %>
|
|
226
|
-
```
|
|
227
|
-
|
|
228
211
|
```html
|
|
229
212
|
<div class="nano-alert nano-alert--success" role="alert">
|
|
230
213
|
<div class="nano-alert__icon"><!-- SVG --></div>
|
|
@@ -243,11 +226,6 @@ Contextual feedback with icon, title, and description.
|
|
|
243
226
|
|
|
244
227
|
#### Checkbox
|
|
245
228
|
|
|
246
|
-
```erb
|
|
247
|
-
<%= render "components/checkbox", label: "Accept terms", name: "tos", error: true %>
|
|
248
|
-
<%= render "components/checkbox", label: "Remember me", checked: true %>
|
|
249
|
-
```
|
|
250
|
-
|
|
251
229
|
```html
|
|
252
230
|
<div class="nano-checkbox">
|
|
253
231
|
<input type="checkbox" id="tos" class="nano-checkbox__input" name="tos">
|
|
@@ -255,29 +233,23 @@ Contextual feedback with icon, title, and description.
|
|
|
255
233
|
</div>
|
|
256
234
|
```
|
|
257
235
|
|
|
258
|
-
**Options:** `label`, `name`, `value`, `checked`, `disabled`, `error`, `id`
|
|
259
|
-
|
|
260
236
|
#### Radio Group
|
|
261
237
|
|
|
262
|
-
```erb
|
|
263
|
-
<%= render "components/radio_group",
|
|
264
|
-
legend: "Plan",
|
|
265
|
-
name: "plan",
|
|
266
|
-
options: [
|
|
267
|
-
{ label: "Free", value: "free", checked: true },
|
|
268
|
-
{ label: "Pro", value: "pro" },
|
|
269
|
-
{ label: "Enterprise", value: "enterprise" }
|
|
270
|
-
] %>
|
|
271
|
-
```
|
|
272
|
-
|
|
273
238
|
```html
|
|
274
239
|
<fieldset class="nano-radio-group">
|
|
275
240
|
<legend class="nano-radio-group__legend">Plan</legend>
|
|
276
241
|
<div class="nano-radio">
|
|
277
|
-
<input type="radio" id="plan-
|
|
278
|
-
<label for="plan-
|
|
242
|
+
<input type="radio" id="plan-free" name="plan" value="free" class="nano-radio__input" checked>
|
|
243
|
+
<label for="plan-free" class="nano-radio__label">Free</label>
|
|
244
|
+
</div>
|
|
245
|
+
<div class="nano-radio">
|
|
246
|
+
<input type="radio" id="plan-pro" name="plan" value="pro" class="nano-radio__input">
|
|
247
|
+
<label for="plan-pro" class="nano-radio__label">Pro</label>
|
|
248
|
+
</div>
|
|
249
|
+
<div class="nano-radio">
|
|
250
|
+
<input type="radio" id="plan-ent" name="plan" value="enterprise" class="nano-radio__input">
|
|
251
|
+
<label for="plan-ent" class="nano-radio__label">Enterprise</label>
|
|
279
252
|
</div>
|
|
280
|
-
<!-- ... -->
|
|
281
253
|
</fieldset>
|
|
282
254
|
```
|
|
283
255
|
|
|
@@ -285,10 +257,6 @@ Contextual feedback with icon, title, and description.
|
|
|
285
257
|
|
|
286
258
|
Toggle switch with Stimulus controller.
|
|
287
259
|
|
|
288
|
-
```erb
|
|
289
|
-
<%= render "components/switch", label: "Enable notifications", checked: true %>
|
|
290
|
-
```
|
|
291
|
-
|
|
292
260
|
```html
|
|
293
261
|
<button type="button" role="switch" aria-checked="true" class="nano-switch"
|
|
294
262
|
data-controller="nanoui-switch" data-action="nanoui-switch#toggle">
|
|
@@ -299,24 +267,19 @@ Toggle switch with Stimulus controller.
|
|
|
299
267
|
|
|
300
268
|
#### Select
|
|
301
269
|
|
|
302
|
-
Native `<select>` with custom styling.
|
|
303
|
-
|
|
304
|
-
```erb
|
|
305
|
-
<%= render "components/select",
|
|
306
|
-
label: "Country",
|
|
307
|
-
placeholder: "Select a country",
|
|
308
|
-
options: ["United States", "Canada", "United Kingdom"] %>
|
|
309
|
-
|
|
310
|
-
<%= render "components/select",
|
|
311
|
-
label: "Role",
|
|
312
|
-
required: true,
|
|
313
|
-
options: [
|
|
314
|
-
{ label: "Admin", value: "admin" },
|
|
315
|
-
{ label: "Editor", value: "editor" }
|
|
316
|
-
] %>
|
|
317
|
-
```
|
|
270
|
+
Native `<select>` with custom styling. Bare `<select>` gets styled automatically.
|
|
318
271
|
|
|
319
|
-
|
|
272
|
+
```html
|
|
273
|
+
<div class="nano-field">
|
|
274
|
+
<label for="country">Country</label>
|
|
275
|
+
<select id="country">
|
|
276
|
+
<option value="">Select a country</option>
|
|
277
|
+
<option>United States</option>
|
|
278
|
+
<option>Canada</option>
|
|
279
|
+
<option>United Kingdom</option>
|
|
280
|
+
</select>
|
|
281
|
+
</div>
|
|
282
|
+
```
|
|
320
283
|
|
|
321
284
|
---
|
|
322
285
|
|
|
@@ -326,19 +289,6 @@ Native `<select>` with custom styling.
|
|
|
326
289
|
|
|
327
290
|
Native `<dialog>` with `showModal()` — free focus trap, Escape close, and `::backdrop`.
|
|
328
291
|
|
|
329
|
-
```erb
|
|
330
|
-
<%= render "components/dialog",
|
|
331
|
-
title: "Edit Profile",
|
|
332
|
-
description: "Update your info.",
|
|
333
|
-
trigger: render("components/button") { "Open" },
|
|
334
|
-
footer: safe_join([
|
|
335
|
-
render("components/button", variant: "outline", html: { data: { action: "nanoui-dialog#close" } }) { "Cancel" },
|
|
336
|
-
render("components/button", variant: "primary") { "Save" }
|
|
337
|
-
]) do %>
|
|
338
|
-
<p>Dialog body content.</p>
|
|
339
|
-
<% end %>
|
|
340
|
-
```
|
|
341
|
-
|
|
342
292
|
```html
|
|
343
293
|
<div data-controller="nanoui-dialog">
|
|
344
294
|
<button data-action="nanoui-dialog#open">Open</button>
|
|
@@ -347,12 +297,18 @@ Native `<dialog>` with `showModal()` — free focus trap, Escape close, and `::b
|
|
|
347
297
|
aria-labelledby="dialog-title">
|
|
348
298
|
<div class="nano-dialog__content">
|
|
349
299
|
<header class="nano-dialog__header">
|
|
350
|
-
<h2 id="dialog-title" class="nano-dialog__title">
|
|
300
|
+
<h2 id="dialog-title" class="nano-dialog__title">Edit Profile</h2>
|
|
301
|
+
<p class="nano-dialog__description">Update your info.</p>
|
|
351
302
|
</header>
|
|
352
|
-
<div class="nano-dialog__body"
|
|
353
|
-
|
|
303
|
+
<div class="nano-dialog__body">
|
|
304
|
+
<p>Dialog body content.</p>
|
|
305
|
+
</div>
|
|
306
|
+
<footer class="nano-dialog__footer">
|
|
307
|
+
<button class="nano-btn--outline" data-action="nanoui-dialog#close">Cancel</button>
|
|
308
|
+
<button>Save</button>
|
|
309
|
+
</footer>
|
|
354
310
|
<button class="nano-dialog__close" data-action="nanoui-dialog#close"
|
|
355
|
-
aria-label="Close dialog"
|
|
311
|
+
aria-label="Close dialog">×</button>
|
|
356
312
|
</div>
|
|
357
313
|
</dialog>
|
|
358
314
|
</div>
|
|
@@ -364,14 +320,16 @@ Native `<dialog>` with `showModal()` — free focus trap, Escape close, and `::b
|
|
|
364
320
|
|
|
365
321
|
Click-activated menu with keyboard navigation.
|
|
366
322
|
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
<
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
323
|
+
```html
|
|
324
|
+
<div data-controller="nanoui-dropdown">
|
|
325
|
+
<button class="nano-btn--outline" data-action="nanoui-dropdown#toggle">Options</button>
|
|
326
|
+
<div class="nano-dropdown__menu" data-nanoui-dropdown-target="menu">
|
|
327
|
+
<button class="nano-dropdown__item">Profile</button>
|
|
328
|
+
<button class="nano-dropdown__item">Settings</button>
|
|
329
|
+
<div class="nano-dropdown__separator"></div>
|
|
330
|
+
<button class="nano-dropdown__item">Log out</button>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
375
333
|
```
|
|
376
334
|
|
|
377
335
|
Keyboard: Arrow Up/Down navigates items, Escape closes, click outside closes.
|
|
@@ -380,12 +338,12 @@ Keyboard: Arrow Up/Down navigates items, Escape closes, click outside closes.
|
|
|
380
338
|
|
|
381
339
|
Hover/focus tooltip with configurable delay.
|
|
382
340
|
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
|
|
341
|
+
```html
|
|
342
|
+
<div data-controller="nanoui-tooltip" data-nanoui-tooltip-text-value="Add to favorites">
|
|
343
|
+
<button class="nano-btn--primary nano-btn--icon">
|
|
386
344
|
<!-- heart icon SVG -->
|
|
387
|
-
|
|
388
|
-
|
|
345
|
+
</button>
|
|
346
|
+
</div>
|
|
389
347
|
```
|
|
390
348
|
|
|
391
349
|
**Positions:** top (default), bottom, left, right. **Delay:** 200ms default.
|
|
@@ -396,16 +354,19 @@ Auto-dismissing notifications stacked bottom-right.
|
|
|
396
354
|
|
|
397
355
|
Place the container once in your layout:
|
|
398
356
|
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
<%= render "components/toast_container" %>
|
|
357
|
+
```html
|
|
358
|
+
<div class="nano-toast-container" data-controller="nanoui-toast"></div>
|
|
402
359
|
```
|
|
403
360
|
|
|
404
|
-
Add toasts dynamically
|
|
361
|
+
Add toasts dynamically:
|
|
405
362
|
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
|
|
363
|
+
```html
|
|
364
|
+
<div class="nano-toast nano-toast--success" role="alert">
|
|
365
|
+
<div class="nano-toast__content">
|
|
366
|
+
<p class="nano-toast__title">Saved!</p>
|
|
367
|
+
<p class="nano-toast__description">Changes applied.</p>
|
|
368
|
+
</div>
|
|
369
|
+
</div>
|
|
409
370
|
```
|
|
410
371
|
|
|
411
372
|
**Variants:** default, success, destructive, warning. **Auto-dismiss:** 5000ms default.
|
|
@@ -418,57 +379,85 @@ Add toasts dynamically (via Turbo Stream or JS):
|
|
|
418
379
|
|
|
419
380
|
Semantic table with responsive scroll wrapper.
|
|
420
381
|
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
</
|
|
431
|
-
|
|
432
|
-
|
|
382
|
+
```html
|
|
383
|
+
<div class="nano-table-wrapper">
|
|
384
|
+
<table class="nano-table nano-table--striped nano-table--hoverable">
|
|
385
|
+
<thead>
|
|
386
|
+
<tr>
|
|
387
|
+
<th class="nano-table__head">Name</th>
|
|
388
|
+
<th class="nano-table__head">Email</th>
|
|
389
|
+
<th class="nano-table__head">Status</th>
|
|
390
|
+
</tr>
|
|
391
|
+
</thead>
|
|
392
|
+
<tbody>
|
|
393
|
+
<tr class="nano-table__row">
|
|
394
|
+
<td class="nano-table__cell">Jane Doe</td>
|
|
395
|
+
<td class="nano-table__cell">jane@example.com</td>
|
|
396
|
+
<td class="nano-table__cell">
|
|
397
|
+
<span class="nano-badge nano-badge--success">Active</span>
|
|
398
|
+
</td>
|
|
399
|
+
</tr>
|
|
400
|
+
</tbody>
|
|
401
|
+
</table>
|
|
402
|
+
</div>
|
|
433
403
|
```
|
|
434
404
|
|
|
435
|
-
**Options:** `headers`, `striped`, `hoverable`, `class`
|
|
436
|
-
|
|
437
405
|
#### Tabs
|
|
438
406
|
|
|
439
407
|
WAI-ARIA tabs pattern with arrow key navigation.
|
|
440
408
|
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
409
|
+
```html
|
|
410
|
+
<div data-controller="nanoui-tabs" class="nano-tabs">
|
|
411
|
+
<div role="tablist" aria-label="Settings" class="nano-tabs__list">
|
|
412
|
+
<button role="tab" aria-selected="true" aria-controls="general"
|
|
413
|
+
class="nano-tabs__trigger" data-action="nanoui-tabs#select">General</button>
|
|
414
|
+
<button role="tab" aria-selected="false" aria-controls="security"
|
|
415
|
+
class="nano-tabs__trigger" data-action="nanoui-tabs#select">Security</button>
|
|
416
|
+
<button role="tab" aria-selected="false" aria-controls="billing"
|
|
417
|
+
class="nano-tabs__trigger" data-action="nanoui-tabs#select">Billing</button>
|
|
418
|
+
</div>
|
|
419
|
+
<div role="tabpanel" id="general" class="nano-tabs__content">General settings...</div>
|
|
420
|
+
<div role="tabpanel" id="security" class="nano-tabs__content" hidden>Security settings...</div>
|
|
421
|
+
<div role="tabpanel" id="billing" class="nano-tabs__content" hidden>Billing info...</div>
|
|
422
|
+
</div>
|
|
447
423
|
```
|
|
448
424
|
|
|
449
|
-
**Options:** `tabs` (array), `label` (aria-label), `hash` (URL hash sync)
|
|
450
|
-
|
|
451
425
|
#### Accordion
|
|
452
426
|
|
|
453
427
|
Native `<details>`/`<summary>` with optional single-open mode.
|
|
454
428
|
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
429
|
+
```html
|
|
430
|
+
<div class="nano-accordion" data-controller="nanoui-accordion"
|
|
431
|
+
data-nanoui-accordion-single-value="true">
|
|
432
|
+
<details class="nano-accordion__item" open>
|
|
433
|
+
<summary class="nano-accordion__trigger">Is it free?</summary>
|
|
434
|
+
<div class="nano-accordion__content">Yes, MIT licensed.</div>
|
|
435
|
+
</details>
|
|
436
|
+
<details class="nano-accordion__item">
|
|
437
|
+
<summary class="nano-accordion__trigger">Build step?</summary>
|
|
438
|
+
<div class="nano-accordion__content">No, vanilla CSS.</div>
|
|
439
|
+
</details>
|
|
440
|
+
<details class="nano-accordion__item">
|
|
441
|
+
<summary class="nano-accordion__trigger">Dark mode?</summary>
|
|
442
|
+
<div class="nano-accordion__content">Add .dark class to <html>.</div>
|
|
443
|
+
</details>
|
|
444
|
+
</div>
|
|
461
445
|
```
|
|
462
446
|
|
|
463
|
-
**Options:** `items` (array), `single` (single-open mode), `class`
|
|
464
|
-
|
|
465
447
|
#### Progress
|
|
466
448
|
|
|
467
449
|
Native `<progress>` element with custom styling.
|
|
468
450
|
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
|
|
451
|
+
```html
|
|
452
|
+
<div class="nano-progress">
|
|
453
|
+
<progress class="nano-progress__bar" value="65" max="100"></progress>
|
|
454
|
+
<span class="nano-progress__label">65%</span>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
<div class="nano-progress nano-progress--success">
|
|
458
|
+
<progress class="nano-progress__bar" value="100" max="100"></progress>
|
|
459
|
+
<span class="nano-progress__label">Complete</span>
|
|
460
|
+
</div>
|
|
472
461
|
```
|
|
473
462
|
|
|
474
463
|
**Variants:** default (primary), success, warning, destructive
|
|
@@ -523,6 +512,7 @@ rails generate nanoui:component --all
|
|
|
523
512
|
## Philosophy
|
|
524
513
|
|
|
525
514
|
- **Semantic HTML first** — `<dialog>`, `<details>`, `<progress>`, `<fieldset>`, `<output>`
|
|
515
|
+
- **Native element styling** — Bare HTML elements look good without classes
|
|
526
516
|
- **Accessibility is not optional** — ARIA attributes, keyboard navigation, focus management, screen reader support
|
|
527
517
|
- **No build step** — No Tailwind, no PostCSS, no webpack. Vanilla CSS with native nesting
|
|
528
518
|
- **You own the code** — Generator copies files into your app. Edit freely, no runtime dependency
|