ariadne_view_components 0.0.81 → 0.0.83

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/app/assets/javascripts/ariadne_view_components.js +14 -14
  4. data/app/assets/javascripts/ariadne_view_components.js.br +0 -0
  5. data/app/assets/javascripts/ariadne_view_components.js.gz +0 -0
  6. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  7. data/app/assets/stylesheets/ariadne_view_components.css +1 -1
  8. data/app/assets/stylesheets/ariadne_view_components.css.br +0 -0
  9. data/app/assets/stylesheets/ariadne_view_components.css.gz +0 -0
  10. data/app/components/ariadne/behaviors/captionable.rb +1 -1
  11. data/app/components/ariadne/behaviors/tooltipable.rb +1 -1
  12. data/app/components/ariadne/form/group/component.html.erb +0 -2
  13. data/app/components/ariadne/form/group/component.rb +4 -1
  14. data/app/components/ariadne/form/radio_button/component.html.erb +1 -1
  15. data/app/components/ariadne/form/radio_button/component.rb +1 -1
  16. data/app/components/ariadne/form/select/component.html.erb +10 -0
  17. data/app/components/ariadne/form/select/component.rb +81 -0
  18. data/app/components/ariadne/ui/accordion/component.html.erb +7 -0
  19. data/app/components/ariadne/ui/accordion/component.rb +27 -0
  20. data/app/components/ariadne/ui/accordion/component.ts +69 -0
  21. data/app/components/ariadne/ui/accordion/item/component.html.erb +15 -0
  22. data/app/components/ariadne/ui/accordion/item/component.rb +54 -0
  23. data/app/components/ariadne/ui/badge/component.html.erb +1 -1
  24. data/app/components/ariadne/ui/badge/component.rb +0 -1
  25. data/app/components/ariadne/ui/button/component.html.erb +2 -1
  26. data/app/components/ariadne/ui/button/component.rb +48 -10
  27. data/app/components/ariadne/ui/card/component.html.erb +12 -2
  28. data/app/components/ariadne/ui/card/component.rb +21 -2
  29. data/app/components/ariadne/ui/card/header/component.html.erb +3 -4
  30. data/app/components/ariadne/ui/card/header/component.rb +8 -5
  31. data/app/components/ariadne/ui/combobox/component.rb +4 -2
  32. data/app/components/ariadne/ui/combobox/component.ts +27 -11
  33. data/app/components/ariadne/ui/dialog/component.rb +18 -2
  34. data/app/components/ariadne/ui/flash/component.html.erb +11 -11
  35. data/app/components/ariadne/ui/flash/component.rb +30 -12
  36. data/app/components/ariadne/ui/link/component.rb +32 -7
  37. data/app/components/ariadne/ui/list/component.html.erb +8 -1
  38. data/app/components/ariadne/ui/list/component.rb +17 -2
  39. data/app/components/ariadne/ui/popover/component.rb +1 -1
  40. data/app/components/ariadne/ui/typography/component.rb +5 -0
  41. data/app/frontend/controllers/form_validity_controller.ts +32 -0
  42. data/app/lib/ariadne/view_helper.rb +6 -0
  43. data/lib/ariadne/forms/dsl/badge.rb +2 -2
  44. data/lib/ariadne/forms/dsl/button_input.rb +2 -1
  45. data/lib/ariadne/forms/dsl/clipboard_copy_button.rb +34 -0
  46. data/lib/ariadne/forms/dsl/form_object.rb +1 -1
  47. data/lib/ariadne/forms/dsl/input.rb +1 -1
  48. data/lib/ariadne/forms/dsl/input_methods.rb +4 -0
  49. data/lib/ariadne/forms/dsl/select_input.rb +50 -0
  50. data/lib/ariadne/view_components/version.rb +1 -1
  51. metadata +12 -2
@@ -16,10 +16,32 @@ module Ariadne
16
16
  option :type, default: proc { "button" }
17
17
  option :state, default: proc { "" }
18
18
  option :theme, default: proc { :primary }
19
- option :size, default: proc { :base }
19
+ option :size, default: proc { :md }
20
20
  option :width, default: proc { :narrow }
21
21
 
