primer_view_components 0.0.45 → 0.0.49

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +194 -0
  3. data/app/components/primer/{auto_complete_component.d.ts → auto_complete/auto_component.d.ts} +0 -0
  4. data/app/components/primer/{auto_complete_component.js → auto_complete/auto_component.js} +0 -0
  5. data/app/components/primer/base_component.rb +36 -7
  6. data/app/components/primer/beta/auto_complete.rb +159 -0
  7. data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
  8. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +0 -0
  9. data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
  10. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
  11. data/app/components/primer/beta/auto_complete/item.rb +44 -0
  12. data/app/components/primer/beta/avatar.rb +77 -0
  13. data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
  14. data/app/components/primer/beta/avatar_stack.rb +92 -0
  15. data/app/components/primer/border_box_component.rb +3 -0
  16. data/app/components/primer/component.rb +9 -1
  17. data/app/components/primer/details_component.rb +12 -8
  18. data/app/components/primer/image_crop.html.erb +4 -4
  19. data/app/components/primer/image_crop.rb +1 -1
  20. data/app/components/primer/markdown.rb +9 -9
  21. data/app/components/primer/menu_component.rb +7 -3
  22. data/app/components/primer/navigation/tab_component.rb +34 -6
  23. data/app/components/primer/popover_component.rb +6 -3
  24. data/app/components/primer/primer.d.ts +1 -1
  25. data/app/components/primer/primer.js +1 -1
  26. data/app/components/primer/primer.ts +1 -1
  27. data/app/components/primer/tab_nav_component.rb +9 -6
  28. data/app/components/primer/timeline_item_component.rb +2 -2
  29. data/app/components/primer/tooltip.rb +1 -1
  30. data/app/components/primer/truncate.rb +6 -1
  31. data/app/components/primer/underline_nav_component.rb +13 -6
  32. data/{app/lib → lib}/primer/classify.rb +12 -39
  33. data/{app/lib → lib}/primer/classify/cache.rb +6 -20
  34. data/{app/lib → lib}/primer/classify/flex.rb +0 -0
  35. data/{app/lib → lib}/primer/classify/functional_background_colors.rb +2 -0
  36. data/{app/lib → lib}/primer/classify/functional_border_colors.rb +2 -0
  37. data/{app/lib → lib}/primer/classify/functional_colors.rb +0 -0
  38. data/{app/lib → lib}/primer/classify/functional_text_colors.rb +2 -0
  39. data/{app/lib → lib}/primer/classify/grid.rb +0 -0
  40. data/{app/lib → lib}/primer/classify/utilities.rb +54 -22
  41. data/{app/lib → lib}/primer/classify/utilities.yml +124 -0
  42. data/lib/primer/view_components.rb +35 -6
  43. data/lib/primer/view_components/constants.rb +55 -0
  44. data/lib/primer/view_components/linters/argument_mappers/base.rb +39 -0
  45. data/lib/primer/view_components/linters/argument_mappers/button.rb +35 -44
  46. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +25 -0
  47. data/lib/primer/view_components/linters/argument_mappers/label.rb +56 -0
  48. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +1 -2
  49. data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
  50. data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
  51. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
  52. data/lib/primer/view_components/linters/helpers.rb +56 -38
  53. data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
  54. data/lib/primer/view_components/statuses.rb +14 -0
  55. data/lib/primer/view_components/version.rb +1 -1
  56. data/lib/rubocop/config/default.yml +12 -0
  57. data/lib/rubocop/cop/primer.rb +4 -0
  58. data/lib/rubocop/cop/primer/no_tag_memoize.rb +42 -0
  59. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +75 -0
  60. data/lib/tasks/constants.rake +12 -0
  61. data/lib/tasks/docs.rake +89 -34
  62. data/lib/tasks/utilities.rake +9 -11
  63. data/lib/yard/docs_helper.rb +12 -3
  64. data/static/arguments.yml +977 -0
  65. data/static/assets/view-components.svg +18 -0
  66. data/static/classes.yml +174 -0
  67. data/static/constants.json +628 -0
  68. data/static/statuses.json +5 -5
  69. metadata +44 -27
  70. data/app/components/primer/auto_complete.rb +0 -156
  71. data/app/components/primer/auto_complete/item.rb +0 -42
  72. data/app/components/primer/avatar_component.rb +0 -75
  73. data/app/components/primer/avatar_stack_component.rb +0 -84
  74. data/app/components/primer/details_menu_component.d.ts +0 -1
  75. data/app/components/primer/details_menu_component.js +0 -1
