primer_view_components 0.0.16 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/app/components/primer/avatar_component.rb +27 -9
  4. data/app/components/primer/avatar_stack_component.html.erb +10 -0
  5. data/app/components/primer/avatar_stack_component.rb +81 -0
  6. data/app/components/primer/base_component.rb +8 -4
  7. data/app/components/primer/blankslate_component.html.erb +1 -1
  8. data/app/components/primer/blankslate_component.rb +18 -25
  9. data/app/components/primer/border_box_component.rb +29 -13
  10. data/app/components/primer/box_component.rb +10 -0
  11. data/app/components/primer/breadcrumb_component.rb +3 -2
  12. data/app/components/primer/button_component.rb +3 -3
  13. data/app/components/primer/button_group_component.html.erb +5 -0
  14. data/app/components/primer/button_group_component.rb +37 -0
  15. data/app/components/primer/button_marketing_component.rb +73 -0
  16. data/app/components/primer/component.rb +13 -0
  17. data/app/components/primer/counter_component.rb +16 -9
  18. data/app/components/primer/details_component.rb +10 -6
  19. data/app/components/primer/dropdown/menu_component.html.erb +12 -0
  20. data/app/components/primer/dropdown/menu_component.rb +48 -0
  21. data/app/components/primer/dropdown_component.html.erb +9 -0
  22. data/app/components/primer/dropdown_component.rb +77 -0
  23. data/app/components/primer/dropdown_menu_component.rb +35 -3
  24. data/app/components/primer/flash_component.html.erb +2 -5
  25. data/app/components/primer/flash_component.rb +18 -19
  26. data/app/components/primer/flex_component.rb +47 -9
  27. data/app/components/primer/flex_item_component.rb +16 -1
  28. data/app/components/primer/heading_component.rb +7 -0
  29. data/app/components/primer/label_component.rb +6 -6
  30. data/app/components/primer/layout_component.rb +2 -2
  31. data/app/components/primer/link_component.rb +7 -3
  32. data/app/components/primer/markdown_component.rb +293 -0
  33. data/app/components/primer/menu_component.html.erb +6 -0
  34. data/app/components/primer/menu_component.rb +71 -0
  35. data/app/components/primer/octicon_component.rb +11 -6
  36. data/app/components/primer/popover_component.rb +6 -4
  37. data/app/components/primer/progress_bar_component.rb +9 -9
  38. data/app/components/primer/slot.rb +1 -0
  39. data/app/components/primer/spinner_component.rb +10 -7
  40. data/app/components/primer/state_component.rb +6 -6
  41. data/app/components/primer/subhead_component.rb +6 -3
  42. data/app/components/primer/text_component.rb +1 -1
  43. data/app/components/primer/timeline_item_component.html.erb +4 -16
  44. data/app/components/primer/timeline_item_component.rb +41 -49
  45. data/app/components/primer/tooltip_component.rb +88 -0
  46. data/app/components/primer/truncate_component.rb +41 -0
  47. data/app/components/primer/underline_nav_component.rb +26 -1
  48. data/app/components/primer/view_components.rb +9 -0
  49. data/lib/primer/class_name_helper.rb +1 -0
  50. data/lib/primer/classify.rb +139 -107
  51. data/lib/primer/classify/cache.rb +125 -0
  52. data/lib/primer/fetch_or_fallback_helper.rb +9 -0
  53. data/lib/primer/join_style_arguments_helper.rb +14 -0
  54. data/lib/primer/view_components.rb +32 -0
  55. data/lib/primer/view_components/engine.rb +1 -0
  56. data/lib/primer/view_components/version.rb +1 -1
  57. data/lib/yard/renders_many_handler.rb +19 -0
  58. data/lib/yard/renders_one_handler.rb +19 -0
  59. data/static/statuses.json +1 -0
  60. metadata +80 -19
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # The Tooltip component is a wrapper component that will apply a tooltip to the provided content.
5
+ class TooltipComponent < Primer::Component
6
+ DIRECTION_DEFAULT = :n
7
+ ALIGN_DEFAULT = :default
8
+ MULTILINE_DEFAULT = false
9
+ DELAY_DEFAULT = false
10
+
11
+ ALIGN_MAPPING = {
12
+ ALIGN_DEFAULT => "",
13
+ :left_1 => "tooltipped-align-left-1",
14
+ :right_1 => "tooltipped-align-right-1",
15
+ :left_2 => "tooltipped-align-left-2",
16
+ :right_2 => "tooltipped-align-right-2"
17
+ }.freeze
18
+
19
+ DIRECTION_OPTIONS = [DIRECTION_DEFAULT] + %i[
20
+ nw
21
+ ne
22
+ w
23
+ e
24
+ sw
25
+ s
26
+ se
27
+ ]
28
+
29
+ # @example 55|Default
30
+ # <div class="pt-5">
31
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder")) { "Default Bold Text" } %>
32
+ # </div>
33
+ #
34
+ # @example 65|Wrapping another component
35
+ # <div class="pt-5">
36
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder")) do %>
37
+ # <%= render(Primer::ButtonComponent.new) { "Bold Button" } %>
38
+ # <% end %>
39
+ # </div>
40
+ #
41
+ # @example 65|With a direction
42
+ # <div class="pt-5">
43
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder", direction: :s)) { "Bold Text With a Direction" } %>
44
+ # </div>
45
+ #
46
+ # @example 65|With an alignment
47
+ # <div class="pt-5">
48
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder", direction: :s, alignment: :right_1)) { "Bold Text With an Alignment" } %>
49
+ # </div>
50
+ #
51
+ # @example 65|Without a delay
52
+ # <div class="pt-5">
53
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder", direction: :s, no_delay: true)) { "Bold Text without a delay" } %>
54
+ # </div>
55
+ #
56
+ # @param label [String] the text to appear in the tooltip
57
+ # @param direction [String] Direction of the tooltip. <%= one_of(Primer::TooltipComponent::DIRECTION_OPTIONS) %>
58
+ # @param align [String] Align tooltips to the left or right of an element, combined with a `direction` to specify north or south. <%= one_of(Primer::TooltipComponent::ALIGN_MAPPING.keys) %>
59
+ # @param multiline [Boolean] Use this when you have long content
60
+ # @param no_delay [Boolean] By default the tooltips have a slight delay before appearing. Set true to override this
61
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
62
+ def initialize(
63
+ label:,
64
+ direction: DIRECTION_DEFAULT,
65
+ align: ALIGN_DEFAULT,
66
+ multiline: MULTILINE_DEFAULT,
67
+ no_delay: DELAY_DEFAULT,
68
+ **system_arguments
69
+ )
70
+ @system_arguments = system_arguments
71
+ @system_arguments[:tag] ||= :span
72
+ @system_arguments[:aria] = { label: label }
73
+
74
+ @system_arguments[:classes] = class_names(
75
+ @system_arguments[:classes],
76
+ "tooltipped",
77
+ "tooltipped-#{fetch_or_fallback(DIRECTION_OPTIONS, direction, DIRECTION_DEFAULT)}",
78
+ ALIGN_MAPPING[fetch_or_fallback(ALIGN_MAPPING.keys, align, ALIGN_DEFAULT)],
79
+ "tooltipped-no-delay" => fetch_or_fallback_boolean(no_delay, DELAY_DEFAULT),
80
+ "tooltipped-multiline" => fetch_or_fallback_boolean(multiline, MULTILINE_DEFAULT)
81
+ )
82
+ end
83
+
84
+ def call
85
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use TruncateComponent to shorten overflowing text with an ellipsis.
5
+ class TruncateComponent < Primer::Component
6
+ # @example auto|Default
7
+ # <div class="col-2">
8
+ # <%= render(Primer::TruncateComponent.new(tag: :p)) { "branch-name-that-is-really-long" } %>
9
+ # </div>
10
+ #
11
+ # @example auto|Inline
12
+ # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true)) { "branch-name-that-is-really-long" } %>
13
+ #
14
+ # @example auto|Expandable
15
+ # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true, expandable: true)) { "branch-name-that-is-really-long" } %>
16
+ #
17
+ # @example auto|Custom size
18
+ # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true, expandable: true, max_width: 100)) { "branch-name-that-is-really-long" } %>
19
+ #
20
+ # @param inline [Boolean] Whether the element is inline (or inline-block).
21
+ # @param expandable [Boolean] Whether the entire string should be revealed on hover. Can only be used in conjunction with `inline`.
22
+ # @param max_width [Integer] Sets the max-width of the text.
23
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
+ def initialize(inline: false, expandable: false, max_width: nil, **system_arguments)
25
+ @system_arguments = system_arguments
26
+ @system_arguments[:tag] ||= :div
27
+ @system_arguments[:classes] = class_names(
28
+ @system_arguments[:classes],
29
+ "css-truncate",
30
+ "css-truncate-overflow" => !inline,
31
+ "css-truncate-target" => inline,
32
+ "expandable" => inline && expandable
33
+ )
34
+ @system_arguments[:style] = join_style_arguments(@system_arguments[:style], "max-width: #{max_width}px;") unless max_width.nil?
35
+ end
36
+
37
+ def call
38
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
39
+ end
40
+ end
41
+ end
@@ -1,12 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use the UnderlineNav component to style navigation with a minimal
5
+ # underlined selected state, typically used for navigation placed at the top
6
+ # of the page.
4
7
  class UnderlineNavComponent < Primer::Component
