element_component 0.6.0 → 0.8.0
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.
- checksums.yaml +4 -4
- data/AGENTS.md +5 -5
- data/README.md +348 -41
- data/examples/alert_example.rb +17 -17
- data/examples/badge_example.rb +63 -0
- data/examples/breadcrumb_example.rb +40 -0
- data/examples/button_example.rb +86 -0
- data/examples/button_group_example.rb +55 -0
- data/examples/card_example.rb +62 -0
- data/examples/carousel_example.rb +97 -0
- data/examples/close_button_example.rb +40 -0
- data/examples/dropdown_example.rb +131 -0
- data/examples/list_group_example.rb +68 -0
- data/examples/modal_example.rb +122 -0
- data/examples/nav_example.rb +77 -0
- data/examples/navbar_example.rb +104 -0
- data/examples/pagination_example.rb +47 -0
- data/examples/progress_example.rb +54 -0
- data/examples/spinner_example.rb +49 -0
- data/examples/table_example.rb +41 -0
- data/lib/element_component/components/alert.rb +3 -3
- data/lib/element_component/components/badge.rb +18 -0
- data/lib/element_component/components/breadcrumb/item.rb +29 -0
- data/lib/element_component/components/breadcrumb.rb +26 -0
- data/lib/element_component/components/button.rb +25 -0
- data/lib/element_component/components/button_group.rb +18 -0
- data/lib/element_component/components/card/body.rb +14 -0
- data/lib/element_component/components/card/footer.rb +14 -0
- data/lib/element_component/components/card/header.rb +14 -0
- data/lib/element_component/components/card/image.rb +17 -0
- data/lib/element_component/components/card/text.rb +14 -0
- data/lib/element_component/components/card/title.rb +14 -0
- data/lib/element_component/components/card.rb +21 -0
- data/lib/element_component/components/carousel/caption.rb +14 -0
- data/lib/element_component/components/carousel/item.rb +16 -0
- data/lib/element_component/components/carousel.rb +70 -0
- data/lib/element_component/components/close_button.rb +17 -0
- data/lib/element_component/components/dropdown/divider.rb +20 -0
- data/lib/element_component/components/dropdown/header.rb +22 -0
- data/lib/element_component/components/dropdown/item.rb +33 -0
- data/lib/element_component/components/dropdown/menu.rb +15 -0
- data/lib/element_component/components/dropdown.rb +43 -0
- data/lib/element_component/components/list_group/item.rb +23 -0
- data/lib/element_component/components/list_group.rb +18 -0
- data/lib/element_component/components/modal/body.rb +14 -0
- data/lib/element_component/components/modal/content.rb +14 -0
- data/lib/element_component/components/modal/dialog.rb +21 -0
- data/lib/element_component/components/modal/footer.rb +14 -0
- data/lib/element_component/components/modal/header.rb +16 -0
- data/lib/element_component/components/modal/title.rb +14 -0
- data/lib/element_component/components/modal.rb +42 -0
- data/lib/element_component/components/nav/item.rb +14 -0
- data/lib/element_component/components/nav/link.rb +18 -0
- data/lib/element_component/components/nav.rb +23 -0
- data/lib/element_component/components/navbar/brand.rb +15 -0
- data/lib/element_component/components/navbar/collapse.rb +16 -0
- data/lib/element_component/components/navbar/nav.rb +14 -0
- data/lib/element_component/components/navbar/toggler.rb +22 -0
- data/lib/element_component/components/navbar.rb +51 -0
- data/lib/element_component/components/pagination/item.rb +27 -0
- data/lib/element_component/components/pagination.rb +33 -0
- data/lib/element_component/components/progress/bar.rb +24 -0
- data/lib/element_component/components/progress.rb +17 -0
- data/lib/element_component/components/spinner.rb +19 -0
- data/lib/element_component/components/table.rb +21 -0
- data/lib/element_component/components.rb +16 -0
- data/lib/element_component/element.rb +5 -3
- data/lib/element_component/version.rb +1 -1
- metadata +61 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CardHeader < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("div", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "card-header")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CardImage < Element
|
|
6
|
+
def initialize(src: "", top: false, bottom: false, **attributes, &block)
|
|
7
|
+
super("img", closing_tag: false, &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "card-img")
|
|
10
|
+
add_attribute(class: "card-img-top") if top
|
|
11
|
+
add_attribute(class: "card-img-bottom") if bottom
|
|
12
|
+
add_attribute(src: src)
|
|
13
|
+
add_attribute(attributes) unless attributes.empty?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CardText < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("p", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "card-text")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CardTitle < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("h5", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "card-title")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "card/header"
|
|
4
|
+
require_relative "card/body"
|
|
5
|
+
require_relative "card/footer"
|
|
6
|
+
require_relative "card/title"
|
|
7
|
+
require_relative "card/text"
|
|
8
|
+
require_relative "card/image"
|
|
9
|
+
|
|
10
|
+
module ElementComponent
|
|
11
|
+
module Components
|
|
12
|
+
class Card < Element
|
|
13
|
+
def initialize(**attributes, &)
|
|
14
|
+
super("div", &)
|
|
15
|
+
|
|
16
|
+
add_attribute(class: "card")
|
|
17
|
+
add_attribute(attributes) unless attributes.empty?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CarouselCaption < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("div", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "carousel-caption")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CarouselItem < Element
|
|
6
|
+
def initialize(active: false, interval: nil, **attributes, &block)
|
|
7
|
+
super("div", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "carousel-item")
|
|
10
|
+
add_attribute(class: "active") if active
|
|
11
|
+
add_attribute("data-bs-interval": interval.to_s) if interval
|
|
12
|
+
add_attribute(attributes) unless attributes.empty?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "carousel/item"
|
|
4
|
+
require_relative "carousel/caption"
|
|
5
|
+
|
|
6
|
+
module ElementComponent
|
|
7
|
+
module Components
|
|
8
|
+
class Carousel < Element
|
|
9
|
+
def initialize(id: "carousel", fade: false, indicators: true, controls: true, **attributes, &block)
|
|
10
|
+
@carousel_id = id
|
|
11
|
+
@show_indicators = indicators
|
|
12
|
+
@show_controls = controls
|
|
13
|
+
super("div", &block)
|
|
14
|
+
|
|
15
|
+
add_attribute(id: id)
|
|
16
|
+
add_attribute(class: "carousel")
|
|
17
|
+
add_attribute(class: "slide")
|
|
18
|
+
add_attribute(class: "carousel-fade") if fade
|
|
19
|
+
add_attribute(attributes) unless attributes.empty?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def indicator_button(index, active)
|
|
25
|
+
target = "data-bs-target=\"##{@carousel_id}\""
|
|
26
|
+
slide = "data-bs-slide-to=\"#{index}\""
|
|
27
|
+
active_attr = ' class="active" aria-current="true"' if active
|
|
28
|
+
"<button type=\"button\" #{target} #{slide}#{active_attr}></button>"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_indicators
|
|
32
|
+
html = +""
|
|
33
|
+
contents.each_with_index do |item, index|
|
|
34
|
+
next unless item.is_a?(CarouselItem)
|
|
35
|
+
|
|
36
|
+
active = item.attributes[:class]&.include?("active") || index.zero?
|
|
37
|
+
html << indicator_button(index, active)
|
|
38
|
+
end
|
|
39
|
+
html
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def control_button(direction, label)
|
|
43
|
+
target = "data-bs-target=\"##{@carousel_id}\""
|
|
44
|
+
slide = "data-bs-slide=\"#{direction}\""
|
|
45
|
+
"<button class=\"carousel-control-#{direction}\" type=\"button\" #{target} #{slide}>" \
|
|
46
|
+
"<span class=\"carousel-control-#{direction}-icon\" aria-hidden=\"true\"></span>" \
|
|
47
|
+
"<span class=\"visually-hidden\">#{label}</span></button>"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build
|
|
51
|
+
@html << "<#{@element}"
|
|
52
|
+
@html << (mount_attributes.empty? ? ">" : " #{mount_attributes}>")
|
|
53
|
+
|
|
54
|
+
@html << "<div class=\"carousel-indicators\">#{build_indicators}</div>" if @show_indicators
|
|
55
|
+
|
|
56
|
+
@html << "<div class=\"carousel-inner\">"
|
|
57
|
+
@html << mount_content
|
|
58
|
+
@html << "</div>"
|
|
59
|
+
|
|
60
|
+
if @show_controls
|
|
61
|
+
@html << control_button("prev", "Previous")
|
|
62
|
+
@html << control_button("next", "Next")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@html << "</#{@element}>" if @closing_tag
|
|
66
|
+
@html
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class CloseButton < Element
|
|
6
|
+
def initialize(disabled: false, **attributes)
|
|
7
|
+
super("button", closing_tag: false)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "btn-close")
|
|
10
|
+
add_attribute(type: "button")
|
|
11
|
+
add_attribute("aria-label": "Close")
|
|
12
|
+
add_attribute(disabled: "") if disabled
|
|
13
|
+
add_attribute(attributes) unless attributes.empty?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class DropdownDivider < Element
|
|
6
|
+
def initialize(**attributes)
|
|
7
|
+
super("li")
|
|
8
|
+
|
|
9
|
+
inner = Element.new("hr", class: "dropdown-divider", **attributes)
|
|
10
|
+
@inner_divider = inner
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def mount_content
|
|
16
|
+
@inner_divider&.render || ""
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class DropdownHeader < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("li", &)
|
|
8
|
+
|
|
9
|
+
inner = Element.new("h6", class: "dropdown-header", **attributes)
|
|
10
|
+
@inner_header = inner
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def mount_content
|
|
16
|
+
inner = super
|
|
17
|
+
@inner_header&.add_content(inner)
|
|
18
|
+
"<li>#{@inner_header&.render}</li>"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class DropdownItem < Element
|
|
6
|
+
VALID_TYPES = %i[button link].freeze
|
|
7
|
+
|
|
8
|
+
def initialize(type: :link, href: "#", active: false, disabled: false, **attributes, &block)
|
|
9
|
+
tag = type == :button ? "button" : "a"
|
|
10
|
+
super("li", &block)
|
|
11
|
+
|
|
12
|
+
inner = Element.new(tag, class: "dropdown-item", href: (tag == "a" ? href : nil),
|
|
13
|
+
type: (tag == "button" ? "button" : nil), **attributes)
|
|
14
|
+
inner.add_attribute(class: "active") if active
|
|
15
|
+
inner.add_attribute(class: "disabled") if disabled
|
|
16
|
+
inner.add_attribute(tabindex: "-1") if disabled
|
|
17
|
+
inner.add_attribute("aria-disabled": "true") if disabled
|
|
18
|
+
|
|
19
|
+
inner.add_content(&block) if block
|
|
20
|
+
|
|
21
|
+
@inner_item = inner
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def mount_content
|
|
27
|
+
inner = super
|
|
28
|
+
@inner_item&.add_content(inner)
|
|
29
|
+
"<li>#{@inner_item&.render || inner}</li>"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class DropdownMenu < Element
|
|
6
|
+
def initialize(align: nil, **attributes, &block)
|
|
7
|
+
super("ul", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "dropdown-menu")
|
|
10
|
+
add_attribute(class: "dropdown-menu-#{align}") if align
|
|
11
|
+
add_attribute(attributes) unless attributes.empty?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "dropdown/menu"
|
|
4
|
+
require_relative "dropdown/item"
|
|
5
|
+
require_relative "dropdown/divider"
|
|
6
|
+
require_relative "dropdown/header"
|
|
7
|
+
|
|
8
|
+
module ElementComponent
|
|
9
|
+
module Components
|
|
10
|
+
class Dropdown < Element
|
|
11
|
+
VALID_DIRECTIONS = %i[dropup dropend dropstart].freeze
|
|
12
|
+
|
|
13
|
+
def initialize(direction: nil, **attributes, &block)
|
|
14
|
+
super("div", &block)
|
|
15
|
+
|
|
16
|
+
add_attribute(class: "dropdown")
|
|
17
|
+
add_attribute(class: direction.to_s) if direction
|
|
18
|
+
add_attribute(attributes) unless attributes.empty?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def toggle_button(label: "Dropdown", variant: :secondary, split: false, **btn_attributes, &block)
|
|
22
|
+
if split
|
|
23
|
+
split_btn = Button.new(variant: variant, class: "dropdown-toggle dropdown-toggle-split",
|
|
24
|
+
**btn_attributes)
|
|
25
|
+
split_btn.add_content(
|
|
26
|
+
Element.new("span", class: "visually-hidden") { add_content("Toggle dropdown") }
|
|
27
|
+
)
|
|
28
|
+
add_content(ButtonGroup.new do
|
|
29
|
+
add_content(Button.new(variant: variant, **btn_attributes) { add_content(label) })
|
|
30
|
+
add_content(split_btn)
|
|
31
|
+
end)
|
|
32
|
+
else
|
|
33
|
+
btn = Element.new("button", "aria-expanded": "false", "data-bs-toggle": "dropdown",
|
|
34
|
+
class: "btn btn-#{variant} dropdown-toggle", type: "button", **btn_attributes)
|
|
35
|
+
btn.add_content(label) if label
|
|
36
|
+
block&.call(self)
|
|
37
|
+
add_content(btn)
|
|
38
|
+
end
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ListGroupItem < Element
|
|
6
|
+
VALID_VARIANTS = %i[primary secondary success danger warning info light dark].freeze
|
|
7
|
+
|
|
8
|
+
def initialize(variant: nil, active: false, disabled: false, href: nil, **attributes, &block)
|
|
9
|
+
tag = href ? "a" : "li"
|
|
10
|
+
super(tag, &block)
|
|
11
|
+
|
|
12
|
+
add_attribute(class: "list-group-item")
|
|
13
|
+
add_attribute(class: "list-group-item-action") if href || tag == "a"
|
|
14
|
+
add_attribute(class: "list-group-item-#{variant}") if variant
|
|
15
|
+
add_attribute(class: "active") if active
|
|
16
|
+
add_attribute(class: "disabled") if disabled
|
|
17
|
+
add_attribute(href: href) if href
|
|
18
|
+
add_attribute("aria-current": "true") if active
|
|
19
|
+
add_attribute(attributes) unless attributes.empty?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "list_group/item"
|
|
4
|
+
|
|
5
|
+
module ElementComponent
|
|
6
|
+
module Components
|
|
7
|
+
class ListGroup < Element
|
|
8
|
+
def initialize(flush: false, numbered: false, **attributes, &block)
|
|
9
|
+
super("ul", &block)
|
|
10
|
+
|
|
11
|
+
add_attribute(class: "list-group")
|
|
12
|
+
add_attribute(class: "list-group-flush") if flush
|
|
13
|
+
add_attribute(class: "list-group-numbered") if numbered
|
|
14
|
+
add_attribute(attributes) unless attributes.empty?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalBody < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("div", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "modal-body")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalContent < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("div", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "modal-content")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalDialog < Element
|
|
6
|
+
VALID_SIZES = %i[sm lg xl].freeze
|
|
7
|
+
VALID_FULLSCREEN = %i[always sm md lg xl xxl].freeze
|
|
8
|
+
|
|
9
|
+
def initialize(scrollable: false, centered: false, size: nil, fullscreen: nil, **attributes, &block)
|
|
10
|
+
super("div", &block)
|
|
11
|
+
|
|
12
|
+
add_attribute(class: "modal-dialog")
|
|
13
|
+
add_attribute(class: "modal-dialog-scrollable") if scrollable
|
|
14
|
+
add_attribute(class: "modal-dialog-centered") if centered
|
|
15
|
+
add_attribute(class: "modal-#{size}") if size
|
|
16
|
+
add_attribute(class: "modal-fullscreen#{"-#{fullscreen}-down" unless fullscreen == :always}") if fullscreen
|
|
17
|
+
add_attribute(attributes) unless attributes.empty?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalFooter < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("div", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "modal-footer")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalHeader < Element
|
|
6
|
+
def initialize(close_button: true, **attributes, &block)
|
|
7
|
+
super("div", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "modal-header")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
|
|
12
|
+
add_content(CloseButton.new) if close_button
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class ModalTitle < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("h5", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "modal-title")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "modal/dialog"
|
|
4
|
+
require_relative "modal/content"
|
|
5
|
+
require_relative "modal/header"
|
|
6
|
+
require_relative "modal/title"
|
|
7
|
+
require_relative "modal/body"
|
|
8
|
+
require_relative "modal/footer"
|
|
9
|
+
|
|
10
|
+
module ElementComponent
|
|
11
|
+
module Components
|
|
12
|
+
class Modal < Element
|
|
13
|
+
VALID_SIZES = %i[sm lg xl].freeze
|
|
14
|
+
VALID_FULLSCREEN = %i[always sm md lg xl xxl].freeze
|
|
15
|
+
|
|
16
|
+
def initialize(fade: true, static: false, scrollable: false, centered: false, size: nil, fullscreen: nil,
|
|
17
|
+
**attributes, &block)
|
|
18
|
+
super("div", &block)
|
|
19
|
+
|
|
20
|
+
add_attribute(class: "modal")
|
|
21
|
+
add_attribute(class: "fade") if fade
|
|
22
|
+
add_attribute(tabindex: "-1")
|
|
23
|
+
add_attribute("aria-hidden": "true")
|
|
24
|
+
add_attribute("data-bs-backdrop": "static") if static
|
|
25
|
+
add_attribute("data-bs-keyboard": "false") if static
|
|
26
|
+
|
|
27
|
+
add_content(ModalDialog.new(scrollable: scrollable, centered: centered, size: size, fullscreen: fullscreen))
|
|
28
|
+
add_attribute(attributes) unless attributes.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def build
|
|
34
|
+
@html << "<#{@element}"
|
|
35
|
+
@html << (mount_attributes.empty? ? ">" : " #{mount_attributes}>")
|
|
36
|
+
@html << mount_content
|
|
37
|
+
@html << "</#{@element}>" if @closing_tag
|
|
38
|
+
@html
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavItem < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("li", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "nav-item")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavLink < Element
|
|
6
|
+
def initialize(href: "#", active: false, disabled: false, **attributes, &block)
|
|
7
|
+
super("a", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "nav-link")
|
|
10
|
+
add_attribute(class: "active") if active
|
|
11
|
+
add_attribute(class: "disabled") if disabled
|
|
12
|
+
add_attribute(href: href)
|
|
13
|
+
add_attribute("aria-current": "page") if active
|
|
14
|
+
add_attribute(attributes) unless attributes.empty?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "nav/item"
|
|
4
|
+
require_relative "nav/link"
|
|
5
|
+
|
|
6
|
+
module ElementComponent
|
|
7
|
+
module Components
|
|
8
|
+
class Nav < Element
|
|
9
|
+
VALID_TYPES = %i[tabs pills underline].freeze
|
|
10
|
+
|
|
11
|
+
def initialize(type: nil, fill: false, justified: false, vertical: false, **attributes, &block)
|
|
12
|
+
super("ul", &block)
|
|
13
|
+
|
|
14
|
+
add_attribute(class: "nav")
|
|
15
|
+
add_attribute(class: "nav-#{type}") if type
|
|
16
|
+
add_attribute(class: "nav-fill") if fill
|
|
17
|
+
add_attribute(class: "nav-justified") if justified
|
|
18
|
+
add_attribute(class: "flex-column") if vertical
|
|
19
|
+
add_attribute(attributes) unless attributes.empty?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavbarBrand < Element
|
|
6
|
+
def initialize(href: "#", **attributes, &block)
|
|
7
|
+
super("a", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "navbar-brand")
|
|
10
|
+
add_attribute(href: href)
|
|
11
|
+
add_attribute(attributes) unless attributes.empty?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavbarCollapse < Element
|
|
6
|
+
def initialize(id: nil, **attributes, &block)
|
|
7
|
+
super("div", &block)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "collapse")
|
|
10
|
+
add_attribute(class: "navbar-collapse")
|
|
11
|
+
add_attribute(id: id) if id
|
|
12
|
+
add_attribute(attributes) unless attributes.empty?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavbarNav < Element
|
|
6
|
+
def initialize(**attributes, &)
|
|
7
|
+
super("ul", &)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "navbar-nav")
|
|
10
|
+
add_attribute(attributes) unless attributes.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElementComponent
|
|
4
|
+
module Components
|
|
5
|
+
class NavbarToggler < Element
|
|
6
|
+
def initialize(target: nil, **attributes)
|
|
7
|
+
super("button", closing_tag: false)
|
|
8
|
+
|
|
9
|
+
add_attribute(class: "navbar-toggler")
|
|
10
|
+
add_attribute(type: "button")
|
|
11
|
+
add_attribute("data-bs-toggle": "collapse")
|
|
12
|
+
add_attribute("data-bs-target": "##{target}") if target
|
|
13
|
+
add_attribute("aria-controls": target) if target
|
|
14
|
+
add_attribute("aria-expanded": "false")
|
|
15
|
+
add_attribute("aria-label": "Toggle navigation")
|
|
16
|
+
add_attribute(attributes) unless attributes.empty?
|
|
17
|
+
|
|
18
|
+
add_content(Element.new("span", class: "navbar-toggler-icon"))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|