primer_view_components 0.0.13 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/app/components/primer/base_component.rb +63 -15
  4. data/app/components/primer/blankslate_component.html.erb +4 -4
  5. data/app/components/primer/blankslate_component.rb +28 -2
  6. data/app/components/primer/border_box_component.rb +4 -0
  7. data/app/components/primer/box_component.rb +10 -0
  8. data/app/components/primer/breadcrumb_component.rb +2 -1
  9. data/app/components/primer/button_component.rb +1 -1
  10. data/app/components/primer/button_group_component.html.erb +5 -0
  11. data/app/components/primer/button_group_component.rb +34 -0
  12. data/app/components/primer/button_marketing_component.rb +73 -0
  13. data/app/components/primer/component.rb +14 -0
  14. data/app/components/primer/counter_component.rb +16 -12
  15. data/app/components/primer/details_component.rb +10 -6
  16. data/app/components/primer/dropdown_menu_component.rb +31 -3
  17. data/app/components/primer/flash_component.rb +2 -3
  18. data/app/components/primer/flex_component.rb +10 -9
  19. data/app/components/primer/flex_item_component.rb +2 -1
  20. data/app/components/primer/heading_component.rb +7 -0
  21. data/app/components/primer/label_component.rb +15 -9
  22. data/app/components/primer/link_component.rb +1 -1
  23. data/app/components/primer/octicon_component.rb +4 -3
  24. data/app/components/primer/popover_component.rb +3 -1
  25. data/app/components/primer/progress_bar_component.rb +5 -5
  26. data/app/components/primer/slot.rb +1 -0
  27. data/app/components/primer/spinner_component.rb +3 -4
  28. data/app/components/primer/state_component.rb +3 -3
  29. data/app/components/primer/subhead_component.rb +3 -0
  30. data/app/components/primer/timeline_item_component.rb +3 -0
  31. data/app/components/primer/tooltip_component.rb +88 -0
  32. data/app/components/primer/truncate_component.rb +41 -0
  33. data/app/components/primer/underline_nav_component.rb +26 -1
  34. data/app/components/primer/view_components.rb +5 -0
  35. data/lib/primer/class_name_helper.rb +1 -0
  36. data/lib/primer/classify.rb +129 -107
  37. data/lib/primer/fetch_or_fallback_helper.rb +9 -0
  38. data/lib/primer/join_style_arguments_helper.rb +14 -0
  39. data/lib/primer/view_components.rb +1 -0
  40. data/lib/primer/view_components/engine.rb +1 -0
  41. data/lib/primer/view_components/version.rb +1 -1
  42. metadata +42 -22
@@ -8,19 +8,19 @@ module Primer
8
8
  COLOR_DEFAULT => "",
9
9
  :green => "State--green",
10
10
  :red => "State--red",
11
- :purple => "State--purple",
11
+ :purple => "State--purple"
12
12
  }.freeze
13
13
  COLOR_OPTIONS = COLOR_MAPPINGS.keys
14
14
 
15
15
  SIZE_DEFAULT = :default
16
16
  SIZE_MAPPINGS = {
17
17
  SIZE_DEFAULT => "",
18
- :small => "State--small",
18
+ :small => "State--small"
19
19
  }.freeze
20
20
  SIZE_OPTIONS = SIZE_MAPPINGS.keys
21
21
 
22
22
  TAG_DEFAULT = :span
23
- TAG_OPTIONS = [TAG_DEFAULT, :div, :a]
23
+ TAG_OPTIONS = [TAG_DEFAULT, :div, :a].freeze
24
24
 
25
25
  # @example 40|Default
26
26
  # <%= render(Primer::StateComponent.new(title: "title")) { "State" } %>
@@ -67,6 +67,7 @@ module Primer
67
67
  heading.present?
68
68
  end
69
69
 
70
+ # :nodoc
70
71
  class Heading < ViewComponent::Slot
71
72
  include ClassNameHelper
72
73
 
@@ -85,6 +86,7 @@ module Primer
85
86
  end
86
87
  end
87
88
 
89
+ # :nodoc
88
90
  class Actions < ViewComponent::Slot
89
91
  include ClassNameHelper
90
92
 
@@ -98,6 +100,7 @@ module Primer
98
100
  end
99
101
  end
100
102
 
103
+ # :nodoc
101
104
  class Description < ViewComponent::Slot
102
105
  include ClassNameHelper
103
106
 