5
8
  ALIGN_DEFAULT = :left
6
- ALIGN_OPTIONS = [ALIGN_DEFAULT, :right]
9
+ ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
7
10
 
8
11
  with_content_areas :body, :actions
9
12
 
13
+ # @example auto|Default
14
+ # <%= render(Primer::UnderlineNavComponent.new) do |component| %>
15
+ # <% component.with(:body) do %>
16
+ # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
17
+ # <% end %>
18
+ # <% component.with(:actions) do %>
19
+ # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
20
+ # <% end %>
21
+ # <% end %>
22
+ #
23
+ # @example auto|Align right
24
+ # <%= render(Primer::UnderlineNavComponent.new(align: :right)) do |component| %>
25
+ # <% component.with(:body) do %>
26
+ # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
27
+ # <% end %>
28
+ # <% component.with(:actions) do %>
29
+ # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
30
+ # <% end %>
31
+ # <% end %>
32
+ #
33
+ # @param align [Symbol] <%= one_of(Primer::UnderlineNavComponent::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavComponent::ALIGN_DEFAULT %>
34
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
10
35
  def initialize(align: ALIGN_DEFAULT, **system_arguments)
11
36
  @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
12
37
 
@@ -15,6 +15,7 @@ require "octicons_helper/helper"
15
15
  require "primer/class_name_helper"
