primer_view_components 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -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 +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/item.rb +1 -3
  8. data/app/components/primer/alpha/action_menu.rb +1 -1
  9. data/app/components/primer/alpha/modal_dialog.js +6 -0
  10. data/app/components/primer/alpha/modal_dialog.ts +6 -0
  11. data/app/components/primer/alpha/overlay/header.html.erb +5 -3
  12. data/app/components/primer/alpha/overlay/header.rb +4 -1
  13. data/app/components/primer/alpha/overlay.css +1 -1
  14. data/app/components/primer/alpha/overlay.css.json +1 -1
  15. data/app/components/primer/alpha/overlay.css.map +1 -1
  16. data/app/components/primer/alpha/overlay.pcss +1 -1
  17. data/app/components/primer/alpha/overlay.rb +1 -0
  18. data/app/components/primer/alpha/toggle_switch.css +1 -1
  19. data/app/components/primer/alpha/toggle_switch.css.json +11 -11
  20. data/app/components/primer/alpha/toggle_switch.css.map +1 -1
  21. data/app/components/primer/alpha/toggle_switch.d.ts +1 -1
  22. data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
  23. data/app/components/primer/alpha/toggle_switch.js +44 -42
  24. data/app/components/primer/alpha/toggle_switch.pcss +4 -4
  25. data/app/components/primer/alpha/toggle_switch.rb +7 -0
  26. data/app/components/primer/alpha/toggle_switch.ts +50 -41
  27. data/app/components/primer/beta/auto_complete.rb +1 -1
  28. data/app/components/primer/focus_group.js +10 -6
  29. data/app/components/primer/focus_group.ts +10 -5
  30. data/lib/primer/forms/dsl/input.rb +4 -8
  31. data/lib/primer/forms/dsl/text_field_input.rb +0 -4
  32. data/lib/primer/forms/dsl/toggle_switch_input.rb +4 -0
  33. data/lib/primer/forms/form_control.html.erb +3 -5
  34. data/lib/primer/forms/primer_base_component_wrapper.html.erb +3 -0
  35. data/lib/primer/forms/primer_base_component_wrapper.rb +24 -0
  36. data/lib/primer/forms/toggle_switch.html.erb +3 -3
  37. data/lib/primer/forms/toggle_switch.rb +6 -2
  38. data/lib/primer/forms/toggle_switch_input.js +7 -2
  39. data/lib/primer/forms/toggle_switch_input.ts +9 -2
  40. data/lib/primer/static/generate_info_arch.rb +3 -0
  41. data/lib/primer/view_components/version.rb +1 -1
  42. data/lib/primer/yard/component_manifest.rb +1 -1
  43. data/lib/primer/yard/lookbook_pages_backend.rb +7 -1
  44. data/lib/primer/yard/registry.rb +4 -0
  45. data/previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb +19 -0
  46. data/previews/primer/alpha/overlay_preview.rb +31 -0
  47. data/static/arguments.json +7 -1
  48. data/static/info_arch.json +312 -1
  49. data/static/previews.json +5 -0
  50. metadata +5 -9
  51. data/lib/tasks/docs.rake +0 -185
  52. data/lib/tasks/helpers/ast_processor.rb +0 -44
  53. data/lib/tasks/helpers/ast_traverser.rb +0 -77
  54. data/lib/tasks/primer_view_components.rake +0 -47
  55. data/lib/tasks/static.rake +0 -29
  56. data/lib/tasks/test.rake +0 -83
  57. data/lib/tasks/utilities.rake +0 -109
@@ -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()
@@ -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
@@ -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 = 8
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
@@ -0,0 +1,19 @@
1
+ <div style="width:100%; height: 400px; display: flex; justify-content: center; align-items: center;">
2
+ <div style="position:relative;">
3
+ <%= render(Primer::Alpha::Overlay.new(
4
+ title: title,
5
+ subtitle: subtitle,
6
+ role: role,
7
+ size: size,
8
+ placement: placement,
9
+ anchor_align: anchor_align,
10
+ anchor_side: anchor_side,
11
+ allow_out_of_bounds: allow_out_of_bounds,
12
+ visually_hide_title: visually_hide_title,
13
+ )) do |d| %>
14
+ <% d.with_header(title: title, size: header_size) %>
15
+ <% d.with_show_button { button_text } %>
16
+ <% d.with_body { body_text } %>
17
+ <% end %>
18
+ </div>
19
+ </div>
@@ -132,6 +132,37 @@ module Primer
132
132
  body_text: body_text
133
133
  })
134
134
  end
135
+
136
+ # @label Middle Of Page with relative container
137
+ #
138
+ # @param title [String] text
139
+ # @param subtitle [String] text
140
+ # @param role [Symbol] select [dialog, menu]
141
+ # @param size [Symbol] select [auto, small, medium, medium_portrait, large, xlarge]
142
+ # @param anchor_align [Symbol] select [start, center, end]
143
+ # @param anchor_side [Symbol] select [inside_top, inside_bottom, inside_left, inside_right, inside_center, outside_top, outside_bottom, outside_left, outside_right]
144
+ # @param allow_out_of_bounds [Boolean] toggle
145
+ # @param visually_hide_title [Boolean] toggle
146
+ #
147
+ # @param header_size [Symbol] select [medium, large]
148
+ # @param button_text [String] text
149
+ # @param body_text [String] text
150
+ def middle_of_page_with_relative_container(title: "Test Overlay", subtitle: nil, role: :dialog, size: :auto, placement: :anchored, anchor_align: :center, anchor_side: :outside_bottom, allow_out_of_bounds: false, visually_hide_title: false, header_size: :medium, button_text: "Show Overlay", body_text: "")
151
+ render_with_template(locals: {
152
+ title: title,
153
+ subtitle: subtitle,
154
+ role: role,
155
+ size: size,
156
+ placement: placement,
157
+ anchor_align: anchor_align,
158
+ anchor_side: anchor_side,
159
+ allow_out_of_bounds: allow_out_of_bounds,
160
+ visually_hide_title: visually_hide_title,
161
+ header_size: header_size,
162
+ button_text: button_text,
163
+ body_text: body_text
164
+ })
165
+ end
135
166
  end
136
167
  end
137
168
  end
@@ -1692,7 +1692,13 @@
1692
1692
  "name": "subtitle",
1693
1693
  "type": "String",
1694
1694
  "default": "`nil`",
1695
- "description": "Provides dditional context for the Overlay, also setting the `aria-describedby` attribute."
1695
+ "description": "Provides additional context for the Overlay, also setting the `aria-describedby` attribute."
1696
+ },
1697
+ {
1698
+ "name": "overlay_id",
1699
+ "type": "String",
1700
+ "default": "`nil`",
1701
+ "description": "Provides the id of the overlay element so the close button can close it"
1696
1702
  },
1697
1703
  {
1698
1704
  "name": "size",