bs5 0.0.23 → 0.0.28

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/bs5/alert_component.html.erb +1 -1
  3. data/app/components/bs5/alert_component.rb +1 -0
  4. data/app/components/bs5/button_tag_component.rb +10 -1
  5. data/app/components/bs5/carousel/caption_component.html.erb +3 -0
  6. data/app/components/bs5/carousel/caption_component.rb +8 -0
  7. data/app/components/bs5/carousel/item_component.html.erb +4 -0
  8. data/app/components/bs5/carousel/item_component.rb +74 -0
  9. data/app/components/bs5/carousel_component.html.erb +30 -0
  10. data/app/components/bs5/carousel_component.rb +60 -0
  11. data/app/components/bs5/close_button_component.rb +14 -6
  12. data/app/components/bs5/dropdown/item_component.html.erb +1 -0
  13. data/app/components/bs5/dropdown/item_component.rb +39 -0
  14. data/app/components/bs5/dropdown_component.html.erb +22 -0
  15. data/app/components/bs5/dropdown_component.rb +154 -0
  16. data/app/components/bs5/modal/body_component.html.erb +3 -0
  17. data/app/components/bs5/modal/body_component.rb +8 -0
  18. data/app/components/bs5/modal/controller_component.html.erb +1 -0
  19. data/app/components/bs5/modal/controller_component.rb +40 -0
  20. data/app/components/bs5/modal/footer_component.html.erb +4 -0
  21. data/app/components/bs5/modal/footer_component.rb +8 -0
  22. data/app/components/bs5/modal/header_component.html.erb +4 -0
  23. data/app/components/bs5/modal/header_component.rb +18 -0
  24. data/app/components/bs5/modal_component.html.erb +11 -0
  25. data/app/components/bs5/modal_component.rb +80 -0
  26. data/app/components/bs5/toast/body_component.html.erb +3 -0
  27. data/app/components/bs5/toast/body_component.rb +8 -0
  28. data/app/components/bs5/toast/header_component.html.erb +4 -0
  29. data/app/components/bs5/toast/header_component.rb +9 -0
  30. data/app/components/bs5/toast_component.html.erb +8 -0
  31. data/app/components/bs5/toast_component.rb +72 -0
  32. data/app/components/bs5/toast_container_component.html.erb +3 -0
  33. data/app/components/bs5/toast_container_component.rb +19 -0
  34. data/app/helpers/bs5/components_helper.rb +3 -2
  35. data/app/views/bs5/examples/alert/color/snippet.html.erb +8 -24
  36. data/app/views/bs5/examples/alert/default/snippet.html.erb +1 -3
  37. data/app/views/bs5/examples/carousel/_dark_variant.html.erb +2 -0
  38. data/app/views/bs5/examples/carousel/_examples.html.erb +13 -0
  39. data/app/views/bs5/examples/carousel/dark_variant/snippet1.html.erb +25 -0
  40. data/app/views/bs5/examples/carousel/examples/snippet1.html.erb +13 -0
  41. data/app/views/bs5/examples/carousel/examples/snippet2.html.erb +13 -0
  42. data/app/views/bs5/examples/carousel/examples/snippet3.html.erb +13 -0
  43. data/app/views/bs5/examples/carousel/examples/snippet4.html.erb +25 -0
  44. data/app/views/bs5/examples/carousel/examples/snippet5.html.erb +13 -0
  45. data/app/views/bs5/examples/carousel/examples/snippet6.html.erb +13 -0
  46. data/app/views/bs5/examples/dropdowns/dark/_example.html.erb +2 -0
  47. data/app/views/bs5/examples/dropdowns/dark/snippet.html.erb +7 -0
  48. data/app/views/bs5/examples/dropdowns/directions/_example.html.erb +7 -0
  49. data/app/views/bs5/examples/dropdowns/directions/snippet1.html.erb +17 -0
  50. data/app/views/bs5/examples/dropdowns/directions/snippet2.html.erb +17 -0
  51. data/app/views/bs5/examples/dropdowns/directions/snippet3.html.erb +17 -0
  52. data/app/views/bs5/examples/dropdowns/menu_alignment/_example.html.erb +5 -0
  53. data/app/views/bs5/examples/dropdowns/menu_alignment/snippet1.html.erb +5 -0
  54. data/app/views/bs5/examples/dropdowns/menu_alignment/snippet2.html.erb +7 -0
  55. data/app/views/bs5/examples/dropdowns/menu_alignment/snippet3.html.erb +7 -0
  56. data/app/views/bs5/examples/dropdowns/menu_content/_example.html.erb +9 -0
  57. data/app/views/bs5/examples/dropdowns/menu_content/snippet1.html.erb +5 -0
  58. data/app/views/bs5/examples/dropdowns/menu_content/snippet2.html.erb +7 -0
  59. data/app/views/bs5/examples/dropdowns/menu_content/snippet3.html.erb +10 -0
  60. data/app/views/bs5/examples/dropdowns/menu_content/snippet4.html.erb +24 -0
  61. data/app/views/bs5/examples/dropdowns/menu_items/_example.html.erb +7 -0
  62. data/app/views/bs5/examples/dropdowns/menu_items/snippet1.html.erb +5 -0
  63. data/app/views/bs5/examples/dropdowns/menu_items/snippet2.html.erb +6 -0
  64. data/app/views/bs5/examples/dropdowns/menu_items/snippet3.html.erb +5 -0
  65. data/app/views/bs5/examples/dropdowns/menu_items/snippet4.html.erb +5 -0
  66. data/app/views/bs5/examples/dropdowns/single/_example.html.erb +4 -0
  67. data/app/views/bs5/examples/dropdowns/single/snippet1.html.erb +5 -0
  68. data/app/views/bs5/examples/dropdowns/single/snippet2.html.erb +47 -0
  69. data/app/views/bs5/examples/dropdowns/single/snippet3.html.erb +47 -0
  70. data/app/views/bs5/examples/dropdowns/sizing/_example.html.erb +3 -0
  71. data/app/views/bs5/examples/dropdowns/sizing/snippet1.html.erb +17 -0
  72. data/app/views/bs5/examples/dropdowns/sizing/snippet2.html.erb +17 -0
  73. data/app/views/bs5/examples/dropdowns/split/_example.html.erb +3 -0
  74. data/app/views/bs5/examples/dropdowns/split/snippet1.html.erb +35 -0
  75. data/app/views/bs5/examples/dropdowns/split/snippet2.html.erb +47 -0
  76. data/app/views/bs5/examples/list_group/active/snippet.html.erb +5 -5
  77. data/app/views/bs5/examples/list_group/default/snippet.html.erb +5 -5
  78. data/app/views/bs5/examples/list_group/disabled/snippet.html.erb +5 -5
  79. data/app/views/bs5/examples/list_group/flush/snippet.html.erb +5 -5
  80. data/app/views/bs5/examples/list_group/horizontal/snippet.html.erb +18 -18
  81. data/app/views/bs5/examples/list_group/style/default.html.erb +8 -8
  82. data/app/views/bs5/examples/modal/_examples.html.erb +9 -0
  83. data/app/views/bs5/examples/modal/_fullscreen.html.erb +2 -0
  84. data/app/views/bs5/examples/modal/_optional_sizes.html.erb +2 -0
  85. data/app/views/bs5/examples/modal/examples/snippet1.html.erb +12 -0
  86. data/app/views/bs5/examples/modal/examples/snippet2.html.erb +12 -0
  87. data/app/views/bs5/examples/modal/examples/snippet3.html.erb +14 -0
  88. data/app/views/bs5/examples/modal/examples/snippet4.html.erb +12 -0
  89. data/app/views/bs5/examples/modal/fullscreen/snippet1.html.erb +55 -0
  90. data/app/views/bs5/examples/modal/optional_sizes/snippet1.html.erb +23 -0
  91. data/app/views/bs5/examples/toasts/color_schemes/_example.html.erb +2 -0
  92. data/app/views/bs5/examples/toasts/color_schemes/snippet.html.erb +33 -0
  93. data/app/views/bs5/examples/toasts/custom_content/_example.html.erb +3 -0
  94. data/app/views/bs5/examples/toasts/custom_content/snippet1.html.erb +3 -0
  95. data/app/views/bs5/examples/toasts/custom_content/snippet2.html.erb +9 -0
  96. data/app/views/bs5/examples/toasts/default/_example.html.erb +2 -0
  97. data/app/views/bs5/examples/toasts/default/snippet.html.erb +17 -0
  98. data/app/views/bs5/examples/toasts/js_options/_example.html.erb +2 -0
  99. data/app/views/bs5/examples/toasts/js_options/snippet.html.erb +23 -0
  100. data/app/views/bs5/examples/toasts/placement/_example.html.erb +3 -0
  101. data/app/views/bs5/examples/toasts/placement/snippet1.html.erb +44 -0
  102. data/app/views/bs5/examples/toasts/placement/snippet2.html.erb +24 -0
  103. data/app/views/bs5/examples/toasts/stacking/_example.html.erb +2 -0
  104. data/app/views/bs5/examples/toasts/stacking/snippet.html.erb +37 -0
  105. data/app/views/bs5/pages/carousel.html.erb +3 -0
  106. data/app/views/bs5/pages/dropdowns.html.erb +10 -0
  107. data/app/views/bs5/pages/modal.html.erb +4 -0
  108. data/app/views/bs5/pages/toasts.html.erb +7 -0
  109. data/app/views/layouts/bs5/pages.html.erb +4 -0
  110. data/lib/bs5/version.rb +1 -1
  111. data/lib/generators/bs5/install/templates/bs5.js +24 -13
  112. data/lib/tasks/rubocop.rake +2 -0
  113. metadata +96 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fde2cc4be44c7ef1b396e7761904765ee31f1801acb7a88b1f4507cf302994c2