16
16
  require "primer/classify"
17
17
  require "primer/fetch_or_fallback_helper"
18
+ require "primer/join_style_arguments_helper"
18
19
 
19
20
  # Base configurations
20
21
 
@@ -25,13 +26,17 @@ require_relative "slot"
25
26
  # Components
26
27
 
27
28
  require_relative "avatar_component"
29
+ require_relative "avatar_stack_component"
28
30
  require_relative "blankslate_component"
29
31
  require_relative "border_box_component"
30
32
  require_relative "box_component"
31
33
  require_relative "breadcrumb_component"
32
34
  require_relative "button_component"
35
+ require_relative "button_group_component"
36
+ require_relative "button_marketing_component"
33
37
  require_relative "counter_component"
34
38
  require_relative "details_component"
39
+ require_relative "dropdown_component"
35
40
  require_relative "dropdown_menu_component"
36
41
  require_relative "flash_component"
37
42
  require_relative "flex_component"
@@ -40,6 +45,8 @@ require_relative "heading_component"
40
45
  require_relative "label_component"
41
46
  require_relative "layout_component"
42
47
  require_relative "link_component"
48
+ require_relative "markdown_component"
49
+ require_relative "menu_component"
43
50
  require_relative "octicon_component"
44
51
  require_relative "popover_component"
45
52
  require_relative "progress_bar_component"
@@ -48,4 +55,6 @@ require_relative "state_component"
48
55
  require_relative "subhead_component"
49
56
  require_relative "text_component"
50
57
  require_relative "timeline_item_component"
58
+ require_relative "tooltip_component"
59
+ require_relative "truncate_component"
51
60
  require_relative "underline_nav_component"
