bs5 0.0.9 → 0.0.14

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/bs5/accordion_component.html.erb +3 -10
  3. data/app/components/bs5/accordion_component.rb +1 -0
  4. data/app/components/bs5/button_tag_component.rb +31 -52
  5. data/app/components/bs5/button_to_component.rb +109 -0
  6. data/app/components/bs5/list_group_component.html.erb +17 -0
  7. data/app/components/bs5/list_group_component.rb +143 -0
  8. data/app/controllers/bs5/pages_controller.rb +11 -0
  9. data/app/helpers/bs5/components_helper.rb +14 -1
  10. data/app/service/bs5/collapse_service.rb +47 -0
  11. data/app/views/bs5/examples/accordion/default/_example.html.erb +1 -1
  12. data/app/views/bs5/examples/accordion/flush/_example.html.erb +1 -1
  13. data/app/views/bs5/examples/alert/additional_content/_example.html.erb +1 -1
  14. data/app/views/bs5/examples/alert/default/_example.html.erb +1 -1
  15. data/app/views/bs5/examples/alert/dismissable/_example.html.erb +1 -1
  16. data/app/views/bs5/examples/alert/style/_example.html.erb +1 -1
  17. data/app/views/bs5/examples/badge/default/_example.html.erb +1 -1
  18. data/app/views/bs5/examples/badge/pill/_example.html.erb +1 -1
  19. data/app/views/bs5/examples/badge/style/_example.html.erb +1 -1
  20. data/app/views/bs5/examples/breadcrumb/default/_example.html.erb +1 -1
  21. data/app/views/bs5/examples/buttons/button_tag/block_buttons/_example.html.erb +5 -0
  22. data/app/views/bs5/examples/buttons/{block_buttons → button_tag/block_buttons}/block_buttons.html.erb +0 -0
  23. data/app/views/bs5/examples/buttons/{block_buttons → button_tag/block_buttons}/responsive_block_buttons_1.html.erb +0 -0
  24. data/app/views/bs5/examples/buttons/{block_buttons → button_tag/block_buttons}/responsive_block_buttons_2.html.erb +0 -0
  25. data/app/views/bs5/examples/buttons/{block_buttons → button_tag/block_buttons}/responsive_block_buttons_3.html.erb +0 -0
  26. data/app/views/bs5/examples/buttons/button_tag/default/_example.html.erb +2 -0
  27. data/app/views/bs5/examples/buttons/button_tag/default/snippet.html.erb +15 -0
  28. data/app/views/bs5/examples/buttons/button_tag/outline/_example.html.erb +2 -0
  29. data/app/views/bs5/examples/buttons/button_tag/outline/snippet.html.erb +19 -0
  30. data/app/views/bs5/examples/buttons/button_tag/size/_example.html.erb +3 -0
  31. data/app/views/bs5/examples/buttons/button_tag/size/large.html.erb +3 -0
  32. data/app/views/bs5/examples/buttons/button_tag/size/small.html.erb +3 -0
  33. data/app/views/bs5/examples/buttons/button_tag/style/_example.html.erb +2 -0
  34. data/app/views/bs5/examples/buttons/button_tag/style/snippet.html.erb +19 -0
  35. data/app/views/bs5/examples/buttons/button_tag/toggle_states/_example.html.erb +2 -0
  36. data/app/views/bs5/examples/buttons/{toggle_states → button_tag/toggle_states}/snippet.html.erb +0 -0
  37. data/app/views/bs5/examples/buttons/button_to/default/_example.html.erb +2 -0
  38. data/app/views/bs5/examples/buttons/button_to/default/snippet.html.erb +11 -0
  39. data/app/views/bs5/examples/close_button/default/_example.html.erb +1 -1
  40. data/app/views/bs5/examples/close_button/disabled/_example.html.erb +1 -1
  41. data/app/views/bs5/examples/close_button/white/_example.html.erb +1 -1
  42. data/app/views/bs5/examples/collapse/default/_example.html.erb +4 -0
  43. data/app/views/bs5/examples/collapse/default/multiple_targets.html.erb +21 -0
  44. data/app/views/bs5/examples/collapse/default/snippet.html.erb +9 -0
  45. data/app/views/bs5/examples/list_group/actionable/_example.html.erb +3 -0
  46. data/app/views/bs5/examples/list_group/actionable/button.html.erb +7 -0
  47. data/app/views/bs5/examples/list_group/actionable/snippet.html.erb +7 -0
  48. data/app/views/bs5/examples/list_group/active/_example.html.erb +2 -0
  49. data/app/views/bs5/examples/list_group/active/snippet.html.erb +7 -0
  50. data/app/views/bs5/examples/list_group/checkboxes_and_radios/_example.html.erb +3 -0
  51. data/app/views/bs5/examples/list_group/checkboxes_and_radios/default.html.erb +22 -0
  52. data/app/views/bs5/examples/list_group/checkboxes_and_radios/with_labels.html.erb +32 -0
  53. data/app/views/bs5/examples/list_group/custom_content/_example.html.erb +2 -0
  54. data/app/views/bs5/examples/list_group/custom_content/default.html.erb +32 -0
  55. data/app/views/bs5/examples/list_group/default/_example.html.erb +2 -0
  56. data/app/views/bs5/examples/list_group/default/snippet.html.erb +7 -0
  57. data/app/views/bs5/examples/list_group/disabled/_example.html.erb +2 -0
  58. data/app/views/bs5/examples/list_group/disabled/snippet.html.erb +7 -0
  59. data/app/views/bs5/examples/list_group/flush/_example.html.erb +2 -0
  60. data/app/views/bs5/examples/list_group/flush/snippet.html.erb +7 -0
  61. data/app/views/bs5/examples/list_group/horizontal/_example.html.erb +2 -0
  62. data/app/views/bs5/examples/list_group/horizontal/snippet.html.erb +30 -0
  63. data/app/views/bs5/examples/list_group/style/_example.html.erb +3 -0
  64. data/app/views/bs5/examples/list_group/style/actionable.html.erb +11 -0
  65. data/app/views/bs5/examples/list_group/style/default.html.erb +11 -0
  66. data/app/views/bs5/examples/list_group/with_badges/_example.html.erb +2 -0
  67. data/app/views/bs5/examples/list_group/with_badges/default.html.erb +14 -0
  68. data/app/views/bs5/examples/tooltips/default/_example.html.erb +4 -0
  69. data/app/views/bs5/examples/tooltips/default/buttons.html.erb +9 -0
  70. data/app/views/bs5/examples/tooltips/default/disabled_elements.html.erb +3 -0
  71. data/app/views/bs5/examples/tooltips/default/snippet.html.erb +7 -0
  72. data/app/views/bs5/pages/accordion.html.erb +3 -0
  73. data/app/views/bs5/{examples/_alert.html.erb → pages/alert.html.erb} +1 -1
  74. data/app/views/bs5/{examples/_badge.html.erb → pages/badge.html.erb} +1 -1
  75. data/app/views/bs5/pages/breadcrumb.html.erb +2 -0
  76. data/app/views/bs5/pages/buttons.html.erb +11 -0
  77. data/app/views/bs5/{examples/_close_button.html.erb → pages/close_button.html.erb} +1 -1
  78. data/app/views/bs5/pages/collapse.html.erb +2 -0
  79. data/app/views/bs5/pages/list_group.html.erb +11 -0
  80. data/app/views/bs5/pages/tooltips.html.erb +2 -0
  81. data/app/views/layouts/bs5/pages.html.erb +33 -0
  82. data/config/locales/en.yml +6 -0
  83. data/config/routes.rb +2 -2
  84. data/lib/bs5/version.rb +1 -1
  85. data/lib/generators/bs5/install/install_generator.rb +12 -4
  86. data/lib/generators/bs5/install/templates/bs5.js +14 -0
  87. metadata +80 -26
  88. data/app/controllers/bs5/examples_controller.rb +0 -9
  89. data/app/views/bs5/examples/_accordion.html.erb +0 -3
  90. data/app/views/bs5/examples/_breadcrumb.html.erb +0 -2
  91. data/app/views/bs5/examples/_buttons.html.erb +0 -7
  92. data/app/views/bs5/examples/buttons/block_buttons/_example.html.erb +0 -5
  93. data/app/views/bs5/examples/buttons/default/_example.html.erb +0 -2
  94. data/app/views/bs5/examples/buttons/default/snippet.html.erb +0 -15
  95. data/app/views/bs5/examples/buttons/outline/_example.html.erb +0 -2
  96. data/app/views/bs5/examples/buttons/outline/snippet.html.erb +0 -19
  97. data/app/views/bs5/examples/buttons/size/_example.html.erb +0 -3
  98. data/app/views/bs5/examples/buttons/size/large.html.erb +0 -3
  99. data/app/views/bs5/examples/buttons/size/small.html.erb +0 -3
  100. data/app/views/bs5/examples/buttons/style/_example.html.erb +0 -2
  101. data/app/views/bs5/examples/buttons/style/snippet.html.erb +0 -19
  102. data/app/views/bs5/examples/buttons/toggle_states/_example.html.erb +0 -2
  103. data/app/views/bs5/examples/index.html.erb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54b572156c8e8680ba3937031736fe9cdb6e2aeaf2ea88cb49b6e26c18e02c35
