primer_view_components 0.0.43 → 0.0.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -4
  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 +97 -41
  7. data/app/components/primer/auto_complete/auto_complete.html.erb +1 -0
  8. data/app/components/primer/beta/text.rb +27 -0
  9. data/app/components/primer/blankslate_component.rb +2 -1
  10. data/app/components/primer/button_component.rb +3 -2
  11. data/app/components/primer/details_component.rb +12 -1
  12. data/app/components/primer/dropdown.d.ts +1 -0
  13. data/app/components/primer/{dropdown_component.html.erb → dropdown.html.erb} +2 -1
  14. data/app/components/primer/dropdown.js +1 -0
  15. data/app/components/primer/dropdown.rb +149 -0
  16. data/app/components/primer/dropdown.ts +1 -0
  17. data/app/components/primer/dropdown/menu.d.ts +1 -0
  18. data/app/components/primer/dropdown/menu.html.erb +25 -0
  19. data/app/components/primer/dropdown/menu.js +1 -0
  20. data/app/components/primer/dropdown/menu.rb +99 -0
  21. data/app/components/primer/dropdown/menu.ts +1 -0
  22. data/app/components/primer/heading_component.rb +1 -1
  23. data/app/components/primer/icon_button.rb +1 -1
  24. data/app/components/primer/navigation/tab_component.rb +2 -2
  25. data/app/components/primer/octicon_component.rb +3 -2
  26. data/app/components/primer/primer.d.ts +1 -0
  27. data/app/components/primer/primer.js +1 -0
  28. data/app/components/primer/primer.ts +1 -0
  29. data/app/components/primer/spinner_component.rb +2 -0
  30. data/lib/primer/view_components/linters/argument_mappers/button.rb +82 -0
  31. data/lib/primer/view_components/linters/argument_mappers/conversion_error.rb +10 -0
  32. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +46 -0
  33. data/lib/primer/view_components/linters/button_component_migration_counter.rb +20 -1
  34. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +1 -1
  35. data/lib/primer/view_components/linters/helpers.rb +7 -3
  36. data/lib/primer/view_components/version.rb +1 -1
  37. data/lib/tasks/docs.rake +111 -96
  38. data/lib/yard/docs_helper.rb +12 -2
  39. data/static/statuses.json +6 -4
  40. metadata +17 -8
  41. data/app/components/primer/button_marketing_component.rb +0 -68
  42. data/app/components/primer/dropdown/menu_component.html.erb +0 -12
  43. data/app/components/primer/dropdown/menu_component.rb +0 -46
  44. data/app/components/primer/dropdown_component.rb +0 -73
  45. data/app/components/primer/text_component.rb +0 -25
@@ -0,0 +1 @@
1
+ import './dropdown/menu';
@@ -1,6 +1,7 @@
1
1
  <%= render(Primer::DetailsComponent.new(**@system_arguments)) do |c| %>
2
- <% c.summary(classes: @summary_classes) do %>
2
+ <% c.summary(**@button_arguments) do %>
3
3
  <%= button %>
4
+ <% if @with_caret %><div class="dropdown-caret"></div><% end %>
4
5
  <% end %>
5
6
 
6
7
  <% c.body do %>
