better_ui 0.7.2 → 0.9.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 +86 -29
- data/app/components/better_ui/application_component.rb +34 -0
- data/app/components/better_ui/avatar_component/avatar_component.html.erb +15 -0
- data/app/components/better_ui/avatar_component.rb +227 -0
- data/app/components/better_ui/badge_component/badge_component.html.erb +16 -0
- data/app/components/better_ui/badge_component.rb +114 -0
- data/app/components/better_ui/breadcrumb/breadcrumb_component/breadcrumb_component.html.erb +12 -0
- data/app/components/better_ui/breadcrumb/breadcrumb_component.rb +148 -0
- data/app/components/better_ui/breadcrumb/item_component/item_component.html.erb +11 -0
- data/app/components/better_ui/breadcrumb/item_component.rb +78 -0
- data/app/components/better_ui/card_component.rb +45 -11
- data/app/components/better_ui/concerns/inline_label_styles.rb +137 -0
- data/app/components/better_ui/container_component/container_component.html.erb +3 -0
- data/app/components/better_ui/container_component.rb +143 -0
- data/app/components/better_ui/dialog/alert_component/alert_component.html.erb +61 -0
- data/app/components/better_ui/dialog/alert_component.rb +78 -0
- data/app/components/better_ui/dialog/confirm_component/confirm_component.html.erb +67 -0
- data/app/components/better_ui/dialog/confirm_component.rb +80 -0
- data/app/components/better_ui/dialog/dialog_component/dialog_component.html.erb +44 -0
- data/app/components/better_ui/dialog/dialog_component.rb +81 -0
- data/app/components/better_ui/divider_component/divider_component.html.erb +11 -0
- data/app/components/better_ui/divider_component.rb +344 -0
- data/app/components/better_ui/drawer/sidebar_component.rb +1 -0
- data/app/components/better_ui/dropdown/divider_component/divider_component.html.erb +1 -0
- data/app/components/better_ui/dropdown/divider_component.rb +20 -0
- data/app/components/better_ui/dropdown/dropdown_component/dropdown_component.html.erb +19 -0
- data/app/components/better_ui/dropdown/dropdown_component.rb +108 -0
- data/app/components/better_ui/dropdown/header_component/header_component.html.erb +3 -0
- data/app/components/better_ui/dropdown/header_component.rb +25 -0
- data/app/components/better_ui/dropdown/item_component/item_component.html.erb +7 -0
- data/app/components/better_ui/dropdown/item_component.rb +97 -0
- data/app/components/better_ui/fa_icon_component/fa_icon_component.html.erb +1 -0
- data/app/components/better_ui/fa_icon_component.rb +165 -0
- data/app/components/better_ui/forms/base_component.rb +3 -1
- data/app/components/better_ui/forms/select_component/select_component.html.erb +86 -0
- data/app/components/better_ui/forms/select_component.rb +347 -0
- data/app/components/better_ui/forms/text_input_component.rb +24 -2
- data/app/components/better_ui/heading_component/heading_component.html.erb +11 -0
- data/app/components/better_ui/heading_component.rb +259 -0
- data/app/components/better_ui/link_component/link_component.html.erb +5 -0
- data/app/components/better_ui/link_component.rb +169 -0
- data/app/components/better_ui/progress_component/progress_component.html.erb +15 -0
- data/app/components/better_ui/progress_component.rb +98 -0
- data/app/components/better_ui/spinner_component/spinner_component.html.erb +11 -0
- data/app/components/better_ui/spinner_component.rb +70 -0
- data/app/components/better_ui/table/cell_component/cell_component.html.erb +3 -0
- data/app/components/better_ui/table/cell_component.rb +84 -0
- data/app/components/better_ui/table/column_component.rb +75 -0
- data/app/components/better_ui/table/header_cell_component/header_cell_component.html.erb +18 -0
- data/app/components/better_ui/table/header_cell_component.rb +138 -0
- data/app/components/better_ui/table/header_component/header_component.html.erb +5 -0
- data/app/components/better_ui/table/header_component.rb +37 -0
- data/app/components/better_ui/table/row_component/row_component.html.erb +5 -0
- data/app/components/better_ui/table/row_component.rb +88 -0
- data/app/components/better_ui/table/table_component/table_component.html.erb +90 -0
- data/app/components/better_ui/table/table_component.rb +467 -0
- data/app/components/better_ui/tabs/container_component/container_component.html.erb +40 -0
- data/app/components/better_ui/tabs/container_component.rb +428 -0
- data/app/components/better_ui/tabs/panel_component/panel_component.html.erb +3 -0
- data/app/components/better_ui/tabs/panel_component.rb +105 -0
- data/app/components/better_ui/tabs/tab_component/tab_component.html.erb +9 -0
- data/app/components/better_ui/tabs/tab_component.rb +316 -0
- data/app/components/better_ui/tag_component/tag_component.html.erb +33 -0
- data/app/components/better_ui/tag_component.rb +114 -0
- data/app/components/better_ui/tooltip_component/tooltip_component.html.erb +11 -0
- data/app/components/better_ui/tooltip_component.rb +154 -0
- data/app/form_builders/better_ui/ui_form_builder.rb +90 -0
- data/app/helpers/better_ui/application_helper.rb +575 -0
- data/lib/better_ui/engine.rb +7 -0
- data/lib/better_ui/version.rb +1 -1
- metadata +63 -3
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<%= render BetterUi::Dialog::DialogComponent.new(
|
|
2
|
+
size: size,
|
|
3
|
+
close_on_backdrop: close_on_backdrop,
|
|
4
|
+
close_on_escape: close_on_escape,
|
|
5
|
+
show_close_button: false,
|
|
6
|
+
**options
|
|
7
|
+
) do |dialog| %>
|
|
8
|
+
<% if trigger? %>
|
|
9
|
+
<% dialog.with_trigger do %>
|
|
10
|
+
<%= trigger %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= render BetterUi::CardComponent.new(style: :bordered, shadow: :sm, size: :md) do |card| %>
|
|
15
|
+
<% card.with_body do %>
|
|
16
|
+
<div class="text-center">
|
|
17
|
+
<% if icon %>
|
|
18
|
+
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full <%= icon_color_classes %>">
|
|
19
|
+
<% case icon_name %>
|
|
20
|
+
<% when :check_circle %>
|
|
21
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
22
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
23
|
+
</svg>
|
|
24
|
+
<% when :exclamation_circle %>
|
|
25
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
26
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
|
|
27
|
+
</svg>
|
|
28
|
+
<% when :exclamation_triangle %>
|
|
29
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
30
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
|
31
|
+
</svg>
|
|
32
|
+
<% when :information_circle %>
|
|
33
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
34
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
|
35
|
+
</svg>
|
|
36
|
+
<% end %>
|
|
37
|
+
</div>
|
|
38
|
+
<% end %>
|
|
39
|
+
|
|
40
|
+
<% if title %>
|
|
41
|
+
<h3 class="mt-4 text-lg font-semibold text-grayscale-900"><%= title %></h3>
|
|
42
|
+
<% end %>
|
|
43
|
+
|
|
44
|
+
<% if text %>
|
|
45
|
+
<p class="mt-2 text-sm text-grayscale-500"><%= text %></p>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<% card.with_footer do %>
|
|
51
|
+
<div class="flex flex-col-reverse sm:flex-row sm:justify-end gap-3">
|
|
52
|
+
<%= render(BetterUi::ButtonComponent.new(
|
|
53
|
+
variant: variant,
|
|
54
|
+
style: :solid,
|
|
55
|
+
container_classes: "w-full",
|
|
56
|
+
data: { action: "click->better-ui--dialog--dialog#close" }
|
|
57
|
+
)) do %><%= button_label %><% end %>
|
|
58
|
+
</div>
|
|
59
|
+
<% end %>
|
|
60
|
+
<% end %>
|
|
61
|
+
<% end %>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
module Dialog
|
|
5
|
+
class AlertComponent < ApplicationComponent
|
|
6
|
+
renders_one :trigger
|
|
7
|
+
|
|
8
|
+
ICON_VARIANTS = {
|
|
9
|
+
success: :check_circle,
|
|
10
|
+
danger: :exclamation_circle,
|
|
11
|
+
warning: :exclamation_triangle,
|
|
12
|
+
info: :information_circle,
|
|
13
|
+
primary: :information_circle,
|
|
14
|
+
secondary: :information_circle,
|
|
15
|
+
accent: :information_circle,
|
|
16
|
+
light: :information_circle,
|
|
17
|
+
dark: :information_circle
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def initialize(
|
|
21
|
+
variant: :info,
|
|
22
|
+
title: nil,
|
|
23
|
+
text: nil,
|
|
24
|
+
icon: true,
|
|
25
|
+
button_label: "OK",
|
|
26
|
+
size: :sm,
|
|
27
|
+
close_on_backdrop: true,
|
|
28
|
+
close_on_escape: true,
|
|
29
|
+
**options
|
|
30
|
+
)
|
|
31
|
+
@variant = validate_variant(normalize_symbol(variant, :info))
|
|
32
|
+
@title = title
|
|
33
|
+
@text = text
|
|
34
|
+
@icon = icon
|
|
35
|
+
@button_label = button_label
|
|
36
|
+
@size = normalize_symbol(size, :sm)
|
|
37
|
+
@close_on_backdrop = close_on_backdrop
|
|
38
|
+
@close_on_escape = close_on_escape
|
|
39
|
+
@options = options
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
attr_reader :variant, :title, :text, :icon, :button_label, :size,
|
|
45
|
+
:close_on_backdrop, :close_on_escape, :options
|
|
46
|
+
|
|
47
|
+
def icon_name
|
|
48
|
+
ICON_VARIANTS[@variant]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def icon_color_classes
|
|
52
|
+
case @variant
|
|
53
|
+
when :success then "text-success-600 bg-success-100"
|
|
54
|
+
when :danger then "text-danger-600 bg-danger-100"
|
|
55
|
+
when :warning then "text-warning-600 bg-warning-100"
|
|
56
|
+
when :info then "text-info-600 bg-info-100"
|
|
57
|
+
when :primary then "text-primary-600 bg-primary-100"
|
|
58
|
+
when :secondary then "text-secondary-600 bg-secondary-100"
|
|
59
|
+
when :accent then "text-accent-600 bg-accent-100"
|
|
60
|
+
when :light then "text-grayscale-600 bg-grayscale-100"
|
|
61
|
+
when :dark then "text-grayscale-800 bg-grayscale-200"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def normalize_symbol(value, fallback)
|
|
66
|
+
sym = value.to_s.strip.to_sym
|
|
67
|
+
sym.blank? ? fallback : sym
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def validate_variant(variant)
|
|
71
|
+
unless BetterUi::ApplicationComponent::VARIANTS.key?(variant)
|
|
72
|
+
raise ArgumentError, "Invalid variant: #{variant}. Must be one of: #{BetterUi::ApplicationComponent::VARIANTS.keys.join(", ")}"
|
|
73
|
+
end
|
|
74
|
+
variant
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<%= render BetterUi::Dialog::DialogComponent.new(
|
|
2
|
+
size: size,
|
|
3
|
+
close_on_backdrop: close_on_backdrop,
|
|
4
|
+
close_on_escape: close_on_escape,
|
|
5
|
+
show_close_button: false,
|
|
6
|
+
**options
|
|
7
|
+
) do |dialog| %>
|
|
8
|
+
<% if trigger? %>
|
|
9
|
+
<% dialog.with_trigger do %>
|
|
10
|
+
<%= trigger %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= render BetterUi::CardComponent.new(style: :bordered, shadow: :sm, size: :md) do |card| %>
|
|
15
|
+
<% card.with_body do %>
|
|
16
|
+
<div class="text-center">
|
|
17
|
+
<% if icon %>
|
|
18
|
+
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full <%= icon_color_classes %>">
|
|
19
|
+
<% case icon_name %>
|
|
20
|
+
<% when :check_circle %>
|
|
21
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
22
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
23
|
+
</svg>
|
|
24
|
+
<% when :exclamation_circle %>
|
|
25
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
26
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
|
|
27
|
+
</svg>
|
|
28
|
+
<% when :exclamation_triangle %>
|
|
29
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
30
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
|
31
|
+
</svg>
|
|
32
|
+
<% when :information_circle %>
|
|
33
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
34
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
|
35
|
+
</svg>
|
|
36
|
+
<% end %>
|
|
37
|
+
</div>
|
|
38
|
+
<% end %>
|
|
39
|
+
|
|
40
|
+
<% if title %>
|
|
41
|
+
<h3 class="mt-4 text-lg font-semibold text-grayscale-900"><%= title %></h3>
|
|
42
|
+
<% end %>
|
|
43
|
+
|
|
44
|
+
<% if text %>
|
|
45
|
+
<p class="mt-2 text-sm text-grayscale-500"><%= text %></p>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<% card.with_footer do %>
|
|
51
|
+
<div class="flex flex-col-reverse sm:flex-row sm:justify-end gap-3">
|
|
52
|
+
<%= render(BetterUi::ButtonComponent.new(
|
|
53
|
+
variant: :secondary,
|
|
54
|
+
style: :outline,
|
|
55
|
+
container_classes: "w-full sm:w-auto",
|
|
56
|
+
data: { action: "click->better-ui--dialog--dialog#cancel" }
|
|
57
|
+
)) do %><%= cancel_label %><% end %>
|
|
58
|
+
<%= render(BetterUi::ButtonComponent.new(
|
|
59
|
+
variant: variant,
|
|
60
|
+
style: :solid,
|
|
61
|
+
container_classes: "w-full sm:w-auto",
|
|
62
|
+
data: { action: "click->better-ui--dialog--dialog#confirm" }
|
|
63
|
+
)) do %><%= confirm_label %><% end %>
|
|
64
|
+
</div>
|
|
65
|
+
<% end %>
|
|
66
|
+
<% end %>
|
|
67
|
+
<% end %>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
module Dialog
|
|
5
|
+
class ConfirmComponent < ApplicationComponent
|
|
6
|
+
renders_one :trigger
|
|
7
|
+
|
|
8
|
+
ICON_VARIANTS = {
|
|
9
|
+
success: :check_circle,
|
|
10
|
+
danger: :exclamation_circle,
|
|
11
|
+
warning: :exclamation_triangle,
|
|
12
|
+
info: :information_circle,
|
|
13
|
+
primary: :information_circle,
|
|
14
|
+
secondary: :information_circle,
|
|
15
|
+
accent: :information_circle,
|
|
16
|
+
light: :information_circle,
|
|
17
|
+
dark: :information_circle
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def initialize(
|
|
21
|
+
variant: :warning,
|
|
22
|
+
title: nil,
|
|
23
|
+
text: nil,
|
|
24
|
+
icon: true,
|
|
25
|
+
confirm_label: "Confirm",
|
|
26
|
+
cancel_label: "Cancel",
|
|
27
|
+
size: :sm,
|
|
28
|
+
close_on_backdrop: false,
|
|
29
|
+
close_on_escape: false,
|
|
30
|
+
**options
|
|
31
|
+
)
|
|
32
|
+
@variant = validate_variant(normalize_symbol(variant, :warning))
|
|
33
|
+
@title = title
|
|
34
|
+
@text = text
|
|
35
|
+
@icon = icon
|
|
36
|
+
@confirm_label = confirm_label
|
|
37
|
+
@cancel_label = cancel_label
|
|
38
|
+
@size = normalize_symbol(size, :sm)
|
|
39
|
+
@close_on_backdrop = close_on_backdrop
|
|
40
|
+
@close_on_escape = close_on_escape
|
|
41
|
+
@options = options
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
attr_reader :variant, :title, :text, :icon, :confirm_label, :cancel_label,
|
|
47
|
+
:size, :close_on_backdrop, :close_on_escape, :options
|
|
48
|
+
|
|
49
|
+
def icon_name
|
|
50
|
+
ICON_VARIANTS[@variant]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def icon_color_classes
|
|
54
|
+
case @variant
|
|
55
|
+
when :success then "text-success-600 bg-success-100"
|
|
56
|
+
when :danger then "text-danger-600 bg-danger-100"
|
|
57
|
+
when :warning then "text-warning-600 bg-warning-100"
|
|
58
|
+
when :info then "text-info-600 bg-info-100"
|
|
59
|
+
when :primary then "text-primary-600 bg-primary-100"
|
|
60
|
+
when :secondary then "text-secondary-600 bg-secondary-100"
|
|
61
|
+
when :accent then "text-accent-600 bg-accent-100"
|
|
62
|
+
when :light then "text-grayscale-600 bg-grayscale-100"
|
|
63
|
+
when :dark then "text-grayscale-800 bg-grayscale-200"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def normalize_symbol(value, fallback)
|
|
68
|
+
sym = value.to_s.strip.to_sym
|
|
69
|
+
sym.blank? ? fallback : sym
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def validate_variant(variant)
|
|
73
|
+
unless BetterUi::ApplicationComponent::VARIANTS.key?(variant)
|
|
74
|
+
raise ArgumentError, "Invalid variant: #{variant}. Must be one of: #{BetterUi::ApplicationComponent::VARIANTS.keys.join(", ")}"
|
|
75
|
+
end
|
|
76
|
+
variant
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<div <%= tag.attributes(component_attributes) %>>
|
|
2
|
+
<% if trigger? %>
|
|
3
|
+
<div data-action="click->better-ui--dialog--dialog#open">
|
|
4
|
+
<%= trigger %>
|
|
5
|
+
</div>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<div data-dialog-overlay
|
|
9
|
+
role="dialog"
|
|
10
|
+
aria-modal="true"
|
|
11
|
+
class="fixed inset-0 z-[1000]"
|
|
12
|
+
<%= "hidden" unless open %>>
|
|
13
|
+
<%# Backdrop %>
|
|
14
|
+
<div data-better-ui--dialog--dialog-target="backdrop"
|
|
15
|
+
data-action="click->better-ui--dialog--dialog#backdropClick"
|
|
16
|
+
class="fixed inset-0 bg-black/50 transition-opacity duration-200 <%= open ? 'opacity-100' : 'opacity-0' %>">
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<%# Centering wrapper %>
|
|
20
|
+
<div class="fixed inset-0 overflow-y-auto">
|
|
21
|
+
<div class="flex min-h-full items-center justify-center p-4 text-center sm:p-0"
|
|
22
|
+
data-action="click->better-ui--dialog--dialog#backdropClick">
|
|
23
|
+
<%# Panel (size-only wrapper) %>
|
|
24
|
+
<div data-better-ui--dialog--dialog-target="panel"
|
|
25
|
+
class="<%= panel_classes %>"
|
|
26
|
+
role="document">
|
|
27
|
+
|
|
28
|
+
<% if show_close_button %>
|
|
29
|
+
<button type="button"
|
|
30
|
+
class="absolute right-4 top-4 text-grayscale-400 hover:text-grayscale-500 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 rounded-md p-1 z-10"
|
|
31
|
+
data-action="click->better-ui--dialog--dialog#close"
|
|
32
|
+
aria-label="Close">
|
|
33
|
+
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
34
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
35
|
+
</svg>
|
|
36
|
+
</button>
|
|
37
|
+
<% end %>
|
|
38
|
+
|
|
39
|
+
<%= content %>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
module Dialog
|
|
5
|
+
class DialogComponent < ApplicationComponent
|
|
6
|
+
renders_one :trigger
|
|
7
|
+
|
|
8
|
+
SIZES = {
|
|
9
|
+
sm: "sm:max-w-sm",
|
|
10
|
+
md: "sm:max-w-md",
|
|
11
|
+
lg: "sm:max-w-lg",
|
|
12
|
+
xl: "sm:max-w-xl",
|
|
13
|
+
xxl: "sm:max-w-2xl",
|
|
14
|
+
full: "sm:max-w-full sm:mx-4"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def initialize(
|
|
18
|
+
size: :md,
|
|
19
|
+
close_on_backdrop: true,
|
|
20
|
+
close_on_escape: true,
|
|
21
|
+
open: false,
|
|
22
|
+
show_close_button: true,
|
|
23
|
+
container_classes: nil,
|
|
24
|
+
**options
|
|
25
|
+
)
|
|
26
|
+
@size = validate_size(size)
|
|
27
|
+
@close_on_backdrop = close_on_backdrop
|
|
28
|
+
@close_on_escape = close_on_escape
|
|
29
|
+
@open = open
|
|
30
|
+
@show_close_button = show_close_button
|
|
31
|
+
@container_classes = container_classes
|
|
32
|
+
@options = options
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
attr_reader :size, :close_on_backdrop, :close_on_escape, :open,
|
|
38
|
+
:show_close_button, :container_classes, :options
|
|
39
|
+
|
|
40
|
+
def component_id
|
|
41
|
+
@options[:id] || "dialog-#{object_id}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def controller_data
|
|
45
|
+
{
|
|
46
|
+
controller: "better-ui--dialog--dialog",
|
|
47
|
+
"better-ui--dialog--dialog-open-value": @open,
|
|
48
|
+
"better-ui--dialog--dialog-close-on-backdrop-value": @close_on_backdrop,
|
|
49
|
+
"better-ui--dialog--dialog-close-on-escape-value": @close_on_escape
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def component_attributes
|
|
54
|
+
{
|
|
55
|
+
id: component_id,
|
|
56
|
+
data: controller_data,
|
|
57
|
+
**@options.except(:id)
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def panel_classes
|
|
62
|
+
css_classes(
|
|
63
|
+
"relative w-full text-left",
|
|
64
|
+
"transition-all duration-200",
|
|
65
|
+
"opacity-0 scale-95 translate-y-4 sm:translate-y-0 sm:scale-95",
|
|
66
|
+
SIZES[@size],
|
|
67
|
+
@container_classes
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_size(size)
|
|
72
|
+
size = size.to_s.strip.to_sym if size.respond_to?(:to_s)
|
|
73
|
+
size = :md if size.blank?
|
|
74
|
+
unless SIZES.key?(size)
|
|
75
|
+
raise ArgumentError, "Invalid size: #{size}. Must be one of: #{SIZES.keys.join(", ")}"
|
|
76
|
+
end
|
|
77
|
+
size
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% if horizontal? && has_label? %>
|
|
2
|
+
<div class="<%= wrapper_classes %>" role="separator" <%= tag.attributes(html_attributes) %>>
|
|
3
|
+
<div class="<%= line_classes(:first) %>"></div>
|
|
4
|
+
<span class="<%= label_text_classes %>"><%= @label %></span>
|
|
5
|
+
<div class="<%= line_classes(:second) %>"></div>
|
|
6
|
+
</div>
|
|
7
|
+
<% elsif horizontal? %>
|
|
8
|
+
<hr class="<%= component_classes %>" <%= tag.attributes(html_attributes) %>>
|
|
9
|
+
<% else %>
|
|
10
|
+
<div class="<%= component_classes %>" role="separator" <%= tag.attributes(html_attributes) %>></div>
|
|
11
|
+
<% end %>
|