4
- data.tar.gz: 4a4650ceee8e21d32f6a905f00c398e072bb407a4f118cd95488454f9ef61121
3
+ metadata.gz: fe7d17d9f86d5887ab9e3a9cbc86212c19a6ed20526ac905339f6b997c044096
4
+ data.tar.gz: 4d2df678ad8595ebff4a123325a84593dee109fe57a614aaa2473a7d88fb5e9c
5
5
  SHA512:
6
- metadata.gz: c3be0fb1a7839cafbd9673ee974879fd2e95c13e25c5a0f73a27c278c0f2abb1d4305d7eaf965999e5c5fcd390079d116c9aea297e63c1ce5530fdc3e455deb8
7
- data.tar.gz: 73f164bfd36774c565a358e23e294d49b8f386db1450e92a9e73cefd81fa2951b7560705c6e098607a5005e50bf071c094a23d1eacfadf304be61c07995771df
6
+ metadata.gz: f9a8d6249245234d557749abeecbe37feda5e13cbdf2e749baa96f77ffab0cb1b82d7c9c7e00f6751eda8860b396efb333ef8a7a69ca56908c9cd3f1570b9400
7
+ data.tar.gz: 8d4de475b7f904a29ec63bc1845b58a7122fccd366f787616e9f7b7c36e1bba1d4886adc31d0e506de223fea7c84afbaddec553d7d307164adf0c79d949ddb45
@@ -6,16 +6,9 @@
6
6
  id="<%= item.header_id %>"
