primer_view_components 0.0.114 → 0.0.116

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -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/assets/styles/primer_view_components.css +2 -2
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/item.rb +6 -6
  8. data/app/components/primer/alpha/auto_complete/auto_complete.html.erb +1 -1
  9. data/app/components/primer/alpha/auto_complete.rb +10 -10
  10. data/app/components/primer/alpha/banner.html.erb +1 -1
  11. data/app/components/primer/alpha/dialog.rb +2 -0
  12. data/app/components/primer/alpha/dropdown/menu.rb +2 -0
  13. data/app/components/primer/alpha/dropdown.html.erb +3 -3
  14. data/app/components/primer/alpha/image_crop.html.erb +1 -1
  15. data/app/components/primer/alpha/layout.css +1 -0
  16. data/app/components/primer/alpha/layout.css.json +1 -0
  17. data/app/components/primer/alpha/layout.css.map +1 -0
  18. data/app/components/primer/alpha/layout.pcss +268 -0
  19. data/app/components/primer/alpha/layout.rb +1 -1
  20. data/app/components/primer/{menu_component.css → alpha/menu.css} +0 -0
  21. data/app/components/primer/alpha/menu.css.json +1 -0
  22. data/app/components/primer/alpha/menu.css.map +1 -0
  23. data/app/components/primer/{menu_component.html.erb → alpha/menu.html.erb} +0 -0
  24. data/app/components/primer/{menu_component.pcss → alpha/menu.pcss} +0 -0
  25. data/app/components/primer/alpha/menu.rb +76 -0
  26. data/app/components/primer/{octicon_symbols_component.html.erb → alpha/octicon_symbols.html.erb} +0 -0
  27. data/app/components/primer/alpha/octicon_symbols.rb +59 -0
  28. data/app/components/primer/alpha/segmented_control.css +1 -1
  29. data/app/components/primer/alpha/segmented_control.css.json +1 -1
  30. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  31. data/app/components/primer/alpha/segmented_control.pcss +12 -0
  32. data/app/components/primer/alpha/segmented_control.rb +5 -5
  33. data/app/components/primer/alpha/tab_panels.rb +6 -6
  34. data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
  35. data/app/components/primer/alpha/toggle_switch.rb +6 -6
  36. data/app/components/primer/alpha/tool_tip.js +77 -69
  37. data/app/components/primer/alpha/tool_tip.ts +63 -51
  38. data/app/components/primer/alpha/underline_panels.rb +6 -6
  39. data/app/components/primer/beta/auto_complete/item.rb +5 -4
  40. data/app/components/primer/beta/auto_complete.rb +15 -13
  41. data/app/components/primer/beta/avatar_stack.rb +2 -0
  42. data/app/components/primer/beta/blankslate.rb +48 -47
  43. data/app/components/primer/beta/border_box/header.rb +2 -0
  44. data/app/components/primer/beta/border_box.rb +2 -0
  45. data/app/components/primer/beta/breadcrumbs.rb +1 -0
  46. data/app/components/primer/beta/button.css +1 -1
  47. data/app/components/primer/beta/button.css.json +1 -1
  48. data/app/components/primer/beta/button.css.map +1 -1
  49. data/app/components/primer/beta/button.pcss +5 -0
  50. data/app/components/primer/beta/button.rb +8 -7
  51. data/app/components/primer/beta/button_group.rb +3 -0
  52. data/app/components/primer/beta/clipboard_copy.html.erb +2 -2
  53. data/app/components/primer/beta/close_button.rb +1 -1
  54. data/app/components/primer/beta/details.rb +6 -3
  55. data/app/components/primer/beta/flash.rb +1 -0
  56. data/app/components/primer/beta/icon_button.html.erb +1 -1
  57. data/app/components/primer/beta/link.rb +1 -0
  58. data/app/components/primer/{octicon_component.html.erb → beta/octicon.html.erb} +0 -0
  59. data/app/components/primer/beta/octicon.rb +89 -0
  60. data/app/components/primer/beta/popover.rb +1 -0
  61. data/app/components/primer/beta/progress_bar.rb +7 -7
  62. data/app/components/primer/beta/relative_time.rb +1 -1
  63. data/app/components/primer/{spinner_component.html.erb → beta/spinner.html.erb} +0 -0
  64. data/app/components/primer/beta/spinner.rb +45 -0
  65. data/app/components/primer/beta/truncate.rb +3 -2
  66. data/app/components/primer/blankslate_component.rb +3 -3
  67. data/app/components/primer/button_component.rb +5 -5
  68. data/app/components/primer/component.rb +1 -0
  69. data/app/components/primer/dropdown_menu_component.rb +3 -3
  70. data/app/components/primer/icon_button.html.erb +2 -2
  71. data/app/components/primer/local_time.rb +2 -0
  72. data/app/components/primer/menu_component.rb +2 -69
  73. data/app/components/primer/navigation/tab_component.rb +2 -2
  74. data/app/components/primer/octicon_component.rb +2 -81
  75. data/app/components/primer/octicon_symbols_component.rb +2 -52
  76. data/app/components/primer/primer.d.ts +2 -0
  77. data/app/components/primer/primer.js +2 -0
  78. data/app/components/primer/primer.pcss +2 -1
  79. data/app/components/primer/primer.ts +2 -0
  80. data/app/components/primer/spinner_component.rb +2 -38
  81. data/app/components/primer/time_ago_component.rb +1 -1
  82. data/app/components/primer/timeline_item_component.rb +2 -2
  83. data/app/forms/immediate_validation_form.rb +29 -0
  84. data/app/forms/multi_input_form.rb +4 -2
  85. data/app/lib/primer/css/layout.css +1 -378
  86. data/app/lib/primer/css/layout.css.json +1 -1
  87. data/app/lib/primer/octicon/cache.rb +1 -1
  88. data/app/lib/primer/view_helper.rb +1 -1
  89. data/lib/primer/deprecations.yml +26 -0
  90. data/lib/primer/forms/builder.rb +47 -8
  91. data/lib/primer/forms/check_box.html.erb +3 -1
  92. data/lib/primer/forms/dsl/form_reference_input.rb +25 -2
  93. data/lib/primer/forms/dsl/input.rb +50 -1
  94. data/lib/primer/forms/dsl/multi_input.rb +6 -9
  95. data/lib/primer/forms/dsl/select_list_input.rb +1 -1
  96. data/lib/primer/forms/dsl/text_field_input.rb +31 -1
  97. data/lib/primer/forms/form_control.html.erb +17 -13
  98. data/lib/primer/forms/form_control.rb +2 -0
  99. data/lib/primer/forms/form_reference.html.erb +1 -1
  100. data/lib/primer/forms/form_reference.rb +4 -0
  101. data/lib/primer/forms/multi.html.erb +6 -2
  102. data/lib/primer/forms/primer_multi_input.d.ts +10 -0
  103. data/lib/primer/forms/primer_multi_input.js +45 -0
  104. data/lib/primer/forms/primer_multi_input.ts +46 -0
  105. data/lib/primer/forms/primer_text_field.d.ts +1 -0
  106. data/lib/primer/forms/primer_text_field.js +62 -0
  107. data/lib/primer/forms/primer_text_field.ts +48 -0
  108. data/lib/primer/forms/radio_button.html.erb +3 -1
  109. data/lib/primer/forms/text_field.html.erb +8 -8
  110. data/lib/primer/forms/text_field.rb +11 -0
  111. data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +1 -1
  112. data/lib/primer/view_components/version.rb +1 -1
  113. data/lib/tasks/docs.rake +5 -5
  114. data/lib/tasks/helpers/ast_traverser.rb +1 -1
  115. data/previews/primer/alpha/action_list_preview.rb +1 -1
  116. data/previews/primer/alpha/auto_complete_preview.rb +62 -6
  117. data/previews/primer/alpha/layout_preview.rb +179 -6
  118. data/previews/primer/{menu_component_preview → alpha/menu_preview}/default.html.erb +3 -3
  119. data/previews/primer/{menu_component_preview → alpha/menu_preview}/playground.html.erb +3 -3
  120. data/previews/primer/alpha/menu_preview.rb +14 -0
  121. data/previews/primer/alpha/tab_panels_preview.rb +8 -8
  122. data/previews/primer/alpha/toggle_switch_preview.rb +11 -9
  123. data/previews/primer/beta/auto_complete_preview/with_submit_button.html.erb +1 -1
  124. data/previews/primer/beta/auto_complete_preview.rb +19 -17
  125. data/previews/primer/beta/details_preview.rb +6 -6
  126. data/previews/primer/beta/octicon_preview.rb +24 -0
  127. data/previews/primer/beta/spinner_preview.rb +22 -0
  128. data/previews/primer/forms/forms_preview/immediate_validation_form.html.erb +3 -0
  129. data/previews/primer/forms/forms_preview/multi_input_form.html.erb +12 -1
  130. data/previews/primer/forms/forms_preview.rb +2 -0
  131. data/previews/primer/local_time_component_preview.rb +3 -0
  132. data/previews/primer/time_ago_component_preview.rb +3 -0
  133. data/previews/primer/url_helpers.rb +15 -0
  134. data/static/arguments.json +159 -159
  135. data/static/audited_at.json +4 -0
  136. data/static/constants.json +42 -34
  137. data/static/statuses.json +10 -6
  138. metadata +32 -15
  139. data/app/components/primer/menu_component.css.json +0 -1
  140. data/app/components/primer/menu_component.css.map +0 -1
  141. data/previews/primer/menu_component_preview.rb +0 -12
  142. data/previews/primer/octicon_component_preview.rb +0 -22
  143. data/previews/primer/spinner_component_preview.rb +0 -20
