primer_view_components 0.0.84 → 0.0.87

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/components/primer/alpha/auto_complete/item.rb +1 -1
  6. data/app/components/primer/alpha/auto_complete.rb +1 -1
  7. data/app/components/primer/alpha/button_marketing.rb +1 -1
  8. data/app/components/primer/alpha/text_field.rb +105 -0
  9. data/app/components/primer/alpha/tool-tip-element.d.ts +3 -1
  10. data/app/components/primer/alpha/tool-tip-element.js +20 -13
  11. data/app/components/primer/alpha/tool-tip-element.ts +23 -14
  12. data/app/components/primer/alpha/tooltip.rb +1 -1
  13. data/app/components/primer/beta/base_button.rb +47 -0
  14. data/app/components/primer/{alpha → beta}/border_box/header.html.erb +0 -0
  15. data/app/components/primer/{alpha → beta}/border_box/header.rb +6 -6
  16. data/app/components/primer/{border_box_component.html.erb → beta/border_box.html.erb} +0 -0
  17. data/app/components/primer/beta/border_box.rb +147 -0
  18. data/app/components/primer/blankslate_component.html.erb +0 -5
  19. data/app/components/primer/border_box_component.rb +2 -140
  20. data/app/components/primer/button_component.html.erb +12 -4
  21. data/app/components/primer/button_component.rb +2 -2
  22. data/app/components/primer/clipboard_copy.rb +6 -2
  23. data/app/components/primer/close_button.rb +1 -1
  24. data/app/components/primer/hellip_button.rb +1 -1
  25. data/app/components/primer/icon_button.html.erb +6 -0
  26. data/app/components/primer/icon_button.rb +46 -10
  27. data/app/components/primer/link_component.rb +12 -5
  28. data/app/helpers/primer/form_helper.rb +10 -0
  29. data/app/lib/primer/join_style_arguments_helper.rb +1 -1
  30. data/lib/primer/classify/utilities.rb +3 -6
  31. data/lib/primer/form_components.rb +36 -0
  32. data/lib/primer/forms/acts_as_component.rb +118 -0
  33. data/lib/primer/forms/base.html.erb +8 -0
  34. data/lib/primer/forms/base.rb +142 -0
  35. data/lib/primer/forms/base_component.rb +62 -0
  36. data/lib/primer/forms/buffer_rewriter.rb +51 -0
  37. data/lib/primer/forms/builder.rb +48 -0
  38. data/lib/primer/forms/caption.html.erb +10 -0
  39. data/lib/primer/forms/caption.rb +29 -0
  40. data/lib/primer/forms/check_box.html.erb +9 -0
  41. data/lib/primer/forms/check_box.rb +16 -0
  42. data/lib/primer/forms/check_box_group.html.erb +12 -0
  43. data/lib/primer/forms/check_box_group.rb +14 -0
  44. data/lib/primer/forms/dsl/check_box_group_input.rb +41 -0
  45. data/lib/primer/forms/dsl/check_box_input.rb +27 -0
  46. data/lib/primer/forms/dsl/form_object.rb +25 -0
  47. data/lib/primer/forms/dsl/form_reference_input.rb +36 -0
  48. data/lib/primer/forms/dsl/hidden_input.rb +29 -0
  49. data/lib/primer/forms/dsl/input.rb +237 -0
  50. data/lib/primer/forms/dsl/input_group.rb +34 -0
  51. data/lib/primer/forms/dsl/input_methods.rb +86 -0
  52. data/lib/primer/forms/dsl/multi_input.rb +58 -0
  53. data/lib/primer/forms/dsl/radio_button_group_input.rb +38 -0
  54. data/lib/primer/forms/dsl/radio_button_input.rb +37 -0
  55. data/lib/primer/forms/dsl/select_list_input.rb +53 -0
  56. data/lib/primer/forms/dsl/submit_button_input.rb +28 -0
  57. data/lib/primer/forms/dsl/text_area_input.rb +33 -0
  58. data/lib/primer/forms/dsl/text_field_input.rb +65 -0
  59. data/lib/primer/forms/form_control.html.erb +18 -0
  60. data/lib/primer/forms/form_control.rb +23 -0
  61. data/lib/primer/forms/form_list.html.erb +5 -0
  62. data/lib/primer/forms/form_list.rb +21 -0
  63. data/lib/primer/forms/form_reference.html.erb +3 -0
  64. data/lib/primer/forms/form_reference.rb +14 -0
  65. data/lib/primer/forms/group.html.erb +5 -0
  66. data/lib/primer/forms/group.rb +27 -0
  67. data/lib/primer/forms/hidden_field.html.erb +1 -0
  68. data/lib/primer/forms/hidden_field.rb +15 -0
  69. data/lib/primer/forms/multi.html.erb +3 -0
  70. data/lib/primer/forms/multi.rb +14 -0
  71. data/lib/primer/forms/radio_button.html.erb +14 -0
  72. data/lib/primer/forms/radio_button.rb +29 -0
  73. data/lib/primer/forms/radio_button_group.html.erb +12 -0
  74. data/lib/primer/forms/radio_button_group.rb +14 -0
  75. data/lib/primer/forms/select_list.html.erb +5 -0
  76. data/lib/primer/forms/select_list.rb +26 -0
  77. data/lib/primer/forms/separator.html.erb +1 -0
  78. data/lib/primer/forms/separator.rb +8 -0
  79. data/lib/primer/forms/spacing_wrapper.html.erb +3 -0
  80. data/lib/primer/forms/spacing_wrapper.rb +8 -0
  81. data/lib/primer/forms/submit_button.html.erb +4 -0
  82. data/lib/primer/forms/submit_button.rb +50 -0
  83. data/lib/primer/forms/text_area.html.erb +5 -0
  84. data/lib/primer/forms/text_area.rb +16 -0
  85. data/lib/primer/forms/text_field.html.erb +19 -0
  86. data/lib/primer/forms/text_field.rb +14 -0
  87. data/lib/primer/view_components/engine.rb +34 -0
  88. data/lib/primer/view_components/linters/argument_mappers/button.rb +2 -2
  89. data/lib/primer/view_components/linters/button_component_migration_counter.rb +1 -1
  90. data/lib/primer/view_components/linters/helpers/deprecated_components_helpers.rb +2 -8
  91. data/lib/primer/view_components/version.rb +1 -1
  92. data/lib/rubocop/cop/primer/component_name_migration.rb +3 -0
  93. data/lib/rubocop/cop/primer/deprecated_arguments.rb +0 -10
  94. data/lib/tasks/deprecated.rake +22 -0
  95. data/lib/tasks/docs.rake +5 -3
  96. data/static/arguments.yml +148 -39
  97. data/static/audited_at.json +4 -2
  98. data/static/classes.yml +2 -1
  99. data/static/constants.json +44 -39
  100. data/static/statuses.json +7 -5
  101. metadata +69 -8
  102. data/app/components/primer/base_button.rb +0 -43
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class Input
8
+ SPACE_DELIMITED_ARIA_ATTRIBUTES = %i[describedby].freeze
9
+ DEFAULT_SIZE = :medium
10
+ SIZE_MAPPINGS = {
11
+ :small => "FormControl-small",
12
+ DEFAULT_SIZE => "FormControl-medium",
13
+ :large => "FormControl-large"
14
+ }.freeze
15
+ SIZE_OPTIONS = SIZE_MAPPINGS.keys
16
+
17
+ include Primer::ClassNameHelper
18
+
19
+ attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids
20
+
21
+ def initialize(builder:, form:, **system_arguments)
22
+ @builder = builder
23
+ @form = form
24
+
25
+ @input_arguments = system_arguments
26
+ @label_arguments = @input_arguments.delete(:label_arguments) || {}
27
+
28
+ @label_arguments[:class] = class_names(
29
+ @label_arguments[:class],
30
+ @input_arguments.fetch(:visually_hide_label, false) ? "sr-only" : nil
31
+ )
32
+
33
+ @input_arguments.delete(:visually_hide_label)
34
+
35
+ @input_arguments.delete(:class) if @input_arguments[:class].blank?
36
+ @label_arguments.delete(:class) if @label_arguments[:class].blank?
37
+
38
+ @caption = @input_arguments.delete(:caption)
39
+ @validation_message = @input_arguments.delete(:validation_message)
40
+ @invalid = @input_arguments.delete(:invalid)
41
+ @full_width = @input_arguments.delete(:full_width)
42
+ @size = @input_arguments.delete(:size)
43
+
44
+ @input_arguments[:invalid] = "true" if invalid?
45
+
46
+ base_id = SecureRandom.hex[0..5]
47
+
48
+ @ids = {}.tap do |id_map|
49
+ id_map[:validation] = "validation-#{base_id}" if invalid?
50
+ id_map[:caption] = "caption-#{base_id}" if caption? || caption_template?
51
+ end
52
+
53
+ add_input_aria(:required, true) if required?
54
+ add_input_aria(:describedby, ids.values) if ids.any?
55
+
56
+ # avoid browser-native validation, which doesn't match Primer's style
57
+ input_arguments.delete(:required)
58
+ end
59
+
60
+ def add_input_classes(*class_names)
61
+ input_arguments[:class] = class_names(
62
+ input_arguments[:class], *class_names
63
+ )
64
+ end
65
+
66
+ def add_label_classes(*class_names)
67
+ label_arguments[:class] = class_names(
68
+ label_arguments[:class], *class_names
69
+ )
70
+ end
71
+
72
+ def add_input_aria(key, value)
73
+ @input_arguments[:aria] ||= {}
74
+
75
+ @input_arguments[:aria][key] = if space_delimited_aria_attribute?(key)
76
+ aria_join(@input_arguments[:aria][key], *Array(value))
77
+ else
78
+ value
79
+ end
80
+ end
81
+
82
+ def add_input_data(key, value)
83
+ input_data[key] = value
84
+ end
85
+
86
+ def remove_input_data(key)
87
+ input_data.delete(key)
88
+ end
89
+
90
+ def merge_input_arguments!(arguments)
91
+ arguments.each do |k, v|
92
+ case k
93
+ when :class, :classes, "class", "classes"
94
+ add_input_classes(v)
95
+ when :aria, "aria"
96
+ v.each do |aria_k, aria_v|
97
+ add_input_aria(aria_k, aria_v)
98
+ end
99
+ when :data, "data"
100
+ v.each do |data_k, data_v|
101
+ add_input_data(data_k, data_v)
102
+ end
103
+ else
104
+ @input_arguments[k] = v
105
+ end
106
+ end
107
+ end
108
+
109
+ def validation_id
110
+ ids[:validation]
111
+ end
112
+
113
+ def caption_id
114
+ ids[:caption]
115
+ end
116
+
117
+ def caption?
118
+ caption.present?
119
+ end
120
+
121
+ def caption_template?
122
+ return false unless form
123
+
124
+ form.caption_template?(caption_template_name)
125
+ end
126
+
127
+ def render_caption_template
128
+ form.render_caption_template(caption_template_name)
129
+ end
130
+
131
+ def valid?
132
+ validation_messages.empty? && !@invalid
133
+ end
134
+
135
+ def invalid?
136
+ !valid?
137
+ end
138
+
139
+ def hidden?
140
+ !!input_arguments[:hidden]
141
+ end
142
+
143
+ def required?
144
+ input_arguments[:required] ||
145
+ input_arguments[:aria_required] ||
146
+ input_arguments[:"aria-required"] ||
147
+ input_arguments.dig(:aria, :required)
148
+ end
149
+
150
+ def disabled?
151
+ input_arguments.include?(:disabled)
152
+ end
153
+
154
+ def full_width?
155
+ @full_width
156
+ end
157
+
158
+ def size
159
+ @size ||= SIZE_MAPPINGS.include?(@size) ? @size : DEFAULT_SIZE
160
+ end
161
+
162
+ def validation_messages
163
+ @validation_messages ||=
164
+ if validation_message
165
+ [validation_message]
166
+ elsif builder.object.respond_to?(:errors)
167
+ name ? builder.object.errors.full_messages_for(name) : []
168
+ else
169
+ []
170
+ end
171
+ end
172
+
173
+ def autofocus!
174
+ input_arguments[:autofocus] = true
175
+ end
176
+
177
+ # :nocov:
178
+ def name
179
+ raise_for_abstract_method!(__method__)
180
+ end
181
+
182
+ def label
183
+ raise_for_abstract_method!(__method__)
184
+ end
185
+
186
+ def type
187
+ raise_for_abstract_method!(__method__)
188
+ end
189
+
190
+ def to_component
191
+ raise_for_abstract_method!(__method__)
192
+ end
193
+ # :nocov:
194
+
195
+ def focusable?
196
+ false
197
+ end
198
+
199
+ def input?
200
+ true
201
+ end
202
+
203
+ private
204
+
205
+ def input_data
206
+ @input_arguments[:data] ||= {}
207
+ end
208
+
209
+ def caption_template_name
210
+ return nil unless name
211
+
212
+ @caption_template_name ||= if respond_to?(:value)
213
+ :"#{name}_#{value}"
214
+ else
215
+ name.to_sym
216
+ end
217
+ end
218
+
219
+ def space_delimited_aria_attribute?(attrib)
220
+ SPACE_DELIMITED_ARIA_ATTRIBUTES.include?(attrib)
221
+ end
222
+
223
+ def aria_join(*values)
224
+ values = values.flat_map { |v| v.to_s.split }
225
+ values.reject!(&:empty?)
226
+ values.join(" ")
227
+ end
228
+
229
+ # :nocov:
230
+ def raise_for_abstract_method!(method_name)
231
+ raise NotImplementedError, "subclasses must implement ##{method_name}."
232
+ end
233
+ # :nocov:
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class InputGroup
8
+ include InputMethods
9
+
10
+ attr_reader :builder, :form, :system_arguments
11
+
12
+ def initialize(builder:, form:, **system_arguments)
13
+ @builder = builder
14
+ @form = form
15
+ @system_arguments = system_arguments
16
+
17
+ yield(self) if block_given?
18
+ end
19
+
20
+ def to_component
21
+ Group.new(inputs: inputs, builder: builder, form: form, **@system_arguments)
22
+ end
23
+
24
+ def type
25
+ :group
26
+ end
27
+
28
+ def input?
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ module InputMethods
8
+ def fields_for(*args, **kwargs, &block)
9
+ add_input FormReferenceInput.new(*args, builder: builder, form: form, **kwargs, &block)
10
+ end
11
+
12
+ def multi(**options, &block)
13
+ add_input MultiInput.new(builder: builder, form: form, **options, &block)
14
+ end
15
+
16
+ def hidden(**options)
17
+ add_input HiddenInput.new(builder: builder, form: form, **options)
18
+ end
19
+
20
+ def check_box(**options)
21
+ add_input CheckBoxInput.new(builder: builder, form: form, **options)
22
+ end
23
+
24
+ def radio_button_group(**options, &block)
25
+ add_input RadioButtonGroupInput.new(builder: builder, form: form, **options, &block)
26
+ end
27
+
28
+ def check_box_group(**options, &block)
29
+ add_input CheckBoxGroupInput.new(builder: builder, form: form, **options, &block)
30
+ end
31
+
32
+ def separator
33
+ add_input Separator.new
34
+ end
35
+
36
+ # START text input methods
37
+
38
+ def text_field(**options, &block)
39
+ options = decorate_options(**options)
40
+ add_input TextFieldInput.new(builder: builder, form: form, **options, &block)
41
+ end
42
+
43
+ def text_area(**options, &block)
44
+ options = decorate_options(**options)
45
+ add_input TextAreaInput.new(builder: builder, form: form, **options, &block)
46
+ end
47
+
48
+ # END text input methods
49
+
50
+ # START select input methods
51
+
52
+ def select_list(**options, &block)
53
+ options = decorate_options(**options)
54
+ add_input SelectListInput.new(builder: builder, form: form, **options, &block)
55
+ end
56
+
57
+ # END select input methods
58
+
59
+ # START button input methods
60
+
61
+ def submit(**options, &block)
62
+ options = decorate_options(**options)
63
+ add_input SubmitButtonInput.new(builder: builder, form: form, **options, &block)
64
+ end
65
+
66
+ # END button input methods
67
+
68
+ def inputs
69
+ @inputs ||= []
70
+ end
71
+
72
+ private
73
+
74
+ def add_input(input)
75
+ inputs << input
76
+ end
77
+
78
+ # Called before the corresponding Input class is instantiated. The return value of this method is passed
79
+ # to the Input class's constructor.
80
+ def decorate_options(**options)
81
+ options
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class MultiInput < Input
8
+ include InputMethods
9
+
10
+ attr_reader :name, :label
11
+
12
+ def initialize(name:, label:, **system_arguments)
13
+ @name = name
14
+ @label = label
15
+
16
+ super(**system_arguments)
17
+
18
+ yield(self) if block_given?
19
+ end
20
+
21
+ def to_component
22
+ Multi.new(input: self)
23
+ end
24
+
25
+ def type
26
+ :multi
27
+ end
28
+
29
+ private
30
+
31
+ def add_input(input)
32
+ super
33
+
34
+ check_one_input_visible!
35
+ end
36
+
37
+ def decorate_options(name: nil, **options)
38
+ check_name!(name) if name
39
+ new_options = { name: name || @name, label: nil, **options }
40
+ new_options[:id] = nil if options[:hidden]
41
+ new_options
42
+ end
43
+
44
+ def check_name!(name)
45
+ return if name == @name
46
+
47
+ raise ArgumentError, "Inputs inside a `multi' block must all have the same name. Expected '#{@name}', got '#{name}'."
48
+ end
49
+
50
+ def check_one_input_visible!
51
+ return if inputs.count { |input| !input.hidden? } <= 1
52
+
53
+ raise ArgumentError, "Only one input can be visible at a time in a `multi' block."
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class RadioButtonGroupInput < Input
8
+ attr_reader :name, :label, :radio_buttons
9
+
10
+ def initialize(name:, label: nil, **system_arguments)
11
+ @name = name
12
+ @label = label
13
+ @radio_buttons = []
14
+
15
+ super(**system_arguments)
16
+
17
+ add_label_classes("FormControl-label", "mb-2")
18
+
19
+ yield(self) if block_given?
20
+ end
21
+
22
+ def to_component
23
+ RadioButtonGroup.new(input: self)
24
+ end
25
+
26
+ def type
27
+ :radio_button_group
28
+ end
29
+
30
+ def radio_button(**system_arguments, &block)
31
+ @radio_buttons << RadioButtonInput.new(
32
+ builder: @builder, form: @form, name: @name, **system_arguments, &block
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class RadioButtonInput < Input
8
+ attr_reader :name, :value, :label, :nested_form_block, :nested_form_arguments
9
+
10
+ def initialize(name:, value:, label:, **system_arguments)
11
+ @name = name
12
+ @value = value
13
+ @label = label
14
+
15
+ super(**system_arguments)
16
+
17
+ yield(self) if block_given?
18
+ end
19
+
20
+ def to_component
21
+ RadioButton.new(input: self)
22
+ end
23
+
24
+ def nested_form(**system_arguments, &block)
25
+ @nested_form_arguments = system_arguments
26
+ @nested_form_block = block
27
+ end
28
+
29
+ # :nocov:
30
+ def type
31
+ :radio_button
32
+ end
33
+ # :nocov:
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class SelectListInput < Input
8
+ # :nodoc:
9
+ class Option
10
+ attr_reader :label, :value, :system_arguments
11
+
12
+ def initialize(label:, value:, **system_arguments)
13
+ @label = label
14
+ @value = value
15
+ @system_arguments = system_arguments
16
+ end
17
+ end
18
+
19
+ attr_reader :name, :label, :options
20
+
21
+ def initialize(name:, label:, **system_arguments)
22
+ @name = name
23
+ @label = label
24
+ @options = []
25
+
26
+ super(**system_arguments)
27
+
28
+ yield(self) if block_given?
29
+ end
30
+
31
+ def option(**system_arguments)
32
+ @options << Option.new(**system_arguments)
33
+ end
34
+
35
+ def to_component
36
+ SelectList.new(input: self)
37
+ end
38
+
39
+ # :nocov:
40
+ def type
41
+ :select_list
42
+ end
43
+ # :nocov:
44
+
45
+ # :nocov:
46
+ def focusable?
47
+ true
48
+ end
49
+ # :nocov:
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class SubmitButtonInput < Input
8
+ attr_reader :name, :label, :block
9
+
10
+ def initialize(name:, label:, **system_arguments, &block)
11
+ @name = name
12
+ @label = label
13
+ @block = block
14
+
15
+ super(**system_arguments)
16
+ end
17
+
18
+ def to_component
19
+ SubmitButton.new(input: self)
20
+ end
21
+
22
+ def type
23
+ :submit_button
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class TextAreaInput < Input
8
+ attr_reader :name, :label
9
+
10
+ def initialize(name:, label:, **system_arguments)
11
+ @name = name
12
+ @label = label
13
+
14
+ super(**system_arguments)
15
+ end
16
+
17
+ def to_component
18
+ TextArea.new(input: self)
19
+ end
20
+
21
+ def type
22
+ :text_area
23
+ end
24
+
25
+ # :nocov:
26
+ def focusable?
27
+ true
28
+ end
29
+ # :nocov:
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class TextFieldInput < Input
8
+ attr_reader(
9
+ *%i[
10
+ name label show_clear_button leading_visual clear_button_id
11
+ visually_hide_label inset monospace field_wrap_classes
12
+ ]
13
+ )
14
+
15
+ def initialize(name:, label:, **system_arguments)
16
+ @name = name
17
+ @label = label
18
+
19
+ @show_clear_button = system_arguments.delete(:show_clear_button)
20
+ @leading_visual = system_arguments.delete(:leading_visual)
21
+ @clear_button_id = system_arguments.delete(:clear_button_id)
22
+ @inset = system_arguments.delete(:inset)
23
+ @monospace = system_arguments.delete(:monospace)
24
+
25
+ super(**system_arguments)
26
+
27
+ add_input_classes(
28
+ "FormControl-input",
29
+ Primer::Forms::Dsl::Input::SIZE_MAPPINGS[size]
30
+ )
31
+
32
+ add_input_classes("FormControl-inset") if inset?
33
+ add_input_classes("FormControl-monospace") if monospace?
34
+
35
+ @field_wrap_classes = class_names(
36
+ "FormControl-input-wrap",
37
+ Primer::Forms::Dsl::Input::SIZE_MAPPINGS[size],
38
+ "FormControl-input-wrap--trailingAction": show_clear_button?,
39
+ "FormControl-input-wrap--leadingVisual": leading_visual?
40
+ )
41
+ end
42
+
43
+ alias show_clear_button? show_clear_button
44
+ alias inset? inset
45
+ alias monospace? monospace
46
+
47
+ def to_component
48
+ TextField.new(input: self)
49
+ end
50
+
51
+ def type
52
+ :text_field
53
+ end
54
+
55
+ def focusable?
56
+ true
57
+ end
58
+
59
+ def leading_visual?
60
+ !!@leading_visual
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ <%= content_tag(:div, style: "flex-grow: 1", **@form_group_arguments) do %>
2
+ <% if @input.label %>
3
+ <%= builder.label(@input.name, **@input.label_arguments) do %>
4
+ <%= @input.label %>
5
+ <% if @input.required? %>
6
+ <span aria-hidden="true">*</span>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
10
+ <%= content %>
11
+ <% if @input.invalid? && @input.validation_messages.present? %>
12
+ <div class="FormControl-inlineValidation" id="<%= @input.validation_id %>">
13
+ <%= render(Primer::OcticonComponent.new(icon: :"alert-fill", size: :xsmall, aria: { hidden: true })) %>
14
+ <span><%= @input.validation_messages.first %></span>
15
+ </div>
16
+ <% end %>
17
+ <%= render(Caption.new(input: @input)) %>
18
+ <% end %>