primer_view_components 0.0.86 → 0.0.89

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/app/components/primer/alpha/text_field.rb +1 -1
  4. data/app/components/primer/alpha/tooltip.rb +1 -0
  5. data/app/components/primer/{button_group.html.erb → beta/button_group.html.erb} +0 -0
  6. data/app/components/primer/beta/button_group.rb +57 -0
  7. data/app/components/primer/blankslate_component.html.erb +25 -0
  8. data/app/components/primer/blankslate_component.rb +150 -2
  9. data/app/components/primer/box.rb +25 -0
  10. data/app/components/primer/box_component.rb +2 -20
  11. data/app/components/primer/button_group.rb +2 -50
  12. data/app/components/primer/flex_component.rb +20 -20
  13. data/app/components/primer/flex_item_component.rb +4 -4
  14. data/app/components/primer/icon_button.html.erb +8 -2
  15. data/app/components/primer/icon_button.rb +6 -0
  16. data/app/components/primer/label_component.rb +32 -10
  17. data/app/components/primer/link_component.rb +14 -0
  18. data/app/components/primer/popover_component.rb +1 -1
  19. data/app/helpers/primer/form_helper.rb +10 -0
  20. data/lib/primer/form_components.rb +2 -2
  21. data/lib/primer/forms/base.html.erb +1 -1
  22. data/lib/primer/forms/base.rb +5 -0
  23. data/lib/primer/forms/base_component.rb +4 -0
  24. data/lib/primer/forms/buffer_rewriter.rb +3 -2
  25. data/lib/primer/forms/builder.rb +48 -0
  26. data/lib/primer/forms/check_box_group.html.erb +1 -1
  27. data/lib/primer/forms/dsl/input.rb +1 -23
  28. data/lib/primer/forms/dsl/input_group.rb +0 -7
  29. data/lib/primer/forms/group.html.erb +1 -1
  30. data/lib/primer/forms/multi.html.erb +1 -1
  31. data/lib/primer/view_components/engine.rb +11 -0
  32. data/lib/primer/view_components/linters/argument_mappers/label.rb +11 -4
  33. data/lib/primer/view_components/linters/flash_migration_counter.rb +1 -1
  34. data/lib/primer/view_components/linters/helpers/deprecated_components_helpers.rb +2 -0
  35. data/lib/primer/view_components/version.rb +1 -1
  36. data/lib/rubocop/cop/primer/component_name_migration.rb +2 -0
  37. data/lib/rubocop/cop/primer/deprecated_label_variants.rb +71 -0
  38. data/lib/tasks/docs.rake +2 -2
  39. data/lib/yard/docs_helper.rb +1 -1
  40. data/static/arguments.yml +56 -48
  41. data/static/audited_at.json +2 -0
  42. data/static/classes.yml +2 -0
  43. data/static/constants.json +20 -7
  44. data/static/statuses.json +4 -2
  45. metadata +11 -6
  46. data/app/components/primer/link_component.html.erb +0 -12
@@ -79,5 +79,19 @@ module Primer
79
79
  def before_render
80
80
  raise ArgumentError, "href is required when using <a> tag" if @system_arguments[:tag] == :a && @system_arguments[:href].nil? && !Rails.env.production?
81
81
  end
82
+
83
+ def call
84
+ if tooltip.present?
85
+ render Primer::BaseComponent.new(tag: :span, position: :relative) do
86
+ render(Primer::BaseComponent.new(**@system_arguments)) do
87
+ content
88
+ end.to_s + tooltip.to_s
89
+ end
90
+ else
91
+ render(Primer::BaseComponent.new(**@system_arguments)) do
92
+ content
93
+ end
94
+ end
95
+ end
82
96
  end
83
97
  end
@@ -119,7 +119,7 @@ module Primer
119
119
  end
120
120
 
121
121
  def body_component
122
- Primer::BoxComponent.new(**@body_arguments)
122
+ Primer::Box.new(**@body_arguments)
123
123
  end
