primer_view_components 0.0.23 → 0.0.28
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/CHANGELOG.md +98 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/javascripts/primer_view_components.js.map.orig +5 -0
- data/app/assets/javascripts/primer_view_components.js.orig +6 -0
- data/app/components/primer/auto_complete_component.d.ts +1 -0
- data/app/components/primer/auto_complete_component.html.erb +5 -0
- data/app/components/primer/auto_complete_component.js +1 -0
- data/app/components/primer/auto_complete_component.rb +98 -0
- data/app/components/primer/auto_complete_component.ts +1 -0
- data/app/components/primer/auto_complete_item_component.rb +40 -0
- data/app/components/primer/avatar_component.rb +8 -9
- data/app/components/primer/base_component.rb +7 -15
- data/app/components/primer/blankslate_component.html.erb +1 -5
- data/app/components/primer/blankslate_component.rb +2 -0
- data/app/components/primer/border_box_component.rb +32 -6
- data/app/components/primer/box_component.rb +3 -5
- data/app/components/primer/breadcrumb_component.html.erb +1 -2
- data/app/components/primer/breadcrumb_component.rb +24 -12
- data/app/components/primer/component.rb +1 -13
- data/app/components/primer/counter_component.rb +17 -9
- data/app/components/primer/details_component.rb +3 -3
- data/app/components/primer/dropdown_menu_component.rb +2 -4
- data/app/components/primer/flash_component.html.erb +2 -2
- data/app/components/primer/flash_component.rb +2 -4
- data/app/components/primer/flex_component.rb +16 -16
- data/app/components/primer/heading_component.rb +1 -1
- data/app/components/primer/label_component.rb +9 -9
- data/app/components/primer/layout_component.html.erb +3 -9
- data/app/components/primer/layout_component.rb +30 -5
- data/app/components/primer/link_component.rb +37 -9
- data/app/components/primer/octicon_component.rb +4 -7
- data/app/components/primer/popover_component.html.erb +3 -7
- data/app/components/primer/popover_component.rb +58 -62
- data/app/components/primer/primer.d.ts +3 -0
- data/app/components/primer/primer.js +2 -0
- data/app/components/primer/primer.ts +2 -0
- data/app/components/primer/progress_bar_component.html.erb +1 -1
- data/app/components/primer/progress_bar_component.rb +24 -27
- data/app/components/primer/spinner_component.rb +2 -4
- data/app/components/primer/state_component.rb +2 -4
- data/app/components/primer/subhead_component.rb +2 -0
- data/app/components/primer/tab_container_component.d.ts +1 -0
- data/app/components/primer/text_component.rb +3 -1
- data/app/components/primer/time_ago_component.d.ts +1 -0
- data/app/components/primer/time_ago_component.js +1 -0
- data/app/components/primer/time_ago_component.rb +47 -0
- data/app/components/primer/time_ago_component.ts +1 -0
- data/app/components/primer/timeline_item_component.rb +2 -1
- data/app/components/primer/underline_nav_component.html.erb +5 -5
- data/app/components/primer/underline_nav_component.rb +24 -5
- data/app/lib/primer/classify.rb +9 -14
- data/app/lib/primer/classify/cache.rb +7 -2
- data/app/lib/primer/classify/functional_background_colors.rb +61 -0
- data/app/lib/primer/classify/functional_border_colors.rb +51 -0
- data/app/lib/primer/classify/functional_colors.rb +66 -0
- data/app/lib/primer/classify/functional_text_colors.rb +62 -0
- data/app/lib/primer/fetch_or_fallback_helper.rb +13 -4
- data/app/lib/primer/status/dsl.rb +43 -0
- data/app/lib/primer/test_selector_helper.rb +20 -0
- data/app/lib/primer/view_helper.rb +9 -12
- data/lib/primer/view_components/engine.rb +4 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/static/statuses.json +1 -1
- metadata +37 -4
- data/app/lib/primer/view_helper/dsl.rb +0 -34
@@ -3,9 +3,10 @@
|
|
3
3
|
module Primer
|
4
4
|
# Renders an [Octicon](https://primer.style/octicons/) with <%= link_to_system_arguments_docs %>.
|
5
5
|
class OcticonComponent < Primer::Component
|
6
|
-
|
6
|
+
status :beta
|
7
7
|
|
8
|
-
include
|
8
|
+
include ClassNameHelper
|
9
|
+
include TestSelectorHelper
|
9
10
|
include OcticonsHelper
|
10
11
|
|
11
12
|
SIZE_DEFAULT = :small
|
@@ -38,15 +39,11 @@ module Primer
|
|
38
39
|
# Filter out classify options to prevent them from becoming invalid html attributes.
|
39
40
|
# Note height and width are both classify options and valid html attributes.
|
40
41
|
octicon_helper_options = @system_arguments.slice(:height, :width)
|
41
|
-
@system_arguments = @system_arguments.except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
|
42
|
+
@system_arguments = add_test_selector(@system_arguments).except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
|
42
43
|
end
|
43
44
|
|
44
45
|
def call
|
45
46
|
octicon(@icon, { **@system_arguments })
|
46
47
|
end
|
47
|
-
|
48
|
-
def self.status
|
49
|
-
Primer::Component::STATUSES[:beta]
|
50
|
-
end
|
51
48
|
end
|
52
49
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
-
<%= render
|
3
|
-
|
4
|
-
|
5
|
-
<%= heading.content %>
|
6
|
-
<% end %>
|
7
|
-
<% end %>
|
8
|
-
<%= body.content %>
|
2
|
+
<%= render(body_component) do %>
|
3
|
+
<%= heading %>
|
4
|
+
<%= body %>
|
9
5
|
<% end %>
|
10
6
|
<% end %>
|
@@ -5,37 +5,84 @@ module Primer
|
|
5
5
|
#
|
6
6
|
# By default, the popover renders with absolute positioning, meaning it should usually be wrapped in an element with a relative position in order to be positioned properly. To render the popover with relative positioning, use the relative property.
|
7
7
|
class PopoverComponent < Primer::Component
|
8
|
-
include ViewComponent::
|
8
|
+
include ViewComponent::SlotableV2
|
9
|
+
status :beta
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
CARET_DEFAULT = :top
|
12
|
+
CARET_MAPPINGS = {
|
13
|
+
CARET_DEFAULT => "",
|
14
|
+
:bottom => "Popover-message--bottom",
|
15
|
+
:bottom_right => "Popover-message--bottom-right",
|
16
|
+
:bottom_left => "Popover-message--bottom-left",
|
17
|
+
:left => "Popover-message--left",
|
18
|
+
:left_bottom => "Popover-message--left-bottom",
|
19
|
+
:left_top => "Popover-message--left-top",
|
20
|
+
:right => "Popover-message--right",
|
21
|
+
:right_bottom => "Popover-message--right-bottom",
|
22
|
+
:right_top => "Popover-message--right-top",
|
23
|
+
:top_left => "Popover-message--top-left",
|
24
|
+
:top_right => "Popover-message--top-right"
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# The heading
|
28
|
+
#
|
29
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
30
|
+
renders_one :heading, lambda { |**system_arguments|
|
31
|
+
system_arguments[:mb] ||= 2
|
32
|
+
system_arguments[:tag] ||= :h4
|
33
|
+
|
34
|
+
Primer::HeadingComponent.new(**system_arguments)
|
35
|
+
}
|
36
|
+
|
37
|
+
# The body
|
38
|
+
#
|
39
|
+
# @param caret [Symbol] <%= one_of(Primer::PopoverComponent::CARET_MAPPINGS.keys) %>
|
40
|
+
# @param large [Boolean] Whether to use the large version of the component.
|
41
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
42
|
+
renders_one :body, lambda { |caret: CARET_DEFAULT, large: false, **system_arguments, &block|
|
43
|
+
system_arguments[:classes] = class_names(
|
44
|
+
system_arguments[:classes],
|
45
|
+
"Popover-message Box",
|
46
|
+
CARET_MAPPINGS[fetch_or_fallback(CARET_MAPPINGS.keys, caret, CARET_DEFAULT)],
|
47
|
+
"Popover-message--large" => large
|
48
|
+
)
|
49
|
+
system_arguments[:p] ||= 4
|
50
|
+
system_arguments[:mt] ||= 2
|
51
|
+
system_arguments[:mx] ||= :auto
|
52
|
+
system_arguments[:text_align] ||= :left
|
53
|
+
system_arguments[:box_shadow] ||= :large
|
54
|
+
|
55
|
+
# This is a hack to allow the parent to set the slot's content
|
56
|
+
@body_arguments = system_arguments
|
57
|
+
block&.call
|
58
|
+
}
|
12
59
|
|
13
60
|
# @example Default
|
14
61
|
# <%= render Primer::PopoverComponent.new do |component| %>
|
15
|
-
# <% component.
|
62
|
+
# <% component.heading do %>
|
16
63
|
# Activity feed
|
17
64
|
# <% end %>
|
18
|
-
# <% component.
|
65
|
+
# <% component.body do %>
|
19
66
|
# This is the Popover body.
|
20
67
|
# <% end %>
|
21
68
|
# <% end %>
|
22
69
|
#
|
23
70
|
# @example Large
|
24
71
|
# <%= render Primer::PopoverComponent.new do |component| %>
|
25
|
-
# <% component.
|
72
|
+
# <% component.heading do %>
|
26
73
|
# Activity feed
|
27
74
|
# <% end %>
|
28
|
-
# <% component.
|
75
|
+
# <% component.body(large: true) do %>
|
29
76
|
# This is the large Popover body.
|
30
77
|
# <% end %>
|
31
78
|
# <% end %>
|
32
79
|
#
|
33
80
|
# @example Caret position
|
34
81
|
# <%= render Primer::PopoverComponent.new do |component| %>
|
35
|
-
# <% component.
|
82
|
+
# <% component.heading do %>
|
36
83
|
# Activity feed
|
37
84
|
# <% end %>
|
38
|
-
# <% component.
|
85
|
+
# <% component.body(caret: :left) do %>
|
39
86
|
# This is the large Popover body.
|
40
87
|
# <% end %>
|
41
88
|
# <% end %>
|
@@ -57,59 +104,8 @@ module Primer
|
|
57
104
|
body.present?
|
58
105
|
end
|
59
106
|
|
60
|
-
|
61
|
-
|
62
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
63
|
-
def initialize(**system_arguments)
|
64
|
-
@system_arguments = system_arguments
|
65
|
-
@system_arguments[:mb] ||= 2
|
66
|
-
@system_arguments[:tag] ||= :h4
|
67
|
-
end
|
68
|
-
|
69
|
-
def component
|
70
|
-
Primer::HeadingComponent.new(**@system_arguments)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# :nodoc:
|
75
|
-
class Body < Slot
|
76
|
-
CARET_DEFAULT = :top
|
77
|
-
CARET_MAPPINGS = {
|
78
|
-
CARET_DEFAULT => "",
|
79
|
-
:bottom => "Popover-message--bottom",
|
80
|
-
:bottom_right => "Popover-message--bottom-right",
|
81
|
-
:bottom_left => "Popover-message--bottom-left",
|
82
|
-
:left => "Popover-message--left",
|
83
|
-
:left_bottom => "Popover-message--left-bottom",
|
84
|
-
:left_top => "Popover-message--left-top",
|
85
|
-
:right => "Popover-message--right",
|
86
|
-
:right_bottom => "Popover-message--right-bottom",
|
87
|
-
:right_top => "Popover-message--right-top",
|
88
|
-
:top_left => "Popover-message--top-left",
|
89
|
-
:top_right => "Popover-message--top-right"
|
90
|
-
}.freeze
|
91
|
-
|
92
|
-
# @param caret [Symbol] <%= one_of(Primer::PopoverComponent::Body::CARET_MAPPINGS.keys) %>
|
93
|
-
# @param large [Boolean] Whether to use the large version of the component.
|
94
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
95
|
-
def initialize(caret: CARET_DEFAULT, large: false, **system_arguments)
|
96
|
-
@system_arguments = system_arguments
|
97
|
-
@system_arguments[:classes] = class_names(
|
98
|
-
system_arguments[:classes],
|
99
|
-
"Popover-message Box",
|
100
|
-
CARET_MAPPINGS[fetch_or_fallback(CARET_MAPPINGS.keys, caret, CARET_DEFAULT)],
|
101
|
-
"Popover-message--large" => large
|
102
|
-
)
|
103
|
-
@system_arguments[:p] ||= 4
|
104
|
-
@system_arguments[:mt] ||= 2
|
105
|
-
@system_arguments[:mx] ||= :auto
|
106
|
-
@system_arguments[:text_align] ||= :left
|
107
|
-
@system_arguments[:box_shadow] ||= :large
|
108
|
-
end
|
109
|
-
|
110
|
-
def component
|
111
|
-
Primer::BoxComponent.new(**@system_arguments)
|
112
|
-
end
|
107
|
+
def body_component
|
108
|
+
Primer::BoxComponent.new(**@body_arguments)
|
113
109
|
end
|
114
110
|
end
|
115
111
|
end
|
@@ -3,9 +3,25 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use ProgressBar to visualize task completion.
|
5
5
|
class ProgressBarComponent < Primer::Component
|
6
|
-
include ViewComponent::
|
6
|
+
include ViewComponent::SlotableV2
|
7
|
+
status :beta
|
7
8
|
|
8
|
-
|
9
|
+
# Use the Item slot to add an item to the progress bas
|
10
|
+
#
|
11
|
+
# @param percentage [Integer] The percent complete
|
12
|
+
# @param bg [Symbol] The background color
|
13
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
|
14
|
+
renders_many :items, lambda { |percentage: 0, bg: :success_inverse, **system_arguments|
|
15
|
+
percentage = percentage
|
16
|
+
system_arguments = system_arguments
|
17
|
+
|
18
|
+
system_arguments[:tag] = :span
|
19
|
+
system_arguments[:bg] = bg
|
20
|
+
system_arguments[:style] = join_style_arguments(system_arguments[:style], "width: #{percentage}%;")
|
21
|
+
system_arguments[:classes] = class_names("Progress-item", system_arguments[:classes])
|
22
|
+
|
23
|
+
Primer::BaseComponent.new(**system_arguments)
|
24
|
+
}
|
9
25
|
|
10
26
|
SIZE_DEFAULT = :default
|
11
27
|
|
@@ -18,24 +34,24 @@ module Primer
|
|
18
34
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
19
35
|
# @example Default
|
20
36
|
# <%= render(Primer::ProgressBarComponent.new) do |component| %>
|
21
|
-
# <% component.
|
37
|
+
# <% component.item(percentage: 25) %>
|
22
38
|
# <% end %>
|
23
39
|
#
|
24
40
|
# @example Small
|
25
41
|
# <%= render(Primer::ProgressBarComponent.new(size: :small)) do |component| %>
|
26
|
-
# <% component.
|
42
|
+
# <% component.item(bg: :info_inverse, percentage: 50) %>
|
27
43
|
# <% end %>
|
28
44
|
#
|
29
45
|
# @example Large
|
30
46
|
# <%= render(Primer::ProgressBarComponent.new(size: :large)) do |component| %>
|
31
|
-
# <% component.
|
47
|
+
# <% component.item(bg: :danger_inverse, percentage: 75) %>
|
32
48
|
# <% end %>
|
33
49
|
#
|
34
50
|
# @example Multiple items
|
35
51
|
# <%= render(Primer::ProgressBarComponent.new) do |component| %>
|
36
|
-
# <% component.
|
37
|
-
# <% component.
|
38
|
-
# <% component.
|
52
|
+
# <% component.item(percentage: 10) %>
|
53
|
+
# <% component.item(bg: :info_inverse, percentage: 20) %>
|
54
|
+
# <% component.item(bg: :danger_inverse, percentage: 30) %>
|
39
55
|
# <% end %>
|
40
56
|
#
|
41
57
|
# @param size [Symbol] <%= one_of(Primer::ProgressBarComponent::SIZE_OPTIONS) %> Increases height.
|
@@ -53,24 +69,5 @@ module Primer
|
|
53
69
|
def render?
|
54
70
|
items.any?
|
55
71
|
end
|
56
|
-
|
57
|
-
# :nodoc:
|
58
|
-
class Item < Primer::Slot
|
59
|
-
attr_reader :system_arguments
|
60
|
-
|
61
|
-
# @param percentage [Integer] Percentage completion of item.
|
62
|
-
# @param bg [Symbol] Color of item.
|
63
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
64
|
-
def initialize(percentage: 0, bg: :green, **system_arguments)
|
65
|
-
@percentage = percentage
|
66
|
-
@system_arguments = system_arguments
|
67
|
-
|
68
|
-
@system_arguments[:tag] = :span
|
69
|
-
@system_arguments[:bg] = bg
|
70
|
-
@system_arguments[:style] =
|
71
|
-
join_style_arguments(@system_arguments[:style], "width: #{@percentage}%;")
|
72
|
-
@system_arguments[:classes] = class_names("Progress-item", @system_arguments[:classes])
|
73
|
-
end
|
74
|
-
end
|
75
72
|
end
|
76
73
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use Primer::SpinnerComponent to let users know that content is being loaded.
|
5
5
|
class SpinnerComponent < Primer::Component
|
6
|
+
status :beta
|
7
|
+
|
6
8
|
DEFAULT_SIZE = :medium
|
7
9
|
SIZE_MAPPINGS = {
|
8
10
|
:small => 16,
|
@@ -34,9 +36,5 @@ module Primer
|
|
34
36
|
@system_arguments[:viewBox] = "0 0 16 16"
|
35
37
|
@system_arguments[:fill] = :none
|
36
38
|
end
|
37
|
-
|
38
|
-
def self.status
|
39
|
-
Primer::Component::STATUSES[:beta]
|
40
|
-
end
|
41
39
|
end
|
42
40
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Primer
|
4
4
|
# Component for rendering the status of an item.
|
5
5
|
class StateComponent < Primer::Component
|
6
|
+
status :beta
|
7
|
+
|
6
8
|
COLOR_DEFAULT = :default
|
7
9
|
NEW_COLOR_MAPPINGS = {
|
8
10
|
open: "State--open",
|
@@ -68,9 +70,5 @@ module Primer
|
|
68
70
|
def call
|
69
71
|
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
70
72
|
end
|
71
|
-
|
72
|
-
def self.status
|
73
|
-
Primer::Component::STATUSES[:beta]
|
74
|
-
end
|
75
73
|
end
|
76
74
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/tab-container-element';
|
@@ -3,9 +3,11 @@
|
|
3
3
|
module Primer
|
4
4
|
# The Text component is a wrapper component that will apply typography styles to the text inside.
|
5
5
|
class TextComponent < Primer::Component
|
6
|
+
status :beta
|
7
|
+
|
6
8
|
# @example Default
|
7
9
|
# <%= render(Primer::TextComponent.new(tag: :p, font_weight: :bold)) { "Bold Text" } %>
|
8
|
-
# <%= render(Primer::TextComponent.new(tag: :p, color: :
|
10
|
+
# <%= render(Primer::TextComponent.new(tag: :p, color: :text_danger)) { "Danger Text" } %>
|
9
11
|
#
|
10
12
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
11
13
|
def initialize(**system_arguments)
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements';
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements';
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
# Use Primer::TimeAgoComponent to display a time relative to how long ago it was. This component requires JavaScript.
|
5
|
+
class TimeAgoComponent < Primer::Component
|
6
|
+
#
|
7
|
+
# @example Default
|
8
|
+
# <%= render(Primer::TimeAgoComponent.new(time: Time.at(628232400))) %>
|
9
|
+
#
|
10
|
+
# @param time [Time] The time to be formatted
|
11
|
+
# @param micro [Boolean] If true then the text will be formatted in "micro" mode, using as few characters as possible
|
12
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
13
|
+
def initialize(time:, micro: false, **system_arguments)
|
14
|
+
@system_arguments = system_arguments
|
15
|
+
@system_arguments[:datetime] = time.utc.iso8601
|
16
|
+
@system_arguments[:classes] = class_names("no-wrap", @system_arguments[:classes])
|
17
|
+
@system_arguments[:tag] = "time-ago"
|
18
|
+
@system_arguments[:format] = "micro" if micro
|
19
|
+
@time = time
|
20
|
+
@micro = micro
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { time_in_words }
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def time_in_words
|
30
|
+
return @time.in_time_zone.strftime("%b %-d, %Y") unless @micro
|
31
|
+
|
32
|
+
seconds_ago = Time.current - @time
|
33
|
+
|
34
|
+
if seconds_ago < 1.minute
|
35
|
+
"1m"
|
36
|
+
elsif seconds_ago >= 1.minute && seconds_ago < 1.hour
|
37
|
+
"#{(seconds_ago / 60).floor}m"
|
38
|
+
elsif seconds_ago >= 1.hour && seconds_ago < 1.day
|
39
|
+
"#{(seconds_ago / 60 / 60).floor}h"
|
40
|
+
elsif seconds_ago >= 1.day && seconds_ago < 1.year
|
41
|
+
"#{(seconds_ago / 60 / 60 / 24).floor}d"
|
42
|
+
elsif seconds_ago >= 1.year
|
43
|
+
"#{(seconds_ago / 60 / 60 / 24 / 365).floor}y"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements'
|
@@ -4,6 +4,7 @@ module Primer
|
|
4
4
|
# Use `TimelineItem` to display items on a vertical timeline, connected by badge elements.
|
5
5
|
class TimelineItemComponent < Primer::Component
|
6
6
|
include ViewComponent::SlotableV2
|
7
|
+
status :beta
|
7
8
|
|
8
9
|
# Avatar to be rendered to the left of the Badge.
|
9
10
|
#
|
@@ -40,7 +41,7 @@ module Primer
|
|
40
41
|
# <div style="padding-left: 60px">
|
41
42
|
# <%= render(Primer::TimelineItemComponent.new) do |component| %>
|
42
43
|
# <% component.avatar(src: "https://github.com/github.png", alt: "github") %>
|
43
|
-
# <% component.badge(bg: :
|
44
|
+
# <% component.badge(bg: :success_inverse, color: :text_white, icon: :check) %>
|
44
45
|
# <% component.body { "Success!" } %>
|
45
46
|
# <% end %>
|
46
47
|
# </div>
|