@@ -4,6 +4,7 @@
4
4
  #
5
5
  # Helps build a list of conditional class names
6
6
  module Primer
7
+ # :nodoc:
7
8
  module ClassNameHelper
8
9
  def class_names(*args)
9
10
  classes = []
@@ -1,27 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "classify/cache"
4
+
3
5
  module Primer
6
+ # :nodoc:
4
7
  class Classify
5
- MARGIN_DIRECTION_KEYS = [:mt, :ml, :mb, :mr]
6
- SPACING_KEYS = ([:m, :my, :mx, :p, :py, :px, :pt, :pl, :pb, :pr] + MARGIN_DIRECTION_KEYS).freeze
8
+ MARGIN_DIRECTION_KEYS = %i[mt ml mb mr].freeze
9
+ SPACING_KEYS = (%i[m my mx p py px pt pl pb pr] + MARGIN_DIRECTION_KEYS).freeze
7
10
  DIRECTION_KEY = :direction
8
11
  JUSTIFY_CONTENT_KEY = :justify_content
9
12
  ALIGN_ITEMS_KEY = :align_items
10
13
  DISPLAY_KEY = :display
11
14
  RESPONSIVE_KEYS = ([DISPLAY_KEY, DIRECTION_KEY, JUSTIFY_CONTENT_KEY, ALIGN_ITEMS_KEY, :col, :float] + SPACING_KEYS).freeze
12
- BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"]
15
+ BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
13
16
 
14
17
  # Keys where we can simply translate { key: value } into ".key-value"
15
- CONCAT_KEYS = SPACING_KEYS + [:hide, :position, :v, :float, :col, :text, :box_shadow].freeze
18
+ CONCAT_KEYS = SPACING_KEYS + %i[hide position v float col text box_shadow].freeze
16
19
 
17
20
  INVALID_CLASS_NAME_PREFIXES =
18
21
  (["bg-", "color-", "text-", "d-", "v-align-", "wb-", "text-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
22
+ FUNCTIONAL_COLOR_REGEX = /(primary|secondary|tertiary|link|success|warning|danger|info)/.freeze
19
23
 
20
24
  COLOR_KEY = :color
21
25
  BG_KEY = :bg
22
26
  VERTICAL_ALIGN_KEY = :vertical_align
23
27
  WORD_BREAK_KEY = :word_break
24
- TEXT_KEYS = [:text_align, :font_weight]
28
+ TEXT_KEYS = %i[text_align font_weight].freeze
25
29
  FLEX_KEY = :flex
26
30
  FLEX_GROW_KEY = :flex_grow
27
31
  FLEX_SHRINK_KEY = :flex_shrink
@@ -30,19 +34,20 @@ module Primer
30
34
  HEIGHT_KEY = :height
31
35
  BOX_SHADOW_KEY = :box_shadow
32
36
  VISIBILITY_KEY = :visibility
37
+ ANIMATION_KEY = :animation
33
38
 
34
39
  BOOLEAN_MAPPINGS = {
35
40
  underline: {
36
41
  mappings: [
37
42
  {
38
43
  value: true,
39
- css_class: "text-underline",
44
+ css_class: "text-underline"
40
45
  },
41
46
  {
42
47
  value: false,
43
- css_class: "no-underline",
44
- },
45
- ],
48
+ css_class: "no-underline"
49
+ }
50
+ ]
46
51
  },
47
52
  top: {
48
53
  mappings: [
@@ -77,8 +82,9 @@ module Primer
77
82
  ]
78
83
  }
79
84
  }.freeze
80
- BORDER_KEYS = [:border, :border_color].freeze
81
- BORDER_MARGIN_KEYS = [:border_top, :border_bottom, :border_left, :border_right].freeze
85
+ BORDER_KEYS = %i[border border_color].freeze
86
+ BORDER_MARGIN_KEYS = %i[border_top border_bottom border_left border_right].freeze
87
+ BORDER_RADIUS_KEY = :border_radius
82
88
  TYPOGRAPHY_KEYS = [:font_size].freeze
