bs5 0.0.26 → 0.0.31

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/bs5/carousel/caption_component.html.erb +3 -0
  3. data/app/components/bs5/carousel/caption_component.rb +8 -0
  4. data/app/components/bs5/carousel/item_component.html.erb +4 -0
  5. data/app/components/bs5/carousel/item_component.rb +74 -0
  6. data/app/components/bs5/carousel_component.html.erb +30 -0
  7. data/app/components/bs5/carousel_component.rb +60 -0
  8. data/app/components/bs5/modal/body_component.html.erb +3 -0
  9. data/app/components/bs5/modal/body_component.rb +8 -0
  10. data/app/components/bs5/modal/controller_component.html.erb +1 -0
  11. data/app/components/bs5/modal/controller_component.rb +40 -0
  12. data/app/components/bs5/modal/footer_component.html.erb +4 -0
  13. data/app/components/bs5/modal/footer_component.rb +8 -0
  14. data/app/components/bs5/modal/header_component.html.erb +4 -0
  15. data/app/components/bs5/modal/header_component.rb +18 -0
  16. data/app/components/bs5/modal_component.html.erb +11 -0
  17. data/app/components/bs5/modal_component.rb +80 -0
  18. data/app/components/bs5/nav/item_component.html.erb +1 -0
  19. data/app/components/bs5/nav/item_component.rb +80 -0
  20. data/app/components/bs5/nav_component.html.erb +7 -0
  21. data/app/components/bs5/nav_component.rb +47 -0
  22. data/app/components/bs5/progress/bar_component.html.erb +1 -0
  23. data/app/components/bs5/progress/bar_component.rb +60 -0
  24. data/app/components/bs5/progress_component.html.erb +9 -0
  25. data/app/components/bs5/progress_component.rb +15 -0
  26. data/app/components/bs5/tabs/item_component.html.erb +3 -0
  27. data/app/components/bs5/tabs/item_component.rb +48 -0
  28. data/app/components/bs5/tabs/link_component.html.erb +1 -0
  29. data/app/components/bs5/tabs/link_component.rb +27 -0
  30. data/app/components/bs5/tabs_component.html.erb +16 -0
  31. data/app/components/bs5/tabs_component.rb +63 -0
  32. data/app/helpers/bs5/components_helper.rb +6 -3
  33. data/app/views/bs5/examples/carousel/_dark_variant.html.erb +2 -0
  34. data/app/views/bs5/examples/carousel/_examples.html.erb +13 -0
  35. data/app/views/bs5/examples/carousel/dark_variant/snippet1.html.erb +25 -0
  36. data/app/views/bs5/examples/carousel/examples/snippet1.html.erb +13 -0
  37. data/app/views/bs5/examples/carousel/examples/snippet2.html.erb +13 -0
  38. data/app/views/bs5/examples/carousel/examples/snippet3.html.erb +13 -0
  39. data/app/views/bs5/examples/carousel/examples/snippet4.html.erb +25 -0
  40. data/app/views/bs5/examples/carousel/examples/snippet5.html.erb +13 -0
  41. data/app/views/bs5/examples/carousel/examples/snippet6.html.erb +13 -0
  42. data/app/views/bs5/examples/modal/_examples.html.erb +9 -0
  43. data/app/views/bs5/examples/modal/_fullscreen.html.erb +2 -0
  44. data/app/views/bs5/examples/modal/_optional_sizes.html.erb +2 -0
  45. data/app/views/bs5/examples/modal/examples/snippet1.html.erb +12 -0
  46. data/app/views/bs5/examples/modal/examples/snippet2.html.erb +12 -0
  47. data/app/views/bs5/examples/modal/examples/snippet3.html.erb +14 -0
  48. data/app/views/bs5/examples/modal/examples/snippet4.html.erb +12 -0
  49. data/app/views/bs5/examples/modal/fullscreen/snippet1.html.erb +55 -0
  50. data/app/views/bs5/examples/modal/optional_sizes/snippet1.html.erb +23 -0
  51. data/app/views/bs5/examples/navs_and_tabs/_base_nav.html.erb +2 -0
  52. data/app/views/bs5/examples/navs_and_tabs/_dropdowns.html.erb +5 -0
  53. data/app/views/bs5/examples/navs_and_tabs/_flex_utils.html.erb +2 -0
  54. data/app/views/bs5/examples/navs_and_tabs/_styles.html.erb +15 -0
  55. data/app/views/bs5/examples/navs_and_tabs/_tabs.html.erb +4 -0
  56. data/app/views/bs5/examples/navs_and_tabs/base_nav/snippet1.html.erb +6 -0
  57. data/app/views/bs5/examples/navs_and_tabs/dropdowns/snippet1.html.erb +14 -0
  58. data/app/views/bs5/examples/navs_and_tabs/dropdowns/snippet2.html.erb +14 -0
  59. data/app/views/bs5/examples/navs_and_tabs/flex_utils/snippet1.html.erb +6 -0
  60. data/app/views/bs5/examples/navs_and_tabs/styles/snippet1.html.erb +6 -0
  61. data/app/views/bs5/examples/navs_and_tabs/styles/snippet2.html.erb +6 -0
  62. data/app/views/bs5/examples/navs_and_tabs/styles/snippet3.html.erb +6 -0
  63. data/app/views/bs5/examples/navs_and_tabs/styles/snippet4.html.erb +6 -0
  64. data/app/views/bs5/examples/navs_and_tabs/styles/snippet5.html.erb +6 -0
  65. data/app/views/bs5/examples/navs_and_tabs/styles/snippet6.html.erb +6 -0
  66. data/app/views/bs5/examples/navs_and_tabs/styles/snippet7.html.erb +6 -0
  67. data/app/views/bs5/examples/navs_and_tabs/styles/snippet8.html.erb +6 -0
  68. data/app/views/bs5/examples/navs_and_tabs/styles/snippet9.html.erb +6 -0
  69. data/app/views/bs5/examples/navs_and_tabs/tabs/snippet1.html.erb +11 -0
  70. data/app/views/bs5/examples/navs_and_tabs/tabs/snippet2.html.erb +11 -0
  71. data/app/views/bs5/examples/navs_and_tabs/tabs/snippet3.html.erb +11 -0
  72. data/app/views/bs5/examples/progress/_animated.html.erb +2 -0
  73. data/app/views/bs5/examples/progress/_backgrounds.html.erb +2 -0
  74. data/app/views/bs5/examples/progress/_examples.html.erb +2 -0
  75. data/app/views/bs5/examples/progress/_labels.html.erb +2 -0
  76. data/app/views/bs5/examples/progress/_multiple_bars.html.erb +2 -0
  77. data/app/views/bs5/examples/progress/_striped.html.erb +2 -0
  78. data/app/views/bs5/examples/progress/animated/snippet1.html.erb +13 -0
  79. data/app/views/bs5/examples/progress/backgrounds/snippet1.html.erb +13 -0
  80. data/app/views/bs5/examples/progress/examples/snippet1.html.erb +17 -0
  81. data/app/views/bs5/examples/progress/labels/snippet1.html.erb +5 -0
  82. data/app/views/bs5/examples/progress/multiple_bars/snippet1.html.erb +5 -0
  83. data/app/views/bs5/examples/progress/striped/snippet1.html.erb +13 -0
  84. data/app/views/bs5/pages/carousel.html.erb +3 -0
  85. data/app/views/bs5/pages/modal.html.erb +4 -0
  86. data/app/views/bs5/pages/navs_and_tabs.html.erb +6 -0
  87. data/app/views/bs5/pages/progress.html.erb +7 -0
  88. data/app/views/layouts/bs5/pages.html.erb +4 -0
  89. data/lib/bs5/version.rb +1 -1
  90. metadata +95 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14b5dca44bb60e64b8eb925c7a617c2e7f6214bf33e1d35a44454b0fc617351c
