primer_view_components 0.0.83 → 0.0.86

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/components/primer/alpha/auto_complete/auto_complete.html.erb +24 -0
  6. data/app/components/primer/alpha/auto_complete/item.rb +46 -0
  7. data/app/components/primer/alpha/auto_complete.rb +158 -0
  8. data/app/components/primer/alpha/button_marketing.rb +1 -1
  9. data/app/components/primer/alpha/text_field.rb +105 -0
  10. data/app/components/primer/alpha/tool-tip-element.d.ts +3 -1
  11. data/app/components/primer/alpha/tool-tip-element.js +20 -13
  12. data/app/components/primer/alpha/tool-tip-element.ts +23 -14
  13. data/app/components/primer/alpha/tooltip.rb +1 -1
  14. data/app/components/primer/beta/auto_complete/auto_complete.html.erb +21 -17
  15. data/app/components/primer/beta/auto_complete/item.html.erb +21 -0
  16. data/app/components/primer/beta/auto_complete/item.rb +42 -6
  17. data/app/components/primer/beta/auto_complete.rb +93 -55
  18. data/app/components/primer/beta/base_button.rb +47 -0
  19. data/app/components/primer/{alpha → beta}/border_box/header.html.erb +0 -0
  20. data/app/components/primer/{alpha → beta}/border_box/header.rb +6 -6
  21. data/app/components/primer/{border_box_component.html.erb → beta/border_box.html.erb} +0 -0
  22. data/app/components/primer/beta/border_box.rb +147 -0
  23. data/app/components/primer/blankslate_component.rb +2 -150
  24. data/app/components/primer/border_box_component.rb +2 -140
  25. data/app/components/primer/button_component.html.erb +12 -4
  26. data/app/components/primer/button_component.rb +2 -2
  27. data/app/components/primer/clipboard_copy.rb +6 -2
  28. data/app/components/primer/close_button.rb +1 -1
  29. data/app/components/primer/conditional_wrapper.rb +36 -0
  30. data/app/components/primer/hellip_button.rb +1 -1
  31. data/app/components/primer/icon_button.html.erb +6 -0
  32. data/app/components/primer/icon_button.rb +46 -10
  33. data/app/components/primer/link_component.html.erb +12 -0
  34. data/app/components/primer/link_component.rb +2 -9
  35. data/app/lib/primer/join_style_arguments_helper.rb +1 -1
  36. data/lib/primer/classify/utilities.rb +3 -6
  37. data/lib/primer/form_components.rb +36 -0
  38. data/lib/primer/forms/acts_as_component.rb +118 -0
  39. data/lib/primer/forms/base.html.erb +8 -0
  40. data/lib/primer/forms/base.rb +137 -0
  41. data/lib/primer/forms/base_component.rb +58 -0
  42. data/lib/primer/forms/buffer_rewriter.rb +50 -0
  43. data/lib/primer/forms/caption.html.erb +10 -0
  44. data/lib/primer/forms/caption.rb +29 -0
  45. data/lib/primer/forms/check_box.html.erb +9 -0
  46. data/lib/primer/forms/check_box.rb +16 -0
  47. data/lib/primer/forms/check_box_group.html.erb +12 -0
  48. data/lib/primer/forms/check_box_group.rb +14 -0
  49. data/lib/primer/forms/dsl/check_box_group_input.rb +41 -0
  50. data/lib/primer/forms/dsl/check_box_input.rb +27 -0
  51. data/lib/primer/forms/dsl/form_object.rb +25 -0
  52. data/lib/primer/forms/dsl/form_reference_input.rb +36 -0
  53. data/lib/primer/forms/dsl/hidden_input.rb +29 -0
  54. data/lib/primer/forms/dsl/input.rb +259 -0
  55. data/lib/primer/forms/dsl/input_group.rb +41 -0
  56. data/lib/primer/forms/dsl/input_methods.rb +86 -0
  57. data/lib/primer/forms/dsl/multi_input.rb +58 -0
  58. data/lib/primer/forms/dsl/radio_button_group_input.rb +38 -0
  59. data/lib/primer/forms/dsl/radio_button_input.rb +37 -0
  60. data/lib/primer/forms/dsl/select_list_input.rb +53 -0
  61. data/lib/primer/forms/dsl/submit_button_input.rb +28 -0
  62. data/lib/primer/forms/dsl/text_area_input.rb +33 -0
  63. data/lib/primer/forms/dsl/text_field_input.rb +65 -0
  64. data/lib/primer/forms/form_control.html.erb +18 -0
  65. data/lib/primer/forms/form_control.rb +23 -0
  66. data/lib/primer/forms/form_list.html.erb +5 -0
  67. data/lib/primer/forms/form_list.rb +21 -0
  68. data/lib/primer/forms/form_reference.html.erb +3 -0
  69. data/lib/primer/forms/form_reference.rb +14 -0
  70. data/lib/primer/forms/group.html.erb +5 -0
  71. data/lib/primer/forms/group.rb +27 -0
  72. data/lib/primer/forms/hidden_field.html.erb +1 -0
  73. data/lib/primer/forms/hidden_field.rb +15 -0
  74. data/lib/primer/forms/multi.html.erb +3 -0
  75. data/lib/primer/forms/multi.rb +14 -0
  76. data/lib/primer/forms/radio_button.html.erb +14 -0
  77. data/lib/primer/forms/radio_button.rb +29 -0
  78. data/lib/primer/forms/radio_button_group.html.erb +12 -0
  79. data/lib/primer/forms/radio_button_group.rb +14 -0
  80. data/lib/primer/forms/select_list.html.erb +5 -0
  81. data/lib/primer/forms/select_list.rb +26 -0
  82. data/lib/primer/forms/separator.html.erb +1 -0
  83. data/lib/primer/forms/separator.rb +8 -0
  84. data/lib/primer/forms/spacing_wrapper.html.erb +3 -0
  85. data/lib/primer/forms/spacing_wrapper.rb +8 -0
  86. data/lib/primer/forms/submit_button.html.erb +4 -0
  87. data/lib/primer/forms/submit_button.rb +50 -0
  88. data/lib/primer/forms/text_area.html.erb +5 -0
  89. data/lib/primer/forms/text_area.rb +16 -0
  90. data/lib/primer/forms/text_field.html.erb +19 -0
  91. data/lib/primer/forms/text_field.rb +14 -0
  92. data/lib/primer/view_components/engine.rb +23 -0
  93. data/lib/primer/view_components/linters/argument_mappers/button.rb +2 -2
  94. data/lib/primer/view_components/linters/button_component_migration_counter.rb +1 -1
  95. data/lib/primer/view_components/linters/helpers/deprecated_components_helpers.rb +4 -8
  96. data/lib/primer/view_components/version.rb +1 -1
  97. data/lib/rubocop/cop/primer/component_name_migration.rb +3 -0
  98. data/lib/tasks/deprecated.rake +22 -0
  99. data/lib/tasks/docs.rake +8 -6
  100. data/static/arguments.yml +188 -52
  101. data/static/audited_at.json +7 -2
  102. data/static/classes.yml +25 -8
  103. data/static/constants.json +66 -39
  104. data/static/statuses.json +8 -3
  105. metadata +71 -7
  106. data/app/components/primer/base_button.rb +0 -43
  107. data/app/components/primer/blankslate_component.html.erb +0 -30
