primer_view_components 0.0.48 → 0.0.52

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 (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"