7
7
  class="accordion-header"
8
8
  >
9
- <button
10
- class="<%= item.button_class %>"
11
- type="button"
12
- data-toggle="collapse"
13
- data-target="#<%= item.collapse_id %>"
14
- aria-expanded="true"
15
- aria-controls="<%= item.collapse_id %>"
16
- >
17
- <%= item.title %>
18
- </button>
9
+ <%= button_tag item.title,
10
+ bs5_collapse(target: "##{item.collapse_id}", expanded: !item.collapsed?)
11
+ .merge(type: :button, class: item.button_class) %>
19
12
  </h2>
20
13
  <div
21
14
  id="<%= item.collapse_id %>"
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Bs5
4
4
  class AccordionComponent < ViewComponent::Base
5
+ include ComponentsHelper
5
6
  include ViewComponent::Slotable
6
7
 
7
8
  with_slot :item, collection: true, class_name: 'Item'
@@ -3,17 +3,23 @@
3
3
  module Bs5
4
4
  class ButtonTagComponent < ViewComponent::Base
5
5
  STYLES = %i[primary secondary success danger warning info light dark link].freeze
6
- SIZES = %i[small large].freeze
6
+ DEFAULT_STYLE = :primary
7
+ SIZES = { small: :sm, large: :lg }.freeze
8
+ CLASS_PREFIX = 'btn'
7
9
 
8
- attr_reader :content_or_options, :options, :size
10
+ attr_reader :content_or_options, :size
9
11
 
10
12
  include ActiveModel::Validations
