primer_view_components 0.0.43 → 0.0.47

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -3
  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/avatar_stack_component.rb +9 -3
  7. data/app/components/primer/base_component.rb +52 -23
  8. data/app/components/primer/beta/auto_complete.rb +159 -0
  9. data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
  10. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +1 -0
  11. data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
  12. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
  13. data/app/components/primer/beta/auto_complete/item.rb +44 -0
  14. data/app/components/primer/beta/avatar.rb +77 -0
  15. data/app/components/primer/beta/text.rb +27 -0
  16. data/app/components/primer/blankslate_component.rb +2 -1
  17. data/app/components/primer/border_box_component.rb +3 -0
  18. data/app/components/primer/button_component.rb +3 -2
  19. data/app/components/primer/clipboard_copy.rb +25 -7
  20. data/app/components/primer/component.rb +4 -0
  21. data/app/components/primer/details_component.rb +18 -3
  22. data/app/components/primer/dropdown.d.ts +1 -0
  23. data/app/components/primer/{dropdown_component.html.erb → dropdown.html.erb} +2 -1
  24. data/app/components/primer/dropdown.js +1 -0
  25. data/app/components/primer/dropdown.rb +149 -0
  26. data/app/components/primer/dropdown.ts +1 -0
  27. data/app/components/primer/dropdown/menu.d.ts +1 -0
  28. data/app/components/primer/dropdown/menu.html.erb +25 -0
  29. data/app/components/primer/dropdown/menu.js +1 -0
  30. data/app/components/primer/dropdown/menu.rb +99 -0
  31. data/app/components/primer/dropdown/menu.ts +1 -0
  32. data/app/components/primer/heading_component.rb +1 -1
  33. data/app/components/primer/icon_button.rb +1 -1
  34. data/app/components/primer/image_crop.rb +1 -1
  35. data/app/components/primer/markdown.rb +9 -9
  36. data/app/components/primer/menu_component.rb +7 -3
  37. data/app/components/primer/navigation/tab_component.rb +6 -6
  38. data/app/components/primer/octicon_component.rb +3 -2
  39. data/app/components/primer/popover_component.rb +6 -3
  40. data/app/components/primer/primer.d.ts +2 -1
  41. data/app/components/primer/primer.js +2 -1
  42. data/app/components/primer/primer.ts +2 -1
  43. data/app/components/primer/spinner_component.rb +2 -0
  44. data/app/components/primer/tab_nav_component.rb +5 -3
  45. data/app/components/primer/timeline_item_component.rb +2 -2
  46. data/app/components/primer/tooltip.rb +1 -1
  47. data/app/components/primer/truncate.rb +5 -0
  48. data/app/components/primer/underline_nav_component.rb +10 -4
  49. data/{app/lib → lib}/primer/classify.rb +16 -33
  50. data/{app/lib → lib}/primer/classify/cache.rb +6 -40
  51. data/{app/lib → lib}/primer/classify/flex.rb +0 -0
  52. data/{app/lib → lib}/primer/classify/functional_background_colors.rb +2 -0
  53. data/{app/lib → lib}/primer/classify/functional_border_colors.rb +2 -0
  54. data/{app/lib → lib}/primer/classify/functional_colors.rb +0 -0
  55. data/{app/lib → lib}/primer/classify/functional_text_colors.rb +2 -0
  56. data/{app/lib → lib}/primer/classify/grid.rb +0 -0
  57. data/lib/primer/classify/utilities.rb +148 -0
  58. data/lib/primer/classify/utilities.yml +1271 -0
  59. data/lib/primer/view_components.rb +1 -0
  60. data/lib/primer/view_components/linters/argument_mappers/button.rb +82 -0
  61. data/lib/primer/view_components/linters/argument_mappers/conversion_error.rb +10 -0
  62. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +47 -0
  63. data/lib/primer/view_components/linters/button_component_migration_counter.rb +24 -1
  64. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +1 -1
  65. data/lib/primer/view_components/linters/helpers.rb +137 -18
  66. data/lib/primer/view_components/statuses.rb +14 -0
  67. data/lib/primer/view_components/version.rb +1 -1
  68. data/lib/tasks/docs.rake +179 -110
  69. data/lib/tasks/utilities.rake +105 -0
  70. data/lib/yard/docs_helper.rb +13 -3
  71. data/static/statuses.json +9 -7
  72. metadata +41 -27
  73. data/app/components/primer/auto_complete.rb +0 -100
  74. data/app/components/primer/auto_complete/item.rb +0 -42
  75. data/app/components/primer/avatar_component.rb +0 -75
  76. data/app/components/primer/button_marketing_component.rb +0 -68
  77. data/app/components/primer/dropdown/menu_component.html.erb +0 -12
  78. data/app/components/primer/dropdown/menu_component.rb +0 -46
  79. data/app/components/primer/dropdown_component.rb +0 -73
  80. data/app/components/primer/text_component.rb +0 -25
  81. data/app/lib/primer/classify/spacing.rb +0 -63
