bs5 0.0.23 → 0.0.28

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ <div class="modal-body">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Modal
5
+ class BodyComponent < ViewComponent::Base
6
+ end
7
+ end
8
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ <div class="modal-footer">
2
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
3
+ <%= content %>
4
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Modal
5
+ class FooterComponent < ViewComponent::Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ <div class="modal-header">
2
+ <h5 class="modal-title" id="<%= @label_id %>"><%= content %></h5>
3
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
4
+ </div>
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Modal
5
+ class HeaderComponent < ViewComponent::Base
6
+ attr_reader :title
7
+
8
+ def initialize(title: nil, label_id: nil)
9
+ @title = title
10
+ @label_id = label_id
11
+ end
12
+
13
+ def content
14
+ title || @content
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ <%= controller %>
2
+
3
+ <%= tag.div(modal_attributes) do %>
4
+ <div class="<%= dialog_classes %>">
5
+ <div class="modal-content">
6
+ <%= header %>
7
+ <%= body %>
8
+ <%= footer %>
9
+ </div>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ class ModalComponent < ViewComponent::Base
5
+ include ViewComponent::SlotableV2
6
+ using HashRefinement
7
+
8
+ MODAL_OPTIONS = %i[backdrop keyboard focus].freeze
9
+
10
+ renders_one :controller, lambda { |_modal_id: nil|
11
+ Bs5::Modal::ControllerComponent.new(modal_id: modal_id)
12
+ }
13
+ renders_one :header, lambda { |_label_id: nil|
14
+ Bs5::Modal::HeaderComponent.new(label_id: label_id)
15
+ }
16
+ renders_one :body, Bs5::Modal::BodyComponent
17
+ renders_one :footer, Bs5::Modal::FooterComponent
18
+
19
+ def initialize(options = {})
20
+ @options = options.symbolize_keys
21
+ extract_options
22
+ end
23
+
24
+ private
25
+
26
+ def extract_options
27
+ @scroll = @options.delete(:scroll)
28
+ @center = @options.delete(:center)
29
+ @size = @options.delete(:size)
30
+ @fullscreen = @options.delete(:fullscreen)
31
+
32
+ extract_modal_options
33
+ end
34
+
35
+ def extract_modal_options
36
+ @modal_options = @options.extract!(*MODAL_OPTIONS)
37
+ end
38
+
39
+ def modal_attributes
40
+ { class: 'modal fade',
41
+ id: modal_id,
42
+ tabindex: -1,
43
+ aria: { labelledby: label_id, hidden: true },
44
+ data: @modal_options.prefix_keys_with_bs }
45
+ end
46
+
47
+ def dialog_classes
48
+ class_names = ['modal-dialog']
49
+ class_names << 'modal-dialog-scrollable' if scroll?
50
+ class_names << 'modal-dialog-centered' if center?
51
+ class_names << "modal-#{@size}" if size?
52
+ class_names << fullscreen_class
53
+
54
+ class_names.join(' ')
55
+ end
56
+
57
+ def fullscreen_class
58
+ return unless fullscreen?
59
+
60
+ class_name = %w[modal fullscreen]
61
+ class_name << [@fullscreen, 'down'] if @fullscreen.is_a?(Symbol)
62
+
63
+ class_name.join('-')
64
+ end
65
+
66
+ def modal_id
67
+ "modal-#{object_id}"
68
+ end
69
+
70
+ def label_id
71
+ "modal-label-#{object_id}"
72
+ end
73
+
74
+ %i[scroll center size fullscreen].each do |name|
75
+ define_method("#{name}?") do
76
+ !instance_variable_get("@#{name}").nil?
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ <div class="toast-body">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Toast
5
+ class BodyComponent < ViewComponent::Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ <div class="toast-header">
2
+ <%= content %>
3
+ <%= bs5_close_button(dismiss: :toast) %>
4
+ </div>
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Toast
5
+ class HeaderComponent < ViewComponent::Base
6
+ include ComponentsHelper
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ <%= tag.div(component_attributes) do %>
2
+ <%= header %>
3
+ <%= body %>
4
+
5
+ <%- if close_button? && !header? %>
6
+ <%= bs5_close_button(white: white_text?, class: 'ms-auto me-2', dismiss: :toast) %>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ class ToastComponent < ViewComponent::Base
5
+ include ViewComponent::SlotableV2
6
+ include ComponentsHelper
7
+ using HashRefinement
8
+
9
+ attr_reader :color
10
+
11
+ renders_one :header, Bs5::Toast::HeaderComponent
12
+ renders_one :body, Bs5::Toast::BodyComponent
13
+
14
+ def initialize(options = {})
15
+ @options = options.symbolize_keys
16
+ @color = @options.delete(:color)
17
+ @close_button = @options.fetch(:close_button, true)
18
+ @data_options = @options.extract!(:animation, :autohide, :delay)
19
+ end
20
+
21
+ def header?
22
+ !!header
23
+ end
24
+
25
+ def component_attributes
26
+ default_options = {
27
+ role: :alert,
28
+ aria: { live: 'assertive', atomic: true },
29
+ data: data_options
30
+ }
31
+
32
+ @options[:class] = component_class
33
+
34
+ @options.merge(default_options)
35
+ end
36
+
37
+ def white_text?
38
+ color? && color.in?(%i[primary secondary success danger dark])
39
+ end
40
+
41
+ private
42
+
43
+ def data_options
44
+ @data_options.prefix_keys_with_bs
45
+ end
46
+
47
+ def component_class
48
+ class_names = Array(@options[:class])
49
+ class_names << 'toast'
50
+ class_names << contextual_class
51
+ class_names.compact.join(' ')
52
+ end
53
+
54
+ def contextual_class
55
+ return unless color?
56
+
57
+ class_names = ['border-0']
58
+ class_names << "bg-#{color}"
59
+ class_names << 'text-white' if white_text?
60
+
61
+ class_names
62
+ end
63
+
64
+ def color?
65
+ !!color
66
+ end
67
+
68
+ def close_button?
69
+ @close_button
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ <div class="<%= component_class %>"">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ class ToastContainerComponent < ViewComponent::Base
5
+ def initialize(options = {})
6
+ @options = options.symbolize_keys
7
+ end
8
+
9
+ def component_class
10
+ class_names = Array(@options[:class])
11
+ class_names << 'toast-container'
12
+ class_names.compact.join(' ')
13
+ end
14
+
15
+ def render?
16
+ content.present?
17
+ end
18
+ end
19
+ end
@@ -2,8 +2,9 @@
2
2
 
