primer_view_components 0.0.40 → 0.0.45

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +239 -1
  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/button_marketing.rb +70 -0
  6. data/app/components/primer/auto_complete.rb +99 -41
  7. data/app/components/primer/auto_complete/auto_complete.html.erb +1 -0
  8. data/app/components/primer/{auto_complete/auto_component.d.ts → auto_complete_component.d.ts} +0 -0
  9. data/app/components/primer/{auto_complete/auto_component.js → auto_complete_component.js} +0 -0
  10. data/app/components/primer/avatar_stack_component.rb +2 -2
  11. data/app/components/primer/base_component.rb +31 -21
  12. data/app/components/primer/beta/text.rb +27 -0
  13. data/app/components/primer/blankslate_component.html.erb +1 -0
  14. data/app/components/primer/blankslate_component.rb +65 -46
  15. data/app/components/primer/button_component.rb +3 -2
  16. data/app/components/primer/button_group.rb +1 -1
  17. data/app/components/primer/clipboard_copy.rb +25 -7
  18. data/app/components/primer/clipboard_copy_component.js +13 -2
  19. data/app/components/primer/clipboard_copy_component.ts +15 -2
  20. data/app/components/primer/component.rb +1 -1
  21. data/app/components/primer/details_component.rb +12 -1
  22. data/app/components/primer/details_menu_component.d.ts +1 -0
  23. data/app/components/primer/details_menu_component.js +1 -0
  24. data/app/components/primer/dropdown.d.ts +1 -0
  25. data/app/components/primer/{dropdown_component.html.erb → dropdown.html.erb} +2 -1
  26. data/app/components/primer/dropdown.js +1 -0
  27. data/app/components/primer/dropdown.rb +149 -0
  28. data/app/components/primer/dropdown.ts +1 -0
  29. data/app/components/primer/dropdown/menu.d.ts +1 -0
  30. data/app/components/primer/dropdown/menu.html.erb +25 -0
  31. data/app/components/primer/dropdown/menu.js +1 -0
  32. data/app/components/primer/dropdown/menu.rb +99 -0
  33. data/app/components/primer/dropdown/menu.ts +1 -0
  34. data/app/components/primer/flash_component.rb +2 -2
  35. data/app/components/primer/heading_component.rb +1 -1
  36. data/app/components/primer/hidden_text_expander.rb +2 -2
  37. data/app/components/primer/icon_button.rb +1 -1
  38. data/app/components/primer/image.rb +46 -0
  39. data/app/components/primer/image_crop.rb +2 -2
  40. data/app/components/primer/label_component.rb +6 -2
  41. data/app/components/primer/local_time.d.ts +1 -0
  42. data/app/components/primer/local_time.js +1 -0
  43. data/app/components/primer/local_time.rb +59 -0
  44. data/app/components/primer/local_time.ts +1 -0
  45. data/app/components/primer/markdown.rb +6 -2
  46. data/app/components/primer/navigation/tab_component.rb +10 -3
  47. data/app/components/primer/octicon_component.rb +15 -12
  48. data/app/components/primer/primer.d.ts +2 -0
  49. data/app/components/primer/primer.js +2 -0
  50. data/app/components/primer/primer.ts +2 -0
  51. data/app/components/primer/spinner_component.rb +2 -0
  52. data/app/components/primer/tab_nav_component.html.erb +5 -1
  53. data/app/components/primer/tab_nav_component.rb +62 -9
  54. data/app/components/primer/{tooltip_component.rb → tooltip.rb} +10 -8
  55. data/app/components/primer/truncate.rb +6 -2
  56. data/app/components/primer/underline_nav_component.html.erb +1 -1
  57. data/app/components/primer/underline_nav_component.rb +17 -1
  58. data/app/lib/primer/classify.rb +35 -12
  59. data/app/lib/primer/classify/cache.rb +12 -17
  60. data/app/lib/primer/classify/grid.rb +45 -0
  61. data/app/lib/primer/classify/utilities.rb +137 -0
  62. data/app/lib/primer/classify/utilities.yml +1147 -0
  63. data/app/lib/primer/tabbed_component_helper.rb +2 -2
  64. data/app/lib/primer/view_helper.rb +2 -1
  65. data/lib/primer/view_components/engine.rb +2 -0
  66. data/lib/primer/view_components/linters.rb +3 -0
  67. data/lib/primer/view_components/linters/argument_mappers/button.rb +82 -0
  68. data/lib/primer/view_components/linters/argument_mappers/conversion_error.rb +10 -0
  69. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +48 -0
  70. data/lib/primer/view_components/linters/button_component_migration_counter.rb +39 -0
  71. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +16 -0
  72. data/lib/primer/view_components/linters/helpers.rb +191 -0
  73. data/lib/primer/view_components/version.rb +1 -1
  74. data/lib/tasks/docs.rake +184 -109
  75. data/lib/tasks/utilities.rake +99 -0
  76. data/lib/yard/docs_helper.rb +12 -2
  77. data/static/statuses.json +10 -6
  78. metadata +65 -14
  79. data/app/components/primer/button_marketing_component.rb +0 -68
  80. data/app/components/primer/dropdown/menu_component.html.erb +0 -12
  81. data/app/components/primer/dropdown/menu_component.rb +0 -46
  82. data/app/components/primer/dropdown_component.rb +0 -73
  83. data/app/components/primer/text_component.rb +0 -25
  84. data/app/lib/primer/classify/spacing.rb +0 -63