@@ -36,6 +36,7 @@ module Primer
36
36
  avatar.present? || badge.present? || body.present?
37
37
  end
38
38
 
39
+ # :nodoc
39
40
  class Avatar < Primer::Slot
40
41
  attr_reader :system_arguments, :alt, :src, :size, :square
41
42
 
@@ -59,6 +60,7 @@ module Primer
59
60
  end
60
61
  end
61
62
 
63
+ # :nodoc
62
64
  class Badge < Primer::Slot
63
65
  attr_reader :system_arguments, :icon
64
66
 
@@ -76,6 +78,7 @@ module Primer
76
78
  end
77
79
  end
78
80
 
81
+ # :nodoc
79
82
  class Body < Primer::Slot
80
83
  attr_reader :system_arguments
81
84
 
@@ -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 100|Default
30
+ # <div class="pt-5">
31
+ # <%= render(Primer::TooltipComponent.new(label: "Even bolder")) { "Default Bold Text" } %>
32
+ # </div>
33
+ #
34
+ # @example 100|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 100|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 100|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 100|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 25|Default
7
+ # <div class="col-2">
8
+ # <%= render(Primer::TruncateComponent.new(tag: :p)) { "branch-name-that-is-really-long" } %>
9
+ # </div>
10
+ #
11
+ # @example 25|Inline
12
+ # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true)) { "branch-name-that-is-really-long" } %>
13
+ #
14
+ # @example 25|Expandable
15
+ # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true, expandable: true)) { "branch-name-that-is-really-long" } %>
16
+ #
17
+ # @example 25|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 70|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 70|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
 
@@ -30,6 +31,8 @@ require_relative "border_box_component"
30
31
  require_relative "box_component"
31
32
  require_relative "breadcrumb_component"
32
33
  require_relative "button_component"
34
+ require_relative "button_group_component"
35
+ require_relative "button_marketing_component"
33
36
  require_relative "counter_component"
34
37
  require_relative "details_component"
35
38
  require_relative "dropdown_menu_component"
@@ -48,4 +51,6 @@ require_relative "state_component"
48
51
  require_relative "subhead_component"
49
52
  require_relative "text_component"
50
53
  require_relative "timeline_item_component"
54
+ require_relative "tooltip_component"
55
+ require_relative "truncate_component"
51
56
  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,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # :nodoc:
4
5
  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
6
+ MARGIN_DIRECTION_KEYS = %i[mt ml mb mr].freeze
7
+ SPACING_KEYS = (%i[m my mx p py px pt pl pb pr] + MARGIN_DIRECTION_KEYS).freeze
7
8
  DIRECTION_KEY = :direction
8
9
  JUSTIFY_CONTENT_KEY = :justify_content
9
10
  ALIGN_ITEMS_KEY = :align_items
10
11
  DISPLAY_KEY = :display
11
12
  RESPONSIVE_KEYS = ([DISPLAY_KEY, DIRECTION_KEY, JUSTIFY_CONTENT_KEY, ALIGN_ITEMS_KEY, :col, :float] + SPACING_KEYS).freeze
12
- BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"]
13
+ BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
13
14
 
14
15
  # 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
16
+ CONCAT_KEYS = SPACING_KEYS + %i[hide position v float col text box_shadow].freeze
16
17
 
17
18
  INVALID_CLASS_NAME_PREFIXES =
18
19
  (["bg-", "color-", "text-", "d-", "v-align-", "wb-", "text-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
@@ -21,7 +22,7 @@ module Primer
21
22
  BG_KEY = :bg
22
23
  VERTICAL_ALIGN_KEY = :vertical_align
23
24
  WORD_BREAK_KEY = :word_break
24
- TEXT_KEYS = [:text_align, :font_weight]
25
+ TEXT_KEYS = %i[text_align font_weight].freeze
25
26
  FLEX_KEY = :flex
26
27
  FLEX_GROW_KEY = :flex_grow
27
28
  FLEX_SHRINK_KEY = :flex_shrink
@@ -29,20 +30,21 @@ module Primer
29
30
  WIDTH_KEY = :width
30
31
  HEIGHT_KEY = :height
31
32
  BOX_SHADOW_KEY = :box_shadow
32
-
33
+ VISIBILITY_KEY = :visibility
34
+ ANIMATION_KEY = :animation
33
35
 
34
36
  BOOLEAN_MAPPINGS = {
35
37
  underline: {
36
38
  mappings: [
37
39
  {
38
40
  value: true,
39
- css_class: "text-underline",
41
+ css_class: "text-underline"
40
42
  },
41
43
  {
42
44
  value: false,
43
- css_class: "no-underline",
44
- },
45
- ],
45
+ css_class: "no-underline"
46
+ }
47
+ ]
46
48
  },
47
49
  top: {
48
50
  mappings: [
@@ -77,8 +79,9 @@ module Primer
77
79
  ]
78
80
  }
79
81
  }.freeze