22
- renders_one :leading_visual_icon, Ariadne::UI::Heroicon::Component
22
+ # Leading visuals appear to the left of the button text.
23
+ #
24
+ # Use:
25
+ #
26
+ # - `leading_visual_heroicon` for a <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
27
+ renders_one :leading_visual, types: {
28
+ heroicon: lambda { |**options|
29
+ options[:size] = @size
30
+ Ariadne::UI::Heroicon::Component.new(**options)
31
+ },
32
+ }
33
+
34
+ # Trailing visuals appear to the right of the button text.
35
+ #
36
+ # Use:
37
+ #
38
+ # - `trailing_visual_heroicon` for a <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
39
+ renders_one :trailing_visual, types: {
40
+ heroicon: lambda { |**options|
41
+ options[:size] = @size
42
+ Ariadne::UI::Heroicon::Component.new(**options)
43
+ },
44
+ }
23
45
 
24
46
  accepts_html_attributes do |html_attrs|
25
47
  html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(theme:, size:, icon_only:, width:), html_attrs[:class]].join(" "))
@@ -45,7 +67,8 @@ module Ariadne
45
67
  @icon_only = true
46
68
  @aria_label = aria(html_attrs, "label")
47
69
  @aria_description = aria(html_attrs, "description")
48
- options.delete(:size)
70
+
71
+ options[:size] = @size
49
72
 
50
73
  @icon = Ariadne::UI::Heroicon::Component.new(**options)
51
74
  self
@@ -60,7 +83,7 @@ module Ariadne
60
83
  "ariadne-gap-x-1.5",
61
84
  "ariadne-rounded",
62
85
  "ariadne-px-2",
63
- "ariadne-py-1",
86
+ # "ariadne-py-1",
64
87
  "ariadne-font-semibold",
65
88
  "ariadne-shadow-sm",
66
89
  "ariadne-text-black",
@@ -140,6 +163,12 @@ module Ariadne
140
163
  "dark:active:ariadne-bg-red-400",
141
164
  ]
142
165
  end
166
+
167
+ none do
168
+ [
169
+ "ariadne-shadow-none",
170
+ ]
171
+ end
143
172
  end
144
173
 
145
174
  size do
@@ -154,7 +183,7 @@ module Ariadne
154
183
  "ariadne-leading-5",
155
184
  ]
156
185
  end
157
- base do
186
+ md do
158
187
  [
159
188
  "ariadne-rounded-md",
160
189
  "ariadne-px-2.5",
@@ -190,9 +219,7 @@ module Ariadne
190
219
  end
191
220
  end
192
221
 
193
- private
194
-
195
- def button_tag
222
+ private def button_tag
196
223
  if link?
197
224
  "a"
198
225
  else
@@ -200,8 +227,19 @@ module Ariadne
200
227
  end
201
228
  end
202
229
 
203
- def link? = as == :link
204
- def button? = as == :button
230
+ private def link? = as == :link
231
+ private def button? = as == :button
232
+
233
+ private def trimmed_content
234
+ return if content.blank?
235
+
236
+ trimmed_content = content.strip
237
+
238
+ return trimmed_content unless content.html_safe?
239
+
240
+ # strip unsets `html_safe`, so we have to set it back again to guarantee that HTML blocks won't break
241
+ trimmed_content.html_safe # rubocop:disable Rails/OutputSafety
242
+ end
205
243
  end
206
244
  end
207
245
  end
@@ -1,7 +1,17 @@
1
1
  <div class="<%= html_attrs[:class] %>" <%= html_attributes %>>
2
+ <% if href.present? %>
3
+ <%= render(Ariadne::UI::Link::Component.new(href: href, theme: :none, html_attrs: { class: "w-full h-full"})) do %>
4
+ <%= header %>
5
+ <div class="ariadne-p-6 ariadne-pt-0">
6
+ <%= content %>
7
+ </div>
8
+ <%= footer %>
9
+ <% end %>
10
+ <% else %>
2
11
  <%= header %>
3
- <div class="ariadne-p-6 ariadne-pt-0">
4
- <%= content %>
12
+ <div class="ariadne-p-6 ariadne-pt-0">
13
+ <%= content %>
5
14
  </div>
6
15
  <%= footer %>
7
16
  </div>
17
+ <% end %>
@@ -5,10 +5,12 @@ module Ariadne
5
5
  module UI
6
6
  module Card
7
7
  class Component < Ariadne::BaseComponent
8
+ option :href, default: -> { nil }
9
+
8
10
  renders_one :header, Ariadne::UI::Card::Header::Component
9
11
 
10
12
  accepts_html_attributes do |html_attrs|
11
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style, html_attrs[:class]].join(" "))
13
+ html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(link: href.present? ? :yes : :no), html_attrs[:class]].join(" "))
12
14
  end