@@ -1,3 +1,4 @@
1
+ <%= label %>
1
2
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
3
  <%= input %>
3
4
  <%= icon %>
@@ -39,7 +39,7 @@ module Primer
39
39
  # @param tag [Symbol] <%= one_of(Primer::AvatarStackComponent::TAG_OPTIONS) %>
40
40
  # @param align [Symbol] <%= one_of(Primer::AvatarStackComponent::ALIGN_OPTIONS) %>
41
41
  # @param tooltipped [Boolean] Whether to add a tooltip to the stack or not.
42
- # @param body_arguments [Hash] Parameters to add to the Body. If `tooltipped` is set, has the same arguments as <%= link_to_component(Primer::TooltipComponent) %>.
42
+ # @param body_arguments [Hash] Parameters to add to the Body. If `tooltipped` is set, has the same arguments as <%= link_to_component(Primer::Tooltip) %>.
43
43
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
44
44
  def initialize(tag: DEFAULT_TAG, align: ALIGN_DEFAULT, tooltipped: false, body_arguments: {}, **system_arguments)
45
45
  @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
@@ -63,7 +63,7 @@ module Primer
63
63
 
64
64
  def body_component
65
65
  if @tooltipped
66
- Primer::TooltipComponent.new(**@body_arguments)
66
+ Primer::Tooltip.new(**@body_arguments)
67
67
  else
68
68
  Primer::BaseComponent.new(**@body_arguments)
69
69
  end
@@ -83,7 +83,9 @@ module Primer
83
83
  #
84
84
  # | Name | Type | Description |
85
85
  # | :- | :- | :- |
86
- # | `col` | Integer | Number of columns. |
86
+ # | `clearfix` | Boolean | Wether to assign the `clearfix` class. |
87
+ # | `col` | Integer | Number of columns. <%= one_of(Primer::Classify::Grid::COL_VALUES) %> |
88
+ # | `container` | Symbol | Size of the container. <%= one_of(Primer::Classify::Grid::CONTAINER_VALUES) %> |
87
89
  #
88
90
  # ## Layout
89
91
  #
@@ -91,7 +93,7 @@ module Primer
91
93
  # | :- | :- | :- |
92
94
  # | `display` | Symbol | <%= one_of([:none, :block, :flex, :inline, :inline_block, :inline_flex, :table, :table_cell]) %> |
93
95
  # | `height` | Symbol | <%= one_of([:fit]) %> |
94
- # | `hide` | Symbol | Hide the element at a specific breakpoint. <%= one_of([:sm, :md, :lg, :xl]) %> |
96
+ # | `hide` | Symbol | Hide the element at a specific breakpoint. <%= one_of(Primer::Classify::Utilities.mappings(:hide)) %> |
95
97
  # | `v` | Symbol | Visibility. <%= one_of([:hidden, :visible]) %> |