@@ -4,7 +4,9 @@
4
4
  <%= builder.label(@input.name, **@input.label_arguments) do %>
5
5
  <%= @input.label %>
6
6
  <% end %>
7
- <%= render(Caption.new(input: @input)) %>
7
+ <% if @input.form_control? %>
8
+ <%= render(Caption.new(input: @input)) %>
9
+ <% end %>
8
10
  </span>
9
11
  <% end %>
10
12
  <% if @input.nested_form_block %>
@@ -5,11 +5,34 @@ module Primer
5
5
  module Dsl
6
6
  # :nodoc:
7
7
  class FormReferenceInput < Input
8
- attr_reader :ref_block, :fields_for_args, :fields_for_kwargs
8
+ attr_reader :ref_block, :fields_for_args, :fields_for_kwargs, :nested
9
+ alias nested? nested
9
10
 
10
- def initialize(*fields_for_args, builder:, form:, **fields_for_kwargs, &block)
11
+ # Pass `nested: false` to prevent the referenced form fields from being treated as nested
12
+ # under the parent form's model. For example, consider these models:
13
+
14
+ # class User < ActiveRecord::Base
15
+ # has_many :addresses
16
+ # end
17
+
18
+ # class Address < ActiveRecord::Base
19
+ # belongs_to :user
20
+ # end
21
+
22
+ # A sign-up form might include fields from `User` as well as `Address`. Since addresses are
23
+ # associated with users, it's perfectly natural to accept the address fields as nested
24
+ # attributes. Rails will name each field accordingly. For example, the `street` field on
25
+ # `Address` will be named `user[address][street]`.
26
+
27
+ # For situations like this where an association exists between two models, the nested
28
+ # attributes approach works great. However sometimes all you want is to compose two forms
29
+ # together that aren't connected by an association. In such cases the fields will still
30
+ # include the name of the parent model, eg. `user[address][street]` instead of what we want,
31
+ # `address[street]`. To render the form independent of the parent, pass `nested: false`.
32
+ def initialize(*fields_for_args, builder:, form:, nested: true, **fields_for_kwargs, &block)
11
33
  @fields_for_args = fields_for_args
