primer_view_components 0.0.85 → 0.0.86

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -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/item.rb +1 -1
  6. data/app/components/primer/alpha/auto_complete.rb +1 -1
  7. data/app/components/primer/alpha/button_marketing.rb +1 -1
  8. data/app/components/primer/alpha/text_field.rb +105 -0
  9. data/app/components/primer/alpha/tool-tip-element.d.ts +3 -1
  10. data/app/components/primer/alpha/tool-tip-element.js +20 -13
  11. data/app/components/primer/alpha/tool-tip-element.ts +23 -14
  12. data/app/components/primer/alpha/tooltip.rb +1 -1
  13. data/app/components/primer/beta/base_button.rb +47 -0
  14. data/app/components/primer/{alpha → beta}/border_box/header.html.erb +0 -0
  15. data/app/components/primer/{alpha → beta}/border_box/header.rb +6 -6
  16. data/app/components/primer/{border_box_component.html.erb → beta/border_box.html.erb} +0 -0
  17. data/app/components/primer/beta/border_box.rb +147 -0
  18. data/app/components/primer/blankslate_component.rb +2 -150
  19. data/app/components/primer/border_box_component.rb +2 -140
  20. data/app/components/primer/button_component.html.erb +12 -4
  21. data/app/components/primer/button_component.rb +2 -2
  22. data/app/components/primer/clipboard_copy.rb +6 -2
  23. data/app/components/primer/close_button.rb +1 -1
  24. data/app/components/primer/hellip_button.rb +1 -1
  25. data/app/components/primer/icon_button.html.erb +6 -0
  26. data/app/components/primer/icon_button.rb +46 -10
  27. data/app/components/primer/link_component.html.erb +12 -0
  28. data/app/components/primer/link_component.rb +2 -9
  29. data/app/lib/primer/join_style_arguments_helper.rb +1 -1
  30. data/lib/primer/classify/utilities.rb +3 -6
  31. data/lib/primer/form_components.rb +36 -0
  32. data/lib/primer/forms/acts_as_component.rb +118 -0
  33. data/lib/primer/forms/base.html.erb +8 -0
  34. data/lib/primer/forms/base.rb +137 -0
  35. data/lib/primer/forms/base_component.rb +58 -0
  36. data/lib/primer/forms/buffer_rewriter.rb +50 -0
  37. data/lib/primer/forms/caption.html.erb +10 -0
  38. data/lib/primer/forms/caption.rb +29 -0
  39. data/lib/primer/forms/check_box.html.erb +9 -0
  40. data/lib/primer/forms/check_box.rb +16 -0
  41. data/lib/primer/forms/check_box_group.html.erb +12 -0
  42. data/lib/primer/forms/check_box_group.rb +14 -0
  43. data/lib/primer/forms/dsl/check_box_group_input.rb +41 -0
  44. data/lib/primer/forms/dsl/check_box_input.rb +27 -0
  45. data/lib/primer/forms/dsl/form_object.rb +25 -0
  46. data/lib/primer/forms/dsl/form_reference_input.rb +36 -0
  47. data/lib/primer/forms/dsl/hidden_input.rb +29 -0
  48. data/lib/primer/forms/dsl/input.rb +259 -0
  49. data/lib/primer/forms/dsl/input_group.rb +41 -0
  50. data/lib/primer/forms/dsl/input_methods.rb +86 -0
  51. data/lib/primer/forms/dsl/multi_input.rb +58 -0
  52. data/lib/primer/forms/dsl/radio_button_group_input.rb +38 -0
  53. data/lib/primer/forms/dsl/radio_button_input.rb +37 -0
  54. data/lib/primer/forms/dsl/select_list_input.rb +53 -0
  55. data/lib/primer/forms/dsl/submit_button_input.rb +28 -0
  56. data/lib/primer/forms/dsl/text_area_input.rb +33 -0
  57. data/lib/primer/forms/dsl/text_field_input.rb +65 -0
  58. data/lib/primer/forms/form_control.html.erb +18 -0
  59. data/lib/primer/forms/form_control.rb +23 -0
  60. data/lib/primer/forms/form_list.html.erb +5 -0
  61. data/lib/primer/forms/form_list.rb +21 -0
  62. data/lib/primer/forms/form_reference.html.erb +3 -0
  63. data/lib/primer/forms/form_reference.rb +14 -0
  64. data/lib/primer/forms/group.html.erb +5 -0
  65. data/lib/primer/forms/group.rb +27 -0
  66. data/lib/primer/forms/hidden_field.html.erb +1 -0
  67. data/lib/primer/forms/hidden_field.rb +15 -0
  68. data/lib/primer/forms/multi.html.erb +3 -0
  69. data/lib/primer/forms/multi.rb +14 -0
  70. data/lib/primer/forms/radio_button.html.erb +14 -0
  71. data/lib/primer/forms/radio_button.rb +29 -0
  72. data/lib/primer/forms/radio_button_group.html.erb +12 -0
  73. data/lib/primer/forms/radio_button_group.rb +14 -0
  74. data/lib/primer/forms/select_list.html.erb +5 -0
  75. data/lib/primer/forms/select_list.rb +26 -0
  76. data/lib/primer/forms/separator.html.erb +1 -0
  77. data/lib/primer/forms/separator.rb +8 -0
  78. data/lib/primer/forms/spacing_wrapper.html.erb +3 -0
  79. data/lib/primer/forms/spacing_wrapper.rb +8 -0
  80. data/lib/primer/forms/submit_button.html.erb +4 -0
  81. data/lib/primer/forms/submit_button.rb +50 -0
  82. data/lib/primer/forms/text_area.html.erb +5 -0
  83. data/lib/primer/forms/text_area.rb +16 -0
  84. data/lib/primer/forms/text_field.html.erb +19 -0
  85. data/lib/primer/forms/text_field.rb +14 -0
  86. data/lib/primer/view_components/engine.rb +23 -0
  87. data/lib/primer/view_components/linters/argument_mappers/button.rb +2 -2
  88. data/lib/primer/view_components/linters/button_component_migration_counter.rb +1 -1
  89. data/lib/primer/view_components/linters/helpers/deprecated_components_helpers.rb +2 -8
  90. data/lib/primer/view_components/version.rb +1 -1
  91. data/lib/rubocop/cop/primer/component_name_migration.rb +3 -0
  92. data/lib/tasks/deprecated.rake +22 -0
  93. data/lib/tasks/docs.rake +5 -3
  94. data/static/arguments.yml +148 -39
  95. data/static/audited_at.json +4 -2
  96. data/static/classes.yml +2 -1
  97. data/static/constants.json +44 -39
  98. data/static/statuses.json +7 -5
  99. metadata +66 -7
  100. data/app/components/primer/base_button.rb +0 -43
  101. 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
@@ -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