primer_view_components 0.0.48 → 0.0.52

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +155 -0
  3. data/app/components/primer/base_component.rb +2 -2
  4. data/app/components/primer/beta/avatar.rb +1 -1
  5. data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
  6. data/app/components/primer/beta/avatar_stack.rb +92 -0
  7. data/app/components/primer/beta/truncate.html.erb +5 -0
  8. data/app/components/primer/beta/truncate.rb +110 -0
  9. data/app/components/primer/border_box_component.rb +27 -1
  10. data/app/components/primer/clipboard_copy.html.erb +2 -2
  11. data/app/components/primer/clipboard_copy.rb +1 -1
  12. data/app/components/primer/dropdown.rb +7 -7
  13. data/app/components/primer/icon_button.rb +1 -1
  14. data/app/components/primer/image_crop.html.erb +4 -4
  15. data/app/components/primer/label_component.rb +13 -12
  16. data/app/components/primer/navigation/tab_component.rb +16 -2
  17. data/app/components/primer/progress_bar_component.rb +0 -3
  18. data/app/components/primer/tab_nav_component.rb +4 -3
  19. data/app/components/primer/truncate.rb +1 -1
  20. data/app/components/primer/underline_nav_component.rb +3 -2
  21. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -0
  22. data/app/lib/primer/octicon/cache.rb +1 -1
  23. data/app/lib/primer/tabbed_component_helper.rb +1 -1
  24. data/app/lib/primer/view_helper.rb +1 -0
  25. data/lib/primer/classify.rb +4 -16
  26. data/lib/primer/classify/cache.rb +0 -5
  27. data/lib/primer/classify/flex.rb +1 -1
  28. data/lib/primer/classify/functional_colors.rb +1 -1
  29. data/lib/primer/classify/utilities.rb +51 -13
  30. data/lib/primer/classify/utilities.yml +16 -0
  31. data/lib/primer/classify/validation.rb +18 -0
  32. data/lib/primer/view_components.rb +34 -6
  33. data/lib/primer/view_components/constants.rb +55 -0
  34. data/lib/primer/view_components/linters/argument_mappers/base.rb +100 -0
  35. data/lib/primer/view_components/linters/argument_mappers/button.rb +33 -46
  36. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +19 -0
  37. data/lib/primer/view_components/linters/argument_mappers/helpers/erb_block.rb +67 -0
  38. data/lib/primer/view_components/linters/argument_mappers/label.rb +49 -0
  39. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +6 -5
  40. data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
  41. data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
  42. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
  43. data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +16 -0
  44. data/lib/primer/view_components/linters/helpers.rb +47 -42
  45. data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
  46. data/lib/primer/view_components/version.rb +1 -1
  47. data/lib/rubocop/config/default.yml +5 -0
  48. data/lib/rubocop/cop/primer.rb +1 -2
  49. data/lib/rubocop/cop/primer/deprecated_arguments.rb +173 -0
  50. data/lib/rubocop/cop/primer/no_tag_memoize.rb +1 -0
  51. data/lib/rubocop/cop/primer/primer_octicon.rb +178 -0
  52. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +12 -16
  53. data/lib/tasks/constants.rake +12 -0
  54. data/lib/tasks/coverage.rake +4 -0
  55. data/lib/tasks/docs.rake +27 -25
  56. data/lib/tasks/utilities.rake +9 -13
  57. data/lib/yard/docs_helper.rb +15 -5
  58. data/static/arguments.yml +980 -0
  59. data/static/assets/view-components.svg +18 -0
  60. data/static/classes.yml +182 -0
  61. data/static/constants.json +640 -0
  62. data/static/statuses.json +4 -2
  63. metadata +29 -10
  64. data/app/components/primer/avatar_stack_component.rb +0 -90
@@ -2,7 +2,7 @@
2
2
  <% if content.present? %>
3
3
  <%= content %>
