primer_view_components 0.0.84 → 0.0.87
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/components/primer/alpha/auto_complete/item.rb +1 -1
- data/app/components/primer/alpha/auto_complete.rb +1 -1
- data/app/components/primer/alpha/button_marketing.rb +1 -1
- data/app/components/primer/alpha/text_field.rb +105 -0
- data/app/components/primer/alpha/tool-tip-element.d.ts +3 -1
- data/app/components/primer/alpha/tool-tip-element.js +20 -13
- data/app/components/primer/alpha/tool-tip-element.ts +23 -14
- data/app/components/primer/alpha/tooltip.rb +1 -1
- data/app/components/primer/beta/base_button.rb +47 -0
- data/app/components/primer/{alpha → beta}/border_box/header.html.erb +0 -0
- data/app/components/primer/{alpha → beta}/border_box/header.rb +6 -6
- data/app/components/primer/{border_box_component.html.erb → beta/border_box.html.erb} +0 -0
- data/app/components/primer/beta/border_box.rb +147 -0
- data/app/components/primer/blankslate_component.html.erb +0 -5
- data/app/components/primer/border_box_component.rb +2 -140
- data/app/components/primer/button_component.html.erb +12 -4
- data/app/components/primer/button_component.rb +2 -2
- data/app/components/primer/clipboard_copy.rb +6 -2
- data/app/components/primer/close_button.rb +1 -1
- data/app/components/primer/hellip_button.rb +1 -1
- data/app/components/primer/icon_button.html.erb +6 -0
- data/app/components/primer/icon_button.rb +46 -10
- data/app/components/primer/link_component.rb +12 -5
- data/app/helpers/primer/form_helper.rb +10 -0
- data/app/lib/primer/join_style_arguments_helper.rb +1 -1
- data/lib/primer/classify/utilities.rb +3 -6
- data/lib/primer/form_components.rb +36 -0
- data/lib/primer/forms/acts_as_component.rb +118 -0
- data/lib/primer/forms/base.html.erb +8 -0
- data/lib/primer/forms/base.rb +142 -0
- data/lib/primer/forms/base_component.rb +62 -0
- data/lib/primer/forms/buffer_rewriter.rb +51 -0
- data/lib/primer/forms/builder.rb +48 -0
- data/lib/primer/forms/caption.html.erb +10 -0
- data/lib/primer/forms/caption.rb +29 -0
- data/lib/primer/forms/check_box.html.erb +9 -0
- data/lib/primer/forms/check_box.rb +16 -0
- data/lib/primer/forms/check_box_group.html.erb +12 -0
- data/lib/primer/forms/check_box_group.rb +14 -0
- data/lib/primer/forms/dsl/check_box_group_input.rb +41 -0
- data/lib/primer/forms/dsl/check_box_input.rb +27 -0
- data/lib/primer/forms/dsl/form_object.rb +25 -0
- data/lib/primer/forms/dsl/form_reference_input.rb +36 -0
- data/lib/primer/forms/dsl/hidden_input.rb +29 -0
- data/lib/primer/forms/dsl/input.rb +237 -0
- data/lib/primer/forms/dsl/input_group.rb +34 -0
- data/lib/primer/forms/dsl/input_methods.rb +86 -0
- data/lib/primer/forms/dsl/multi_input.rb +58 -0
- data/lib/primer/forms/dsl/radio_button_group_input.rb +38 -0
- data/lib/primer/forms/dsl/radio_button_input.rb +37 -0
- data/lib/primer/forms/dsl/select_list_input.rb +53 -0
- data/lib/primer/forms/dsl/submit_button_input.rb +28 -0
- data/lib/primer/forms/dsl/text_area_input.rb +33 -0
- data/lib/primer/forms/dsl/text_field_input.rb +65 -0
- data/lib/primer/forms/form_control.html.erb +18 -0
- data/lib/primer/forms/form_control.rb +23 -0
- data/lib/primer/forms/form_list.html.erb +5 -0
- data/lib/primer/forms/form_list.rb +21 -0
- data/lib/primer/forms/form_reference.html.erb +3 -0
- data/lib/primer/forms/form_reference.rb +14 -0
- data/lib/primer/forms/group.html.erb +5 -0
- data/lib/primer/forms/group.rb +27 -0
- data/lib/primer/forms/hidden_field.html.erb +1 -0
- data/lib/primer/forms/hidden_field.rb +15 -0
- data/lib/primer/forms/multi.html.erb +3 -0
- data/lib/primer/forms/multi.rb +14 -0
- data/lib/primer/forms/radio_button.html.erb +14 -0
- data/lib/primer/forms/radio_button.rb +29 -0
- data/lib/primer/forms/radio_button_group.html.erb +12 -0
- data/lib/primer/forms/radio_button_group.rb +14 -0
- data/lib/primer/forms/select_list.html.erb +5 -0
- data/lib/primer/forms/select_list.rb +26 -0
- data/lib/primer/forms/separator.html.erb +1 -0
- data/lib/primer/forms/separator.rb +8 -0
- data/lib/primer/forms/spacing_wrapper.html.erb +3 -0
- data/lib/primer/forms/spacing_wrapper.rb +8 -0
- data/lib/primer/forms/submit_button.html.erb +4 -0
- data/lib/primer/forms/submit_button.rb +50 -0
- data/lib/primer/forms/text_area.html.erb +5 -0
- data/lib/primer/forms/text_area.rb +16 -0
- data/lib/primer/forms/text_field.html.erb +19 -0
- data/lib/primer/forms/text_field.rb +14 -0
- data/lib/primer/view_components/engine.rb +34 -0
- data/lib/primer/view_components/linters/argument_mappers/button.rb +2 -2
- data/lib/primer/view_components/linters/button_component_migration_counter.rb +1 -1
- data/lib/primer/view_components/linters/helpers/deprecated_components_helpers.rb +2 -8
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/rubocop/cop/primer/component_name_migration.rb +3 -0
- data/lib/rubocop/cop/primer/deprecated_arguments.rb +0 -10
- data/lib/tasks/deprecated.rake +22 -0
- data/lib/tasks/docs.rake +5 -3
- data/static/arguments.yml +148 -39
- data/static/audited_at.json +4 -2
- data/static/classes.yml +2 -1
- data/static/constants.json +44 -39
- data/static/statuses.json +7 -5
- metadata +69 -8
- data/app/components/primer/base_button.rb +0 -43
@@ -1,145 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
-
|
5
|
-
|
6
|
-
status :beta
|
7
|
-
|
8
|
-
DEFAULT_PADDING = :default
|
9
|
-
PADDING_MAPPINGS = {
|
10
|
-
DEFAULT_PADDING => "",
|
11
|
-
:condensed => "Box--condensed",
|
12
|
-
:spacious => "Box--spacious"
|
13
|
-
}.freeze
|
14
|
-
PADDING_SUGGESTION = "Perhaps you could consider using :padding options of #{PADDING_MAPPINGS.keys.to_sentence}?"
|
15
|
-
|
16
|
-
DEFAULT_ROW_SCHEME = :default
|
17
|
-
ROW_SCHEME_MAPPINGS = {
|
18
|
-
DEFAULT_ROW_SCHEME => "",
|
19
|
-
:neutral => "Box-row--gray",
|
20
|
-
:info => "Box-row--blue",
|
21
|
-
:warning => "Box-row--yellow"
|
22
|
-
}.freeze
|
23
|
-
|
24
|
-
# Optional Header.
|
25
|
-
#
|
26
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
27
|
-
# @accessibility
|
28
|
-
# When using header.title, the recommended tag is a heading tag, such as h1, h2, h3, etc.
|
29
|
-
renders_one :header, "Primer::Alpha::BorderBox::Header"
|
30
|
-
|
31
|
-
# Optional Body.
|
32
|
-
#
|
33
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
34
|
-
renders_one :body, lambda { |**system_arguments|
|
35
|
-
system_arguments[:tag] = :div
|
36
|
-
system_arguments[:classes] = class_names(
|
37
|
-
"Box-body",
|
38
|
-
system_arguments[:classes]
|
39
|
-
)
|
40
|
-
|
41
|
-
Primer::BaseComponent.new(**system_arguments)
|
42
|
-
}
|
43
|
-
|
44
|
-
# Optional Footer.
|
45
|
-
#
|
46
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
47
|
-
renders_one :footer, lambda { |**system_arguments|
|
48
|
-
system_arguments[:tag] = :div
|
49
|
-
system_arguments[:classes] = class_names(
|
50
|
-
"Box-footer",
|
51
|
-
system_arguments[:classes]
|
52
|
-
)
|
53
|
-
|
54
|
-
Primer::BaseComponent.new(**system_arguments)
|
55
|
-
}
|
56
|
-
|
57
|
-
# Use Rows to add rows with borders and maintain the same padding.
|
58
|
-
#
|
59
|
-
# @param scheme [Symbol] Color scheme. <%= one_of(Primer::BorderBoxComponent::ROW_SCHEME_MAPPINGS.keys) %>
|
60
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
61
|
-
renders_many :rows, lambda { |scheme: DEFAULT_ROW_SCHEME, **system_arguments|
|
62
|
-
system_arguments[:tag] = :li
|
63
|
-
system_arguments[:classes] = class_names(
|
64
|
-
"Box-row",
|
65
|
-
ROW_SCHEME_MAPPINGS[fetch_or_fallback(ROW_SCHEME_MAPPINGS.keys, scheme, DEFAULT_ROW_SCHEME)],
|
66
|
-
system_arguments[:classes]
|
67
|
-
)
|
68
|
-
|
69
|
-
Primer::BaseComponent.new(**system_arguments)
|
70
|
-
}
|
71
|
-
|
72
|
-
# @example Header with title, body, rows, and footer
|
73
|
-
# <%= render(Primer::BorderBoxComponent.new) do |component| %>
|
74
|
-
# <% component.header do |h| %>
|
75
|
-
# <% h.title(tag: :h2) do %>
|
76
|
-
# Header
|
77
|
-
# <% end %>
|
78
|
-
# <% end %>
|
79
|
-
# <% component.body do %>
|
80
|
-
# Body
|
81
|
-
# <% end %>
|
82
|
-
# <% component.row do %>
|
83
|
-
# <% if true %>
|
84
|
-
# Row one
|
85
|
-
# <% end %>
|
86
|
-
# <% end %>
|
87
|
-
# <% component.row do %>
|
88
|
-
# Row two
|
89
|
-
# <% end %>
|
90
|
-
# <% component.footer do %>
|
91
|
-
# Footer
|
92
|
-
# <% end %>
|
93
|
-
# <% end %>
|
94
|
-
#
|
95
|
-
# @example Padding density
|
96
|
-
# <%= render(Primer::BorderBoxComponent.new(padding: :condensed)) do |component| %>
|
97
|
-
# <% component.header do %>
|
98
|
-
# Header
|
99
|
-
# <% end %>
|
100
|
-
# <% component.body do %>
|
101
|
-
# Body
|
102
|
-
# <% end %>
|
103
|
-
# <% component.row do %>
|
104
|
-
# Row two
|
105
|
-
# <% end %>
|
106
|
-
# <% component.footer do %>
|
107
|
-
# Footer
|
108
|
-
# <% end %>
|
109
|
-
# <% end %>
|
110
|
-
#
|
111
|
-
# @example Row colors
|
112
|
-
# <%= render(Primer::BorderBoxComponent.new) do |component| %>
|
113
|
-
# <% component.row do %>
|
114
|
-
# Default
|
115
|
-
# <% end %>
|
116
|
-
# <% component.row(scheme: :neutral) do %>
|
117
|
-
# Neutral
|
118
|
-
# <% end %>
|
119
|
-
# <% component.row(scheme: :info) do %>
|
120
|
-
# Info
|
121
|
-
# <% end %>
|
122
|
-
# <% component.row(scheme: :warning) do %>
|
123
|
-
# Warning
|
124
|
-
# <% end %>
|
125
|
-
# <% end %>
|
126
|
-
#
|
127
|
-
# @param padding [Symbol] <%= one_of(Primer::BorderBoxComponent::PADDING_MAPPINGS.keys) %>
|
128
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
129
|
-
def initialize(padding: DEFAULT_PADDING, **system_arguments)
|
130
|
-
@system_arguments = deny_tag_argument(**system_arguments)
|
131
|
-
@system_arguments[:tag] = :div
|
132
|
-
@system_arguments[:classes] = class_names(
|
133
|
-
"Box",
|
134
|
-
PADDING_MAPPINGS[fetch_or_fallback(PADDING_MAPPINGS.keys, padding, DEFAULT_PADDING)],
|
135
|
-
system_arguments[:classes]
|
136
|
-
)
|
137
|
-
|
138
|
-
@system_arguments[:system_arguments_denylist] = { [:p, :pt, :pb, :pr, :pl] => PADDING_SUGGESTION }
|
139
|
-
end
|
140
|
-
|
141
|
-
def render?
|
142
|
-
rows.any? || header.present? || body.present? || footer.present?
|
143
|
-
end
|
4
|
+
class BorderBoxComponent < Primer::Beta::BorderBox
|
5
|
+
status :deprecated
|
144
6
|
end
|
145
7
|
end
|
@@ -1,4 +1,12 @@
|
|
1
|
-
|
2
|
-
<%=
|
3
|
-
|
4
|
-
|
1
|
+
<% if tooltip.present? %>
|
2
|
+
<%= render Primer::BaseComponent.new(tag: :div, position: :relative, display: :inline_block) do %>
|
3
|
+
<%= render Primer::Beta::BaseButton.new(**@system_arguments) do -%>
|
4
|
+
<%= leading_visual %><%= trimmed_content %><%= trailing_visual %><%= primer_octicon("triangle-down", ml: 2, mr: -1) if @dropdown %>
|
5
|
+
<% end -%>
|
6
|
+
<%= tooltip %>
|
7
|
+
<% end -%>
|
8
|
+
<% else %>
|
9
|
+
<%= render Primer::Beta::BaseButton.new(**@system_arguments) do -%>
|
10
|
+
<%= leading_visual %><%= trimmed_content %><%= trailing_visual %><%= primer_octicon("triangle-down", ml: 2, mr: -1) if @dropdown %>
|
11
|
+
<% end -%>
|
12
|
+
<% end %>
|
@@ -123,8 +123,8 @@ module Primer
|
|
123
123
|
# @param scheme [Symbol] <%= one_of(Primer::ButtonComponent::SCHEME_OPTIONS) %>
|
124
124
|
# @param variant [Symbol] DEPRECATED. <%= one_of(Primer::ButtonComponent::SIZE_OPTIONS) %>
|
125
125
|
# @param size [Symbol] <%= one_of(Primer::ButtonComponent::SIZE_OPTIONS) %>
|
126
|
-
# @param tag [Symbol] (Primer::BaseButton::DEFAULT_TAG) <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
|
127
|
-
# @param type [Symbol] (Primer::BaseButton::DEFAULT_TYPE) <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
|
126
|
+
# @param tag [Symbol] (Primer::Beta::BaseButton::DEFAULT_TAG) <%= one_of(Primer::Beta::BaseButton::TAG_OPTIONS) %>
|
127
|
+
# @param type [Symbol] (Primer::Beta::BaseButton::DEFAULT_TYPE) <%= one_of(Primer::Beta::BaseButton::TYPE_OPTIONS) %>
|
128
128
|
# @param group_item [Boolean] Whether button is part of a ButtonGroup.
|
129
129
|
# @param block [Boolean] Whether button is full-width with `display: block`.
|
130
130
|
# @param dropdown [Boolean] Whether or not to render a dropdown caret.
|
@@ -12,7 +12,7 @@ module Primer
|
|
12
12
|
# <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) %>
|
13
13
|
#
|
14
14
|
# @example With text instead of icons
|
15
|
-
# <%= render(Primer::ClipboardCopy.new(value: "Text to copy"
|
15
|
+
# <%= render(Primer::ClipboardCopy.new(value: "Text to copy")) do %>
|
16
16
|
# Click to copy!
|
17
17
|
# <% end %>
|
18
18
|
#
|
@@ -34,10 +34,14 @@ module Primer
|
|
34
34
|
@system_arguments[:value] = value if value.present?
|
35
35
|
end
|
36
36
|
|
37
|
+
# :nodoc:
|
38
|
+
def before_render
|
39
|
+
validate_aria_label if content.blank?
|
40
|
+
end
|
41
|
+
|
37
42
|
private
|
38
43
|
|
39
44
|
def validate!
|
40
|
-
validate_aria_label
|
41
45
|
raise ArgumentError, "Must provide either `value` or `for`" if @value.nil? && @system_arguments[:for].nil?
|
42
46
|
end
|
43
47
|
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%= render Primer::BaseComponent.new(tag: :div, position: :relative, display: :inline_block) do %>
|
2
|
+
<%= render Primer::Beta::BaseButton.new(**@system_arguments) do -%>
|
3
|
+
<%= render Primer::OcticonComponent.new(icon: @icon) %>
|
4
|
+
<% end -%>
|
5
|
+
<%= render Primer::Alpha::Tooltip.new(**@tooltip_arguments) %>
|
6
|
+
<% end %>
|
@@ -8,6 +8,7 @@ module Primer
|
|
8
8
|
# The `aria-label` should describe the action to be invoked rather than the icon itself. For instance,
|
9
9
|
# if your `IconButton` renders a magnifying glass icon and invokes a search action, the `aria-label` should be
|
10
10
|
# `"Search"` instead of `"Magnifying glass"`.
|
11
|
+
# Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
|
11
12
|
# [Learn more about best functional image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/functional)
|
12
13
|
class IconButton < Primer::Component
|
13
14
|
status :beta
|
@@ -18,9 +19,10 @@ module Primer
|
|
18
19
|
:danger => "btn-octicon-danger"
|
19
20
|
}.freeze
|
20
21
|
SCHEME_OPTIONS = SCHEME_MAPPINGS.keys
|
22
|
+
|
21
23
|
# @example Default
|
22
24
|
#
|
23
|
-
# <%= render(Primer::IconButton.new(icon: :search, "aria-label": "Search")) %>
|
25
|
+
# <%= render(Primer::IconButton.new(icon: :search, "aria-label": "Search", id: "search-button")) %>
|
24
26
|
#
|
25
27
|
# @example Schemes
|
26
28
|
#
|
@@ -29,23 +31,41 @@ module Primer
|
|
29
31
|
#
|
30
32
|
# @example In a BorderBox
|
31
33
|
#
|
32
|
-
# <%= render(Primer::
|
34
|
+
# <%= render(Primer::Beta::BorderBox.new) do |component| %>
|
33
35
|
# <% component.body do %>
|
34
36
|
# <%= render(Primer::Beta::Text.new(pr: 2)) { "Body" } %>
|
35
37
|
# <%= render(Primer::IconButton.new(icon: :pencil, box: true, "aria-label": "Edit")) %>
|
36
38
|
# <% end %>
|
37
39
|
# <% end %>
|
38
40
|
#
|
41
|
+
# @example With an `aria-description`
|
42
|
+
# @description
|
43
|
+
# If you need to have a longer description for the icon button, use both the `aria-label` and `aria-description`
|
44
|
+
# attributes. A label should be short and concise, while the description can be longer as it is intended to provide
|
45
|
+
# more context and information. See the accessibility section for more information.
|
46
|
+
# @code
|
47
|
+
# <%= render(Primer::IconButton.new(icon: :bold, "aria-label": "Bold", "aria-description": "Add bold text, Cmd+b")) %>
|
48
|
+
#
|
49
|
+
# @example Custom tooltip direction
|
50
|
+
#
|
51
|
+
# <%= render(Primer::IconButton.new(icon: :search, "aria-label": "Search", tooltip_direction: :e)) %>
|
52
|
+
#
|
39
53
|
# @param scheme [Symbol] <%= one_of(Primer::IconButton::SCHEME_OPTIONS) %>
|
40
54
|
# @param icon [String] Name of <%= link_to_octicons %> to use.
|
41
|
-
# @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
|
42
|
-
# @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
|
43
|
-
# @param
|
55
|
+
# @param tag [Symbol] <%= one_of(Primer::Beta::BaseButton::TAG_OPTIONS) %>
|
56
|
+
# @param type [Symbol] <%= one_of(Primer::Beta::BaseButton::TYPE_OPTIONS) %>
|
57
|
+
# @param aria-label [String] String that can be read by assistive technology. A label should be short and concise. See the accessibility section for more information.
|
58
|
+
# @param aria-description [String] String that can be read by assistive technology. A description can be longer as it is intended to provide more context and information. See the accessibility section for more information.
|
59
|
+
# @param tooltip_direction [Symbol] (Primer::Alpha::Tooltip::DIRECTION_DEFAULT) <%= one_of(Primer::Alpha::Tooltip::DIRECTION_OPTIONS) %>
|
60
|
+
# @param box [Boolean] Whether the button is in a <%= link_to_component(Primer::Beta::BorderBox) %>. If `true`, the button will have the `Box-btn-octicon` class.
|
44
61
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
45
|
-
def initialize(icon:, scheme: DEFAULT_SCHEME, box: false, **system_arguments)
|
62
|
+
def initialize(icon:, scheme: DEFAULT_SCHEME, box: false, tooltip_direction: Primer::Alpha::Tooltip::DIRECTION_DEFAULT, **system_arguments)
|
46
63
|
@icon = icon
|
47
64
|
|
48
65
|
@system_arguments = system_arguments
|
66
|
+
|
67
|
+
@system_arguments[:id] ||= "icon-button-#{SecureRandom.hex(4)}"
|
68
|
+
|
49
69
|
@system_arguments[:classes] = class_names(
|
50
70
|
"btn-octicon",
|
51
71
|
SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)],
|
@@ -54,11 +74,27 @@ module Primer
|
|
54
74
|
)
|
55
75
|
|
56
76
|
validate_aria_label
|
57
|
-
end
|
58
77
|
|
59
|
-
|
60
|
-
|
61
|
-
|
78
|
+
@aria_label = aria("label", @system_arguments)
|
79
|
+
@aria_description = aria("description", @system_arguments)
|
80
|
+
|
81
|
+
@tooltip_arguments = {
|
82
|
+
for_id: @system_arguments[:id],
|
83
|
+
direction: tooltip_direction
|
84
|
+
}
|
85
|
+
|
86
|
+
# If we have both an `aria-label` and a `aria-description`, we create a `Tooltip` with the description type and keep the `aria-label` in the button.
|
87
|
+
# Otherwise, the `aria-label` is used as the tooltip text, which is the `aria-labelled-by` of the button, so we don't set it in the button.
|
88
|
+
if @aria_label.present? && @aria_description.present?
|
89
|
+
@system_arguments.delete(:"aria-description")
|
90
|
+
@system_arguments[:aria].delete(:description) if @system_arguments.include?(:aria)
|
91
|
+
@tooltip_arguments[:text] = @aria_description
|
92
|
+
@tooltip_arguments[:type] = :description
|
93
|
+
else
|
94
|
+
@system_arguments.delete(:"aria-label")
|
95
|
+
@system_arguments[:aria].delete(:label) if @system_arguments.include?(:aria)
|
96
|
+
@tooltip_arguments[:text] = @aria_label
|
97
|
+
@tooltip_arguments[:type] = :label
|
62
98
|
end
|
63
99
|
end
|
64
100
|
end
|
@@ -17,6 +17,8 @@ module Primer
|
|
17
17
|
|
18
18
|
# `Tooltip` that appears on mouse hover or keyboard focus over the link. Use tooltips sparingly and as a last resort.
|
19
19
|
# **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
|
20
|
+
# The tooltip will appear adjacent to the anchor element. Both the tooltip and the anchor will be nested
|
21
|
+
# under a positioning wrapper.
|
20
22
|
# Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information.
|
21
23
|
#
|
22
24
|
# @param type [Symbol] (:description) <%= one_of(Primer::Alpha::Tooltip::TYPE_OPTIONS) %>
|
@@ -43,9 +45,6 @@ module Primer
|
|
43
45
|
# @example Without underline
|
44
46
|
# <%= render(Primer::LinkComponent.new(href: "#", underline: false)) { "Link" } %>
|
45
47
|
#
|
46
|
-
# @example Span as link
|
47
|
-
# <%= render(Primer::LinkComponent.new(tag: :span)) { "Span as a link" } %>
|
48
|
-
#
|
49
48
|
# @example With tooltip
|
50
49
|
# @description
|
51
50
|
# Use tooltips sparingly and as a last resort. Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information.
|
@@ -82,8 +81,16 @@ module Primer
|
|
82
81
|
end
|
83
82
|
|
84
83
|
def call
|
85
|
-
|
86
|
-
|
84
|
+
if tooltip.present?
|
85
|
+
render Primer::BaseComponent.new(tag: :span, position: :relative) do
|
86
|
+
render(Primer::BaseComponent.new(**@system_arguments)) do
|
87
|
+
content
|
88
|
+
end.to_s + tooltip.to_s
|
89
|
+
end
|
90
|
+
else
|
91
|
+
render(Primer::BaseComponent.new(**@system_arguments)) do
|
92
|
+
content
|
93
|
+
end
|
87
94
|
end
|
88
95
|
end
|
89
96
|
end
|
@@ -7,15 +7,12 @@ module Primer
|
|
7
7
|
class Classify
|
8
8
|
# Handler for PrimerCSS utility classes loaded from utilities.rake
|
9
9
|
class Utilities
|
10
|
-
|
11
|
-
# Disabling because we want to load symbols, strings, and integers from the .yml file
|
12
|
-
# rubocop:disable Security/YAMLLoad
|
13
|
-
UTILITIES = YAML.load(
|
10
|
+
UTILITIES = YAML.safe_load(
|
14
11
|
File.read(
|
15
12
|
File.join(File.dirname(__FILE__), "./utilities.yml")
|
16
|
-
)
|
13
|
+
),
|
14
|
+
permitted_classes: [Symbol]
|
17
15
|
).freeze
|
18
|
-
# rubocop:enable Security/YAMLLoad
|
19
16
|
|
20
17
|
BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
|
21
18
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
# :nodoc:
|
5
|
+
class FormComponents
|
6
|
+
def self.from_input(input_klass)
|
7
|
+
Class.new(Primer::Component) do
|
8
|
+
@input_klass = input_klass
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :input_klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(**system_arguments, &block)
|
15
|
+
@system_arguments = system_arguments
|
16
|
+
@block = block
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
builder = Primer::Forms::Builder.new(
|
21
|
+
nil, nil, __vc_original_view_context, {}
|
22
|
+
)
|
23
|
+
|
24
|
+
input = self.class.input_klass.new(
|
25
|
+
builder: builder,
|
26
|
+
form: nil,
|
27
|
+
**@system_arguments,
|
28
|
+
&@block
|
29
|
+
)
|
30
|
+
|
31
|
+
input.to_component.render_in(__vc_original_view_context) { content }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module Primer
|
6
|
+
module Forms
|
7
|
+
# :nodoc:
|
8
|
+
module ActsAsComponent
|
9
|
+
# :nodoc:
|
10
|
+
module InstanceMethods
|
11
|
+
delegate :render, :content_tag, :output_buffer, :capture, to: :@view_context
|
12
|
+
|
13
|
+
def render_in(view_context, &block)
|
14
|
+
@view_context = view_context
|
15
|
+
before_render
|
16
|
+
perform_render(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# :nocov:
|
20
|
+
def perform_render(&_block)
|
21
|
+
raise NotImplementedError, "subclasses must implement ##{__method__}."
|
22
|
+
end
|
23
|
+
# :nocov:
|
24
|
+
|
25
|
+
def before_render; end
|
26
|
+
|
27
|
+
# :nocov:
|
28
|
+
# rubocop:disable Naming/AccessorMethodName
|
29
|
+
def set_original_view_context(view_context)
|
30
|
+
@view_context = view_context
|
31
|
+
end
|
32
|
+
# rubocop:enable Naming/AccessorMethodName
|
33
|
+
# :nocov:
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.extended(base)
|
37
|
+
base.include(InstanceMethods)
|
38
|
+
end
|
39
|
+
|
40
|
+
TemplateGlob = Struct.new(:glob_pattern, :method_name, :on_compile_callback)
|
41
|
+
TemplateParams = Struct.new(:source, :identifier, :type, :format)
|
42
|
+
|
43
|
+
attr_accessor :template_root_path
|
44
|
+
|
45
|
+
def renders_templates(glob_pattern, method_name = nil, &block)
|
46
|
+
template_globs << TemplateGlob.new(glob_pattern, method_name, block)
|
47
|
+
end
|
48
|
+
alias renders_template renders_templates
|
49
|
+
|
50
|
+
def compile!
|
51
|
+
# always recompile in dev
|
52
|
+
return if defined?(@compiled) && @compiled && !Rails.env.development?
|
53
|
+
|
54
|
+
template_globs.each do |template_glob|
|
55
|
+
compile_templates_in(template_glob)
|
56
|
+
end
|
57
|
+
|
58
|
+
@compiled = true
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def template_globs
|
64
|
+
@template_globs ||= []
|
65
|
+
end
|
66
|
+
|
67
|
+
def compile_templates_in(template_glob)
|
68
|
+
pattern = if Pathname(template_glob.glob_pattern).absolute?
|
69
|
+
template_glob.glob_pattern
|
70
|
+
else
|
71
|
+
# skip compilation for anonymous form classes, as in tests
|
72
|
+
return unless template_root_path
|
73
|
+
|
74
|
+
File.join(template_root_path, template_glob.glob_pattern)
|
75
|
+
end
|
76
|
+
|
77
|
+
template_paths = Dir.glob(pattern)
|
78
|
+
|
79
|
+
raise "Cannot compile multiple templates with the same method name." if template_paths.size > 1 && template_glob.method_name
|
80
|
+
|
81
|
+
template_paths.each do |template_path|
|
82
|
+
method_name = template_glob.method_name
|
83
|
+
method_name ||= "render_#{File.basename(template_path).chomp('.html.erb')}"
|
84
|
+
define_template_method(template_path, method_name)
|
85
|
+
template_glob&.on_compile_callback&.call(template_path)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def define_template_method(template_path, method_name)
|
90
|
+
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
91
|
+
# rubocop:disable Style/EvalWithLocation
|
92
|
+
class_eval <<-RUBY, template_path, 0
|
93
|
+
private def #{method_name}
|
94
|
+
capture { #{compile_template(template_path)} }
|
95
|
+
end
|
96
|
+
RUBY
|
97
|
+
# rubocop:enable Style/EvalWithLocation
|
98
|
+
# rubocop:enable Style/DocumentDynamicEvalDefinition
|
99
|
+
end
|
100
|
+
|
101
|
+
def compile_template(path)
|
102
|
+
handler = ActionView::Template.handler_for_extension("erb")
|
103
|
+
template = File.read(path)
|
104
|
+
template_params = TemplateParams.new({
|
105
|
+
source: template,
|
106
|
+
identifier: __FILE__,
|
107
|
+
type: "text/html",
|
108
|
+
format: "text/html"
|
109
|
+
})
|
110
|
+
|
111
|
+
# change @output_buffer ivar to output_buffer method call
|
112
|
+
BufferRewriter.rewrite(
|
113
|
+
handler.call(template_params, template)
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|