@@ -0,0 +1 @@
1
+ import './dropdown/menu';
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # `Dropdown` is a lightweight context menu for housing navigation and actions.
5
+ # They're great for instances where you don't need the full power (and code) of the SelectMenu.
6
+ class Dropdown < Primer::Component
7
+ # Required trigger for the dropdown. Has the same arguments as <%= link_to_component(Primer::ButtonComponent) %>,
8
+ # but it is locked as a `summary` tag.
9
+ renders_one :button, lambda { |**system_arguments, &block|
10
+ @button_arguments = system_arguments
11
+ @button_arguments[:button] = true
12
+
13
+ view_context.capture { block&.call }
14
+ }
15
+
16
+ # Required context menu for the dropdown.
17
+ #
18
+ # @param as [Symbol] When `as` is `:list`, wraps the menu in a `<ul>` with a `<li>` for each item.
19
+ # @param direction [Symbol] <%= one_of(Primer::Dropdown::Menu::DIRECTION_OPTIONS) %>
20
+ # @param scheme [Symbol] Pass `:dark` for dark mode theming
21
+ # @param header [String] Optional string to display as the header
22
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
23
+ renders_one :menu, "Primer::Dropdown::Menu"
24
+
25
+ # @example Default
26
+ # <%= render(Primer::Dropdown.new) do |c| %>
27
+ # <% c.button do %>
28
+ # Dropdown
29
+ # <% end %>
30
+ #
31
+ # <%= c.menu(header: "Options") do |menu|
32
+ # menu.item { "Item 1" }
33
+ # menu.item { "Item 2" }
34
+ # menu.item { "Item 3" }
35
+ # end %>
36
+ # <% end %>
37
+ #
38
+ # @example With dividers
39
+ #
40
+ # @description
41
+ # Dividers can be used to separate a group of items. They don't have any content.
42
+ # @code
43
+ # <%= render(Primer::Dropdown.new) do |c| %>
44
+ # <% c.button do %>
45
+ # Dropdown
46
+ # <% end %>
47
+ #
48
+ # <%= c.menu(header: "Options") do |menu|
49
+ # menu.item { "Item 1" }
50
+ # menu.item { "Item 2" }
51
+ # menu.item(divider: true)
52
+ # menu.item { "Item 3" }
53
+ # menu.item { "Item 4" }
54
+ # menu.item(divider: true)
55
+ # menu.item { "Item 5" }
56
+ # menu.item { "Item 6" }
57
+ # end %>
58
+ # <% end %>
59
+ #
60
+ # @example With direction
61
+ # <%= render(Primer::Dropdown.new(display: :inline_block)) do |c| %>
62
+ # <% c.button do %>
63
+ # Dropdown
64
+ # <% end %>
65
+ #
66
+ # <%= c.menu(header: "Options", direction: :s) do |menu|
67
+ # menu.item { "Item 1" }
68
+ # menu.item { "Item 2" }
69
+ # menu.item { "Item 3" }
70
+ # menu.item { "Item 4" }
71
+ # end %>
72
+ # <% end %>
73
+ #
74
+ # @example With caret
75
+ # <%= render(Primer::Dropdown.new(with_caret: true)) do |c| %>
76
+ # <% c.button do %>
77
+ # Dropdown
78
+ # <% end %>
79
+ #
80
+ # <%= c.menu(header: "Options") do |menu|
81
+ # menu.item { "Item 1" }
82
+ # menu.item { "Item 2" }
83
+ # menu.item { "Item 3" }
84
+ # menu.item { "Item 4" }
85
+ # end %>
86
+ # <% end %>
87
+ #
88
+ # @example Customizing the button
89
+ # <%= render(Primer::Dropdown.new) do |c| %>
90
+ # <% c.button(scheme: :primary, variant: :small) do %>
91
+ # Dropdown
92
+ # <% end %>
93
+ #
94
+ # <%= c.menu(header: "Options") do |menu|
95
+ # menu.item { "Item 1" }
96
+ # menu.item { "Item 2" }
97
+ # menu.item { "Item 3" }
98
+ # menu.item { "Item 4" }
99
+ # end %>
100
+ # <% end %>
101
+ #
102
+ # @example Menu as list
103
+ # <%= render(Primer::Dropdown.new) do |c| %>
104
+ # <% c.button do %>
105
+ # Dropdown
106
+ # <% end %>
107
+ #
108
+ # <%= c.menu(as: :list, header: "Options") do |menu|
109
+ # menu.item { "Item 1" }
110
+ # menu.item { "Item 2" }
111
+ # menu.item(divider: true)
112
+ # menu.item { "Item 3" }
113
+ # menu.item { "Item 4" }
114
+ # end %>
115
+ # <% end %>
116
+ #
117
+ # @example Customizing menu items
118
+ # <%= render(Primer::Dropdown.new) do |c| %>
119
+ # <% c.button do %>
120
+ # Dropdown
121
+ # <% end %>
122
+ #
123
+ # <%= c.menu(header: "Options") do |menu|
124
+ # menu.item(tag: :button) { "Item 1" }
125
+ # menu.item(classes: "custom-class") { "Item 2" }
126
+ # menu.item { "Item 3" }
127
+ # end %>
128
+ # <% end %>
129
+ #
130
+ # @param overlay [Symbol] <%= one_of(Primer::DetailsComponent::OVERLAY_MAPPINGS.keys) %>
131
+ # @param with_caret [Boolean] Whether or not a caret should be rendered in the button.
132
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
133
+ def initialize(overlay: :default, with_caret: false, **system_arguments)
134
+ @with_caret = with_caret
135
+
136
+ @system_arguments = system_arguments
137
+ @system_arguments[:overlay] = overlay
138
+ @system_arguments[:reset] = true
139
+ @system_arguments[:classes] = class_names(
140
+ @system_arguments[:classes],
141
+ "dropdown"
142
+ )
143
+ end
144
+
145
+ def render?
146
+ button.present? && menu.present?
147
+ end
148
+ end
149
+ end
@@ -0,0 +1 @@
1
+ import './dropdown/menu'
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element';
@@ -0,0 +1,25 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <% if @header.present? %>
3
+ <div class="dropdown-header">
4
+ <%= @header %>
5
+ </div>
6
+ <% end %>
7
+
8
+ <% if list? %>
9
+ <ul>
10
+ <% items.each do |item| %>
11
+ <% if item.divider? %>
12
+ <%= item %>
13
+ <% else %>
14
+ <li>
15
+ <%= item %>
16
+ </li>
17
+ <% end %>
18
+ <% end %>
19
+ </ul>
20
+ <% else %>
21
+ <% items.each do |item| %>
22
+ <%= item %>
23
+ <% end %>
24
+ <% end %>
25
+ <% end %>
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element';
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Dropdown
5
+ # This component is part of `Dropdown` and should not be
6
+ # used as a standalone component.
7
+ class Menu < Primer::Component
8
+ AS_DEFAULT = :default
9
+ AS_OPTIONS = [AS_DEFAULT, :list].freeze
10
+
11
+ SCHEME_DEFAULT = :default
12
+ SCHEME_MAPPINGS = {
13
+ SCHEME_DEFAULT => "",
14
+ :dark => "dropdown-menu-dark"
15
+ }.freeze
16
+
17
+ DIRECTION_DEFAULT = :se
18
+ DIRECTION_OPTIONS = [DIRECTION_DEFAULT, :sw, :w, :e, :ne, :s].freeze
19
+
20
+ # @param tag [Symbol] <%= one_of(Primer::Dropdown::Menu::Item::TAG_OPTIONS) %>.
21
+ # @param divider [Boolean] Whether the item is a divider without any function.
22
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
23
+ renders_many :items, lambda { |divider: false, **system_arguments|
24
+ Primer::Dropdown::Menu::Item.new(as: @as, divider: divider, **system_arguments)
25
+ }
26
+
27
+ # @param as [Symbol] When `as` is `:list`, wraps the menu in a `<ul>` with a `<li>` for each item.
28
+ # @param direction [Symbol] <%= one_of(Primer::Dropdown::Menu::DIRECTION_OPTIONS) %>.
29
+ # @param header [String] Header to be displayed above the menu.
30
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
31
+ def initialize(as: AS_DEFAULT, direction: DIRECTION_DEFAULT, scheme: SCHEME_DEFAULT, header: nil, **system_arguments)
32
+ @header = header
33
+ @direction = direction
34
+ @as = fetch_or_fallback(AS_OPTIONS, as, AS_DEFAULT)
35
+
36
+ @system_arguments = system_arguments
37
+ @system_arguments[:tag] = "details-menu"
38
+ @system_arguments[:role] = "menu"
39
+
40
+ @system_arguments[:classes] = class_names(
41
+ @system_arguments[:classes],
42
+ "dropdown-menu",
43
+ "dropdown-menu-#{fetch_or_fallback(DIRECTION_OPTIONS, direction, DIRECTION_DEFAULT)}",
44
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, SCHEME_DEFAULT)]
45
+ )
46
+ end
47
+
48
+ private
49
+
50
+ def list?
51
+ @as == :list
52
+ end
53
+
54
+ # Items to be rendered in the `Dropdown` menu.
55
+ class Item < Primer::Component
56
+ TAG_DEFAULT = :a
57
+ BUTTON_TAGS = [:button, :summary].freeze
58
+ TAG_OPTIONS = [TAG_DEFAULT, *BUTTON_TAGS].freeze
59
+
60
+ def initialize(as:, tag: TAG_DEFAULT, divider: false, **system_arguments)
61
+ @divider = divider
62
+ @as = as
63
+
64
+ @system_arguments = system_arguments
65
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, TAG_DEFAULT)
66
+ @system_arguments[:tag] = :li if list? && divider?
67
+ @system_arguments[:role] ||= :menuitem
68
+ @system_arguments[:role] = :separator if divider
69
+ @system_arguments[:classes] = class_names(
70
+ @system_arguments[:classes],
71
+ "dropdown-item" => !divider,
72
+ "dropdown-divider" => divider
73
+ )
74
+ end
75
+
76
+ def call
77
+ component = if BUTTON_TAGS.include?(@system_arguments[:tag])
78
+ Primer::ButtonComponent.new(scheme: :link, **@system_arguments)
79
+ else
80
+ Primer::BaseComponent.new(**@system_arguments)
81
+ end
82
+
83
+ # divider has no content
84
+ render(component) if divider?
85
+
86
+ render(component) { content }
87
+ end
88
+
89
+ def divider?
90
+ @divider
91
+ end
92
+
93
+ def list?
94
+ @as == :list
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1 @@
1
+ import '@github/details-menu-element'
@@ -5,7 +5,7 @@ module Primer
5
5
  #