4
4
  <% else %>
5
- <%= render Primer::OcticonComponent.new("clippy") %>
6
- <%= render Primer::OcticonComponent.new("check", color: :icon_success, style: "display: none;") %>
5
+ <%= render Primer::OcticonComponent.new(:paste) %>
6
+ <%= render Primer::OcticonComponent.new(:check, color: :icon_success, style: "display: none;") %>
7
7
  <% end %>
8
8
  <% end %>
@@ -6,7 +6,7 @@ module Primer
6
6
  # @accessibility
7
7
  # Always set an accessible label to help the user interact with the component.
8
8
  class ClipboardCopy < Primer::Component
9
- status :alpha
9
+ status :beta
10
10
 
11
11
  # @example Default
12
12
  # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) %>
@@ -28,7 +28,7 @@ module Primer
28
28
  # Dropdown
29
29
  # <% end %>
30
30
  #
31
- # <%= c.menu(header: "Options") do |menu|
31
+ # <% c.menu(header: "Options") do |menu|
32
32
  # menu.item { "Item 1" }
33
33
  # menu.item { "Item 2" }
34
34
  # menu.item { "Item 3" }
@@ -45,7 +45,7 @@ module Primer
45
45
  # Dropdown
46
46
  # <% end %>
47
47
  #
48
- # <%= c.menu(header: "Options") do |menu|
48
+ # <% c.menu(header: "Options") do |menu|
49
49
  # menu.item { "Item 1" }
50
50
  # menu.item { "Item 2" }
51
51
  # menu.item(divider: true)
@@ -63,7 +63,7 @@ module Primer
63
63
  # Dropdown
64
64
  # <% end %>
65
65
  #
66
- # <%= c.menu(header: "Options", direction: :s) do |menu|
66
+ # <% c.menu(header: "Options", direction: :s) do |menu|
67
67
  # menu.item { "Item 1" }
68
68
  # menu.item { "Item 2" }
69
69
  # menu.item { "Item 3" }
@@ -77,7 +77,7 @@ module Primer
77
77
  # Dropdown
78
78
  # <% end %>
79
79
  #
80
- # <%= c.menu(header: "Options") do |menu|
80
+ # <% c.menu(header: "Options") do |menu|
81
81
  # menu.item { "Item 1" }
82
82
  # menu.item { "Item 2" }
83
83
  # menu.item { "Item 3" }
@@ -91,7 +91,7 @@ module Primer
91
91
  # Dropdown
92
92
  # <% end %>
93
93
  #
94
- # <%= c.menu(header: "Options") do |menu|
94
+ # <% c.menu(header: "Options") do |menu|
95
95
  # menu.item { "Item 1" }
96
96
  # menu.item { "Item 2" }
97
97
  # menu.item { "Item 3" }
@@ -105,7 +105,7 @@ module Primer
105
105
  # Dropdown
106
106
  # <% end %>
107
107
  #
108
- # <%= c.menu(as: :list, header: "Options") do |menu|
108
+ # <% c.menu(as: :list, header: "Options") do |menu|
109
109
  # menu.item { "Item 1" }
110
110
  # menu.item { "Item 2" }
111
111
  # menu.item(divider: true)
@@ -120,7 +120,7 @@ module Primer
120
120
  # Dropdown
121
121
  # <% end %>
122
122
  #
123
- # <%= c.menu(header: "Options") do |menu|
123
+ # <% c.menu(header: "Options") do |menu|
124
124
  # menu.item(tag: :button) { "Item 1" }
125
125
  # menu.item(classes: "custom-class") { "Item 2" }
126
126
  # menu.item { "Item 3" }
@@ -42,7 +42,7 @@ module Primer
42
42
  # @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
43
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
44
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
45
- def initialize(scheme: DEFAULT_SCHEME, icon:, box: false, **system_arguments)
45
+ def initialize(icon:, scheme: DEFAULT_SCHEME, box: false, **system_arguments)
46
46
  @icon = icon
