primer_view_components 0.0.45 → 0.0.49

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +194 -0
  3. data/app/components/primer/{auto_complete_component.d.ts → auto_complete/auto_component.d.ts} +0 -0
  4. data/app/components/primer/{auto_complete_component.js → auto_complete/auto_component.js} +0 -0
  5. data/app/components/primer/base_component.rb +36 -7
  6. data/app/components/primer/beta/auto_complete.rb +159 -0
  7. data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
  8. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +0 -0
  9. data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
  10. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
  11. data/app/components/primer/beta/auto_complete/item.rb +44 -0
  12. data/app/components/primer/beta/avatar.rb +77 -0
  13. data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
  14. data/app/components/primer/beta/avatar_stack.rb +92 -0
  15. data/app/components/primer/border_box_component.rb +3 -0
  16. data/app/components/primer/component.rb +9 -1
  17. data/app/components/primer/details_component.rb +12 -8
  18. data/app/components/primer/image_crop.html.erb +4 -4
  19. data/app/components/primer/image_crop.rb +1 -1
  20. data/app/components/primer/markdown.rb +9 -9
  21. data/app/components/primer/menu_component.rb +7 -3
  22. data/app/components/primer/navigation/tab_component.rb +34 -6
  23. data/app/components/primer/popover_component.rb +6 -3
  24. data/app/components/primer/primer.d.ts +1 -1
  25. data/app/components/primer/primer.js +1 -1
  26. data/app/components/primer/primer.ts +1 -1
  27. data/app/components/primer/tab_nav_component.rb +9 -6
  28. data/app/components/primer/timeline_item_component.rb +2 -2
  29. data/app/components/primer/tooltip.rb +1 -1
  30. data/app/components/primer/truncate.rb +6 -1
  31. data/app/components/primer/underline_nav_component.rb +13 -6
  32. data/{app/lib → lib}/primer/classify.rb +12 -39
  33. data/{app/lib → lib}/primer/classify/cache.rb +6 -20
  34. data/{app/lib → lib}/primer/classify/flex.rb +0 -0
  35. data/{app/lib → lib}/primer/classify/functional_background_colors.rb +2 -0
  36. data/{app/lib → lib}/primer/classify/functional_border_colors.rb +2 -0
  37. data/{app/lib → lib}/primer/classify/functional_colors.rb +0 -0
  38. data/{app/lib → lib}/primer/classify/functional_text_colors.rb +2 -0
  39. data/{app/lib → lib}/primer/classify/grid.rb +0 -0
  40. data/{app/lib → lib}/primer/classify/utilities.rb +54 -22
  41. data/{app/lib → lib}/primer/classify/utilities.yml +124 -0
  42. data/lib/primer/view_components.rb +35 -6
  43. data/lib/primer/view_components/constants.rb +55 -0
  44. data/lib/primer/view_components/linters/argument_mappers/base.rb +39 -0
  45. data/lib/primer/view_components/linters/argument_mappers/button.rb +35 -44
  46. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +25 -0
  47. data/lib/primer/view_components/linters/argument_mappers/label.rb +56 -0
  48. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +1 -2
  49. data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
  50. data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
  51. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
  52. data/lib/primer/view_components/linters/helpers.rb +56 -38
  53. data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
  54. data/lib/primer/view_components/statuses.rb +14 -0
  55. data/lib/primer/view_components/version.rb +1 -1
  56. data/lib/rubocop/config/default.yml +12 -0
  57. data/lib/rubocop/cop/primer.rb +4 -0
  58. data/lib/rubocop/cop/primer/no_tag_memoize.rb +42 -0
  59. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +75 -0
  60. data/lib/tasks/constants.rake +12 -0
  61. data/lib/tasks/docs.rake +89 -34
  62. data/lib/tasks/utilities.rake +9 -11
  63. data/lib/yard/docs_helper.rb +12 -3
  64. data/static/arguments.yml +977 -0
  65. data/static/assets/view-components.svg +18 -0
  66. data/static/classes.yml +174 -0
  67. data/static/constants.json +628 -0
  68. data/static/statuses.json +5 -5
  69. metadata +44 -27
  70. data/app/components/primer/auto_complete.rb +0 -156
  71. data/app/components/primer/auto_complete/item.rb +0 -42
  72. data/app/components/primer/avatar_component.rb +0 -75
  73. data/app/components/primer/avatar_stack_component.rb +0 -84
  74. data/app/components/primer/details_menu_component.d.ts +0 -1
  75. data/app/components/primer/details_menu_component.js +0 -1