4
- data.tar.gz: d69a795e889ece4139479843c7e2e5f6ffa48df347f0463529513060c1401214
3
+ metadata.gz: 215200d1f6820e7e163cbd6b214f9952645e225f535c45a34254ef53f445480a
4
+ data.tar.gz: cc2f9daf0107719ee613670620ddb42e42a08b995bb32a7348003f9b74761584
5
5
  SHA512:
6
- metadata.gz: 4474fe20875677d9e8f45ca929d8e3ee95d6919a65065d472d2e12d9b74b765c6f491398b7691b8bf85b8a35d2b4cdc807839648f007a4836c47768ab865ac74
7
- data.tar.gz: d70751a40bda629d0ba59324cab991b94dca962248ec22625edd36344750476830ed655a4fd21c3b3e3a7b133609217c33267c96df3af39125a3600f3be5539b
6
+ metadata.gz: 8361ad156b1c5aa5a2e8d2e85482a891792fe28693aff0ab0de36a7acc258d1818934512a7b9c76d4be17de2e96f0c6207affa1f5765add53cff6bc83e999b74
7
+ data.tar.gz: 978c438199e216476b87a1eef92dcab0b9b8d828daca289c4eb7cc8b97fa802f75ef4620c06541870caeca578845303eb874fde87988036bea462918e5d0fc97
@@ -1,6 +1,6 @@
1
1
  <div class="<%= component_class %>" role="alert">