6
6
  # - Set tag to one of `:h1`, `:h2`, `:h3`, `:h4`, `:h5`, `:h6` based on what is appropriate for the page context.
7
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 %>
8
+ # - Do not use `Heading` for styling alone. For simply styling text, consider using <%= link_to_component(Primer::Beta::Text) %> with relevant <%= link_to_typography_docs %>
9
9
  # such as `font_size` and `font_weight`.
10
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.
11
11
  #
@@ -31,7 +31,7 @@ module Primer
31
31
  #
32
32
  # <%= render(Primer::BorderBoxComponent.new) do |component| %>
33
33
  # <% component.body do %>
34
- # <%= render(Primer::TextComponent.new(pr: 2)) { "Body" } %>
34
+ # <%= render(Primer::Beta::Text.new(pr: 2)) { "Body" } %>
35
35
  # <%= render(Primer::IconButton.new(icon: :pencil, box: true, "aria-label": "Edit")) %>
36
36
  # <% end %>
37
37
  # <% end %>
@@ -38,8 +38,8 @@ module Primer
38
38
 
39
39
  # The Tab's text.
40
40
  #
41
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::TextComponent) %>.
42
- renders_one :text, Primer::TextComponent
41
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Text) %>.
42
+ renders_one :text, Primer::Beta::Text
43
43
 