@@ -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,4 +1,4 @@
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';
@@ -1,4 +1,4 @@
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';
@@ -1,4 +1,4 @@
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'
@@ -10,8 +10,10 @@ 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
  #
16
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique ID of panel.
15
17
  # @param selected [Boolean] Whether the tab is selected.
16
18
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
17
19
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -62,19 +64,19 @@ module Primer
62
64
  #
63
65
  # @example With panels
64
66
  # <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
65
- # <% c.tab(selected: true) do |t| %>
67
+ # <% c.tab(selected: true, panel_id: "panel-1", id: "tab-1") do |t| %>
66
68
  # <% t.text { "Tab 1" } %>
67
69
  # <% t.panel do %>
68
70
  # Panel 1
69
71
  # <% end %>
70
72
  # <% end %>
71
- # <% c.tab do |t| %>
73
+ # <% c.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
72
74
  # <% t.text { "Tab 2" } %>
73
75
  # <% t.panel do %>
74
76
  # Panel 2
75
77
  # <% end %>
76
78
  # <% end %>
77
- # <% c.tab do |t| %>
79
+ # <% c.tab(id: "tab-3", panel_id: "panel-3") do |t| %>
78
80
  # <% t.text { "Tab 3" } %>
79
81
  # <% t.panel do %>
80
82
  # Panel 3
@@ -119,7 +121,8 @@ module Primer
119
121
  # <% end %>
120
122
  #
121
123
  # @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.
124
+ # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels. When true, <%= link_to_component(Primer::TabContainerComponent) %>
125
+ # is rendered along with JavaScript behavior. Additionally, the `tab` slot will render as a button as opposed to an anchor.
123
126
  # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
124
127
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper. Only applies if `with_panel` is `true`.
125
128
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -130,7 +133,7 @@ module Primer
130
133
  @body_arguments = body_arguments
131
134
  @wrapper_arguments = wrapper_arguments
132
135
 