13
15
 
14
16
  renders_one :footer, Ariadne::UI::Card::Footer::Component
@@ -18,13 +20,30 @@ module Ariadne
18
20
  [
19
21
  "ariadne-rounded-lg",
20
22
  "ariadne-border",
21
- "ariadne-shadow-sm",
22
23
  "ariadne-bg-foreground",
23
24
  "dark:ariadne-bg-foreground-dark",
24
25
  "ariadne-text-content",
25
26
  "dark:ariadne-text-content-dark",
26
27
  ]
27
28
  end
29
+
30
+ variants do
31
+ link do
32
+ no do
33
+ []
34
+ end
35
+
36
+ yes do
37
+ [
38
+ "hover:ariadne-shadow-md",
39
+ "hover:ariadne-border-indigo-600",
40
+ "dark:hover:ariadne-border-indigo-400",
41
+ "hover:ariadne-bg-foreground-700/10",
42
+ "dark:hover:ariadne-bg-foreground-300/10",
43
+ ]
44
+ end
45
+ end
46
+ end
28
47
  end
29
48
  end
30
49
  end
@@ -1,7 +1,6 @@
1
1
  <div class="<%= html_attrs[:class] %>" <%= html_attributes %>>
2
- <%= title %>
3
-
4
- <% if description %>
2
+ <%= title %>
3
+ <% if description %>
5
4
  <%= description %>
6
- <% end %>
5
+ <% end %>
7
6
  </div>
@@ -6,17 +6,20 @@ module Ariadne
6
6
  module Card
7
7
  module Header
8
8
  class Component < Ariadne::BaseComponent
9
- option :prioritize, default: proc { :title }
10
- option :size, default: proc { :base }
11
-
12
9
  renders_one :title, lambda { |type: :subheading, **options|
13
10
  options[:type] ||= type
11
+ options[:html_attrs] ||= {}
12
+ options[:html_attrs][:class] ||= ""
13
+ options[:html_attrs][:class] = [
14
+ "ariadne-grow",
15
+ "ariadne-leading-none",
16
+ options[:html_attrs][:class],
17
+ ]
14
18
  Ariadne::UI::Typography::Component.new(**options)
15
19
  }
16
20
 
17
- renders_one :description, lambda { |type: :muted, size: :sm, **options|
21
+ renders_one :description, lambda { |type: :muted, **options|
18
22
  options[:type] ||= type
19
- options[:size] ||= size
20
23
  Ariadne::UI::Typography::Component.new(**options)
21
24
  }
22
25
 
@@ -19,12 +19,14 @@ module Ariadne
19
19
  renders_one :button, Ariadne::UI::Button::Component
20
20
 
21
21
  accepts_html_attributes do |html_attrs|
22
+ html_attrs[:data] ||= {}
22
23
  html_attrs[:data] = {
23
- controller: stimulus_name,
24
+ controller: "#{stimulus_name} #{html_attrs[:data].delete(:controller)}".strip,
24
25
  "#{stimulus_name}-target": "wrapper",
25
26
  "#{stimulus_name}-placement-value": placement,
26
27
  "#{stimulus_name}-clamped-value": clamped,
27
- }
28
+ }.merge(html_attrs[:data])
29
+
28
30
  if changed_action
29
31
  html_attrs[:data][:action] = "#{stimulus_name}:changed->#{changed_action}"
30
32
  end
@@ -13,6 +13,7 @@ export default class ComboboxController extends controllerFactory<HTMLDetailsEle
13
13
  values: {
14
14
  clamped: Boolean,
15
15
  placement: String,
16
+ dynamicLabelPrefix: String,
16
17
  },
17
18
  }) {
18
19
  private changedIds = new Set<string>()
@@ -43,17 +44,19 @@ export default class ComboboxController extends controllerFactory<HTMLDetailsEle
43
44
  }
44
45
 
