bootstrap4_helper 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ # @description
6
+ # - Naming convention used as to not pollute views where the module is
7
+ # included. @config is a common instance variable name. We don't want
8
+ # to risk overriding another developers variable.
9
+ #
10
+ @_bs4h_config = Configuration.new
11
+
12
+ class << self
13
+ # @description
14
+ # - Simple interface for exposing the configuration object.
15
+ #
16
+ # @return [Bootstrap4Helper::Configuration]
17
+ #
18
+ def config
19
+ yield @_bs4h_config if block_given?
20
+
21
+ @_bs4h_config
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,150 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ # @description
6
+ #
7
+ #
8
+ class Modal < Component
9
+ # @description
10
+ # -
11
+ #
12
+ # @param [ActionView] template
13
+ # @param [Hash]
14
+ #
15
+ def initialize(template, opts = {}, &block)
16
+ super(template)
17
+
18
+ @id = opts.fetch(:id, uuid)
19
+ @class = opts.fetch(:class, '')
20
+ @data = opts.fetch(:data, {})
21
+ @scrollable = opts.fetch(:scrollable, false)
22
+ @vcentered = opts.fetch(:vcentered, false)
23
+ @content = block || proc { '' }
24
+ end
25
+
26
+ # @description
27
+ # - Build the header component for the modal.
28
+ #
29
+ # @param [Hash] opts
30
+ #
31
+ def header(opts = {}, &block)
32
+ build_main_component :header, opts, &block
33
+ end
34
+
35
+ # @description
36
+ # - Builds the body component.
37
+ #
38
+ # @param [Hash] opts
39
+ #
40
+ def body(opts = {}, &block)
41
+ build_main_component :body, opts, &block
42
+ end
43
+
44
+ # @description
45
+ # - Builds the footer component.
46
+ #
47
+ # @param [Hash] opts
48
+ #
49
+ def footer(opts = {}, &block)
50
+ build_main_component :footer, opts, &block
51
+ end
52
+
53
+ # @description
54
+ # - Builds a title component.
55
+ #
56
+ # @param [Hash] opts
57
+ #
58
+ def title(opts = {}, &block)
59
+ build_sub_component :h5, :title, opts, &block
60
+ end
61
+
62
+ # @description
63
+ # - Builds a close button component.
64
+ #
65
+ # @param [Hash] opts
66
+ #
67
+ def close_button(opts = {})
68
+ klass = opts.fetch(:class, '')
69
+
70
+ content_tag(
71
+ :button,
72
+ type: 'button',
73
+ class: block_given? ? klass : 'close',
74
+ data: { dismiss: 'modal' },
75
+ aria: { label: 'Close' }
76
+ ) do
77
+ block_given? ? yield : xbutton
78
+ end
79
+ end
80
+
81
+ # @description
82
+ # -
83
+ #
84
+ def to_s
85
+ content_tag :div, id: @id, class: "modal #{@class}", tabindex: -1, role: 'dialog', data: @data do
86
+ content_tag :div, class: "modal-dialog #{scrollable} #{vcentered}", role: 'document' do
87
+ content_tag(:div, class: 'modal-content') { @content.call(self) }
88
+ end
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ # @description
95
+ # - Used to build main components, usually divs.
96
+ #
97
+ # @param [Symbol|String] type
98
+ # @param [Hash] opts
99
+ #
100
+ def build_main_component(type, opts = {}, &block)
101
+ build_sub_component :div, type, opts, &block
102
+ end
103
+
104
+ # @description
105
+ # - Used to build more specific components.
106
+ #
107
+ # @param [Symbol] tag
108
+ # @param [Symbol|String] type
109
+ # @param [Hash] opts
110
+ #
111
+ def build_sub_component(tag, type, opts = {}, &block)
112
+ id = opts.fetch(:id, nil)
113
+ klass = opts.fetch(:class, '')
114
+ data = opts.fetch(:data, {})
115
+
116
+ content_tag(
117
+ tag,
118
+ id: id,
119
+ class: "modal-#{type} #{klass}",
120
+ data: data,
121
+ &block
122
+ )
123
+ end
124
+
125
+ # @description
126
+ # - Builds the `x` button normally used in the header.
127
+ #
128
+ def xbutton
129
+ content_tag :span, '&times;'.html_safe, aria: { hidden: true }
130
+ end
131
+
132
+ # @description
133
+ # - Gets the scrollable CSS class.
134
+ #
135
+ # @return [String]
136
+ #
137
+ def scrollable
138
+ @scrollable ? 'modal-dialog-scrollable' : ''
139
+ end
140
+
141
+ # @description
142
+ # - Gets the vertical-center CSS class.
143
+ #
144
+ # @return [String]
145
+ #
146
+ def vcentered
147
+ @vcentered ? 'modal-dialog-centered' : ''
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,100 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ # @description
6
+ # -
7
+ #
8
+ class Nav < Component
9
+ # @description
10
+ # -
11
+ #
12
+ # @param [ActionView] template
13
+ # @param [NilClass|String|Symbol|Hash] context_or_options
14
+ # @param [Hash]
15
+ #
16
+ def initialize(template, opts = {}, &block)
17
+ super(template)
18
+
19
+ @id = opts.fetch(:id, uuid)
20
+ @class = opts.fetch(:class, '')
21
+ @data = opts.fetch(:data, {})
22
+ @child = opts.fetch(:child, {})
23
+ @content = block || proc { '' }
24
+
25
+ @dropdown = Dropdown.new(@template)
26
+ end
27
+
28
+ # @description
29
+ # - Adds an nav-item to the nav component. this method gets used when the nav-item
30
+ # links to content in a tab or something.
31
+ #
32
+ # @param [Symbol|String] target
33
+ # @param [Hash] opts
34
+ #
35
+ # rubocop:disable Metrics/MethodLength
36
+ def item(target, opts = {})
37
+ id = opts.fetch(:id, nil)
38
+ klass = opts.fetch(:class, '')
39
+ data = opts.fetch(:data, {})
40
+ aria = opts.fetch(:aria, {})
41
+
42
+ content_tag :li, id: id, class: 'nav-item', data: data do
43
+ content_tag(
44
+ :a,
45
+ class: "nav-link #{klass}",
46
+ href: "##{target}",
47
+ tabindex: -1,
48
+ data: @child[:data],
49
+ aria: aria
50
+ ) do
51
+ block_given? ? yield : target.to_s.titleize
52
+ end
53
+ end
54
+ end
55
+ # rubocop:enable Metrics/MethodLength
56
+
57
+ # @description
58
+ # - Use this when the nav item is nothing more than a hyperlink.
59
+ #
60
+ def link(name = nil, options = nil, html_options = nil, &block)
61
+ html_options = (html_options || {}).merge(class: 'nav-link')
62
+
63
+ @template.link_to(name, options, html_options, &block)
64
+ end
65
+
66
+ # @description
67
+ # - Creates a dropdown menu for the nav.
68
+ #
69
+ # @param [NilClass|Symbol|String] name
70
+ # @param [Hash] opts
71
+ #
72
+ def dropdown(name, opts = {}, &block)
73
+ id = opts.fetch(:id, nil)
74
+ klass = opts.fetch(:class, '')
75
+ data = opts.fetch(:data, {})
76
+ aria = opts.fetch(:aria, {}).merge(haspopup: true, expanded: false)
77
+
78
+ content_tag :li, id: id, class: 'nav-item dropdown', data: data do
79
+ content_tag(
80
+ :a,
81
+ name,
82
+ class: "nav-link dropdown-toggle #{klass}",
83
+ href: '#',
84
+ data: { toggle: 'dropdown' },
85
+ role: 'button',
86
+ aria: aria
87
+ ) + @dropdown.menu(opts, &block).to_s.html_safe
88
+ end
89
+ end
90
+
91
+ # @description
92
+ # -
93
+ #
94
+ def to_s
95
+ content_tag :ul, id: @id, class: "nav #{@class}" do
96
+ @content.call(self)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,4 +1,12 @@
1
1
  module Bootstrap4Helper
