primer_view_components 0.0.34 → 0.0.39

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -21
  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_component.rb → auto_complete.rb} +14 -12
  6. data/app/components/primer/{auto_complete_component.d.ts → auto_complete/auto_complete.d.ts} +0 -0
  7. data/app/components/primer/{auto_complete_component.html.erb → auto_complete/auto_complete.html.erb} +0 -0
  8. data/app/components/primer/{auto_complete_component.js → auto_complete/auto_complete.js} +0 -0
  9. data/app/components/primer/{auto_complete_component.ts → auto_complete/auto_complete.ts} +0 -0
  10. data/app/components/primer/auto_complete/auto_component.d.ts +1 -0
  11. data/app/components/primer/auto_complete/auto_component.js +1 -0
  12. data/app/components/primer/auto_complete/item.rb +42 -0
  13. data/app/components/primer/avatar_component.rb +22 -3
  14. data/app/components/primer/avatar_stack_component.rb +3 -1
  15. data/app/components/primer/base_button.rb +47 -0
  16. data/app/components/primer/base_component.rb +7 -8
  17. data/app/components/primer/blankslate_component.rb +4 -1
  18. data/app/components/primer/border_box_component.rb +1 -1
  19. data/app/components/primer/box_component.rb +1 -1
  20. data/app/components/primer/breadcrumb_component.rb +1 -1
  21. data/app/components/primer/button_component.html.erb +9 -0
  22. data/app/components/primer/button_component.rb +60 -21
  23. data/app/components/primer/{button_group_component.html.erb → button_group.html.erb} +0 -0
  24. data/app/components/primer/button_group.rb +61 -0
  25. data/app/components/primer/button_marketing_component.rb +4 -9
  26. data/app/components/primer/clipboard_copy.html.erb +8 -0
  27. data/app/components/primer/clipboard_copy.rb +26 -0
  28. data/app/components/primer/clipboard_copy_component.d.ts +1 -0
  29. data/app/components/primer/clipboard_copy_component.js +23 -0
  30. data/app/components/primer/clipboard_copy_component.ts +26 -0
  31. data/app/components/primer/close_button.rb +39 -0
  32. data/app/components/primer/component.rb +17 -2
  33. data/app/components/primer/counter_component.rb +1 -1
  34. data/app/components/primer/details_component.rb +1 -1
  35. data/app/components/primer/dropdown/menu_component.rb +1 -1
  36. data/app/components/primer/dropdown_component.rb +2 -2
  37. data/app/components/primer/dropdown_menu_component.rb +1 -1
  38. data/app/components/primer/flash_component.rb +1 -1
  39. data/app/components/primer/flex_component.rb +1 -1
  40. data/app/components/primer/flex_item_component.rb +20 -1
  41. data/app/components/primer/heading_component.rb +32 -4
  42. data/app/components/primer/hidden_text_expander.rb +41 -0
  43. data/app/components/primer/icon_button.rb +48 -0
  44. data/app/components/primer/label_component.rb +1 -1
  45. data/app/components/primer/layout_component.rb +1 -1
  46. data/app/components/primer/link_component.rb +1 -1
  47. data/app/components/primer/markdown_component.rb +1 -1
  48. data/app/components/primer/menu_component.rb +1 -1
  49. data/app/components/primer/navigation/tab_component.html.erb +9 -7
  50. data/app/components/primer/navigation/tab_component.rb +27 -3
  51. data/app/components/primer/octicon_component.rb +35 -14
  52. data/app/components/primer/popover_component.rb +1 -1
  53. data/app/components/primer/primer.d.ts +2 -1
  54. data/app/components/primer/primer.js +2 -1
  55. data/app/components/primer/primer.ts +2 -1
  56. data/app/components/primer/progress_bar_component.rb +1 -1
  57. data/app/components/primer/spinner_component.rb +1 -1
  58. data/app/components/primer/state_component.rb +2 -2
  59. data/app/components/primer/subhead_component.rb +1 -1
  60. data/app/components/primer/tab_container_component.rb +1 -1
  61. data/app/components/primer/tab_nav_component.html.erb +2 -2
  62. data/app/components/primer/tab_nav_component.rb +23 -9
  63. data/app/components/primer/text_component.rb +1 -1
  64. data/app/components/primer/time_ago_component.rb +1 -1
  65. data/app/components/primer/timeline_item_component.rb +1 -1
  66. data/app/components/primer/tooltip_component.rb +1 -1
  67. data/app/components/primer/{truncate_component.rb → truncate.rb} +8 -6
  68. data/app/components/primer/underline_nav_component.rb +47 -15
  69. data/app/lib/primer/classify.rb +8 -33
  70. data/app/lib/primer/classify/cache.rb +19 -14
  71. data/app/lib/primer/classify/flex.rb +111 -0
  72. data/app/lib/primer/classify/functional_border_colors.rb +1 -2
  73. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -2
  74. data/app/lib/primer/octicon/cache.rb +38 -0
  75. data/app/lib/primer/tabbed_component_helper.rb +4 -0
  76. data/lib/primer/view_components/version.rb +1 -1
  77. data/static/statuses.json +1 -1
  78. metadata +116 -32
  79. data/app/assets/javascripts/primer_view_components.js.map.orig +0 -5
  80. data/app/assets/javascripts/primer_view_components.js.orig +0 -6
  81. data/app/components/primer/auto_complete_item_component.rb +0 -38
  82. data/app/components/primer/button_group_component.rb +0 -35
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use `BaseButton` to render an unstyled `<button>` tag that can be customized.
5
+ class BaseButton < Primer::Component
6
+ status :beta
7
+
8
+ DEFAULT_TAG = :button
9
+ TAG_OPTIONS = [DEFAULT_TAG, :a, :summary].freeze
10
+
11
+ DEFAULT_TYPE = :button
12
+ TYPE_OPTIONS = [DEFAULT_TYPE, :reset, :submit].freeze
13
+
14
+ # @example Block
15
+ # <%= render(Primer::BaseButton.new(block: :true)) { "Block" } %>
16
+ # <%= render(Primer::BaseButton.new(block: :true, scheme: :primary)) { "Primary block" } %>
17
+ #
18
+ # @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
19
+ # @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
20
+ # @param block [Boolean] Whether button is full-width with `display: block`.
21
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
22
+ def initialize(
23
+ tag: DEFAULT_TAG,
24
+ type: DEFAULT_TYPE,
25
+ block: false,
26
+ **system_arguments
27
+ )
28
+ @system_arguments = system_arguments
29
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
30
+
31
+ if @system_arguments[:tag] == :button
32
+ @system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
33
+ else
34
+ @system_arguments[:role] = :button
35
+ end
36
+
37
+ @system_arguments[:classes] = class_names(
38
+ system_arguments[:classes],
39
+ "btn-block" => block
40
+ )
41
+ end
42
+
43
+ def call
44
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
45
+ end
46
+ end
47
+ end
@@ -25,8 +25,6 @@ module Primer
25
25
  class BaseComponent < Primer::Component