47
47
 
48
48
  @system_arguments = system_arguments
@@ -5,8 +5,8 @@
5
5
  <%= render(Primer::SpinnerComponent.new(size: :large, flex: 1, "data-loading-slot": true)) %>
6
6
  <% end %>
7
7
 
8
- <input type="hidden" data-image-crop-input="x" name="cropped_x">
9
- <input type="hidden" data-image-crop-input="y" name="cropped_y">
10
- <input type="hidden" data-image-crop-input="width" name="cropped_width">
11
- <input type="hidden" data-image-crop-input="height" name="cropped_height">
8
+ <input autocomplete="off" type="hidden" data-image-crop-input="x" name="cropped_x">
9
+ <input autocomplete="off" type="hidden" data-image-crop-input="y" name="cropped_y">
10
+ <input autocomplete="off" type="hidden" data-image-crop-input="width" name="cropped_width">
11
+ <input autocomplete="off" type="hidden" data-image-crop-input="height" name="cropped_height">
12
12
  <% end %>
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Primer
4
4
  # Use `Label` to add contextual metadata to a design.
5
+ #
6
+ # @accessibility
7
+ # Use `aria-label` if the `Label` or the context around it don't explain the label.
5
8
  class LabelComponent < Primer::Component
6
9
  status :beta
7
10
 
@@ -29,27 +32,25 @@ module Primer
29
32
  VARIANT_OPTIONS = VARIANT_MAPPINGS.keys << nil
30
33
 
31
34
  # @example Schemes
32
- # <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "Default" } %>
33
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :primary)) { "Primary" } %>
34
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :secondary)) { "Secondary" } %>
35
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :info)) { "Info" } %>
36
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :success)) { "Success" } %>
37
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :warning)) { "Warning" } %>
38
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :danger)) { "Danger" } %>
35
+ # <%= render(Primer::LabelComponent.new) { "Default" } %>
36
+ # <%= render(Primer::LabelComponent.new( scheme: :primary)) { "Primary" } %>
37
+ # <%= render(Primer::LabelComponent.new( scheme: :secondary)) { "Secondary" } %>
38
+ # <%= render(Primer::LabelComponent.new( scheme: :info)) { "Info" } %>
39
+ # <%= render(Primer::LabelComponent.new( scheme: :success)) { "Success" } %>
40
+ # <%= render(Primer::LabelComponent.new( scheme: :warning)) { "Warning" } %>
41
+ # <%= render(Primer::LabelComponent.new( scheme: :danger)) { "Danger" } %>
39
42
  #
40
43
  # @example Variants
41
- # <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "Default" } %>
42
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", variant: :large)) { "Large" } %>
44
+ # <%= render(Primer::LabelComponent.new) { "Default" } %>
45
+ # <%= render(Primer::LabelComponent.new( variant: :large)) { "Large" } %>
43
46
  #
44
47
  # @param tag [Symbol] <%= one_of(Primer::LabelComponent::TAG_OPTIONS) %>
45
- # @param title [String] `title` attribute for the component element.
46
48
  # @param scheme [Symbol] <%= one_of(Primer::LabelComponent::SCHEME_MAPPINGS.keys) %>
47
49
  # @param variant [Symbol] <%= one_of(Primer::LabelComponent::VARIANT_OPTIONS) %>
48
50
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
49
- def initialize(tag: DEFAULT_TAG, title:, scheme: nil, variant: nil, **system_arguments)
51
+ def initialize(tag: DEFAULT_TAG, scheme: nil, variant: nil, **system_arguments)
50
52
  @system_arguments = system_arguments
51
53
  @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
