primer_view_components 0.1.7 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -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/divider.rb +1 -1
  8. data/app/components/primer/alpha/action_list/heading.html.erb +2 -2
  9. data/app/components/primer/alpha/action_list/heading.rb +9 -5
  10. data/app/components/primer/alpha/action_list/item.rb +1 -3
  11. data/app/components/primer/alpha/action_list.css +1 -1
  12. data/app/components/primer/alpha/action_list.css.json +1 -0
  13. data/app/components/primer/alpha/action_list.css.map +1 -1
  14. data/app/components/primer/alpha/action_list.html.erb +1 -0
  15. data/app/components/primer/alpha/action_list.pcss +5 -0
  16. data/app/components/primer/alpha/action_list.rb +14 -11
  17. data/app/components/primer/alpha/action_menu.rb +1 -1
  18. data/app/components/primer/alpha/dialog.rb +4 -0
  19. data/app/components/primer/alpha/modal_dialog.js +6 -0
  20. data/app/components/primer/alpha/modal_dialog.ts +6 -0
  21. data/app/components/primer/alpha/nav_list/divider.rb +14 -0
  22. data/app/components/primer/alpha/nav_list/group.html.erb +7 -0
  23. data/app/components/primer/alpha/nav_list/group.rb +24 -11
  24. data/app/components/primer/alpha/nav_list/item.rb +4 -0
  25. data/app/components/primer/alpha/nav_list.d.ts +0 -1
  26. data/app/components/primer/alpha/nav_list.html.erb +9 -4
  27. data/app/components/primer/alpha/nav_list.js +3 -4
  28. data/app/components/primer/alpha/nav_list.rb +87 -10
  29. data/app/components/primer/alpha/nav_list.ts +3 -2
  30. data/app/components/primer/alpha/overlay/header.html.erb +5 -3
  31. data/app/components/primer/alpha/overlay/header.rb +4 -1
  32. data/app/components/primer/alpha/overlay.css +1 -1
  33. data/app/components/primer/alpha/overlay.css.json +1 -1
  34. data/app/components/primer/alpha/overlay.css.map +1 -1
  35. data/app/components/primer/alpha/overlay.pcss +1 -1
  36. data/app/components/primer/alpha/overlay.rb +1 -0
  37. data/app/components/primer/alpha/segmented_control.css +1 -1
  38. data/app/components/primer/alpha/segmented_control.css.json +2 -2
  39. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  40. data/app/components/primer/alpha/segmented_control.pcss +10 -8
  41. data/app/components/primer/alpha/text_field.css +1 -1
  42. data/app/components/primer/alpha/text_field.css.json +11 -11
  43. data/app/components/primer/alpha/text_field.css.map +1 -1
  44. data/app/components/primer/alpha/text_field.pcss +2 -2
  45. data/app/components/primer/alpha/toggle_switch.css +1 -1
  46. data/app/components/primer/alpha/toggle_switch.css.json +11 -11
  47. data/app/components/primer/alpha/toggle_switch.css.map +1 -1
  48. data/app/components/primer/alpha/toggle_switch.d.ts +1 -1
  49. data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
  50. data/app/components/primer/alpha/toggle_switch.js +44 -42
  51. data/app/components/primer/alpha/toggle_switch.pcss +4 -4
  52. data/app/components/primer/alpha/toggle_switch.rb +7 -0
  53. data/app/components/primer/alpha/toggle_switch.ts +50 -41
  54. data/app/components/primer/beta/auto_complete.rb +1 -1
  55. data/app/components/primer/beta/button.css +1 -1
  56. data/app/components/primer/beta/button.css.json +2 -0
  57. data/app/components/primer/beta/button.css.map +1 -1
  58. data/app/components/primer/beta/button.pcss +9 -0
  59. data/app/components/primer/component.rb +3 -96
  60. data/app/components/primer/focus_group.js +10 -6
  61. data/app/components/primer/focus_group.ts +10 -5
  62. data/app/lib/primer/attributes_helper.rb +105 -0
  63. data/lib/primer/forms/dsl/input.rb +4 -8
  64. data/lib/primer/forms/dsl/text_field_input.rb +0 -4
  65. data/lib/primer/forms/dsl/toggle_switch_input.rb +4 -0
  66. data/lib/primer/forms/form_control.html.erb +3 -5
  67. data/lib/primer/forms/primer_base_component_wrapper.html.erb +3 -0
  68. data/lib/primer/forms/primer_base_component_wrapper.rb +24 -0
  69. data/lib/primer/forms/text_field.rb +6 -0
  70. data/lib/primer/forms/toggle_switch.html.erb +3 -3
  71. data/lib/primer/forms/toggle_switch.rb +6 -2
  72. data/lib/primer/forms/toggle_switch_input.js +7 -2
  73. data/lib/primer/forms/toggle_switch_input.ts +9 -2
  74. data/lib/primer/static/generate_info_arch.rb +3 -0
  75. data/lib/primer/view_components/version.rb +1 -1
  76. data/lib/primer/yard/component_manifest.rb +1 -1
  77. data/lib/primer/yard/lookbook_pages_backend.rb +7 -1
  78. data/lib/primer/yard/registry.rb +4 -0
  79. data/previews/primer/alpha/nav_list_preview/trailing_action.html.erb +10 -10
  80. data/previews/primer/alpha/nav_list_preview.rb +37 -16
  81. data/previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb +19 -0
  82. data/previews/primer/alpha/overlay_preview.rb +31 -0
  83. data/previews/primer/beta/button_preview/trailing_counter.html.erb +11 -0
  84. data/previews/primer/beta/button_preview.rb +15 -0
  85. data/previews/primer/box_preview.rb +28 -0
  86. data/static/arguments.json +29 -13
  87. data/static/audited_at.json +1 -0
  88. data/static/classes.json +3 -0
  89. data/static/constants.json +3 -0
  90. data/static/info_arch.json +448 -20
  91. data/static/previews.json +43 -0
  92. data/static/statuses.json +1 -0
  93. metadata +10 -9
  94. data/lib/tasks/docs.rake +0 -185
  95. data/lib/tasks/helpers/ast_processor.rb +0 -44
  96. data/lib/tasks/helpers/ast_traverser.rb +0 -77
  97. data/lib/tasks/primer_view_components.rake +0 -47
  98. data/lib/tasks/static.rake +0 -29
  99. data/lib/tasks/test.rake +0 -83
  100. data/lib/tasks/utilities.rake +0 -109
