bs5 0.0.25 → 0.0.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/components/bs5/carousel/caption_component.html.erb +3 -0
- data/app/components/bs5/carousel/caption_component.rb +8 -0
- data/app/components/bs5/carousel/item_component.html.erb +4 -0
- data/app/components/bs5/carousel/item_component.rb +74 -0
- data/app/components/bs5/carousel_component.html.erb +30 -0
- data/app/components/bs5/carousel_component.rb +60 -0
- data/app/components/bs5/dropdown/item_component.html.erb +1 -0
- data/app/components/bs5/dropdown/item_component.rb +39 -0
- data/app/components/bs5/dropdown_component.html.erb +22 -0
- data/app/components/bs5/dropdown_component.rb +154 -0
- data/app/components/bs5/modal/body_component.html.erb +3 -0
- data/app/components/bs5/modal/body_component.rb +8 -0
- data/app/components/bs5/modal/controller_component.html.erb +1 -0
- data/app/components/bs5/modal/controller_component.rb +40 -0
- data/app/components/bs5/modal/footer_component.html.erb +4 -0
- data/app/components/bs5/modal/footer_component.rb +8 -0
- data/app/components/bs5/modal/header_component.html.erb +4 -0
- data/app/components/bs5/modal/header_component.rb +18 -0
- data/app/components/bs5/modal_component.html.erb +11 -0
- data/app/components/bs5/modal_component.rb +80 -0
- data/app/components/bs5/nav/item_component.html.erb +1 -0
- data/app/components/bs5/nav/item_component.rb +80 -0
- data/app/components/bs5/nav_component.html.erb +7 -0
- data/app/components/bs5/nav_component.rb +47 -0
- data/app/components/bs5/progress/bar_component.html.erb +1 -0
- data/app/components/bs5/progress/bar_component.rb +60 -0
- data/app/components/bs5/progress_component.html.erb +9 -0
- data/app/components/bs5/progress_component.rb +15 -0
- data/app/components/bs5/tabs/item_component.html.erb +3 -0
- data/app/components/bs5/tabs/item_component.rb +48 -0
- data/app/components/bs5/tabs/link_component.html.erb +1 -0
- data/app/components/bs5/tabs/link_component.rb +27 -0
- data/app/components/bs5/tabs_component.html.erb +16 -0
- data/app/components/bs5/tabs_component.rb +63 -0
- data/app/helpers/bs5/components_helper.rb +6 -3
- data/app/views/bs5/examples/alert/color/snippet.html.erb +8 -24
- data/app/views/bs5/examples/alert/default/snippet.html.erb +1 -3
- data/app/views/bs5/examples/carousel/_dark_variant.html.erb +2 -0
- data/app/views/bs5/examples/carousel/_examples.html.erb +13 -0
- data/app/views/bs5/examples/carousel/dark_variant/snippet1.html.erb +25 -0
- data/app/views/bs5/examples/carousel/examples/snippet1.html.erb +13 -0
- data/app/views/bs5/examples/carousel/examples/snippet2.html.erb +13 -0
- data/app/views/bs5/examples/carousel/examples/snippet3.html.erb +13 -0
- data/app/views/bs5/examples/carousel/examples/snippet4.html.erb +25 -0
- data/app/views/bs5/examples/carousel/examples/snippet5.html.erb +13 -0
- data/app/views/bs5/examples/carousel/examples/snippet6.html.erb +13 -0
- data/app/views/bs5/examples/dropdowns/dark/_example.html.erb +2 -0
- data/app/views/bs5/examples/dropdowns/dark/snippet.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/directions/_example.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/directions/snippet1.html.erb +17 -0
- data/app/views/bs5/examples/dropdowns/directions/snippet2.html.erb +17 -0
- data/app/views/bs5/examples/dropdowns/directions/snippet3.html.erb +17 -0
- data/app/views/bs5/examples/dropdowns/menu_alignment/_example.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/menu_alignment/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/menu_alignment/snippet2.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/menu_alignment/snippet3.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/menu_content/_example.html.erb +9 -0
- data/app/views/bs5/examples/dropdowns/menu_content/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/menu_content/snippet2.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/menu_content/snippet3.html.erb +10 -0
- data/app/views/bs5/examples/dropdowns/menu_content/snippet4.html.erb +24 -0
- data/app/views/bs5/examples/dropdowns/menu_items/_example.html.erb +7 -0
- data/app/views/bs5/examples/dropdowns/menu_items/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/menu_items/snippet2.html.erb +6 -0
- data/app/views/bs5/examples/dropdowns/menu_items/snippet3.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/menu_items/snippet4.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/single/_example.html.erb +4 -0
- data/app/views/bs5/examples/dropdowns/single/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/dropdowns/single/snippet2.html.erb +47 -0
- data/app/views/bs5/examples/dropdowns/single/snippet3.html.erb +47 -0
- data/app/views/bs5/examples/dropdowns/sizing/_example.html.erb +3 -0
- data/app/views/bs5/examples/dropdowns/sizing/snippet1.html.erb +17 -0
- data/app/views/bs5/examples/dropdowns/sizing/snippet2.html.erb +17 -0
- data/app/views/bs5/examples/dropdowns/split/_example.html.erb +3 -0
- data/app/views/bs5/examples/dropdowns/split/snippet1.html.erb +35 -0
- data/app/views/bs5/examples/dropdowns/split/snippet2.html.erb +47 -0
- data/app/views/bs5/examples/list_group/active/snippet.html.erb +5 -5
- data/app/views/bs5/examples/list_group/default/snippet.html.erb +5 -5
- data/app/views/bs5/examples/list_group/disabled/snippet.html.erb +5 -5
- data/app/views/bs5/examples/list_group/flush/snippet.html.erb +5 -5
- data/app/views/bs5/examples/list_group/horizontal/snippet.html.erb +18 -18
- data/app/views/bs5/examples/list_group/style/default.html.erb +8 -8
- data/app/views/bs5/examples/modal/_examples.html.erb +9 -0
- data/app/views/bs5/examples/modal/_fullscreen.html.erb +2 -0
- data/app/views/bs5/examples/modal/_optional_sizes.html.erb +2 -0
- data/app/views/bs5/examples/modal/examples/snippet1.html.erb +12 -0
- data/app/views/bs5/examples/modal/examples/snippet2.html.erb +12 -0
- data/app/views/bs5/examples/modal/examples/snippet3.html.erb +14 -0
- data/app/views/bs5/examples/modal/examples/snippet4.html.erb +12 -0
- data/app/views/bs5/examples/modal/fullscreen/snippet1.html.erb +55 -0
- data/app/views/bs5/examples/modal/optional_sizes/snippet1.html.erb +23 -0
- data/app/views/bs5/examples/navs_and_tabs/_base_nav.html.erb +2 -0
- data/app/views/bs5/examples/navs_and_tabs/_dropdowns.html.erb +5 -0
- data/app/views/bs5/examples/navs_and_tabs/_flex_utils.html.erb +2 -0
- data/app/views/bs5/examples/navs_and_tabs/_styles.html.erb +15 -0
- data/app/views/bs5/examples/navs_and_tabs/_tabs.html.erb +4 -0
- data/app/views/bs5/examples/navs_and_tabs/base_nav/snippet1.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/dropdowns/snippet1.html.erb +14 -0
- data/app/views/bs5/examples/navs_and_tabs/dropdowns/snippet2.html.erb +14 -0
- data/app/views/bs5/examples/navs_and_tabs/flex_utils/snippet1.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet1.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet2.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet3.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet4.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet5.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet6.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet7.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet8.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/styles/snippet9.html.erb +6 -0
- data/app/views/bs5/examples/navs_and_tabs/tabs/snippet1.html.erb +11 -0
- data/app/views/bs5/examples/navs_and_tabs/tabs/snippet2.html.erb +11 -0
- data/app/views/bs5/examples/navs_and_tabs/tabs/snippet3.html.erb +11 -0
- data/app/views/bs5/examples/progress/_animated.html.erb +2 -0
- data/app/views/bs5/examples/progress/_backgrounds.html.erb +2 -0
- data/app/views/bs5/examples/progress/_examples.html.erb +2 -0
- data/app/views/bs5/examples/progress/_labels.html.erb +2 -0
- data/app/views/bs5/examples/progress/_multiple_bars.html.erb +2 -0
- data/app/views/bs5/examples/progress/_striped.html.erb +2 -0
- data/app/views/bs5/examples/progress/animated/snippet1.html.erb +13 -0
- data/app/views/bs5/examples/progress/backgrounds/snippet1.html.erb +13 -0
- data/app/views/bs5/examples/progress/examples/snippet1.html.erb +17 -0
- data/app/views/bs5/examples/progress/labels/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/progress/multiple_bars/snippet1.html.erb +5 -0
- data/app/views/bs5/examples/progress/striped/snippet1.html.erb +13 -0
- data/app/views/bs5/examples/toasts/default/snippet.html.erb +1 -1
- data/app/views/bs5/pages/carousel.html.erb +3 -0
- data/app/views/bs5/pages/dropdowns.html.erb +10 -0
- data/app/views/bs5/pages/modal.html.erb +4 -0
- data/app/views/bs5/pages/navs_and_tabs.html.erb +6 -0
- data/app/views/bs5/pages/progress.html.erb +7 -0
- data/app/views/layouts/bs5/pages.html.erb +5 -0
- data/lib/bs5/version.rb +1 -1
- metadata +122 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3cddc2280bdce3dfc49c8c980c0176cbdf80f0f5ad5ecf462482d3514818a7a9
|
4
|
+
data.tar.gz: 3b9c82cf6f9eeabb0752a9ab8f5d2c7019b339cc86dcd389d844d4eccb04c65d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c55b185ac6ee246cb9f2b0e853f13238b2f8c90962e2472c69a89d599d9cf003b3a4224718b3dd2d1991e106f7344c214ec9a68eb799101892b115c703fb41e8
|
7
|
+
data.tar.gz: b7bd776ed2d0701f63672cb1a4242c5d7e4a9f4f14ff597b9ef79bf9eb88e2f44098b6ce43c573ae3cd8c3601890a3aeed8a4e9c5960c8c5706ec2fc0f9c2378
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs5
|
4
|
+
module Carousel
|
5
|
+
class ItemComponent < ViewComponent::Base
|
6
|
+
include ViewComponent::SlotableV2
|
7
|
+
using HashRefinement
|
8
|
+
|
9
|
+
COMPONENT_OPTIONS = %i[interval].freeze
|
10
|
+
|
11
|
+
renders_one :caption, Bs5::Carousel::CaptionComponent
|
12
|
+
|
13
|
+
attr_accessor :active
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@options = options.symbolize_keys
|
17
|
+
extract_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def active?
|
21
|
+
active
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def extract_options
|
27
|
+
extract_component_options
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_component_options
|
31
|
+
@component_options = @options.extract!(*COMPONENT_OPTIONS)
|
32
|
+
end
|
33
|
+
|
34
|
+
def component_attributes
|
35
|
+
{ class: component_classes,
|
36
|
+
data: @component_options.prefix_keys_with_bs }
|
37
|
+
end
|
38
|
+
|
39
|
+
def component_classes
|
40
|
+
class_names = %w[carousel-item]
|
41
|
+
class_names << 'active' if active?
|
42
|
+
|
43
|
+
class_names
|
44
|
+
end
|
45
|
+
|
46
|
+
def content
|
47
|
+
set_element_class_names
|
48
|
+
element.to_html.html_safe # rubocop:disable Rails/OutputSafety
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_element_class_names
|
52
|
+
class_names = Array(element[:class])
|
53
|
+
class_names << element_classes
|
54
|
+
element[:class] = class_names.join(' ')
|
55
|
+
end
|
56
|
+
|
57
|
+
def element_classes
|
58
|
+
%w[d-block w-100]
|
59
|
+
end
|
60
|
+
|
61
|
+
def element
|
62
|
+
@element ||= begin
|
63
|
+
if (elements = Nokogiri::HTML::DocumentFragment.parse(@content).elements).one?
|
64
|
+
elements.first
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def element?
|
70
|
+
!!element
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<%= tag.div(component_attributes) do %>
|
2
|
+
<% items.each_with_index do |item, index| %>
|
3
|
+
<% item.active = index.zero? %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<% if indicators? %>
|
7
|
+
<ol class="carousel-indicators">
|
8
|
+
<% items.each_with_index do |item, index| %>
|
9
|
+
<li data-bs-target="#<%= id %>" data-bs-slide-to="<%= index %>" class="<%= item.active? ? 'active' : '' %>"></li>
|
10
|
+
<% end %>
|
11
|
+
</ol>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="carousel-inner">
|
15
|
+
<% items.each_with_index do |item, index| %>
|
16
|
+
<%= item %>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<% if controls? %>
|
21
|
+
<a class="carousel-control-prev" href="#<%= id %>" role="button" data-bs-slide="prev">
|
22
|
+
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
23
|
+
<span class="visually-hidden">Previous</span>
|
24
|
+
</a>
|
25
|
+
<a class="carousel-control-next" href="#<%= id %>" role="button" data-bs-slide="next">
|
26
|
+
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
27
|
+
<span class="visually-hidden">Next</span>
|
28
|
+
</a>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs5
|
4
|
+
class CarouselComponent < ViewComponent::Base
|
5
|
+
include ComponentsHelper
|
6
|
+
include ViewComponent::SlotableV2
|
7
|
+
using HashRefinement
|
8
|
+
|
9
|
+
CAROUSEL_OPTIONS = %i[interval keyboard pause slide wrap touch].freeze
|
10
|
+
|
11
|
+
renders_many :items, Bs5::Carousel::ItemComponent
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@options = options.symbolize_keys
|
15
|
+
extract_options
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def extract_options
|
21
|
+
@controls = @options.delete(:controls)
|
22
|
+
@indicators = @options.delete(:indicators)
|
23
|
+
@crossfade = @options.delete(:crossfade)
|
24
|
+
@dark = @options.delete(:dark)
|
25
|
+
|
26
|
+
extract_carousel_options
|
27
|
+
end
|
28
|
+
|
29
|
+
def extract_carousel_options
|
30
|
+
@carousel_options = @options.extract!(*CAROUSEL_OPTIONS)
|
31
|
+
end
|
32
|
+
|
33
|
+
def id
|
34
|
+
"carousel-#{object_id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def items_count
|
38
|
+
items.size
|
39
|
+
end
|
40
|
+
|
41
|
+
def component_attributes
|
42
|
+
{ class: component_class,
|
43
|
+
id: id,
|
44
|
+
data: @carousel_options.merge(ride: :carousel).prefix_keys_with_bs }
|
45
|
+
end
|
46
|
+
|
47
|
+
def component_class
|
48
|
+
class_names = %w[carousel slide]
|
49
|
+
class_names << %w[carousel-fade] if crossfade?
|
50
|
+
class_names << %w[carousel-dark] if dark?
|
51
|
+
class_names.join(' ')
|
52
|
+
end
|
53
|
+
|
54
|
+
%i[controls indicators crossfade dark].each do |name|
|
55
|
+
define_method("#{name}?") do
|
56
|
+
!instance_variable_get("@#{name}").nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<li><%= content || tag.hr(class: 'dropdown-divider') %></li>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs5
|
4
|
+
module Dropdown
|
5
|
+
class ItemComponent < ViewComponent::Base
|
6
|
+
private
|
7
|
+
|
8
|
+
def content
|
9
|
+
return nil if @content.blank?
|
10
|
+
|
11
|
+
if actionable_element?
|
12
|
+
set_actionable_element_class_names
|
13
|
+
actionable_element.to_html.html_safe # rubocop:disable Rails/OutputSafety
|
14
|
+
else
|
15
|
+
@content
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_actionable_element_class_names
|
20
|
+
class_names = Array(actionable_element[:class])
|
21
|
+
class_names << 'dropdown-item'
|
22
|
+
actionable_element[:class] = class_names.join(' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
def actionable_element
|
26
|
+
@actionable_element ||= begin
|
27
|
+
if (elements = Nokogiri::HTML::DocumentFragment.parse(@content).elements).one? &&
|
28
|
+
(element = elements.first).name.in?(%w[a button])
|
29
|
+
element
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def actionable_element?
|
35
|
+
!!actionable_element
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<% if split? %>
|
2
|
+
<% if dropstart? %>
|
3
|
+
<%= bs5_button_group do %>
|
4
|
+
<div class="<%= component_class %>">
|
5
|
+
<%= split_button_toggle %>
|
6
|
+
<%= menu_content %>
|
7
|
+
</div>
|
8
|
+
<%= split_button %>
|
9
|
+
<% end %>
|
10
|
+
<% else %>
|
11
|
+
<div class="<%= component_class %>">
|
12
|
+
<%= split_button %>
|
13
|
+
<%= split_button_toggle %>
|
14
|
+
<%= menu_content %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
<% else %>
|
18
|
+
<div class="<%= component_class %>">
|
19
|
+
<%= single_button %>
|
20
|
+
<%= menu_content %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs5
|
4
|
+
class DropdownComponent < ViewComponent::Base # rubocop:disable Metrics/ClassLength
|
5
|
+
include ViewComponent::SlotableV2
|
6
|
+
include ComponentsHelper
|
7
|
+
using HashRefinement
|
8
|
+
|
9
|
+
CLASS_PREFIX = 'dropdown'
|
10
|
+
CLASS_NAMES = {
|
11
|
+
visually_hidden: 'visually-hidden',
|
12
|
+
toggle_split: "#{CLASS_PREFIX}-toggle-split",
|
13
|
+
toggle: "#{CLASS_PREFIX}-toggle",
|
14
|
+
menu: "#{CLASS_PREFIX}-menu",
|
15
|
+
menu_dark: "#{CLASS_PREFIX}-menu-dark",
|
16
|
+
menu_end: "#{CLASS_PREFIX}-menu-end"
|
17
|
+
}.freeze
|
18
|
+
DIRECTIONS = {
|
19
|
+
up: :dropup,
|
20
|
+
end: :dropend,
|
21
|
+
start: :dropstart
|
22
|
+
}.with_indifferent_access.freeze
|
23
|
+
DROPDOWN_OPTIONS = %i[offset flip boundary reference display].freeze
|
24
|
+
|
25
|
+
renders_many :items, Bs5::Dropdown::ItemComponent
|
26
|
+
attr_reader :title
|
27
|
+
|
28
|
+
def initialize(content_or_options = nil, options = {})
|
29
|
+
if content_or_options.is_a? Hash
|
30
|
+
@options = content_or_options.symbolize_keys
|
31
|
+
else
|
32
|
+
@title = content_or_options
|
33
|
+
@options = options.symbolize_keys
|
34
|
+
end
|
35
|
+
|
36
|
+
extract_options
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def extract_options
|
42
|
+
@split = @options.delete(:split)
|
43
|
+
@dark = @options.delete(:dark)
|
44
|
+
@direction = @options.delete(:direction)
|
45
|
+
@align = @options.delete(:align)
|
46
|
+
|
47
|
+
extract_dropdown_options
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_dropdown_options
|
51
|
+
@dropdown_options = @options.extract!(*DROPDOWN_OPTIONS)
|
52
|
+
end
|
53
|
+
|
54
|
+
def split_button_toggle
|
55
|
+
bs5_button_tag(split_button_toggle_options) do
|
56
|
+
tag.span('Toggle Dropdown', class: CLASS_NAMES[:visually_hidden])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def split_button
|
61
|
+
bs5_button_tag title, split_button_options
|
62
|
+
end
|
63
|
+
|
64
|
+
def single_button
|
65
|
+
bs5_button_tag title, single_button_options
|
66
|
+
end
|
67
|
+
|
68
|
+
def menu_content
|
69
|
+
if items.any?
|
70
|
+
tag.ul(class: dropdown_menu_classes) { items.map(&method(:concat)) }
|
71
|
+
else
|
72
|
+
tag.div(content, class: dropdown_menu_classes)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def single_button_options
|
77
|
+
@options.merge(default_options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def component_class
|
81
|
+
class_names = split? ? ['btn-group'] : [CLASS_PREFIX]
|
82
|
+
class_names << DIRECTIONS[@direction] if direction?
|
83
|
+
|
84
|
+
class_names.join(' ')
|
85
|
+
end
|
86
|
+
|
87
|
+
def split_button_options
|
88
|
+
@options.merge(default_button_options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def split_button_toggle_options
|
92
|
+
single_button_options.dup.tap do |h|
|
93
|
+
h[:class] += " #{CLASS_NAMES[:toggle_split]}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
%i[split dark direction].each do |name|
|
98
|
+
define_method("#{name}?") do
|
99
|
+
!instance_variable_get("@#{name}").nil?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dropstart?
|
104
|
+
@direction == :start
|
105
|
+
end
|
106
|
+
|
107
|
+
def default_button_options
|
108
|
+
{ type: :button }
|
109
|
+
end
|
110
|
+
|
111
|
+
def default_options
|
112
|
+
default_button_options.merge({
|
113
|
+
data: default_data_options.merge(@dropdown_options).prefix_keys_with_bs,
|
114
|
+
aria: { expanded: false },
|
115
|
+
class: CLASS_NAMES[:toggle]
|
116
|
+
})
|
117
|
+
end
|
118
|
+
|
119
|
+
def default_data_options
|
120
|
+
{ toggle: :dropdown }.tap do |h|
|
121
|
+
h[:display] = 'static' if responsive_align?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def dropdown_menu_classes
|
126
|
+
class_names = [CLASS_NAMES[:menu]]
|
127
|
+
class_names << CLASS_NAMES[:menu_dark] if dark?
|
128
|
+
class_names << align_classes
|
129
|
+
|
130
|
+
class_names.compact.join(' ')
|
131
|
+
end
|
132
|
+
|
133
|
+
def align_classes
|
134
|
+
case @align
|
135
|
+
when Symbol
|
136
|
+
CLASS_NAMES[:menu_end]
|
137
|
+
when Hash
|
138
|
+
responsive_align_classes
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def responsive_align_classes
|
143
|
+
k, v = @align.first
|
144
|
+
class_names = ["#{CLASS_PREFIX}-menu-#{v}-#{k}"]
|
145
|
+
class_names << CLASS_NAMES[:menu_end] if @align.with_indifferent_access.key?(:start)
|
146
|
+
|
147
|
+
class_names
|
148
|
+
end
|
149
|
+
|
150
|
+
def responsive_align?
|
151
|
+
@align.is_a? Hash
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= content %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs5
|
4
|
+
module Modal
|
5
|
+
class ControllerComponent < ViewComponent::Base
|
6
|
+
def initialize(modal_id:)
|
7
|
+
@modal_id = modal_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def content
|
11
|
+
return nil if @content.blank?
|
12
|
+
|
13
|
+
if actionable_element?
|
14
|
+
set_actionable_element_attributes
|
15
|
+
actionable_element.to_html.html_safe # rubocop:disable Rails/OutputSafety
|
16
|
+
else
|
17
|
+
@content
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_actionable_element_attributes
|
22
|
+
actionable_element['data-bs-toggle'] = 'modal'
|
23
|
+
actionable_element['data-bs-target'] = "##{@modal_id}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def actionable_element
|
27
|
+
@actionable_element ||= begin
|
28
|
+
if (elements = Nokogiri::HTML::DocumentFragment.parse(@content).elements).one? &&
|
29
|
+
(element = elements.first).name.in?(%w[a button])
|
30
|
+
element
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def actionable_element?
|
36
|
+
!!actionable_element
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|