12
34
  @fields_for_kwargs = fields_for_kwargs
35
+ @nested = nested
13
36
  @ref_block = block
14
37
 
15
38
  super(builder: builder, form: form, **fields_for_kwargs)
@@ -16,7 +16,9 @@ module Primer
16
16
 
17
17
  include Primer::ClassNameHelper
18
18
 
19
- attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids
19
+ attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids, :form_control
20
+
21
+ alias form_control? form_control
20
22
 
21
23
  def initialize(builder:, form:, **system_arguments)
22
24
  @builder = builder
@@ -41,6 +43,37 @@ module Primer
41
43
  @full_width = @input_arguments.delete(:full_width)
42
44
  @size = @input_arguments.delete(:size)
43
45
 
46
+ # If scope_name_to_model is false, the name of the input for eg. `my_field`
47
+ # will be `my_field` instead of the Rails default of `model[my_field]`.
48
+ #
49
+ # We achieve this by passing the `name` option to Rails form builder
50
+ # methods. These methods will use the passed name if provided instead
51
+ # of generating a scoped one.
52
+ #
53
+ # rubocop:disable Style/IfUnlessModifier
54
+ unless @input_arguments.delete(:scope_name_to_model) { true }
55
+ @input_arguments[:name] = name
56
+ end
57
+ # rubocop:enable Style/IfUnlessModifier
58
+
59
+ # If scope_id_to_model is false, the name of the input for eg. `my_field`
60
+ # will be `my_field` instead of the Rails default of `model_my_field`.
61
+ #
62
+ # We achieve this by passing the `id` option to Rails form builder
63
+ # methods. These methods will use the passed id if provided instead
64
+ # of generating a scoped one. The id is the name of the field unless
65
+ # explicitly provided in system_arguments.
66
+ #
67
+ # rubocop:disable Style/IfUnlessModifier
68
+ unless @input_arguments.delete(:scope_id_to_model) { true }
69
+ @input_arguments[:id] = @input_arguments.delete(:id) { name }
70
+ end
71
+ # rubocop:enable Style/IfUnlessModifier
72
+
73
+ # Whether or not to wrap the component in a FormControl, which renders a
74
+ # label above and validation message beneath the input.
75
+ @form_control = @input_arguments.delete(:form_control) { true }
76
+
44
77
  @input_arguments[:invalid] = "true" if invalid?
