primer_view_components 0.1.8 → 0.1.9

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