2
+ # @description
3
+ #
4
+ #
2
5
  class Railtie < ::Rails::Railtie
6
+ config.after_initialize do
7
+ ActiveSupport.on_load(:action_view) do
8
+ include Bootstrap4Helper if Bootstrap4Helper.config.autoload_in_views?
9
+ end
10
+ end
3
11
  end
4
12
  end
@@ -0,0 +1,41 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ # @description
6
+ # - a simple CSS spinner component.
7
+ #
8
+ class Spinner < Component
9
+ # @description
10
+ # -
11
+ #
12
+ # @param [ActionView] template
13
+ # @param [Hash] opts
14
+ #
15
+ def initialize(template, opts = {}, &block)
16
+ super(template)
17
+
18
+ @type = opts.fetch(:type, :border)
19
+ @id = opts.fetch(:id, uuid)
20
+ @class = opts.fetch(:class, '')
21
+ @data = opts.fetch(:data, {})
22
+ @content = block || proc { '' }
23
+ end
24
+
25
+ # @description
26
+ # -
27
+ #
28
+ def to_s
29
+ content_tag(
30
+ :span,
31
+ id: @id,
32
+ class: "spinner-#{@type} #{@class}",
33
+ role: 'status',
34
+ aria: { hidden: true },
35
+ data: @data
36
+ ) do
37
+ content_tag :span, 'Loading', class: 'sr-only'
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,66 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ # @description
6
+ #
7
+ #
8
+ class Tab < Component
9
+ # @description
10
+ # -
11
+ #
12
+ # @param [ActionView] template
13
+ # @param [Hash] opts
14
+ # @param [Hash]
15
+ #
16
+ def initialize(template, opts = {}, &block)
17
+ super(template)
18
+
19
+ @type = opts.fetch(:type, :tabs)
20
+ @id = opts.fetch(:id, uuid)
21
+ @class = opts.fetch(:class, '')
22
+ @data = opts.fetch(:data, {})
23
+ @content = block || proc { '' }
24
+ end
25
+
26
+ # @description
27
+ # - Builds a custom Nav component for the tabs.
28
+ #
29
+ # @param [Hash] opts
30
+ # @return [Nav]
31
+ #
32
+ def nav(opts = {}, &block)
33
+ opts[:class] = (opts[:class] || '') << " nav-#{@type}"
34
+ opts[:data] = (opts[:data] || {}).merge(toggle: 'tab')
35
+ opts[:child] = {
36
+ data: {
37
+ toggle: 'tab'
38
+ }
39
+ }
40
+
41
+ Nav.new(@template, opts, &block)
42
+ end
43
+
44
+ # @description
45
+ # - Builds the Content object for the Tab.
46
+ #
47
+ # @param [Hash] opts
48
+ # @return [Tab::Content]
49
+ #
50
+ def content(opts = {}, &block)
51
+ Content.new(@template, opts, &block)
52
+ end
53
+
54
+ # @description
55
+ # - This has a weird interaction. Because this object doesn't actually return any wrapping
56
+ # string or DOM element, we want to return nil, so that only the output buffer on the sub components are returned.
57
+ # If we return the return value of the block, we will get the last element added to the input
58
+ # buffer as an unescaped string.
59
+ #
60
+ def to_s
61
+ @content.call(self)
62
+
63
+ nil
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,50 @@
1
+ # @root
2
+ #
3
+ #
4
+ module Bootstrap4Helper
5
+ #
6
+ #
7
+ #
8
+ class Tab
9
+ #
10
+ #
11
+ #
12
+ class Content < Component
13
+ # @description
14
+ # -
15
+ #
16
+ # @param [ActionView] template
17
+ # @param [NilClass|String|Symbol|Hash] context_or_options
18
+ # @param [Hash]
19
+ #
20
+ def initialize(template, opts = {}, &block)
21
+ super(template)
22
+
23
+ @id = opts.fetch(:id, uuid)
24
+ @class = opts.fetch(:class, '')
25
+ @data = opts.fetch(:data, {})
26
+ @content = block || proc { '' }
27
+ end
28
+
29
+ # @description
30
+ # -
31
+ #
32
+ def pane(source, opts = {}, &block)
33
+ id = opts.fetch(:id, nil)
34
+ klass = opts.fetch(:class, '')
35
+ data = opts.fetch(:data, {})
36
+
37
+ content_tag :div, id: source, class: "tab-pane #{klass}", role: 'tabpanel', &block
38
+ end
39
+
40
+ # @description
41
+ # -
42
+ #
43
+ def to_s
44
+ content_tag :div, id: @id, class: "tab-content #{@class}" do
45
+ @content.call(self)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end