@@ -16,6 +16,7 @@ module Primer
16
16
  include ViewComponent::PolymorphicSlots
17
17
  end
18
18
 
19
+ include AttributesHelper
19
20
  include ClassNameHelper
20
21
  include FetchOrFallbackHelper
21
22
  include TestSelectorHelper
@@ -25,15 +26,13 @@ module Primer
25
26
  include Audited::Dsl
26
27
 
27
28
  INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze
28
- PLURAL_ARIA_ATTRIBUTES = %i[describedby labelledby].freeze
29
- PLURAL_DATA_ATTRIBUTES = %i[target targets].freeze
30
29
 
31
30
  def self.deprecated?
32
31
  status == :deprecated
33
32
  end
34
33
 
35
- def self.generate_id
36
- "#{name.demodulize.underscore.dasherize}-#{SecureRandom.uuid}"
34
+ def self.generate_id(base_name: name.demodulize.underscore.dasherize)
35
+ "#{base_name}-#{SecureRandom.uuid}"
37
36
  end
38
37
 
39
38
  private
@@ -56,98 +55,6 @@ module Primer
56
55
  ActiveSupport::Deprecation.warn(message)
57
56
  end
58
57
 
59
- def aria(val, system_arguments)
60
- system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
61
- end
62
-
63
- # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
64
- # each hash and returns them in the new hash.
65
- #
66
- # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
67
- # => { disabled: "true", invalid: "true" }
68
- #
69
- # Certain aria attributes can contain multiple values separated by spaces. merge_aria
70
- # will combine these plural attributes into a composite string.
71
- #
72
- # Eg. merge_aria({ "aria-labelledby": "foo" }, { aria: { labelledby: "bar" } })
73
- # => { labelledby: "foo bar" }
74
- #
75
- # It's designed to be used to normalize and merge aria information from system_arguments
76
- # hashes. Consider using this pattern in component initializers:
77
- #
78
- # @system_arguments[:aria] = merge_aria(
79
- # @system_arguments,
80
- # { aria: { labelled_by: id } }
81
- # )
82
- def merge_aria(*hashes)
83
- merge_prefixed_attribute_hashes(
84
- *hashes, prefix: :aria, plural_keys: PLURAL_ARIA_ATTRIBUTES
85
- )
86
- end
87
-
88
- # Merges hashes that contain "data-*" keys and nested data: hashes. Removes keys from
89
- # each hash and returns them in the new hash.
90
- #
91
- # Eg. merge_data({ "data-foo": "true" }, { data: { bar: "true" } })
92
- # => { foo: "true", bar: "true" }
93
- #
94
- # Certain data attributes can contain multiple values separated by spaces. merge_data
95
- # will combine these plural attributes into a composite string.
96
- #
97
- # Eg. merge_data({ "data-target": "foo" }, { data: { target: "bar" } })
98
- # => { target: "foo bar" }
99
- #
100
- # It's designed to be used to normalize and merge data information from system_arguments
101
- # hashes. Consider using this pattern in component initializers:
102
- #
103
- # @system_arguments[:data] = merge_aria(
104
- # @system_arguments,
105
- # { data: { foo: "bar" } }
106
- # )
107
- def merge_data(*hashes)
108
- merge_prefixed_attribute_hashes(
109
- *hashes, prefix: :data, plural_keys: PLURAL_DATA_ATTRIBUTES
110
- )
111
- end
112
-
113
- def merge_prefixed_attribute_hashes(*hashes, prefix:, plural_keys:)
114
- {}.tap do |result|
115
- hashes.each do |hash|
116
- next unless hash
117
-
118
- prefix_hash = hash.delete(prefix) || {}
119
-
120
- prefix_hash.each_pair do |key, val|
121
- result[key] =
122
- if plural_keys.include?(key)
123
- [*(result[key] || "").split, val].join(" ").strip
124
- else
125
- val
126
- end
127
- end
128
-
129
- hash.delete_if do |key, val|
130
- key_s = key.to_s
131
-
132
- if key.start_with?("#{prefix}-")
133
- bare_key = key_s.sub("#{prefix}-", "").to_sym
134
-
135
- result[bare_key] =
136
- if plural_keys.include?(bare_key)
137
- [*(result[bare_key] || "").split, val].join(" ").strip
138
- else
139
- val
140
- end
141
-
142
- true
143
- else
144
- false
145
- end
146
- end
147
- end
148
- end
149
- end
150
-
151
58
  def validate_aria_label