26
26
  status :beta
27
27
 
28
- include TestSelectorHelper
29
-
30
28
  # ## HTML attributes
31
29
  #
32
30
  # System arguments include most HTML attributes. For example:
@@ -71,12 +69,14 @@ module Primer
71
69
  #
72
70
  # | Name | Type | Description |
73
71
  # | :- | :- | :- |
74
- # | `align_items` | Symbol | <%= one_of([:flex_start, :flex_end, :center, :baseline, :stretch]) %> |
75
- # | `align_self` | Symbol | <%= one_of([:auto, :start, :end, :center, :baseline, :stretch]) %> |
72
+ # | `align_items` | Symbol | <%= one_of(Primer::Classify::Flex::ALIGN_ITEMS_VALUES) %> |
73
+ # | `align_self` | Symbol | <%= one_of(Primer::Classify::Flex::ALIGN_SELF_VALUES) %> |
74
+ # | `direction` | Symbol | <%= one_of(Primer::Classify::Flex::DIRECTION_VALUES) %> |
75
+ # | `flex` | Integer, Symbol | <%= one_of(Primer::Classify::Flex::FLEX_VALUES) %> |
76
76
  # | `flex_grow` | Integer | To enable, set to `0`. |
77
77
  # | `flex_shrink` | Integer | To enable, set to `0`. |