83
89
  VALID_KEYS = (
84
90
  CONCAT_KEYS +
@@ -88,6 +94,7 @@ module Primer
88
94
  TYPOGRAPHY_KEYS +
89
95
  TEXT_KEYS +
90
96
  [
97
+ BORDER_RADIUS_KEY,
91
98
  COLOR_KEY,
92
99
  BG_KEY,
93
100
  DISPLAY_KEY,
@@ -103,7 +110,8 @@ module Primer
103
110
  WIDTH_KEY,
104
111
  HEIGHT_KEY,
105
112
  BOX_SHADOW_KEY,
106
- VISIBILITY_KEY
113
+ VISIBILITY_KEY,
114
+ ANIMATION_KEY
107
115
  ]
108
116
  ).freeze
109
117
 
@@ -111,30 +119,31 @@ module Primer
111
119
  def call(classes: "", style: nil, **args)
112
120
  extracted_results = extract_hash(args)
113
121
 
114
- {
115
- class: [validated_class_names(classes), extracted_results[:classes]].compact.join(" ").presence,
116
- style: [extracted_results[:styles], style].compact.join("").presence,
117
- }.merge(extracted_results.except(:classes, :styles))
122
+ extracted_results[:class] = [
123
+ validated_class_names(classes),
124
+ extracted_results.delete(:classes)
125
+ ].compact.join(" ").presence
126
+
127
+ extracted_results[:style] = [
128
+ extracted_results.delete(:styles),
129
+ style
130
+ ].compact.join("").presence
131
+
132
+ extracted_results
118
133
  end
119
134
 
120
135
  private
121
136
 
122
137
  def validated_class_names(classes)
123
- return unless classes.present?
138
+ return if classes.blank?
124
139
 
125
140
  if ENV["RAILS_ENV"] == "development"
126
141
  invalid_class_names =
127
142
  classes.split(" ").each_with_object([]) do |class_name, memo|
128
- if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) }
129
- memo << class_name
130
- end
143
+ memo << class_name if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) }
131
144
  end
132
145
 
133
- if invalid_class_names.any?
134
- raise ArgumentError.new(
135
- "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.",
136
- )
137
- end
146
+ 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." if invalid_class_names.any?
138
147
  end
139
148
 
140
149
  classes
@@ -152,99 +161,122 @@ module Primer
152
161
  # Example usage:
153
162
  # extract_hash({ mt: 4, py: 2 }) => "mt-4 py-2"
154
163
  def extract_hash(styles_hash)
155
- out = styles_hash.each_with_object({ classes: [], styles: [] }) do |(key, value), memo|
164
+ memo = { classes: [], styles: +"" }
165
+ styles_hash.each do |key, value|
156
166
  next unless VALID_KEYS.include?(key)
157
167
 
158
- if value.is_a?(Array) && !RESPONSIVE_KEYS.include?(key)
159
- raise ArgumentError, "#{key} does not support responsive values"
168
+ if value.is_a?(Array)
169
+ raise ArgumentError, "#{key} does not support responsive values" unless RESPONSIVE_KEYS.include?(key)
170
+
171
+ value.each_with_index do |val, index|
172
+ Primer::Classify::Cache.read(memo, key, val, BREAKPOINTS[index]) || extract_value(memo, key, val, BREAKPOINTS[index])
173
+ end
174
+ else
175
+ Primer::Classify::Cache.read(memo, key, value, BREAKPOINTS[0]) || extract_value(memo, key, value, BREAKPOINTS[0])
160
176
  end
177
+ end
161
178
 
162
- Array(value).each_with_index do |val, index|
163
- next if val.nil?
179
+ memo[:classes] = memo[:classes].join(" ")
164
180
 
165
- if SPACING_KEYS.include?(key)
166
- if MARGIN_DIRECTION_KEYS.include?(key)
167
- raise ArgumentError, "value of #{key} must be between -6 and 6" if (val < -6 || val > 6)
168
- elsif !((key == :mx || key == :my) && val == :auto)
169
- raise ArgumentError, "value of #{key} must be between 0 and 6" if (val < 0 || val > 6)
170
- end
171
- end
181
+ memo
182
+ end
183
+
184
+ def extract_value(memo, key, val, breakpoint)
185
+ return if val.nil? || val == ""
186
+
187
+ if SPACING_KEYS.include?(key)
188
+ if MARGIN_DIRECTION_KEYS.include?(key)
189
+ raise ArgumentError, "value of #{key} must be between -6 and 6" if val < -6 || val > 6
190
+ elsif !((key == :mx || key == :my) && val == :auto)
191
+ raise ArgumentError, "value of #{key} must be between 0 and 6" if val.negative? || val > 6
192
+ end
193
+ end
172
194
 
