primer_view_components 0.0.43 → 0.0.47

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