element_component 0.5.0 → 0.7.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +126 -0
  3. data/README.md +440 -25
  4. data/examples/alert_example.rb +97 -0
  5. data/examples/badge_example.rb +63 -0
  6. data/examples/breadcrumb_example.rb +36 -0
  7. data/examples/button_example.rb +86 -0
  8. data/examples/button_group_example.rb +55 -0
  9. data/examples/card_example.rb +62 -0
  10. data/examples/carousel_example.rb +95 -0
  11. data/examples/close_button_example.rb +40 -0
  12. data/examples/dropdown_example.rb +123 -0
  13. data/examples/list_group_example.rb +60 -0
  14. data/examples/modal_example.rb +120 -0
  15. data/examples/nav_example.rb +75 -0
  16. data/examples/navbar_example.rb +96 -0
  17. data/examples/pagination_example.rb +47 -0
  18. data/examples/progress_example.rb +54 -0
  19. data/examples/spinner_example.rb +49 -0
  20. data/examples/table_example.rb +41 -0
  21. data/lib/element_component/components/alert/close_button.rb +17 -0
  22. data/lib/element_component/components/alert/heading.rb +14 -0
  23. data/lib/element_component/components/alert/link.rb +15 -0
  24. data/lib/element_component/components/alert.rb +25 -0
  25. data/lib/element_component/components/badge.rb +18 -0
  26. data/lib/element_component/components/breadcrumb/item.rb +29 -0
  27. data/lib/element_component/components/breadcrumb.rb +26 -0
  28. data/lib/element_component/components/button.rb +25 -0
  29. data/lib/element_component/components/button_group.rb +18 -0
  30. data/lib/element_component/components/card/body.rb +14 -0
  31. data/lib/element_component/components/card/footer.rb +14 -0
  32. data/lib/element_component/components/card/header.rb +14 -0
  33. data/lib/element_component/components/card/image.rb +17 -0
  34. data/lib/element_component/components/card/text.rb +14 -0
  35. data/lib/element_component/components/card/title.rb +14 -0
  36. data/lib/element_component/components/card.rb +21 -0
  37. data/lib/element_component/components/carousel/caption.rb +14 -0
  38. data/lib/element_component/components/carousel/item.rb +16 -0
  39. data/lib/element_component/components/carousel.rb +70 -0
  40. data/lib/element_component/components/close_button.rb +17 -0
  41. data/lib/element_component/components/dropdown/divider.rb +20 -0
  42. data/lib/element_component/components/dropdown/header.rb +22 -0
  43. data/lib/element_component/components/dropdown/item.rb +33 -0
  44. data/lib/element_component/components/dropdown/menu.rb +15 -0
  45. data/lib/element_component/components/dropdown.rb +43 -0
  46. data/lib/element_component/components/list_group/item.rb +23 -0
  47. data/lib/element_component/components/list_group.rb +18 -0
  48. data/lib/element_component/components/modal/body.rb +14 -0
  49. data/lib/element_component/components/modal/content.rb +14 -0
  50. data/lib/element_component/components/modal/dialog.rb +21 -0
  51. data/lib/element_component/components/modal/footer.rb +14 -0
  52. data/lib/element_component/components/modal/header.rb +16 -0
  53. data/lib/element_component/components/modal/title.rb +14 -0
  54. data/lib/element_component/components/modal.rb +42 -0
  55. data/lib/element_component/components/nav/item.rb +14 -0
  56. data/lib/element_component/components/nav/link.rb +18 -0
  57. data/lib/element_component/components/nav.rb +23 -0
  58. data/lib/element_component/components/navbar/brand.rb +15 -0
  59. data/lib/element_component/components/navbar/collapse.rb +16 -0
  60. data/lib/element_component/components/navbar/nav.rb +14 -0
  61. data/lib/element_component/components/navbar/toggler.rb +22 -0
  62. data/lib/element_component/components/navbar.rb +51 -0
  63. data/lib/element_component/components/pagination/item.rb +27 -0
  64. data/lib/element_component/components/pagination.rb +33 -0
  65. data/lib/element_component/components/progress/bar.rb +24 -0
  66. data/lib/element_component/components/progress.rb +17 -0
  67. data/lib/element_component/components/spinner.rb +19 -0
  68. data/lib/element_component/components/table.rb +21 -0
  69. data/lib/element_component/components.rb +24 -0
  70. data/lib/element_component/element.rb +21 -7
  71. data/lib/element_component/version.rb +3 -1
  72. data/lib/element_component.rb +3 -1
  73. metadata +68 -1
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "breadcrumb/item"
4
+
5
+ module ElementComponent
6
+ module Components
7
+ class Breadcrumb < Element
8
+ def initialize(**attributes, &)
9
+ super("nav", &)
10
+
11
+ add_attribute("aria-label": "breadcrumb")
12
+ add_attribute(attributes) unless attributes.empty?
13
+ end
14
+
15
+ def build
16
+ @html << "<#{@element}"
17
+ @html << (mount_attributes.empty? ? ">" : " #{mount_attributes}>")
18
+ @html << "<ol class=\"breadcrumb\">"
19
+ @html << mount_content
20
+ @html << "</ol>"
21
+ @html << "</#{@element}>" if @closing_tag
22
+ @html
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElementComponent
4
+ module Components
5
+ class Button < Element
6
+ VALID_VARIANTS = %i[primary secondary success danger warning info light dark link].freeze
7
+ VALID_SIZES = %i[sm lg].freeze
8
+
9
+ def initialize(variant: :primary, outline: false, size: nil, href: nil, **attributes, &block)
10
+ if href
11
+ super("a", &block)
12
+ add_attribute(href: href)
13
+ else
14
+ super("button", &block)
15
+ add_attribute(type: "button")
16
+ end
17
+
18
+ add_attribute(class: "btn")
19
+ add_attribute(class: outline ? "btn-outline-#{variant}" : "btn-#{variant}")
20
+ add_attribute(class: "btn-#{size}") if size
21
+ add_attribute(attributes) unless attributes.empty?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElementComponent
4
+ module Components
5
+ class ButtonGroup < Element
6
+ VALID_SIZES = %i[sm lg].freeze
7
+
8
+ def initialize(size: nil, vertical: false, **attributes, &block)
9
+ super("div", &block)
10
+
11
+ add_attribute(class: vertical ? "btn-group-vertical" : "btn-group")
12
+ add_attribute(class: "btn-group-#{size}") if size
13
+ add_attribute(role: "group")
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 CardBody < Element
6
+ def initialize(**attributes, &)
7
+ super("div", &)
8
+
9
+ add_attribute(class: "card-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 CardFooter < Element
6
+ def initialize(**attributes, &)
7
+ super("div", &)
8
+
9
+ add_attribute(class: "card-footer")
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 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
+ instance_eval(&block) if block
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