133
- @system_arguments[:tag] ||= :div
136
+ @system_arguments[:tag] = :div
134
137
  @system_arguments[:classes] = class_names(
135
138
  "tabnav",
136
139
  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(
@@ -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">
@@ -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,8 +13,13 @@ 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
  #
22
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
18
23
  # @param selected [Boolean] Whether the tab is selected.
19
24
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
20
25
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -34,9 +39,10 @@ module Primer
34
39
 
35
40
  # Use actions for a call to action.
36
41
  #
42
+ # @param tag [Symbol] (Primer::UnderlineNavComponent::ACTIONS_TAG_DEFAULT) <%= one_of(Primer::UnderlineNavComponent::ACTIONS_TAG_OPTIONS) %>
37
43
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
38
- renders_one :actions, lambda { |**system_arguments|
39
- system_arguments[:tag] ||= :div
44
+ renders_one :actions, lambda { |tag: ACTIONS_TAG_DEFAULT, **system_arguments|
45
+ system_arguments[:tag] = fetch_or_fallback(ACTIONS_TAG_OPTIONS, tag, ACTIONS_TAG_DEFAULT)
40
46
  system_arguments[:classes] = class_names("UnderlineNav-actions", system_arguments[:classes])
41
47
 
42
48
  Primer::BaseComponent.new(**system_arguments)
@@ -99,13 +105,13 @@ module Primer
99
105
  #
100
106
  # @example With panels
101
107
  # <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
102
- # <% component.tab(selected: true) do |t| %>
108
+ # <% component.tab(selected: true, id: "tab-1", panel_id: "panel-1") do |t| %>
103
109
  # <% t.text { "Item 1" } %>
104
110
  # <% t.panel do %>
105
111
  # Panel 1
106
112
  # <% end %>
107
113
  # <% end %>
108
- # <% component.tab do |t| %>
114
+ # <% component.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
109
115
  # <% t.text { "Item 2" } %>
110
116
  # <% t.panel do %>
111
117
  # Panel 2
@@ -131,7 +137,8 @@ module Primer
131
137
  # <% end %>
132
138
  #
133
139
  # @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.
140
+ # @param with_panel [Boolean] Whether the `UnderlineNav` should navigate through pages or panels. When true, <%= link_to_component(Primer::TabContainerComponent) %> is
141
+ # rendered along with JavaScript behavior.
135
142
  # @param align [Symbol] <%= one_of(Primer::UnderlineNavComponent::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavComponent::ALIGN_DEFAULT %>
136
143
  # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
137
144
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper. Only applies if `with_panel` is `true`.
@@ -1,40 +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
- # Load the utilities.yml file.
7
- # Disabling because we want to load symbols, strings, and integers from the .yml file
8
- # rubocop:disable Security/YAMLLoad
9
- UTILITIES = YAML.load(
10
- File.read(
11
- File.join(File.dirname(__FILE__), "./classify/utilities.yml")
12
- )
13
- ).freeze
14
- # rubocop:enable Security/YAMLLoad
15
-
16
- DISPLAY_KEY = :display
17
-
18
14
  # Keys where we can simply translate { key: value } into ".key-value"
19
- CONCAT_KEYS = %i[position v text box_shadow].freeze
15
+ CONCAT_KEYS = %i[text box_shadow].freeze
20
16
 
21
17
  INVALID_CLASS_NAME_PREFIXES =
22
- (["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
23
19
 
24
20
  COLOR_KEY = :color
25
21
  BG_KEY = :bg
26
- VERTICAL_ALIGN_KEY = :vertical_align
27
- WORD_BREAK_KEY = :word_break
28
22
  TEXT_KEYS = %i[font_family font_style font_weight text_align text_transform].freeze
29
23
  WIDTH_KEY = :width
30
24
  HEIGHT_KEY = :height
31
25
  BOX_SHADOW_KEY = :box_shadow
32
- VISIBILITY_KEY = :visibility
33
- ANIMATION_KEY = :animation
34
26
  CONTAINER_KEY = :container
35
27
 
36
28
  BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
37
- RESPONSIVE_KEYS = ([DISPLAY_KEY, Primer::Classify::Grid::COL_KEY] + Primer::Classify::Flex::RESPONSIVE_KEYS).freeze
29
+ RESPONSIVE_KEYS = ([Primer::Classify::Grid::COL_KEY] + Primer::Classify::Flex::RESPONSIVE_KEYS).freeze
38
30
 
39
31
  BOOLEAN_MAPPINGS = {
40
32
  underline: {
@@ -88,7 +80,7 @@ module Primer
88
80
  BORDER_RADIUS_KEY = :border_radius
89
81
  TYPOGRAPHY_KEYS = [:font_size].freeze
90
82
  VALID_KEYS = (
91
- UTILITIES.keys +
83
+ Primer::Classify::Utilities::UTILITIES.keys +
92
84
  CONCAT_KEYS +
93
85
  BOOLEAN_MAPPINGS.keys +
94
86
  BORDER_MARGIN_KEYS +
@@ -102,14 +94,9 @@ module Primer
102
94
  BORDER_RADIUS_KEY,
103
95
  COLOR_KEY,
104
96
  BG_KEY,
105
- DISPLAY_KEY,
106
- VERTICAL_ALIGN_KEY,
107
- WORD_BREAK_KEY,
108
97
  WIDTH_KEY,
109
98
  HEIGHT_KEY,
110
99
  BOX_SHADOW_KEY,
111
- VISIBILITY_KEY,
112
- ANIMATION_KEY,
113
100
  CONTAINER_KEY
114
101
  ]
115
102
  ).freeze
@@ -197,12 +184,6 @@ module Primer
197
184
  end
198
185
  elsif key == COLOR_KEY
199
186
  memo[:classes] << Primer::Classify::FunctionalTextColors.color(val)
200
- elsif key == DISPLAY_KEY
201
- memo[:classes] << "d#{breakpoint}-#{val.to_s.dasherize}"
202
- elsif key == VERTICAL_ALIGN_KEY
203
- memo[:classes] << "v-align-#{val.to_s.dasherize}"
204
- elsif key == WORD_BREAK_KEY
205
- memo[:classes] << "wb-#{val.to_s.dasherize}"
206
187
  elsif key == BORDER_KEY
207
188
  border_value = if val == true
208
189
  "border"
@@ -243,14 +224,6 @@ module Primer
243
224
  else
244
225
  "color-shadow-#{val.to_s.dasherize}"
245
226
  end
246
- elsif key == VISIBILITY_KEY
247
- memo[:classes] << "v-#{val.to_s.dasherize}"
248
- elsif key == ANIMATION_KEY
249
- memo[:classes] << if val == :grow
250
- "hover-grow"
251
- else
252
- "anim-#{val.to_s.dasherize}"
253
- end
254
227
  else
255
228
  memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{val.to_s.dasherize}"
256
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:
@@ -49,11 +55,6 @@ module Primer
49
55
  values: Primer::Classify::Grid::COL_VALUES
50
56
  )
51
57
 
52
- preload(
53
- keys: Primer::Classify::DISPLAY_KEY,
54
- values: [:flex, :block, :inline_block, :inline_flex, :none, :table, :table_cell]
55
- )
56
-
57
58
  preload(
58
59
  keys: [Primer::Classify::COLOR_KEY],
59
60
  values: Primer::Classify::FunctionalTextColors::OPTIONS
@@ -64,16 +65,6 @@ module Primer
64
65
  values: Primer::Classify::FunctionalBackgroundColors::OPTIONS
65
66
  )
66
67
 
67
- preload(
68
- keys: Primer::Classify::VERTICAL_ALIGN_KEY,
69
- values: [:baseline, :top, :middle, :bottom, :text_top, :text_bottom]
70
- )
71
-
72
- preload(
73
- keys: Primer::Classify::WORD_BREAK_KEY,
74
- values: [:break_all]
75
- )
76
-
77
68
  preload(
78
69
  keys: :text_align,
79
70
  values: [:left, :center, :right]
@@ -113,11 +104,6 @@ module Primer
113
104
  keys: Primer::Classify::BOX_SHADOW_KEY,
114
105
  values: [true, :small, :medium, :large, :extra_large, :none]
115
106
  )
116
-
117
- preload(
118
- keys: Primer::Classify::VISIBILITY_KEY,
119
- values: [:hidden, :visible]
120
- )
121
107
  end
122
108
 
123
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
@@ -1,17 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  # :nodoc:
4
6
  module Primer
5
7
  class Classify
6
8
  # Handler for PrimerCSS utility classes loaded from utilities.rake
7
9
  class Utilities
10
+ # Load the utilities.yml file.
11
+ # Disabling because we want to load symbols, strings, and integers from the .yml file
12
+ # rubocop:disable Security/YAMLLoad
13
+ UTILITIES = YAML.load(
14
+ File.read(
15
+ File.join(File.dirname(__FILE__), "./utilities.yml")
16
+ )
17
+ ).freeze
18
+ # rubocop:enable Security/YAMLLoad
19
+ BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
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
+ }.freeze
29
+
8
30
  class << self
9
31
  def classname(key, val, breakpoint = "")
10
32
  if (valid = validate(key, val, breakpoint))
11
33
  valid
12
34
  else
13
35
  # Get selector
14
- Primer::Classify::UTILITIES[key][val][Primer::Classify::BREAKPOINTS.index(breakpoint)]
36
+ UTILITIES[key][val][BREAKPOINTS.index(breakpoint)]
15
37
  end
16
38
  end
17
39
 
@@ -19,14 +41,14 @@ module Primer
19
41
  #
20
42
  # returns Boolean
21
43
  def supported_key?(key)
22
- Primer::Classify::UTILITIES[key].present?
44
+ UTILITIES[key].present?
23
45
  end
24
46
 
25
47
  # Does the Utilitiy class support the given key and value
26
48
  #
27
49
  # returns Boolean
28
50
  def supported_value?(key, val)
29
- supported_key?(key) && Primer::Classify::UTILITIES[key][val].present?
51
+ supported_key?(key) && UTILITIES[key][val].present?
30
52
  end
31
53
 
32
54
  # Does the given selector exist in the utilities file
@@ -34,7 +56,7 @@ module Primer
34
56
  # returns Boolean
35
57
  def supported_selector?(selector)
36
58
  # This method is too slow to run in production
37
- return false if Rails.env.production?
59
+ return false if ENV["RAILS_ENV"] == "production"
38
60
 
39
61
  find_selector(selector).present?
40
62
  end
@@ -43,7 +65,7 @@ module Primer
43
65
  #
44
66
  # returns Boolean
45
67
  def responsive?(key, val)
46
- supported_value?(key, val) && Primer::Classify::UTILITIES[key][val].count > 1
68
+ supported_value?(key, val) && UTILITIES[key][val].count > 1
47
69
  end
48
70
 
49
71
  # Get the options for the given key
@@ -52,13 +74,13 @@ module Primer
52
74
  def mappings(key)
53
75
  return unless supported_key?(key)
54
76
 
55
- Primer::Classify::UTILITIES[key].keys
77
+ UTILITIES[key].keys
56
78
  end
57
79
 
58
80
  # Extract hash from classes ie. "mr-1 mb-2 foo" => { mr: 1, mb: 2, classes: "foo" }
59
81
  def classes_to_hash(classes)
60
82
  # This method is too slow to run in production
61
- return { classes: classes } if Rails.env.production?
83
+ return { classes: classes } if ENV["RAILS_ENV"] == "production"
62
84
 
63
85
  obj = {}
64
86
  classes = classes.split(" ")
@@ -93,38 +115,48 @@ module Primer
93
115
  private
94
116
 
95
117
  def find_selector(selector)
96
- # 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" ] }`
97
- Primer::Classify::UTILITIES.each do |key, value_hash|
98
- # Each value hash will also contain an array of classnames for breakpoints
99
- # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
100
- value_hash.each do |key_argument, classnames|
101
- # Skip each value hash until we get one with the selector
102
- next unless classnames.include?(selector)
103
-
104
- # Return [:mr, 0, 1]
105
- # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
106
- return [key, key_argument, classnames.index(selector)]
107
- end
118
+ key = infer_selector_key(selector)
119
+ value_hash = UTILITIES[key]
120
+
121
+ return nil if value_hash.blank?
122
+
123
+ # Each value hash will also contain an array of classnames for breakpoints
124
+ # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
125
+ value_hash.each do |key_argument, classnames|
126
+ # Skip each value hash until we get one with the selector
127
+ next unless classnames.include?(selector)
128
+
129
+ # Return [:mr, 0, 1]
130
+ # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
131
+ return [key, key_argument, classnames.index(selector)]
108
132
  end
109
133
 
110
134
  nil
111
135
  end
112
136
 
137
+ def infer_selector_key(selector)
138
+ REPLACEMENT_KEYS.each do |k, v|
139
+ return v.to_sym if selector.match?(Regexp.new(k))
140
+ end
141
+
142
+ selector.split("-").first.to_sym
143
+ end
144
+
113
145
  def validate(key, val, breakpoint)
114
146
  unless supported_key?(key)
115
- raise ArgumentError, "#{key} is not a valid Primer utility key" unless Rails.env.production?
147
+ raise ArgumentError, "#{key} is not a valid Primer utility key" unless ENV["RAILS_ENV"] == "production"
116
148
 
117
149
  return ""
118
150
  end
119
151
 
120
152
  unless breakpoint.empty? || responsive?(key, val)
121
- raise ArgumentError, "#{key} does not support responsive values" unless Rails.env.production?
153
+ raise ArgumentError, "#{key} does not support responsive values" unless ENV["RAILS_ENV"] == "production"
122
154
 
123
155
  return ""
124
156
  end
125
157
 
126
158
  unless supported_value?(key, val)
127
- raise ArgumentError, "#{val} is not a valid value for :#{key}. Use one of #{mappings(key)}" unless Rails.env.production?
159
+ raise ArgumentError, "#{val} is not a valid value for :#{key}. Use one of #{mappings(key)}" unless ENV["RAILS_ENV"] == "production"
128
160
 
129
161
  return ""
130
162
  end