44
44
  # Counter to be rendered in the Tab right.
45
45
  #
@@ -27,8 +27,9 @@ module Primer
27
27
  # @example Helper
28
28
  # <%= primer_octicon(:check) %>
29
29
  #
30
- # @param icon [Symbol] Name of <%= link_to_octicons %> to use.
31
- # @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
30
+ # @param icon_name [Symbol, String] Name of <%= link_to_octicons %> to use.
31
+ # @param icon [Symbol, String] Name of <%= link_to_octicons %> to use.
32
+ # @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS, sort: false) %>
32
33
  # @param use_symbol [Boolean] EXPERIMENTAL (May change or be removed) - Set to true when using with <%= link_to_component(Primer::OcticonSymbolsComponent) %>.
33
34
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
34
35
  def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, use_symbol: false, **system_arguments)
@@ -4,3 +4,4 @@ import './tab_container_component';
4
4
  import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
+ import './dropdown';
@@ -4,3 +4,4 @@ import './tab_container_component';
4
4
  import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
+ import './dropdown';
@@ -4,3 +4,4 @@ import './tab_container_component'
4
4
  import './time_ago_component'
5
5
  import './local_time'
6
6
  import './image_crop'
7
+ import './dropdown'
@@ -27,6 +27,8 @@ module Primer
27
27
  # <%= render(Primer::SpinnerComponent.new(size: :large)) %>
