primer_view_components 0.0.86 → 0.0.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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