52
- @system_arguments[:title] = title
53
54
  @system_arguments[:classes] = class_names(
54
55
  "Label",
55
56
  system_arguments[:classes],
@@ -20,6 +20,7 @@ module Primer
20
20
  renders_one :panel, lambda { |**system_arguments|
21
21
  return unless @with_panel
22
22
 
23
+ system_arguments[:id] = @panel_id
23
24
  system_arguments[:tag] = :div
24
25
  system_arguments[:role] ||= :tabpanel
25
26
  system_arguments[:tabindex] = 0
@@ -98,10 +99,11 @@ module Primer
98
99
  # @param list [Boolean] Whether the Tab is an item in a `<ul>` list.
99
100
  # @param selected [Boolean] Whether the Tab is selected or not.
100
101
  # @param with_panel [Boolean] Whether the Tab has an associated panel.
102
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
101
103
  # @param icon_classes [Boolean] Classes that must always be applied to icons.
102
104
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> to be used in the `<li>` wrapper when the tab is an item in a list.
103
105
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
104
- def initialize(list: false, selected: false, with_panel: false, icon_classes: "", wrapper_arguments: {}, **system_arguments)
106
+ def initialize(list: false, selected: false, with_panel: false, panel_id: "", icon_classes: "", wrapper_arguments: {}, **system_arguments)
105
107
  @selected = selected
106
108
  @icon_classes = icon_classes
107
109
  @list = list
@@ -114,6 +116,7 @@ module Primer
114
116
  @system_arguments[:tag] = :button
115
117
  @system_arguments[:type] = :button
116
118
  @system_arguments[:role] = :tab
119
+ panel_id(panel_id)
117
120
  else
118
121
  @system_arguments[:tag] = :a
119
122
  end
@@ -139,7 +142,18 @@ module Primer
139
142
  end
140
143
 
141
144
  render(Primer::BaseComponent.new(**@wrapper_arguments)) do
142
- yield
145
+ yield if block_given?
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def panel_id(panel_id)
152
+ if panel_id.blank?
153
+ raise ArgumentError, "`panel_id` is required" unless Rails.env.production?
154
+ else
155
+ @panel_id = panel_id
156
+ @system_arguments[:"aria-controls"] = @panel_id
143
157
  end
144
158
  end
145
159
  end
@@ -11,9 +11,6 @@ module Primer
11
11
  # @param bg [Symbol] The background color
12
12
  # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
13
13
  renders_many :items, lambda { |percentage: 0, bg: :success_inverse, **system_arguments|
14
- percentage = percentage
15
- system_arguments = system_arguments
16
-
17
14
  system_arguments[:tag] = :span
18
15
  system_arguments[:bg] = bg
19
16
  system_arguments[:style] = join_style_arguments(system_arguments[:style], "width: #{percentage}%;")
@@ -13,6 +13,7 @@ module Primer
13
13
  # Tabs to be rendered. When `with_panel` is set on the parent, a button is rendered for panel navigation. Otherwise,
14
14
  # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
15
15
  #
16
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique ID of panel.
16
17
  # @param selected [Boolean] Whether the tab is selected.
17
18
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
18
19
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -63,19 +64,19 @@ module Primer
63
64
  #
64
65
  # @example With panels
65
66
  # <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
66
- # <% c.tab(selected: true, id: "tab-1") do |t| %>
67
+ # <% c.tab(selected: true, panel_id: "panel-1", id: "tab-1") do |t| %>
67
68
  # <% t.text { "Tab 1" } %>
68
69
  # <% t.panel do %>
69
70
  # Panel 1
70
71
  # <% end %>
71
72
  # <% end %>
72
- # <% c.tab(id: "tab-2") do |t| %>
73
+ # <% c.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
73
74
  # <% t.text { "Tab 2" } %>
74
75
  # <% t.panel do %>
75
76
  # Panel 2
76
77
  # <% end %>
77
78
  # <% end %>
78
- # <% c.tab(id: "tab-3") do |t| %>
79
+ # <% c.tab(id: "tab-3", panel_id: "panel-3") do |t| %>
79
80
  # <% t.text { "Tab 3" } %>
80
81
  # <% t.panel do %>
81
82
  # Panel 3
@@ -6,7 +6,7 @@ module Primer
6
6
  status :beta
7
7
 
8
8
  DEFAULT_TAG = :div
9
- TAG_OPTIONS = [DEFAULT_TAG, :span, :p].freeze
9
+ TAG_OPTIONS = [DEFAULT_TAG, :span, :p, :strong].freeze
10
10
 
11
11
  # @example Default
12
12
  # <div class="col-2">
@@ -19,6 +19,7 @@ module Primer
19
19
  # Use the tabs to list navigation items. When `with_panel` is set on the parent, a button is rendered for panel navigation. Otherwise,
20
20
  # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
21
21
  #
22
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
22
23
  # @param selected [Boolean] Whether the tab is selected.
23
24
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
25
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -104,13 +105,13 @@ module Primer
104
105
  #
105
106
  # @example With panels
106
107
  # <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
107
- # <% component.tab(selected: true, id: "tab-1") do |t| %>
108
+ # <% component.tab(selected: true, id: "tab-1", panel_id: "panel-1") do |t| %>
108
109
  # <% t.text { "Item 1" } %>
109
110
  # <% t.panel do %>
110
111
  # Panel 1
111
112
  # <% end %>
112
113
  # <% end %>
113
- # <% component.tab(id: "tab-2") do |t| %>
114
+ # <% component.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
114
115
  # <% t.text { "Item 2" } %>
115
116
  # <% t.panel do %>
116
117
  # Panel 2
@@ -48,6 +48,7 @@ module Primer
48
48
  end
49
49
  end
50
50
 
51
+ # rubocop:disable Style/OptionalBooleanParameter
51
52
  def fetch_or_fallback_boolean(given_value, fallback = false)
52
53
  if [true, false].include?(given_value)
53
54
  given_value
@@ -55,6 +56,7 @@ module Primer
55
56
  fallback
56
57
  end
57
58
  end
59
+ # rubocop:enable Style/OptionalBooleanParameter
58
60
 
59
61
  def silence_deprecations?
60
62
  Rails.application.config.primer_view_components.silence_deprecations
@@ -6,7 +6,7 @@ module Primer
6
6
  class Cache
7
7
  LOOKUP = {} # rubocop:disable Style/MutableConstant
8
8
  # Preload the top 20 used icons.
9
- PRELOADED_ICONS = [:alert, :check, :"chevron-down", :clippy, :clock, :"dot-fill", :info, :"kebab-horizontal", :link, :lock, :mail, :pencil, :plus, :question, :repo, :search, :"shield-lock", :star, :trash, :x].freeze
9
+ PRELOADED_ICONS = [:alert, :check, :"chevron-down", :paste, :clock, :"dot-fill", :info, :"kebab-horizontal", :link, :lock, :mail, :pencil, :plus, :question, :repo, :search, :"shield-lock", :star, :trash, :x].freeze
10
10
 
11
11
  class << self
12
12
  def get_key(symbol:, size:, width: nil, height: nil)
@@ -24,7 +24,7 @@ module Primer
24
24
  return yield unless @with_panel
25
25
 
26
26
  render Primer::TabContainerComponent.new(**system_arguments) do
27
- yield
27
+ yield if block_given?
28
28
  end
29
29
  end
30
30
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :nocov:
3
4
  module Primer
4
5
  # Module to allow shorthand calls for Primer components
5
6
  module ViewHelper
@@ -7,6 +7,7 @@ require_relative "classify/functional_border_colors"
7
7
  require_relative "classify/functional_text_colors"
8
8
  require_relative "classify/grid"
9
9
  require_relative "classify/utilities"
10
+ require_relative "classify/validation"
10
11
 
11
12
  module Primer
12
13
  # :nodoc:
@@ -14,14 +15,9 @@ module Primer
14
15
  # Keys where we can simply translate { key: value } into ".key-value"
15
16
  CONCAT_KEYS = %i[text box_shadow].freeze
16
17
 
17
- INVALID_CLASS_NAME_PREFIXES =
18
- (["bg-", "color-", "text-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
19
-
20
18
  COLOR_KEY = :color
21
19
  BG_KEY = :bg
22
20
  TEXT_KEYS = %i[font_family font_style font_weight text_align text_transform].freeze
23
- WIDTH_KEY = :width
24
- HEIGHT_KEY = :height
25
21
  BOX_SHADOW_KEY = :box_shadow
26
22
  CONTAINER_KEY = :container
27
23
 
@@ -94,8 +90,6 @@ module Primer
94
90
  BORDER_RADIUS_KEY,
95
91
  COLOR_KEY,
96
92
  BG_KEY,
97
- WIDTH_KEY,
98
- HEIGHT_KEY,
99
93
  BOX_SHADOW_KEY,
100
94
  CONTAINER_KEY
101
95
  ]
@@ -113,7 +107,7 @@ module Primer
113
107
  extracted_results[:style] = [
114
108
  extracted_results.delete(:styles),
115
109
  style
116
- ].compact.join("").presence
110
+ ].compact.join.presence
117
111
 
118
112
  extracted_results
119
113
  end
@@ -125,8 +119,8 @@ module Primer
125
119
 
126
120
  if force_system_arguments? && !ENV["PRIMER_WARNINGS_DISABLED"]
127
121
  invalid_class_names =
128
- classes.split(" ").each_with_object([]) do |class_name, memo|
129
- memo << class_name if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) } || Primer::Classify::Utilities.supported_selector?(class_name)
122
+ classes.split.each_with_object([]) do |class_name, memo|
123
+ memo << class_name if Primer::Classify::Validation.invalid?(class_name)
130
124
  end
131
125
 
132
126
  raise ArgumentError, "Use System Arguments (https://primer.style/view-components/system-arguments) instead of Primer CSS class #{'name'.pluralize(invalid_class_names.length)} #{invalid_class_names.to_sentence}. This warning will not be raised in production. Set PRIMER_WARNINGS_DISABLED=1 to disable this warning." if invalid_class_names.any?
@@ -202,12 +196,6 @@ module Primer
202
196
  memo[:classes] << Primer::Classify::Flex.classes(key, val, breakpoint)
203
197
  elsif Primer::Classify::Grid::KEYS.include?(key)
204
198
  memo[:classes] << Primer::Classify::Grid.classes(key, val, breakpoint)
205
- elsif key == WIDTH_KEY || key == HEIGHT_KEY
206
- if val == :fit
207
- memo[:classes] << "#{key}-#{val}"
208
- else
209
- memo[key] = val
210
- end
211
199
  elsif TEXT_KEYS.include?(key)
212
200
  memo[:classes] << "text-#{val.to_s.dasherize}"
213
201
  elsif TYPOGRAPHY_KEYS.include?(key)
@@ -95,11 +95,6 @@ module Primer
95
95
  values: Primer::Classify::Flex::ALIGN_SELF_VALUES
96
96
  )
