baldur 0.1.7 → 0.2.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.
@@ -1,4 +1,48 @@
1
1
  @layer components {
2
+ .sidebar-shell {
3
+ min-height: 100vh;
4
+ background: var(--color-surface-low);
5
+ }
6
+
7
+ .sidebar-shell__main {
8
+ min-width: 0;
9
+ flex: 1 1 auto;
10
+ display: flex;
11
+ flex-direction: column;
12
+ }
13
+
14
+ .sidebar-shell__desktop {
15
+ display: none;
16
+ flex-shrink: 0;
17
+ border-right: 1px solid var(--color-outline-variant);
18
+ background: var(--color-surface);
19
+ padding: var(--space-3);
20
+ flex-direction: column;
21
+ }
22
+
23
+ .sidebar__brand-link {
24
+ display: inline-flex;
25
+ text-decoration: none;
26
+ }
27
+
28
+ .sidebar__brand-link .brand-lockup {
29
+ display: inline-flex;
30
+ align-items: center;
31
+ gap: var(--space-2);
32
+ color: var(--color-on-surface);
33
+ }
34
+
35
+ .sidebar__brand-link .brand-lockup__logo {
36
+ width: 2.25rem;
37
+ height: 2.25rem;
38
+ border-radius: var(--radius-xl);
39
+ object-fit: cover;
40
+ }
41
+
42
+ .sidebar__brand-link .brand-lockup__wordmark {
43
+ color: var(--color-on-surface);
44
+ }
45
+
2
46
  .sidebar {
3
47
  position: sticky;
4
48
  top: 0;
@@ -21,6 +65,196 @@
21
65
  font-weight: 500;
22
66
  }
23
67
 
68
+ .sidebar__header {
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: space-between;
72
+ gap: var(--space-2);
73
+ }
74
+
75
+ .sidebar__slot--header {
76
+ margin-top: var(--space-4);
77
+ }
78
+
79
+ .sidebar__nav {
80
+ margin-top: var(--space-6);
81
+ display: flex;
82
+ flex: 1 1 auto;
83
+ flex-direction: column;
84
+ gap: var(--space-1);
85
+ }
86
+
87
+ .sidebar__section-divider {
88
+ margin-block: var(--space-6);
89
+ border-top: 1px solid var(--color-outline-variant);
90
+ }
91
+
92
+ .sidebar__section-label {
93
+ margin: 0 0 var(--space-2);
94
+ padding-inline: var(--space-3);
95
+ color: var(--color-on-surface-variant);
96
+ font-size: 0.75rem;
97
+ font-weight: 600;
98
+ letter-spacing: 0.08em;
99
+ text-transform: uppercase;
100
+ }
101
+
102
+ .sidebar__footer {
103
+ margin-top: auto;
104
+ border-top: 1px solid var(--color-outline-variant);
105
+ padding-top: var(--space-4);
106
+ }
107
+
108
+ .sidebar__footer-inner {
109
+ display: flex;
110
+ flex-direction: column;
111
+ align-items: flex-start;
112
+ gap: var(--space-3);
113
+ }
114
+
115
+ .sidebar-mobile {
116
+ display: block;
117
+ }
118
+
119
+ .sidebar-mobile__topbar {
120
+ position: sticky;
121
+ top: 0;
122
+ z-index: 10;
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: space-between;
126
+ gap: var(--space-3);
127
+ border-bottom: 1px solid var(--color-outline-variant);
128
+ background: var(--color-surface-highest);
129
+ padding: var(--space-3) var(--space-4);
130
+ }
131
+
132
+ .sidebar-mobile__brand .brand-lockup__logo {
133
+ width: 1.75rem;
134
+ height: 1.75rem;
135
+ border-radius: var(--radius-lg);
136
+ object-fit: cover;
137
+ }
138
+
139
+ .sidebar-mobile__brand .brand-lockup__wordmark {
140
+ color: var(--color-on-surface);
141
+ font-size: 1.125rem;
142
+ font-weight: 700;
143
+ }
144
+
145
+ .sidebar-mobile__panel {
146
+ position: fixed;
147
+ inset: 0;
148
+ z-index: 40;
149
+ display: flex;
150
+ }
151
+
152
+ .sidebar-mobile__scrim {
153
+ position: fixed;
154
+ inset: 0;
155
+ }
156
+
157
+ .sidebar-mobile__surface {
158
+ position: relative;
159
+ display: flex;
160
+ flex: 1 1 auto;
161
+ width: 100%;
162
+ max-width: 20rem;
163
+ flex-direction: column;
164
+ background: var(--color-surface-highest);
165
+ }
166
+
167
+ .sidebar-mobile__close-shell {
168
+ position: absolute;
169
+ top: 0;
170
+ right: 0;
171
+ margin-right: -3rem;
172
+ padding-top: var(--space-2);
173
+ }
174
+
175
+ .sidebar-mobile__close {
176
+ color: var(--color-inverse-on-surface);
177
+ }
178
+
179
+ .sidebar-mobile__close-icon {
180
+ width: 1.5rem;
181
+ height: 1.5rem;
182
+ }
183
+
184
+ .sidebar-mobile__content {
185
+ flex: 1 1 auto;
186
+ overflow-y: auto;
187
+ padding: var(--space-5) var(--space-4) var(--space-4);
188
+ }
189
+
190
+ .sidebar-mobile__slot--header {
191
+ margin-bottom: var(--space-5);
192
+ }
193
+
194
+ .sidebar-mobile__slot--footer {
195
+ border-top: 1px solid var(--color-outline-variant);
196
+ padding: var(--space-4);
197
+ }
198
+
199
+ .sidebar-mobile__nav {
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: var(--space-1);
203
+ }
204
+
205
+ .sidebar-mobile__link {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: var(--space-3);
209
+ border-radius: var(--radius-lg);
210
+ padding: 0.625rem 0.75rem;
211
+ color: var(--color-text-soft);
212
+ font-size: 0.875rem;
213
+ font-weight: 500;
214
+ text-decoration: none;
215
+ }
216
+
217
+ .sidebar-mobile__link:hover,
218
+ .sidebar-mobile__link--active {
219
+ color: var(--color-primary);
220
+ background: color-mix(in srgb, var(--color-primary) 10%, transparent);
221
+ }
222
+
223
+ .sidebar-mobile__icon {
224
+ width: 1.25rem;
225
+ height: 1.25rem;
226
+ flex-shrink: 0;
227
+ }
228
+
229
+ .sidebar-mobile__section-divider {
230
+ margin-block: var(--space-5);
231
+ border-top: 1px solid var(--color-outline-variant);
232
+ }
233
+
234
+ .sidebar-mobile__section-label {
235
+ margin: 0 0 var(--space-2);
236
+ padding-inline: var(--space-3);
237
+ color: var(--color-on-surface-variant);
238
+ font-size: 0.75rem;
239
+ font-weight: 600;
240
+ letter-spacing: 0.08em;
241
+ text-transform: uppercase;
242
+ }
243
+
244
+ @media (min-width: 48rem) {
245
+ .sidebar-shell {
246
+ display: flex;
247
+ }
248
+
249
+ .sidebar-shell__desktop {
250
+ display: flex;
251
+ }
252
+
253
+ .sidebar-mobile {
254
+ display: none;
255
+ }
256
+ }
257
+
24
258
  .sidebar__toggle {
25
259
  cursor: pointer;
26
260
  pointer-events: auto;
@@ -25,4 +25,5 @@
25
25
  @import "./baldur/application/components/stepper.css";
26
26
  @import "./baldur/application/components/switch.css";
27
27
  @import "./baldur/application/components/table.css";
28
+ @import "./baldur/application/components/confirmation.css";
28
29
  @import "./baldur/application/components/timeline.css";
@@ -165,6 +165,31 @@ module Baldur
165
165
  }.merge(options)
166
166
  end
167
167
 
168
+ def ui_modal_host(id:, classes: nil, &block)
169
+ body = block_given? ? capture(&block) : nil
170
+ baldur_render "baldur/components/modal_host",
171
+ id: id,
172
+ classes: classes,
173
+ body: body
174
+ end
175
+
176
+ def ui_confirmation_modal(host_id:, dialog_id:, title:, description: nil, tone: :default, confirm_label: "Confirm", cancel_label: "Cancel", confirm_button_options: {}, cancel_button_options: {}, type_to_confirm: nil, body: nil, &block)
177
+ body = block_given? ? capture(&block) : body
178
+ type_to_confirm = nil unless type_to_confirm.is_a?(Hash)
179
+ baldur_render "baldur/components/confirmation_modal",
180
+ host_id: host_id,
181
+ dialog_id: dialog_id,
182
+ title: title,
183
+ description: description,
184
+ tone: tone,
185
+ confirm_label: confirm_label,
186
+ cancel_label: cancel_label,
187
+ confirm_button_options: confirm_button_options,
188
+ cancel_button_options: cancel_button_options,
189
+ type_to_confirm: type_to_confirm,
190
+ body: body
191
+ end
192
+
168
193
  def ui_badge(text:, variant: :default, size: :sm, html_options: {})
169
194
  baldur_render "baldur/components/badge", text: text, variant: variant, size: size, html_options: html_options
170
195
  end
@@ -0,0 +1,99 @@
1
+ <%
2
+ host_id = local_assigns.fetch(:host_id)
3
+ dialog_id = local_assigns.fetch(:dialog_id)
4
+ title = local_assigns.fetch(:title)
5
+ description = local_assigns[:description]
6
+ tone = (local_assigns[:tone] || :default).to_sym
7
+ confirm_label = local_assigns.fetch(:confirm_label, "Confirm")
8
+ cancel_label = local_assigns.fetch(:cancel_label, "Cancel")
9
+ confirm_button_options = local_assigns.fetch(:confirm_button_options, {})
10
+ cancel_button_options = local_assigns.fetch(:cancel_button_options, {})
11
+ type_to_confirm = local_assigns[:type_to_confirm]
12
+ body = local_assigns.fetch(:body, nil) unless defined?(body)
13
+
14
+ confirm_variant = tone == :danger ? :danger : :primary
15
+ confirm_btn_opts = { label: confirm_label, variant: confirm_variant, type: :submit }.merge(confirm_button_options.except(:data))
16
+ if confirm_button_options[:data].present?
17
+ confirm_btn_opts[:data] = confirm_button_options[:data]
18
+ end
19
+
20
+ cancel_btn_opts = { label: cancel_label, variant: :ghost }.merge(cancel_button_options.except(:data))
21
+ cancel_btn_opts[:data] = { modal_close: true }.merge(cancel_button_options[:data] || {})
22
+
23
+ has_type_to_confirm = type_to_confirm.is_a?(Hash)
24
+ expected_text = has_type_to_confirm ? type_to_confirm[:expected_text].to_s : nil
25
+ confirm_input_id = has_type_to_confirm ? "#{dialog_id}-confirm-input" : nil
26
+ confirm_input_label = has_type_to_confirm ? type_to_confirm[:label].to_s : nil
27
+ confirm_input_placeholder = has_type_to_confirm ? (type_to_confirm[:placeholder].to_s.presence || expected_text) : nil
28
+ confirm_input_hint = has_type_to_confirm ? type_to_confirm[:hint] : nil
29
+ case_sensitive = has_type_to_confirm ? (type_to_confirm[:case_sensitive] != false) : true
30
+
31
+ if has_type_to_confirm
32
+ confirm_btn_opts[:disabled] = true
33
+ confirm_btn_opts[:data] = (confirm_btn_opts[:data] || {}).merge(confirmation_target: "submit")
34
+ end
35
+ %>
36
+ <div id="<%= host_id %>"
37
+ class="fixed inset-0 z-50 hidden flex items-center justify-center bg-black/40 p-4"
38
+ data-controller="modal<%= has_type_to_confirm ? " confirmation" : "" %>"
39
+ <%= has_type_to_confirm ? 'data-confirmation-case-sensitive-value="' + case_sensitive.to_s + '"' : '' %>
40
+ data-modal-selector-value="#<%= host_id %>"
41
+ data-modal="true"
42
+ aria-hidden="true">
43
+ <div id="<%= dialog_id %>" class="dialog motion-fade-scale">
44
+ <div class="flex items-start justify-between gap-4">
45
+ <div>
46
+ <h3 class="text-xl font-semibold text-[color:var(--color-on-surface)]">
47
+ <% if tone == :danger %>
48
+ <span class="inline-flex items-center gap-2">
49
+ <%= ui_icon("triangle-alert", class_name: "h-5 w-5 text-[color:var(--color-error)]") %>
50
+ <%= title %>
51
+ </span>
52
+ <% else %>
53
+ <%= title %>
54
+ <% end %>
55
+ </h3>
56
+ <% if description.present? %>
57
+ <p class="text-sm text-[color:color-mix(in srgb,var(--color-on-surface) 75%,transparent)]"><%= description %></p>
58
+ <% end %>
59
+ </div>
60
+ <button type="button" class="icon-button" aria-label="Close modal" data-modal-close="true">
61
+ <%= ui_icon("x", class_name: "h-5 w-5") %>
62
+ </button>
63
+ </div>
64
+ <% if body.present? %>
65
+ <div class="mt-4 space-y-3 text-sm text-[color:var(--color-on-surface)]">
66
+ <%= body %>
67
+ </div>
68
+ <% end %>
69
+ <% if has_type_to_confirm %>
70
+ <div class="mt-4 space-y-2">
71
+ <% if confirm_input_label.present? %>
72
+ <label for="<%= confirm_input_id %>" class="field__label text-sm font-medium text-[color:var(--color-on-surface)]"><%= confirm_input_label %></label>
73
+ <% end %>
74
+ <div class="text-field__input">
75
+ <input id="<%= confirm_input_id %>"
76
+ type="text"
77
+ autocomplete="off"
78
+ class="text-field__control"
79
+ data-confirmation-target="input"
80
+ data-action="input->confirmation#validate"
81
+ <%= confirm_input_placeholder.present? ? "placeholder=\"#{confirm_input_placeholder}\"".html_safe : "" %>
82
+ data-modal-autofocus="true" />
83
+ </div>
84
+ <% if confirm_input_hint.present? %>
85
+ <p class="text-sm text-muted"><%= confirm_input_hint %></p>
86
+ <% end %>
87
+ <% if expected_text.present? %>
88
+ <span hidden data-confirmation-target="expectedText"><%= expected_text %></span>
89
+ <% end %>
90
+ </div>
91
+ <% end %>
92
+ <div class="mt-6 flex flex-wrap items-center gap-3">
93
+ <div class="ml-auto flex flex-wrap gap-3 justify-end">
94
+ <%= render "baldur/components/button", **cancel_btn_opts %>
95
+ <%= render "baldur/components/button", **confirm_btn_opts %>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
@@ -0,0 +1,10 @@
1
+ <% classes = local_assigns[:classes] %>
2
+ <% body = local_assigns.fetch(:body, nil) unless defined?(body) %>
3
+ <div id="<%= id %>"
4
+ class="fixed inset-0 z-50 hidden flex items-center justify-center bg-black/40 p-4 <%= classes %>"
5
+ data-controller="modal"
6
+ data-modal-selector-value="#<%= id %>"
7
+ data-modal="true"
8
+ aria-hidden="true">
9
+ <%= body %>
10
+ </div>
@@ -19,7 +19,7 @@
19
19
  ]