@@ -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)
@@ -23,12 +23,15 @@ module Primer
23
23
  :top_right => "Popover-message--top-right"
24
24
  }.freeze
25
25
 
26
+ DEFAULT_HEADING_TAG = :h4
27
+
26
28
  # The heading
27
29
  #
30
+ # @param tag [Symbol] (Primer::PopoverComponent::DEFAULT_HEADING_TAG) <%= one_of(Primer::HeadingComponent::TAG_OPTIONS) %>
28
31
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
29
- renders_one :heading, lambda { |**system_arguments|
32
+ renders_one :heading, lambda { |tag: DEFAULT_HEADING_TAG, **system_arguments|
33
+ system_arguments[:tag] = tag
30
34
  system_arguments[:mb] ||= 2
31
- system_arguments[:tag] ||= :h4
32
35
 
33
36
  Primer::HeadingComponent.new(**system_arguments)
34
37
  }
@@ -106,7 +109,7 @@ module Primer
106
109
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
107
110
  def initialize(**system_arguments)
108
111
  @system_arguments = system_arguments
109
- @system_arguments[:tag] ||= :div
112
+ @system_arguments[:tag] = :div
110
113
  @system_arguments[:classes] = class_names(
111
114
  system_arguments[:classes],
112
115
  "Popover"
@@ -1,6 +1,7 @@
1
- import './auto_complete/auto_complete';
1
+ import './beta/auto_complete/auto_complete';
2
2
  import './clipboard_copy_component';
3
3
  import './tab_container_component';
4
4
  import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
+ import './dropdown';
@@ -1,6 +1,7 @@
1
- import './auto_complete/auto_complete';
1
+ import './beta/auto_complete/auto_complete';
2
2
  import './clipboard_copy_component';
3
3
  import './tab_container_component';
4
4
  import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
+ import './dropdown';
@@ -1,6 +1,7 @@
1
- import './auto_complete/auto_complete'
1
+ import './beta/auto_complete/auto_complete'
2
2
  import './clipboard_copy_component'
3
3
  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
@@ -10,7 +10,8 @@ module Primer
10
10
  DEFAULT_EXTRA_ALIGN = :left
11
11
  EXTRA_ALIGN_OPTIONS = [DEFAULT_EXTRA_ALIGN, :right].freeze
12
12
 
13
- # Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
13
+ # Tabs to be rendered. When `with_panel` is set on the parent, a button is rendered for panel navigation. Otherwise,
14
+ # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
14
15
  #
15
16
  # @param selected [Boolean] Whether the tab is selected.
16
17
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -119,7 +120,8 @@ module Primer
119
120
  # <% end %>
120
121
  #
121
122
  # @param label [String] Used to set the `aria-label` on the top level `<nav>` element.
122
- # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
123
+ # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels. When true, <%= link_to_component(Primer::TabContainerComponent) %>
124
+ # is rendered along with JavaScript behavior. Additionally, the `tab` slot will render as a button as opposed to an anchor.
123
125
  # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
124
126
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper. Only applies if `with_panel` is `true`.
125
127
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -130,7 +132,7 @@ module Primer
130
132
  @body_arguments = body_arguments
131
133
  @wrapper_arguments = wrapper_arguments
132
134
 
133
- @system_arguments[:tag] ||= :div
135
+ @system_arguments[:tag] = :div
134
136
  @system_arguments[:classes] = class_names(
135
137
  "tabnav",
136
138
  system_arguments[:classes]
@@ -7,14 +7,14 @@ module Primer
7
7
 
8
8
  # Avatar to be rendered to the left of the Badge.
9
9
  #
10
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::AvatarComponent) %>.
10
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Avatar) %>.
11
11
  renders_one :avatar, lambda { |src:, size: 40, square: true, **system_arguments|
12
12
  system_arguments[:classes] = class_names(
13
13
  "TimelineItem-avatar",
14
14
  system_arguments[:classes]
15
15
  )
16
16
 
17
- Primer::AvatarComponent.new(src: src, size: size, square: square, **system_arguments)
17
+ Primer::Beta::Avatar.new(src: src, size: size, square: square, **system_arguments)
18
18
  }
19
19
 
20
20
  # Badge that will be connected to other TimelineItems.
@@ -70,7 +70,7 @@ module Primer
70
70
  **system_arguments
71
71
  )
