primer_view_components 0.0.45 → 0.0.49

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