20
20
  )
21
21
  end
22
- brand_markup = link_to(brand_markup, resolved_brand[:href], class: "inline-flex no-underline") if resolved_brand[:href].present?
22
+ brand_markup = link_to(brand_markup, resolved_brand[:href], class: "sidebar__brand-link") if resolved_brand[:href].present?
23
23
 
24
24
  render_nav_link = lambda do |link, mobile: false|
25
25
  options = link[:html_options].deep_dup
@@ -29,12 +29,12 @@
29
29
  options[:aria] = (options[:aria] || {}).merge(current: (link[:active] ? "page" : nil))
30
30
 
31
31
  if mobile
32
- mobile_class = link[:active] ? "bg-primary/10 text-primary" : "text-soft hover:bg-surface-lowest"
33
- options[:class] = ["flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium", mobile_class, options[:class]].compact.join(" ")
32
+ mobile_class = link[:active] ? "sidebar-mobile__link sidebar-mobile__link--active" : "sidebar-mobile__link"
33
+ options[:class] = [mobile_class, options[:class]].compact.join(" ")
34
34
  link_to(link[:path], **options) do
35
35
  safe_join(
36
36
  [
37
- ui_icon(link[:icon], class_name: "h-5 w-5 shrink-0"),
37
+ ui_icon(link[:icon], class_name: "sidebar-mobile__icon"),
38
38
  content_tag(:span, link[:name])
39
39
  ]
40
40
  )