124
124
  end
125
125
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # :nodoc:
5
+ module FormHelper
6
+ def primer_form_with(**kwargs, &block)
7
+ form_with(**kwargs, skip_default_ids: false, builder: Primer::Forms::Builder, &block)
8
+ end
9
+ end
10
+ end
@@ -17,7 +17,7 @@ module Primer
17
17
  end
18
18
 
19
19
  def call
20
- builder = ActionView::Helpers::FormBuilder.new(
20
+ builder = Primer::Forms::Builder.new(
21
21
  nil, nil, __vc_original_view_context, {}
22
22
  )
23
23
 
@@ -28,7 +28,7 @@ module Primer
28
28
  &@block
29
29
  )
30
30
 
31
- input.render_in(__vc_original_view_context) { content }
31
+ input.to_component.render_in(__vc_original_view_context) { content }
32
32
  end
33
33
  end
34
34
  end
@@ -1,6 +1,6 @@
1
1
  <%= render(SpacingWrapper.new) do %>
2
2
  <% inputs.each do |input| %>
3
- <%= render(input) %>
3
+ <%= render(input.to_component) %>
4
4
  <% end %>
5
5
  <% end %>
6
6
  <% if after_content? %>
@@ -17,6 +17,11 @@ module Primer
17
17
  end
18
18
 
19
19
  def new(builder, **options)
20
+ if builder && !builder.is_a?(Primer::Forms::Builder)
21
+ raise ArgumentError, "please pass an instance of Primer::Forms::Builder when "\
22
+ "constructing a form object (consider using the `primer_form_with` helper)"
23
+ end
24
+
20
25
  allocate.tap do |form|
21
26
  form.instance_variable_set(:@builder, builder)
22
27
  form.send(:initialize, **options)
@@ -39,6 +39,10 @@ module Primer
39
39
  false
40
40
  end
41
41
 
42
+ def to_component
43
+ self
44
+ end
45
+
42
46
  private
43
47
 
44
48
  def compile_and_render_template
@@ -16,8 +16,9 @@ module Primer
16
16
  code.dup.tap do |result|
17
17
  parser.var_refs.reverse_each do |lineno, stop|
18
18
  line_offset = line_offsets[lineno]
19
- start = (stop - "@output_buffer".length) + line_offset
20
19
  stop += line_offset
20
+ stop -= 1 if stop < code.length
21
+ start = stop - "@output_buffer".length
21
22
  result[start...stop] = "output_buffer"
22
23
  end
23
24
  end
@@ -39,7 +40,7 @@ module Primer
39
40
  def on_var_ref(var)
40
41
  return unless var == "@output_buffer"
41
42
 
42
- var_refs << [lineno, column - 1]
43
+ var_refs << [lineno, column]
43
44
  end
44
45
 
45
46
  def var_refs
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "primer/classify"
4
+
5
+ module Primer
6
+ module Forms
7
+ # :nodoc:
8
+ class Builder < ActionView::Helpers::FormBuilder
9
+ include Primer::ClassNameHelper
10
+
11
+ UTILITY_KEYS = Primer::Classify::Utilities::UTILITIES.keys.freeze
12
+
13
+ def label(*args, **options, &block)
14
+ super(*args, classify(options), &block)
15
+ end
16
+
17
+ def check_box(*args, **options, &block)
18
+ super(*args, classify(options), &block)
19
+ end
20
+
21
+ def radio_button(*args, **options, &block)
22
+ super(*args, classify(options), &block)
23
+ end
24
+
25
+ def select(*args, **options, &block)
26
+ super(*args, classify(options), &block)
27
+ end
28
+
29
+ def text_field(*args, **options, &block)
30
+ super(*args, classify(options), &block)
31
+ end
32
+
33
+ def text_area(*args, **options, &block)
34
+ super(*args, classify(options), &block)
35
+ end
36
+
37
+ private
38
+
39
+ def classify(options)
40
+ options[:classes] = class_names(options.delete(:class), options[:classes])
41
+ options.merge!(Primer::Classify.call(options))
42
+ options.except!(*UTILITY_KEYS)
43
+ options[:class] = class_names(options[:class], options.delete(:classes))
44
+ options
45
+ end
46
+ end
47
+ end
48
+ end
@@ -6,7 +6,7 @@
6
6
  <% end %>