45
46
  setupForm(): void {
46
- // https://github.com/github/details-menu-element?tab=readme-ov-file#markup
47
- for (const checkbox of this.popoverTarget.querySelectorAll('input[type="checkbox"]')) {
48
- checkbox.addEventListener('change', (e: {target: HTMLInputElement}) => {
49
- const value = e.target as HTMLInputElement
50
- if (this.changedIds.has(value)) {
51
- this.changedIds.delete(value)
52
- } else {
53
- this.changedIds.add(value)
54
- }
55
- this.dispatch('clicked', {detail: value})
56
- })
47
+ for (const formType of ['checkbox', 'radio']) {
48
+ // https://github.com/github/details-menu-element?tab=readme-ov-file#markup
49
+ for (const el of this.popoverTarget.querySelectorAll(`input[type="${formType}"]`)) {
50
+ el.addEventListener('change', (e: {target: HTMLInputElement}) => {
51
+ const value = e.target as HTMLInputElement
52
+ if (this.changedIds.has(value)) {
53
+ this.changedIds.delete(value)
54
+ } else {
55
+ this.changedIds.add(value)
56
+ }
57
+ this.dispatch('clicked', {detail: value})
58
+ })
59
+ }
57
60
  }
58
61
  }
59
62
 
@@ -97,6 +100,19 @@ export default class ComboboxController extends controllerFactory<HTMLDetailsEle
97
100
  this.unsubAutoUpdate = autoUpdate(this.buttonTarget, this.popoverTarget, updatePopoverPosition)
98
101
  }
99
102
 