173
- dasherized_val = val.to_s.dasherize
174
- breakpoint = BREAKPOINTS[index]
175
-
176
- if BOOLEAN_MAPPINGS.has_key?(key)
177
- BOOLEAN_MAPPINGS[key][:mappings].map { |m| m[:css_class] if m[:value] == val }.compact.each do |css_class|
178
- memo[:classes] << css_class
179
- end
180
- elsif key == BG_KEY
181
- if val.to_s.starts_with?("#")
182
- memo[:styles] << "background-color: #{val};"
183
- else
184
- memo[:classes] << "bg-#{dasherized_val}"
185
- end
186
- elsif key == COLOR_KEY
187
- if val.to_s.chars.last !~ /\D/
188
- memo[:classes] << "color-#{dasherized_val}"
189
- else
190
- memo[:classes] << "text-#{dasherized_val}"
191
- end
192
- elsif key == DISPLAY_KEY
193
- memo[:classes] << "d#{breakpoint}-#{dasherized_val}"
194
- elsif key == VERTICAL_ALIGN_KEY
195
- memo[:classes] << "v-align-#{dasherized_val}"
196
- elsif key == WORD_BREAK_KEY
197
- memo[:classes] << "wb-#{dasherized_val}"
198
- elsif BORDER_KEYS.include?(key)
199
- memo[:classes] << "border-#{dasherized_val}"
200
- elsif BORDER_MARGIN_KEYS.include?(key)
201
- memo[:classes] << "#{key.to_s.dasherize}-#{val}"
202
- elsif key == DIRECTION_KEY
203
- memo[:classes] << "flex#{breakpoint}-#{dasherized_val}"
204
- elsif key == JUSTIFY_CONTENT_KEY
205
- formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
206
- memo[:classes] << "flex#{breakpoint}-justify-#{formatted_value}"
207
- elsif key == ALIGN_ITEMS_KEY
208
- memo[:classes] << "flex#{breakpoint}-items-#{val.to_s.gsub("flex_", "")}"
209
- elsif key == FLEX_KEY
210
- memo[:classes] << "flex-#{val}"
211
- elsif key == FLEX_GROW_KEY
212
- memo[:classes] << "flex-grow-#{val}"
213
- elsif key == FLEX_SHRINK_KEY
214
- memo[:classes] << "flex-shrink-#{val}"
215
- elsif key == ALIGN_SELF_KEY
216
- memo[:classes] << "flex-self-#{val}"
217
- elsif key == WIDTH_KEY || key == HEIGHT_KEY
218
- if val == :fit || val == :fill
219
- memo[:classes] << "#{key}-#{val}"
220
- else
221
- memo[key] = val
222
- end
223
- elsif TEXT_KEYS.include?(key)
224
- memo[:classes] << "text-#{dasherized_val}"
225
- elsif TYPOGRAPHY_KEYS.include?(key)
226
- memo[:classes] << "f#{dasherized_val}"
227
- elsif MARGIN_DIRECTION_KEYS.include?(key) && val < 0
228
- memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-n#{val.abs}"
229
- elsif key == BOX_SHADOW_KEY
230
- if val == true
231
- memo[:classes] << "box-shadow"
232
- else
233
- memo[:classes] << "box-shadow-#{dasherized_val}"
234
- end
235
- elsif key == VISIBILITY_KEY
236
- memo[:classes] << "v-#{dasherized_val}"
195
+ if BOOLEAN_MAPPINGS.key?(key)
196
+ BOOLEAN_MAPPINGS[key][:mappings].map { |m| m[:css_class] if m[:value] == val }.compact.each do |css_class|
197
+ memo[:classes] << css_class
198
+ end
199
+ elsif key == BG_KEY
200
+ if val.to_s.start_with?("#")
201
+ memo[:styles] << "background-color: #{val};"
202
+ else
203
+ memo[:classes] << "bg-#{val.to_s.dasherize}"
204
+ end
205
+ elsif key == COLOR_KEY
206
+ char_code = val[-1].ord
207
+ # Does this string end in a character that is NOT a number?
208
+ memo[:classes] <<
209
+ if (char_code >= 48 && char_code <= 57) || # 48 is the charcode for 0; 57 is the charcode for 9
210
+ FUNCTIONAL_COLOR_REGEX.match?(val)
211
+ "color-#{val.to_s.dasherize}"
237
212
  else