80
- BORDER_KEYS = [:border, :border_color].freeze
81
- BORDER_MARGIN_KEYS = [:border_top, :border_bottom, :border_left, :border_right].freeze
82
+ BORDER_KEYS = %i[border border_color].freeze
83
+ BORDER_MARGIN_KEYS = %i[border_top border_bottom border_left border_right].freeze
84
+ BORDER_RADIUS_KEY = :border_radius
82
85
  TYPOGRAPHY_KEYS = [:font_size].freeze
83
86
  VALID_KEYS = (
84
87
  CONCAT_KEYS +
@@ -88,6 +91,7 @@ module Primer
88
91
  TYPOGRAPHY_KEYS +
89
92
  TEXT_KEYS +
90
93
  [
94
+ BORDER_RADIUS_KEY,
91
95
  COLOR_KEY,
92
96
  BG_KEY,
93
97
  DISPLAY_KEY,
@@ -102,7 +106,9 @@ module Primer
102
106
  ALIGN_SELF_KEY,
103
107
  WIDTH_KEY,
104
108
  HEIGHT_KEY,
105
- BOX_SHADOW_KEY
109
+ BOX_SHADOW_KEY,
110
+ VISIBILITY_KEY,
111
+ ANIMATION_KEY
106
112
  ]
107
113
  ).freeze
108
114
 
@@ -110,30 +116,31 @@ module Primer
110
116
  def call(classes: "", style: nil, **args)
111
117
  extracted_results = extract_hash(args)
112
118
 
113
- {
114
- class: [validated_class_names(classes), extracted_results[:classes]].compact.join(" ").presence,
115
- style: [extracted_results[:styles], style].compact.join("").presence,
116
- }.merge(extracted_results.except(:classes, :styles))
119
+ extracted_results[:class] = [
120
+ validated_class_names(classes),
121
+ extracted_results.delete(:classes)
122
+ ].compact.join(" ").presence
123
+
124
+ extracted_results[:style] = [
125
+ extracted_results.delete(:styles),
126
+ style
127
+ ].compact.join("").presence
128
+
129
+ extracted_results
117
130
  end
118
131
 
119
132
  private
120
133
 
121
134
  def validated_class_names(classes)
122
- return unless classes.present?
135
+ return if classes.blank?
123
136
 
124
137
  if ENV["RAILS_ENV"] == "development"
125
138
  invalid_class_names =
126
139
  classes.split(" ").each_with_object([]) do |class_name, memo|
127
- if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) }
128
- memo << class_name
129
- end
140
+ memo << class_name if INVALID_CLASS_NAME_PREFIXES.any? { |prefix| class_name.start_with?(prefix) }
130
141
  end
131
142
 
132
- if invalid_class_names.any?
133
- raise ArgumentError.new(
134
- "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.",
135
- )
136
- end
143
+ 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?
137
144
  end
138
145
 
139
146
  classes
@@ -151,96 +158,111 @@ module Primer
151
158
  # Example usage:
152
159
  # extract_hash({ mt: 4, py: 2 }) => "mt-4 py-2"
153
160
  def extract_hash(styles_hash)
154
- out = styles_hash.each_with_object({ classes: [], styles: [] }) do |(key, value), memo|
161
+ memo = { classes: [], styles: +"" }
162
+ styles_hash.each do |key, value|
155
163
  next unless VALID_KEYS.include?(key)
156
164
 
157
- if value.is_a?(Array) && !RESPONSIVE_KEYS.include?(key)
158
- raise ArgumentError, "#{key} does not support responsive values"
165
+ if value.is_a?(Array)
166
+ raise ArgumentError, "#{key} does not support responsive values" unless RESPONSIVE_KEYS.include?(key)
167
+
168
+ value.each_with_index do |val, index|
169
+ extract_value(memo, key, val, BREAKPOINTS[index])
170
+ end
171
+ else
172
+ extract_value(memo, key, value, BREAKPOINTS[0])
159
173
  end