97
97
 
98
- preload(
99
- keys: [Primer::Classify::WIDTH_KEY, Primer::Classify::HEIGHT_KEY],
100
- values: [:fit]
101
- )
102
-
103
98
  preload(
104
99
  keys: Primer::Classify::BOX_SHADOW_KEY,
105
100
  values: [true, :small, :medium, :large, :extra_large, :none]
@@ -89,7 +89,7 @@ module Primer
89
89
  def justify_content(value, breakpoint)
90
90
  val = fetch_or_fallback(JUSTIFY_CONTENT_VALUES, value)
91
91
 
92
- formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
92
+ formatted_value = val.to_s.gsub(/(flex_|space_)/, "")
93
93
  "flex#{breakpoint}-justify-#{formatted_value}"
94
94
  end
95
95
 
@@ -24,9 +24,9 @@ module Primer
24
24
  value:,
25
25
  mappings:,
26
26
  non_functional_prefix:,
27
+ functional_options:,
27
28
  functional_prefix: "",
28
29
  number_prefix: "",
29
- functional_options:,
30
30
  options_without_mappigs: []
31
31
  )
32
32
  sym_value = value.to_sym
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  # :nodoc:
4
6
  module Primer
5
7
  class Classify
@@ -16,6 +18,17 @@ module Primer
16
18
  # rubocop:enable Security/YAMLLoad