7
7
  <%= render(SpacingWrapper.new) do %>
8
8
  <% @input.check_boxes.each do |check_box| %>
9
- <%= render(check_box) %>
9
+ <%= render(check_box.to_component) %>
10
10
  <% end %>
11
11
  <% end %>
12
12
  </fieldset>
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "primer/classify"
4
-
5
3
  module Primer
6
4
  module Forms
7
5
  module Dsl
@@ -16,8 +14,6 @@ module Primer
16
14
  }.freeze
17
15
  SIZE_OPTIONS = SIZE_MAPPINGS.keys
18
16
 
19
- UTILITY_KEYS = Primer::Classify::Utilities::UTILITIES.keys.freeze
20
-
21
17
  include Primer::ClassNameHelper
22
18
 
23
19
  attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids
@@ -27,14 +23,11 @@ module Primer
27
23
  @form = form
28
24
 
29
25
  @input_arguments = system_arguments
30
- process_classes!(@input_arguments)
31
-
32
26
  @label_arguments = @input_arguments.delete(:label_arguments) || {}
33
- process_classes!(@label_arguments)
34
27
 
35
28
  @label_arguments[:class] = class_names(
36
29
  @label_arguments[:class],
37
- @input_arguments.fetch(:visually_hide_label, true) ? "sr-only" : nil
30
+ @input_arguments.fetch(:visually_hide_label, false) ? "sr-only" : nil
38
31
  )
39
32
 
40
33
  @input_arguments.delete(:visually_hide_label)
@@ -207,23 +200,8 @@ module Primer
207
200
  true
208
201
  end
209
202
 
210
- # Avoid using Rails delegation here for performance reasons
211
- # rubocop:disable Rails/Delegate
212
- def render_in(view_context)
213
- to_component.render_in(view_context)
214
- end
215
- # rubocop:enable Rails/Delegate
216
-
217
203
  private
218
204
 
219
- def process_classes!(args)
220
- args[:classes] = class_names(args.delete(:class), args[:classes])
221
- args.merge!(Primer::Classify.call(args))
222
- args[:class] = class_names(args[:class], args.delete(:classes))
223
- args.except!(*UTILITY_KEYS)
224
- args
225
- end
226
-
227
205
  def input_data
228
206
  @input_arguments[:data] ||= {}
229
207
  end
@@ -28,13 +28,6 @@ module Primer
28
28
  def input?
29
29
  true
30
30
  end
31
-
32
- # Avoid using Rails delegation here for performance reasons
33
- # rubocop:disable Rails/Delegate
34
- def render_in(view_context)
35
- to_component.render_in(view_context)
36
- end
37
- # rubocop:enable Rails/Delegate
38
31
  end
39
32
  end
40
33
  end
@@ -1,5 +1,5 @@
1
1
  <%= content_tag_if(horizontal?, :div, class: "d-flex", style: "gap: 15px;") do %>
2
2
  <% @inputs.each do |input| %>
3
- <%= render(input) %>
3
+ <%= render(input.to_component) %>
4
4
  <% end %>
5
5
  <% end %>
@@ -1,3 +1,3 @@
1
1
  <% @input.inputs.each do |child_input| %>
2
- <%= render(child_input) %>
2
+ <%= render(child_input.to_component) %>
3
3
  <% end %>
@@ -15,6 +15,7 @@ module Primer
15
15
 
16
16
  config.eager_load_paths = %W[
17
17
  #{root}/app/components
18
+ #{root}/app/helpers
18
19
  #{root}/app/lib
19
20
  ]