4
- data.tar.gz: 49dc980ff0a533774090543e1f8920c3ae7d4d4037c9fd84a5aa3425bb1a8faf
3
+ metadata.gz: 1c86a9e7b0f6d9206edcb412b45574112e5d5a4b3cf7bb6e7232c9622a539f0b
4
+ data.tar.gz: 27ae2ba4e66fe54247f339c9a0b221267317f106d99c8a8fa073621dca445116
5
5
  SHA512:
6
- metadata.gz: 2329cc993b4ab1d5930802dfab3f71d878843ce20ebc51bd861c488179e9c4f993b81e48bf1fca791af6886e735de751bbe4ae90f04e641249409e4bade1fc0f
7
- data.tar.gz: ae01cfa6597d19ea0cacff53947b70f3ca8e4c0da463ede006ceef58268efa021a8851684bda0f1702db6a6092b15239fc9b633d62877bed44c2bf330e85b0dd
6
+ metadata.gz: 5da95224fa4acaf34acf85c196ea882b3296bf7c0120753971888c1c228a3d352c37ef50ed3fabff3fb972c9528c40552de1415f149c3686b50b712f0c82219a
7
+ data.tar.gz: 6ca0a9dbd9cefdac7d8ab6160017b90df1ea522d09b0a959bf23a08ac00ac1de457c99ac097d7dd7ca92c4fcdd79eb1fa8dd98f82255371b0d70c48ff9b699ee
@@ -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
@@ -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 @@
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
@@ -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 @@
1
+ <%= content %>
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module Nav
5
+ class ItemComponent < ViewComponent::Base
6
+ def initialize(options = {})
7
+ @options = options.symbolize_keys
8
+ extract_options
9
+ end
10
+
11
+ private
12
+
13
+ def extract_options
14
+ @active = @options.delete(:active)
15
+ @disabled = @options.delete(:disabled)
16
+ end
17
+
18
+ def content
19
+ set_element_attributes
20
+ fragment.to_html.html_safe # rubocop:disable Rails/OutputSafety
21
+ end
22
+
23
+ def set_element_attributes
24
+ element['aria-current'] = 'page' if active?
25
+
26
+ if disabled?
27
+ element['aria-disabled'] = true
28
+ element['tabindex'] = -1
29
+ end
30
+
31
+ set_element_class_names
32
+ element.replace(element.to_html)
33
+ end
34
+
35
+ def set_element_class_names
36
+ class_names = Array(element[:class])
37
+ class_names << Array(@options[:class])
38
+ class_names << extra_classes
39
+ element[:class] = class_names.compact.uniq.join(' ')
40
+ end
41
+
42
+ def extra_classes
43
+ class_names = element_classes
44
+ class_names << active_class
45
+ class_names << disabled_class
46
+ class_names.compact.uniq
47
+ end
48
+
49
+ def element_classes
50
+ %w[nav-link]
51
+ end
52
+
53
+ def active_class
54
+ return unless active?
55
+
56
+ %w[active]
57
+ end
58
+
59
+ def disabled_class
60
+ return unless disabled?
61
+
62
+ %w[disabled]
63
+ end
64
+
65
+ def element
66
+ @element ||= fragment.at_css('button', 'a')
67
+ end
68
+
69
+ def fragment
70
+ @fragment ||= Nokogiri::HTML::DocumentFragment.parse(@content)
71
+ end
72
+
73
+ %i[active disabled].each do |name|
74
+ define_method("#{name}?") do
75
+ !!instance_variable_get("@#{name}")
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end