78
- # | `flex` | Integer, Symbol | <%= one_of([1, :auto]) %> |
79
- # | `justify_content` | Symbol | <%= one_of([:flex_start, :flex_end, :center, :space_between, :space_around]) %> |
78
+ # | `flex_wrap` | Symbol | <%= one_of(Primer::Classify::Flex::WRAP_MAPPINGS.keys) %> |
79
+ # | `justify_content` | Symbol | <%= one_of(Primer::Classify::Flex::JUSTIFY_CONTENT_VALUES) %> |
80
80
  # | `width` | Symbol | <%= one_of([:fit, :fill]) %> |
81
81
  #
82
82
  # ## Grid
@@ -89,7 +89,7 @@ module Primer
89
89
  #
90
90
  # | Name | Type | Description |
91
91
  # | :- | :- | :- |
92
- # | `display` | Symbol | <%= one_of([:none, :block, :flex, :inline, :inline_block, :table, :table_cell]) %> |
92
+ # | `display` | Symbol | <%= one_of([:none, :block, :flex, :inline, :inline_block, :inline_flex, :table, :table_cell]) %> |
93
93
  # | `height` | Symbol | <%= one_of([:fit, :fill]) %> |
94
94
  # | `hide` | Symbol | Hide the element at a specific breakpoint. <%= one_of([:sm, :md, :lg, :xl]) %> |
95
95
  # | `v` | Symbol | Visibility. <%= one_of([:hidden, :visible]) %> |
@@ -140,7 +140,6 @@ module Primer
140
140
  # | Name | Type | Description |
141
141
  # | :- | :- | :- |
142
142
  # | classes | String | CSS class name value to be concatenated with generated Primer CSS classes. |
143
- # | tag | Symbol | HTML tag name to be passed to `content_tag`. |
144
143
  # | test_selector | String | Adds `data-test-selector='given value'` in non-Production environments for testing purposes. |
145
144
  def initialize(tag:, classes: nil, **system_arguments)
146
145
  @tag = tag
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use Primer::BlankslateComponent when there is a lack of content within a page or section. Use as placeholder to tell users why something isn't there.
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
+ # [Learn more about best heading practices (WAI Headings)](https://www.w3.org/WAI/tutorials/page-structure/headings/)
5
8
  class BlankslateComponent < Primer::Component
6
9
  status :beta
7
10
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # BorderBox is a Box component with a border.
4
+ # `BorderBox` is a Box component with a border.
5
5
  class BorderBoxComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # A basic wrapper component for most layout related needs.
4
+ # `Box` is a basic wrapper component for most layout related needs.
5
5
  class BoxComponent < Primer::Component
6
6
  status :stable
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use breadcrumbs to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item, which is a plain string indicating the current page.
4
+ # Use `Breadcrumb` to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item, which is a plain string indicating the current page.
5
5
  class BreadcrumbComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -0,0 +1,9 @@
1
+ <%= render Primer::BaseButton.new(**@system_arguments) do %>
2
+ <%= icon %>
3
+ <%= content %>
4
+ <%= counter %>
5
+
6
+ <% if @caret %>
7
+ <%= primer_octicon("triangle-down") %>
8
+ <% end %>
9
+ <% end %>
@@ -1,14 +1,19 @@
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 `Button` for actions (e.g. in forms). Use links for destinations, or moving from one page to another.
5
5
  class ButtonComponent < Primer::Component
6
+ status :beta
7
+
6
8
  DEFAULT_SCHEME = :default