96
98
  # | `vertical_align` | Symbol | <%= one_of([:baseline, :top, :middle, :bottom, :text_top, :text_bottom]) %> |
97
99
  #
@@ -100,7 +102,7 @@ module Primer
100
102
  # | Name | Type | Description |
101
103
  # | :- | :- | :- |
102
104
  # | `bottom` | Boolean | If `false`, sets `bottom: 0`. |
103
- # | `float` | Symbol | <%= one_of([:left, :right]) %> |
105
+ # | `float` | Symbol | <%= one_of(Primer::Classify::Utilities.mappings(:float)) %> |
104
106
  # | `left` | Boolean | If `false`, sets `left: 0`. |
105
107
  # | `position` | Symbol | <%= one_of([:relative, :absolute, :fixed]) %> |
106
108
  # | `right` | Boolean | If `false`, sets `right: 0`. |
@@ -110,28 +112,31 @@ module Primer
110
112
  #
111
113
  # | Name | Type | Description |
112
114
  # | :- | :- | :- |
113
- # | `m` | Integer | Margin. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:m]) %> |
114
- # | `mb` | Integer | Margin bottom. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:mb]) %> |
115
- # | `ml` | Integer | Margin left. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:ml]) %> |
116
- # | `mr` | Integer | Margin right. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:mr]) %> |
117
- # | `mt` | Integer | Margin top. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:mt]) %> |
118
- # | `mx` | Integer | Horizontal margins. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:mx]) %> |
119
- # | `my` | Integer | Vertical margins. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:my]) %> |
120
- # | `p` | Integer | Padding. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:p]) %> |
121
- # | `pb` | Integer | Padding bottom. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:pb]) %> |
122
- # | `pl` | Integer | Padding left. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:pl]) %> |
123
- # | `pr` | Integer | Padding right. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:pr]) %> |
124
- # | `pt` | Integer | Padding left. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:pt]) %> |
125
- # | `px` | Integer | Horizontal padding. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:px]) %> |
126
- # | `py` | Integer | Vertical padding. <%= one_of(Primer::Classify::Spacing::MAPPINGS[:py]) %> |
115
+ # | `m` | Integer | Margin. <%= one_of(Primer::Classify::Utilities.mappings(:m)) %> |
116
+ # | `mb` | Integer | Margin bottom. <%= one_of(Primer::Classify::Utilities.mappings(:mb)) %> |
117
+ # | `ml` | Integer | Margin left. <%= one_of(Primer::Classify::Utilities.mappings(:ml)) %> |
118
+ # | `mr` | Integer | Margin right. <%= one_of(Primer::Classify::Utilities.mappings(:mr)) %> |
119
+ # | `mt` | Integer | Margin top. <%= one_of(Primer::Classify::Utilities.mappings(:mt)) %> |
120
+ # | `mx` | Integer | Horizontal margins. <%= one_of(Primer::Classify::Utilities.mappings(:mx)) %> |
121
+ # | `my` | Integer | Vertical margins. <%= one_of(Primer::Classify::Utilities.mappings(:my)) %> |
122
+ # | `p` | Integer | Padding. <%= one_of(Primer::Classify::Utilities.mappings(:p)) %> |
123
+ # | `pb` | Integer | Padding bottom. <%= one_of(Primer::Classify::Utilities.mappings(:pb)) %> |
124
+ # | `pl` | Integer | Padding left. <%= one_of(Primer::Classify::Utilities.mappings(:pl)) %> |
125
+ # | `pr` | Integer | Padding right. <%= one_of(Primer::Classify::Utilities.mappings(:pr)) %> |
126
+ # | `pt` | Integer | Padding left. <%= one_of(Primer::Classify::Utilities.mappings(:pt)) %> |
127
+ # | `px` | Integer | Horizontal padding. <%= one_of(Primer::Classify::Utilities.mappings(:px)) %> |
128
+ # | `py` | Integer | Vertical padding. <%= one_of(Primer::Classify::Utilities.mappings(:py)) %> |
127
129
  #