20
21
 
@@ -39,6 +40,16 @@ module Primer
39
40
  end
40
41
  end
41
42
 
43
+ initializer "primer.forms.helpers" do
44
+ ActiveSupport.on_load :action_controller do
45
+ require "primer/form_helper"
46
+ helper Primer::FormHelper
47
+
48
+ # make primer_form_with available to view components also
49
+ ViewComponent::Base.prepend(Primer::FormHelper)
50
+ end
51
+ end
52
+
42
53
  initializer "primer_view_components.zeitwerk_ignore" do
43
54
  Rails.autoloaders.each do |autoloader|
44
55
  autoloader.ignore(Engine.root.join("lib", "primer", "view_components", "linters.rb"))
@@ -13,9 +13,9 @@ module ERBLint
13
13
  symbolize: true
14
14
  ).freeze
15
15
 
16
- VARIANT_MAPPINGS = Primer::ViewComponents::Constants.get(
16
+ SIZE_MAPPINGS = Primer::ViewComponents::Constants.get(
17
17
  component: "Primer::LabelComponent",
18
- constant: "VARIANT_MAPPINGS",
18
+ constant: "SIZE_MAPPINGS",
19
19
  symbolize: true
20
20
  ).freeze
21
21
 
@@ -24,6 +24,11 @@ module ERBLint
24
24
  constant: "DEFAULT_TAG"
25
25
  ).freeze
26
26
 
27
+ INLINE_CLASS = Primer::ViewComponents::Constants.get(
28
+ component: "Primer::LabelComponent",
29
+ constant: "INLINE_CLASS"
30
+ ).freeze
31
+
27
32
  ATTRIBUTES = %w[title].freeze
28
33
 
29
34
  def attribute_to_args(attribute)
@@ -36,8 +41,10 @@ module ERBLint
36
41
 
37
42
  if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
38
43
  acc[:scheme] = SCHEME_MAPPINGS[class_name]
39
- elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
40
- acc[:variant] = VARIANT_MAPPINGS[class_name]
44
+ elsif SIZE_MAPPINGS[class_name] && acc[:size].nil?
45
+ acc[:size] = SIZE_MAPPINGS[class_name]
46
+ elsif class_name == INLINE_CLASS && acc[:inline].nil?
47
+ acc[:inline] = true
41
48
  else
42
49
  acc[:classes] << class_name
43
50
  end
@@ -12,7 +12,7 @@ module ERBLint
12
12
 
13
13
  TAGS = %w[div].freeze
14
14
  CLASSES = %w[flash].freeze
15
- MESSAGE = "We are migrating flashes to use [Primer::Beta::Flash](https://primer.style/view-components/components/flash), please try to use that instead of raw HTML."
15
+ MESSAGE = "We are migrating flashes to use [Primer::Beta::Flash](https://primer.style/view-components/components/beta/flash), please try to use that instead of raw HTML."
16
16
  ARGUMENT_MAPPER = ArgumentMappers::Flash
17
17
  COMPONENT = "Primer::Beta::Flash"
18
18
 
@@ -7,10 +7,12 @@ module ERBLint
7
7
  module DeprecatedComponentsHelpers
8
8
  # If there is no alternative to suggest, set the value to nil