238
- memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{dasherized_val}"
213
+ "text-#{val.to_s.dasherize}"
239
214
  end
215
+ elsif key == DISPLAY_KEY
216
+ memo[:classes] << "d#{breakpoint}-#{val.to_s.dasherize}"
217
+ elsif key == VERTICAL_ALIGN_KEY
218
+ memo[:classes] << "v-align-#{val.to_s.dasherize}"
219
+ elsif key == WORD_BREAK_KEY
220
+ memo[:classes] << "wb-#{val.to_s.dasherize}"
221
+ elsif BORDER_KEYS.include?(key)
222
+ border_value = if val == true
223
+ "border"
224
+ else
225
+ "border-#{val.to_s.dasherize}"
226
+ end
227
+
228
+ memo[:classes] << border_value
229
+ elsif BORDER_MARGIN_KEYS.include?(key)
230
+ memo[:classes] << "#{key.to_s.dasherize}-#{val}"
231
+ elsif key == BORDER_RADIUS_KEY
232
+ memo[:classes] << "rounded-#{val}"
233
+ elsif key == DIRECTION_KEY
234
+ memo[:classes] << "flex#{breakpoint}-#{val.to_s.dasherize}"
235
+ elsif key == JUSTIFY_CONTENT_KEY
236
+ formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
237
+ memo[:classes] << "flex#{breakpoint}-justify-#{formatted_value}"
238
+ elsif key == ALIGN_ITEMS_KEY
239
+ memo[:classes] << "flex#{breakpoint}-items-#{val.to_s.gsub('flex_', '')}"
240
+ elsif key == FLEX_KEY
241
+ memo[:classes] << "flex-#{val}"
242
+ elsif key == FLEX_GROW_KEY
243
+ memo[:classes] << "flex-grow-#{val}"
244
+ elsif key == FLEX_SHRINK_KEY
245
+ memo[:classes] << "flex-shrink-#{val}"
246
+ elsif key == ALIGN_SELF_KEY
247
+ memo[:classes] << "flex-self-#{val}"
248
+ elsif key == WIDTH_KEY || key == HEIGHT_KEY
249
+ if val == :fit || val == :fill
250
+ memo[:classes] << "#{key}-#{val}"
251
+ else
252
+ memo[key] = val
240
253
  end
254
+ elsif TEXT_KEYS.include?(key)
255
+ memo[:classes] << "text-#{val.to_s.dasherize}"
256
+ elsif TYPOGRAPHY_KEYS.include?(key)
257
+ memo[:classes] << "f#{val.to_s.dasherize}"
258
+ elsif MARGIN_DIRECTION_KEYS.include?(key) && val.negative?
259
+ memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-n#{val.abs}"
260
+ elsif key == BOX_SHADOW_KEY
261
+ memo[:classes] << if val == true
262
+ "box-shadow"
263
+ else
264
+ "box-shadow-#{val.to_s.dasherize}"
265
+ end
266
+ elsif key == VISIBILITY_KEY
267
+ memo[:classes] << "v-#{val.to_s.dasherize}"
268
+ elsif key == ANIMATION_KEY
269
+ memo[:classes] << if val == :grow
270
+ "hover-grow"
271
+ else
272
+ "anim-#{val.to_s.dasherize}"
273
+ end
274
+ else
275
+ memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{val.to_s.dasherize}"
241
276
  end
242
-
243
- {
244
- classes: out[:classes].join(" "),
245
- styles: out[:styles].join(" ")
246
- }.merge(out.except(:classes, :styles))
247
277
  end
248
278
  end
279
+
280
+ Cache.preload!
249
281
  end
250
282
  end