3
3
  module Bs5
4
4
  module ComponentsHelper
5
- COMPONENTS = %w[accordion alert badge close_button breadcrumb button_group button_tag button_to button_toolbar
6
- list_group spinner].freeze
5
+ COMPONENTS = %w[accordion alert badge breadcrumb button_group button_tag button_to button_toolbar
6
+ carousel close_button
7
+ dropdown list_group modal spinner toast toast_container].freeze
7
8
 
8
9
  COMPONENTS.each do |name|
9
10
  define_method("bs5_#{name}") do |*args, &block|
@@ -1,31 +1,15 @@
1
- <%= bs5_alert(color: :primary) do %>
2
- A simple primary alert—check it out!
3
- <%- end %>
1
+ <%= bs5_alert(color: :primary) { "A simple primary alert—check it out!" } %>
4
2
 
5
- <%= bs5_alert(color: :secondary) do %>
6
- A simple secondary alert—check it out!
7
- <%- end %>
3
+ <%= bs5_alert(color: :secondary) { "A simple secondary alert—check it out!" } %>
8
4
 
9
- <%= bs5_alert(color: :success) do %>
10
- A simple success alert—check it out!
11
- <%- end %>
5
+ <%= bs5_alert(color: :success) { "A simple success alert—check it out!" } %>
12
6
 
