ariadne_view_components 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/ariadne-form-with.d.ts +20 -0
  4. data/app/assets/javascripts/ariadne-form.d.ts +22 -0
  5. data/app/assets/javascripts/ariadne.d.ts +1 -0
  6. data/app/assets/javascripts/ariadne_view_components.js +7 -1
  7. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  8. data/app/assets/javascripts/clipboard-copy-component.d.ts +4 -0
  9. data/app/assets/javascripts/comment-component.d.ts +13 -0
  10. data/app/assets/javascripts/rich-text-area-component.d.ts +4 -0
  11. data/app/assets/javascripts/slideover-component.d.ts +9 -0
  12. data/app/assets/javascripts/time-ago-component.d.ts +1 -0
  13. data/app/assets/javascripts/time_ago_component.d.ts +1 -0
  14. data/app/assets/javascripts/tooltip-component.d.ts +24 -0
  15. data/app/assets/stylesheets/application.ariadne_view_components.css +6 -3
  16. data/app/assets/stylesheets/prosemirror.css +323 -0
  17. data/app/assets/stylesheets/tooltip-component.css +37 -0
  18. data/app/components/ariadne/ariadne-form.ts +96 -0
  19. data/app/components/ariadne/ariadne.ts +11 -1
  20. data/app/components/ariadne/base_button.rb +12 -12
  21. data/app/components/ariadne/base_component.rb +13 -131
  22. data/app/components/ariadne/blankslate_component.html.erb +5 -5
  23. data/app/components/ariadne/blankslate_component.rb +5 -10
  24. data/app/components/ariadne/body_component.rb +30 -0
  25. data/app/components/ariadne/button_component.rb +12 -16
  26. data/app/components/ariadne/clipboard_copy_component.html.erb +5 -4
  27. data/app/components/ariadne/clipboard_copy_component.rb +41 -3
  28. data/app/components/ariadne/comment-component.ts +55 -0
  29. data/app/components/ariadne/comment_component.html.erb +22 -0
  30. data/app/components/ariadne/comment_component.rb +57 -0
  31. data/app/components/ariadne/component.rb +4 -3
  32. data/app/components/ariadne/container_component.rb +1 -1
  33. data/app/components/ariadne/counter_component.rb +4 -4
  34. data/app/components/ariadne/flash_component.html.erb +12 -12
  35. data/app/components/ariadne/flash_component.rb +17 -17
  36. data/app/components/ariadne/flex_component.rb +49 -0
  37. data/app/components/ariadne/footer_component.html.erb +1 -1
  38. data/app/components/ariadne/footer_component.rb +1 -1
  39. data/app/components/ariadne/grid_component.html.erb +13 -4
  40. data/app/components/ariadne/grid_component.rb +22 -11
  41. data/app/components/ariadne/header_component.html.erb +7 -7
  42. data/app/components/ariadne/header_component.rb +8 -8
  43. data/app/components/ariadne/heading_component.rb +3 -3
  44. data/app/components/ariadne/heroicon_component.html.erb +4 -6
  45. data/app/components/ariadne/heroicon_component.rb +21 -10
  46. data/app/components/ariadne/inline_flex_component.rb +14 -12
  47. data/app/components/ariadne/link_component.rb +13 -8
  48. data/app/components/ariadne/list_component.html.erb +5 -7
  49. data/app/components/ariadne/list_component.rb +9 -38
  50. data/app/components/ariadne/main_component.rb +32 -0
  51. data/app/components/ariadne/narrow_container_component.html.erb +3 -0
  52. data/app/components/ariadne/narrow_container_component.rb +30 -0
  53. data/app/components/ariadne/panel_bar_component.html.erb +20 -0
  54. data/app/components/ariadne/panel_bar_component.rb +79 -0
  55. data/app/components/ariadne/pill_component.rb +2 -2
  56. data/app/components/ariadne/rich-text-area-component.ts +32 -0
  57. data/app/components/ariadne/rich_text_area_component.html.erb +6 -0
  58. data/app/components/ariadne/rich_text_area_component.rb +35 -0
  59. data/app/components/ariadne/slideover-component.ts +3 -3
  60. data/app/components/ariadne/slideover_component.html.erb +3 -6
  61. data/app/components/ariadne/slideover_component.rb +19 -15
  62. data/app/components/ariadne/tab_bar_component.html.erb +3 -0
  63. data/app/components/ariadne/tab_bar_component.rb +45 -0
  64. data/app/components/ariadne/tab_component.html.erb +7 -0
  65. data/app/components/ariadne/tab_component.rb +43 -0
  66. data/app/components/ariadne/{time_ago_component.ts → time-ago-component.ts} +0 -0
  67. data/app/components/ariadne/time_ago_component.rb +2 -2
  68. data/app/components/ariadne/timeline_component.html.erb +6 -6
  69. data/app/components/ariadne/tooltip-component.ts +57 -0
  70. data/app/components/ariadne/tooltip_component.html.erb +4 -0
  71. data/app/components/ariadne/tooltip_component.rb +34 -31
  72. data/app/lib/ariadne/action_view_extensions/form_helper.rb +4 -1
  73. data/app/lib/ariadne/fetch_or_fallback_helper.rb +3 -1
  74. data/app/lib/ariadne/form_builder.rb +22 -22
  75. data/app/lib/ariadne/icon_helper.rb +1 -1
  76. data/lib/ariadne/view_components/engine.rb +171 -3
  77. data/lib/ariadne/view_components/version.rb +1 -1
  78. data/lib/ariadne/view_components.rb +31 -30
  79. data/lib/rubocop/config/default.yml +0 -6
  80. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +1 -0
  81. data/lib/tasks/docs.rake +9 -0
  82. data/static/arguments.yml +186 -15
  83. data/static/audited_at.json +12 -2
  84. data/static/classes.yml +200 -154
  85. data/static/constants.json +168 -146
  86. data/static/statuses.json +12 -2
  87. metadata +65 -13
  88. data/lib/ariadne/classify/utilities.rb +0 -199
  89. data/lib/ariadne/classify/utilities.yml +0 -1817
  90. data/lib/ariadne/classify/validation.rb +0 -18
  91. data/lib/ariadne/classify.rb +0 -218
  92. data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +0 -252
  93. data/lib/rubocop/cop/ariadne/component_name_migration.rb +0 -35
  94. data/lib/rubocop/cop/ariadne/system_argument_instead_of_class.rb +0 -57
  95. 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,218 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "classify/utilities"