45
78
 
46
79
  base_id = SecureRandom.hex[0..5]
@@ -200,6 +233,22 @@ module Primer
200
233
  true
201
234
  end
202
235
 
236
+ def need_validation_element?
237
+ invalid?
238
+ end
239
+
240
+ def validation_arguments
241
+ {
242
+ class: "FormControl-inlineValidation",
243
+ id: validation_id,
244
+ hidden: valid?
245
+ }
246
+ end
247
+
248
+ def validation_message_arguments
249
+ {}
250
+ end
251
+
203
252
  private
204
253
 
205
254
  def input_data
@@ -34,19 +34,16 @@ module Primer
34
34
  check_one_input_visible!
35
35
  end
36
36
 
37
- def decorate_options(name: nil, **options)
38
- check_name!(name) if name
39
- new_options = { name: name || @name, label: nil, **options }
37
+ def decorate_options(name:, **options)
38
+ new_options = { name: @name, label: nil, form_control: false, **options }
39
+ new_options[:data] ||= {}
40
+ new_options[:data][:name] = name
41
+ new_options[:data][:targets] = "primer-multi-input.fields"
40
42
  new_options[:id] = nil if options[:hidden]
43
+ new_options[:disabled] = true if options[:hidden] # disable to avoid submitting to server
41
44
  new_options
42
45
  end
43
46
 
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
47
  def check_one_input_visible!
51
48
  return if inputs.count { |input| !input.hidden? } <= 1
52
49
 
@@ -5,7 +5,7 @@ module Primer
5
5
  module Dsl
6
6
  # :nodoc:
7
7
  class SelectListInput < Input
8
- SELECT_ARGUMENTS = %i[multiple disabled include_blank prompt].freeze
8
+ SELECT_ARGUMENTS = %i[multiple include_blank prompt].freeze
9
9
 
10
10
  # :nodoc:
11
11
  class Option
@@ -8,7 +8,7 @@ module Primer
8
8
  attr_reader(
9
9
  *%i[
10
10
  name label show_clear_button leading_visual clear_button_id
11
- visually_hide_label inset monospace field_wrap_classes
11
+ visually_hide_label inset monospace field_wrap_classes auto_check_src
12
12
  ]
13
13
  )
14
14
 
@@ -21,6 +21,7 @@ module Primer
21
21
  @clear_button_id = system_arguments.delete(:clear_button_id)
22
22
  @inset = system_arguments.delete(:inset)
23
23
  @monospace = system_arguments.delete(:monospace)
24
+ @auto_check_src = system_arguments.delete(:auto_check_src)
24
25
 
25
26
  super(**system_arguments)
26
27
 
@@ -29,6 +30,7 @@ module Primer
29
30
  Primer::Forms::Dsl::Input::SIZE_MAPPINGS[size]
30
31
  )
31
32
 