9
9
  COMPONENT_TO_USE_INSTEAD = {
10
+ "Primer::ButtonGroup" => "Primer::Beta::ButtonGroup",
10
11
  "Primer::Alpha::AutoComplete::Item" => "Primer::Beta::AutoComplete::Item",
11
12
  "Primer::Alpha::AutoComplete" => "Primer::Beta::AutoComplete",
12
13
  "Primer::BlankslateComponent" => "Primer::Beta::Blankslate",
13
14
  "Primer::BorderBoxComponent" => "Primer::Beta::BorderBox",
15
+ "Primer::BoxComponent" => "Primer::Box",
14
16
  "Primer::DropdownMenuComponent" => nil,
15
17
  "Primer::Tooltip" => "Primer::Alpha::Tooltip",
16
18
  "Primer::FlexComponent" => nil,
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 86
8
+ PATCH = 89
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  # Primer::Beta::ComponentName.new()
16
16
  class ComponentNameMigration < BaseCop
17
17
  DEPRECATIONS = {
18
+ "Primer::BoxComponent" => "Primer::Box",
19
+ "Primer::ButtonGroup" => "Primer::Beta::ButtonGroup",
18
20
  "Primer::BlankslateComponent" => "Primer::Beta::Blankslate",
19
21
  "Primer::BorderBoxComponent" => "Primer::Beta::BorderBox",
20
22
  "Primer::BaseButton" => "Primer::Beta::BaseButton",
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ # :nocov:
6
+ module RuboCop
7
+ module Cop
8
+ module Primer
9
+ # This cop ensures that `LabelComponent`s don't use the old `variant` argument.
10
+ #
11
+ # bad
12
+ # Primer::LabelComponent.new(variant: :large)
13
+ #
14
+ # good
15
+ # Primer::LabelComponent.new(size: :large)
16
+ #
17
+ # bad
18
+ # Primer::LabelComponent.new(variant: :inline)
19
+ #
20
+ # good
21
+ # Primer::LabelComponent.new(inline: true)
22
+ class DeprecatedLabelVariants < BaseCop
23
+ def on_send(node)
24
+ return unless label_node?(node)
25
+ return unless node.arguments?
26
+
27
+ # we are looking for hash arguments and they are always last
28
+ kwargs = node.arguments.last
29
+
30
+ return unless kwargs.type == :hash
31
+
32
+ kwargs.pairs.each do |pair|
33
+ # skip if we're not dealing with a symbol or string
34
+ next if pair.key.type != :sym
35
+ next unless pair.value.type == :sym || pair.value.type == :str
36
+ next if pair.key.value != :variant
37
+
38
+ case pair.value.value
39
+ when :large, "large"
40
+ add_offense(pair, message: "Avoid using `variant: :large` with `LabelComponent`. Use `size: :large` instead.")
41
+ when :inline, "inline"
42
+ add_offense(pair, message: "Avoid using `variant: :inline` with `LabelComponent`. Use `inline: true` instead.")
43
+ end
44
+ end
45
+ end
46
+
47
+ def autocorrect(node)
48
+ lambda do |corrector|
49
+ replacement =
50
+ case node.value.value
51
+ when :large, "large"
52
+ "size: :large"
53
+ when :inline, "inline"
54
+ "inline: true"
55
+ end
56
+
57
+ corrector.replace(node, replacement)
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def label_node?(node)
64
+ return if node.nil?
65
+
66
+ node.method_name == :new && !node.receiver.nil? && node.receiver.const_name == "Primer::LabelComponent"
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/tasks/docs.rake CHANGED
@@ -44,10 +44,10 @@ namespace :docs do
44
44
  Primer::Beta::Blankslate,
45
45
  Primer::Beta::BorderBox,
46
46
  Primer::Beta::BorderBox::Header,
47
- Primer::BoxComponent,
47
+ Primer::Box,
48
48
  Primer::Beta::Breadcrumbs,
49
49
  Primer::ButtonComponent,
50
- Primer::ButtonGroup,
50
+ Primer::Beta::ButtonGroup,
51
51
  Primer::Alpha::ButtonMarketing,
52
52
  Primer::ClipboardCopy,
53
53
  Primer::CloseButton,
@@ -28,7 +28,7 @@ module YARD
28
28
  prefix = "One of"
29
29
  prefix = prefix.downcase if lower
30
30
 
31
- "#{prefix} #{values.to_sentence(last_word_connector: ', or ')}."
31
+ "#{prefix} #{values.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}."
32
32
  end
33
33
 
34
34
  def link_to_accessibility