152
59
  aria_label = aria("label", @system_arguments)
153
60
  aria_labelledby = aria("labelledby", @system_arguments)
@@ -14,11 +14,11 @@ import '@oddbird/popover-polyfill';
14
14
  const menuItemSelector = '[role="menuitem"],[role="menuitemcheckbox"],[role="menuitemradio"]';
15
15
  const popoverSelector = (() => {
16
16
  try {
17
- document.querySelector(':open');
18
- return ':open';
17
+ document.querySelector(':popover-open');
18
+ return ':popover-open';
19
19
  }
20
20
  catch (_a) {
21
- return '.\\:open';
21
+ return '.\\:popover-open';
22
22
  }
23
23
  })();
24
24
  const getMnemonicFor = (item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim()[0].toLowerCase(); };
@@ -80,28 +80,34 @@ export default class FocusGroupElement extends HTMLElement {
80
80
  if (key === 'Up' || key === 'ArrowUp') {
81
81
  if (direction === 'vertical' || direction === 'both') {
82
82
  index -= index < 0 ? 0 : 1;
83
+ event.preventDefault();
83
84
  }
84
85
  }
85
86
  else if (key === 'Down' || key === 'ArrowDown') {
86
87
  if (direction === 'vertical' || direction === 'both') {
87
88
  index += 1;
89
+ event.preventDefault();
88
90
  }
89
91
  }
90
92
  else if (event.key === 'Left' || event.key === 'ArrowLeft') {
91
93
  if (direction === 'horizontal' || direction === 'both') {
92
94
  index -= 1;
95
+ event.preventDefault();
93
96
  }
94
97
  }
95
98
  else if (event.key === 'Right' || event.key === 'ArrowRight') {
96
99
  if (direction === 'horizontal' || direction === 'both') {
97
100
  index += 1;
101
+ event.preventDefault();
98
102
  }
99
103
  }
100
104
  else if (event.key === 'Home' || event.key === 'PageUp') {
101
105
  index = 0;
106
+ event.preventDefault();
102
107
  }
103
108
  else if (event.key === 'End' || event.key === 'PageDown') {
104
109
  index = items.length - 1;
110
+ event.preventDefault();
105
111
  }
106
112
  else if (this.mnemonics && printable.test(key)) {
107
113
  const mnemonic = key.toLowerCase();
@@ -126,9 +132,7 @@ export default class FocusGroupElement extends HTMLElement {
126
132
  if ((el === null || el === void 0 ? void 0 : el.popover) === 'auto') {
127
133
  el.showPopover();
128
134
  }
129
- else {
130
- el = (el === null || el === void 0 ? void 0 : el.parentElement) || null;
131
- }
135
+ el = (el === null || el === void 0 ? void 0 : el.parentElement) || null;
132
136
  } while (el);
133
137
  }
134
138
  focusEl === null || focusEl === void 0 ? void 0 : focusEl.focus();
@@ -4,10 +4,10 @@ const menuItemSelector = '[role="menuitem"],[role="menuitemcheckbox"],[role="men
4
4
 
5
5
  const popoverSelector = (() => {
6
6
  try {
7
- document.querySelector(':open')
8
- return ':open'
7
+ document.querySelector(':popover-open')
8
+ return ':popover-open'
9
9
  } catch {
10
- return '.\\:open'
10
+ return '.\\:popover-open'
11
11
  }
12
12
  })()
13
13
 
@@ -79,23 +79,29 @@ export default class FocusGroupElement extends HTMLElement {
79
79
  if (key === 'Up' || key === 'ArrowUp') {
80
80
  if (direction === 'vertical' || direction === 'both') {
81
81
  index -= index < 0 ? 0 : 1
82
+ event.preventDefault()
82
83
  }
83
84
  } else if (key === 'Down' || key === 'ArrowDown') {
84
85
  if (direction === 'vertical' || direction === 'both') {
85
86
  index += 1
87
+ event.preventDefault()
86
88
  }
87
89
  } else if (event.key === 'Left' || event.key === 'ArrowLeft') {
88
90
  if (direction === 'horizontal' || direction === 'both') {
89
91
  index -= 1
92
+ event.preventDefault()
90
93
  }
91
94
  } else if (event.key === 'Right' || event.key === 'ArrowRight') {
92
95
  if (direction === 'horizontal' || direction === 'both') {
93
96
  index += 1
97
+ event.preventDefault()
94
98
  }
95
99
  } else if (event.key === 'Home' || event.key === 'PageUp') {
96
100
  index = 0
101
+ event.preventDefault()
97
102
  } else if (event.key === 'End' || event.key === 'PageDown') {
98
103
  index = items.length - 1
104
+ event.preventDefault()
99
105
  } else if (this.mnemonics && printable.test(key)) {
100
106
  const mnemonic = key.toLowerCase()
101
107
  const offset = index > 0 && getMnemonicFor(event.target as Element) === mnemonic ? index : 0
@@ -115,9 +121,8 @@ export default class FocusGroupElement extends HTMLElement {
115
121
  el = el.closest(`[popover]:not(${popoverSelector})`)
116
122
  if (el?.popover === 'auto') {
117
123
  el.showPopover()
118
- } else {
119
- el = el?.parentElement || null
120
124
  }
125
+ el = el?.parentElement || null
121
126
  } while (el)
122
127
  }
123
128
  focusEl?.focus()
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # :nodoc:
5
+ module AttributesHelper
6
+ PLURAL_ARIA_ATTRIBUTES = %i[describedby labelledby].freeze
7
+ PLURAL_DATA_ATTRIBUTES = %i[target targets].freeze
8
+
9
+ def aria(val, system_arguments)
10
+ system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
11
+ end
12
+
13
+ def data(val, system_arguments)
14
+ system_arguments[:"data-#{val}"] || system_arguments.dig(:data, val.to_sym)
15
+ end
16
+
17
+ # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
18
+ # each hash and returns them in the new hash.
19
+ #
20
+ # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
21
+ # => { disabled: "true", invalid: "true" }
22
+ #
23
+ # Certain aria attributes can contain multiple values separated by spaces. merge_aria
24
+ # will combine these plural attributes into a composite string.
25
+ #
26
+ # Eg. merge_aria({ "aria-labelledby": "foo" }, { aria: { labelledby: "bar" } })
27
+ # => { labelledby: "foo bar" }
28
+ #
29
+ # It's designed to be used to normalize and merge aria information from system_arguments
30
+ # hashes. Consider using this pattern in component initializers:
31
+ #
32
+ # @system_arguments[:aria] = merge_aria(
33
+ # @system_arguments,
34
+ # { aria: { labelled_by: id } }
35
+ # )
36
+ def merge_aria(*hashes)
37
+ merge_prefixed_attribute_hashes(
38
+ *hashes, prefix: :aria, plural_keys: PLURAL_ARIA_ATTRIBUTES
39
+ )
40
+ end
41
+
42
+ # Merges hashes that contain "data-*" keys and nested data: hashes. Removes keys from
43
+ # each hash and returns them in the new hash.
44
+ #
45
+ # Eg. merge_data({ "data-foo": "true" }, { data: { bar: "true" } })
46
+ # => { foo: "true", bar: "true" }
47
+ #
48
+ # Certain data attributes can contain multiple values separated by spaces. merge_data
49
+ # will combine these plural attributes into a composite string.
50
+ #
51
+ # Eg. merge_data({ "data-target": "foo" }, { data: { target: "bar" } })
52
+ # => { target: "foo bar" }
53
+ #
54
+ # It's designed to be used to normalize and merge data information from system_arguments
55
+ # hashes. Consider using this pattern in component initializers:
56
+ #
57
+ # @system_arguments[:data] = merge_aria(
58
+ # @system_arguments,
59
+ # { data: { foo: "bar" } }
60
+ # )
61
+ def merge_data(*hashes)
62
+ merge_prefixed_attribute_hashes(
63
+ *hashes, prefix: :data, plural_keys: PLURAL_DATA_ATTRIBUTES
64
+ )
65
+ end
66
+
67
+ def merge_prefixed_attribute_hashes(*hashes, prefix:, plural_keys:)
68
+ {}.tap do |result|
69
+ hashes.each do |hash|
70
+ next unless hash
71
+
72
+ prefix_hash = hash.delete(prefix) || {}
73
+
74
+ prefix_hash.each_pair do |key, val|
75
+ result[key] =
76
+ if plural_keys.include?(key)
77
+ [*(result[key] || "").split, val].join(" ").strip
78
+ else
79
+ val
80
+ end
81
+ end
82
+
83
+ hash.delete_if do |key, val|
84
+ key_s = key.to_s
85
+
86
+ if key.start_with?("#{prefix}-")
87
+ bare_key = key_s.sub("#{prefix}-", "").to_sym
88
+
89
+ result[bare_key] =
90
+ if plural_keys.include?(bare_key)
91
+ [*(result[bare_key] || "").split, val].join(" ").strip
92
+ else
93
+ val
94
+ end
95
+
96
+ true
97
+ else
98
+ false
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -47,7 +47,7 @@ module Primer
47
47
 
48
48
  include Primer::ClassNameHelper
49
49
 
50
- attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids, :form_control
50
+ attr_reader :builder, :form, :input_arguments, :label_arguments, :caption, :validation_message, :ids, :form_control, :base_id
51
51
 
52
52
  alias form_control? form_control
53
53
 
@@ -107,11 +107,11 @@ module Primer
107
107
 
108
108
  @input_arguments[:invalid] = "true" if invalid?
109
109
 
110
- base_id = SecureRandom.uuid
110
+ @base_id = SecureRandom.uuid
111
111
 
112
112
  @ids = {}.tap do |id_map|
113
- id_map[:validation] = "validation-#{base_id}" if invalid?
114
- id_map[:caption] = "caption-#{base_id}" if caption? || caption_template?
113
+ id_map[:validation] = "validation-#{@base_id}"
114
+ id_map[:caption] = "caption-#{@base_id}" if caption? || caption_template?
115
115
  end
116
116
 
117
117
  add_input_aria(:required, true) if required?
@@ -264,10 +264,6 @@ module Primer
264
264
  true
265
265
  end
266
266
 
267
- def need_validation_element?
268
- invalid?
269
- end
270
-
271
267
  def validation_arguments
272
268
  {
273
269
  class: "FormControl-inlineValidation",
@@ -57,10 +57,6 @@ module Primer
57
57
  !!@leading_visual
58
58
  end
59
59
 
60
- def need_validation_element?
61
- super || auto_check_src.present?
62
- end
63
-
64
60
  def validation_arguments
65
61
  if auto_check_src.present?
66
62
  super.merge(
@@ -29,6 +29,10 @@ module Primer
29
29
  def type
30
30
  :toggle_switch
31
31
  end
32
+
33
+ def validation_arguments
34
+ super.merge(role: "alert")
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -9,11 +9,9 @@
9
9
  <% end %>
10
10
  <% end %>
11
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 %>
12
+ <%= content_tag(:div, **@input.validation_arguments) do %>
13
+ <%= render(Primer::Beta::Octicon.new(icon: :"alert-fill", size: :xsmall, aria: { hidden: true })) %>
14
+ <%= content_tag(:span, @input.invalid? ? @input.validation_messages.first : "", **@input.validation_message_arguments) %>
17
15
  <% end %>
18
16
  <%= render(Caption.new(input: @input)) %>
19
17
  <% end %>
@@ -0,0 +1,3 @@
1
+ <%= render(Primer::BaseComponent.new(classes: @classes, **@system_arguments)) do %>
2
+ <%= content %>
3
+ <% end %>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "primer/class_name_helper"
4
+
5
+ module Primer
6
+ module Forms
7
+ # Wraps Primer::BaseComponent.
8
+ class PrimerBaseComponentWrapper < BaseComponent
9
+ include Primer::ClassNameHelper
10
+
11
+ def initialize(**system_arguments)
12
+ @system_arguments = system_arguments
13
+
14
+ # Extract class and classes so they can be passed to Primer::BaseComponent
15
+ # as classes:. The class: argument is expected by Rails, but Primer expects
16
+ # classes:, reminiscent of HashWithIndifferentAccess shenanigans.
17
+ @classes = class_names(
18
+ system_arguments.delete(:classes),
19
+ system_arguments.delete(:class)
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -6,6 +6,11 @@ module Primer
6
6
  class TextField < BaseComponent
7
7
  delegate :builder, :form, to: :@input
8
8
 
9
+ INPUT_WRAP_SIZE = {
10
+ small: "FormControl-input-wrap--small",
11
+ large: "FormControl-input-wrap--large"
12
+ }.freeze
13
+
9
14
  def initialize(input:)
10
15
  @input = input
11
16
 
@@ -17,6 +22,7 @@ module Primer
17
22
  @field_wrap_arguments = {
18
23
  class: class_names(
19
24
  "FormControl-input-wrap",
25
+ INPUT_WRAP_SIZE[input.size],
20
26
  "FormControl-input-wrap--trailingAction": @input.show_clear_button?,
21
27
  "FormControl-input-wrap--leadingVisual": @input.leading_visual?
22
28
  ),
@@ -1,6 +1,6 @@
1
- <%= content_tag("toggle-switch-input", **@input.input_arguments) do %>
1
+ <%= content_tag("toggle-switch-input", class: "FormControl-toggleSwitchInput", hidden: @input.hidden?) do %>
2
2
  <span style="flex-grow: 1">
3
- <%= builder.label(@input.name, **@input.label_arguments) do %>
3
+ <%= render(Primer::Forms::PrimerBaseComponentWrapper.new(tag: :span, **@input.label_arguments)) do %>
4
4
  <%= @input.label %>
5
5
  <% end %>
6
6
 
@@ -18,5 +18,5 @@
18
18
  }
19
19
  )
20
20
  %>
21
- <%= render(Primer::Alpha::ToggleSwitch.new(src: @input.src, csrf: csrf)) %>
21
+ <%= render(Primer::Alpha::ToggleSwitch.new(src: @input.src, csrf: csrf, **@input.input_arguments)) %>
22
22
  <% end %>
@@ -9,8 +9,12 @@ module Primer
9
9
  def initialize(input:)
10
10
  @input = input
11
11
  @input.add_label_classes("FormControl-label")
12
- @input.add_input_classes("FormControl-toggleSwitchInput")
13
- @input.input_arguments[:hidden] = "hidden" if @input.hidden?
12
+ @input.label_arguments[:id] = label_id
13
+ @input.add_input_aria(:labelledby, label_id)
14
+ end
15
+
16
+ def label_id
17
+ @label_id ||= "label-#{@input.base_id}"
14
18
  end
15
19
  end
16
20
  end
@@ -1,3 +1,4 @@
1
+ /* eslint-disable custom-elements/expose-class-on-global */
1
2
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
3
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
4
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -8,11 +9,15 @@ import { controller, target } from '@github/catalyst';
8
9
  let ToggleSwitchInputElement = class ToggleSwitchInputElement extends HTMLElement {
9
10
  connectedCallback() {
10
11
  this.addEventListener('toggleSwitchError', (event) => {
11
- this.validationMessageElement.innerText = event.detail;
12
+ this.validationMessageElement.textContent = event.detail;
12
13
  this.validationElement.removeAttribute('hidden');
13
14
  });
14
15
  this.addEventListener('toggleSwitchSuccess', () => {
15
- this.validationMessageElement.innerText = '';
16
+ this.validationMessageElement.textContent = '';
17
+ this.validationElement.setAttribute('hidden', 'hidden');
18
+ });
19
+ this.addEventListener('toggleSwitchLoading', () => {
20
+ this.validationMessageElement.textContent = '';
16
21
  this.validationElement.setAttribute('hidden', 'hidden');
17
22
  });
18
23
  }
@@ -1,3 +1,5 @@
1
+ /* eslint-disable custom-elements/expose-class-on-global */
2
+
1
3
  import {controller, target} from '@github/catalyst'
2
4
 
3
5
  @controller
@@ -7,12 +9,17 @@ export class ToggleSwitchInputElement extends HTMLElement {
7
9
 
8
10
  connectedCallback() {
9
11
  this.addEventListener('toggleSwitchError', (event: Event) => {
10
- this.validationMessageElement.innerText = (event as CustomEvent).detail
12
+ this.validationMessageElement.textContent = (event as CustomEvent).detail
11
13
  this.validationElement.removeAttribute('hidden')
12
14
  })
13
15
 
14
16
  this.addEventListener('toggleSwitchSuccess', () => {
15
- this.validationMessageElement.innerText = ''
17
+ this.validationMessageElement.textContent = ''
18
+ this.validationElement.setAttribute('hidden', 'hidden')
19
+ })
20
+
21
+ this.addEventListener('toggleSwitchLoading', () => {
22
+ this.validationMessageElement.textContent = ''
16
23
  this.validationElement.setAttribute('hidden', 'hidden')
17
24
  })
18
25
  }
@@ -72,6 +72,9 @@ module Primer
72
72
  memo[component] = {
73
73
  "fully_qualified_name" => component.name,
74
74
  "description" => description,
75
+ "is_form_component" => docs.manifest_entry.form_component?,
76
+ "is_published" => docs.manifest_entry.published?,
77
+ "requires_js" => docs.manifest_entry.requires_js?,
75
78
  **arg_data,
76
79
  "slots" => slot_docs,
77
80
  "methods" => method_docs,
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 1
9
- PATCH = 7
9
+ PATCH = 9
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -129,7 +129,7 @@ module Primer
129
129
  end
130
130
 
131
131
  def ref_for(klass)
132
- ref_cache[klass] ||= ComponentRef.new(klass, COMPONENTS[klass])
132
+ ref_cache[klass] ||= ComponentRef.new(klass, COMPONENTS.fetch(klass, {}))
133
133
  end
134
134
 
135
135
  private
@@ -10,7 +10,7 @@ module Primer
10
10
  PREVIEW_MAP = {
11
11
  Primer::Alpha::TextField => [:single_text_field_form, :multi_text_field_form],
12
12
  Primer::Alpha::TextArea => [],
13
- Primer::Alpha::Select => [:select_list_form],
13
+ Primer::Alpha::Select => [:select_form],
14
14
  Primer::Alpha::MultiInput => [:multi_input_form],
15
15
  Primer::Alpha::RadioButton => [:radio_button_with_nested_form],
16
16
  Primer::Alpha::RadioButtonGroup => [:radio_button_group_form],
@@ -49,6 +49,12 @@ module Primer
49
49
 
50
50
  preview_methods = PREVIEW_MAP[component]
51
51
  preview_erbs = preview_methods.map do |preview_method|
52
+ # rubocop:disable Style/IfUnlessModifier
53
+ if Primer::Forms::FormsPreview.instance_methods.exclude?(preview_method)
54
+ raise "Preview '#{preview_method}' does not exist in Primer::Forms::FormsPreview"
55
+ end
56
+ # rubocop:enable Style/IfUnlessModifier
57
+
52
58
  "<%= embed Primer::Forms::FormsPreview, #{preview_method.inspect} %>"
53
59
  end
54
60
  # rubocop:enable Lint/UselessAssignment
@@ -89,6 +89,10 @@ module Primer
89
89
  def a11y_reviewed?
90
90
  metadata[:a11y_reviewed]
91
91
  end
92
+
93
+ def manifest_entry
94
+ @manifest_entry ||= ComponentManifest.ref_for(component)
95
+ end
92
96
  end
93
97
 
94
98
  # Wrapper around an instance of YARD::Registry that provides easy access to component
@@ -1,19 +1,19 @@
1
- <%= render(Primer::Alpha::NavList.new) do |list| %>
1
+ <%= render(Primer::Alpha::NavList.new(aria: { label: "Workflow results" })) do |list| %>
2
2
  <% list.with_group do |group| %>
3
- <%= group.with_heading(title: "Shopping list") %>
4
- <% group.with_item(label: "Bread", href: "/list/1") do |item| %>
5
- <%= item.with_trailing_action(icon: :plus, aria: { label: "Activate alert" }, name: "bread_button") %>
3
+ <% group.with_heading(title: "Workflows") %>
4
+ <% group.with_item(label: "Build and Test", href: "/workflows/1") do |item| %>
5
+ <%= item.with_trailing_action(icon: :sync, aria: { label: "Build and test: re-run workflow" }, name: "build_and_test_button") %>
6
6
  <% end %>
7
- <% group.with_item(label: "Cheese", href: "/list/2") do |item| %>
8
- <%= item.with_trailing_action(icon: :plus, aria: { label: "Activate alert" }, name: "cheese_button") %>
7
+ <% group.with_item(label: "Publish", href: "/workflows/2") do |item| %>
8
+ <%= item.with_trailing_action(icon: :sync, aria: { label: "Publish: re-run workflow" }, name: "publish_button") %>
9
9
  <% end %>
10
10
  <% end %>
11
11
  <% end %>
12
12
 
13
13
  <script type="text/javascript" data-eval="true">
14
- const breadButton = document.querySelector("[name=bread_button]")
15
- breadButton.addEventListener("click", () => alert("You selected bread."))
14
+ const breadButton = document.querySelector("[name=build_and_test_button]")
15
+ breadButton.addEventListener("click", () => alert("The 'Build and Test' workflow will be re-run."))
16
16
 
17
- const cheeseButton = document.querySelector("[name=cheese_button]")
18
- cheeseButton.addEventListener("click", () => alert("You selected cheese."))
17
+ const cheeseButton = document.querySelector("[name=publish_button]")
18
+ cheeseButton.addEventListener("click", () => alert("The 'Publish' workflow will be re-run."))
19
19
  </script>