bs5 0.0.26 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
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