@@ -53,13 +53,13 @@
53
53
  end
54
54
  %>
55
55
 
56
- <div class="<%= ["sidebar-shell min-h-screen bg-surface-low md:flex", shell_class].compact.join(" ") %>"
56
+ <div class="<%= ["sidebar-shell", shell_class].compact.join(" ") %>"
57
57
  data-controller="sidebar"
58
58
  data-sidebar-storage-key-value="baldur-sidebar-collapsed"
59
59
  data-sidebar-collapsed-value="<%= collapsed %>">
60
- <aside class="sidebar hidden shrink-0 border-r border-[color:var(--color-outline-variant)] bg-[color:var(--color-surface)] px-3 py-4 md:flex flex-col"
60
+ <aside class="sidebar sidebar-shell__desktop"
61
61
  aria-label="Primary navigation">
62
- <div class="sidebar__header flex items-center justify-between gap-2">
62
+ <div class="sidebar__header">
63
63
  <%= brand_markup %>
64
64
  <button type="button"
65
65
  class="icon-button sidebar__toggle"
@@ -72,20 +72,20 @@
72
72
  </div>
73
73
 
74
74
  <% if header_content.present? %>
75
- <div class="sidebar__menu mt-4">
75
+ <div class="sidebar__menu sidebar__slot sidebar__slot--header">
76
76
  <%= header_content %>