72
72
  @system_arguments = system_arguments
73
- @system_arguments[:tag] ||= :span
73
+ @system_arguments[:tag] ||= :span # rubocop:disable Primer/NoTagMemoize
74
74
  @system_arguments[:aria] = { label: label }
75
75
 
76
76
  @system_arguments[:classes] = class_names(
@@ -22,6 +22,11 @@ module Primer
22
22
  # @example Custom size
23
23
  # <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true, max_width: 100)) { "branch-name-that-is-really-long" } %>
24
24
  #
25
+ # @example With HTML content
26
+ # <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true, max_width: 100)) do %>
27
+ # <span>branch-name-that-is-really-long</span>
28
+ # <% end %>
29
+ #
25
30
  # @param tag [Symbol] <%= one_of(Primer::Truncate::TAG_OPTIONS) %>
26
31
  # @param inline [Boolean] Whether the element is inline (or inline-block).
27
32
  # @param expandable [Boolean] Whether the entire string should be revealed on hover. Can only be used in conjunction with `inline`.
@@ -13,7 +13,11 @@ module Primer
13
13
  BODY_TAG_DEFAULT = :div
14
14
  BODY_TAG_OPTIONS = [BODY_TAG_DEFAULT, :ul].freeze
15
15
 
16
- # Use the tabs to list navigation items. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
16
+ ACTIONS_TAG_DEFAULT = :div
17
+ ACTIONS_TAG_OPTIONS = [ACTIONS_TAG_DEFAULT, :span].freeze
18
+
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
+ # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
17
21
  #
18
22
  # @param selected [Boolean] Whether the tab is selected.
19
23
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -34,9 +38,10 @@ module Primer
34
38
 
35
39
  # Use actions for a call to action.
36
40
  #
41
+ # @param tag [Symbol] (Primer::UnderlineNavComponent::ACTIONS_TAG_DEFAULT) <%= one_of(Primer::UnderlineNavComponent::ACTIONS_TAG_OPTIONS) %>
37
42
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
38
- renders_one :actions, lambda { |**system_arguments|
39
- system_arguments[:tag] ||= :div
43
+ renders_one :actions, lambda { |tag: ACTIONS_TAG_DEFAULT, **system_arguments|
44
+ system_arguments[:tag] = fetch_or_fallback(ACTIONS_TAG_OPTIONS, tag, ACTIONS_TAG_DEFAULT)
40
45
  system_arguments[:classes] = class_names("UnderlineNav-actions", system_arguments[:classes])
41
46
 
42
47
  Primer::BaseComponent.new(**system_arguments)
@@ -131,7 +136,8 @@ module Primer
131
136
  # <% end %>
132
137
  #
133
138
  # @param label [String] The `aria-label` on top level `<nav>` element.
134
- # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
139
+ # @param with_panel [Boolean] Whether the `UnderlineNav` should navigate through pages or panels. When true, <%= link_to_component(Primer::TabContainerComponent) %> is
140
+ # rendered along with JavaScript behavior.
135
141
  # @param align [Symbol] <%= one_of(Primer::UnderlineNavComponent::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavComponent::ALIGN_DEFAULT %>
136
142
  # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
137
143
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper. Only applies if `with_panel` is `true`.
@@ -1,31 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "classify/cache"
4
+ require_relative "classify/flex"
5
+ require_relative "classify/functional_background_colors"
6
+ require_relative "classify/functional_border_colors"
7
+ require_relative "classify/functional_text_colors"
8
+ require_relative "classify/grid"
9
+ require_relative "classify/utilities"
10
+
3
11
  module Primer
4
12
  # :nodoc:
5
13
  class Classify
6
- DISPLAY_KEY = :display
7
- SPACING_KEYS = Primer::Classify::Spacing::KEYS
8
-
9
14
  # Keys where we can simply translate { key: value } into ".key-value"
10
- CONCAT_KEYS = SPACING_KEYS + %i[hide position v float text box_shadow].freeze
15
+ CONCAT_KEYS = %i[text box_shadow].freeze
11
16
 
12
17
  INVALID_CLASS_NAME_PREFIXES =
13
- (["bg-", "color-", "text-", "d-", "v-align-", "wb-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
18
+ (["bg-", "color-", "text-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
14
19
 
15
20
  COLOR_KEY = :color
16
21
  BG_KEY = :bg
17
- VERTICAL_ALIGN_KEY = :vertical_align
18
- WORD_BREAK_KEY = :word_break
19
22
  TEXT_KEYS = %i[font_family font_style font_weight text_align text_transform].freeze
20
23
  WIDTH_KEY = :width
21
24
  HEIGHT_KEY = :height
22
25
  BOX_SHADOW_KEY = :box_shadow
23
- VISIBILITY_KEY = :visibility
24
- ANIMATION_KEY = :animation
25
26
  CONTAINER_KEY = :container
26
27
 
27
28
  BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
28
- RESPONSIVE_KEYS = ([DISPLAY_KEY, :float, Primer::Classify::Grid::COL_KEY] + SPACING_KEYS + Primer::Classify::Flex::RESPONSIVE_KEYS).freeze
29
+ RESPONSIVE_KEYS = ([Primer::Classify::Grid::COL_KEY] + Primer::Classify::Flex::RESPONSIVE_KEYS).freeze
29
30
 
30
31
  BOOLEAN_MAPPINGS = {
31
32
  underline: {
@@ -79,6 +80,7 @@ module Primer
79
80
  BORDER_RADIUS_KEY = :border_radius
80
81
  TYPOGRAPHY_KEYS = [:font_size].freeze
81
82
  VALID_KEYS = (
83
+ Primer::Classify::Utilities::UTILITIES.keys +
82
84
  CONCAT_KEYS +
83
85
  BOOLEAN_MAPPINGS.keys +
84
86
  BORDER_MARGIN_KEYS +
@@ -92,14 +94,9 @@ module Primer
92
94
  BORDER_RADIUS_KEY,
93
95
  COLOR_KEY,
94
96
  BG_KEY,
95
- DISPLAY_KEY,
96
- VERTICAL_ALIGN_KEY,
97
- WORD_BREAK_KEY,
98
97
  WIDTH_KEY,
99
98
  HEIGHT_KEY,
100
99
  BOX_SHADOW_KEY,
101
- VISIBILITY_KEY,
102
- ANIMATION_KEY,
103
100
  CONTAINER_KEY
104
101
  ]
105
102
  ).freeze
@@ -129,7 +126,7 @@ module Primer
129
126
  if force_system_arguments? && !ENV["PRIMER_WARNINGS_DISABLED"]
130
127
  invalid_class_names =
131
128
  classes.split(" ").each_with_object([]) do |class_name, memo|
132
- memo << class_name if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) }
129
+ memo << class_name if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) } || Primer::Classify::Utilities.supported_selector?(class_name)
133
130
  end
134
131
 
135
132
  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?
@@ -155,7 +152,7 @@ module Primer
155
152
  next unless VALID_KEYS.include?(key)
156
153
 
157
154
  if value.is_a?(Array)
158
- raise ArgumentError, "#{key} does not support responsive values" unless RESPONSIVE_KEYS.include?(key)
155
+ raise ArgumentError, "#{key} does not support responsive values" unless RESPONSIVE_KEYS.include?(key) || Primer::Classify::Utilities.supported_key?(key)
159
156
 
160
157
  value.each_with_index do |val, index|
161
158
  Primer::Classify::Cache.read(memo, key, val, BREAKPOINTS[index]) || extract_value(memo, key, val, BREAKPOINTS[index])
@@ -173,8 +170,8 @@ module Primer
173
170
  def extract_value(memo, key, val, breakpoint)
174
171
  return if val.nil? || val == ""
175
172
 
176
- if SPACING_KEYS.include?(key)
177
- memo[:classes] << Primer::Classify::Spacing.spacing(key, val, breakpoint)
173
+ if Primer::Classify::Utilities.supported_key?(key)
174
+ memo[:classes] << Primer::Classify::Utilities.classname(key, val, breakpoint)
178
175
  elsif BOOLEAN_MAPPINGS.key?(key)
179
176
  BOOLEAN_MAPPINGS[key][:mappings].each do |m|
180
177
  memo[:classes] << m[:css_class] if m[:value] == val && m[:css_class].present?
@@ -187,12 +184,6 @@ module Primer
187
184
  end
188
185
  elsif key == COLOR_KEY
189
186
  memo[:classes] << Primer::Classify::FunctionalTextColors.color(val)
190
- elsif key == DISPLAY_KEY
191
- memo[:classes] << "d#{breakpoint}-#{val.to_s.dasherize}"
192
- elsif key == VERTICAL_ALIGN_KEY
193
- memo[:classes] << "v-align-#{val.to_s.dasherize}"
194
- elsif key == WORD_BREAK_KEY
195
- memo[:classes] << "wb-#{val.to_s.dasherize}"
196
187
  elsif key == BORDER_KEY
197
188
  border_value = if val == true
198
189
  "border"
@@ -233,14 +224,6 @@ module Primer
233
224
  else
234
225
  "color-shadow-#{val.to_s.dasherize}"
235
226
  end
236
- elsif key == VISIBILITY_KEY
237
- memo[:classes] << "v-#{val.to_s.dasherize}"
238
- elsif key == ANIMATION_KEY
239
- memo[:classes] << if val == :grow
240
- "hover-grow"
241
- else
242
- "anim-#{val.to_s.dasherize}"
243
- end
244
227
  else
245
228
  memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{val.to_s.dasherize}"
246
229
  end
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "flex"
4
+ require_relative "functional_background_colors"
5
+ require_relative "functional_border_colors"
6
+ require_relative "functional_text_colors"
7
+ require_relative "grid"
8
+
3
9
  module Primer
4
10
  class Classify
5
11
  # :nodoc:
@@ -19,26 +25,6 @@ module Primer
19
25
  end
20
26
 
21
27
  def preload!
22
- preload(
23
- keys: Primer::Classify::Spacing::MARGIN_DIRECTION_MAPPINGS.keys,
24
- values: Primer::Classify::Spacing::MARGIN_DIRECTION_OPTIONS
25
- )
26
-
27
- preload(
28
- keys: Primer::Classify::Spacing::BASE_MAPPINGS.keys,
29
- values: Primer::Classify::Spacing::BASE_OPTIONS
30
- )
31
-
32
- preload(
33
- keys: Primer::Classify::Spacing::AUTO_MAPPINGS.keys,
34
- values: Primer::Classify::Spacing::AUTO_OPTIONS
35
- )
36
-
37
- preload(
38
- keys: Primer::Classify::Spacing::RESPONSIVE_MAPPINGS.keys,
39
- values: Primer::Classify::Spacing::RESPONSIVE_OPTIONS
40
- )
41
-
42
28
  preload(
43
29
  keys: Primer::Classify::Flex::DIRECTION_KEY,
44
30
  values: Primer::Classify::Flex::DIRECTION_VALUES
@@ -69,11 +55,6 @@ module Primer
69
55
  values: Primer::Classify::Grid::COL_VALUES
70
56
  )
71
57
 
72
- preload(
73
- keys: Primer::Classify::DISPLAY_KEY,
74
- values: [:flex, :block, :inline_block, :inline_flex, :none, :table, :table_cell]
75
- )
76
-
77
58
  preload(
78
59
  keys: [Primer::Classify::COLOR_KEY],
79
60
  values: Primer::Classify::FunctionalTextColors::OPTIONS
@@ -84,16 +65,6 @@ module Primer
84
65
  values: Primer::Classify::FunctionalBackgroundColors::OPTIONS
85
66
  )
86
67
 
87
- preload(
88
- keys: Primer::Classify::VERTICAL_ALIGN_KEY,
89
- values: [:baseline, :top, :middle, :bottom, :text_top, :text_bottom]
90
- )
91
-
92
- preload(
93
- keys: Primer::Classify::WORD_BREAK_KEY,
94
- values: [:break_all]
95
- )
96
-
97
68
  preload(
98
69
  keys: :text_align,
99
70
  values: [:left, :center, :right]
@@ -133,11 +104,6 @@ module Primer
133
104
  keys: Primer::Classify::BOX_SHADOW_KEY,
134
105
  values: [true, :small, :medium, :large, :extra_large, :none]
135
106
  )
136
-
137
- preload(
138
- keys: Primer::Classify::VISIBILITY_KEY,
139
- values: [:hidden, :visible]
140
- )
141
107
  end
142
108
 
143
109
  def preload(keys:, values:)
File without changes
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "functional_colors"
4
+
3
5
  module Primer
4
6
  class Classify
5
7
  # Background specific functional colors
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "functional_colors"
4
+
3
5
  module Primer
4
6
  class Classify
5
7
  # Border specific functional colors
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "functional_colors"
4
+
3
5
  module Primer
4
6
  class Classify
5
7
  # Text specific functional colors.
File without changes
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Primer
5
+ class Classify
6
+ # Handler for PrimerCSS utility classes loaded from utilities.rake
7
+ class Utilities
8
+ # Load the utilities.yml file.
9
+ # Disabling because we want to load symbols, strings, and integers from the .yml file
10
+ # rubocop:disable Security/YAMLLoad
11
+ UTILITIES = YAML.load(
12
+ File.read(
13
+ File.join(File.dirname(__FILE__), "./utilities.yml")
14
+ )
15
+ ).freeze
16
+ # rubocop:enable Security/YAMLLoad
17
+ BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
18
+
19
+ class << self
20
+ def classname(key, val, breakpoint = "")
21
+ if (valid = validate(key, val, breakpoint))
22
+ valid
23
+ else
24
+ # Get selector
25
+ UTILITIES[key][val][BREAKPOINTS.index(breakpoint)]
26
+ end
27
+ end
28
+
29
+ # Does the Utilitiy class support the given key
30
+ #
31
+ # returns Boolean
32
+ def supported_key?(key)
33
+ UTILITIES[key].present?
34
+ end
35
+
36
+ # Does the Utilitiy class support the given key and value
37
+ #
38
+ # returns Boolean
39
+ def supported_value?(key, val)
40
+ supported_key?(key) && UTILITIES[key][val].present?
41
+ end
42
+
43
+ # Does the given selector exist in the utilities file
44
+ #
45
+ # returns Boolean
46
+ def supported_selector?(selector)
47
+ # This method is too slow to run in production
48
+ return false if ENV["RAILS_ENV"] == "production"
49
+
50
+ find_selector(selector).present?
51
+ end
52
+
53
+ # Is the key and value responsive
54
+ #
55
+ # returns Boolean
56
+ def responsive?(key, val)
57
+ supported_value?(key, val) && UTILITIES[key][val].count > 1
58
+ end
59
+
60
+ # Get the options for the given key
61
+ #
62
+ # returns Array or nil if key not supported
63
+ def mappings(key)
64
+ return unless supported_key?(key)
65
+
66
+ UTILITIES[key].keys
67
+ end
68
+
69
+ # Extract hash from classes ie. "mr-1 mb-2 foo" => { mr: 1, mb: 2, classes: "foo" }
70
+ def classes_to_hash(classes)
71
+ # This method is too slow to run in production
72
+ return { classes: classes } if ENV["RAILS_ENV"] == "production"
73
+
74
+ obj = {}
75
+ classes = classes.split(" ")
76
+ # Loop through all classes supplied and reject ones we find a match for
77
+ # So when we're at the end of the loop we have classes left with any non-system classes.
78
+ classes.reject! do |classname|
79
+ key, value, index = find_selector(classname)
80
+ next false if key.nil?
81
+
82
+ # Create array if nil
83
+ obj[key] = Array.new(5, nil) if obj[key].nil?
84
+ # Place the arguments in the responsive array based on index mr: [nil, 2]
85
+ obj[key][index] = value
86
+ next true
87
+ end
88
+
89
+ # Transform responsive arrays into arrays without trailing nil, so `mr: [1, nil, nil, nil, nil]` becomes `mr: 1`
90
+ obj.transform_values! do |value|
91
+ value = value.reverse.drop_while(&:nil?).reverse
92
+ if value.count == 1
93
+ value.first
94
+ else
95
+ value
96
+ end
97
+ end
98
+
99
+ # Add back the non-system classes
100
+ obj[:classes] = classes.join(" ") if classes.any?
101
+ obj
102
+ end
103
+
104
+ private
105
+
106
+ 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
119
+ end
120
+
121
+ nil
122
+ end
123
+
124
+ def validate(key, val, breakpoint)
125
+ unless supported_key?(key)
126
+ raise ArgumentError, "#{key} is not a valid Primer utility key" unless ENV["RAILS_ENV"] == "production"
127
+
128
+ return ""
129
+ end
130
+
131
+ unless breakpoint.empty? || responsive?(key, val)
132
+ raise ArgumentError, "#{key} does not support responsive values" unless ENV["RAILS_ENV"] == "production"
133
+
134
+ return ""
135
+ end
136
+
137
+ unless supported_value?(key, val)
138
+ raise ArgumentError, "#{val} is not a valid value for :#{key}. Use one of #{mappings(key)}" unless ENV["RAILS_ENV"] == "production"
139
+
140
+ return ""
141
+ end
142
+
143
+ nil
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end