4
- require_relative "classify/validation"
5
-
6
- module Ariadne
7
- # :nodoc:
8
- class Classify
9
- FLEX_VALUES = [1, :auto].freeze
10
-
11
- FLEX_WRAP_MAPPINGS = {
12
- wrap: "flex-wrap",
13
- nowrap: "flex-nowrap",
14
- reverse: "flex-wrap-reverse",
15
- }.freeze
16
-
17
- FLEX_ALIGN_SELF_VALUES = [:auto, :start, :end, :center, :baseline, :stretch].freeze
18
-
19
- FLEX_DIRECTION_VALUES = [:column, :column_reverse, :row, :row_reverse].freeze
20
-
21
- FLEX_JUSTIFY_CONTENT_VALUES = [:flex_start, :flex_end, :center, :space_between, :space_around].freeze
22
-
23
- FLEX_ALIGN_ITEMS_VALUES = [:flex_start, :flex_end, :center, :baseline, :stretch].freeze
24
-
25
- LOOKUP = Ariadne::Classify::Utilities::UTILITIES
26
-
27
- class << self
28
- # Utility for mapping component configuration into Tailwind CSS class names.
29
- #
30
- # args can contain utility keys that mimic the interface used by
31
- # Ariadne components, as well as the special entries :classes
32
- # and :style.
33
- #
34
- # Returns a hash containing two entries. The :classes entry is a string of
35
- # Tailwind CSS class names, including any classes given in the :classes entry
36
- # in args. The :style entry is the value of the given :style entry given in
37
- # args.
38
- #
39
- #
40
- # Example usage:
41
- # extract_css_attrs({ mt: 4, py: 2 }) => { classes: "mt-4 py-2", style: nil }
42
- # extract_css_attrs(classes: "d-flex", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: nil }
43
- # extract_css_attrs(classes: "d-flex", style: "float: left", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: "float: left" }
44
- #
45
- def call(args)
46
- style = nil
47
- args = [] if args.blank?
48
-
49
- classes = [].tap do |result|
50
- args.each do |key, val|
51
- case key
52
- when :classes
53
- # insert :classes first to avoid huge doc diffs
54
- if (class_names = validated_class_names(val))
55
- result.unshift(class_names)
56
- end
57
- next
58
- when :style
59
- style = val
60
- next
61
- end
62
-
63
- next unless LOOKUP[key]
64
-
65
- if val.is_a?(Array)
66
- # A while loop is ~3.5x faster than Array#each.
67
- brk = 0
68
- while brk < val.size
69
- item = val[brk]
70
-
71
- if item.nil?
72
- brk += 1
73
- next
74
- end
75
-
76
- # Believe it or not, three calls to Hash#[] and an inline rescue
77
- # are about 30% faster than Hash#dig. It also ensures validate is
78
- # only called when necessary, i.e. when the class can't be found
79
- # in the lookup table.
80
- # rubocop:disable Style/RescueModifier
81
- found = (LOOKUP[key][item][brk] rescue nil) || validate(key, item, brk)
82
- # rubocop:enable Style/RescueModifier
83
- result << found if found
84
- brk += 1
85
- end
86
- else
87
- next if val.nil?
88
-
89
- # rubocop:disable Style/RescueModifier
90
- found = (LOOKUP[key][val][0] rescue nil) || validate(key, val, 0)
91
- # rubocop:enable Style/RescueModifier
92
- result << found if found
93
- end
94
- end
95
- end.join(" ")
96
-
97
- result = {}
98
-
99
- result[:class] = classes if classes.present?
100
- result[:style] = style if style.present?
101
-
102
- result
103
- end
104
-
105
- private def validate(key, val, brk)
106
- brk_str = Ariadne::Classify::Utilities::BREAKPOINTS[brk]
107
- Ariadne::Classify::Utilities.validate(key, val, brk_str)
108
- end
109
-
110
- private def validated_class_names(classes)
111
- return if classes.blank?
112
-
113
- corrected_classes = correct_classes(classes)
114
-
115
- if raise_on_invalid_options? && !ENV["ARIADNE_WARNINGS_DISABLED"]
116
- invalid_class_names =
117
- corrected_classes.each_with_object([]) do |class_name, memo|
118
- memo << class_name if Ariadne::Classify::Validation.invalid?(class_name)
119
- end
120
-
121
- # TODO: implement this
122
- if invalid_class_names.any?
123
- # raise ArgumentError, <<~MSG
124
- # Use Tailwind CSS class names instead of your own #{"name".pluralize(invalid_class_names.length)} #{invalid_class_names.to_sentence}.
125
- # Set ARIADNE_WARNINGS_DISABLED=1 to disable this warning.
126
- # MSG
127
- end
128
- end
129
-
130
- corrected_classes.join(" ")
131
- end
132
-
133
- # TODO: automate this, ugh. peek at utilities.yml
134
- BG_PREFIX = /^bg-/.freeze
135
- BG_PSEUDO_PREFIX = /^\S+:bg-/.freeze
136
- BORDER_PREFIX = /^border-/.freeze
137
- BORDER_PSEUDO_PREFIX = /^\S+:border-/.freeze
138
- TEXT_ASPECT_PREFIX = /^text-\S+-/.freeze
139
- TEXT_ASPECT_PSEUDO_PREFIX = /^\S+:text-\S+-/.freeze
140
- TEXT_PREFIX = /^text-/.freeze
141
- TEXT_PSEUDO_PREFIX = /^\S+:text-/.freeze
142
-
143
- BORDER_STATE_PREFIX = /^border-state-/.freeze
144
- BORDER_SIDE_PREFIX = /^border-.(?:-)?/.freeze
145
-
146
- # TODO: TEST!
147
- private def correct_classes(classes)
148
- matched_bg = ""
149
- matched_bg_pseudo = {}
150
- matched_border = ""
151
- matched_border_pseudo = {}
152
- matched_text_aspect = {}
153
- matched_text_aspect_pseudo = {}
154
- matched_text = ""
155
- matched_text_pseudo = {}
156
-
157
- classes.split(" ").reverse.each_with_object([]) do |c, memo|
158
- next if c.blank?
159
-
160
- class_name = c.strip
161
-
162
- if class_name.match(BG_PREFIX)
163
- next if matched_bg.present?
164
-
165
- memo << matched_bg = class_name
166
- elsif class_name.match(BG_PSEUDO_PREFIX)
167
- next if matched_bg_pseudo.keys.any? { |m| m.start_with?(class_name.split(":").first) }
168
-
169
- matched_bg_pseudo[class_name] = true
170
- memo << class_name
171
-
172
- elsif class_name.match(BORDER_PREFIX)
173
- next if matched_border.present?
174
-
175
- if class_name.match(BORDER_STATE_PREFIX) || class_name.match(BORDER_SIDE_PREFIX)
176
- memo << class_name
177
- next
178
- end
179
-
180
- memo << matched_border = class_name
181
- elsif class_name.match(BORDER_PSEUDO_PREFIX)
182
- next if matched_border_pseudo.keys.any? { |m| m.start_with?(class_name.split(":").first) }
183
-
184
- matched_border_pseudo[class_name] = true
185
- memo << class_name
186
-
187
- elsif class_name.match(TEXT_ASPECT_PREFIX)
188
- next if matched_text_aspect.keys.any? { |m| m.start_with?(class_name.split(":").first) }
189
-
190
- matched_text_aspect[class_name] = true
191
- memo << class_name
192
- elsif class_name.match(TEXT_ASPECT_PSEUDO_PREFIX)
193
- next if matched_text_aspect_pseudo.keys.any? { |m| m.start_with?(class_name.split(":").first) }
194
-
195
- matched_text_aspect_pseudo[class_name] = true
196
- memo << class_name
197
-
198
- elsif class_name.match(TEXT_PREFIX)
199
- next if matched_text.present?
200
-
201
- memo << matched_text = class_name
202
- elsif class_name.match(TEXT_PSEUDO_PREFIX)
203
- next if matched_text_pseudo.keys.any? { |m| m.start_with?(class_name.split(":").first) }
204
-
205
- matched_text_pseudo[class_name] = true
206
- memo << class_name
207
- else
208
- memo << class_name
209
- end
210
- end.uniq.reverse
211
- end
212
-
213
- private def raise_on_invalid_options?
214
- Rails.application.config.ariadne_view_components.raise_on_invalid_options
215
- end
216
- end
217
- end
218
- 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
- ":m"
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: :m" if size_attributes.values.any?(":m")
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