77
77
  </div>
78
78
  <% end %>
79
79
 
80
- <nav class="mt-6 flex flex-1 flex-col gap-1" aria-label="Primary navigation links">
80
+ <nav class="sidebar__nav" aria-label="Primary navigation links">
81
81
  <% primary_links.each do |link| %>
82
82
  <%= render_nav_link.call(link) %>
83
83
  <% end %>
84
84
 
85
85
  <% if secondary_links.any? %>
86
- <div class="my-6 border-t border-[color:var(--color-outline-variant)]"></div>
86
+ <div class="sidebar__section-divider"></div>
87
87
  <% if secondary_label.present? %>
88
- <p class="sidebar__section-label mb-2 px-3 text-xs font-semibold uppercase tracking-wide text-[color:var(--color-on-surface-variant)]"><%= secondary_label %></p>
88
+ <p class="sidebar__section-label"><%= secondary_label %></p>
89
89
  <% end %>
90
90
  <% secondary_links.each do |link| %>
91
91
  <%= render_nav_link.call(link) %>
@@ -93,9 +93,9 @@
93
93
  <% end %>
94
94
  </nav>
95
95
 
96
- <% if footer_content.present? %>
97
- <div class="sidebar__footer mt-auto border-t border-[color:var(--color-outline-variant)] pt-4">
98
- <div class="sidebar__footer-inner flex flex-col items-start gap-3">
96
+ <% if footer_content.present? %>
97
+ <div class="sidebar__footer">
98
+ <div class="sidebar__footer-inner">
99
99
  <%= footer_content %>
