openproject-primer_view_components 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -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_bar.css +1 -1
- data/app/components/primer/alpha/action_bar.css.json +1 -4
- data/app/components/primer/alpha/action_bar.css.map +1 -1
- data/app/components/primer/alpha/action_bar.pcss +1 -17
- data/app/components/primer/alpha/action_bar_element.js +21 -9
- data/app/components/primer/alpha/action_list/item.rb +0 -2
- data/app/components/primer/alpha/action_list.css +1 -1
- data/app/components/primer/alpha/action_list.css.map +1 -1
- data/app/components/primer/alpha/action_list.rb +0 -1
- data/app/components/primer/alpha/action_menu/action_menu_element.js +44 -20
- data/app/components/primer/alpha/action_menu/list.rb +0 -9
- data/app/components/primer/alpha/action_menu.html.erb +20 -18
- data/app/components/primer/alpha/auto_complete.css +1 -1
- data/app/components/primer/alpha/auto_complete.css.map +1 -1
- data/app/components/primer/alpha/button_marketing.css +1 -1
- data/app/components/primer/alpha/button_marketing.css.map +1 -1
- data/app/components/primer/alpha/dialog/header.rb +1 -1
- data/app/components/primer/alpha/dropdown.css +1 -1
- data/app/components/primer/alpha/dropdown.css.map +1 -1
- data/app/components/primer/alpha/layout.css +1 -1
- data/app/components/primer/alpha/layout.css.map +1 -1
- data/app/components/primer/alpha/menu.css +1 -1
- data/app/components/primer/alpha/menu.css.map +1 -1
- data/app/components/primer/alpha/nav_list/divider.rb +1 -0
- data/app/components/primer/alpha/nav_list/group.rb +1 -0
- data/app/components/primer/alpha/nav_list/heading.rb +1 -0
- data/app/components/primer/alpha/nav_list/item.rb +1 -0
- data/app/components/primer/alpha/nav_list.rb +1 -0
- data/app/components/primer/alpha/octicon_symbols.html.erb +1 -1
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +0 -1
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/segmented_control.css +1 -1
- data/app/components/primer/alpha/segmented_control.css.json +0 -1
- data/app/components/primer/alpha/segmented_control.css.map +1 -1
- data/app/components/primer/alpha/segmented_control.js +2 -1
- data/app/components/primer/alpha/segmented_control.pcss +0 -4
- data/app/components/primer/alpha/tab_nav.css +1 -1
- data/app/components/primer/alpha/tab_nav.css.map +1 -1
- data/app/components/primer/alpha/text_field.css +1 -1
- data/app/components/primer/alpha/text_field.css.json +11 -5
- data/app/components/primer/alpha/text_field.css.map +1 -1
- data/app/components/primer/alpha/text_field.pcss +10 -1
- data/app/components/primer/alpha/toggle_switch.css +1 -1
- data/app/components/primer/alpha/toggle_switch.css.map +1 -1
- data/app/components/primer/alpha/underline_nav.css +1 -1
- data/app/components/primer/alpha/underline_nav.css.map +1 -1
- data/app/components/primer/alpha/x_banner.js +2 -1
- data/app/components/primer/anchored_position.js +2 -1
- data/app/components/primer/beta/auto_complete/item.rb +1 -1
- data/app/components/primer/beta/avatar.rb +1 -1
- data/app/components/primer/beta/base_button.rb +1 -1
- data/app/components/primer/beta/blankslate.css +1 -1
- data/app/components/primer/beta/blankslate.css.json +1 -0
- data/app/components/primer/beta/blankslate.css.map +1 -1
- data/app/components/primer/beta/blankslate.html.erb +16 -14
- data/app/components/primer/beta/blankslate.pcss +52 -2
- data/app/components/primer/beta/border_box.css +1 -1
- data/app/components/primer/beta/border_box.css.map +1 -1
- data/app/components/primer/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +0 -1
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.html.erb +18 -20
- data/app/components/primer/beta/button.pcss +0 -5
- data/app/components/primer/beta/button.rb +3 -0
- data/app/components/primer/beta/button_group.css +1 -1
- data/app/components/primer/beta/button_group.css.json +2 -4
- data/app/components/primer/beta/button_group.css.map +1 -1
- data/app/components/primer/beta/button_group.html.erb +3 -1
- data/app/components/primer/beta/button_group.pcss +2 -4
- data/app/components/primer/beta/button_group.rb +41 -12
- data/app/components/primer/beta/clipboard_copy.rb +4 -0
- data/app/components/primer/beta/clipboard_copy_button.rb +25 -0
- data/app/components/primer/beta/counter.rb +1 -1
- data/app/components/primer/beta/flash.html.erb +1 -1
- data/app/components/primer/beta/icon_button.html.erb +4 -6
- data/app/components/primer/beta/icon_button.rb +1 -3
- data/app/components/primer/beta/label.css +1 -1
- data/app/components/primer/beta/label.css.map +1 -1
- data/app/components/primer/beta/link.css +1 -1
- data/app/components/primer/beta/link.css.map +1 -1
- data/app/components/primer/beta/nav_list.js +14 -7
- data/app/components/primer/beta/subhead.css +1 -1
- data/app/components/primer/beta/subhead.css.json +2 -0
- data/app/components/primer/beta/subhead.css.map +1 -1
- data/app/components/primer/beta/subhead.pcss +8 -1
- data/app/components/primer/beta/subhead.rb +9 -1
- data/app/components/primer/focus_group.js +2 -1
- data/app/forms/action_menu_form.rb +20 -0
- data/app/forms/immediate_validation_form.rb +2 -2
- data/app/lib/primer/fetch_or_fallback_helper.rb +0 -1
- data/app/lib/primer/octicon/cache.rb +1 -1
- data/lib/primer/classify.rb +0 -2
- data/lib/primer/forms/action_menu.html.erb +6 -0
- data/lib/primer/forms/action_menu.rb +25 -0
- data/lib/primer/forms/acts_as_component.rb +0 -3
- data/lib/primer/forms/base.rb +0 -1
- data/lib/primer/forms/base_component.rb +0 -2
- data/lib/primer/forms/dsl/action_menu_input.rb +36 -0
- data/lib/primer/forms/dsl/input.rb +8 -1
- data/lib/primer/forms/dsl/input_methods.rb +9 -0
- data/lib/primer/forms/dsl/text_field_input.rb +8 -0
- data/lib/primer/forms/primer_base_component_wrapper.rb +0 -2
- data/lib/primer/forms/primer_text_field.js +40 -5
- data/lib/primer/forms/primer_text_field.ts +39 -7
- data/lib/primer/forms/validation_message.html.erb +2 -1
- data/lib/primer/static/generate_info_arch.rb +1 -2
- data/lib/primer/static/generate_previews.rb +0 -2
- data/lib/primer/view_components/engine.rb +5 -1
- data/lib/primer/view_components/linters/base_linter.rb +3 -2
- data/lib/primer/view_components/linters/deprecated_components_counter.rb +1 -1
- data/lib/primer/view_components/linters/disallow_action_list.rb +1 -0
- data/lib/primer/view_components/linters/severity_schema.rb +1 -0
- data/lib/primer/view_components/version.rb +1 -2
- data/lib/primer/yard/lookbook_pages_backend.rb +0 -2
- data/lib/rubocop/cop/primer/base_cop.rb +1 -1
- data/lib/rubocop/cop/primer/deprecated_arguments.rb +0 -2
- data/lib/rubocop/cop/primer/deprecated_components.rb +1 -1
- data/lib/rubocop/cop/primer/deprecated_label_schemes.rb +1 -1
- data/lib/rubocop/cop/primer/deprecated_label_variants.rb +1 -1
- data/previews/primer/alpha/octicon_symbols_preview/default.html.erb +6 -0
- data/previews/primer/alpha/octicon_symbols_preview/playground.html.erb +13 -0
- data/previews/primer/alpha/octicon_symbols_preview.rb +21 -0
- data/previews/primer/alpha/text_field_preview.rb +5 -0
- data/previews/primer/beta/avatar_preview.rb +6 -0
- data/previews/primer/beta/button_group_preview.rb +11 -0
- data/previews/primer/beta/clipboard_copy_button_preview.rb +29 -0
- data/previews/primer/beta/subhead_preview.rb +32 -4
- data/previews/primer/forms_preview/action_menu_form.html.erb +3 -0
- data/previews/primer/forms_preview.rb +4 -0
- data/static/arguments.json +75 -13
- data/static/audited_at.json +2 -0
- data/static/classes.json +9 -3
- data/static/constants.json +16 -1
- data/static/info_arch.json +329 -26
- data/static/previews.json +146 -0
- data/static/statuses.json +2 -0
- metadata +14 -4
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :nodoc:
|
4
|
+
class ActionMenuForm < ApplicationForm
|
5
|
+
form do |action_menu_form|
|
6
|
+
action_menu_form.action_menu(name: "city", label: "Favorite city", caption: "Select your favorite!") do |city_list|
|
7
|
+
city_list.with_item(label: "Lopez Island", data: { value: "lopez_island" }) do |item|
|
8
|
+
item.with_leading_visual_icon(icon: :log)
|
9
|
+
end
|
10
|
+
city_list.with_item(label: "Bellevue", data: { value: "bellevue" }) do |item|
|
11
|
+
item.with_leading_visual_icon(icon: :paste)
|
12
|
+
end
|
13
|
+
city_list.with_item(label: "Seattle", data: { value: "seattle" }) do |item|
|
14
|
+
item.with_leading_visual_icon(icon: :"device-camera")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
action_menu_form.submit(name: :submit, label: "Submit")
|
19
|
+
end
|
20
|
+
end
|
@@ -21,8 +21,8 @@ class ImmediateValidationForm < ApplicationForm
|
|
21
21
|
|
22
22
|
validation_form.text_field(
|
23
23
|
name: :random_error,
|
24
|
-
label: "Random error",
|
25
|
-
caption: "Server checks will randomly respond with errors",
|
24
|
+
label: "Random error or success",
|
25
|
+
caption: "Server checks will randomly respond with errors or success",
|
26
26
|
auto_check_src: @view_context.example_check_random_path
|
27
27
|
)
|
28
28
|
end
|
@@ -4,7 +4,7 @@ module Primer
|
|
4
4
|
module Octicon
|
5
5
|
# :nodoc:
|
6
6
|
class Cache
|
7
|
-
LOOKUP = {}
|
7
|
+
LOOKUP = {}
|
8
8
|
# Preload the top 20 used icons.
|
9
9
|
PRELOADED_ICONS = [:alert, :check, :"chevron-down", :paste, :clock, :"dot-fill", :info, :"kebab-horizontal", :link, :lock, :mail, :pencil, :plus, :question, :repo, :search, :"shield-lock", :star, :trash, :x].freeze
|
10
10
|
|
data/lib/primer/classify.rb
CHANGED
@@ -75,7 +75,6 @@ module Primer
|
|
75
75
|
# are about 30% faster than Hash#dig. It also ensures validate is
|
76
76
|
# only called when necessary, i.e. when the class can't be found
|
77
77
|
# in the lookup table.
|
78
|
-
# rubocop:disable Style/RescueModifier
|
79
78
|
found = (LOOKUP[key][item][brk] rescue nil) || validate(key, item, brk)
|
80
79
|
# rubocop:enable Style/RescueModifier
|
81
80
|
result << found if found
|
@@ -93,7 +92,6 @@ module Primer
|
|
93
92
|
end.join(" ")
|
94
93
|
|
95
94
|
# This is much faster than Rails' presence method.
|
96
|
-
# rubocop:disable Rails/Blank
|
97
95
|
{
|
98
96
|
class: !classes || classes.empty? ? nil : classes,
|
99
97
|
style: !style || style.empty? ? nil : style
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Forms
|
5
|
+
# :nodoc:
|
6
|
+
class ActionMenu < BaseComponent
|
7
|
+
delegate :builder, :form, to: :@input
|
8
|
+
|
9
|
+
def initialize(input:)
|
10
|
+
@input = input
|
11
|
+
|
12
|
+
@input.input_arguments[:form_arguments] = {
|
13
|
+
name: @input.name,
|
14
|
+
builder: builder
|
15
|
+
}
|
16
|
+
|
17
|
+
@input.input_arguments[:select_variant] ||= :single
|
18
|
+
|
19
|
+
unless @input.input_arguments.include?(:dynamic_label)
|
20
|
+
@input.input_arguments[:dynamic_label] = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -36,7 +36,6 @@ module Primer
|
|
36
36
|
def before_render; end
|
37
37
|
|
38
38
|
# :nocov:
|
39
|
-
# rubocop:disable Naming/AccessorMethodName
|
40
39
|
def set_original_view_context(view_context)
|
41
40
|
@view_context = view_context
|
42
41
|
end
|
@@ -98,8 +97,6 @@ module Primer
|
|
98
97
|
end
|
99
98
|
|
100
99
|
def define_template_method(template_path, method_name)
|
101
|
-
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
102
|
-
# rubocop:disable Style/EvalWithLocation
|
103
100
|
class_eval <<-RUBY, template_path, 0
|
104
101
|
private def #{method_name}
|
105
102
|
capture { #{compile_template(template_path)} }
|
data/lib/primer/forms/base.rb
CHANGED
@@ -120,7 +120,6 @@ module Primer
|
|
120
120
|
private
|
121
121
|
|
122
122
|
def form_object
|
123
|
-
# rubocop:disable Naming/MemoizedInstanceVariableName
|
124
123
|
@__pf_form_object ||= Primer::Forms::Dsl::FormObject.new(builder: @builder, form: self).tap do |obj|
|
125
124
|
# compile before adding inputs so caption templates are identified
|
126
125
|
self.class.compile!
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Forms
|
5
|
+
module Dsl
|
6
|
+
# :nodoc:
|
7
|
+
class ActionMenuInput < Input
|
8
|
+
attr_reader :name, :label, :block
|
9
|
+
|
10
|
+
def initialize(name:, label:, **system_arguments, &block)
|
11
|
+
@name = name
|
12
|
+
@label = label
|
13
|
+
@block = block
|
14
|
+
|
15
|
+
super(**system_arguments)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_component
|
19
|
+
ActionMenu.new(input: self)
|
20
|
+
end
|
21
|
+
|
22
|
+
# :nocov:
|
23
|
+
def type
|
24
|
+
:action_menu
|
25
|
+
end
|
26
|
+
# :nocov:
|
27
|
+
|
28
|
+
# :nocov:
|
29
|
+
def focusable?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
# :nocov:
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -93,7 +93,6 @@ module Primer
|
|
93
93
|
# methods. These methods will use the passed name if provided instead
|
94
94
|
# of generating a scoped one.
|
95
95
|
#
|
96
|
-
# rubocop:disable Style/IfUnlessModifier
|
97
96
|
unless @input_arguments.delete(:scope_name_to_model) { true }
|
98
97
|
@input_arguments[:name] = name
|
99
98
|
end
|
@@ -297,6 +296,14 @@ module Primer
|
|
297
296
|
{}
|
298
297
|
end
|
299
298
|
|
299
|
+
def validation_success_icon_target
|
300
|
+
""
|
301
|
+
end
|
302
|
+
|
303
|
+
def validation_error_icon_target
|
304
|
+
""
|
305
|
+
end
|
306
|
+
|
300
307
|
private
|
301
308
|
|
302
309
|
def input_data
|
@@ -90,6 +90,15 @@ module Primer
|
|
90
90
|
add_input SelectInput.new(builder: builder, form: form, **options, &block)
|
91
91
|
end
|
92
92
|
|
93
|
+
# Adds an <%= link_to_component(Primer::Alpha::ActionMenu) %> to this form.
|
94
|
+
#
|
95
|
+
# @param options [Hash] The options accepted by the <%= link_to_component(Primer::Alpha::ActionMenu) %> component.
|
96
|
+
# @param block [Proc] The block passed to `#render` when the <%= link_to_component(Primer::Alpha::ActionMenu) %> is rendered. This block is passed an instance of <%= link_to_component(Primer::Alpha::ActionMenu) %>, which can be used to add items, dividers, etc.
|
97
|
+
def action_menu(**options, &block)
|
98
|
+
options = decorate_options(**options)
|
99
|
+
add_input ActionMenuInput.new(builder: builder, form: form, **options, &block)
|
100
|
+
end
|
101
|
+
|
93
102
|
# END select input methods
|
94
103
|
|
95
104
|
# START button input methods
|
@@ -69,6 +69,14 @@ module Primer
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
def validation_success_icon_target
|
73
|
+
"primer-text-field.validationSuccessIcon"
|
74
|
+
end
|
75
|
+
|
76
|
+
def validation_error_icon_target
|
77
|
+
"primer-text-field.validationErrorIcon"
|
78
|
+
end
|
79
|
+
|
72
80
|
def validation_message_arguments
|
73
81
|
if auto_check_src.present?
|
74
82
|
super.merge(
|
@@ -30,8 +30,14 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
30
30
|
var _a;
|
31
31
|
(_a = __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
32
32
|
const { signal } = (__classPrivateFieldSet(this, _PrimerTextFieldElement_abortController, new AbortController(), "f"));
|
33
|
-
this.inputElement.addEventListener('auto-check-success', () => {
|
34
|
-
|
33
|
+
this.inputElement.addEventListener('auto-check-success', async (event) => {
|
34
|
+
const message = await event.detail.response.text();
|
35
|
+
if (message && message.length > 0) {
|
36
|
+
this.setSuccess(message);
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
this.clearError();
|
40
|
+
}
|
35
41
|
}, { signal });
|
36
42
|
this.inputElement.addEventListener('auto-check-error', async (event) => {
|
37
43
|
const errorMessage = await event.detail.response.text();
|
@@ -49,12 +55,35 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
49
55
|
clearError() {
|
50
56
|
this.inputElement.removeAttribute('invalid');
|
51
57
|
this.validationElement.hidden = true;
|
52
|
-
this.validationMessageElement.
|
58
|
+
this.validationMessageElement.replaceChildren();
|
59
|
+
}
|
60
|
+
setValidationMessage(message) {
|
61
|
+
const template = document.createElement('template');
|
62
|
+
// eslint-disable-next-line github/no-inner-html
|
63
|
+
template.innerHTML = message;
|
64
|
+
const fragment = document.importNode(template.content, true);
|
65
|
+
this.validationMessageElement.replaceChildren(fragment);
|
66
|
+
}
|
67
|
+
toggleValidationStyling(isError) {
|
68
|
+
if (isError) {
|
69
|
+
this.validationElement.classList.remove('FormControl-inlineValidation--success');
|
70
|
+
}
|
71
|
+
else {
|
72
|
+
this.validationElement.classList.add('FormControl-inlineValidation--success');
|
73
|
+
}
|
74
|
+
this.validationSuccessIcon.hidden = isError;
|
75
|
+
this.validationErrorIcon.hidden = !isError;
|
76
|
+
this.inputElement.setAttribute('invalid', isError ? 'true' : 'false');
|
77
|
+
}
|
78
|
+
setSuccess(message) {
|
79
|
+
this.toggleValidationStyling(false);
|
80
|
+
this.setValidationMessage(message);
|
81
|
+
this.validationElement.hidden = false;
|
53
82
|
}
|
54
83
|
setError(message) {
|
55
|
-
this.
|
84
|
+
this.toggleValidationStyling(true);
|
85
|
+
this.setValidationMessage(message);
|
56
86
|
this.validationElement.hidden = false;
|
57
|
-
this.inputElement.setAttribute('invalid', 'true');
|
58
87
|
}
|
59
88
|
};
|
60
89
|
_PrimerTextFieldElement_abortController = new WeakMap();
|
@@ -67,6 +96,12 @@ __decorate([
|
|
67
96
|
__decorate([
|
68
97
|
target
|
69
98
|
], PrimerTextFieldElement.prototype, "validationMessageElement", void 0);
|
99
|
+
__decorate([
|
100
|
+
target
|
101
|
+
], PrimerTextFieldElement.prototype, "validationSuccessIcon", void 0);
|
102
|
+
__decorate([
|
103
|
+
target
|
104
|
+
], PrimerTextFieldElement.prototype, "validationErrorIcon", void 0);
|
70
105
|
PrimerTextFieldElement = __decorate([
|
71
106
|
controller
|
72
107
|
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
@@ -8,6 +8,8 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
8
8
|
@target inputElement: HTMLInputElement
|
9
9
|
@target validationElement: HTMLElement
|
10
10
|
@target validationMessageElement: HTMLElement
|
11
|
+
@target validationSuccessIcon: HTMLElement
|
12
|
+
@target validationErrorIcon: HTMLElement
|
11
13
|
|
12
14
|
#abortController: AbortController | null
|
13
15
|
|
@@ -17,10 +19,15 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
17
19
|
|
18
20
|
this.inputElement.addEventListener(
|
19
21
|
'auto-check-success',
|
20
|
-
() => {
|
21
|
-
|
22
|
+
async (event: any) => {
|
23
|
+
const message = await event.detail.response.text()
|
24
|
+
if (message && message.length > 0) {
|
25
|
+
this.setSuccess(message)
|
26
|
+
} else {
|
27
|
+
this.clearError()
|
28
|
+
}
|
22
29
|
},
|
23
|
-
{signal}
|
30
|
+
{signal},
|
24
31
|
)
|
25
32
|
|
26
33
|
this.inputElement.addEventListener(
|
@@ -29,7 +36,7 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
29
36
|
const errorMessage = await event.detail.response.text()
|
30
37
|
this.setError(errorMessage)
|
31
38
|
},
|
32
|
-
{signal}
|
39
|
+
{signal},
|
33
40
|
)
|
34
41
|
}
|
35
42
|
|
@@ -45,12 +52,37 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
45
52
|
clearError(): void {
|
46
53
|
this.inputElement.removeAttribute('invalid')
|
47
54
|
this.validationElement.hidden = true
|
48
|
-
this.validationMessageElement.
|
55
|
+
this.validationMessageElement.replaceChildren()
|
56
|
+
}
|
57
|
+
|
58
|
+
setValidationMessage(message: string): void {
|
59
|
+
const template = document.createElement('template')
|
60
|
+
// eslint-disable-next-line github/no-inner-html
|
61
|
+
template.innerHTML = message
|
62
|
+
const fragment = document.importNode(template.content, true)
|
63
|
+
this.validationMessageElement.replaceChildren(fragment)
|
64
|
+
}
|
65
|
+
|
66
|
+
toggleValidationStyling(isError: boolean): void {
|
67
|
+
if (isError) {
|
68
|
+
this.validationElement.classList.remove('FormControl-inlineValidation--success')
|
69
|
+
} else {
|
70
|
+
this.validationElement.classList.add('FormControl-inlineValidation--success')
|
71
|
+
}
|
72
|
+
this.validationSuccessIcon.hidden = isError
|
73
|
+
this.validationErrorIcon.hidden = !isError
|
74
|
+
this.inputElement.setAttribute('invalid', isError ? 'true' : 'false')
|
75
|
+
}
|
76
|
+
|
77
|
+
setSuccess(message: string): void {
|
78
|
+
this.toggleValidationStyling(false)
|
79
|
+
this.setValidationMessage(message)
|
80
|
+
this.validationElement.hidden = false
|
49
81
|
}
|
50
82
|
|
51
83
|
setError(message: string): void {
|
52
|
-
this.
|
84
|
+
this.toggleValidationStyling(true)
|
85
|
+
this.setValidationMessage(message)
|
53
86
|
this.validationElement.hidden = false
|
54
|
-
this.inputElement.setAttribute('invalid', 'true')
|
55
87
|
}
|
56
88
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<%= content_tag(:div, **@input.validation_arguments) do %>
|
2
|
-
<span class="FormControl-inlineValidation--visual"><%= render(Primer::Beta::Octicon.new(icon: :"
|
2
|
+
<span class="FormControl-inlineValidation--visual" data-target="<%= @input.validation_success_icon_target %>" hidden><%= render(Primer::Beta::Octicon.new(icon: :"check-circle-fill", size: :xsmall, aria: { hidden: true })) %></span>
|
3
|
+
<span class=" FormControl-inlineValidation--visual" data-target="<%= @input.validation_error_icon_target %>"><%= render(Primer::Beta::Octicon.new(icon: :"alert-fill", size: :xsmall, aria: { hidden: true })) %></span>
|
3
4
|
<%= content_tag(:span, @input.invalid? ? @input.validation_messages.first : "", **@input.validation_message_arguments) %>
|
4
5
|
<% end %>
|
@@ -33,7 +33,6 @@ module Primer
|
|
33
33
|
|
34
34
|
{
|
35
35
|
"name" => slot_method.name,
|
36
|
-
# rubocop:disable Style/IfUnlessModifier
|
37
36
|
"description" =>
|
38
37
|
if slot_method.base_docstring.to_s.present?
|
39
38
|
render_erb_ignoring_markdown_code_fences(slot_method.base_docstring)
|
@@ -90,7 +89,7 @@ module Primer
|
|
90
89
|
}
|
91
90
|
end
|
92
91
|
|
93
|
-
statuses = Primer::Status::Dsl::STATUSES.keys.map
|
92
|
+
statuses = Primer::Status::Dsl::STATUSES.keys.map { |k| k.to_s.capitalize }
|
94
93
|
|
95
94
|
Primer::Component.descendants.each do |component|
|
96
95
|
fq_class = component.name.to_s.split("::")
|
@@ -16,11 +16,9 @@ module Primer
|
|
16
16
|
|
17
17
|
component = preview.components.first&.component_class
|
18
18
|
|
19
|
-
# rubocop:disable Style/IfUnlessModifier
|
20
19
|
unless component
|
21
20
|
raise "Could not determine which component `#{preview.preview_class}` is designed to preview. Please add a `@component` annotation."
|
22
21
|
end
|
23
|
-
# rubocop:enable Style/IfUnlessModifier
|
24
22
|
|
25
23
|
_, _, class_name = Primer::Yard::DocsHelper.status_module_and_short_name(component)
|
26
24
|
|
@@ -44,7 +44,11 @@ module Primer
|
|
44
44
|
|
45
45
|
initializer "primer.forms.helpers" do
|
46
46
|
ActiveSupport.on_load :action_controller_base do
|
47
|
-
|
47
|
+
begin
|
48
|
+
require "primer/form_helper"
|
49
|
+
rescue LoadError
|
50
|
+
end
|
51
|
+
|
48
52
|
helper Primer::FormHelper
|
49
53
|
|
50
54
|
# make primer_form_with available to view components also
|
@@ -24,6 +24,7 @@ module ERBLint
|
|
24
24
|
CLASSES = [].freeze
|
25
25
|
REQUIRED_ARGUMENTS = [].freeze
|
26
26
|
|
27
|
+
# :nodoc:
|
27
28
|
class ConfigSchema < LinterConfig
|
28
29
|
property :override_ignores_if_correctable, accepts: [true, false], default: false, reader: :override_ignores_if_correctable?
|
29
30
|
end
|
@@ -154,13 +155,13 @@ module ERBLint
|
|
154
155
|
# Unless explicitly set, we don't want to mark correctable offenses if the counter is correct.
|
155
156
|
if !@config.override_ignores_if_correctable? && expected_count == @total_offenses
|
156
157
|
clear_offenses
|
157
|
-
return
|
158
|
+
return false
|
158
159
|
end
|
159
160
|
|
160
161
|
if @offenses_not_corrected.zero?
|
161
162
|
# have to adjust to get `\n` so we delete the whole line
|
162
163
|
add_offense(processed_source.to_source_range(comment_node.loc.adjust(end_pos: 1)), "Unused erblint:count comment for #{rule_name}", "") if comment_node
|
163
|
-
return
|
164
|
+
return false
|
164
165
|
end
|
165
166
|
|
166
167
|
first_offense = @offenses[0]
|
@@ -63,7 +63,7 @@ module ERBLint
|
|
63
63
|
if offenses_count.zero?
|
64
64
|
# have to adjust to get `\n` so we delete the whole line
|
65
65
|
add_offense_with_severity(processed_source.to_source_range(comment_node.loc.adjust(end_pos: 1)), "Unused erblint:counter comment for #{rule_name}", "") if comment_node
|
66
|
-
return
|
66
|
+
return false
|
67
67
|
end
|
68
68
|
|
69
69
|
first_offense = @offenses[0]
|
@@ -4,6 +4,7 @@ require "erb_lint/utils/severity_levels"
|
|
4
4
|
|
5
5
|
module ERBLint
|
6
6
|
module Linters
|
7
|
+
# :nodoc:
|
7
8
|
class SeveritySchema < LinterConfig
|
8
9
|
# SEVERITY_NAMES :info, :refactor, :convention, :warning, :error, :fatal
|
9
10
|
# see https://github.com/Shopify/erb-lint/blob/main/lib/erb_lint/utils/severity_levels.rb
|
@@ -5,7 +5,7 @@ module Primer
|
|
5
5
|
module ViewComponents
|
6
6
|
module VERSION
|
7
7
|
MAJOR = 0
|
8
|
-
MINOR =
|
8
|
+
MINOR = 17
|
9
9
|
PATCH = 0
|
10
10
|
|
11
11
|
STRING = [MAJOR, MINOR, PATCH].join(".")
|
@@ -13,6 +13,5 @@ module Primer
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
# rubocop:disable Rails/Output
|
17
16
|
puts Primer::ViewComponents::VERSION::STRING if __FILE__ == $PROGRAM_NAME
|
18
17
|
# rubocop:enable Rails/Output
|
@@ -42,14 +42,12 @@ module Primer
|
|
42
42
|
), __dir__
|
43
43
|
)
|
44
44
|
|
45
|
-
# rubocop:disable Lint/UselessAssignment
|
46
45
|
documented_methods = docs.non_slot_methods.select do |mtd|
|
47
46
|
[component.name, "Primer::Forms::Dsl::InputMethods"].include?(mtd.parent.title)
|
48
47
|
end
|
49
48
|
|
50
49
|
preview_methods = PREVIEW_MAP[component]
|
51
50
|
preview_erbs = preview_methods.map do |preview_method|
|
52
|
-
# rubocop:disable Style/IfUnlessModifier
|
53
51
|
if Primer::FormsPreview.instance_methods.exclude?(preview_method)
|
54
52
|
raise "Preview '#{preview_method}' does not exist in Primer::FormsPreview"
|
55
53
|
end
|
@@ -12,7 +12,7 @@ module RuboCop
|
|
12
12
|
# We only verify SystemArguments if it's a `.new` call on a component or
|
13
13
|
# a ViewHeleper call.
|
14
14
|
def valid_node?(node)
|
15
|
-
return if node.nil?
|
15
|
+
return false if node.nil?
|
16
16
|
|
17
17
|
view_helpers.include?(node.method_name) || (node.method_name == :new && !node.receiver.nil? && ::Primer::ViewComponents::STATUSES.key?(node.receiver.const_name))
|
18
18
|
end
|
@@ -298,7 +298,6 @@ module RuboCop
|
|
298
298
|
def extract_kv_from(pair)
|
299
299
|
key = pair.key.value
|
300
300
|
|
301
|
-
# rubocop:disable Lint/BooleanSymbol
|
302
301
|
value = case pair.value.type
|
303
302
|
when :sym, :str
|
304
303
|
pair.value.value.to_sym
|
@@ -307,7 +306,6 @@ module RuboCop
|
|
307
306
|
else
|
308
307
|
return []
|
309
308
|
end
|
310
|
-
# rubocop:enable Lint/BooleanSymbol
|
311
309
|
|
312
310
|
[key, value]
|
313
311
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "rubocop"
|
4
4
|
require "json"
|
5
5
|
require "parser/current"
|
6
|
-
require_relative "
|
6
|
+
require_relative "../../../primer/view_components/linters/helpers/deprecated_components_helpers"
|
7
7
|
|
8
8
|
module RuboCop
|
9
9
|
module Cop
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%= render(Primer::Alpha::OcticonSymbols.new(icons: [{ symbol: :container, size: :medium }])) %>
|
2
|
+
|
3
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="40" width="40" aria-label="Circled container icon" tabindex="0">
|
4
|
+
<circle cx="20" cy="20" r="18" stroke="green" stroke-width="3px" fill="white" />
|
5
|
+
<use href="#octicon_container_24" x="8" y="8" />
|
6
|
+
</svg>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<p style="max-width: 500px">
|
2
|
+
Below is an SVG image containing the chosen octicon surrounded by a green circle. The octicon has been emitted
|
3
|
+
onto the page as an SVG <symbol> element and included into the SVG you see below with the <use> element.
|
4
|
+
See the <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol" target="_blank">MDN docs</a> for
|
5
|
+
more information.
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<%= render(Primer::Alpha::OcticonSymbols.new(icons: [{ symbol: octicon, size: :medium }])) %>
|
9
|
+
|
10
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="40" width="40" aria-label="Circled <%= octicon %> icon" tabindex="0">
|
11
|
+
<circle cx="20" cy="20" r="18" stroke="green" stroke-width="3px" fill="white" />
|
12
|
+
<use href="#octicon_<%= octicon %>_24" x="8" y="8" />
|
13
|
+
</svg>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
# @label OcticonSymbols
|
6
|
+
class OcticonSymbolsPreview < ViewComponent::Preview
|
7
|
+
# @label Playground
|
8
|
+
#
|
9
|
+
# @param octicon [Symbol] medium_octicon
|
10
|
+
def playground(octicon: :container)
|
11
|
+
render_with_template(locals: { octicon: octicon })
|
12
|
+
end
|
13
|
+
|
14
|
+
# @label Default
|
15
|
+
#
|
16
|
+
# @snapshot
|
17
|
+
def default
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -179,6 +179,11 @@ module Primer
|
|
179
179
|
render(Primer::Alpha::TextField.new(auto_check_src: UrlHelpers.example_check_ok_path, name: "my-text-field", label: "My text field"))
|
180
180
|
end
|
181
181
|
|
182
|
+
# @label Auto check request accepted
|
183
|
+
def with_auto_check_accepted
|
184
|
+
render(Primer::Alpha::TextField.new(auto_check_src: UrlHelpers.example_check_accepted_path, name: "my-text-field", label: "My text field"))
|
185
|
+
end
|
186
|
+
|
182
187
|
# @label Auto check request error
|
183
188
|
def with_auto_check_error
|
184
189
|
render(Primer::Alpha::TextField.new(auto_check_src: UrlHelpers.example_check_error_path, name: "my-text-field", label: "My text field"))
|
@@ -64,6 +64,12 @@ module Primer
|
|
64
64
|
render(Primer::Beta::Avatar.new(size: 48, src: Primer::ExampleImage::BASE64_SRC, alt: "@kittenuser"))
|
65
65
|
end
|
66
66
|
|
67
|
+
# @label 64px
|
68
|
+
# @snapshot
|
69
|
+
def size_64
|
70
|
+
render(Primer::Beta::Avatar.new(size: 64, src: Primer::ExampleImage::BASE64_SRC, alt: "@kittenuser"))
|
71
|
+
end
|
72
|
+
|
67
73
|
# @label 80px
|
68
74
|
# @snapshot
|
69
75
|
def size_80
|