128
130
  # ## Typography
129
131
  #
130
132
  # | Name | Type | Description |
131
133
  # | :- | :- | :- |
132
- # | `font_size` | String, Integer | <%= one_of(["00", 0, 1, 2, 3, 4, 5, 6]) %> |
133
- # | `font_weight` | Symbol | Font weight. <%= one_of([:light, :normal, :bold]) %> |
134
+ # | `font_family` | Symbol | Font weight. <%= one_of([:mono]) %> |
135
+ # | `font_size` | String, Integer, Symbol | <%= one_of(["00", 0, 1, 2, 3, 4, 5, 6, :small, :normal]) %> |
136
+ # | `font_style` | Symbol | Font weight. <%= one_of([:italic]) %> |
137
+ # | `font_weight` | Symbol | Font weight. <%= one_of([:light, :normal, :bold, :emphasized]) %> |
134
138
  # | `text_align` | Symbol | Text alignment. <%= one_of([:left, :right, :center]) %> |
139
+ # | `text_transform` | Symbol | Text alignment. <%= one_of([:uppercase]) %> |
135
140
  # | `underline` | Boolean | Whether text should be underlined. |
136
141
  # | `word_break` | Symbol | Whether to break words on line breaks. Can only be `:break_all`. |
137
142
  #
@@ -143,10 +148,15 @@ module Primer
143
148
  # | test_selector | String | Adds `data-test-selector='given value'` in non-Production environments for testing purposes. |
144
149
  def initialize(tag:, classes: nil, **system_arguments)
145
150
  @tag = tag
146
- @result = Primer::Classify.call(**system_arguments.merge(classes: classes))
151
+ @system_arguments = system_arguments
147
152
 
153
+ raise ArgumentError, "`class` is an invalid argument. Use `classes` instead." if system_arguments.key?(:class) && !Rails.env.production?
154
+
155
+ @result = Primer::Classify.call(**@system_arguments.merge(classes: classes))
156
+
157
+ @system_arguments[:"data-view-component"] = true
148
158
  # Filter out Primer keys so they don't get assigned as HTML attributes
149
- @content_tag_args = add_test_selector(system_arguments).except(*Primer::Classify::VALID_KEYS)
159
+ @content_tag_args = add_test_selector(@system_arguments).except(*Primer::Classify::VALID_KEYS)
150
160
  end
151
161
 
152
162
  def call
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # `Text` is a wrapper component that will apply typography styles to the text inside.
6
+ class Text < Primer::Component
7
+ status :beta
8
+
9
+ DEFAULT_TAG = :span
10
+
11
+ # @example Default
12
+ # <%= render(Primer::Beta::Text.new(tag: :p, font_weight: :bold)) { "Bold Text" } %>
13
+ # <%= render(Primer::Beta::Text.new(tag: :p, color: :text_danger)) { "Danger Text" } %>
14
+ #
15
+ # @param tag [Symbol]
16
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
17
+ def initialize(tag: DEFAULT_TAG, **system_arguments)
18
+ @system_arguments = system_arguments
19
+ @system_arguments[:tag] = tag
20
+ end
21
+
22
+ def call
23
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,4 @@
1
+ <%# erblint:counter ButtonComponentMigrationCounter 1 %>
1
2
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
3
  <% if spinner.present? %>
3
4
  <%= spinner %>
@@ -23,61 +23,79 @@ module Primer
23
23
  # description: "Description",
24
24
  # ) %>
25
25
  #
26
- # @example Icon|Add an `icon` to give additional context. Refer to the [Octicons](https://primer.style/octicons/) documentation to choose an icon.
27
- # <%= render Primer::BlankslateComponent.new(
28
- # icon: "octoface",
29
- # title: "Title",
30
- # description: "Description",
31
- # ) %>
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
+ # ) %>
32
35
  #
33
- # @example Loading|Add a [SpinnerComponent](https://primer.style/view-components/components/spinner) to the blankslate in place of an icon.
34
- # <%= render Primer::BlankslateComponent.new(
35
- # title: "Title",
36
- # description: "Description",
37
- # ) do |component| %>
38
- # <% component.spinner(size: :large) %>
39
- # <% end %>
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 %>
40
46
  #
