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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/item.rb +1 -3
- data/app/components/primer/alpha/action_menu.rb +1 -1
- data/app/components/primer/alpha/modal_dialog.js +6 -0
- data/app/components/primer/alpha/modal_dialog.ts +6 -0
- data/app/components/primer/alpha/overlay/header.html.erb +5 -3
- data/app/components/primer/alpha/overlay/header.rb +4 -1
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +1 -1
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/overlay.pcss +1 -1
- data/app/components/primer/alpha/overlay.rb +1 -0
- data/app/components/primer/alpha/toggle_switch.css +1 -1
- data/app/components/primer/alpha/toggle_switch.css.json +11 -11
- data/app/components/primer/alpha/toggle_switch.css.map +1 -1
- data/app/components/primer/alpha/toggle_switch.d.ts +1 -1
- data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
- data/app/components/primer/alpha/toggle_switch.js +44 -42
- data/app/components/primer/alpha/toggle_switch.pcss +4 -4
- data/app/components/primer/alpha/toggle_switch.rb +7 -0
- data/app/components/primer/alpha/toggle_switch.ts +50 -41
- data/app/components/primer/beta/auto_complete.rb +1 -1
- data/app/components/primer/focus_group.js +10 -6
- data/app/components/primer/focus_group.ts +10 -5
- data/lib/primer/forms/dsl/input.rb +4 -8
- data/lib/primer/forms/dsl/text_field_input.rb +0 -4
- data/lib/primer/forms/dsl/toggle_switch_input.rb +4 -0
- data/lib/primer/forms/form_control.html.erb +3 -5
- data/lib/primer/forms/primer_base_component_wrapper.html.erb +3 -0
- data/lib/primer/forms/primer_base_component_wrapper.rb +24 -0
- data/lib/primer/forms/toggle_switch.html.erb +3 -3
- data/lib/primer/forms/toggle_switch.rb +6 -2
- data/lib/primer/forms/toggle_switch_input.js +7 -2
- data/lib/primer/forms/toggle_switch_input.ts +9 -2
- data/lib/primer/static/generate_info_arch.rb +3 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/primer/yard/component_manifest.rb +1 -1
- data/lib/primer/yard/lookbook_pages_backend.rb +7 -1
- data/lib/primer/yard/registry.rb +4 -0
- data/previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb +19 -0
- data/previews/primer/alpha/overlay_preview.rb +31 -0
- data/static/arguments.json +7 -1
- data/static/info_arch.json +312 -1
- data/static/previews.json +5 -0
- metadata +5 -9
- data/lib/tasks/docs.rake +0 -185
- data/lib/tasks/helpers/ast_processor.rb +0 -44
- data/lib/tasks/helpers/ast_traverser.rb +0 -77
- data/lib/tasks/primer_view_components.rake +0 -47
- data/lib/tasks/static.rake +0 -29
- data/lib/tasks/test.rake +0 -83
- 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
|
-
|
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}"
|
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",
|
@@ -9,11 +9,9 @@
|
|
9
9
|
<% end %>
|
10
10
|
<% end %>
|
11
11
|
<%= content %>
|
12
|
-
|
13
|
-
<%=
|
14
|
-
|
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,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",
|
1
|
+
<%= content_tag("toggle-switch-input", class: "FormControl-toggleSwitchInput", hidden: @input.hidden?) do %>
|
2
2
|
<span style="flex-grow: 1">
|
3
|
-
<%=
|
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.
|
13
|
-
@input.
|
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.
|
12
|
+
this.validationMessageElement.textContent = event.detail;
|
12
13
|
this.validationElement.removeAttribute('hidden');
|
13
14
|
});
|
14
15
|
this.addEventListener('toggleSwitchSuccess', () => {
|
15
|
-
this.validationMessageElement.
|
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.
|
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.
|
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,
|
@@ -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 => [:
|
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
|
data/lib/primer/yard/registry.rb
CHANGED
@@ -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
|
data/static/arguments.json
CHANGED
@@ -1692,7 +1692,13 @@
|
|
1692
1692
|
"name": "subtitle",
|
1693
1693
|
"type": "String",
|
1694
1694
|
"default": "`nil`",
|
1695
|
-
"description": "Provides
|
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",
|