11
13
  validates :style, style: true
12
- validates :size, inclusion: { in: SIZES, valid_sizes: SIZES.to_sentence, allow_nil: true }
14
+ validates :size, inclusion: { in: SIZES.keys, valid_sizes: SIZES.keys.to_sentence, allow_nil: true }
13
15
 
14
16
  def initialize(content_or_options = nil, options = nil)
15
- @content_or_options = content_or_options.dup
16
- @options = options.dup
17
+ if content_or_options.is_a? Hash
18
+ self.options = content_or_options
19
+ else
20
+ @content_or_options = content_or_options
21
+ self.options = options
22
+ end
17
23
 
18
24
  extract_custom_options
19
25
  merge_default_options
@@ -24,15 +30,19 @@ module Bs5
24
30
  end
25
31
 
26
32
  def call
27
- if content
28
- button_tag(content_or_options, options) { content }
29
- else
30
- button_tag(content_or_options, options)
31
- end
33
+ button_tag(content || content_or_options, options)
32
34
  end
33
35
 
34
36
  private
35
37
 
38
+ def options=(value)
39
+ @options = Hash(value).symbolize_keys!
40
+ end
41
+
42
+ def options
43
+ @options.empty? ? nil : @options
44
+ end
45
+
36
46
  def extract_custom_options
37
47
  extract_style
38
48
  extract_outline
@@ -40,68 +50,43 @@ module Bs5
40
50
  end
41
51
 
42
52
  def extract_style
43
- if @content_or_options.is_a? Hash
44
- @style = @content_or_options.delete(:style)
45
- @content_or_options = nil if @content_or_options.empty?
46
- elsif @options.is_a? Hash
47
- @style = @options.delete(:style)
48
- @options = nil if @options.empty?
49
- end
53
+ @style = @options.delete(:style)
50
54
  end
51
55
 
52
56
  def extract_outline
53
- if @content_or_options.is_a? Hash
54
- @outline = @content_or_options.delete(:outline)
55
- @content_or_options = nil if @content_or_options.empty?
56
- elsif @options.is_a? Hash
57
- @outline = @options.delete(:outline)
58
- @options = nil if @options.empty?
59
- end
57
+ @outline = @options.delete(:outline)
60
58
  end
61
59
 
62
60
  def extract_size
63
- if @content_or_options.is_a? Hash
64
- @size = @content_or_options.delete(:size)
65
- @content_or_options = nil if @content_or_options.empty?
66
- elsif @options.is_a? Hash
67
- @size = @options.delete(:size)
68
- @options = nil if @options.empty?
69
- end
61
+ @size = @options.delete(:size)
70
62
  end
71
63
 
72
64
  def merge_default_options
73
- if @content_or_options.is_a? Hash
74
- deep_merge_and_join @content_or_options, default_options
75
- else
76
- @options ||= {}
77
- deep_merge_and_join @options, default_options
65
+ @options.deep_merge!(default_options) do |_key, this_val, other_val|
66
+ [this_val, other_val].join(' ').strip
78
67
  end
79
68
  end
80
69
 
81
70
  def default_options
82
- {
83
- class: button_class
84
- }
71
+ { class: button_class }
85
72
  end
86
73
 
87
74
  def button_class
88
- ['btn', contextual_class, size_class].compact.join(' ')
75
+ [CLASS_PREFIX, contextual_class, size_class].compact.join(' ')
89
76
  end
90
77
 
91
78
  def contextual_class
92
- ['btn', outline? ? 'outline' : nil, style].compact.join('-')
79
+ [CLASS_PREFIX, outline? ? 'outline' : nil, style].compact.join('-')
93
80
  end
94
81
 
95
82
  def size_class
96
83
  return unless size?
97
84
 
98
- x = { large: 'lg', small: 'sm' }[@size]
99
-
100
- "btn-#{x}"
85
+ [CLASS_PREFIX, SIZES[size]].join('-')
101
86
  end
102
87
 
103
88
  def style
104
- (@style || 'primary').to_sym
89
+ (@style || DEFAULT_STYLE).to_sym
105
90
  end
106
91
 
107
92
  def outline?