41
- # @example Custom content|Pass custom content as a block in place of `description`.
42
- # <%= render Primer::BlankslateComponent.new(
43
- # title: "Title",
44
- # ) do %>
45
- # <em>Your custom content here</em>
46
- # <% end %>
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 %>
47
56
  #
48
- # @example Action button|Provide a button to guide users to take action from the blankslate. The button appears below the description and custom content.
49
- # <%= render Primer::BlankslateComponent.new(
50
- # icon: "book",
51
- # title: "Welcome to the mona wiki!",
52
- # 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.",
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.",
53
65
  #
54
- # button_text: "Create the first page",
55
- # button_url: "https://github.com/monalisa/mona/wiki/_new",
56
- # ) %>
66
+ # button_text: "Create the first page",
67
+ # button_url: "https://github.com/monalisa/mona/wiki/_new",
68
+ # ) %>
57
69
  #
58
- # @example Link|Add an additional link to help users learn more about a feature. The link will be shown at the very bottom:
59
- # <%= render Primer::BlankslateComponent.new(
60
- # icon: "book",
61
- # title: "Welcome to the mona wiki!",
62
- # 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.",
63
- # link_text: "Learn more about wikis",
64
- # link_url: "https://docs.github.com/en/github/building-a-strong-community/about-wikis",
65
- # ) %>
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
+ # ) %>
66
81
  #
67
- # @example Variations|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.
68
- # <%= render Primer::BlankslateComponent.new(
69
- # icon: "book",
70
- # title: "Welcome to the mona wiki!",
71
- # 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.",
72
- # narrow: true,
73
- # large: true,
74
- # spacious: true,
75
- # ) %>
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
+ # ) %>
76
94
  #
77
95
  # @param title [String] Text that appears in a larger bold font.
78
96
  # @param title_tag [Symbol] HTML tag to use for title.
79
- # @param icon [String] Octicon icon to use at top of component.
80
- # @param icon_size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
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) %>
81
99
  # @param image_src [String] Image to display.
82
100
  # @param image_alt [String] Alt text for image.
83
101
  # @param description [String] Text that appears below the title. Typically a whole sentence.
@@ -89,6 +107,7 @@ module Primer
89
107
  # @param narrow [Boolean] Adds a maximum width.
90
108
  # @param large [Boolean] Increases the font size.
91
109
  # @param spacious [Boolean] Adds extra padding.
110
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
92
111
  def initialize(
93
112
  title: "",
94
113
  title_tag: :h3,
@@ -78,11 +78,12 @@ module Primer
78
78
  #
79
79
  # @param scheme [Symbol] <%= one_of(Primer::ButtonComponent::SCHEME_OPTIONS) %>
80
80
  # @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
81
- # @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
82
- # @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
81
+ # @param tag [Symbol] (Primer::BaseButton::DEFAULT_TAG) <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
82
+ # @param type [Symbol] (Primer::BaseButton::DEFAULT_TYPE) <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
83
83
  # @param group_item [Boolean] Whether button is part of a ButtonGroup.
84
84
  # @param block [Boolean] Whether button is full-width with `display: block`.
85
85
  # @param caret [Boolean] Whether or not to render a caret.
86
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
86
87
  def initialize(
87
88
  scheme: DEFAULT_SCHEME,
88
89
  variant: DEFAULT_VARIANT,
@@ -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
@@ -2,25 +2,43 @@
2
2
 
3
3
  module Primer
4
4
  # Use `ClipboardCopy` to copy element text content or input values to the clipboard.
5
+ #
6
+ # @accessibility
7
+ # Always set an accessible label to help the user interact with the component.
5
8
  class ClipboardCopy < Primer::Component
6
9
  status :alpha
7
10
 
8
11
  # @example Default
9
- # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) %>
12
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) %>
10
13
  #
11
14
  # @example With text instead of icons
12
- # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) do %>
15
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) do %>
13
16
  # Click to copy!
14
17
  # <% end %>