2
2
  <%= content %>
3
3
  <%- if is_dismissable %>
4
- <%= render Bs5::CloseButtonComponent.new(data: { 'bs-dismiss': :alert }) %>
4
+ <%= bs5_close_button(dismiss: :alert) %>
5
5
  <%- end %>
6
6
  </div>
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Bs5
4
4
  class AlertComponent < ViewComponent::Base
5
+ include ComponentsHelper
5
6
  STYLES = %i[primary secondary success danger warning info light dark].freeze
6
7
 
7
8
  attr_reader :color, :is_dismissable
@@ -47,6 +47,7 @@ module Bs5
47
47
  extract_color
48
48
  extract_outline
49
49
  extract_size
50
+ extract_dismiss
50
51
  end
51
52
 
52
53
  def extract_color
@@ -61,6 +62,10 @@ module Bs5
61
62
  @size = @options.delete(:size)
62
63
  end
63
64
 
65
+ def extract_dismiss
66
+ @dismiss = @options.delete(:dismiss)
67
+ end
68
+
64
69
  def merge_default_options
65
70
  @options.deep_merge!(default_options) do |_key, this_val, other_val|
66
71
  [this_val, other_val].join(' ').strip
@@ -68,7 +73,11 @@ module Bs5
68
73
  end
69
74
 
70
75
  def default_options
71
- { class: button_class }
76
+ default_options = { class: button_class }
77
+
78
+ default_options[:data] = { 'bs-dismiss': @dismiss } if @dismiss
79
+
80
+ default_options
72
81
  end
73
82
 
74
83
  def button_class
@@ -0,0 +1,3 @@
1
+ <div class="carousel-caption d-none d-md-block">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Carousel
5
+ class CaptionComponent < ViewComponent::Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ <%= tag.div(component_attributes) do %>
2
+ <%= content %>
3
+ <%= caption %>
4
+ <% end %>
@@ -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
@@ -2,12 +2,19 @@
2
2
 
3
3
  module Bs5
4
4
  class CloseButtonComponent < ViewComponent::Base
5
- attr_reader :data
5
+ def initialize(options = {})
6
+ @options = options.symbolize_keys
6
7
 
7
- def initialize(disabled: false, white: false, data: nil)
8
- @disabled = disabled
9
- @white = white
10
- @data = data
8
+ @disabled = options.delete(:disabled)
9
+ @white = options.delete(:white)
10
+ @dismiss = options.delete(:dismiss)
11
+ @data = options.fetch(:data, {})
12
+ end
13
+
14
+ def data
15
+ @data['bs-dismiss'] = @dismiss if @dismiss
16
+
17
+ @data
11
18
  end
12
19
 
13
20
  private
@@ -21,7 +28,8 @@ module Bs5
21
28
  end
22
29
 
23
30
  def component_class
24
- class_names = ['btn-close']
31
+ class_names = Array(@options[:class])
32
+ class_names << 'btn-close'
25
33
  class_names << %w[btn-close-white] if white?
26
34
  class_names.join(' ')
27
35
  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