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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -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 +2 -2
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/divider.rb +1 -1
- data/app/components/primer/alpha/action_list/heading.html.erb +2 -2
- data/app/components/primer/alpha/action_list/heading.rb +9 -5
- data/app/components/primer/alpha/action_list/item.rb +1 -3
- data/app/components/primer/alpha/action_list.css +1 -1
- data/app/components/primer/alpha/action_list.css.json +1 -0
- data/app/components/primer/alpha/action_list.css.map +1 -1
- data/app/components/primer/alpha/action_list.html.erb +1 -0
- data/app/components/primer/alpha/action_list.pcss +5 -0
- data/app/components/primer/alpha/action_list.rb +14 -11
- data/app/components/primer/alpha/action_menu.rb +1 -1
- data/app/components/primer/alpha/dialog.rb +4 -0
- 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/nav_list/divider.rb +14 -0
- data/app/components/primer/alpha/nav_list/group.html.erb +7 -0
- data/app/components/primer/alpha/nav_list/group.rb +24 -11
- data/app/components/primer/alpha/nav_list/item.rb +4 -0
- data/app/components/primer/alpha/nav_list.d.ts +0 -1
- data/app/components/primer/alpha/nav_list.html.erb +9 -4
- data/app/components/primer/alpha/nav_list.js +3 -4
- data/app/components/primer/alpha/nav_list.rb +87 -10
- data/app/components/primer/alpha/nav_list.ts +3 -2
- 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/segmented_control.css +1 -1
- data/app/components/primer/alpha/segmented_control.css.json +2 -2
- data/app/components/primer/alpha/segmented_control.css.map +1 -1
- data/app/components/primer/alpha/segmented_control.pcss +10 -8
- data/app/components/primer/alpha/text_field.css +1 -1
- data/app/components/primer/alpha/text_field.css.json +11 -11
- data/app/components/primer/alpha/text_field.css.map +1 -1
- data/app/components/primer/alpha/text_field.pcss +2 -2
- 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/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +2 -0
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.pcss +9 -0
- data/app/components/primer/component.rb +3 -96
- data/app/components/primer/focus_group.js +10 -6
- data/app/components/primer/focus_group.ts +10 -5
- data/app/lib/primer/attributes_helper.rb +105 -0
- 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/text_field.rb +6 -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/nav_list_preview/trailing_action.html.erb +10 -10
- data/previews/primer/alpha/nav_list_preview.rb +37 -16
- 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/previews/primer/beta/button_preview/trailing_counter.html.erb +11 -0
- data/previews/primer/beta/button_preview.rb +15 -0
- data/previews/primer/box_preview.rb +28 -0
- data/static/arguments.json +29 -13
- data/static/audited_at.json +1 -0
- data/static/classes.json +3 -0
- data/static/constants.json +3 -0
- data/static/info_arch.json +448 -20
- data/static/previews.json +43 -0
- data/static/statuses.json +1 -0
- metadata +10 -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
@@ -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
|
-
"#{
|
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
|
-
|
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}"
|
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
|
@@ -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",
|
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
|
@@ -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
|
-
|
4
|
-
<% group.with_item(label: "
|
5
|
-
<%= item.with_trailing_action(icon: :
|
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: "
|
8
|
-
<%= item.with_trailing_action(icon: :
|
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=
|
15
|
-
breadButton.addEventListener("click", () => alert("
|
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=
|
18
|
-
cheeseButton.addEventListener("click", () => alert("
|
17
|
+
const cheeseButton = document.querySelector("[name=publish_button]")
|
18
|
+
cheeseButton.addEventListener("click", () => alert("The 'Publish' workflow will be re-run."))
|
19
19
|
</script>
|