13
- <%= bs5_alert(color: :danger) do %>
14
- A simple danger alert—check it out!
15
- <%- end %>
7
+ <%= bs5_alert(color: :danger) { "A simple danger alert—check it out!" } %>
16
8
 
17
- <%= bs5_alert(color: :warning) do %>
18
- A simple warning alert—check it out!
19
- <%- end %>
9
+ <%= bs5_alert(color: :warning) { "A simple warning alert—check it out!" } %>
20
10
 
21
- <%= bs5_alert(color: :info) do %>
22
- A simple info alert—check it out!
23
- <%- end %>
11
+ <%= bs5_alert(color: :info) { "A simple info alert—check it out!" } %>
24
12
 
25
- <%= bs5_alert(color: :light) do %>
26
- A simple light alert—check it out!
27
- <%- end %>
13
+ <%= bs5_alert(color: :light) { "A simple light alert—check it out!" } %>
28
14
 
29
- <%= bs5_alert(color: :dark) do %>
30
- A simple dark alert—check it out!
31
- <%- end %>
15
+ <%= bs5_alert(color: :dark) { "A simple dark alert—check it out!" } %>
@@ -1,3 +1 @@
1
- <%= bs5_alert do %>
2
- A simple primary alert—check it out!
3
- <%- end %>
1
+ <%= bs5_alert { "A simple primary alert—check it out!" } %>
@@ -0,0 +1,2 @@
1
+ <h2>Dark variant</h2>
2
+ <%= bs5_example(snippet: 'carousel/dark_variant/snippet1') %>
@@ -0,0 +1,13 @@
1
+ <h2>Examples</h2>
2
+ <h3>Slides only</h3>
3
+ <%= bs5_example(snippet: 'carousel/examples/snippet1') %>
4
+ <h3>With controls</h3>
5
+ <%= bs5_example(snippet: 'carousel/examples/snippet2') %>
6
+ <h3>With indicators</h3>
7
+ <%= bs5_example(snippet: 'carousel/examples/snippet3') %>
8
+ <h3>With captions</h3>
9
+ <%= bs5_example(snippet: 'carousel/examples/snippet4') %>
10
+ <h3>Crossfade</h3>
11
+ <%= bs5_example(snippet: 'carousel/examples/snippet5') %>
12
+ <h3>Individual <code>.carousel-item</code> interval</h3>
13
+ <%= bs5_example(snippet: 'carousel/examples/snippet6') %>
@@ -0,0 +1,25 @@
1
+ <%= bs5_carousel(controls: true, indicators: true, dark: true) do |c| %>
2
+ <% c.item do |i| %>
3
+ <%= image_tag 'https://picsum.photos/id/131/800/400?grayscale' %>
4
+ <%= i.caption do %>
5
+ <h5>First slide label</h5>
6
+ <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
7
+ <% end %>
8
+ <% end %>
9
+
10
+ <% c.item do |i| %>
11
+ <%= image_tag 'https://picsum.photos/id/383/800/400?grayscale' %>
12
+ <%= i.caption do %>
13
+ <h5>Second slide label</h5>
14
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
15
+ <% end %>
16
+ <% end %>
17
+
18
+ <% c.item do |i| %>
19
+ <%= image_tag 'https://picsum.photos/id/130/800/400' %>
20
+ <%= i.caption do %>
21
+ <h5>Third slide label</h5>
22
+ <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
23
+ <% end %>
24
+ <% end %>
25
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <%= bs5_carousel do |c| %>
2
+ <% c.item do %>
3
+ <%= image_tag 'https://picsum.photos/800/400?random=1' %>
4
+ <% end %>
5
+
6
+ <% c.item do %>
7
+ <%= image_tag 'https://picsum.photos/800/400?random=2' %>
8
+ <% end %>
9
+
10
+ <% c.item do %>
11
+ <%= image_tag 'https://picsum.photos/800/400?random=3' %>
12
+ <% end %>
13
+ <% end %>