174
+ end
160
175
 
161
- Array(value).each_with_index do |val, index|
162
- next if val.nil?
176
+ memo[:classes] = memo[:classes].join(" ")
163
177
 
164
- if SPACING_KEYS.include?(key)
165
- if MARGIN_DIRECTION_KEYS.include?(key)
166
- raise ArgumentError, "value of #{key} must be between -6 and 6" if (val < -6 || val > 6)
167
- elsif !((key == :mx || key == :my) && val == :auto)
168
- raise ArgumentError, "value of #{key} must be between 0 and 6" if (val < 0 || val > 6)
169
- end
170
- end
178
+ memo
179
+ end
171
180
 
172
- dasherized_val = val.to_s.dasherize
173
- breakpoint = BREAKPOINTS[index]
174
-
175
- if BOOLEAN_MAPPINGS.has_key?(key)
176
- BOOLEAN_MAPPINGS[key][:mappings].map { |m| m[:css_class] if m[:value] == val }.compact.each do |css_class|
177
- memo[:classes] << css_class
178
- end
179
- elsif key == BG_KEY
180
- if val.to_s.starts_with?("#")
181
- memo[:styles] << "background-color: #{val};"
182
- else
183
- memo[:classes] << "bg-#{dasherized_val}"
184
- end
185
- elsif key == COLOR_KEY
186
- if val.to_s.chars.last !~ /\D/
187
- memo[:classes] << "color-#{dasherized_val}"
188
- else
189
- memo[:classes] << "text-#{dasherized_val}"
190
- end
191
- elsif key == DISPLAY_KEY
192
- memo[:classes] << "d#{breakpoint}-#{dasherized_val}"
193
- elsif key == VERTICAL_ALIGN_KEY
194
- memo[:classes] << "v-align-#{dasherized_val}"
195
- elsif key == WORD_BREAK_KEY
196
- memo[:classes] << "wb-#{dasherized_val}"
197
- elsif BORDER_KEYS.include?(key)
198
- memo[:classes] << "border-#{dasherized_val}"
199
- elsif BORDER_MARGIN_KEYS.include?(key)
200
- memo[:classes] << "#{key.to_s.dasherize}-#{val}"
201
- elsif key == DIRECTION_KEY
202
- memo[:classes] << "flex#{breakpoint}-#{dasherized_val}"
203
- elsif key == JUSTIFY_CONTENT_KEY
204
- formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
205
- memo[:classes] << "flex#{breakpoint}-justify-#{formatted_value}"
206
- elsif key == ALIGN_ITEMS_KEY
207
- memo[:classes] << "flex#{breakpoint}-items-#{val.to_s.gsub("flex_", "")}"
208
- elsif key == FLEX_KEY
209
- memo[:classes] << "flex-#{val}"
210
- elsif key == FLEX_GROW_KEY
211
- memo[:classes] << "flex-grow-#{val}"
212
- elsif key == FLEX_SHRINK_KEY
213
- memo[:classes] << "flex-shrink-#{val}"
214
- elsif key == ALIGN_SELF_KEY
215
- memo[:classes] << "flex-self-#{val}"
216
- elsif key == WIDTH_KEY || key == HEIGHT_KEY
217
- if val == :fit || val == :fill
218
- memo[:classes] << "#{key}-#{val}"
219
- else
220
- memo[key] = val
221
- end
222
- elsif TEXT_KEYS.include?(key)
223
- memo[:classes] << "text-#{dasherized_val}"
224
- elsif TYPOGRAPHY_KEYS.include?(key)
225
- memo[:classes] << "f#{dasherized_val}"
226
- elsif MARGIN_DIRECTION_KEYS.include?(key) && val < 0
227
- memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-n#{val.abs}"
228
- elsif key == BOX_SHADOW_KEY
229
- if val == true
230
- memo[:classes] << "box-shadow"
231
- else
232
- memo[:classes] << "box-shadow-#{dasherized_val}"
233
- end
234
- else
235
- memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{dasherized_val}"
236
- end
181
+ def extract_value(memo, key, val, breakpoint)
182
+ return if val.nil?
183
+
184
+ if SPACING_KEYS.include?(key)
185
+ if MARGIN_DIRECTION_KEYS.include?(key)
186
+ raise ArgumentError, "value of #{key} must be between -6 and 6" if val < -6 || val > 6
187
+ elsif !((key == :mx || key == :my) && val == :auto)
188
+ raise ArgumentError, "value of #{key} must be between 0 and 6" if val.negative? || val > 6
237
189
  end