@@ -1,4 +1,71 @@
1
1
  ---
2
+ :animation:
3
+ :fade_in:
4
+ - anim-fade-in
5
+ :fade_out:
6
+ - anim-fade-out
7
+ :fade_up:
8
+ - anim-fade-up
9
+ :fade_down:
10
+ - anim-fade-down
11
+ :grow_x:
12
+ - anim-grow-x
13
+ :shrink_x:
14
+ - anim-shrink-x
15
+ :scale_in:
16
+ - anim-scale-in
17
+ :pulse:
18
+ - anim-pulse
19
+ :pulse_in:
20
+ - anim-pulse-in
21
+ :hover_grow:
22
+ - anim-hover-grow
23
+ :rotate:
24
+ - anim-rotate
25
+ :position:
26
+ :static:
27
+ - position-static
28
+ - position-sm-static
29
+ - position-md-static
30
+ - position-lg-static
31
+ - position-xl-static
32
+ :relative:
33
+ - position-relative
34
+ - position-sm-relative
35
+ - position-md-relative
36
+ - position-lg-relative
37
+ - position-xl-relative
38
+ :absolute:
39
+ - position-absolute
40
+ - position-sm-absolute
41
+ - position-md-absolute
42
+ - position-lg-absolute
43
+ - position-xl-absolute
44
+ :fixed:
45
+ - position-fixed
46
+ - position-sm-fixed
47
+ - position-md-fixed
48
+ - position-lg-fixed
49
+ - position-xl-fixed
50
+ :sticky:
51
+ - position-sticky
52
+ - position-sm-sticky
53
+ - position-md-sticky
54
+ - position-lg-sticky
55
+ - position-xl-sticky
56
+ :vertical_align:
57
+ :middle:
58
+ - v-align-middle
59
+ :top:
60
+ - v-align-top
61
+ :bottom:
62
+ - v-align-bottom
63
+ :text_top:
64
+ - v-align-text-top
65
+ :text_bottom:
66
+ - v-align-text-bottom
67
+ :baseline:
68
+ - v-align-baseline
2
69
  :float:
3
70
  :left:
4
71
  - float-left
@@ -1136,6 +1203,63 @@
1136
1203
  - py-md-12
1137
1204
  - py-lg-12
1138
1205
  - py-xl-12
1206
+ :word_break:
1207
+ :break_all:
1208
+ - wb-break-all
1209
+ :display:
1210
+ :block:
1211
+ - d-block
1212
+ - d-sm-block
1213
+ - d-md-block
1214
+ - d-lg-block
1215
+ - d-xl-block
1216
+ :flex:
1217
+ - d-flex
1218
+ - d-sm-flex
1219
+ - d-md-flex
1220
+ - d-lg-flex
1221
+ - d-xl-flex
1222
+ :inline:
1223
+ - d-inline
1224
+ - d-sm-inline
1225
+ - d-md-inline
1226
+ - d-lg-inline
1227
+ - d-xl-inline
1228
+ :inline_block:
1229
+ - d-inline-block
1230
+ - d-sm-inline-block
1231
+ - d-md-inline-block
1232
+ - d-lg-inline-block
1233
+ - d-xl-inline-block
1234
+ :inline_flex:
1235
+ - d-inline-flex
1236
+ - d-sm-inline-flex
1237
+ - d-md-inline-flex
1238
+ - d-lg-inline-flex
1239
+ - d-xl-inline-flex
1240
+ :none:
1241
+ - d-none
1242
+ - d-sm-none
1243
+ - d-md-none
1244
+ - d-lg-none
1245
+ - d-xl-none
1246
+ :table:
1247
+ - d-table
1248
+ - d-sm-table
1249
+ - d-md-table
1250
+ - d-lg-table
1251
+ - d-xl-table
1252
+ :table_cell:
1253
+ - d-table-cell
1254
+ - d-sm-table-cell
1255
+ - d-md-table-cell
1256
+ - d-lg-table-cell
1257
+ - d-xl-table-cell
1258
+ :visibility:
1259
+ :hidden:
1260
+ - v-hidden
1261
+ :visible:
1262
+ - v-visible
1139
1263
  :hide:
1140
1264
  :sm:
1141
1265
  - hide-sm
@@ -1,27 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "primer/classify"
3
4
  require "primer/view_components/version"
4
5
  require "primer/view_components/engine"
5
6
 
6
7
  module Primer
7
8
  # :nodoc:
8
9
  module ViewComponents
9
- DEFAULT_STATUSES_PATH = File.expand_path("static")
10
+ DEFAULT_STATIC_PATH = File.expand_path("static")
10
11
  DEFAULT_STATUS_FILE_NAME = "statuses.json"
12
+ DEFAULT_CONSTANTS_FILE_NAME = "constants.json"
11
13
 
12
14
  # generate_statuses returns a hash mapping component name to
13
15
  # the component's status sorted alphabetically by the component name.
14
16
  def self.generate_statuses
15
- statuses = Primer::Component.descendants.each_with_object({}) do |component, mem|
17
+ Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
16
18
  mem[component.to_s] = component.status.to_s
17
19
  end
18
-
19
- statuses.sort_by { |k, _v| k }.to_h
20
20
  end
21
21
 
22
22
  # dump_statuses generates the status hash and then serializes
23
23
  # it as json at the given path
24
- def self.dump_statuses(path: DEFAULT_STATUSES_PATH)
24
+ def self.dump_statuses(path: DEFAULT_STATIC_PATH)
25
25
  require "json"
26
26
 
27
27
  statuses = generate_statuses
@@ -34,8 +34,37 @@ module Primer
34
34
 
35
35
  # read_statuses returns a JSON string matching the output of
36
36
  # generate_statuses
37
- def self.read_statuses(path: DEFAULT_STATUSES_PATH)
37
+ def self.read_statuses(path: DEFAULT_STATIC_PATH)
38
38
  File.read(File.join(path, DEFAULT_STATUS_FILE_NAME))
39
39
  end
40
+
41
+ # generate_constants returns a hash mapping component name to
42
+ # all of its constants.
43
+ def self.generate_constants
44
+ Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
45
+ mem[component.to_s] = component.constants(false).sort.each_with_object({}) do |constant, h|
46
+ h[constant] = component.const_get(constant)
47
+ end
48
+ end
49
+ end
50
+
51
+ # dump_constants generates the constants hash and then serializes
52
+ # it as json at the given path
53
+ def self.dump_constants(path: DEFAULT_STATIC_PATH)
54
+ require "json"
55
+
56
+ constants = generate_constants
57
+
58
+ File.open(File.join(path, DEFAULT_CONSTANTS_FILE_NAME), "w") do |f|
59
+ f.write(JSON.pretty_generate(constants))
60
+ f.write($INPUT_RECORD_SEPARATOR)
61
+ end
62
+ end
63
+
64
+ # read_constants returns a JSON string matching the output of
65
+ # generate_constants
66
+ def self.read_constants(path: DEFAULT_STATIC_PATH)
67
+ File.read(File.join(path, DEFAULT_CONSTANTS_FILE_NAME))
68
+ end
40
69
  end
41
70
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Primer
6
+ module ViewComponents
7
+ # A module for constants that are used in the view components.
8
+ class Constants
9
+ CONSTANTS = JSON.parse(
10
+ File.read(
11
+ File.join(File.dirname(__FILE__), "../../../static/constants.json")
12
+ )
13
+ ).freeze
14
+
15
+ class << self
16
+ def get(component:, constant:, invert: true, symbolize: false)
17
+ values = CONSTANTS.dig(component, constant)
18
+
19
+ case values
20
+ when Hash
21
+ format_hash(values, invert, symbolize)
22
+ when Array
23
+ format_array(values, symbolize)
24
+ else
25
+ values
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def format_hash(values, invert, symbolize)
32
+ val = values.invert if invert
33
+ # remove defaults
34
+ val = val.except("", nil)
35
+
36
+ return val.transform_values { |v| symbolize_value(v) } if symbolize
37
+
38
+ val
39
+ end
40
+
41
+ def format_array(values, symbolize)
42
+ val = values.select(&:present?)
43
+
44
+ return val.map { |v| symbolize_value(v) } if symbolize
45
+
46
+ val
47
+ end
48
+
49
+ def symbolize_value(value)
50
+ ":#{value}"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "conversion_error"
4
+ require_relative "system_arguments"
5
+ require "primer/view_components/constants"
6
+
7
+ module ERBLint
8
+ module Linters
9
+ module ArgumentMappers
10
+ # Provides the base interface to implement an `ArgumentMapper`.
11
+ # Override attribute_to_args in a child class to customize its mapping behavior.
12
+ class Base
13
+ DEFAULT_TAG = nil
14
+
15
+ def initialize(tag)
16
+ @tag = tag
17
+ end
18
+
19
+ def to_s
20
+ to_args.map { |k, v| "#{k}: #{v}" }.join(", ")
21
+ end
22
+
23
+ def to_args
24
+ args = {}
25
+
26
+ args[:tag] = ":#{@tag.name}" unless self.class::DEFAULT_TAG.nil? || @tag.name == self.class::DEFAULT_TAG
27
+
28
+ @tag.attributes.each do |attribute|
29
+ args.merge!(attribute_to_args(attribute))
30
+ end
31
+
32
+ args
33
+ end
34
+
35
+ def attribute_to_args(attribute); end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,62 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "conversion_error"
4
- require_relative "system_arguments"
3
+ require_relative "base"
5
4
 
6
5
  module ERBLint
7
6
  module Linters
8
7
  module ArgumentMappers
9
8
  # Maps classes in a button element to arguments for the Button component.
10
- class Button
11
- SCHEME_MAPPINGS = {
12
- "btn-primary" => ":primary",
13
- "btn-danger" => ":danger",
14
- "btn-outline" => ":outline",
15
- "btn-invisible" => ":invisible",
16
- "btn-link" => ":link"
17
- }.freeze
9
+ class Button < Base
10
+ require "pry"
18
11
 
19
- VARIANT_MAPPINGS = {
20
- "btn-sm" => ":small",
21
- "btn-large" => ":large"
22
- }.freeze
12
+ SCHEME_MAPPINGS = Primer::ViewComponents::Constants.get(
13
+ component: "Primer::ButtonComponent",
14
+ constant: "SCHEME_MAPPINGS",
15
+ symbolize: true
16
+ ).freeze
23
17
 
24
- TYPE_OPTIONS = %w[button reset submit].freeze
18
+ VARIANT_MAPPINGS = Primer::ViewComponents::Constants.get(
19
+ component: "Primer::ButtonComponent",
20
+ constant: "VARIANT_MAPPINGS",
21
+ symbolize: true
22
+ ).freeze
25
23
 
26
- def initialize(tag)
27
- @tag = tag
28
- end
29
-
30
- def to_s
31
- to_args.map { |k, v| "#{k}: #{v}" }.join(", ")
32
- end
33
-
34
- def to_args
35
- args = {}
24
+ TYPE_OPTIONS = Primer::ViewComponents::Constants.get(
25
+ component: "Primer::BaseButton",
26
+ constant: "TYPE_OPTIONS"
27
+ ).freeze
28
+ DEFAULT_TAG = Primer::ViewComponents::Constants.get(
29
+ component: "Primer::BaseButton",
30
+ constant: "DEFAULT_TAG"
31
+ ).freeze
36
32
 
37
- args[:tag] = ":#{@tag.name}" unless @tag.name == "button"
33
+ def attribute_to_args(attribute)
34
+ attr_name = attribute.name
38
35
 
39
- @tag.attributes.each do |attribute|
40
- attr_name = attribute.name
36
+ if attr_name == "class"
37
+ classes_to_args(attribute)
38
+ elsif attr_name == "disabled"
39
+ { disabled: true }
40
+ elsif attr_name == "type"
41
+ # button is the default type, so we don't need to do anything.
42
+ return {} if attribute.value == "button"
41
43
 
42
- if attr_name == "class"
43
- args = args.merge(classes_to_args(attribute))
44
- elsif attr_name == "disabled"
45
- args[:disabled] = true
46
- elsif attr_name == "type"
47
- # button is the default type, so we don't need to do anything.
48
- next if attribute.value == "button"
44
+ raise ConversionError, "Button component does not support type \"#{attribute.value}\"" unless TYPE_OPTIONS.include?(attribute.value)
49
45
 
50
- raise ConversionError, "Button component does not support type \"#{attribute.value}\"" unless TYPE_OPTIONS.include?(attribute.value)
51
-
52
- args[:type] = ":#{attribute.value}"
53
- else
54
- # Assume the attribute is a system argument.
55
- args.merge!(SystemArguments.new(attribute).to_args)
56
- end
46
+ { type: ":#{attribute.value}" }
47
+ else
48
+ # Assume the attribute is a system argument.
49
+ SystemArguments.new(attribute).to_args
57
50
  end
58
-
59
- args
60
51
  end
61
52
 
62
53
  def classes_to_args(classes)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ module ArgumentMappers
8
+ # Maps attributes in the clipboard-copy element to arguments for the ClipboardCopy component.
9
+ class ClipboardCopy < Base
10
+ DEFAULT_TAG = "clipboard-copy"
11
+
12
+ def attribute_to_args(attribute)
13
+ attr_name = attribute.name
14
+
15
+ if attr_name == "value"
16
+ { value: attribute.value.to_json }
17
+ else
18
+ # Assume the attribute is a system argument.
19
+ SystemArguments.new(attribute).to_args
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ module ArgumentMappers
8
+ # Maps classes in a label element to arguments for the Label component.
9
+ class Label < Base
10
+ SCHEME_MAPPINGS = Primer::ViewComponents::Constants.get(
11
+ component: "Primer::LabelComponent",
12
+ constant: "SCHEME_MAPPINGS",
13
+ symbolize: true
14
+ ).freeze
15
+
16
+ VARIANT_MAPPINGS = Primer::ViewComponents::Constants.get(
17
+ component: "Primer::LabelComponent",
18
+ constant: "VARIANT_MAPPINGS",
19
+ symbolize: true
20
+ ).freeze
21
+
22
+ DEFAULT_TAG = Primer::ViewComponents::Constants.get(
23
+ component: "Primer::LabelComponent",
24
+ constant: "DEFAULT_TAG"
25
+ ).freeze
26
+
27
+ def attribute_to_args(attribute)
28
+ attr_name = attribute.name
29
+
30
+ if attr_name == "class"
31
+ classes_to_args(attribute)
32
+ elsif attr_name == "title"
33
+ { title: attribute.value.to_json }
34
+ else
35
+ # Assume the attribute is a system argument.
36
+ SystemArguments.new(attribute).to_args
37
+ end
38
+ end
39
+
40
+ def classes_to_args(classes)
41
+ classes.value.split(" ").each_with_object({}) do |class_name, acc|
42
+ next if class_name == "Label"
43
+
44
+ if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
45
+ acc[:scheme] = SCHEME_MAPPINGS[class_name]
46
+ elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
47
+ acc[:variant] = VARIANT_MAPPINGS[class_name]
48
+ else
49
+ raise ConversionError, "Cannot convert class \"#{class_name}\""
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end