17
19
  BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
18
20
 
21
+ # Replacements for some classnames that end up being a different argument key
22
+ REPLACEMENT_KEYS = {
23
+ "^anim" => "animation",
24
+ "^v-align" => "vertical_align",
25
+ "^d" => "display",
26
+ "^wb" => "word_break",
27
+ "^v" => "visibility",
28
+ "^width" => "w",
29
+ "^height" => "h"
30
+ }.freeze
31
+
19
32
  class << self
20
33
  def classname(key, val, breakpoint = "")
21
34
  if (valid = validate(key, val, breakpoint))
@@ -72,7 +85,7 @@ module Primer
72
85
  return { classes: classes } if ENV["RAILS_ENV"] == "production"
73
86
 
74
87
  obj = {}
75
- classes = classes.split(" ")
88
+ classes = classes.split
76
89
  # Loop through all classes supplied and reject ones we find a match for
77
90
  # So when we're at the end of the loop we have classes left with any non-system classes.
78
91
  classes.reject! do |classname|
@@ -101,26 +114,51 @@ module Primer
101
114
  obj
102
115
  end
103
116
 
117
+ def classes_to_args(classes)
118
+ classes_to_hash(classes).map do |key, value|
119
+ val = case value
120
+ when Symbol
121
+ ":#{value}"
122
+ when String
123
+ value.to_json
124
+ else
125
+ value
126
+ end
127
+
128
+ "#{key}: #{val}"
129
+ end.join(", ")
130
+ end
131
+
104
132
  private