103
+ updateButtonLabel(e: Event): void {
104
+ const target = e.target as HTMLDetailsElement
105
+ const checkedRadioButton = target.querySelector('input[type=radio]:checked') as HTMLInputElement | null
106
+
107
+ if (!checkedRadioButton) return
108
+
109
+ const selectedText = (checkedRadioButton.labels?.item(0) as HTMLLabelElement).textContent
110
+
111
+ this.buttonTarget.querySelector(
112
+ '[data-ariadne-ui-button-target="content"]',
113
+ ).textContent = `${this.dynamicLabelPrefixValue}${selectedText}`
114
+ }
115
+
100
116
  toggle(): void {
101
117
  this.element.open = !this.element.open
102
118
  this.setupAutoUpdate()
@@ -8,6 +8,7 @@ module Ariadne
8
8
  option :title
9
9
  option :trigger_close_label
10
10
  option :description, optional: true
11
+ option :width, default: proc { :base }
11
12
 
12
13
  renders_one :trigger
13
14
  renders_one :footer
@@ -18,8 +19,6 @@ module Ariadne
18
19
  base do
19
20
  [
20
21
  "ariadne-fixed",
21
- "ariadne-w-96",
22
- "ariadne-max-w-[90vw]",
23
22
  "ariadne-max-h-[90-vh]",
24
23
  "ariadne-shadow-xl",
25
24
  "ariadne-rounded-2xl",
@@ -31,6 +30,23 @@ module Ariadne
31
30
  "backdrop:dark:ariadne-bg-zinc-100/20",
32
31
  ]
33
32
  end
33
+ variants do
34
+ width do
35
+ base do
36
+ [
37
+ "ariadne-w-96",
38
+ "ariadne-max-w-[90vw]",
39
+ ]
40
+ end
41
+
42
+ wide do
43
+ [
44
+ "ariadne-w-3/5",
45
+ "ariadne-max-w-[90vw]",
46
+ ]
47
+ end
48
+ end
49
+ end
34
50
  end
35
51
  end
36
52
  end
@@ -1,18 +1,18 @@
1
1
  <div class="<%= html_attrs[:class] %>" <%= html_attributes %>>
2
- <div class="ariadne-p-4">
2
+ <div class="ariadne-p-4">
3
3
  <div class="ariadne-flex ariadne-items-start">
4
- <div class="ariadne-flex-shrink-0 <%= style(:text, type:) %>">
4
+ <div class="ariadne-flex-shrink-0 <%= style(:text, type:) %>">
5
5
  <%= icon %>
6
- </div>
7
- <div class="ariadne-ml-3 ariadne-w-0 ariadne-flex-1 ariadne-pt-0.5 <%= style(:text, type:) %>">
8
- <p class="ariadne-text-sm ariadne-font-semibold "><%= title %></p>
9
- <p class="ariadne-mt-1 ariadne-text-sm "><%= message %></p>
10
- </div>
11
- <div class="ariadne-ml-4 ariadne-flex ariadne-flex-shrink-0 ">
6
+ </div>
7
+ <div class="ariadne-ml-3 ariadne-w-0 ariadne-flex-1 ariadne-pt-0.5 <%= style(:text, type:) %>">
8
+ <p class="ariadne-text-sm ariadne-font-semibold" data-flash-target="title"><%= title %></p>
9
+ <p class="ariadne-mt-1 ariadne-text-sm" data-flash-target="message"><%= message %></p>
10
+ </div>
11
+ <div class="ariadne-ml-4 ariadne-flex ariadne-flex-shrink-0 ">
12
12
  <% if dismissable? %>
13
- <%= render Ariadne::UI::Button::Component.new(theme: :nude, html_attrs: { class: style(:dismissable, type:), aria: { label: "close_label" }, data: { action: "click->#{stimulus_name}#hide" } }).as_icon(icon: "x-mark", variant: :outline) %>
13
+ <%= render Ariadne::UI::Button::Component.new(theme: :nude, html_attrs: { class: style(:dismissable, type:), aria: { label: "close_label" }, data: { action: "click->#{stimulus_name}#hide" } }).as_icon(icon: "x-mark", variant: :outline) %>
14
14
  <% end %>
15
+ </div>
15
16
  </div>
16
- </div>
17
- </div>
17
+ </div>
18
18
  </div>
@@ -9,20 +9,25 @@ module Ariadne
9
9
  option :dismissible, default: proc { false }
10
10
  option :title
11
11
  option :message
12
+ option :persist, default: proc { false }
13
+ option :width, default: proc { :base }
12
14
 
13
15
  accepts_html_attributes do |html_attrs|
14
- html_attrs[:data] = {
15
- controller: "flash",
16
- transition_enter: "ariadne-transform ariadne-ease-out ariadne-duration-300 ariadne-transition-all",
17
- transition_enter_start: "ariadne-translate-y-2 ariadne-opacity-0 sm:ariadne-translate-y-0 sm:ariadne-translate-x-2",
18
- transition_enter_end: "ariadne-translate-y-0 ariadne-opacity-100 sm:ariadne-translate-x-0",
19
- transition_leave: "ariadne-transition-all ariadne-ease-in ariadne-duration-100",
20
- transition_leave_start: "ariadne-opacity-100",
21
- transition_leave_end: "ariadne-opacity-0",
22
- }
16
+ unless persist
17
+ html_attrs[:data] = {
18
+ controller: "flash",
19
+ transition_enter: "ariadne-transform ariadne-ease-out ariadne-duration-300 ariadne-transition-all",
20
+ transition_enter_start: "ariadne-translate-y-2 ariadne-opacity-0 sm:ariadne-translate-y-0 sm:ariadne-translate-x-2",
21
+ transition_enter_end: "ariadne-translate-y-0 ariadne-opacity-100 sm:ariadne-translate-x-0",
22
+ transition_leave: "ariadne-transition-all ariadne-ease-in ariadne-duration-100",
23
+ transition_leave_start: "ariadne-opacity-100",
24
+ transition_leave_end: "ariadne-opacity-0",
25
+ }
26
+ end
27
+
23
28
  html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([
24
29
  html_attrs[:class],
25
- style(type:),
30
+ style(type:, width:),
26
31
  ])
27
32
  end
28
33
 
@@ -36,8 +41,6 @@ module Ariadne
36
41
  base do
37
42
  [
38
43
  "ariadne-pointer-events-auto",
39
- "ariadne-w-full",
40
- "ariadne-max-w-sm",
41
44
  "ariadne-overflow-hidden",
42
45
  "ariadne-rounded-lg",
43
46
  "ariadne-shadow-lg",
@@ -49,6 +52,21 @@ module Ariadne
49
52
  end
50
53
 
51
54
  variants do
55
+ width do
56
+ base do
57
+ [
58
+ "ariadne-w-full",
59
+ "ariadne-max-w-sm",
60
+ ]
61
+ end
62
+
63
+ full do
64
+ [
65
+ "ariadne-w-full",
66
+ ]
67
+ end
68
+ end
69
+
52
70
  type do
53
71
  danger do
54
72
  [
@@ -19,9 +19,10 @@ module Ariadne
19
19
  style do
20
20
  base do
21
21
  [
22
+ "ariadne-cursor-pointer",
22
23
  "ariadne-text-content",
23
24
  "dark:ariadne-text-content-dark",
24
- "ariadne-inline-flex",
25
+ # "ariadne-inline-flex",
25
26
  "ariadne-items-center",
26
27
  "ariadne-border-b",
27
28
  "ariadne-border-transparent",
@@ -32,21 +33,45 @@ module Ariadne
32
33
  theme do
33
34
  base do
34
35
  [
36
+ "ariadne-text-indigo-600",
37
+ "dark:ariadne-text-indigo-400",
38
+
35
39
  "[&>svg]:ariadne-text-zinc-400",
36
40
  "[&>svg]:dark:ariadne-text-zinc-600",
37
- "hover:ariadne-text-indigo-600",
38
- "dark:hover:ariadne-text-indigo-400",
41
+
42
+ "hover:ariadne-text-indigo-500",
43
+ "dark:hover:ariadne-text-indigo-300",
44
+ "hover:ariadne-border-indigo-500",
45
+ "dark:hover:ariadne-border-indigo-300",
46
+ "focus:ariadne-text-indigo-500",
47
+ "dark:focus:ariadne-text-indigo-300",
48
+ "focus:!ariadne-border-transparent",
49
+ "active:ariadne-bg-indigo-700/10",
50
+ "active:dark:ariadne-bg-indigo-300/10",
51
+ ]
52
+ end
53
+
54
+ nude do
55
+ [
39
56
  "hover:ariadne-border-indigo-600",
40
57
  "dark:hover:ariadne-border-indigo-400",
41
- "focus:ariadne-text-indigo-600",
42
- "dark:focus:ariadne-text-indigo-400",
58
+ "focus:ariadne-text-indigo-500",
59
+ "dark:focus:ariadne-text-indigo-300",
43
60
  "focus:!ariadne-border-transparent",
44
61
  "active:ariadne-bg-indigo-700/10",
45
62
  "active:dark:ariadne-bg-indigo-300/10",
46
63
  ]
47
64
  end
48
- nude { "" }
49
- thick { "ariadne-font-semibold" }
65
+
66
+ none do
67
+ []
68
+ end
69
+
70
+ thick do
71
+ [
72
+ "ariadne-font-semibold",
73
+ ]
74
+ end
50
75
  end
51
76
  size do
52
77
  xs { "ariadne-text-xs ariadne-gap-0.5 [&>svg]:ariadne-size-3" }
@@ -15,12 +15,19 @@
15
15
  <div class="ariadne-truncate" role="menuitemcheckbox"><%= checkbox %></div>
16
16
  </div>
17
17
  <% end %>
18
+ <% radio_buttons.each do |radio_button| %>
19
+ <div
20
+ class="<%= style(:item) %>"
21
+ data-<%= stimulus_name %>-target="searchString">
22
+ <div class="ariadne-truncate" role="menuitemradiobutton"><%= radio_button %></div>
23
+ </div>
24
+ <% end %>
18
25
  <% items.each do |item| %>
19
26
  <div
20
27
  <%= 'role="menuitem"' if as_menu %>
21
28
  class="<%= style(:item) %>"
22
29
  data-<%= stimulus_name %>-target="searchString">
23
- <div class="relative ariadne-flex ariadne-cursor-default ariadne-select-none ariadne-items-center ariadne-rounded-sm ariadne-px-2 ariadne-py-1.5 ariadne-text-sm ariadne-outline-none ariadne-data-[disabled=true]:pointer-events-none ariadne-data-[selected=true]:bg-accent ariadne-data-[selected=true]:text-accent-foreground data-[disabled=true]:ariadne-opacity-50"><%= item %></div>
30
+ <div class="ariadne-relative ariadne-flex "><%= item %></div>
24
31
  </div>
25
32
  <% end %>
26
33
  <div class="ariadne-text-center ariadne-hidden" data-<%= stimulus_name %>-target="emptyRoot">
@@ -42,7 +42,23 @@ module Ariadne
42
42
 
43
43
  options[:html_attrs] ||= {}
44
44
  options[:html_attrs][:class] ||= ""
45
- options[:html_attrs][:class] = "ariadne-truncate ariadne-flex ariadne-gap-0.5 ariadne-items-center ariadne-ps-2 ariadne-pe-1 ariadne-rounded !ariadne-ring-0 hover:ariadne-bg-zinc-100 hover:dark:ariadne-bg-zinc-800 focus-within:ariadne-bg-zinc-100 focus-within:dark:ariadne-bg-zinc-800 ariadne-cursor-pointer #{options[:html_attrs][:class]}"
45
+ options[:html_attrs][:class] = [
46
+ "ariadne-truncate",
47
+ "ariadne-border-b-0",
48
+ "ariadne-flex",
49
+ "ariadne-gap-0.5",
50
+ "ariadne-items-center",
51
+ "ariadne-ps-2",
52
+ "ariadne-pe-1",
53
+ "ariadne-rounded",
54
+ "!ariadne-ring-0",
55
+ "hover:ariadne-bg-zinc-100",
56
+ "hover:dark:ariadne-bg-zinc-800",
57
+ "focus-within:ariadne-bg-zinc-100",
58
+ "focus-within:dark:ariadne-bg-zinc-800",
59
+ "ariadne-cursor-pointer",
60
+ options[:html_attrs][:class],
61
+ ]
46
62
 
47
63
  Ariadne::UI::Link::Component.new(**options)
48
64
  }
@@ -86,7 +102,6 @@ module Ariadne
86
102
  style :item do
87
103
  base do
88
104
  [
89
- "ariadne-flex",
90
105
  # "ariadne-gap-0.5",
91
106
  "ariadne-items-center",
92
107
  "ariadne-rounded",
@@ -68,7 +68,7 @@ module Ariadne
68
68
  end
69
69
 
70
70
  def target_id
71
- @target_id ||= Ariadne.generate_id
71
+ @target_id ||= ::Ariadne::ViewHelper.generate_id
72
72
  end
73
73
 
74
74
  style do
@@ -29,6 +29,8 @@ module Ariadne
29
29
  :h5
30
30
  when :lede
31
31
  :p
32
+ when :text
33
+ :p
32
34
  when :code
33
35
  :code
34
36
  else
@@ -142,6 +144,9 @@ module Ariadne
142
144
  "ariadne-text-muted-foreground",
143
145
  ]
144
146
  end
147
+
148
+ text do
149
+ end
145
150
  end
146
151
  end
147
152
  end
@@ -0,0 +1,32 @@
1
+ import {controllerFactory} from '@utils/createController'
2
+ import {useMutation} from 'stimulus-use'
3
+
4
+ /**
5
+ * Simple controller that sets `disabled` attribute on submit button
6
+ * based on the basic validity of the form (HTML validation only).
7
+ */
8
+ export default class FormValidity extends controllerFactory<HTMLFormElement>()({
9
+ targets: {
10
+ button: HTMLButtonElement,
11
+ form: HTMLFormElement,
12
+ },
13
+ }) {
14
+ private get form(): HTMLFormElement {
15
+ return this.hasFormTarget ? this.formTarget : this.element
16
+ }
17
+
18
+ private runCheck() {
19
+ this.buttonTarget.disabled = !this.form.checkValidity()
20
+ }
21
+
22
+ connect() {
23
+ this.form.addEventListener('input', () => this.runCheck())
24
+ this.runCheck()
25
+
26
+ useMutation(this, {childList: true, subtree: true})
27
+ }
28
+
29
+ mutate() {
30
+ this.runCheck()
31
+ }
32
+ }
@@ -6,6 +6,12 @@ module Ariadne
6
6
  module ViewHelper
7
7
  class ViewHelperNotFound < StandardError; end
8
8
 
9
+ class << self
10
+ def generate_id
11
+ SecureRandom.hex(6)
12
+ end
13
+ end
14
+
9
15
  HELPERS = {
10
16
  heroicon: "Ariadne::UI::Heroicon::Component",
11
17
  }.freeze
@@ -23,11 +23,11 @@ module Ariadne
23
23
  end
24
24
 
25
25
  def type
26
- :group
26
+ :badge
27
27
  end
28
28
 
29
29
  def input?
30
- true
30
+ false
31
31
  end
32
32
  end
33
33
  end
@@ -17,7 +17,8 @@ module Ariadne
17
17
  end
18
18
 
19
19
  def to_component
20
- Ariadne::UI::Button::Component.new(**@options).with_content(@label)
20
+ html_attrs = @input_attributes || {}
21
+ Ariadne::UI::Button::Component.new(**@options, html_attrs: html_attrs).with_content(@label)
21
22
  end
22
23
 
23
24
  # :nocov: