primer_view_components 0.0.38 → 0.0.43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +283 -27
  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/auto_complete.rb +4 -2
  6. data/app/components/primer/auto_complete/item.rb +1 -1
  7. data/app/components/primer/avatar_component.rb +22 -3
  8. data/app/components/primer/avatar_stack_component.rb +8 -5
  9. data/app/components/primer/base_button.rb +1 -1
  10. data/app/components/primer/base_component.rb +24 -13
  11. data/app/components/primer/blankslate_component.html.erb +1 -0
  12. data/app/components/primer/blankslate_component.rb +68 -47
  13. data/app/components/primer/border_box_component.rb +1 -1
  14. data/app/components/primer/box_component.rb +1 -1
  15. data/app/components/primer/breadcrumb_component.rb +1 -1
  16. data/app/components/primer/button_component.html.erb +9 -0
  17. data/app/components/primer/button_component.rb +39 -5
  18. data/app/components/primer/button_group.rb +3 -3
  19. data/app/components/primer/button_marketing_component.rb +1 -1
  20. data/app/components/primer/clipboard_copy.rb +1 -1
  21. data/app/components/primer/clipboard_copy_component.js +17 -8
  22. data/app/components/primer/clipboard_copy_component.ts +19 -8
  23. data/app/components/primer/close_button.rb +4 -2
  24. data/app/components/primer/component.rb +22 -3
  25. data/app/components/primer/counter_component.rb +6 -1
  26. data/app/components/primer/details_component.rb +1 -1
  27. data/app/components/primer/dropdown/menu_component.rb +1 -1
  28. data/app/components/primer/dropdown_component.rb +1 -1
  29. data/app/components/primer/flash_component.rb +3 -3
  30. data/app/components/primer/flex_component.rb +28 -1
  31. data/app/components/primer/flex_item_component.rb +20 -1
  32. data/app/components/primer/heading_component.rb +12 -19
  33. data/app/components/primer/hidden_text_expander.rb +4 -4
  34. data/app/components/primer/icon_button.rb +65 -0
  35. data/app/components/primer/image.rb +46 -0
  36. data/app/components/primer/image_crop.d.ts +1 -0
  37. data/app/components/primer/image_crop.html.erb +12 -0
  38. data/app/components/primer/image_crop.js +1 -0
  39. data/app/components/primer/image_crop.rb +36 -0
  40. data/app/components/primer/image_crop.ts +1 -0
  41. data/app/components/primer/label_component.rb +7 -3
  42. data/app/components/primer/layout_component.rb +1 -1
  43. data/app/components/primer/link_component.rb +1 -1
  44. data/app/components/primer/local_time.d.ts +1 -0
  45. data/app/components/primer/local_time.js +1 -0
  46. data/app/components/primer/local_time.rb +59 -0
  47. data/app/components/primer/local_time.ts +1 -0
  48. data/app/components/primer/{markdown_component.rb → markdown.rb} +12 -7
  49. data/app/components/primer/menu_component.rb +1 -1
  50. data/app/components/primer/navigation/tab_component.rb +8 -1
  51. data/app/components/primer/octicon_component.html.erb +7 -0
  52. data/app/components/primer/octicon_component.rb +53 -19
  53. data/app/components/primer/octicon_symbols_component.html.erb +3 -0
  54. data/app/components/primer/octicon_symbols_component.rb +61 -0
  55. data/app/components/primer/popover_component.rb +1 -1
  56. data/app/components/primer/primer.d.ts +2 -0
  57. data/app/components/primer/primer.js +2 -0
  58. data/app/components/primer/primer.ts +2 -0
  59. data/app/components/primer/progress_bar_component.rb +1 -1
  60. data/app/components/primer/spinner_component.rb +3 -3
  61. data/app/components/primer/state_component.rb +1 -1
  62. data/app/components/primer/subhead_component.rb +34 -4
  63. data/app/components/primer/tab_container_component.rb +1 -1
  64. data/app/components/primer/tab_nav_component.html.erb +5 -1
  65. data/app/components/primer/tab_nav_component.rb +63 -10
  66. data/app/components/primer/text_component.rb +6 -3
  67. data/app/components/primer/time_ago_component.rb +1 -1
  68. data/app/components/primer/timeline_item_component.rb +1 -1
  69. data/app/components/primer/{tooltip_component.rb → tooltip.rb} +11 -9
  70. data/app/components/primer/truncate.rb +7 -3
  71. data/app/components/primer/underline_nav_component.html.erb +1 -1
  72. data/app/components/primer/underline_nav_component.rb +18 -2
  73. data/app/lib/primer/classify.rb +27 -39
  74. data/app/lib/primer/classify/cache.rb +35 -15
  75. data/app/lib/primer/classify/flex.rb +111 -0
  76. data/app/lib/primer/classify/functional_border_colors.rb +1 -2
  77. data/app/lib/primer/classify/grid.rb +45 -0
  78. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -2
  79. data/app/lib/primer/octicon/cache.rb +42 -0
  80. data/app/lib/primer/tabbed_component_helper.rb +2 -2
  81. data/app/lib/primer/view_helper.rb +2 -1
  82. data/lib/primer/view_components.rb +1 -1
  83. data/lib/primer/view_components/engine.rb +2 -0
  84. data/lib/primer/view_components/linters.rb +3 -0
  85. data/lib/primer/view_components/linters/button_component_migration_counter.rb +16 -0
  86. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +16 -0
  87. data/lib/primer/view_components/linters/helpers.rb +89 -0
  88. data/lib/primer/view_components/version.rb +1 -1
  89. data/lib/tasks/coverage.rake +14 -0
  90. data/lib/tasks/docs.rake +372 -0
  91. data/lib/tasks/statuses.rake +12 -0
  92. data/lib/yard/docs_helper.rb +57 -0
  93. data/static/statuses.json +54 -1
  94. metadata +62 -11
  95. data/app/components/primer/button_component.rb.orig +0 -138
  96. data/app/components/primer/foo_bar.d.ts +0 -1
  97. data/app/components/primer/foo_bar.js +0 -1
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use ButtonGroup to render a series of buttons.
4
+ # Use `ButtonGroup` to render a series of buttons.
5
5
  class ButtonGroup < Primer::Component