15
18
  #
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
19
+ # @example Copying from an element
20
+ # <%= render(Primer::ClipboardCopy.new(for: "blob-path", "aria-label": "Copy text to the system clipboard")) %>
21
+ # <div id="blob-path">src/index.js</div>
22
+ #
23
+ # @param aria-label [String] String that will be read to screenreaders when the component is focused
24
+ # @param value [String] Text to copy into the users clipboard when they click the component.
25
+ # @param for [String] Element id from where to get the copied value.
18
26
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
19
- def initialize(label:, value:, **system_arguments)
27
+ def initialize(value: nil, **system_arguments)
20
28
  @system_arguments = system_arguments
29
+ @value = value
30
+
31
+ validate!
32
+
21
33
  @system_arguments[:tag] = "clipboard-copy"
22
- @system_arguments[:value] = value
23
- @system_arguments[:"aria-label"] = label
34
+ @system_arguments[:value] = value if value.present?
35
+ end
36
+
37
+ private
38
+
39
+ def validate!
40
+ validate_aria_label
41
+ raise ArgumentError, "Must provide either `value` or `for`" if @value.nil? && @system_arguments[:for].nil?
24
42
  end
25
43
  end
26
44
  end
@@ -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';
@@ -15,9 +16,19 @@ function toggleCopyButton(button) {
15
16
  toggleSVG(clippyIcon);
16
17
  toggleSVG(checkIcon);
17
18
  }
19
+ const clipboardCopyElementTimers = new WeakMap();
18
20
  document.addEventListener('clipboard-copy', function ({ target }) {
19
21
  if (!(target instanceof HTMLElement))
20
22
  return;
21
- toggleCopyButton(target);
22
- 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));
23
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'
@@ -18,9 +20,20 @@ function toggleCopyButton(button: HTMLElement) {
18
20
  toggleSVG(checkIcon)
19
21
  }
20
22
 
23
+ const clipboardCopyElementTimers = new WeakMap<HTMLElement, number>()
24
+
21
25
  document.addEventListener('clipboard-copy', function ({target}) {
22
26
  if (!(target instanceof HTMLElement)) return
23
- 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
+ }
24
37
 
25
- setTimeout(toggleCopyButton, 2000, target)
38
+ clipboardCopyElementTimers.set(target, setTimeout(toggleCopyButton, CLIPBOARD_COPY_TIMER_DURATION, target))
26
39
  })
@@ -5,7 +5,7 @@ require "view_component/version"
5
5
  module Primer
6
6
  # @private
7
7
  class Component < ViewComponent::Base
8
- include ViewComponent::SlotableV2 unless ViewComponent::VERSION::STRING.to_f >= 2.28
8
+ include ViewComponent::SlotableV2 unless ViewComponent::Base < ViewComponent::SlotableV2
9
9
  include ClassNameHelper
10
10
  include FetchOrFallbackHelper
11
11
  include TestSelectorHelper
@@ -14,7 +14,7 @@ module Primer
14
14
 
15
15
  # Use the Summary slot as a trigger to reveal the content.
16
16
  #
17
- # @param button [Boolean] Whether to render the Summary as a button or not.
17
+ # @param button [Boolean] (true) Whether to render the Summary as a button or not.
18
18
  # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
19
19
  renders_one :summary, lambda { |button: true, **system_arguments|
20
20
  system_arguments[:tag] = :summary
@@ -33,6 +33,17 @@ module Primer
33
33
  Primer::BaseComponent.new(**system_arguments)
34
34
  }
35
35
 
36
+ # @example Default
37
+ #
38
+ # <%= render Primer::DetailsComponent.new do |c| %>
39
+ # component.summary do
40
+ # "Summary"
41
+ # end
42
+ # component.body do
43
+ # "Body"
44
+ # end
45
+ # <% end %>
46
+ #
36
47
  # @param overlay [Symbol] Dictates the type of overlay to render with. <%= one_of(Primer::DetailsComponent::OVERLAY_MAPPINGS.keys) %>
37
48
  # @param reset [Boolean] Defatuls to false. If set to true, it will remove the default caret and remove style from the summary element
38
49
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>