@@ -109,13 +94,7 @@ module Bs5
109
94
  end
110
95
 
111
96
  def size?
112
- !!@size
113
- end
114
-
115
- def deep_merge_and_join(h1, h2)
116
- h1.deep_merge!(h2) do |key, this_val, other_val|
117
- [this_val, other_val].join(' ').strip
118
- end
97
+ !!size
119
98
  end
120
99
  end
121
100
  end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ class ButtonToComponent < ViewComponent::Base
5
+ STYLES = %i[primary secondary success danger warning info light dark link].freeze
6
+ DEFAULT_STYLE = :primary
7
+ SIZES = { small: :sm, large: :lg }.freeze
8
+ CLASS_PREFIX = 'btn'
9
+
10
+ attr_reader :size
11
+
12
+ include ActiveModel::Validations
13
+ validates :style, style: true
14
+ validates :size, inclusion: { in: SIZES.keys, valid_sizes: SIZES.keys.to_sentence, allow_nil: true }
15
+
16
+ def initialize(name = nil, options = nil, html_options = nil)
17
+ @name = name
18
+ @options = options
19
+ @html_options = html_options
20
+
21
+ set_button_to_options
22
+ extract_custom_options
23
+ merge_default_options
24
+ end
25
+
26
+ def before_render
27
+ raise errors.full_messages.to_sentence if invalid?
28
+ end
29
+
30
+ def call
31
+ if content
32
+ button_to(@name, @options, @html_options) { content }
33
+ else
34
+ button_to(@name, @options, @html_options)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def set_button_to_options
41
+ if @name.is_a? Hash
42
+ self.button_to_options = @name
43
+ elsif @options.is_a? Hash
44
+ self.button_to_options = @options
45
+ else
46
+ @html_options ||= {}
47
+ self.button_to_options = @html_options
48
+ end
49
+ end
50
+
51
+ def button_to_options=(hash)
52
+ @button_to_options = hash.symbolize_keys!
53
+ end
54
+
55
+ def extract_custom_options
56
+ extract_style
57
+ extract_outline
58
+ extract_size
59
+ end
60
+
61
+ def extract_style
62
+ @style = @button_to_options.delete(:style)
63
+ end
64
+
65
+ def extract_outline
66
+ @outline = @button_to_options.delete(:outline)
67
+ end
68
+
69
+ def extract_size
70
+ @size = @button_to_options.delete(:size)
71
+ end
72
+
73
+ def merge_default_options
74
+ @button_to_options.deep_merge!(default_options) do |_key, this_val, other_val|
75
+ [this_val, other_val].join(' ').strip
76
+ end
77
+ end
78
+
79
+ def default_options
80
+ { class: button_class }
81
+ end
82
+
83
+ def button_class
84
+ [CLASS_PREFIX, contextual_class, size_class].compact.join(' ')
85
+ end
86
+
87
+ def contextual_class
88
+ [CLASS_PREFIX, outline? ? 'outline' : nil, style].compact.join('-')
89
+ end
90
+
91
+ def size_class
92
+ return unless size?
93
+
94
+ [CLASS_PREFIX, SIZES[size]].join('-')
95
+ end
96
+
97
+ def style
98
+ (@style || DEFAULT_STYLE).to_sym
99
+ end
100
+
101
+ def outline?
102
+ !!@outline
103
+ end
104
+
105
+ def size?
106
+ !!size
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,17 @@
1
+ <% if items.any? %>
2
+ <% if actionables? %>
3
+ <div class="<%= component_class %>">
4
+ <% items.each do |item| %>
5
+ <%= item.decorated_content %>
6
+ <% end %>
7
+ </div>
8
+ <% else %>
9
+ <ul class="<%= component_class %>">
10
+ <% items.each do |item| %>
11
+ <%= tag.li(**item.options) do %>
12
+ <%= item.content %>
13
+ <% end %>
14
+ <% end %>
15
+ </ul>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ class ListGroupComponent < ViewComponent::Base
5
+ CLASS_NAME_BASE = 'list-group'
6
+ CLASS_NAME_FLUSH = "#{CLASS_NAME_BASE}-flush"
7
+ CLASS_NAME_HORIZONTAL = "#{CLASS_NAME_BASE}-horizontal"
8
+
9
+ include ViewComponent::Slotable
10
+
11
+ with_slot :item, collection: true, class_name: 'Item'
12
+
13
+ def initialize(flush: false, horizontal: false)
14
+ @flush = flush
15
+ @horizontal = horizontal
16
+ end
17
+
18
+ private
19
+
20
+ def flush?
21
+ !!@flush
22
+ end
23
+
24
+ def actionables?
25
+ items.any?(&:actionable?)
26
+ end
27
+
28
+ def horizontal?
29
+ !!@horizontal
30
+ end
31
+
32
+ def component_class
33
+ class_names = [CLASS_NAME_BASE]
34
+ class_names << flush_class
35
+ class_names << horizontal_class
36
+ class_names.join(' ')
37
+ end
38
+
39
+ def flush_class
40
+ CLASS_NAME_FLUSH if flush?
41
+ end
42
+
43
+ def horizontal_class
44
+ return unless horizontal?
45
+
46
+ class_names = [CLASS_NAME_HORIZONTAL]
47
+ class_names << @horizontal if @horizontal.in?(%i[sm md lg xl xxl])
48
+ class_names.join('-')
49
+ end
50
+
51
+ class Item < ViewComponent::Slot
52
+ CLASS_NAME_BASE = 'list-group-item'
53
+ CLASS_NAME_ACTION = "#{CLASS_NAME_BASE}-action"
54
+
55
+ attr_reader :options
56
+
57
+ def initialize(options = {})
58
+ @options = options.symbolize_keys
59
+
60
+ @active = @options.delete(:active) || false
61
+ @disabled = @options.delete(:disabled) || false
62
+ @style = @options.delete(:style)
63
+
64
+ set_attributes
65
+ end
66
+
67
+ def actionable?
68
+ !!actionable_element
69
+ end
70
+
71
+ def actionable_element
72
+ @actionable_element ||= begin
73
+ if (elements = Nokogiri::HTML::DocumentFragment.parse(content).elements).one? &&
74
+ (element = elements.first).name.in?(%w[a button label])
75
+ element
76
+ end
77
+ end
78
+ end
79
+
80
+ def decorated_content
81
+ set_actionable_element_attributes
82
+ actionable_element.to_html.html_safe # rubocop:disable Rails/OutputSafety
83
+ end
84
+
85
+ private
86
+
87
+ def set_actionable_element_class_names
88
+ class_names = Array(actionable_element[:class])
89
+ class_names << item_classes
90
+ class_names << CLASS_NAME_ACTION if actionable_element.name.in?(%w[a button])
91
+ actionable_element[:class] = class_names.join(' ')
92
+ end
93
+
94
+ def set_actionable_element_attributes
95
+ set_actionable_element_class_names
96
+ actionable_element['aria-current'] = true if active?
97
+
98
+ return unless disabled?
99
+
100
+ case actionable_element.name
101
+ when 'a'
102
+ actionable_element['aria-disabled'] = true
103
+ actionable_element['tabindex'] = -1
104
+ when 'button'
105
+ actionable_element['disabled'] = ''
106
+ end
107
+ end
108
+
109
+ def set_attributes
110
+ @options[:class] = Array(@options[:class])
111
+ @options[:class] << item_classes
112
+ @options[:aria] ||= {}
113
+ @options[:aria][:current] = true if active?
114
+ @options[:aria][:disabled] = true if disabled?
115
+ end
116
+
117
+ def item_classes
118
+ class_names = [CLASS_NAME_BASE]
119
+ class_names << 'active' if active?
120
+ class_names << 'disabled' if disabled?
121
+ class_names << contextual_class if style?
122
+
123
+ class_names
124
+ end
125
+
126
+ def active?
127
+ !!@active
128
+ end
129
+
130
+ def disabled?
131
+ !!@disabled
132
+ end
133
+
134
+ def style?
135
+ !!@style
136
+ end
137
+
138
+ def contextual_class
139
+ [CLASS_NAME_BASE, @style].join('-')
140
+ end
141
+ end
142
+ end
143
+ end