ariadne_view_components 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +68 -0
  4. data/app/assets/javascripts/ariadne_view_components.js +2 -0
  5. data/app/assets/javascripts/ariadne_view_components.js.map +1 -0
  6. data/app/assets/stylesheets/application.tailwind.css +3 -0
  7. data/app/components/ariadne/ariadne.ts +14 -0
  8. data/app/components/ariadne/base_button.rb +60 -0
  9. data/app/components/ariadne/base_component.rb +155 -0
  10. data/app/components/ariadne/button_component.html.erb +4 -0
  11. data/app/components/ariadne/button_component.rb +158 -0
  12. data/app/components/ariadne/clipboard_copy_component.html.erb +8 -0
  13. data/app/components/ariadne/clipboard_copy_component.rb +50 -0
  14. data/app/components/ariadne/clipboard_copy_component.ts +19 -0
  15. data/app/components/ariadne/component.rb +123 -0
  16. data/app/components/ariadne/content.rb +12 -0
  17. data/app/components/ariadne/counter_component.rb +100 -0
  18. data/app/components/ariadne/flash_component.html.erb +31 -0
  19. data/app/components/ariadne/flash_component.rb +125 -0
  20. data/app/components/ariadne/heading_component.rb +49 -0
  21. data/app/components/ariadne/heroicon_component.html.erb +7 -0
  22. data/app/components/ariadne/heroicon_component.rb +116 -0
  23. data/app/components/ariadne/image_component.rb +51 -0
  24. data/app/components/ariadne/text.rb +25 -0
  25. data/app/components/ariadne/tooltip_component.rb +105 -0
  26. data/app/lib/ariadne/audited/dsl.rb +32 -0
  27. data/app/lib/ariadne/class_name_helper.rb +22 -0
  28. data/app/lib/ariadne/fetch_or_fallback_helper.rb +100 -0
  29. data/app/lib/ariadne/icon_helper.rb +47 -0
  30. data/app/lib/ariadne/join_style_arguments_helper.rb +14 -0
  31. data/app/lib/ariadne/logger_helper.rb +23 -0
  32. data/app/lib/ariadne/status/dsl.rb +41 -0
  33. data/app/lib/ariadne/tab_nav_helper.rb +35 -0
  34. data/app/lib/ariadne/tabbed_component_helper.rb +39 -0
  35. data/app/lib/ariadne/test_selector_helper.rb +20 -0
  36. data/app/lib/ariadne/underline_nav_helper.rb +44 -0
  37. data/app/lib/ariadne/view_helper.rb +22 -0
  38. data/lib/ariadne/classify/utilities.rb +199 -0
  39. data/lib/ariadne/classify/utilities.yml +1817 -0
  40. data/lib/ariadne/classify/validation.rb +18 -0
  41. data/lib/ariadne/classify.rb +210 -0
  42. data/lib/ariadne/view_components/constants.rb +53 -0
  43. data/lib/ariadne/view_components/engine.rb +30 -0
  44. data/lib/ariadne/view_components/linters.rb +3 -0
  45. data/lib/ariadne/view_components/statuses.rb +14 -0
  46. data/lib/ariadne/view_components/version.rb +7 -0
  47. data/lib/ariadne/view_components.rb +59 -0
  48. data/lib/rubocop/config/default.yml +14 -0
  49. data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +252 -0
  50. data/lib/rubocop/cop/ariadne/base_cop.rb +26 -0
  51. data/lib/rubocop/cop/ariadne/component_name_migration.rb +35 -0
  52. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +43 -0
  53. data/lib/rubocop/cop/ariadne/system_argument_instead_of_class.rb +57 -0
  54. data/lib/rubocop/cop/ariadne.rb +3 -0
  55. data/lib/tasks/ariadne_view_components.rake +47 -0
  56. data/lib/tasks/coverage.rake +19 -0
  57. data/lib/tasks/custom_utilities.yml +310 -0
  58. data/lib/tasks/docs.rake +525 -0
  59. data/lib/tasks/helpers/ast_processor.rb +44 -0
  60. data/lib/tasks/helpers/ast_traverser.rb +77 -0
  61. data/lib/tasks/static.rake +15 -0
  62. data/lib/tasks/tailwind.rake +31 -0
  63. data/lib/tasks/utilities.rake +121 -0
  64. data/lib/yard/docs_helper.rb +83 -0
  65. data/lib/yard/renders_many_handler.rb +19 -0
  66. data/lib/yard/renders_one_handler.rb +19 -0
  67. data/static/arguments.yml +251 -0
  68. data/static/assets/view-components.svg +18 -0
  69. data/static/audited_at.json +14 -0
  70. data/static/classes.yml +89 -0
  71. data/static/constants.json +243 -0
  72. data/static/statuses.json +14 -0
  73. data/static/tailwindcss.yml +727 -0
  74. metadata +193 -0
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,43 @@
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 tags are not set with ||=
10
+ #
11
+ # bad
12
+ # @attributes[:tag] ||= :h1
13
+ #
14
+ # good
15
+ # @attributes[:tag] = fetch_or_raise(TAG_OPTIONS, tag)
16
+ #
17
+ # good
18
+ # @attributes[:tag] = :h2
19
+ class NoTagMemoize < RuboCop::Cop::Cop
20
+ INVALID_MESSAGE = <<~STR
21
+ Avoid `[:tag] ||=`. Instead, try one of the following:
22
+ - Don't allow consumers to update the tag by having a fixed tag (e.g. `attributes[:tag] = :div`)
23
+ - Use the `fetch_or_raise` helper to only allow a tag from a restricted list.
24
+ STR
25
+
26
+ def_node_search :tag_memoized?, <<~PATTERN
27
+ (or-asgn
28
+ (send
29
+ _
30
+ _
31
+ (sym :tag)
32
+ )
33
+ _
34
+ )
35
+ PATTERN
36
+
37
+ def on_or_asgn(node)
38
+ add_offense(node, message: INVALID_MESSAGE) if tag_memoized?(node)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
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
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(__dir__, "ariadne", "*.rb")].sort.each { |file| require file }
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ ERB_GLOB = "**/*.html{+*,}.erb"
4
+ RB_GLOB = "**/*.rb"
5
+ BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/.freeze # copied from Rails: action_view/template/handlers/erb/erubi.rb
6
+
7
+ namespace :ariadne_view_components do
8
+ desc "Report arguments used in each component"
9
+ task :report, [:paths] do |_, args|
10
+ require "rubocop"
11
+ require "better_html"
12
+ require "better_html/parser"
13
+ require "erb_lint/processed_source"
14
+ require_relative "helpers/ast_processor"
15
+
16
+ paths = args[:paths].split
17
+ stats = {}
18
+
19
+ rb_files = paths.reduce([]) { |mem, path| mem + Dir[File.join(path, RB_GLOB)] }
20
+
21
+ rb_files.each do |f|
22
+ ast = RuboCop::AST::ProcessedSource.from_file(f, RUBY_VERSION.to_f).ast
23
+ AstProcessor.process_ast(ast, stats)
24
+ end
25
+
26
+ erb_files = paths.reduce([]) { |mem, path| mem + Dir[File.join(path, ERB_GLOB)] }
27
+
28
+ erb_files.each do |f|
29
+ erb_ast = ERBLint::ProcessedSource.new(f, File.read(f)).ast
30
+
31
+ erb_ast.descendants(:erb).each do |erb_node|
32
+ indicator, _, code_node, = *erb_node
33
+
34
+ next if indicator&.children&.first == "#" # don't analyze comments
35
+
36
+ trimmed_source = code_node.loc.source.sub(BLOCK_EXPR, "").strip
37
+ ast = RuboCop::AST::ProcessedSource.new(trimmed_source, RUBY_VERSION.to_f).ast
38
+ AstProcessor.process_ast(ast, stats)
39
+ end
40
+ end
41
+
42
+ File.open(".ariadne-view-components-report.json", "w") do |f|
43
+ f.write(JSON.pretty_generate(stats))
44
+ f.write($INPUT_RECORD_SEPARATOR)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :coverage do
4
+ desc "Run coverage report. This should ideally be done only on CI."
5
+ task :report do
6
+ require "simplecov"
7
+ require "simplecov-console"
8
+
9
+ SimpleCov.minimum_coverage(100)
10
+
11
+ SimpleCov.collate(Dir["simplecov-resultset-*/.resultset.json"], "rails") do
12
+ formatter SimpleCov::Formatter::Console
13
+
14
+ add_group "Ignored Code" do |src_file|
15
+ File.readlines(src_file.filename).grep(/:nocov:/).any?
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,310 @@
1
+ :font_size:
2
+ "00":
3
+ - f00
4
+ 1:
5
+ - f1
6
+ 2:
7
+ - f2
8
+ 3:
9
+ - f3
10
+ 4:
11
+ - f4
12
+ 5:
13
+ - f5
14
+ 6:
15
+ - f6
16
+ :small:
17
+ - text-small
18
+ :normal:
19
+ - text-normal
20
+ :top:
21
+ 0:
22
+ - top-0
23
+ false:
24
+ - top-0
25
+ :bottom:
26
+ 0:
27
+ - bottom-0
28
+ false:
29
+ - bottom-0
30
+ :left:
31
+ 0:
32
+ - left-0
33
+ false:
34
+ - left-0
35
+ :right:
36
+ 0:
37
+ - right-0
38
+ false:
39
+ - right-0
40
+ :underline:
41
+ true:
42
+ - text-underline
43
+ false:
44
+ - no-underline
45
+ :font_family:
46
+ :mono:
47
+ - text-mono
48
+ :font_style:
49
+ :italic:
50
+ - text-italic
51
+ :text_transform:
52
+ :uppercase:
53
+ - text-uppercase
54
+ :text_align:
55
+ :right:
56
+ - text-right
57
+ - text-sm-right
58
+ - text-md-right
59
+ - text-lg-right
60
+ - text-xl-right
61
+ :left:
62
+ - text-left
63
+ - text-sm-left
64
+ - text-md-left
65
+ - text-lg-left
66
+ - text-xl-left
67
+ :center:
68
+ - text-center
69
+ - text-sm-center
70
+ - text-md-center
71
+ - text-lg-center
72
+ - text-xl-center
73
+ :font_weight:
74
+ :light:
75
+ - text-light
76
+ :normal:
77
+ - text-normal
78
+ :bold:
79
+ - text-bold
80
+ :semibold:
81
+ - text-semibold
82
+ :emphasized:
83
+ - text-emphasized
84
+ :box_shadow:
85
+ true:
86
+ - color-shadow-small
87
+ :small:
88
+ - color-shadow-small
89
+ :medium:
90
+ - color-shadow-medium
91
+ :large:
92
+ - color-shadow-large
93
+ :extra_large:
94
+ - color-shadow-extra-large
95
+ :none:
96
+ - box-shadow-none
97
+ false:
98
+ - box-shadow-none
99
+ :border:
100
+ :left:
101
+ - border-left
102
+ :top:
103
+ - border-top
104
+ :bottom:
105
+ - border-bottom
106
+ :right:
107
+ - border-right
108
+ :y:
109
+ - border-y
110
+ :x:
111
+ - border-x
112
+ true:
113
+ - border
114
+ 0:
115
+ - border-0
116
+ false:
117
+ - border-0
118
+ :dashed:
119
+ - border-dashed
120
+ :border_top:
121
+ 0:
122
+ - border-top-0
123
+ :border_bottom:
124
+ 0:
125
+ - border-bottom-0
126
+ :border_left:
127
+ 0:
128
+ - border-left-0
129
+ :border_right:
130
+ 0:
131
+ - border-right-0
132
+ :border_radius:
133
+ 0:
134
+ - rounded-0
135
+ 1:
136
+ - rounded-1
137
+ 2:
138
+ - rounded-2
139
+ 3:
140
+ - rounded-3
141
+ :justify_content:
142
+ :flex_start:
143
+ - flex-justify-start
144
+ - flex-sm-justify-start
145
+ - flex-md-justify-start
146
+ - flex-lg-justify-start
147
+ - flex-xl-justify-start
148
+ :flex_end:
149
+ - flex-justify-end
150
+ - flex-sm-justify-end
151
+ - flex-md-justify-end
152
+ - flex-lg-justify-end
153
+ - flex-xl-justify-end
154
+ :center:
155
+ - flex-justify-center
156
+ - flex-sm-justify-center
157
+ - flex-md-justify-center
158
+ - flex-lg-justify-center
159
+ - flex-xl-justify-center
160
+ :space_between:
161
+ - flex-justify-between
162
+ - flex-sm-justify-between
163
+ - flex-md-justify-between
164
+ - flex-lg-justify-between
165
+ - flex-xl-justify-between
166
+ :space_around:
167
+ - flex-justify-around
168
+ - flex-sm-justify-around
169
+ - flex-md-justify-around
170
+ - flex-lg-justify-around
171
+ - flex-xl-justify-around
172
+ :align_items:
173
+ :flex_start:
174
+ - flex-items-start
175
+ - flex-sm-items-start
176
+ - flex-md-items-start
177
+ - flex-lg-items-start
178
+ - flex-xl-items-start
179
+ :flex_end:
180
+ - flex-items-end
181
+ - flex-sm-items-end
182
+ - flex-md-items-end
183
+ - flex-lg-items-end
184
+ - flex-xl-items-end
185
+ :center:
186
+ - flex-items-center
187
+ - flex-sm-items-center
188
+ - flex-md-items-center
189
+ - flex-lg-items-center
190
+ - flex-xl-items-center
191
+ :baseline:
192
+ - flex-items-baseline
193
+ - flex-sm-items-baseline
194
+ - flex-md-items-baseline
195
+ - flex-lg-items-baseline
196
+ - flex-xl-items-baseline
197
+ :stretch:
198
+ - flex-items-stretch
199
+ - flex-sm-items-stretch
200
+ - flex-md-items-stretch
201
+ - flex-lg-items-stretch
202
+ - flex-xl-items-stretch
203
+ :flex_wrap:
204
+ :wrap:
205
+ - flex-wrap
206
+ - flex-sm-wrap
207
+ - flex-md-wrap
208
+ - flex-lg-wrap
209
+ - flex-xl-wrap
210
+ :nowrap:
211
+ - flex-nowrap
212
+ - flex-sm-nowrap
213
+ - flex-md-nowrap
214
+ - flex-lg-nowrap
215
+ - flex-xl-nowrap
216
+ :reverse:
217
+ - flex-wrap-reverse
218
+ - flex-sm-wrap-reverse
219
+ - flex-md-wrap-reverse
220
+ - flex-lg-wrap-reverse
221
+ - flex-xl-wrap-reverse
222
+ :direction:
223
+ :column:
224
+ - flex-column
225
+ - flex-sm-column
226
+ - flex-md-column
227
+ - flex-lg-column
228
+ - flex-xl-column
229
+ :column_reverse:
230
+ - flex-column-reverse
231
+ - flex-sm-column-reverse
232
+ - flex-md-column-reverse
233
+ - flex-lg-column-reverse
234
+ - flex-xl-column-reverse
235
+ :row:
236
+ - flex-row
237
+ - flex-sm-row
238
+ - flex-md-row
239
+ - flex-lg-row
240
+ - flex-xl-row
241
+ :row_reverse:
242
+ - flex-row-reverse
243
+ - flex-sm-row-reverse
244
+ - flex-md-row-reverse
245
+ - flex-lg-row-reverse
246
+ - flex-xl-row-reverse
247
+ :flex:
248
+ 1:
249
+ - flex-1
250
+ - flex-sm-1
251
+ - flex-md-1
252
+ - flex-lg-1
253
+ - flex-xl-1
254
+ :auto:
255
+ - flex-auto
256
+ - flex-sm-auto
257
+ - flex-md-auto
258
+ - flex-lg-auto
259
+ - flex-xl-auto
260
+ :align_self:
261
+ :auto:
262
+ - flex-self-auto
263
+ - flex-sm-self-auto
264
+ - flex-md-self-auto
265
+ - flex-lg-self-auto
266
+ - flex-xl-self-auto
267
+ :start:
268
+ - flex-self-start
269
+ - flex-sm-self-start
270
+ - flex-md-self-start
271
+ - flex-lg-self-start
272
+ - flex-xl-self-start
273
+ :end:
274
+ - flex-self-end
275
+ - flex-sm-self-end
276
+ - flex-md-self-end
277
+ - flex-lg-self-end
278
+ - flex-xl-self-end
279
+ :center:
280
+ - flex-self-center
281
+ - flex-sm-self-center
282
+ - flex-md-self-center
283
+ - flex-lg-self-center
284
+ - flex-xl-self-center
285
+ :baseline:
286
+ - flex-self-baseline
287
+ - flex-sm-self-baseline
288
+ - flex-md-self-baseline
289
+ - flex-lg-self-baseline
290
+ - flex-xl-self-baseline
291
+ :stretch:
292
+ - flex-self-stretch
293
+ - flex-sm-self-stretch
294
+ - flex-md-self-stretch
295
+ - flex-lg-self-stretch
296
+ - flex-xl-self-stretch
297
+ :flex_grow:
298
+ 0:
299
+ - flex-grow-0
300
+ - flex-sm-grow-0
301
+ - flex-md-grow-0
302
+ - flex-lg-grow-0
303
+ - flex-xl-grow-0
304
+ :flex_shrink:
305
+ 0:
306
+ - flex-shrink-0
307
+ - flex-sm-shrink-0
308
+ - flex-md-shrink-0
309
+ - flex-lg-shrink-0
310
+ - flex-xl-shrink-0