stimulus_plumbers 0.4.11 → 0.4.13
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +31 -9
- data/app/assets/javascripts/stimulus-plumbers/index.es.js +87 -96
- data/app/assets/javascripts/stimulus-plumbers/index.es.js.map +1 -1
- data/app/assets/javascripts/stimulus-plumbers/index.umd.js +1 -1
- data/app/assets/javascripts/stimulus-plumbers/index.umd.js.map +1 -1
- data/config/locales/en.yml +1 -0
- data/docs/architecture.md +1 -1
- data/docs/component/form.md +42 -20
- data/docs/component/icon.md +9 -9
- data/docs/guide.md +2 -1
- data/lib/stimulus_plumbers/components/button/icon_layout.rb +34 -0
- data/lib/stimulus_plumbers/components/button.rb +2 -23
- data/lib/stimulus_plumbers/components/card.rb +1 -1
- data/lib/stimulus_plumbers/components/combobox/builder.rb +52 -14
- data/lib/stimulus_plumbers/components/combobox/date.rb +35 -9
- data/lib/stimulus_plumbers/components/combobox/dropdown.rb +22 -6
- data/lib/stimulus_plumbers/components/combobox/time.rb +18 -5
- data/lib/stimulus_plumbers/components/combobox/trigger.rb +1 -1
- data/lib/stimulus_plumbers/components/combobox/typeahead.rb +23 -8
- data/lib/stimulus_plumbers/components/icon.rb +5 -3
- data/lib/stimulus_plumbers/components/indicator.rb +3 -1
- data/lib/stimulus_plumbers/components/link.rb +1 -1
- data/lib/stimulus_plumbers/components/list/item.rb +1 -1
- data/lib/stimulus_plumbers/components/ordered_list/item.rb +2 -2
- data/lib/stimulus_plumbers/components/popover.rb +7 -3
- data/lib/stimulus_plumbers/components/progress_bar.rb +3 -1
- data/lib/stimulus_plumbers/components/progress_meter.rb +3 -1
- data/lib/stimulus_plumbers/components/progress_ring.rb +4 -2
- data/lib/stimulus_plumbers/components/timeline/event.rb +5 -3
- data/lib/stimulus_plumbers/form/field.rb +4 -2
- data/lib/stimulus_plumbers/form/fields/inputs/code.rb +93 -32
- data/lib/stimulus_plumbers/form/fields/inputs/credit_card.rb +61 -33
- data/lib/stimulus_plumbers/form/fields/inputs/password.rb +37 -12
- data/lib/stimulus_plumbers/form/fields/inputs/search.rb +1 -1
- data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +52 -7
- data/lib/stimulus_plumbers/generators/css_entrypoint.rb +10 -0
- data/lib/stimulus_plumbers/helpers/icon_helper.rb +2 -2
- data/lib/stimulus_plumbers/plumber/dispatcher.rb +14 -12
- data/lib/stimulus_plumbers/plumber/slots.rb +8 -8
- data/lib/stimulus_plumbers/themes/schema.rb +4 -0
- data/lib/stimulus_plumbers/version.rb +1 -1
- data/lib/stimulus_plumbers.rb +1 -0
- data/vendor/ARIA.md +3 -2
- data/vendor/component/manifest.json +8 -1
- data/vendor/controller/docs/input-formatter.md +18 -39
- data/vendor/controller/docs/input-revealable.md +65 -0
- data/vendor/controller/manifest.json +31 -9
- metadata +3 -1
|
@@ -6,8 +6,10 @@ module StimulusPlumbers
|
|
|
6
6
|
class Event < Plumber::Base
|
|
7
7
|
attr_reader :interactive
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
class << self
|
|
10
|
+
def detail_id_for(event_id)
|
|
11
|
+
[event_id, "detail"].compact.join("_")
|
|
12
|
+
end
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def render(datetime: nil, id: nil, interactive: false, orientation: :vertical, **kwargs, &block)
|
|
@@ -106,7 +108,7 @@ module StimulusPlumbers
|
|
|
106
108
|
def render_indicator_content(type:, icon_name:)
|
|
107
109
|
if type == :icon && icon_name
|
|
108
110
|
Components::Icon.new(template).render(
|
|
109
|
-
|
|
111
|
+
icon_name,
|
|
110
112
|
size: :sm,
|
|
111
113
|
classes: theme.resolve(:timeline_item_indicator_icon_slot).fetch(:classes, ""),
|
|
112
114
|
aria: { hidden: "true" }
|
|
@@ -15,8 +15,10 @@ module StimulusPlumbers
|
|
|
15
15
|
|
|
16
16
|
attr_reader :hide_label
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
class << self
|
|
19
|
+
def label_id(input_id)
|
|
20
|
+
[input_id, "label"].compact.join("_")
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def initialize(template, hide_label: false, **kwargs)
|
|
@@ -5,64 +5,124 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Code
|
|
8
|
+
STIMULUS_CONTROLLER = "input-formatter"
|
|
9
|
+
STIMULUS_ACTION = [
|
|
10
|
+
"input->#{STIMULUS_CONTROLLER}#onInput",
|
|
11
|
+
"focus->#{STIMULUS_CONTROLLER}#onFocus",
|
|
12
|
+
"blur->#{STIMULUS_CONTROLLER}#onBlur"
|
|
13
|
+
].join(" ").freeze
|
|
14
|
+
DEFAULT_CHARSET = :digits
|
|
15
|
+
DEFAULT_AUTOCOMPLETE = "one-time-code"
|
|
16
|
+
DEFAULT_SEPARATOR = nil
|
|
17
|
+
|
|
8
18
|
private
|
|
9
19
|
|
|
10
|
-
def render_code_input(
|
|
11
|
-
|
|
20
|
+
def render_code_input(
|
|
21
|
+
attribute,
|
|
22
|
+
html_opts,
|
|
23
|
+
opts,
|
|
24
|
+
error,
|
|
25
|
+
length: nil,
|
|
26
|
+
charset: DEFAULT_CHARSET,
|
|
27
|
+
groups: [],
|
|
28
|
+
separator: DEFAULT_SEPARATOR,
|
|
29
|
+
floating: nil,
|
|
30
|
+
**kwargs
|
|
31
|
+
)
|
|
12
32
|
raise ArgumentError, "floating labels are not supported for code fields" if floating.present?
|
|
13
33
|
|
|
14
34
|
validate_code_options!(length, groups)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
35
|
+
config = {
|
|
36
|
+
error: error,
|
|
37
|
+
length: length,
|
|
38
|
+
charset: charset,
|
|
39
|
+
groups: groups,
|
|
40
|
+
separator: separator,
|
|
41
|
+
autocomplete: kwargs.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE,
|
|
42
|
+
inputmode: kwargs.delete(:inputmode) || (charset.to_sym == DEFAULT_CHARSET ? "numeric" : nil),
|
|
43
|
+
kwargs: kwargs
|
|
44
|
+
}
|
|
20
45
|
render_code_field(attribute, html_opts, opts, config)
|
|
21
46
|
end
|
|
22
47
|
|
|
23
48
|
def render_code_field(attribute, html_opts, opts, config)
|
|
24
|
-
|
|
49
|
+
overlay_options = merge_html_options(
|
|
50
|
+
theme.resolve(:form_field_input_code_overlay, error: config[:error]),
|
|
51
|
+
opts,
|
|
52
|
+
html_opts
|
|
53
|
+
)
|
|
54
|
+
wrapper_options = merge_html_options(
|
|
55
|
+
theme.resolve(:form_field_input_code, error: config[:error]),
|
|
56
|
+
code_options(config)
|
|
57
|
+
)
|
|
58
|
+
@template.content_tag(:div, **wrapper_options) do
|
|
25
59
|
@template.safe_join(
|
|
26
|
-
[render_code_cells(config), code_input(attribute,
|
|
60
|
+
[render_code_cells(config), code_input(attribute, overlay_options, config)]
|
|
27
61
|
)
|
|
28
62
|
end
|
|
29
63
|
end
|
|
30
64
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
controller: "input-formatter",
|
|
65
|
+
def code_options(config)
|
|
66
|
+
{
|
|
67
|
+
data: {
|
|
68
|
+
controller: STIMULUS_CONTROLLER,
|
|
36
69
|
input_formatter_format_value: "code",
|
|
37
|
-
input_formatter_options_value: { charset: config[:charset].to_s, length: config[:length] }
|
|
38
|
-
input_formatter_groups_value: config
|
|
70
|
+
input_formatter_options_value: { charset: config[:charset].to_s, length: config[:length] },
|
|
71
|
+
input_formatter_groups_value: code_groups_value(config)
|
|
39
72
|
}
|
|
40
|
-
}
|
|
41
|
-
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Server-rendered separators already mark the group breaks. Passing groups as well
|
|
77
|
+
# would stamp data-group-end and lay the themed gap on top of the separator.
|
|
78
|
+
def code_groups_value(config)
|
|
79
|
+
return if config[:separator].present?
|
|
80
|
+
|
|
81
|
+
config[:groups].presence
|
|
42
82
|
end
|
|
43
83
|
|
|
44
|
-
def code_input(attribute, html_opts,
|
|
84
|
+
def code_input(attribute, html_opts, config)
|
|
45
85
|
input_options = merge_html_options(
|
|
46
|
-
theme.resolve(:form_field_input_code_overlay, error: config[:error]),
|
|
47
|
-
opts,
|
|
48
86
|
html_opts,
|
|
49
87
|
config[:kwargs],
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
88
|
+
{
|
|
89
|
+
maxlength: config[:length],
|
|
90
|
+
autocomplete: config[:autocomplete],
|
|
91
|
+
inputmode: config[:inputmode],
|
|
92
|
+
data: { input_formatter_target: "input", action: STIMULUS_ACTION }
|
|
93
|
+
}
|
|
53
94
|
)
|
|
54
95
|
@template.text_field(@object_name, attribute, objectify_options(input_options))
|
|
55
96
|
end
|
|
56
97
|
|
|
57
98
|
def render_code_cells(config)
|
|
58
|
-
|
|
99
|
+
@template.content_tag(:div, **merge_html_options(theme.resolve(:form_field_input_code_cells))) do
|
|
100
|
+
@template.safe_join(code_cells(config))
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def code_cells(config)
|
|
105
|
+
groups = config[:groups].presence || [config[:length]]
|
|
106
|
+
groups.flat_map.with_index do |width, index|
|
|
107
|
+
cells = Array.new(width) { render_code_cell(config) }
|
|
108
|
+
index.zero? || config[:separator].blank? ? cells : [render_code_separator(config), *cells]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def render_code_cell(config)
|
|
59
113
|
cell_options = merge_html_options(
|
|
60
114
|
theme.resolve(:form_field_input_code_cell, error: config[:error]),
|
|
61
115
|
{ data: { input_formatter_target: "cell" } }
|
|
62
116
|
)
|
|
63
|
-
@template.content_tag(:
|
|
64
|
-
|
|
65
|
-
|
|
117
|
+
@template.content_tag(:span, nil, **cell_options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def render_code_separator(config)
|
|
121
|
+
separator_options = merge_html_options(
|
|
122
|
+
theme.resolve(:form_field_input_code_separator),
|
|
123
|
+
{ aria: { hidden: true } }
|
|
124
|
+
)
|
|
125
|
+
@template.content_tag(:span, config[:separator], **separator_options)
|
|
66
126
|
end
|
|
67
127
|
|
|
68
128
|
def validate_code_options!(length, groups)
|
|
@@ -73,11 +133,12 @@ module StimulusPlumbers
|
|
|
73
133
|
raise ArgumentError, "groups must add up to length" unless groups.sum == length
|
|
74
134
|
end
|
|
75
135
|
|
|
76
|
-
def valid_groups?(groups)
|
|
77
|
-
|
|
136
|
+
def valid_groups?(groups)
|
|
137
|
+
groups.is_a?(Array) && groups.all? { |group| positive_integer?(group) }
|
|
138
|
+
end
|
|
78
139
|
|
|
79
|
-
def
|
|
80
|
-
|
|
140
|
+
def positive_integer?(value)
|
|
141
|
+
value.is_a?(Integer) && value.positive?
|
|
81
142
|
end
|
|
82
143
|
end
|
|
83
144
|
end
|
|
@@ -5,64 +5,96 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module CreditCard
|
|
8
|
-
|
|
8
|
+
STIMULUS_CONTROLLER = "input-formatter"
|
|
9
|
+
STIMULUS_ACTION = [
|
|
10
|
+
"input->#{STIMULUS_CONTROLLER}#onInput",
|
|
11
|
+
"focus->#{STIMULUS_CONTROLLER}#onFocus",
|
|
12
|
+
"blur->#{STIMULUS_CONTROLLER}#onBlur"
|
|
13
|
+
].join(" ").freeze
|
|
14
|
+
DEFAULT_GROUPS = [4, 4, 4, 4].freeze
|
|
15
|
+
DEFAULT_AUTOCOMPLETE = "cc-number"
|
|
16
|
+
DEFAULT_INPUTMODE = "numeric"
|
|
17
|
+
DEFAULT_SEPARATOR = nil
|
|
9
18
|
|
|
10
19
|
private
|
|
11
20
|
|
|
12
|
-
def render_credit_card_input(
|
|
21
|
+
def render_credit_card_input(
|
|
22
|
+
attribute,
|
|
23
|
+
html_opts,
|
|
24
|
+
opts,
|
|
25
|
+
error,
|
|
26
|
+
groups: DEFAULT_GROUPS,
|
|
27
|
+
separator: DEFAULT_SEPARATOR,
|
|
28
|
+
floating: nil,
|
|
29
|
+
**kwargs
|
|
30
|
+
)
|
|
13
31
|
raise ArgumentError, "floating labels are not supported for credit card fields" if floating.present?
|
|
14
32
|
|
|
15
33
|
normalized_groups = groups.presence || DEFAULT_GROUPS
|
|
16
|
-
inputmode = kwargs.delete(:inputmode) || "numeric"
|
|
17
|
-
autocomplete = kwargs.delete(:autocomplete) || "cc-number"
|
|
18
34
|
validate_credit_card_groups!(normalized_groups)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
config = {
|
|
36
|
+
error: error,
|
|
37
|
+
groups: normalized_groups,
|
|
38
|
+
length: normalized_groups.sum,
|
|
39
|
+
separator: separator,
|
|
40
|
+
autocomplete: kwargs.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE,
|
|
41
|
+
inputmode: kwargs.delete(:inputmode) || DEFAULT_INPUTMODE,
|
|
42
|
+
kwargs: kwargs
|
|
43
|
+
}
|
|
23
44
|
render_credit_card_field(attribute, html_opts, opts, config)
|
|
24
45
|
end
|
|
25
46
|
|
|
26
47
|
def render_credit_card_field(attribute, html_opts, opts, config)
|
|
27
|
-
|
|
48
|
+
overlay_options = merge_html_options(
|
|
49
|
+
theme.resolve(:form_field_input_credit_card_overlay, error: config[:error]),
|
|
50
|
+
opts,
|
|
51
|
+
html_opts
|
|
52
|
+
)
|
|
53
|
+
wrapper_options = merge_html_options(
|
|
54
|
+
theme.resolve(:form_field_input_credit_card, error: config[:error]),
|
|
55
|
+
credit_card_options(config)
|
|
56
|
+
)
|
|
57
|
+
@template.content_tag(:div, **wrapper_options) do
|
|
28
58
|
@template.safe_join(
|
|
29
|
-
[render_credit_card_cells(config), credit_card_input(attribute,
|
|
59
|
+
[render_credit_card_cells(config), credit_card_input(attribute, overlay_options, config)]
|
|
30
60
|
)
|
|
31
61
|
end
|
|
32
62
|
end
|
|
33
63
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
controller: "input-formatter",
|
|
64
|
+
def credit_card_options(config)
|
|
65
|
+
{
|
|
66
|
+
data: {
|
|
67
|
+
controller: STIMULUS_CONTROLLER,
|
|
39
68
|
input_formatter_format_value: "creditCard",
|
|
40
69
|
input_formatter_groups_value: config[:groups]
|
|
41
70
|
}
|
|
42
|
-
}
|
|
43
|
-
)
|
|
71
|
+
}
|
|
44
72
|
end
|
|
45
73
|
|
|
46
|
-
def credit_card_input(attribute, html_opts,
|
|
74
|
+
def credit_card_input(attribute, html_opts, config)
|
|
47
75
|
input_options = merge_html_options(
|
|
48
|
-
theme.resolve(:form_field_input_credit_card_overlay, error: config[:error]),
|
|
49
|
-
opts,
|
|
50
76
|
html_opts,
|
|
51
77
|
config[:kwargs],
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
{
|
|
79
|
+
maxlength: config[:length],
|
|
80
|
+
autocomplete: config[:autocomplete],
|
|
81
|
+
inputmode: config[:inputmode],
|
|
82
|
+
data: { input_formatter_target: "input", action: STIMULUS_ACTION }
|
|
83
|
+
}
|
|
55
84
|
)
|
|
56
85
|
@template.text_field(@object_name, attribute, objectify_options(input_options))
|
|
57
86
|
end
|
|
58
87
|
|
|
59
88
|
def render_credit_card_cells(config)
|
|
60
|
-
|
|
61
|
-
|
|
89
|
+
@template.content_tag(:div, **merge_html_options(theme.resolve(:form_field_input_credit_card_cells))) do
|
|
90
|
+
@template.safe_join(credit_card_cells(config))
|
|
62
91
|
end
|
|
92
|
+
end
|
|
63
93
|
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
def credit_card_cells(config)
|
|
95
|
+
config[:groups].each_index.flat_map do |index|
|
|
96
|
+
cell = render_credit_card_cell(config)
|
|
97
|
+
index.zero? || config[:separator].blank? ? [cell] : [render_credit_card_separator(config), cell]
|
|
66
98
|
end
|
|
67
99
|
end
|
|
68
100
|
|
|
@@ -74,12 +106,12 @@ module StimulusPlumbers
|
|
|
74
106
|
@template.content_tag(:span, nil, **cell_options)
|
|
75
107
|
end
|
|
76
108
|
|
|
77
|
-
def render_credit_card_separator
|
|
109
|
+
def render_credit_card_separator(config)
|
|
78
110
|
separator_options = merge_html_options(
|
|
79
111
|
theme.resolve(:form_field_input_credit_card_separator),
|
|
80
112
|
{ aria: { hidden: true } }
|
|
81
113
|
)
|
|
82
|
-
@template.content_tag(:span,
|
|
114
|
+
@template.content_tag(:span, config[:separator], **separator_options)
|
|
83
115
|
end
|
|
84
116
|
|
|
85
117
|
def validate_credit_card_groups!(groups)
|
|
@@ -87,10 +119,6 @@ module StimulusPlumbers
|
|
|
87
119
|
|
|
88
120
|
raise ArgumentError, "groups must be an array of positive integers"
|
|
89
121
|
end
|
|
90
|
-
|
|
91
|
-
def formatter_actions
|
|
92
|
-
"input->input-formatter#onInput focus->input-formatter#onFocus blur->input-formatter#onBlur"
|
|
93
|
-
end
|
|
94
122
|
end
|
|
95
123
|
end
|
|
96
124
|
end
|
|
@@ -5,11 +5,19 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Password
|
|
8
|
+
STIMULUS_CONTROLLER = "input-revealable"
|
|
9
|
+
STIMULUS_ACTION = "click->#{STIMULUS_CONTROLLER}#toggle".freeze
|
|
10
|
+
DEFAULT_AUTOCOMPLETE = "current-password"
|
|
11
|
+
|
|
8
12
|
def password_field(attribute, floating: nil, revealable: false, **options)
|
|
9
|
-
html_options = merge_html_options(
|
|
13
|
+
html_options = merge_html_options(
|
|
14
|
+
theme.resolve(:form_field_input, floating: floating),
|
|
15
|
+
options,
|
|
16
|
+
{ autocomplete: options.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE }
|
|
17
|
+
)
|
|
10
18
|
if revealable
|
|
11
19
|
render_revealable_password(false) do
|
|
12
|
-
super(attribute, merge_html_options(html_options, { data: {
|
|
20
|
+
super(attribute, merge_html_options(html_options, { data: { input_revealable_target: "input" } }))
|
|
13
21
|
end
|
|
14
22
|
else
|
|
15
23
|
super(attribute, html_options)
|
|
@@ -23,11 +31,12 @@ module StimulusPlumbers
|
|
|
23
31
|
theme.resolve(:form_field_input, floating: floating, error: error),
|
|
24
32
|
opts,
|
|
25
33
|
html_opts,
|
|
26
|
-
kwargs
|
|
34
|
+
kwargs,
|
|
35
|
+
{ autocomplete: kwargs.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE }
|
|
27
36
|
)
|
|
28
37
|
if revealable
|
|
29
38
|
render_revealable_password(error, floating: floating) do
|
|
30
|
-
revealable_html_options = merge_html_options(html_options, { data: {
|
|
39
|
+
revealable_html_options = merge_html_options(html_options, { data: { input_revealable_target: "input" } })
|
|
31
40
|
@template.password_field(@object_name, attribute, objectify_options(revealable_html_options))
|
|
32
41
|
end
|
|
33
42
|
else
|
|
@@ -42,22 +51,38 @@ module StimulusPlumbers
|
|
|
42
51
|
trailing: method(:reveal_button),
|
|
43
52
|
**merge_html_options(
|
|
44
53
|
theme.resolve(:form_field_input_reveal, error: error),
|
|
45
|
-
|
|
54
|
+
data: reveal_data
|
|
46
55
|
)
|
|
47
56
|
) { @template.capture(&block) }
|
|
48
57
|
end
|
|
49
58
|
|
|
50
59
|
def reveal_button
|
|
51
60
|
build_reveal_button do
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
size: :sm,
|
|
55
|
-
aria: { hidden: "true" },
|
|
56
|
-
**theme.resolve(:button_icon)
|
|
61
|
+
@template.safe_join(
|
|
62
|
+
[password_icon("reveal", "revealIcon"), password_icon("conceal", "concealIcon", hidden: true)]
|
|
57
63
|
)
|
|
58
64
|
end
|
|
59
65
|
end
|
|
60
66
|
|
|
67
|
+
def reveal_data
|
|
68
|
+
{
|
|
69
|
+
controller: STIMULUS_CONTROLLER,
|
|
70
|
+
input_revealable_reveal_label_value: I18n.t("stimulus_plumbers.form.password.show", default: "Show password"),
|
|
71
|
+
input_revealable_conceal_label_value: I18n.t("stimulus_plumbers.form.password.hide", default: "Hide password")
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def password_icon(name, target, hidden: false)
|
|
76
|
+
Components::Icon.new(@template).render(
|
|
77
|
+
name,
|
|
78
|
+
size: :sm,
|
|
79
|
+
aria: { hidden: "true" },
|
|
80
|
+
data: { input_revealable_target: target },
|
|
81
|
+
hidden: hidden,
|
|
82
|
+
**theme.resolve(:button_icon)
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
61
86
|
def build_reveal_button(&block)
|
|
62
87
|
@template.content_tag(
|
|
63
88
|
:button,
|
|
@@ -65,8 +90,8 @@ module StimulusPlumbers
|
|
|
65
90
|
theme.resolve(:form_field_input_button_reveal),
|
|
66
91
|
{
|
|
67
92
|
type: "button",
|
|
68
|
-
aria: { label: I18n.t("stimulus_plumbers.form.password.show", default: "Show password")
|
|
69
|
-
data: {
|
|
93
|
+
aria: { label: I18n.t("stimulus_plumbers.form.password.show", default: "Show password") },
|
|
94
|
+
data: { input_revealable_target: "toggle", action: STIMULUS_ACTION }
|
|
70
95
|
}
|
|
71
96
|
)
|
|
72
97
|
) { @template.capture(&block) }
|
|
@@ -5,22 +5,67 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Submit
|
|
8
|
+
include Components::Button::IconLayout
|
|
9
|
+
|
|
8
10
|
def submit(value = nil, options = {})
|
|
9
|
-
|
|
10
|
-
options = value
|
|
11
|
-
value = nil
|
|
12
|
-
end
|
|
11
|
+
value, options = normalize_submit_arguments(value, options)
|
|
13
12
|
value ||= submit_default_value
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
submit_options = extract_submit_options(options)
|
|
14
|
+
|
|
15
|
+
validate_submit_accessible_name!(value, options)
|
|
16
|
+
|
|
17
|
+
render_submit_button(value, options, **submit_options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def normalize_submit_arguments(value, options)
|
|
23
|
+
value.is_a?(Hash) ? [nil, value] : [value, options]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def extract_submit_options(options)
|
|
27
|
+
{
|
|
28
|
+
type: options.delete(:type) { :default },
|
|
29
|
+
variant: options.delete(:variant) { :primary },
|
|
30
|
+
icon_leading: options.delete(:icon_leading),
|
|
31
|
+
icon_trailing: options.delete(:icon_trailing),
|
|
32
|
+
hide_label: options.delete(:hide_label) { false }
|
|
33
|
+
}
|
|
34
|
+
end
|
|
16
35
|
|
|
36
|
+
def render_submit_button(value, options, type:, variant:, icon_leading:, icon_trailing:, hide_label:)
|
|
17
37
|
Components::Button.new(@template).build(type: type, variant: variant) do |attrs|
|
|
18
38
|
@template.tag.button(
|
|
19
39
|
type: "submit",
|
|
20
40
|
**merge_html_options(attrs, theme.resolve(:form_submit, type: type, variant: variant), options)
|
|
21
|
-
) {
|
|
41
|
+
) { build_layout(submit_slots(icon_leading, icon_trailing)) { submit_label(value, hide_label) } }
|
|
22
42
|
end
|
|
23
43
|
end
|
|
44
|
+
|
|
45
|
+
def submit_slots(icon_leading, icon_trailing)
|
|
46
|
+
Components::Button::Slots.new(@template).tap do |slots|
|
|
47
|
+
slots.with_icon_leading(icon_leading) if icon_leading
|
|
48
|
+
slots.with_icon_trailing(icon_trailing) if icon_trailing
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def submit_label(value, hide_label)
|
|
53
|
+
@template.content_tag(
|
|
54
|
+
:span,
|
|
55
|
+
value,
|
|
56
|
+
**merge_html_options(
|
|
57
|
+
theme.resolve(:form_submit_label, hidden: hide_label),
|
|
58
|
+
(hide_label ? { data: { sp_label_hidden: true } } : {})
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def validate_submit_accessible_name!(value, options)
|
|
64
|
+
return if value.present? || options.dig(:aria, :label).present? ||
|
|
65
|
+
options.dig(:aria, :labelledby).present? || options[:"aria-label"].present?
|
|
66
|
+
|
|
67
|
+
raise ArgumentError, "submit button has no accessible name: pass a value or aria: { label: ... }"
|
|
68
|
+
end
|
|
24
69
|
end
|
|
25
70
|
end
|
|
26
71
|
end
|
|
@@ -74,6 +74,7 @@ module StimulusPlumbers
|
|
|
74
74
|
|
|
75
75
|
entry = "/#{relative_to_destination(path)}"
|
|
76
76
|
return if File.readlines(gitignore, chomp: true).include?(entry)
|
|
77
|
+
return if git_ignores?(path)
|
|
77
78
|
|
|
78
79
|
File.open(gitignore, "a") { |file| file.puts(entry) }
|
|
79
80
|
say_status :append, ".gitignore", :green
|
|
@@ -81,6 +82,15 @@ module StimulusPlumbers
|
|
|
81
82
|
say "Could not update .gitignore: #{e.message}. Skipping.", :yellow
|
|
82
83
|
end
|
|
83
84
|
|
|
85
|
+
def git_ignores?(path)
|
|
86
|
+
Dir.chdir(destination_root) do
|
|
87
|
+
system("git", "check-ignore", "-q", relative_to_destination(path), out: File::NULL, err: File::NULL)
|
|
88
|
+
end
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
say "Could not check .gitignore coverage with git: #{e.message}. Proceeding to append.", :yellow
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
# CSS copied by an installer belongs to the application from this point on.
|
|
85
95
|
# Keep an existing file intact so a generator rerun never overwrites local
|
|
86
96
|
# customizations (the same policy used by tailwindcss-rails' installer).
|
|
@@ -8,19 +8,21 @@ require_relative "dispatcher/klass_proxy"
|
|
|
8
8
|
module StimulusPlumbers
|
|
9
9
|
module Plumber
|
|
10
10
|
module Dispatcher
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
class << self
|
|
12
|
+
def build(callable, *args, method_name: nil, init_args: [], init_kwargs: {}, **kwargs, &block)
|
|
13
|
+
case callable
|
|
14
|
+
when Symbol
|
|
15
|
+
MethodCall.new(callable, *args, **kwargs, &block)
|
|
16
|
+
when Proc
|
|
17
|
+
InstanceExec.new(callable, *args, **kwargs)
|
|
18
|
+
when Module
|
|
19
|
+
KlassProxy.new(callable, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs, &block)
|
|
20
|
+
when String
|
|
21
|
+
klass = callable.safe_constantize
|
|
22
|
+
raise ArgumentError, "could not resolve class from: #{callable.inspect}" unless klass
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
KlassProxy.new(klass, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs, &block)
|
|
25
|
+
end
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
module StimulusPlumbers
|
|
4
4
|
module Plumber
|
|
5
5
|
class Slots
|
|
6
|
-
def self.slot(*names, by: nil)
|
|
7
|
-
names.each do |name|
|
|
8
|
-
by ? define_by_slot(name, by) : define_flat_slot(name)
|
|
9
|
-
define_reader(name)
|
|
10
|
-
define_predicate(name)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
6
|
def initialize(template = nil)
|
|
15
7
|
@slots = {}
|
|
16
8
|
@template = template
|
|
@@ -50,6 +42,14 @@ module StimulusPlumbers
|
|
|
50
42
|
end
|
|
51
43
|
|
|
52
44
|
class << self
|
|
45
|
+
def slot(*names, by: nil)
|
|
46
|
+
names.each do |name|
|
|
47
|
+
by ? define_by_slot(name, by) : define_flat_slot(name)
|
|
48
|
+
define_reader(name)
|
|
49
|
+
define_predicate(name)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
53
|
private
|
|
54
54
|
|
|
55
55
|
def define_flat_slot(name)
|
|
@@ -186,6 +186,7 @@ module StimulusPlumbers
|
|
|
186
186
|
form_field_input_code_cell: {
|
|
187
187
|
error: { default: false, validate: Ranges::BOOL }
|
|
188
188
|
}.freeze,
|
|
189
|
+
form_field_input_code_separator: {}.freeze,
|
|
189
190
|
form_field_input_code_overlay: {
|
|
190
191
|
error: { default: false, validate: Ranges::BOOL }
|
|
191
192
|
}.freeze,
|
|
@@ -205,6 +206,9 @@ module StimulusPlumbers
|
|
|
205
206
|
form_submit: {
|
|
206
207
|
type: { default: :default, validate: Button::Ranges::TYPE },
|
|
207
208
|
variant: { default: :primary, validate: Button::Ranges::VARIANT }
|
|
209
|
+
}.freeze,
|
|
210
|
+
form_submit_label: {
|
|
211
|
+
hidden: { default: false, validate: Ranges::BOOL }
|
|
208
212
|
}.freeze
|
|
209
213
|
}.freeze
|
|
210
214
|
|