100
100
  </div>
101
101
  </div>
@@ -104,37 +104,37 @@
104
104
  <button type="button" class="sidebar__toggle-hit-area" aria-label="Toggle navigation" data-action="click->sidebar#toggle"></button>
105
105
  </aside>
106
106
 
107
- <div class="md:hidden" data-controller="mobile-sidebar">
108
- <div class="sticky top-0 z-10 flex items-center justify-between border-b border-outline-variant bg-surface-highest px-4 py-3">
109
- <div><%= brand_markup %></div>
107
+ <div class="sidebar-mobile" data-controller="mobile-sidebar">
108
+ <div class="sidebar-mobile__topbar">
109
+ <div class="sidebar-mobile__brand"><%= brand_markup %></div>
110
110
  <button type="button" class="icon-button" aria-label="Toggle navigation" data-action="mobile-sidebar#toggle">
111
111
  <%= ui_icon("menu", class_name: "h-6 w-6") %>
112
112
  </button>
113
113
  </div>
114
114
 
115
- <div id="mobile-sidebar" class="hidden fixed inset-0 z-40 flex" data-mobile-sidebar-target="panel">
116
- <div class="fixed inset-0 bg-scrim" data-action="click->mobile-sidebar#close"></div>
117
- <div class="relative flex w-full max-w-xs flex-1 flex-col bg-surface-highest">
118
- <div class="absolute right-0 top-0 -mr-12 pt-2">
119
- <button type="button" class="icon-button text-on-inverse" aria-label="Close navigation" data-action="mobile-sidebar#close">
120
- <%= ui_icon("x", class_name: "h-6 w-6 text-on-inverse") %>
115
+ <div id="mobile-sidebar" class="sidebar-mobile__panel hidden" data-mobile-sidebar-target="panel">
116
+ <div class="bg-scrim sidebar-mobile__scrim" data-action="click->mobile-sidebar#close"></div>
117
+ <div class="sidebar-mobile__surface">
118
+ <div class="sidebar-mobile__close-shell">
119
+ <button type="button" class="icon-button sidebar-mobile__close" aria-label="Close navigation" data-action="mobile-sidebar#close">
120
+ <%= ui_icon("x", class_name: "sidebar-mobile__close-icon") %>
121
121
  </button>