33
+ add_input_data(:target, "primer-text-field.inputElement") if auto_check_src.present?
32
34
  add_input_classes("FormControl-inset") if inset?
33
35
  add_input_classes("FormControl-monospace") if monospace?
34
36
  end
@@ -52,6 +54,34 @@ module Primer
52
54
  def leading_visual?
53
55
  !!@leading_visual
54
56
  end
57
+
58
+ def need_validation_element?
59
+ super || auto_check_src.present?
60
+ end
61
+
62
+ def validation_arguments
63
+ if auto_check_src.present?
64
+ super.merge(
65
+ data: {
66
+ target: "primer-text-field.validationElement"
67
+ }
68
+ )
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ def validation_message_arguments
75
+ if auto_check_src.present?
76
+ super.merge(
77
+ data: {
78
+ target: "primer-text-field.validationMessageElement"
79
+ }
80
+ )
81
+ else
82
+ super
83
+ end
84
+ end
55
85
  end
56
86
  end
57
87
  end
@@ -1,18 +1,22 @@
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>
1
+ <% if @input.form_control? %>
2
+ <%= content_tag(:div, **@form_group_arguments) do %>
3
+ <% if @input.label %>
4
+ <%= builder.label(@input.name, **@input.label_arguments) do %>
5
+ <%= @input.label %>
6
+ <% if @input.required? %>
7
+ <span aria-hidden="true">*</span>
8
+ <% end %>
7
9
  <% end %>
8
10
  <% end %>
11
+ <%= content %>
12
+ <% if @input.need_validation_element? %>
13
+ <%= content_tag(:div, **@input.validation_arguments) do %>
14
+ <%= render(Primer::Beta::Octicon.new(icon: :"alert-fill", size: :xsmall, aria: { hidden: true })) %>
15
+ <%= content_tag(:span, @input.validation_messages.first, **@input.validation_message_arguments) %>
16
+ <% end %>
17
+ <% end %>
18
+ <%= render(Caption.new(input: @input)) %>
9
19
  <% end %>
20
+ <% else %>
10
21
  <%= 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
22
  <% end %>
@@ -12,6 +12,8 @@ module Primer
12
12
  @form_group_arguments = {
13
13
  class: class_names(
14
14
  "FormControl",
15
+ "flex-1",
16
+ "width-full",
15
17
  "FormControl--fullWidth" => @input.full_width?
16
18
  )
17
19
  }
@@ -1,3 +1,3 @@
1
- <%= builder.fields_for(*@input.fields_for_args, **@input.fields_for_kwargs) do |fields| %>
1
+ <%= builder_or_view.primer_fields_for(*@input.fields_for_args, **@input.fields_for_kwargs) do |fields| %>
2
2
  <%= render(@input.ref_block.call(fields)) %>
3
3
  <% end %>
@@ -9,6 +9,10 @@ module Primer
9
9
  def initialize(input:)
10
10
  @input = input
11
11
  end
12
+
13
+ def builder_or_view
14
+ @input.nested? ? builder : @view_context
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -1,3 +1,7 @@
1
- <% @input.inputs.each do |child_input| %>
2
- <%= render(child_input.to_component) %>
1
+ <%= render(FormControl.new(input: @input)) do %>
2
+ <primer-multi-input data-name="<%= @input.name %>">
3
+ <% @input.inputs.each do |child_input| %>
4
+ <%= render(child_input.to_component) %>
5
+ <% end %>
6
+ </primer-multi-input>
3
7
  <% end %>