@@ -1,156 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use `Blankslate` when there is a lack of content within a page or section. Use as placeholder to tell users why something isn't there.
5
- # @accessibility
6
- # `Blankslate` renders an `<h3>` element for the title by default. Update the heading level based on what is appropriate for your page hierarchy by setting `title_tag`.
7
- # <%= link_to_heading_practices %>
8
- class BlankslateComponent < Primer::Component
4
+ # BlankslateComponent is deprecated. Please use `Primer::Beta::Blankslate` instead.
5
+ class BlankslateComponent < Primer::Beta::Blankslate
9
6
  status :deprecated
10
-
11
- # Optional Spinner.
12
- #
13
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::SpinnerComponent) %>.
14
- renders_one :spinner, lambda { |**system_arguments|
15
- system_arguments[:mb] ||= 3
16
- Primer::SpinnerComponent.new(**system_arguments)
17
- }
18
-
19
- #
20
- # @example Basic
21
- # <%= render Primer::BlankslateComponent.new(
22
- # title: "Title",
23
- # description: "Description",
24
- # ) %>
25
- #
26
- # @example Icon
27
- # @description
28
- # Add an `icon` to give additional context. Refer to the [Octicons](https://primer.style/octicons/) documentation to choose an icon.
29
- # @code
30
- # <%= render Primer::BlankslateComponent.new(
31
- # icon: :globe,
32
- # title: "Title",
33
- # description: "Description",
34
- # ) %>
35
- #
36
- # @example Loading
37
- # @description
38
- # Add a [SpinnerComponent](https://primer.style/view-components/components/spinner) to the blankslate in place of an icon.
39
- # @code
40
- # <%= render Primer::BlankslateComponent.new(
41
- # title: "Title",
42
- # description: "Description",
43
- # ) do |component| %>
44
- # <% component.spinner(size: :large) %>
45
- # <% end %>
46
- #
47
- # @example Custom content
48
- # @description
49
- # Pass custom content as a block in place of `description`.
50
- # @code
51
- # <%= render Primer::BlankslateComponent.new(
52
- # title: "Title",
53
- # ) do %>
54
- # <em>Your custom content here</em>
55
- # <% end %>
56
- #
57
- # @example Action button
58
- # @description
59
- # Provide a button to guide users to take action from the blankslate. The button appears below the description and custom content.
60
- # @code
61
- # <%= render Primer::BlankslateComponent.new(
62
- # icon: :book,
63
- # title: "Welcome to the mona wiki!",
64
- # description: "Wikis provide a place in your repository to lay out the roadmap of your project, show the current status, and document software better, together.",
65
- #
66
- # button_text: "Create the first page",
67
- # button_url: "https://github.com/monalisa/mona/wiki/_new",
68
- # ) %>
69
- #
70
- # @example Link
71
- # @description
72
- # Add an additional link to help users learn more about a feature. The link will be shown at the very bottom:
73
- # @code
74
- # <%= render Primer::BlankslateComponent.new(
75
- # icon: :book,
76
- # title: "Welcome to the mona wiki!",
77
- # description: "Wikis provide a place in your repository to lay out the roadmap of your project, show the current status, and document software better, together.",
78
- # link_text: "Learn more about wikis",
79
- # link_url: "https://docs.github.com/en/github/building-a-strong-community/about-wikis",
80
- # ) %>
81
- #
82
- # @example Variations
83
- # @description
84
- # There are a few variations of how the Blankslate appears: `narrow` adds a maximum width, `large` increases the font size, and `spacious` adds extra padding.
85
- # @code
86
- # <%= render Primer::BlankslateComponent.new(
87
- # icon: :book,
88
- # title: "Welcome to the mona wiki!",
89
- # description: "Wikis provide a place in your repository to lay out the roadmap of your project, show the current status, and document software better, together.",
90
- # narrow: true,
91
- # large: true,
92
- # spacious: true,
93
- # ) %>
94
- #
95
- # @param title [String] Text that appears in a larger bold font.
96
- # @param title_tag [Symbol] HTML tag to use for title.
97
- # @param icon [Symbol] Octicon icon to use at top of component.
98
- # @param icon_size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS, sort: false) %>
99
- # @param image_src [String] Image to display.
100
- # @param image_alt [String] Alt text for image.
101
- # @param description [String] Text that appears below the title. Typically a whole sentence.
102
- # @param button_text [String] The text of the button.
103
- # @param button_url [String] The URL where the user will be taken after clicking the button.
104
- # @param button_classes [String] Classes to apply to action button
105
- # @param link_text [String] The text of the link.
106
- # @param link_url [String] The URL where the user will be taken after clicking the link.
107
- # @param narrow [Boolean] Adds a maximum width.
108
- # @param large [Boolean] Increases the font size.
109
- # @param spacious [Boolean] Adds extra padding.
110
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
111
- def initialize(
112
- title: "",
113
- title_tag: :h3,
114
- icon: "",
115
- icon_size: :medium,
116
- image_src: "",
117
- image_alt: " ",
118
- description: "",
119
- button_text: "",
120
- button_url: "",
121
- button_classes: "btn-primary my-3",
122
- link_text: "",
123
- link_url: "",
124
-
125
- # variations
126
- narrow: false,
127
- large: false,
128
- spacious: false,
129
-
130
- **system_arguments
131
- )
132
- @system_arguments = system_arguments
133
- @system_arguments[:tag] = :div
134
- @system_arguments[:classes] = class_names(
135
- @system_arguments[:classes],
136
- "blankslate",
137
- "blankslate-narrow": narrow,
138
- "blankslate-large": large,
139
- "blankslate-spacious": spacious
140
- )
141
-
142
- @title_tag = title_tag
143
- @icon = icon
144
- @icon_size = icon_size
145
- @image_src = image_src
146
- @image_alt = image_alt
147
- @title = title
148
- @description = description
149
- @button_text = button_text
150
- @button_url = button_url
151
- @button_classes = button_classes
152
- @link_text = link_text
153
- @link_url = link_url
154
- end
155
7
  end