28
28
  #
29
29
  # @param size [Symbol] <%= one_of(Primer::SpinnerComponent::SIZE_MAPPINGS) %>
30
+ # @param style [String] Custom element styles.
31
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
30
32
  def initialize(size: DEFAULT_SIZE, style: DEFAULT_STYLE, **system_arguments)
31
33
  @system_arguments = system_arguments
32
34
  @system_arguments[:tag] = :svg
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "conversion_error"
4
+ require_relative "system_arguments"
5
+
6
+ module ERBLint
7
+ module Linters
8
+ module ArgumentMappers
9
+ # Maps classes in a button element to arguments for the Button component.
10
+ class Button
11
+ SCHEME_MAPPINGS = {
12
+ "btn-primary" => ":primary",
13
+ "btn-danger" => ":danger",
14
+ "btn-outline" => ":outline",
15
+ "btn-invisible" => ":invisible",
16
+ "btn-link" => ":link"
17
+ }.freeze
18
+
19
+ VARIANT_MAPPINGS = {
20
+ "btn-sm" => ":small",
21
+ "btn-large" => ":large"
22
+ }.freeze
23
+
24
+ TYPE_OPTIONS = %w[button reset submit].freeze
25
+
26
+ def initialize(tag)
27
+ @tag = tag
28
+ end
29
+
30
+ def to_s
31
+ to_args.map { |k, v| "#{k}: #{v}" }.join(", ")
32
+ end
33
+
34
+ def to_args
35
+ args = {}
36
+
37
+ args[:tag] = ":#{@tag.name}" unless @tag.name == "button"
38
+
39
+ @tag.attributes.each do |attribute|
40
+ attr_name = attribute.name
41
+
42
+ if attr_name == "class"
43
+ args = args.merge(classes_to_args(attribute))
44
+ elsif attr_name == "disabled"
45
+ args[:disabled] = true
46
+ elsif attr_name == "type"
47
+ # button is the default type, so we don't need to do anything.
48
+ next if attribute.value == "button"
49
+
50
+ raise ConversionError, "Button component does not support type \"#{attribute.value}\"" unless TYPE_OPTIONS.include?(attribute.value)
51
+
52
+ args[:type] = ":#{attribute.value}"
53
+ else
54
+ # Assume the attribute is a system argument.
55
+ args.merge!(SystemArguments.new(attribute).to_args)
56
+ end
57
+ end
58
+
59
+ args
60
+ end
61
+
62
+ def classes_to_args(classes)
63
+ classes.value.split(" ").each_with_object({}) do |class_name, acc|
64
+ next if class_name == "btn"
65
+
66
+ if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
67
+ acc[:scheme] = SCHEME_MAPPINGS[class_name]
68
+ elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
69
+ acc[:variant] = VARIANT_MAPPINGS[class_name]
70
+ elsif class_name == "btn-block"
71
+ acc[:block] = true
72
+ elsif class_name == "BtnGroup-item"
73
+ acc[:group_item] = true
74
+ else
75
+ raise ConversionError, "Cannot convert class \"#{class_name}\""
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end