122
122
  </div>
123
123
 
124
- <div class="flex-1 overflow-y-auto px-4 pb-4 pt-5">
124
+ <div class="sidebar-mobile__content">
125
125
  <% if mobile_header_content.present? %>
126
- <div class="mb-5"><%= mobile_header_content %></div>
126
+ <div class="sidebar-mobile__slot sidebar-mobile__slot--header"><%= mobile_header_content %></div>
127
127
  <% end %>
128
128
 
129
- <nav class="space-y-1" aria-label="Mobile primary navigation links">
129
+ <nav class="sidebar-mobile__nav" aria-label="Mobile primary navigation links">
130
130
  <% primary_links.each do |link| %>
131
131
  <%= render_nav_link.call(link, mobile: true) %>
132
132
  <% end %>
133
133
 
134
134
  <% if secondary_links.any? %>
135
- <div class="my-5 border-t border-outline-variant"></div>
135
+ <div class="sidebar-mobile__section-divider"></div>
136
136
  <% if secondary_label.present? %>
137
- <p class="mb-2 px-3 text-xs font-semibold uppercase tracking-wide text-on-surface-variant"><%= secondary_label %></p>
137
+ <p class="sidebar-mobile__section-label"><%= secondary_label %></p>
138
138
  <% end %>
139
139
  <% secondary_links.each do |link| %>
140
140
  <%= render_nav_link.call(link, mobile: true) %>
@@ -144,7 +144,7 @@
144
144
  </div>
145
145
 
146
146
  <% if mobile_footer_content.present? %>
147
- <div class="border-t border-outline-variant px-4 py-4">
147
+ <div class="sidebar-mobile__slot sidebar-mobile__slot--footer">
148
148
  <%= mobile_footer_content %>
149
149
  </div>
150
150
  <% end %>
@@ -152,7 +152,7 @@
152
152
  </div>
153
153
  </div>
154
154
 
155
- <div class="flex min-w-0 flex-1 flex-col">
155
+ <div class="sidebar-shell__main">
156
156
  <%= body_content %>
157
157
  </div>
158
158
  </div>
data/baldur.gemspec CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |spec|
4
4
  spec.name = "baldur"
5
5
  spec.version = Baldur::VERSION
6
6
  spec.authors = [ "Varun Murkar" ]
7
- spec.summary = "Reusable Rails UI engine for same-stack application interfaces"
8
- spec.description = "Baldur packages reusable Rails view helpers, components, styles, and Stimulus controllers."
7
+ spec.summary = "Batteries-included Rails UI engine for the importmap, Stimulus, Tailwind stack"
8
+ spec.description = "Baldur helps Rails teams ship polished UI faster with install generators, reusable ui_* helpers, Tailwind components, and Stimulus wiring for apps using Propshaft, importmap-rails, stimulus-rails, and tailwindcss-rails."
9
9
  spec.homepage = "https://github.com/varunmurkar/baldur"
10
10
  spec.license = "MIT"
11
11
  spec.metadata = {
@@ -31,6 +31,6 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_dependency "importmap-rails"
33
33
  spec.add_dependency "lucide-rails"
34
- spec.add_dependency "rails", ">= 8.1.0"
35
- spec.add_dependency "tailwindcss-rails", ">= 4.4.0"
34
+ spec.add_dependency "rails", ">= 7.0.0"
35
+ spec.add_dependency "tailwindcss-rails", ">= 4.3.0"
36
36
  end
@@ -1,3 +1,3 @@
1
1
  module Baldur
2
- VERSION = "0.1.7".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -7,6 +7,7 @@ module Baldur
7
7
 
8
8
  CORE_CONTROLLERS = %w[
9
9
  accordion
10
+ confirmation
10
11
  date_field
11
12
  details_menu
12
13
  form_submit