9
+ LINK_SCHEME = :link
7
10
  SCHEME_MAPPINGS = {
8
11
  DEFAULT_SCHEME => "",
9
12
  :primary => "btn-primary",
10
13
  :danger => "btn-danger",
11
- :outline => "btn-outline"
14
+ :outline => "btn-outline",
15
+ :invisible => "btn-invisible",
16
+ LINK_SCHEME => "btn-link"
12
17
  }.freeze
13
18
  SCHEME_OPTIONS = SCHEME_MAPPINGS.keys
14
19
 
@@ -20,56 +25,90 @@ module Primer
20
25
  }.freeze
21
26
  VARIANT_OPTIONS = VARIANT_MAPPINGS.keys
22
27
 
23
- DEFAULT_TAG = :button
24
- TAG_OPTIONS = [DEFAULT_TAG, :a, :summary].freeze
28
+ # Icon to be rendered in the button.
29
+ #
30
+ # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
31
+ renders_one :icon, Primer::OcticonComponent
25
32
 
26
- DEFAULT_TYPE = :button
27
- TYPE_OPTIONS = [DEFAULT_TYPE, :reset, :submit].freeze
33
+ # Counter to be rendered in the button.
34
+ #
35
+ # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::CounterComponent) %>.
36
+ renders_one :counter, Primer::CounterComponent
28
37
 
29
38
  # @example Schemes
30
39
  # <%= render(Primer::ButtonComponent.new) { "Default" } %>
31
40
  # <%= render(Primer::ButtonComponent.new(scheme: :primary)) { "Primary" } %>
32
41
  # <%= render(Primer::ButtonComponent.new(scheme: :danger)) { "Danger" } %>
33
42
  # <%= render(Primer::ButtonComponent.new(scheme: :outline)) { "Outline" } %>
43
+ # <%= render(Primer::ButtonComponent.new(scheme: :invisible)) { "Invisible" } %>
44
+ # <%= render(Primer::ButtonComponent.new(scheme: :link)) { "Link" } %>
34
45
  #
35
46
  # @example Variants
36
47
  # <%= render(Primer::ButtonComponent.new(variant: :small)) { "Small" } %>
37
48
  # <%= render(Primer::ButtonComponent.new(variant: :medium)) { "Medium" } %>
38
49
  # <%= render(Primer::ButtonComponent.new(variant: :large)) { "Large" } %>
39
50
  #
51
+ # @example Block
52
+ # <%= render(Primer::ButtonComponent.new(block: :true)) { "Block" } %>
53
+ # <%= render(Primer::ButtonComponent.new(block: :true, scheme: :primary)) { "Primary block" } %>
54
+ #
55
+ # @example With icons
56
+ # <%= render(Primer::ButtonComponent.new) do |c| %>
57
+ # <% c.icon(icon: :star) %>
58
+ # Button
59
+ # <% end %>
60
+ #
61
+ # @example With counter
62
+ # <%= render(Primer::ButtonComponent.new) do |c| %>
63
+ # <% c.counter(count: 15) %>
64
+ # Button
65
+ # <% end %>
66
+ #
67
+ # @example With icons and counter
68
+ # <%= render(Primer::ButtonComponent.new) do |c| %>
69
+ # <% c.icon(icon: :star) %>
70
+ # <% c.counter(count: 15) %>
71
+ # Button
72
+ # <% end %>
73
+ #
74
+ # @example With caret
75
+ # <%= render(Primer::ButtonComponent.new(caret: true)) do %>
76
+ # Button
77
+ # <% end %>
78
+ #
40
79
  # @param scheme [Symbol] <%= one_of(Primer::ButtonComponent::SCHEME_OPTIONS) %>
41
80
  # @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
42
- # @param tag [Symbol] <%= one_of(Primer::ButtonComponent::TAG_OPTIONS) %>
43
- # @param type [Symbol] <%= one_of(Primer::ButtonComponent::TYPE_OPTIONS) %>
81
+ # @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
82
+ # @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
44
83
  # @param group_item [Boolean] Whether button is part of a ButtonGroup.