156
8
  end
@@ -1,145 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # `BorderBox` is a Box component with a border.
5
- class BorderBoxComponent < Primer::Component
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
- <%= render Primer::BaseButton.new(**@system_arguments) do -%>
2
- <%= leading_visual %><%= trimmed_content %><%= trailing_visual %><%= primer_octicon("triangle-down", ml: 2, mr: -1) if @dropdown %>
3
- <%= tooltip %>
4
- <% end -%>
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", "aria-label": "Copy text to the system clipboard")) do %>
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
@@ -31,7 +31,7 @@ module Primer
31
31
  end
32
32
 
33
33
  def call
34
- render(Primer::BaseButton.new(**@system_arguments)) do
34
+ render(Primer::Beta::BaseButton.new(**@system_arguments)) do
35
35
  render(Primer::OcticonComponent.new("x"))
36
36
  end
37
37
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Conditionally renders a `Primer::BaseComponent` around the given content. If the given condition
5
+ # is true, a `Primer::BaseComponent` will render around the content. If the condition is false, only
6
+ # the content is rendered.
7
+ #
8
+ # @example True conditional
9
+ # <%# condition is true, so content will be wrapped in a <span> tag
10
+ # <%= render Primer::ConditionalWrapper.new(condition: true, tag: :span, class: "foobar")) do %>
11
+ # <%# also rendered %>
12
+ # <p class="bazboo">Some text</p>
13
+ # <% end %>
14
+ #
15
+ # @example False conditional
16
+ # <%# condition is false so no <span> tag will render around the content (i.e. the <p> tag)
17
+ # <%= render(Primer::ConditionalWrapper.new(condition: false, tag: :span, class: "foobar")) do %>
18
+ # <%# this content will be rendered %>
19
+ # <p class="bazboo">Some text</p>
20
+ # <% end %>
21
+ #
22
+ # @param condition [Boolean] Whether or not to wrap the content in a `Primer::BaseComponent`.
23
+ # @param base_component_arguments [Hash] The arguments to pass to `Primer::BaseComponent`.
24
+ class ConditionalWrapper < Primer::Component
25
+ def initialize(condition:, **base_component_arguments)
26
+ @condition = condition
27
+ @base_component_arguments = base_component_arguments
28
+ end
29
+
30
+ def call
31
+ return content unless @condition
32
+
33
+ BaseComponent.new(**@base_component_arguments).render_in(self) { content }
34
+ end
35
+ end
36
+ end
@@ -33,7 +33,7 @@ module Primer
33
33
  end
