primer_view_components 0.0.13 → 0.0.18

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