238
190
  end
239
191
 
240
- {
241
- classes: out[:classes].join(" "),
242
- styles: out[:styles].join(" ")
243
- }.merge(out.except(:classes, :styles))
192
+ if BOOLEAN_MAPPINGS.key?(key)
193
+ BOOLEAN_MAPPINGS[key][:mappings].map { |m| m[:css_class] if m[:value] == val }.compact.each do |css_class|
194
+ memo[:classes] << css_class
195
+ end
196
+ elsif key == BG_KEY
197
+ if val.to_s.starts_with?("#")
198
+ memo[:styles] << "background-color: #{val};"
199
+ else
200
+ memo[:classes] << "bg-#{val.to_s.dasherize}"
201
+ end
202
+ elsif key == COLOR_KEY
203
+ char_code = val[-1].ord
204
+ # Does this string end in a character that is NOT a number?
205
+ memo[:classes] << if char_code >= 48 && char_code <= 57 # 48 is the charcode for 0; 57 is the charcode for 9
206
+ "color-#{val.to_s.dasherize}"
207
+ else
208
+ "text-#{val.to_s.dasherize}"
209
+ end
210
+ elsif key == DISPLAY_KEY
211
+ memo[:classes] << "d#{breakpoint}-#{val.to_s.dasherize}"
212
+ elsif key == VERTICAL_ALIGN_KEY
213
+ memo[:classes] << "v-align-#{val.to_s.dasherize}"
214
+ elsif key == WORD_BREAK_KEY
215
+ memo[:classes] << "wb-#{val.to_s.dasherize}"
216
+ elsif BORDER_KEYS.include?(key)
217
+ memo[:classes] << "border-#{val.to_s.dasherize}"
218
+ elsif BORDER_MARGIN_KEYS.include?(key)
219
+ memo[:classes] << "#{key.to_s.dasherize}-#{val}"
220
+ elsif key == BORDER_RADIUS_KEY
221
+ memo[:classes] << "rounded-#{val}"
222
+ elsif key == DIRECTION_KEY
223
+ memo[:classes] << "flex#{breakpoint}-#{val.to_s.dasherize}"
224
+ elsif key == JUSTIFY_CONTENT_KEY
225
+ formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
226
+ memo[:classes] << "flex#{breakpoint}-justify-#{formatted_value}"
227
+ elsif key == ALIGN_ITEMS_KEY
228
+ memo[:classes] << "flex#{breakpoint}-items-#{val.to_s.gsub('flex_', '')}"
229
+ elsif key == FLEX_KEY
230
+ memo[:classes] << "flex-#{val}"
231
+ elsif key == FLEX_GROW_KEY
232
+ memo[:classes] << "flex-grow-#{val}"
233
+ elsif key == FLEX_SHRINK_KEY
234
+ memo[:classes] << "flex-shrink-#{val}"
235
+ elsif key == ALIGN_SELF_KEY
236
+ memo[:classes] << "flex-self-#{val}"
237
+ elsif key == WIDTH_KEY || key == HEIGHT_KEY
238
+ if val == :fit || val == :fill
239
+ memo[:classes] << "#{key}-#{val}"
240
+ else
241
+ memo[key] = val
242
+ end
243
+ elsif TEXT_KEYS.include?(key)
244
+ memo[:classes] << "text-#{val.to_s.dasherize}"
245
+ elsif TYPOGRAPHY_KEYS.include?(key)
246
+ memo[:classes] << "f#{val.to_s.dasherize}"
247
+ elsif MARGIN_DIRECTION_KEYS.include?(key) && val.negative?
248
+ memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-n#{val.abs}"
249
+ elsif key == BOX_SHADOW_KEY
250
+ memo[:classes] << if val == true
251
+ "box-shadow"
252
+ else
253
+ "box-shadow-#{val.to_s.dasherize}"
254
+ end
255
+ elsif key == VISIBILITY_KEY
256
+ memo[:classes] << "v-#{val.to_s.dasherize}"
257
+ elsif key == ANIMATION_KEY
258
+ memo[:classes] << if val == :grow
259
+ "hover-grow"
260
+ else
261
+ "anim-#{val.to_s.dasherize}"
262
+ end
263
+ else
264
+ memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{val.to_s.dasherize}"
265
+ end
244
266
  end
245
267
  end
246
268
  end