34
34
 
35
35
  def call
36
- render(Primer::BaseButton.new(**@system_arguments)) { "&hellip;".html_safe }
36
+ render(Primer::Beta::BaseButton.new(**@system_arguments)) { "&hellip;".html_safe }
37
37
  end
38
38
  end
39
39
  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::BorderBoxComponent.new) do |component| %>
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 box [Boolean] Whether the button is in a <%= link_to_component(Primer::BorderBoxComponent) %>. If `true`, the button will have the `Box-btn-octicon` class.
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
- def call
60
- render(Primer::BaseButton.new(**@system_arguments)) do
61
- render(Primer::OcticonComponent.new(icon: @icon))
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
@@ -0,0 +1,12 @@
1
+ <% if tooltip.present? %>
2
+ <%= render Primer::BaseComponent.new(tag: :span, position: :relative) do %>
3
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
4
+ <% content %>
5
+ <% end %>
6
+ <%= tooltip %>
7
+ <% end %>
8
+ <% else %>
9
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
10
+ <% content %>
11
+ <% end %>
12
+ <% 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.
@@ -80,11 +79,5 @@ module Primer
80
79
  def before_render
81
80
  raise ArgumentError, "href is required when using <a> tag" if @system_arguments[:tag] == :a && @system_arguments[:href].nil? && !Rails.env.production?
82
81
  end
83
-
84
- def call
85
- render(Primer::BaseComponent.new(**@system_arguments)) do
86
- content.to_s + tooltip.to_s
87
- end
88
- end
89
82
  end
90
83
  end
@@ -8,7 +8,7 @@ module Primer
8
8
  # join_style_arguments("width: 100%", "height: 100%") =>
9
9
  # "width: 100%;height: 100%"
10
10
  def join_style_arguments(*args)
11
- args.compact.join(";")
11
+ args.compact.map { |a| a.strip.chomp(";") }.join(";")
12
12
  end
13
13
  end
14
14
  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
- # Load the utilities.yml file.
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 = ActionView::Helpers::FormBuilder.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.render_in(__vc_original_view_context) { content }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end