84
+ # @param block [Boolean] Whether button is full-width with `display: block`.
85
+ # @param caret [Boolean] Whether or not to render a caret.
45
86
  def initialize(
46
87
  scheme: DEFAULT_SCHEME,
47
88
  variant: DEFAULT_VARIANT,
48
- tag: DEFAULT_TAG,
49
- type: DEFAULT_TYPE,
50
89
  group_item: false,
90
+ block: false,
91
+ caret: false,
51
92
  **system_arguments
52
93
  )
53
- @system_arguments = system_arguments
54
- @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
55
-
56
- if @system_arguments[:tag] == :a
57
- @system_arguments[:role] = :button
58
- else
59
- @system_arguments[:type] = type
60
- end
94
+ @scheme = scheme
95
+ @caret = caret
61
96
 
97
+ @system_arguments = system_arguments
62
98
  @system_arguments[:classes] = class_names(
63
- "btn",
64
99
  system_arguments[:classes],
65
100
  SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)],
66
101
  VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant, DEFAULT_VARIANT)],
102
+ "btn" => !link?,
103
+ "btn-block" => block,
67
104
  "BtnGroup-item" => group_item
68
105
  )
69
106
  end
70
107
 
71
- def call
72
- render(Primer::BaseComponent.new(**@system_arguments)) { content }
108
+ private
109
+
110
+ def link?
111
+ @scheme == LINK_SCHEME
73
112
  end
74
113
  end
75
114
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use `ButtonGroup` to render a series of buttons.
5
+ class ButtonGroup < Primer::Component
6
+ status :beta
7
+
8
+ # Required list of buttons to be rendered.
9
+ #
10
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %> except for `variant` and `group_item`.
11
+ renders_many :buttons, lambda { |**kwargs|
12
+ kwargs[:group_item] = true
13
+ kwargs[:variant] = @variant
14
+
15
+ Primer::ButtonComponent.new(**kwargs)
16
+ }
17
+
18
+ # @example Default
19
+ #
20
+ # <%= render(Primer::ButtonGroup.new) do |component| %>
21
+ # <% component.button { "Default" } %>
22
+ # <% component.button(scheme: :primary) { "Primary" } %>
23
+ # <% component.button(scheme: :danger) { "Danger" } %>
24
+ # <% component.button(scheme: :outline) { "Outline" } %>
25
+ # <% component.button(classes: "my-class") { "Custom class" } %>
26
+ # <% end %>
27
+ #
28
+ # @example Variants
29
+ #
30
+ # <%= render(Primer::ButtonGroup.new(variant: :small)) do |component| %>
31
+ # <% component.button { "Default" } %>
32
+ # <% component.button(scheme: :primary) { "Primary" } %>
33
+ # <% component.button(scheme: :danger) { "Danger" } %>
34
+ # <% component.button(scheme: :outline) { "Outline" } %>
35
+ # <% end %>
36
+ #
37
+ # <%= render(Primer::ButtonGroup.new(variant: :large)) do |component| %>
38
+ # <% component.button { "Default" } %>
39
+ # <% component.button(scheme: :primary) { "Primary" } %>
40
+ # <% component.button(scheme: :danger) { "Danger" } %>
41
+ # <% component.button(scheme: :outline) { "Outline" } %>
42
+ # <% end %>
43
+ #
44
+ # @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
45
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
46
+ def initialize(variant: Primer::ButtonComponent::DEFAULT_VARIANT, **system_arguments)
47
+ @variant = variant
48
+ @system_arguments = system_arguments
49
+ @system_arguments[:tag] ||= :div
50
+
51
+ @system_arguments[:classes] = class_names(
52
+ "BtnGroup",
53
+ system_arguments[:classes]
54
+ )
55
+ end
56
+
57
+ def render?
58
+ buttons.any?
59
+ end
60
+ end
61
+ end
@@ -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 = {
@@ -50,14 +50,9 @@ module Primer
50
50
  **system_arguments
51
51
  )
