ariadne_view_components 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/ariadne-form-with.d.ts +20 -0
  3. data/app/assets/javascripts/ariadne-form.d.ts +22 -0
  4. data/app/assets/javascripts/ariadne.d.ts +1 -1
  5. data/app/assets/javascripts/ariadne_view_components.js +7 -1
  6. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  7. data/app/assets/javascripts/comment-component.d.ts +13 -0
  8. data/app/assets/javascripts/rich-text-area-component.d.ts +4 -0
  9. data/app/{components/ariadne/time_ago_component.d.ts → assets/javascripts/time-ago-component.d.ts} +0 -0
  10. data/app/assets/stylesheets/application.ariadne_view_components.css +1 -0
  11. data/app/assets/stylesheets/prosemirror.css +323 -0
  12. data/app/components/ariadne/ariadne-form.ts +96 -0
  13. data/app/components/ariadne/ariadne.ts +8 -1
  14. data/app/components/ariadne/base_button.rb +6 -7
  15. data/app/components/ariadne/base_component.rb +13 -131
  16. data/app/components/ariadne/blankslate_component.html.erb +5 -5
  17. data/app/components/ariadne/blankslate_component.rb +4 -9
  18. data/app/components/ariadne/body_component.rb +1 -1
  19. data/app/components/ariadne/button_component.rb +7 -6
  20. data/app/components/ariadne/clipboard_copy_component.html.erb +3 -2
  21. data/app/components/ariadne/comment-component.ts +55 -0
  22. data/app/components/ariadne/comment_component.html.erb +17 -20
  23. data/app/components/ariadne/comment_component.rb +29 -17
  24. data/app/components/ariadne/component.rb +4 -4
  25. data/app/components/ariadne/container_component.rb +1 -1
  26. data/app/components/ariadne/counter_component.rb +4 -4
  27. data/app/components/ariadne/flash_component.html.erb +12 -12
  28. data/app/components/ariadne/flash_component.rb +16 -16
  29. data/app/components/ariadne/flex_component.rb +5 -7
  30. data/app/components/ariadne/footer_component.html.erb +1 -1
  31. data/app/components/ariadne/footer_component.rb +1 -1
  32. data/app/components/ariadne/grid_component.html.erb +4 -4
  33. data/app/components/ariadne/grid_component.rb +9 -9
  34. data/app/components/ariadne/header_component.html.erb +7 -7
  35. data/app/components/ariadne/header_component.rb +8 -8
  36. data/app/components/ariadne/heading_component.rb +3 -3
  37. data/app/components/ariadne/heroicon_component.rb +4 -4
  38. data/app/components/ariadne/inline_flex_component.rb +7 -7
  39. data/app/components/ariadne/link_component.rb +2 -2
  40. data/app/components/ariadne/list_component.rb +6 -5
  41. data/app/components/ariadne/narrow_container_component.html.erb +3 -0
  42. data/app/components/ariadne/narrow_container_component.rb +30 -0
  43. data/app/components/ariadne/panel_bar_component.html.erb +20 -0
  44. data/app/components/ariadne/panel_bar_component.rb +79 -0
  45. data/app/components/ariadne/pill_component.rb +2 -2
  46. data/app/components/ariadne/rich-text-area-component.ts +32 -0
  47. data/app/components/ariadne/rich_text_area_component.html.erb +6 -0
  48. data/app/components/ariadne/rich_text_area_component.rb +35 -0
  49. data/app/components/ariadne/slideover-component.ts +3 -3
  50. data/app/components/ariadne/slideover_component.html.erb +3 -3
  51. data/app/components/ariadne/slideover_component.rb +1 -1
  52. data/app/components/ariadne/tab_bar_component.html.erb +3 -0
  53. data/app/components/ariadne/tab_bar_component.rb +45 -0
  54. data/app/components/ariadne/tab_component.html.erb +7 -0
  55. data/app/components/ariadne/tab_component.rb +43 -0
  56. data/app/components/ariadne/{time_ago_component.ts → time-ago-component.ts} +0 -0
  57. data/app/components/ariadne/time_ago_component.rb +2 -2
  58. data/app/components/ariadne/timeline_component.html.erb +6 -6
  59. data/app/components/ariadne/tooltip-component.ts +3 -3
  60. data/app/components/ariadne/tooltip_component.html.erb +1 -1
  61. data/app/components/ariadne/tooltip_component.rb +1 -1
  62. data/app/lib/ariadne/action_view_extensions/form_helper.rb +4 -1
  63. data/app/lib/ariadne/fetch_or_fallback_helper.rb +3 -1
  64. data/app/lib/ariadne/form_builder.rb +10 -10
  65. data/app/lib/ariadne/icon_helper.rb +1 -1
  66. data/lib/ariadne/view_components/engine.rb +169 -3
  67. data/lib/ariadne/view_components/version.rb +1 -1
  68. data/lib/ariadne/view_components.rb +0 -1
  69. data/lib/rubocop/config/default.yml +0 -6
  70. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +1 -0
  71. data/lib/tasks/docs.rake +6 -1
  72. data/static/arguments.yml +99 -4
  73. data/static/audited_at.json +8 -2
  74. data/static/classes.yml +195 -181
  75. data/static/constants.json +112 -72
  76. data/static/statuses.json +8 -2
  77. metadata +42 -32
  78. data/app/assets/builds/ariadne_view_components.css +0 -1874
  79. data/app/components/ariadne/ariadne.d.ts +0 -1
  80. data/app/components/ariadne/ariadne.js +0 -9
  81. data/app/components/ariadne/clipboard-copy-component.d.ts +0 -4
  82. data/app/components/ariadne/clipboard-copy-component.js +0 -18
  83. data/app/components/ariadne/clipboard_copy_component.d.ts +0 -4
  84. data/app/components/ariadne/clipboard_copy_component.js +0 -18
  85. data/app/components/ariadne/slideover-component.d.ts +0 -9
  86. data/app/components/ariadne/slideover-component.js +0 -20
  87. data/app/components/ariadne/slideover_component.d.ts +0 -9
  88. data/app/components/ariadne/slideover_component.js +0 -19
  89. data/app/components/ariadne/time_ago_component.js +0 -1
  90. data/app/components/ariadne/tooltip-component.d.ts +0 -24
  91. data/app/components/ariadne/tooltip-component.js +0 -42
  92. data/lib/ariadne/classify/utilities.rb +0 -199
  93. data/lib/ariadne/classify/utilities.yml +0 -1817
  94. data/lib/ariadne/classify/validation.rb +0 -18
  95. data/lib/ariadne/classify.rb +0 -124
  96. data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +0 -252
  97. data/lib/rubocop/cop/ariadne/component_name_migration.rb +0 -35
  98. data/lib/rubocop/cop/ariadne/system_argument_instead_of_class.rb +0 -57
  99. data/lib/tasks/utilities.rake +0 -121
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "utilities"
4
-
5
- module Ariadne
6
- class Classify
7
- # :nodoc:
8
- class Validation
9
- INVALID_CLASS_NAME_PREFIXES = /box-shadow-|box_shadow-/
10
-
11
- class << self
12
- def invalid?(class_name)
13
- class_name.start_with?(INVALID_CLASS_NAME_PREFIXES) || Ariadne::Classify::Utilities.supported_selector?(class_name)
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "classify/utilities"
4
- require_relative "classify/validation"
5
-
6
- require "tailwind_merge"
7
-
8
- module Ariadne
9
- # :nodoc:
10
- class Classify
11
- FLEX_VALUES = [1, :auto].freeze
12
-
13
- FLEX_WRAP_MAPPINGS = {
14
- wrap: "flex-wrap",
15
- nowrap: "flex-nowrap",
16
- reverse: "flex-wrap-reverse",
17
- }.freeze
18
-
19
- FLEX_ALIGN_SELF_VALUES = [:auto, :start, :end, :center, :baseline, :stretch].freeze
20
-
21
- FLEX_DIRECTION_VALUES = [:column, :column_reverse, :row, :row_reverse].freeze
22
-
23
- FLEX_JUSTIFY_CONTENT_VALUES = [:flex_start, :flex_end, :center, :space_between, :space_around].freeze
24
-
25
- FLEX_ALIGN_ITEMS_VALUES = [:flex_start, :flex_end, :center, :baseline, :stretch].freeze
26
-
27
- LOOKUP = Ariadne::Classify::Utilities::UTILITIES
28
-
29
- class << self
30
- # Utility for mapping component configuration into Tailwind CSS class names.
31
- #
32
- # args can contain utility keys that mimic the interface used by
33
- # Ariadne components, as well as the special entries :classes
34
- # and :style.
35
- #
36
- # Returns a hash containing two entries. The :classes entry is a string of
37
- # Tailwind CSS class names, including any classes given in the :classes entry
38
- # in args. The :style entry is the value of the given :style entry given in
39
- # args.
40
- #
41
- #
42
- # Example usage:
43
- # extract_css_attrs({ mt: 4, py: 2 }) => { classes: "mt-4 py-2", style: nil }
44
- # extract_css_attrs(classes: "d-flex", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: nil }
45
- # extract_css_attrs(classes: "d-flex", style: "float: left", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: "float: left" }
46
- #
47
- def call(args)
48
- style = nil
49
- args = [] if args.blank?
50
-
51
- classes = [].tap do |result|
52
- args.each do |key, val|
53
- case key
54
- when :classes
55
- # insert :classes first to avoid huge doc diffs
56
- if (class_names = validated_class_names(val))
57
- result.unshift(class_names)
58
- end
59
- next
60
- when :style
61
- style = val
62
- next
63
- end
64
-
65
- next unless LOOKUP[key]
66
-
67
- if val.is_a?(Array)
68
- # A while loop is ~3.5x faster than Array#each.
69
- brk = 0
70
- while brk < val.size
71
- item = val[brk]
72
-
73
- if item.nil?
74
- brk += 1
75
- next
76
- end
77
-
78
- # Believe it or not, three calls to Hash#[] and an inline rescue
79
- # are about 30% faster than Hash#dig. It also ensures validate is
80
- # only called when necessary, i.e. when the class can't be found
81
- # in the lookup table.
82
- # rubocop:disable Style/RescueModifier
83
- found = (LOOKUP[key][item][brk] rescue nil) || validate(key, item, brk)
84
- # rubocop:enable Style/RescueModifier
85
- result << found if found
86
- brk += 1
87
- end
88
- else
89
- next if val.nil?
90
-
91
- # rubocop:disable Style/RescueModifier
92
- found = (LOOKUP[key][val][0] rescue nil) || validate(key, val, 0)
93
- # rubocop:enable Style/RescueModifier
94
- result << found if found
95
- end
96
- end
97
- end.join(" ")
98
-
99
- result = {}
100
-
101
- result[:class] = classes if classes.present?
102
- result[:style] = style if style.present?
103
-
104
- result
105
- end
106
-
107
- private def validate(key, val, brk)
108
- brk_str = Ariadne::Classify::Utilities::BREAKPOINTS[brk]
109
- Ariadne::Classify::Utilities.validate(key, val, brk_str)
110
- end
111
-
112
- private def validated_class_names(classes)
113
- return if classes.blank?
114
-
115
- # TODO: obviously instantiate this
116
- TailwindMerge::Merger.new.merge(classes)
117
- end
118
-
119
- private def raise_on_invalid_options?
120
- Rails.application.config.ariadne_view_components.raise_on_invalid_options
121
- end
122
- end
123
- end
124
- end
@@ -1,252 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rubocop"
4
- require "ariadne/classify/utilities"
5
- require "ariadne/classify/validation"
6
-
7
- # :nocov:
8
- module RuboCop
9
- module Cop
10
- module Ariadne
11
- # This cop ensures that components use System Arguments instead of CSS classes.
12
- #
13
- # bad
14
- # heroicon(icon: :icon, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
15
- # heroicon(icon: "icon", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
16
- # heroicon(icon: "icon-with-dashes")
17
- # heroicon(icon: @ivar)
18
- # heroicon(icon: condition > "icon" : "other-icon")
19
- #
20
- # good
21
- # ariadne_heroicon(icon: :icon, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
22
- # ariadne_heroicon(icon: :"icon-with-dashes", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
23
- # ariadne_heroicon(icon: @ivar, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
24
- # ariadne_heroicon(icon: condition > "icon" : "other-icon", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)
25
- class AriadneHeroicon < RuboCop::Cop::Cop
26
- INVALID_MESSAGE = <<~STR
27
- Replace the `heroicon` helper with `ariadne_heroicon`. See https://ariadne.style/view-components/components/heroicon for details.
28
- STR
29
-
30
- ICON_ATTRIBUTES = ["icon", "variant"].freeze
31
- SIZE_ATTRIBUTES = ["height", "width", "size"].freeze
32
- STRING_ATTRIBUTES = ["aria-", "data-"].freeze
33
- REST_ATTRIBUTES = ["title"].freeze
34
- VALID_ATTRIBUTES = [*ICON_ATTRIBUTES, *SIZE_ATTRIBUTES, *STRING_ATTRIBUTES, *REST_ATTRIBUTES, "class"].freeze
35
-
36
- STRING_ATTRIBUTE_REGEX = Regexp.union(STRING_ATTRIBUTES).freeze
37
- ATTRIBUTE_REGEX = Regexp.union(VALID_ATTRIBUTES).freeze
38
- INVALID_ATTRIBUTE = -1
39
-
40
- def on_send(node)
41
- return unless node.method_name == :heroicon
42
- return unless node.arguments?
43
-
44
- kwargs = kwargs(node)
45
-
46
- return unless kwargs.type == :hash
47
-
48
- attributes = kwargs.keys.map(&:value)
49
-
50
- # Don't convert unknown attributes
51
- return unless attributes.all? { |attribute| attribute.match?(ATTRIBUTE_REGEX) }
52
-
53
- # Can't convert size
54
- return if heroicon_size_attributes(kwargs) == INVALID_ATTRIBUTE
55
-
56
- # find class pair
57
- classes = classes(kwargs)
58
-
59
- return if classes == INVALID_ATTRIBUTE
60
-
61
- # check if classes are convertible
62
- if classes.present?
63
- attributes = ::Ariadne::Classify::Utilities.classes_to_hash(classes)
64
- invalid_classes = (attributes[:classes]&.split(" ") || []).select { |class_name| ::Ariadne::Classify::Validation.invalid?(class_name) }
65
-
66
- # Uses system argument that can't be converted
67
- return if invalid_classes.present?
68
- end
69
-
70
- add_offense(node, message: INVALID_MESSAGE)
71
- end
72
-
73
- def autocorrect(node)
74
- lambda do |corrector|
75
- kwargs = kwargs(node)
76
-
77
- # Converting arguments for the component
78
- classes = classes(kwargs)
79
- icon_and_variant = transform_icon_and_variant(kwargs)
80
- size_attributes = transform_sizes(kwargs)
81
- rest_attributes = rest_args(kwargs)
82
-
83
- args = arguments_as_string(node, icon_and_variant, size_attributes, rest_attributes, classes)
84
-
85
- if node.dot?
86
- corrector.replace(node.loc.expression, "#{node.receiver.source}.ariadne_heroicon(#{args})")
87
- else
88
- corrector.replace(node.loc.expression, "ariadne_heroicon(#{args})")
89
- end
90
- end
91
- end
92
-
93
- private def transform_icon_and_variant(kwargs)
94
- kwargs.pairs.each_with_object({}) do |pair, h|
95
- next unless ICON_ATTRIBUTES.include?(pair.key.value.to_s)
96
-
97
- # We only support symbol or string values...
98
- h[pair.key.value] = case pair.value.type
99
- when :str
100
- { value: pair.value.value.to_s, type: :str }
101
- when :sym
102
- { value: pair.value.source.to_sym, type: :sym }
103
- else # ... but calling source will also get when you want, for :const, :if, etc.
104
- { value: pair.value.source, type: :other }
105
- end
106
- end
107
- end
108
-
109
- private def transform_sizes(kwargs)
110
- attributes = heroicon_size_attributes(kwargs)
111
-
112
- attributes.transform_values do |size|
113
- if size.between?(10, 16)
114
- ""
115
- elsif size.between?(22, 26)
116
- :md
117
- else
118
- size
119
- end
120
- end
121
- end
122
-
123
- private def rest_args(kwargs)
124
- kwargs.pairs.each_with_object({}) do |pair, h|
125
- next unless REST_ATTRIBUTES.include?(pair.key.value.to_s)
126
-
127
- h[pair.key.value] = pair.value.source
128
- end
129
- end
130
-
131
- private def heroicon_size_attributes(kwargs)
132
- kwargs.pairs.each_with_object({}) do |pair, h|
133
- next unless SIZE_ATTRIBUTES.include?(pair.key.value.to_s)
134
-
135
- # We only support string or int values.
136
- case pair.value.type
137
- when :int
138
- h[pair.key.value] = pair.value.source.to_i
139
- when :str
140
- h[pair.key.value] = pair.value.value.to_i
141
- else
142
- return INVALID_ATTRIBUTE
143
- end
144
- end
145
- end
146
-
147
- private def classes(kwargs)
148
- # find class pair
149
- class_arg = kwargs.pairs.find { |kwarg| kwarg.key.value == :class }
150
-
151
- return if class_arg.blank?
152
- return INVALID_ATTRIBUTE unless class_arg.value.type == :str
153
-
154
- class_arg.value.value
155
- end
156
-
157
- private def arguments_as_string(node, icon_and_variant, size_attributes, rest_attributes, classes)
158
- icon = case icon_and_variant[:icon][:type]
159
- when :str
160
- "icon: \"#{icon_and_variant[:icon][:value]}\""
161
- when :sym, :other
162
- "icon: #{icon_and_variant[:icon][:value]}"
163
- end
164
- variant = case icon_and_variant[:variant][:type]
165
- when :str
166
- "variant: \"#{icon_and_variant[:variant][:value]}\""
167
- when :sym, :other
168
- "variant: #{icon_and_variant[:variant][:value]}"
169
- end
170
-
171
- args = "#{icon}, #{variant}"
172
-
173
- size_args = size_attributes_to_string(size_attributes)
174
- string_args = string_args_to_string(node)
175
- rest_args = rest_args_to_string(rest_attributes)
176
-
177
- args = "#{args}, #{size_args}" if size_args.present?
178
- args = "#{args}, #{rest_args}" if rest_args.present?
179
- args = "#{args}, #{utilities_args(classes)}" if classes.present?
180
- args = "#{args}, #{string_args}" if string_args.present?
181
-
182
- args
183
- end
184
-
185
- private def rest_args_to_string(attrs)
186
- return if attrs.blank?
187
-
188
- attrs.map do |key, value|
189
- "#{key}: #{value}"
190
- end.join(", ")
191
- end
192
-
193
- private def utilities_args(classes)
194
- args = ::Ariadne::Classify::Utilities.classes_to_hash(classes)
195
-
196
- color = case args[:color]
197
- when :text_white
198
- :on_emphasis
199
- when Symbol
200
- args[:color].to_s.gsub("text_", "icon_").to_sym
201
- end
202
-
203
- args[:color] = color if color
204
-
205
- ::Ariadne::Classify::Utilities.hash_to_args(args)
206
- end
207
-
208
- private def size_attributes_to_string(size_attributes)
209
- # No arguments if they map to the default size
210
- return if size_attributes.blank? || size_attributes.values.all?(&:blank?)
211
- # Return mapped argument to `size`
212
- return "size: :md" if size_attributes.values.any?(:md)
213
-
214
- size_attributes.map do |key, value|
215
- "#{key}: #{value}"
216
- end.join(", ")
217
- end
218
-
219
- private def string_args_to_string(node)
220
- kwargs = kwargs(node)
221
-
222
- args = kwargs.pairs.each_with_object([]) do |pair, acc|
223
- next unless pair.key.value.to_s.match?(STRING_ATTRIBUTE_REGEX)
224
-
225
- key = pair.key.value.to_s == "data-test-selector" ? "test_selector" : "\"#{pair.key.value}\""
226
- acc << "#{key}: #{pair.value.source}"
227
- end
228
-
229
- args.join(",")
230
- end
231
-
232
- Kwargs = Struct.new(:keys, :pairs, :type)
233
- def kwargs(node)
234
- return node.arguments.last if node.arguments.size > 1
235
-
236
- keys = node.arguments.first.keys
237
- pairs = node.arguments.first.pairs
238
- Kwargs.new(keys, pairs, :hash)
239
- end
240
-
241
- private def icon(node)
242
- return node.source unless node.type == :str
243
- return ":#{node.value}" unless node.value.include?("-")
244
-
245
- # If the icon contains `-` we need to cast the string as a symbol
246
- # E.g: `arrow-down` becomes `:"arrow-down"`
247
- ":#{node.source}"
248
- end
249
- end
250
- end
251
- end
252
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rubocop"
4
-
5
- # :nocov:
6
- module RuboCop
7
- module Cop
8
- module Ariadne
9
- # This cop ensures that components don't use deprecated component names
10
- #
11
- # bad
12
- # Ariadne::ComponentNameComponent.new()
13
- #
14
- # good
15
- # Ariadne::Beta::ComponentName.new()
16
- class ComponentNameMigration < BaseCop
17
- DEPRECATIONS = {
18
- "Ariadne::TestComponent" => "Ariadne::Beta::Test",
19
- }.freeze
20
-
21
- def on_send(node)
22
- return unless node.method_name == :new && !node.receiver.nil? && DEPRECATIONS.key?(node.receiver.const_name)
23
-
24
- add_offense(node.receiver, message: "Don't use deprecated names")
25
- end
26
-
27
- def autocorrect(node)
28
- lambda do |corrector|
29
- corrector.replace(node, DEPRECATIONS[node.const_name])
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rubocop"
4
- require "ariadne/classify/utilities"
5
-
6
- # :nocov:
7
- module RuboCop
8
- module Cop
9
- module Ariadne
10
- # This cop ensures that components use System Arguments instead of CSS classes.
11
- #
12
- # bad
13
- # Component.new(classes: "mr-1")
14
- #
15
- # good
16
- # Component.new(mr: 1)
17
- class SystemArgumentInsteadOfClass < BaseCop
18
- INVALID_MESSAGE = <<~STR
19
- Avoid using CSS classes when you can use System Arguments: https://ariadne.style/view-components/system-arguments.
20
- STR
21
-
22
- def on_send(node)
23
- return unless valid_node?(node)
24
- return unless node.arguments?
25
-
26
- # we are looking for hash arguments and they are always last
27
- kwargs = node.arguments.last
28
-
29
- return unless kwargs.type == :hash
30
-
31
- # find classes pair
32
- classes_arg = kwargs.pairs.find { |kwarg| kwarg.key.value == :classes }
33
-
34
- return if classes_arg.nil?
35
- return unless classes_arg.value.type == :str
36
-
37
- # get actual classes
38
- classes = classes_arg.value.value
39
-
40
- attributes = ::Ariadne::Classify::Utilities.classes_to_hash(classes)
41
-
42
- # no classes are fixable
43
- return if attributes[:classes] == classes
44
-
45
- add_offense(classes_arg, message: INVALID_MESSAGE)
46
- end
47
-
48
- def autocorrect(node)
49
- lambda do |corrector|
50
- args = ::Ariadne::Classify::Utilities.classes_to_args(node.value.value)
51
- corrector.replace(node.loc.expression, args)
52
- end
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :utilities do
4
- desc "Generate CSS utility classes"
5
- task :build do
6
- require "yaml"
7
- require "json"
8
- require File.expand_path("./../../lookbook/config/environment.rb", __dir__)
9
- require "ariadne/classify/utilities"
10
-
11
- # Keys that are looked for to be included in the utilities.yml file
12
- SUPPORTED_KEYS = [
13
- /^anim\b/,
14
- /^color-bg\b/,
15
- /^color-border\b/,
16
- /^color-fg\b/,
17
- /^col\b/,
18
- /^container\b/,
19
- /^clearfix\b/,
20
- /^d\b/,
21
- /^float\b/,
22
- /^height\b/,
23
- /^hide\b/,
24
- /^m[trblxy]?\b/,
25
- /^p[trblxy]?\b/,
26
- /^position\b/,
27
- /^wb\b/,
28
- /^width\b/,
29
- /^v\b/,
30
- ].freeze
31
-
32
- BREAKPOINTS = [nil, "sm", "md", "lg", "xl"].freeze
33
- utility_data =
34
- JSON.parse(
35
- File.read(
36
- File.expand_path(File.join("..", "..", "node_modules", "@primer", "css", "dist", "stats", "utilities.json"), __dir__)
37
- )
38
- )["selectors"]["values"]
39
-
40
- custom_utility_data = YAML.load_file(
41
- File.join(__dir__, "custom_utilities.yml")
42
- )
43
-
44
- layout_data =
45
- JSON.parse(
46
- File.read(
47
- File.expand_path(File.join("..", "..", "node_modules", "@primer", "css", "dist", "stats", "layout.json"), __dir__)
48
- )
49
- )["selectors"]["values"]
50
-
51
- css_data = utility_data + layout_data
52
-
53
- output = {}
54
-
55
- css_data.each do |selector|
56
- selector.sub!(/^./, "")
57
- selector.sub!(/:[^\s]*$/, "")
58
-
59
- # Next if selector has ancestors or sibling selectors
60
- next if selector.match?(/[:><~\[.]/)
61
- next unless SUPPORTED_KEYS.any? { |key| selector =~ key }
62
-
63
- # Dupe so we still have the selector at the end of slicing it up
64
- classname = selector.dup
65
- key = ""
66
-
67
- # Look for a replacement key
68
- Ariadne::Classify::Utilities::REPLACEMENT_KEYS.each do |k, v|
69
- next unless classname.match?(Regexp.new(k))
70
-
71
- key = v
72
- classname.sub!(Regexp.new("#{k}-"), "")
73
- end
74
-
75
- # If we didn't find a replacement, grab the first text before hyphen
76
- if classname == selector
77
- key = classname.split("-").first
78
- classname.sub!(/^[^-]+-/, "")
79
- end
80
-
81
- # Check if the next bit of the classname is a breakpoint
82
- if classname.match?(/^(sm-|md-|lg-|xl-)/)
83
- breakpoint = classname.split("-").first
84
- classname.sub!(/^[^-]+-/, "")
85
- end
86
-
87
- # Change the rest from hyphens to underscores
88
- classname.sub!(/-/, "_")
89
-
90
- # convert padding/margin negative values ie n7 to -7
91
- classname.sub!(/^n/, "-") if classname.match?(/^n[0-9]/)
92
-
93
- # If key and classname are equal, then classname is boolean
94
- classname = true if key == classname
95
-
96
- key = key.to_sym
97
-
98
- if classname.is_a?(String)
99
- classname = classname.match?(/\A[-+]?[0-9]+\z/) ? classname.to_i : classname.to_sym
100
- end
101
-
102
- if output[key].nil?
103
- output[key] = { classname => Array.new(5, nil) }
104
- elsif output[key][classname].nil?
105
- output[key][classname] = Array.new(5, nil)
106
- end
107
-
108
- output[key][classname][BREAKPOINTS.index(breakpoint)] = selector
109
- end
110
-
111
- output.transform_values! do |x|
112
- x.transform_values { |y| y.reverse.drop_while(&:nil?).reverse }
113
- end
114
-
115
- output.merge!(custom_utility_data)
116
-
117
- File.open("lib/ariadne/classify/utilities.yml", "w") do |f|
118
- f.puts YAML.dump(output)
119
- end
120
- end
121
- end