6
6
  status :beta
7
7
 
@@ -22,7 +22,7 @@ module Primer
22
22
  # <% component.button(scheme: :primary) { "Primary" } %>
23
23
  # <% component.button(scheme: :danger) { "Danger" } %>
24
24
  # <% component.button(scheme: :outline) { "Outline" } %>
25
- # <% component.button(classes: "my-class") { "Custom class" } %>
25
+ # <% component.button(classes: "custom-class") { "Custom class" } %>
26
26
  # <% end %>
27
27
  #
28
28
  # @example Variants
@@ -46,7 +46,7 @@ module Primer
46
46
  def initialize(variant: Primer::ButtonComponent::DEFAULT_VARIANT, **system_arguments)
47
47
  @variant = variant
48
48
  @system_arguments = system_arguments
49
- @system_arguments[:tag] ||= :div
49
+ @system_arguments[:tag] = :div
50
50
 
51
51
  @system_arguments[:classes] = class_names(
52
52
  "BtnGroup",
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use buttons for actions (e.g. in forms). Use links for destinations, or moving from one page to another.
4
+ # Use `ButtonMarketing` for actions (e.g. in forms). Use links for destinations, or moving from one page to another.
5
5
  class ButtonMarketingComponent < Primer::Component
6
6
  DEFAULT_SCHEME = :default
7
7
  SCHEME_MAPPINGS = {
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use ClipboardCopy to copy element text content or input values to the clipboard.
4
+ # Use `ClipboardCopy` to copy element text content or input values to the clipboard.
5
5
  class ClipboardCopy < Primer::Component
6
6
  status :alpha
7
7
 
@@ -1,4 +1,5 @@
1
1
  import '@github/clipboard-copy-element';
2
+ const CLIPBOARD_COPY_TIMER_DURATION = 2000;
2
3
  function toggleSVG(svg) {
3
4
  if (svg.style.display === '' || svg.style.display === 'block') {
4
5
  svg.style.display = 'none';
@@ -10,16 +11,24 @@ function toggleSVG(svg) {
10
11
  // Toggle a copy button.
11
12
  function toggleCopyButton(button) {
12
13
  const [clippyIcon, checkIcon] = button.querySelectorAll('.octicon');
13
- if (clippyIcon) {
14
- toggleSVG(clippyIcon);
15
- }
16
- if (checkIcon) {
17
- toggleSVG(checkIcon);
18
- }
14
+ if (!clippyIcon || !checkIcon)
15
+ return;
16
+ toggleSVG(clippyIcon);
17
+ toggleSVG(checkIcon);
19
18
  }
19
+ const clipboardCopyElementTimers = new WeakMap();
20
20
  document.addEventListener('clipboard-copy', function ({ target }) {
21
21
  if (!(target instanceof HTMLElement))
22
22
  return;
23
- toggleCopyButton(target);
24
- setTimeout(toggleCopyButton, 2000, target);
23
+ if (!target.hasAttribute('data-view-component'))
24
+ return;
25
+ const currentTimeout = clipboardCopyElementTimers.get(target);
26
+ if (currentTimeout) {
27
+ clearTimeout(currentTimeout);
28
+ clipboardCopyElementTimers.delete(target);
29
+ }
30
+ else {
31
+ toggleCopyButton(target);
32
+ }
33
+ clipboardCopyElementTimers.set(target, setTimeout(toggleCopyButton, CLIPBOARD_COPY_TIMER_DURATION, target));
25
34
  });
@@ -1,5 +1,7 @@
1
1
  import '@github/clipboard-copy-element'
2
2
 
3
+ const CLIPBOARD_COPY_TIMER_DURATION = 2000
4
+
3
5
  function toggleSVG(svg: SVGElement) {
4
6
  if (svg.style.display === '' || svg.style.display === 'block') {
5
7
  svg.style.display = 'none'
@@ -12,17 +14,26 @@ function toggleSVG(svg: SVGElement) {
12
14
  function toggleCopyButton(button: HTMLElement) {
13
15
  const [clippyIcon, checkIcon] = button.querySelectorAll<SVGElement>('.octicon')
14
16
 
15
- if (clippyIcon) {
16
- toggleSVG(clippyIcon)
17
- }
18
- if (checkIcon) {
19
- toggleSVG(checkIcon)
20
- }
17
+ if (!clippyIcon || !checkIcon) return
18
+
19
+ toggleSVG(clippyIcon)
20
+ toggleSVG(checkIcon)
21
21
  }
22
22
 
23
+ const clipboardCopyElementTimers = new WeakMap<HTMLElement, number>()
24
+
23
25
  document.addEventListener('clipboard-copy', function ({target}) {
24
26
  if (!(target instanceof HTMLElement)) return
25
- toggleCopyButton(target)
27
+ if (!target.hasAttribute('data-view-component')) return
28
+
29
+ const currentTimeout = clipboardCopyElementTimers.get(target)
30
+
31
+ if (currentTimeout) {
32
+ clearTimeout(currentTimeout)
33
+ clipboardCopyElementTimers.delete(target)
34
+ } else {
35
+ toggleCopyButton(target)
36
+ }
26
37
 
27
- setTimeout(toggleCopyButton, 2000, target)
38
+ clipboardCopyElementTimers.set(target, setTimeout(toggleCopyButton, CLIPBOARD_COPY_TIMER_DURATION, target))
28
39
  })
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use CloseButton to render an `×` without default button styles.
4
+ # Use `CloseButton` to render an `×` without default button styles.
5
5
  #
6
6
  # @accessibility
7
- # CloseButton has a default `aria-label` of "Close" to provides assistive technologies with an accessible label.
7
+ # `CloseButton` has a default `aria-label` of "Close" to provides assistive technologies with an accessible label.
8
8
  # You may choose to override this label with something more descriptive via [system_arguments][0].
9
9
  # [0]: https://primer.style/view-components/system-arguments#html-attributes
10
10
  class CloseButton < Primer::Component
11
+ status :beta
12
+
11
13
  DEFAULT_TYPE = :button
12
14
  TYPE_OPTIONS = [DEFAULT_TYPE, :submit].freeze
13
15
 
@@ -1,18 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "octicons_helper/helper"
4
3
  require "view_component/version"
5
4
 
6
5
  module Primer
7
6
  # @private
8
7
  class Component < ViewComponent::Base
9
- include ViewComponent::SlotableV2 unless ViewComponent::VERSION::STRING.to_f >= 2.28
8
+ include ViewComponent::SlotableV2 unless ViewComponent::Base < ViewComponent::SlotableV2
10
9
  include ClassNameHelper
11
10
  include FetchOrFallbackHelper
12
- include OcticonsHelper
13
11
  include TestSelectorHelper
14
12
  include JoinStyleArgumentsHelper
15
13
  include ViewHelper
16
14
  include Status::Dsl
15
+
16
+ private
17
+
18
+ def deprecated_component_warning(new_class: nil, version: nil)
19
+ return if Rails.env.production? || silence_deprecations?
20
+
21
+ message = "#{self.class.name} is deprecated"
22
+ message += " and will be removed in v#{version}." if version
23
+ message += " Use #{new_class.name} instead." if new_class
24
+
25
+ ActiveSupport::Deprecation.warn(message)
26
+ end
27
+
28
+ def validate_aria_label
29
+ aria_label = @system_arguments[:"aria-label"] || @system_arguments.dig(:aria, :label)
30
+ raise ArgumentError, "`aria-label` is required." if aria_label.nil? && !Rails.env.production?
31
+ end
32
+
33
+ def silence_deprecations?
34
+ Rails.application.config.primer_view_components.silence_deprecations
35
+ end
17
36
  end
18
37
  end
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use Primer::CounterComponent to add a count to navigational elements and buttons.
4
+ # Use `Counter` to add a count to navigational elements and buttons.
5
+ #
6
+ # @accessibility
7
+ # Always use `Counter` with adjacent text that provides supplementary information regarding what the count is for. For instance, `Counter`
8
+ # should be accompanied with text such as `issues` or `pull requests`.
9
+ #
5
10
  class CounterComponent < Primer::Component
6
11
  status :beta
7
12
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use DetailsComponent to reveal content after clicking a button.
4
+ # Use `DetailsComponent` to reveal content after clicking a button.
5
5
  class DetailsComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Primer
4
4
  module Dropdown
5
- # This component is part of `Primer::DropdownComponent` and should not be
5
+ # This component is part of `Dropdown` and should not be
6
6
  # used as a standalone component.
7
7
  class MenuComponent < Primer::Component
8
8
  SCHEME_DEFAULT = :default
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Dropdowns are lightweight context menus for housing navigation and actions.
4
+ # `Dropdown` is a lightweight context menu for housing navigation and actions.
5
5
  # They're great for instances where you don't need the full power (and code) of the select menu.
6
6
  class DropdownComponent < Primer::Component
7
7
  # Required trigger for the dropdown. Only accepts a content.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use the Flash component to inform users of successful or pending actions.
4
+ # Use `Flash` to inform users of successful or pending actions.
5
5
  class FlashComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -35,7 +35,7 @@ module Primer
35
35
  # <%= render(Primer::FlashComponent.new(dismissible: true)) { "This is a dismissible flash message!" } %>
36
36
  #
37
37
  # @example Icon
38
- # <%= render(Primer::FlashComponent.new(icon: "people")) { "This is a flash message with an icon!" } %>
38
+ # <%= render(Primer::FlashComponent.new(icon: :people)) { "This is a flash message with an icon!" } %>
39
39
  #
40
40
  # @example With actions
41
41
  # <%= render(Primer::FlashComponent.new) do |component| %>
@@ -48,7 +48,7 @@ module Primer
48
48
  # @param full [Boolean] Whether the component should take up the full width of the screen.
49
49
  # @param spacious [Boolean] Whether to add margin to the bottom of the component.
50
50
  # @param dismissible [Boolean] Whether the component can be dismissed with an X button.
51
- # @param icon [String] Name of Octicon icon to use.
51
+ # @param icon [Symbol] Name of Octicon icon to use.
52
52
  # @param scheme [Symbol] <%= one_of(Primer::FlashComponent::SCHEME_MAPPINGS.keys) %>
53
53
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
54
54
  def initialize(full: false, spacious: false, dismissible: false, icon: nil, scheme: DEFAULT_SCHEME, **system_arguments)
@@ -1,11 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use FlexComponent to make an element lay out its content using the flexbox model.
4
+ # Use `Flex` to make an element lay out its content using the flexbox model.
5
5
  # Before using these utilities, you should be familiar with CSS3 Flexible Box
6
6
  # spec. If you are not, check out MDN's guide [Using CSS Flexible
7
7
  # Boxes](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox).
8
+ #
9
+ # @deprecated
10
+ # Use <%= link_to_component(Primer::BoxComponent) %> instead.
11
+ #
12
+ # **Before**:
13
+ #
14
+ # ```erb
15
+ # <%%= render Primer::FlexComponent.new(justify_content: :center) %>
16
+ # <%%= render Primer::FlexComponent.new(inline: true) %>
17
+ # <%%= render Primer::FlexComponent.new(flex_wrap: true) %>
18
+ # <%%= render Primer::FlexComponent.new(align_items: :start) %>
19
+ # <%%= render Primer::FlexComponent.new(direction: :column) %>
20
+ # ```
21
+ #
22
+ # **After**:
23
+ #
24
+ # ```erb
25
+ # <%%= render Primer::BoxComponent.new(display: :flex, justify_content: :center) %>
26
+ # <%%= render Primer::BoxComponent.new(display: :inline_flex) %>
27
+ # <%%= render Primer::BoxComponent.new(display: :flex, flex_wrap: :wrap) %>
28
+ # <%%= render Primer::BoxComponent.new(display: :flex, align_items: :start) %>
29
+ # <%%= render Primer::BoxComponent.new(display: :flex, direction: :column) %>
30
+ # ```
8
31
  class FlexComponent < Primer::Component
32
+ status :deprecated
33
+
9
34
  JUSTIFY_CONTENT_DEFAULT = nil
10
35
  JUSTIFY_CONTENT_MAPPINGS = {
11
36
  flex_start: "flex-justify-start",
@@ -77,6 +102,8 @@ module Primer
77
102
  direction: nil,
78
103
  **system_arguments
79
104
  )
105
+ deprecated_component_warning(new_class: Primer::BoxComponent, version: "0.0.40")
106
+
80
107
  @align_items = fetch_or_fallback(ALIGN_ITEMS_OPTIONS, align_items, ALIGN_ITEMS_DEFAULT)
81
108
  @justify_content = fetch_or_fallback(JUSTIFY_CONTENT_OPTIONS, justify_content, JUSTIFY_CONTENT_DEFAULT)
82
109
  @flex_wrap = fetch_or_fallback(FLEX_WRAP_OPTIONS, flex_wrap, FLEX_WRAP_DEFAULT)
@@ -1,9 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use FlexItemComponent to specify the ability of a flex item to alter its
4
+ # Use `FlexItem` to specify the ability of a flex item to alter its
5
5
  # dimensions to fill available space
6
+ #
7
+ # @deprecated
8
+ # Use <%= link_to_component(Primer::BoxComponent) %> instead.
9
+ #
10
+ # **Before**:
11
+ #
12
+ # ```erb
13
+ # <%%= render Primer::FlexItemComponent.new(flex_auto: :auto) %>
14
+ # ```
15
+ #
16
+ # **After**:
17
+ #
18
+ # ```erb
19
+ # <%%= render Primer::BoxComponent.new(flex: :auto) %>
20
+ # ```
6
21
  class FlexItemComponent < Primer::Component
22
+ status :deprecated
23
+
7
24
  FLEX_AUTO_DEFAULT = false
8
25
  FLEX_AUTO_ALLOWED_VALUES = [FLEX_AUTO_DEFAULT, true].freeze
9
26
 
@@ -21,6 +38,8 @@ module Primer
21
38
  # @param flex_auto [Boolean] Fills available space and auto-sizes based on the content. Defaults to <%= Primer::FlexItemComponent::FLEX_AUTO_DEFAULT %>
22
39
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
23
40
  def initialize(flex_auto: FLEX_AUTO_DEFAULT, **system_arguments)
41
+ deprecated_component_warning(new_class: Primer::BoxComponent, version: "0.0.40")
42
+
24
43
  @system_arguments = system_arguments
25
44
  @system_arguments[:classes] =
26
45
  class_names(
@@ -1,20 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Heading can be used to communicate page organization and hierarchy.
4
+ # `Heading` should be used to communicate page organization and hierarchy.
5
5
  #
6
- # - Set tag to one of `:h1`, `:h2`, `:h3`, `:h4`, `:h5`, `:h6` based on what is
7
- # appropriate for the page context.
8
- # - Use Heading as the title of a section or sub section.
9
- # - Do not use Heading for styling alone. To style text without conveying heading semantics,
10
- # consider using <%= link_to_component(Primer::TextComponent) %> with relevant <%= link_to_typography_docs %>.
11
- # - Do not jump heading levels. For instance, do not follow a `<h1>` with an `<h3>`. Heading levels should
12
- # increase by one in ascending order.
6
+ # - Set tag to one of `:h1`, `:h2`, `:h3`, `:h4`, `:h5`, `:h6` based on what is appropriate for the page context.
7
+ # - Use `Heading` as the title of a section or sub section.
8
+ # - Do not use `Heading` for styling alone. For simply styling text, consider using <%= link_to_component(Primer::TextComponent) %> with relevant <%= link_to_typography_docs %>
9
+ # such as `font_size` and `font_weight`.
10
+ # - Do not jump heading levels. For instance, do not follow a `<h1>` with an `<h3>`. Heading levels should increase by one in ascending order.
13
11
  #
14
12
  # @accessibility
15
- # Headings convey semantic meaning. Assistive technology users rely on headings to quickly navigate and scan information on a page.
16
- # Inappropriate use of headings can lead to a confusing experience.
17
- # [Learn more about best heading practices (WAI Headings)](https://www.w3.org/WAI/tutorials/page-structure/headings/)
13
+ # While sighted users rely on visual cues such as font size changes to determine what the heading is, assistive technology users rely on programatic cues that can be read out.
14
+ # When text on a page is visually implied to be a heading, ensure that it is coded as a heading. Additionally, visually implied heading level and coded heading level should be
15
+ # consistent. [See WCAG success criteria: 1.3.1: Info and Relationships](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)
16
+ #
17
+ # Headings allow assistive technology users to quickly navigate around a page. Navigation to text that is not meant to be a heading can be a confusing experience.
18
+ # <%= link_to_heading_practices %>
18
19
  class HeadingComponent < Primer::Component
19
20
  status :beta
20
21
 
@@ -29,14 +30,6 @@ module Primer
29
30
  # <%= render(Primer::HeadingComponent.new(tag: :h5)) { "H5 Text" } %>
30
31
  # <%= render(Primer::HeadingComponent.new(tag: :h6)) { "H6 Text" } %>
31
32
  #
32
- # @example With `font_size`
33
- # <%= render(Primer::HeadingComponent.new(tag: :h1, font_size: 6)) { "h1 tag, font_size 6" } %>
34
- # <%= render(Primer::HeadingComponent.new(tag: :h2, font_size: 3)) { "h2 tag, font_size 3" } %>
35
- # <%= render(Primer::HeadingComponent.new(tag: :h3, font_size: 2)) { "h3 tag, font_size 2" } %>
36
- # <%= render(Primer::HeadingComponent.new(tag: :h4, font_size: 0)) { "h4 tag, font_size 0" } %>
37
- # <%= render(Primer::HeadingComponent.new(tag: :h5, font_size: 1)) { "h5 tag, font_size 1" } %>
38
- # <%= render(Primer::HeadingComponent.new(tag: :h6, font_size: 4)) { "h6 tag, font_size 4" } %>
39
- #
40
33
  # @param tag [String] <%= one_of(Primer::HeadingComponent::TAG_OPTIONS) %>
41
34
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
42
35
  def initialize(tag:, **system_arguments)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use HiddenTextExpander to indicate and toggle hidden text.
4
+ # Use `HiddenTextExpander` to indicate and toggle hidden text.
5
5
  class HiddenTextExpander < Primer::Component
6
6
  # @example Default
7
7
  # <%= render(Primer::HiddenTextExpander.new) %>
@@ -10,14 +10,14 @@ module Primer
10
10
  # <%= render(Primer::HiddenTextExpander.new(inline: true)) %>
11
11
  #
12
12
  # @example Styling the button
13
- # <%= render(Primer::HiddenTextExpander.new(button_arguments: { p: 1, classes: "my-custom-class" })) %>
13
+ # <%= render(Primer::HiddenTextExpander.new(button_arguments: { p: 1, classes: "custom-class" })) %>
14
14
  #
15
15
  # @param inline [Boolean] Whether or not the expander is inline.
16
16
  # @param button_arguments [Hash] <%= link_to_system_arguments_docs %> for the button element.
17
17
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
18
18
  def initialize(inline: false, button_arguments: {}, **system_arguments)
19
19
  @system_arguments = system_arguments
20
- @system_arguments[:tag] ||= :span
20
+ @system_arguments[:tag] = :span
21
21
  @system_arguments[:classes] = class_names(
22
22
  "hidden-text-expander",
23
23
  @system_arguments[:classes],
@@ -34,7 +34,7 @@ module Primer
34
34
 
35
35
  def call
36
36
  render(Primer::BaseComponent.new(**@system_arguments)) do
37
- render(Primer::BaseButton.new(**@button_arguments)) { "&hellip;" }
37
+ render(Primer::BaseButton.new(**@button_arguments)) { "&hellip;".html_safe }
38
38
  end
39
39
  end
40
40
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use `IconButton` to render Icon-only buttons without the default button styles.
5
+ #
6
+ # @accessibility
7
+ # `IconButton` requires an `aria-label`, which will provide assistive technologies with an accessible label.
8
+ # The `aria-label` should describe the action to be invoked rather than the icon itself. For instance,
9
+ # if your `IconButton` renders a magnifying glass icon and invokves a search action, the `aria-label` should be
10
+ # `"Search"` instead of `"Magnifying glass"`.
11
+ # [Learn more about best functional image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/functional)
12
+ class IconButton < Primer::Component
13
+ status :beta
14
+
15
+ DEFAULT_SCHEME = :default
16
+ SCHEME_MAPPINGS = {
17
+ DEFAULT_SCHEME => "",
18
+ :danger => "btn-octicon-danger"
19
+ }.freeze
20
+ SCHEME_OPTIONS = SCHEME_MAPPINGS.keys
21
+ # @example Default
22
+ #
23
+ # <%= render(Primer::IconButton.new(icon: :search, "aria-label": "Search")) %>
24
+ #
25
+ # @example Schemes
26
+ #
27
+ # <%= render(Primer::IconButton.new(icon: :search, "aria-label": "Search")) %>
28
+ # <%= render(Primer::IconButton.new(icon: :trash, "aria-label": "Delete", scheme: :danger)) %>
29
+ #
30
+ # @example In a BorderBox
31
+ #
32
+ # <%= render(Primer::BorderBoxComponent.new) do |component| %>
33
+ # <% component.body do %>
34
+ # <%= render(Primer::TextComponent.new(pr: 2)) { "Body" } %>
35
+ # <%= render(Primer::IconButton.new(icon: :pencil, box: true, "aria-label": "Edit")) %>
36
+ # <% end %>
37
+ # <% end %>
38
+ #
39
+ # @param scheme [Symbol] <%= one_of(Primer::IconButton::SCHEME_OPTIONS) %>
40
+ # @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.
44
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
45
+ def initialize(scheme: DEFAULT_SCHEME, icon:, box: false, **system_arguments)
46
+ @icon = icon
47
+
48
+ @system_arguments = system_arguments
49
+ @system_arguments[:classes] = class_names(
50
+ "btn-octicon",
51
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)],
52
+ system_arguments[:classes],
53
+ "Box-btn-octicon" => box
54
+ )
55
+
56
+ validate_aria_label
57
+ end
58
+
59
+ def call
60
+ render(Primer::BaseButton.new(**@system_arguments)) do
61
+ render(Primer::OcticonComponent.new(icon: @icon))
62
+ end
63
+ end
64
+ end
65
+ end