105
133
 
106
134
  def find_selector(selector)
107
- # Search each key/value_hash pair, eg. key `:mr` and value_hash `{ 0 => [ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ] }`
108
- UTILITIES.each do |key, value_hash|
109
- # Each value hash will also contain an array of classnames for breakpoints
110
- # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
111
- value_hash.each do |key_argument, classnames|
112
- # Skip each value hash until we get one with the selector
113
- next unless classnames.include?(selector)
114
-
115
- # Return [:mr, 0, 1]
116
- # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
117
- return [key, key_argument, classnames.index(selector)]
118
- end
135
+ key = infer_selector_key(selector)
136
+ value_hash = UTILITIES[key]
137
+
138
+ return nil if value_hash.blank?
139
+
140
+ # Each value hash will also contain an array of classnames for breakpoints
141
+ # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
142
+ value_hash.each do |key_argument, classnames|
143
+ # Skip each value hash until we get one with the selector
144
+ next unless classnames.include?(selector)
145
+
146
+ # Return [:mr, 0, 1]
147
+ # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
148
+ return [key, key_argument, classnames.index(selector)]
119
149
  end
120
150
 
121
151
  nil
122
152
  end
123
153
 
154
+ def infer_selector_key(selector)
155
+ REPLACEMENT_KEYS.each do |k, v|
156
+ return v.to_sym if selector.match?(Regexp.new(k))
157
+ end
158
+
159
+ selector.split("-").first.to_sym
160
+ end
161
+
124
162
  def validate(key, val, breakpoint)
125
163
  unless supported_key?(key)
126
164
  raise ArgumentError, "#{key} is not a valid Primer utility key" unless ENV["RAILS_ENV"] == "production"