primer_view_components 0.0.44 → 0.0.48
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +187 -0
- data/app/components/primer/avatar_stack_component.rb +9 -3
- data/app/components/primer/base_component.rb +52 -23
- data/app/components/primer/beta/auto_complete.rb +159 -0
- data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
- data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +0 -0
- data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
- data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
- data/app/components/primer/beta/auto_complete/item.rb +44 -0
- data/app/components/primer/beta/avatar.rb +77 -0
- data/app/components/primer/border_box_component.rb +3 -0
- data/app/components/primer/clipboard_copy.rb +25 -7
- data/app/components/primer/component.rb +9 -1
- data/app/components/primer/details_component.rb +12 -8
- data/app/components/primer/image_crop.rb +1 -1
- data/app/components/primer/markdown.rb +9 -9
- data/app/components/primer/menu_component.rb +7 -3
- data/app/components/primer/navigation/tab_component.rb +19 -5
- data/app/components/primer/popover_component.rb +6 -3
- data/app/components/primer/primer.d.ts +1 -1
- data/app/components/primer/primer.js +1 -1
- data/app/components/primer/primer.ts +1 -1
- data/app/components/primer/tab_nav_component.rb +8 -6
- data/app/components/primer/timeline_item_component.rb +2 -2
- data/app/components/primer/tooltip.rb +1 -1
- data/app/components/primer/truncate.rb +5 -0
- data/app/components/primer/underline_nav_component.rb +12 -6
- data/{app/lib → lib}/primer/classify.rb +16 -33
- data/{app/lib → lib}/primer/classify/cache.rb +6 -40
- data/{app/lib → lib}/primer/classify/flex.rb +0 -0
- data/{app/lib → lib}/primer/classify/functional_background_colors.rb +2 -0
- data/{app/lib → lib}/primer/classify/functional_border_colors.rb +2 -0
- data/{app/lib → lib}/primer/classify/functional_colors.rb +0 -0
- data/{app/lib → lib}/primer/classify/functional_text_colors.rb +2 -0
- data/{app/lib → lib}/primer/classify/grid.rb +0 -0
- data/lib/primer/classify/utilities.rb +148 -0
- data/lib/primer/classify/utilities.yml +1271 -0
- data/lib/primer/view_components.rb +1 -0
- data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +5 -4
- data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -5
- data/lib/primer/view_components/linters/helpers.rb +132 -17
- data/lib/primer/view_components/statuses.rb +14 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/rubocop/config/default.yml +12 -0
- data/lib/rubocop/cop/primer.rb +4 -0
- data/lib/rubocop/cop/primer/no_tag_memoize.rb +42 -0
- data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +75 -0
- data/lib/tasks/docs.rake +72 -18
- data/lib/tasks/utilities.rake +105 -0
- data/lib/yard/docs_helper.rb +1 -1
- data/static/statuses.json +4 -4
- metadata +30 -21
- data/app/components/primer/auto_complete.rb +0 -156
- data/app/components/primer/auto_complete/item.rb +0 -42
- data/app/components/primer/avatar_component.rb +0 -75
- data/app/lib/primer/classify/spacing.rb +0 -63
@@ -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.
|
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 %>
|
@@ -62,19 +63,19 @@ module Primer
|
|
62
63
|
#
|
63
64
|
# @example With panels
|
64
65
|
# <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
|
65
|
-
# <% c.tab(selected: true) do |t| %>
|
66
|
+
# <% c.tab(selected: true, id: "tab-1") do |t| %>
|
66
67
|
# <% t.text { "Tab 1" } %>
|
67
68
|
# <% t.panel do %>
|
68
69
|
# Panel 1
|
69
70
|
# <% end %>
|
70
71
|
# <% end %>
|
71
|
-
# <% c.tab do |t| %>
|
72
|
+
# <% c.tab(id: "tab-2") do |t| %>
|
72
73
|
# <% t.text { "Tab 2" } %>
|
73
74
|
# <% t.panel do %>
|
74
75
|
# Panel 2
|
75
76
|
# <% end %>
|
76
77
|
# <% end %>
|
77
|
-
# <% c.tab do |t| %>
|
78
|
+
# <% c.tab(id: "tab-3") do |t| %>
|
78
79
|
# <% t.text { "Tab 3" } %>
|
79
80
|
# <% t.panel do %>
|
80
81
|
# Panel 3
|
@@ -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]
|
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::
|
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::
|
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
|
-
|
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 {
|
39
|
-
system_arguments[:tag]
|
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)
|
@@ -99,13 +104,13 @@ module Primer
|
|
99
104
|
#
|
100
105
|
# @example With panels
|
101
106
|
# <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
|
102
|
-
# <% component.tab(selected: true) do |t| %>
|
107
|
+
# <% component.tab(selected: true, id: "tab-1") do |t| %>
|
103
108
|
# <% t.text { "Item 1" } %>
|
104
109
|
# <% t.panel do %>
|
105
110
|
# Panel 1
|
106
111
|
# <% end %>
|
107
112
|
# <% end %>
|
108
|
-
# <% component.tab do |t| %>
|
113
|
+
# <% component.tab(id: "tab-2") do |t| %>
|
109
114
|
# <% t.text { "Item 2" } %>
|
110
115
|
# <% t.panel do %>
|
111
116
|
# Panel 2
|
@@ -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
|
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 =
|
15
|
+
CONCAT_KEYS = %i[text box_shadow].freeze
|
11
16
|
|
12
17
|
INVALID_CLASS_NAME_PREFIXES =
|
13
|
-
(["bg-", "color-", "text-", "
|
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 = ([
|
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
|
177
|
-
memo[:classes] << Primer::Classify::
|
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
|
File without changes
|
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
|