52
52
  @system_arguments = system_arguments
53
+ @system_arguments[:block] = false
53
54
  @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
54
-
55
- if @system_arguments[:tag] == :a
56
- @system_arguments[:role] = :button
57
- else
58
- @system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
59
- end
60
-
55
+ @system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
61
56
  @system_arguments[:classes] = class_names(
62
57
  "btn-mktg",
63
58
  SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)],
@@ -67,7 +62,7 @@ module Primer
67
62
  end
68
63
 
69
64
  def call
70
- render(Primer::BaseComponent.new(**@system_arguments)) { content }
65
+ render(Primer::BaseButton.new(**@system_arguments)) { content }
71
66
  end
72
67
  end
73
68
  end
@@ -0,0 +1,8 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <% if content.present? %>
3
+ <%= content %>
4
+ <% else %>
5
+ <%= render Primer::OcticonComponent.new("clippy") %>
6
+ <%= render Primer::OcticonComponent.new("check", color: :icon_success, style: "display: none;") %>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use `ClipboardCopy` to copy element text content or input values to the clipboard.
5
+ class ClipboardCopy < Primer::Component
6
+ status :alpha
7
+
8
+ # @example Default
9
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) %>
10
+ #
11
+ # @example With text instead of icons
12
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) do %>
13
+ # Click to copy!
14
+ # <% end %>
15
+ #
16
+ # @param label [String] String that will be read to screenreaders when the component is focused
17
+ # @param value [String] Text to copy into the users clipboard when they click the component
18
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
19
+ def initialize(label:, value:, **system_arguments)
20
+ @system_arguments = system_arguments
21
+ @system_arguments[:tag] = "clipboard-copy"
22
+ @system_arguments[:value] = value
23
+ @system_arguments[:"aria-label"] = label
24
+ end
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ import '@github/clipboard-copy-element';
@@ -0,0 +1,23 @@
1
+ import '@github/clipboard-copy-element';
2
+ function toggleSVG(svg) {
3
+ if (svg.style.display === '' || svg.style.display === 'block') {
4
+ svg.style.display = 'none';
5
+ }
6
+ else {
7
+ svg.style.display = 'block';
8
+ }
9
+ }
10
+ // Toggle a copy button.
11
+ function toggleCopyButton(button) {
12
+ const [clippyIcon, checkIcon] = button.querySelectorAll('.octicon');
13
+ if (!clippyIcon || !checkIcon)
14
+ return;
15
+ toggleSVG(clippyIcon);
16
+ toggleSVG(checkIcon);
17
+ }
18
+ document.addEventListener('clipboard-copy', function ({ target }) {
19
+ if (!(target instanceof HTMLElement))
20
+ return;
21
+ toggleCopyButton(target);
22
+ setTimeout(toggleCopyButton, 2000, target);
23
+ });
@@ -0,0 +1,26 @@
1
+ import '@github/clipboard-copy-element'
2
+
3
+ function toggleSVG(svg: SVGElement) {
4
+ if (svg.style.display === '' || svg.style.display === 'block') {
5
+ svg.style.display = 'none'
6
+ } else {
7
+ svg.style.display = 'block'
8
+ }
9
+ }
10
+
11
+ // Toggle a copy button.
12
+ function toggleCopyButton(button: HTMLElement) {
13
+ const [clippyIcon, checkIcon] = button.querySelectorAll<SVGElement>('.octicon')
14
+
15
+ if (!clippyIcon || !checkIcon) return
16
+
17
+ toggleSVG(clippyIcon)
18
+ toggleSVG(checkIcon)
19
+ }
20
+
21
+ document.addEventListener('clipboard-copy', function ({target}) {
22
+ if (!(target instanceof HTMLElement)) return
23
+ toggleCopyButton(target)
24
+
25
+ setTimeout(toggleCopyButton, 2000, target)
26
+ })