@@ -0,0 +1,10 @@
1
+ export declare class PrimerMultiInputElement extends HTMLElement {
2
+ fields: HTMLInputElement[];
3
+ activateField(name: string): void;
4
+ private findField;
5
+ }
6
+ declare global {
7
+ interface Window {
8
+ PrimerMultiInputElement: typeof PrimerMultiInputElement;
9
+ }
10
+ }
@@ -0,0 +1,45 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /* eslint-disable custom-elements/expose-class-on-global */
8
+ import { controller, targets } from '@github/catalyst';
9
+ let PrimerMultiInputElement = class PrimerMultiInputElement extends HTMLElement {
10
+ activateField(name) {
11
+ var _a, _b;
12
+ const fieldWithName = this.findField(name);
13
+ if (!fieldWithName)
14
+ return;
15
+ for (const field of this.fields) {
16
+ if (field === fieldWithName)
17
+ continue;
18
+ field.setAttribute('disabled', 'disabled');
19
+ field.setAttribute('hidden', 'hidden');
20
+ (_a = field.parentElement) === null || _a === void 0 ? void 0 : _a.setAttribute('hidden', 'hidden');
21
+ }
22
+ fieldWithName.removeAttribute('disabled');
23
+ fieldWithName.removeAttribute('hidden');
24
+ (_b = fieldWithName.parentElement) === null || _b === void 0 ? void 0 : _b.removeAttribute('hidden');
25
+ }
26
+ findField(name) {
27
+ for (const field of this.fields) {
28
+ if (field.getAttribute('data-name') === name) {
29
+ return field;
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+ };
35
+ __decorate([
36
+ targets
37
+ ], PrimerMultiInputElement.prototype, "fields", void 0);
38
+ PrimerMultiInputElement = __decorate([
39
+ controller
40
+ ], PrimerMultiInputElement);
41
+ export { PrimerMultiInputElement };
42
+ if (!window.customElements.get('primer-multi-input')) {
43
+ Object.assign(window, { PrimerMultiInputElement });
44
+ window.customElements.define('primer-multi-input', PrimerMultiInputElement);
45
+ }
@@ -0,0 +1,46 @@
1
+ /* eslint-disable custom-elements/expose-class-on-global */
2
+ import {controller, targets} from '@github/catalyst'
3
+
4
+ @controller
5
+ export class PrimerMultiInputElement extends HTMLElement {
6
+ @targets fields: HTMLInputElement[]
7
+
8
+ activateField(name: string) {
9
+ const fieldWithName = this.findField(name)
10
+ if (!fieldWithName) return
11
+
12
+ for (const field of this.fields) {
13
+ if (field === fieldWithName) continue
14
+
15
+ field.setAttribute('disabled', 'disabled')
16
+ field.setAttribute('hidden', 'hidden')
17
+
18
+ field.parentElement?.setAttribute('hidden', 'hidden')
19
+ }
20
+
21
+ fieldWithName.removeAttribute('disabled')
22
+ fieldWithName.removeAttribute('hidden')
23
+ fieldWithName.parentElement?.removeAttribute('hidden')
24
+ }
25
+
26
+ private findField(name: string): HTMLElement | null {
27
+ for (const field of this.fields) {
28
+ if (field.getAttribute('data-name') === name) {
29
+ return field
30
+ }
31
+ }
32
+
33
+ return null
34
+ }
35
+ }
36
+
37
+ declare global {
38
+ interface Window {
39
+ PrimerMultiInputElement: typeof PrimerMultiInputElement
40
+ }
41
+ }
42
+
43
+ if (!window.customElements.get('primer-multi-input')) {
44
+ Object.assign(window, {PrimerMultiInputElement})
45
+ window.customElements.define('primer-multi-input', PrimerMultiInputElement)
46
+ }
@@ -0,0 +1 @@
1
+ import '@github/auto-check-element';
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
13
+ if (kind === "m") throw new TypeError("Private method is not writable");
14
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
15
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
16
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
+ };
18
+ var _PrimerTextFieldElement_abortController;
19
+ import '@github/auto-check-element';
20
+ import { controller, target } from '@github/catalyst';
21
+ let PrimerTextFieldElement = class PrimerTextFieldElement extends HTMLElement {
22
+ constructor() {
23
+ super(...arguments);
24
+ _PrimerTextFieldElement_abortController.set(this, void 0);
25
+ }
26
+ connectedCallback() {
27
+ var _a;
28
+ (_a = __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
29
+ const { signal } = (__classPrivateFieldSet(this, _PrimerTextFieldElement_abortController, new AbortController(), "f"));
30
+ this.inputElement.addEventListener('auto-check-success', () => { this.clearError(); }, { signal });
31
+ this.inputElement.addEventListener('auto-check-error', (event) => {
32
+ event.detail.response.text().then((error_message) => { this.setError(error_message); });
33
+ }, { signal });
34
+ }
35
+ disconnectedCallback() {
36
+ var _a;
37
+ (_a = __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
38
+ }
39
+ clearError() {
40
+ this.inputElement.removeAttribute('invalid');
41
+ this.validationElement.hidden = true;
42
+ this.validationMessageElement.innerText = '';
43
+ }
44
+ setError(message) {
45
+ this.validationMessageElement.innerText = message;
46
+ this.validationElement.hidden = false;
47
+ this.inputElement.setAttribute('invalid', 'true');
48
+ }
49
+ };
50
+ _PrimerTextFieldElement_abortController = new WeakMap();
51
+ __decorate([
52
+ target
53
+ ], PrimerTextFieldElement.prototype, "inputElement", void 0);
54
+ __decorate([
55
+ target
56
+ ], PrimerTextFieldElement.prototype, "validationElement", void 0);
57
+ __decorate([
58
+ target
59
+ ], PrimerTextFieldElement.prototype, "validationMessageElement", void 0);
60
+ PrimerTextFieldElement = __decorate([
61
+ controller
62
+ ], PrimerTextFieldElement);
@@ -0,0 +1,48 @@
1
+ import '@github/auto-check-element'
2
+ import {controller, target} from '@github/catalyst'
3
+
4
+ @controller
5
+ class PrimerTextFieldElement extends HTMLElement {
6
+ @target inputElement: HTMLInputElement
7
+ @target validationElement: HTMLElement
8
+ @target validationMessageElement: HTMLElement
9
+
10
+ #abortController: AbortController | null
11
+
12
+ connectedCallback(): void {
13
+ this.#abortController?.abort()
14
+ const {signal} = (this.#abortController = new AbortController())
15
+
16
+ this.inputElement.addEventListener(
17
+ 'auto-check-success',
18
+ () => { this.clearError() },
19
+ {signal}
20
+ )
21
+
22
+ this.inputElement.addEventListener(
23
+ 'auto-check-error',
24
+ (event: any) => {
25
+ event.detail.response.text().then(
26
+ (error_message: string) => { this.setError(error_message) }
27
+ )
28
+ },
29
+ {signal}
30
+ )
31
+ }
32
+
33
+ disconnectedCallback() {
34
+ this.#abortController?.abort()
35
+ }
36
+
37
+ clearError(): void {
38
+ this.inputElement.removeAttribute('invalid')
39
+ this.validationElement.hidden = true
40
+ this.validationMessageElement.innerText = ''
41
+ }
42
+
43
+ setError(message: string): void {
44
+ this.validationMessageElement.innerText = message
45
+ this.validationElement.hidden = false
46
+ this.inputElement.setAttribute('invalid', 'true')
47
+ }
48
+ }
@@ -4,7 +4,9 @@
4
4
  <%= builder.label(@input.name, value: @input.value, **@input.label_arguments) do %>
5
5
  <%= @input.label %>
6
6
  <% end %>
7
- <%= render(Caption.new(input: @input)) %>
7
+ <% if @input.form_control? %>
8
+ <%= render(Caption.new(input: @input)) %>
9
+ <% end %>
8
10
  </span>
9
11
  <% end %>
10
12
  <% if @input.nested_form_block %>
@@ -1,19 +1,19 @@
1
- <%= render(FormControl.new(input: @input)) do %>
2
- <% if @input.leading_visual || @input.show_clear_button? %>
1
+ <%= render Primer::ConditionalWrapper.new(condition: @input.auto_check_src, tag: "primer-text-field") do %>
2
+ <%= render(FormControl.new(input: @input)) do %>
3
3
  <%= content_tag(:div, **@field_wrap_arguments) do %>
4
4
  <% if @input.leading_visual %>
5
5
  <span class="FormControl-input-leadingVisualWrap">
6
- <%= render(Primer::OcticonComponent.new(**@input.leading_visual)) %>
6
+ <%= render(Primer::Beta::Octicon.new(**@input.leading_visual)) %>
7
7
  </span>
8
8
  <% end %>
9
- <%= builder.text_field(@input.name, **@input.input_arguments) %>
9
+ <%= render Primer::ConditionalWrapper.new(condition: @input.auto_check_src, tag: "auto-check", csrf: auto_check_authenticity_token, src: @input.auto_check_src) do %>
10
+ <%= builder.text_field(@input.name, **@input.input_arguments) %>
11
+ <% end %>
10
12
  <% if @input.show_clear_button? %>
11
- <button id="<%= @input.clear_button_id %>" class="FormControl-input-trailingAction" aria-label="Clear">
12
- <%= render(Primer::OcticonComponent.new(icon: :"x-circle-fill")) %>
13
+ <button type="button" id="<%= @input.clear_button_id %>" class="FormControl-input-trailingAction" aria-label="Clear">
14
+ <%= render(Primer::Beta::Octicon.new(icon: :"x-circle-fill")) %>
13
15
  </button>
14
16
  <% end %>
15
17
  <% end %>
16
- <% else %>
17
- <%= builder.text_field(@input.name, **@input.input_arguments) %>
18
18
  <% end %>
19
19
  <% end %>
@@ -20,6 +20,17 @@ module Primer
20
20
  hidden: @input.hidden?
21
21
  }
22
22
  end
23
+
24
+ def auto_check_authenticity_token
25
+ return @auto_check_authenticity_token if defined?(@auto_check_authenticity_token)
26
+
27
+ @auto_check_authenticity_token =
28
+ if @input.auto_check_src
29
+ @view_context.form_authenticity_token(
30
+ form_options: { method: :post, action: @input.auto_check_src }
31
+ )
32
+ end
33
+ end
23
34
  end
24
35
  end
25
36
  end
@@ -40,7 +40,7 @@ module ERBLint
40
40
  if ast.method_name == :primer_octicon || ast.method_name == :octicon
41
41
  octicon_kwargs = ast.arguments[1]
42
42
  icon = icon(ast.arguments)
43
- elsif ast.method_name == :render && code.include?("Primer::OcticonComponent")
43
+ elsif ast.method_name == :render && code.include?("Primer::Beta::Octicon")
44
44
  octicon_kwargs = ast.arguments.first.arguments.last
45
45
  icon = icon(ast.arguments.first.arguments)
46
46
  else
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 0
9
- PATCH = 114
9
+ PATCH = 116
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
data/lib/tasks/docs.rake CHANGED
@@ -37,7 +37,7 @@ namespace :docs do
37
37
  Primer::HellipButton,
38
38
  Primer::Alpha::Image,
39
39
  Primer::LocalTime,
40
- Primer::OcticonSymbolsComponent,
40
+ Primer::Alpha::OcticonSymbols,
41
41
  Primer::Alpha::ImageCrop,
42
42
  Primer::IconButton,
43
43
  Primer::Beta::AutoComplete,
@@ -68,13 +68,13 @@ namespace :docs do
68
68
  Primer::LayoutComponent,
69
69
  Primer::Beta::Link,
70
70
  Primer::Beta::Markdown,
71
- Primer::MenuComponent,
71
+ Primer::Alpha::Menu,
72
72
  Primer::Navigation::TabComponent,
73
- Primer::OcticonComponent,
73
+ Primer::Beta::Octicon,
74
74
  Primer::Beta::Popover,
75
75
  Primer::Beta::ProgressBar,
76
76
  Primer::StateComponent,
77
- Primer::SpinnerComponent,
77
+ Primer::Beta::Spinner,
78
78
  Primer::SubheadComponent,
79
79
  Primer::TabContainerComponent,
80
80
  Primer::Beta::Text,
@@ -515,7 +515,7 @@ namespace :docs do
515
515
  def lookbook_url(component)
516
516
  path = component.name.underscore.gsub("_component", "")
517
517
 
518
- "https://primer.style/view-components/lookbook/inspect/#{path}/default/"
518
+ "https://primer.style/view-components/lookbook/inspect/#{path}_preview/default/"
519
519
  end
520
520
 
521
521
  def preview_exists?(component)
@@ -54,7 +54,7 @@ class AstTraverser
54
54
  end
55
55
 
56
56
  # Octicon is the only component that accepts positional arguments.
57
- res[:icon] = args.first.source if name == "Primer::OcticonComponent" && args.size > 1
57
+ res[:icon] = args.first.source if name == "Primer::Beta::Octicon" && args.size > 1
58
58
 
59
59
  res
60
60
  end
@@ -169,7 +169,7 @@ module Primer
169
169
  tooltip: false
170
170
  )
171
171
  list = Primer::Alpha::ActionList.new(aria: { label: "Action List" })
172
- list.item(
172
+ list.with_item(
173
173
  label: label,
174
174
  truncate_label: truncate_label,
175
175
  href: href,