stimulus_plumbers 0.4.0 → 0.4.2
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 +24 -0
- data/README.md +11 -4
- data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +125 -12
- data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.es.js +681 -312
- data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.umd.js +1 -1
- data/app/assets/stylesheets/stimulus_plumbers/tokens.css +26 -22
- data/config/locales/en.yml +21 -0
- data/lib/stimulus_plumbers/components/avatar.rb +13 -5
- data/lib/stimulus_plumbers/components/calendar/turbo/days_of_month.rb +47 -7
- data/lib/stimulus_plumbers/components/calendar/turbo/months_of_year.rb +56 -18
- data/lib/stimulus_plumbers/components/calendar/turbo/years_of_decade.rb +44 -16
- data/lib/stimulus_plumbers/components/calendar/turbo.rb +59 -12
- data/lib/stimulus_plumbers/components/calendar.rb +48 -64
- data/lib/stimulus_plumbers/components/card.rb +7 -7
- data/lib/stimulus_plumbers/components/combobox/date/navigation.rb +16 -8
- data/lib/stimulus_plumbers/components/combobox/date/navigator.rb +3 -1
- data/lib/stimulus_plumbers/components/combobox/date.rb +35 -18
- data/lib/stimulus_plumbers/components/combobox/time.rb +56 -50
- data/lib/stimulus_plumbers/components/input_group.rb +2 -2
- data/lib/stimulus_plumbers/components/list/item.rb +2 -2
- data/lib/stimulus_plumbers/components/list/section.rb +1 -1
- data/lib/stimulus_plumbers/components/popover.rb +1 -1
- data/lib/stimulus_plumbers/components/timeline/event/slots.rb +18 -0
- data/lib/stimulus_plumbers/components/timeline/event.rb +189 -0
- data/lib/stimulus_plumbers/components/timeline/group.rb +42 -0
- data/lib/stimulus_plumbers/components/timeline.rb +40 -0
- data/lib/stimulus_plumbers/form/builder.rb +11 -3
- data/lib/stimulus_plumbers/form/field.rb +4 -5
- data/lib/stimulus_plumbers/form/fields/inputs/checkbox.rb +1 -1
- data/lib/stimulus_plumbers/form/fields/inputs/combobox.rb +2 -2
- data/lib/stimulus_plumbers/form/fields/inputs/datetime.rb +13 -1
- data/lib/stimulus_plumbers/form/fields/inputs/file.rb +9 -4
- data/lib/stimulus_plumbers/form/fields/inputs/password.rb +35 -24
- data/lib/stimulus_plumbers/form/fields/inputs/radio.rb +15 -3
- data/lib/stimulus_plumbers/form/fields/inputs/search.rb +62 -31
- data/lib/stimulus_plumbers/form/fields/inputs/select.rb +3 -1
- data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +4 -4
- data/lib/stimulus_plumbers/form/fields/inputs/text.rb +9 -4
- data/lib/stimulus_plumbers/form/fields/inputs/text_area.rb +9 -4
- data/lib/stimulus_plumbers/form/fields/label/floating.rb +3 -3
- data/lib/stimulus_plumbers/helpers/calendar_helper.rb +1 -1
- data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +22 -2
- data/lib/stimulus_plumbers/helpers/timeline_helper.rb +15 -0
- data/lib/stimulus_plumbers/helpers.rb +2 -0
- data/lib/stimulus_plumbers/plumber/renderer.rb +2 -2
- data/lib/stimulus_plumbers/themes/base.rb +2 -1
- data/lib/stimulus_plumbers/themes/schema/form/floating/ranges.rb +15 -0
- data/lib/stimulus_plumbers/themes/schema.rb +63 -16
- data/lib/stimulus_plumbers/version.rb +1 -1
- data/lib/stimulus_plumbers.rb +4 -1
- metadata +7 -2
- data/lib/stimulus_plumbers/components/combobox/time/drum.rb +0 -43
|
@@ -30,84 +30,86 @@ module StimulusPlumbers
|
|
|
30
30
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
|
-
def render_time(panel_attrs: {}, format: :h12, step: 1, value: nil, label:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@time = parse_time(value)
|
|
33
|
+
def render_time(panel_attrs: {}, format: :h12, step: 1, value: nil, label: nil, labelledby: nil)
|
|
34
|
+
step = [1, step.to_i].max
|
|
35
|
+
time = parse_time(value)
|
|
37
36
|
|
|
38
|
-
attrs = merge_html_options(
|
|
39
|
-
|
|
40
|
-
theme.resolve(:combobox_time),
|
|
41
|
-
dialog_attrs(label, labelledby)
|
|
42
|
-
)
|
|
43
|
-
template.content_tag(:div, **attrs) { template.safe_join(drums) }
|
|
37
|
+
attrs = merge_html_options(panel_attrs, theme.resolve(:combobox_time), dialog_attrs(label, labelledby))
|
|
38
|
+
template.content_tag(:div, **attrs) { template.safe_join(drums(format, step, time)) }
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
def dialog_attrs(label, labelledby)
|
|
42
|
+
resolved_label = label || I18n.t("stimulus_plumbers.combobox.time.dialog_label")
|
|
47
43
|
{
|
|
48
44
|
role: "dialog",
|
|
49
|
-
aria: labelled_aria(
|
|
45
|
+
aria: labelled_aria(resolved_label, labelledby: labelledby),
|
|
50
46
|
data: { controller: STIMULUS_CONTROLLER, action: STIMULUS_ACTION }
|
|
51
47
|
}
|
|
52
48
|
end
|
|
53
49
|
|
|
54
|
-
def drums
|
|
55
|
-
cols = [hour_drum, minute_drum]
|
|
56
|
-
cols << period_drum if
|
|
50
|
+
def drums(format, step, time)
|
|
51
|
+
cols = [hour_drum(format, time), minute_drum(step, time)]
|
|
52
|
+
cols << period_drum(time) if format == :h12
|
|
57
53
|
cols
|
|
58
54
|
end
|
|
59
55
|
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
56
|
+
def hour_drum(format, time)
|
|
57
|
+
items = if format == :h12
|
|
58
|
+
(1..12).map { |h| [h.to_s] * 2 }
|
|
59
|
+
else
|
|
60
|
+
(0..23).map { |h| [h.to_s.rjust(2, "0")] * 2 }
|
|
61
|
+
end
|
|
62
|
+
render_drum("hour", t("hour_label"), items, selected_hour(format, time))
|
|
68
63
|
end
|
|
69
64
|
|
|
70
|
-
def
|
|
71
|
-
|
|
65
|
+
def minute_drum(step, time)
|
|
66
|
+
items = (0...60).step(step).map { |m| [m.to_s.rjust(2, "0")] * 2 }
|
|
67
|
+
selected = time ? round_minute(time.min, step).to_s.rjust(2, "0") : nil
|
|
68
|
+
render_drum("minute", t("minute_label"), items, selected)
|
|
72
69
|
end
|
|
73
70
|
|
|
74
|
-
def
|
|
75
|
-
items = (
|
|
76
|
-
selected =
|
|
77
|
-
render_drum("
|
|
71
|
+
def period_drum(time)
|
|
72
|
+
items = [[t("am"), "AM"], [t("pm"), "PM"]]
|
|
73
|
+
selected = time && (time.hour < 12 ? "AM" : "PM")
|
|
74
|
+
render_drum("period", t("period_label"), items, selected)
|
|
78
75
|
end
|
|
79
76
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def hour_items
|
|
85
|
-
if @format == :h12
|
|
86
|
-
(1..12).map { |h| [h.to_s, h.to_s] }
|
|
87
|
-
else
|
|
88
|
-
(0..23).map { |h| [h.to_s.rjust(2, "0")] * 2 }
|
|
89
|
-
end
|
|
90
|
-
end
|
|
77
|
+
def selected_hour(format, time)
|
|
78
|
+
return nil unless time
|
|
91
79
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if @format == :h12
|
|
96
|
-
h = @time.hour % 12
|
|
80
|
+
if format == :h12
|
|
81
|
+
h = time.hour % 12
|
|
97
82
|
(h.zero? ? 12 : h).to_s
|
|
98
83
|
else
|
|
99
|
-
|
|
84
|
+
time.hour.to_s.rjust(2, "0")
|
|
100
85
|
end
|
|
101
86
|
end
|
|
102
87
|
|
|
103
|
-
def
|
|
104
|
-
return minute if
|
|
88
|
+
def round_minute(minute, step)
|
|
89
|
+
return minute if step == 1
|
|
105
90
|
|
|
106
|
-
((minute.to_f /
|
|
91
|
+
((minute.to_f / step).round * step) % 60
|
|
107
92
|
end
|
|
108
93
|
|
|
109
|
-
def
|
|
110
|
-
|
|
94
|
+
def render_drum(target, label, items, selected)
|
|
95
|
+
attrs = merge_html_options(
|
|
96
|
+
theme.resolve(:combobox_listbox),
|
|
97
|
+
theme.resolve(:combobox_time_drum, type: target == "period" ? :period : :unit),
|
|
98
|
+
{
|
|
99
|
+
role: "listbox",
|
|
100
|
+
tabindex: "0",
|
|
101
|
+
aria: { label: label },
|
|
102
|
+
data: { "#{STIMULUS_CONTROLLER}_target": target }
|
|
103
|
+
},
|
|
104
|
+
{ data: { action: "click->#{STIMULUS_CONTROLLER}#select keydown->#{STIMULUS_CONTROLLER}#onNavigate" } }
|
|
105
|
+
)
|
|
106
|
+
template.content_tag(:ul, **attrs) do
|
|
107
|
+
template.safe_join(
|
|
108
|
+
items.map do |text, value|
|
|
109
|
+
Options::Option.new(template).render(label: text, value: value, selected: value.to_s == selected.to_s)
|
|
110
|
+
end
|
|
111
|
+
)
|
|
112
|
+
end
|
|
111
113
|
end
|
|
112
114
|
|
|
113
115
|
def parse_time(value)
|
|
@@ -117,6 +119,10 @@ module StimulusPlumbers
|
|
|
117
119
|
rescue ArgumentError
|
|
118
120
|
nil
|
|
119
121
|
end
|
|
122
|
+
|
|
123
|
+
def t(key)
|
|
124
|
+
I18n.t("stimulus_plumbers.combobox.time.#{key}")
|
|
125
|
+
end
|
|
120
126
|
end
|
|
121
127
|
end
|
|
122
128
|
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module StimulusPlumbers
|
|
4
4
|
module Components
|
|
5
5
|
class InputGroup < Plumber::Base
|
|
6
|
-
def render(leading: nil, trailing: nil, error: false, **kwargs, &block)
|
|
6
|
+
def render(leading: nil, trailing: nil, error: false, floating: nil, **kwargs, &block)
|
|
7
7
|
html_options = merge_html_options(
|
|
8
|
-
theme.resolve(:input_group, error: error),
|
|
8
|
+
theme.resolve(:input_group, error: error, floating: floating),
|
|
9
9
|
kwargs
|
|
10
10
|
)
|
|
11
11
|
template.content_tag(:div, **html_options) do
|
|
@@ -66,7 +66,7 @@ module StimulusPlumbers
|
|
|
66
66
|
return unless title || description
|
|
67
67
|
|
|
68
68
|
template.content_tag(:span, **merge_html_options(theme.resolve(:list_item_content))) do
|
|
69
|
-
template.safe_join([title, description]
|
|
69
|
+
template.safe_join([title, description])
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -75,7 +75,7 @@ module StimulusPlumbers
|
|
|
75
75
|
icon_trailing = render_icon_slot(slots, :icon_trailing)
|
|
76
76
|
content = render_content_slot(slots)
|
|
77
77
|
|
|
78
|
-
template.safe_join([icon_leading, content, icon_trailing]
|
|
78
|
+
template.safe_join([icon_leading, content, icon_trailing])
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
@@ -16,7 +16,7 @@ module StimulusPlumbers
|
|
|
16
16
|
@trigger_html = nil
|
|
17
17
|
@panel_html = nil
|
|
18
18
|
yield self
|
|
19
|
-
template.safe_join([@trigger_html, @panel_html]
|
|
19
|
+
template.safe_join([@trigger_html, @panel_html])
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def trigger(haspopup: "dialog", controls: @panel_id, **kwargs, &block)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class Timeline
|
|
6
|
+
class Event
|
|
7
|
+
class Slots < Plumber::Slots
|
|
8
|
+
slot :indicator, :time, :title, :trigger, :description, :detail, :actions
|
|
9
|
+
|
|
10
|
+
def with_indicator(icon: nil)
|
|
11
|
+
set_slot(:indicator, icon, { type: icon ? :icon : :dot, icon: icon })
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class Timeline
|
|
6
|
+
class Event < Plumber::Base
|
|
7
|
+
attr_reader :interactive
|
|
8
|
+
|
|
9
|
+
def self.detail_id_for(event_id)
|
|
10
|
+
[event_id, "detail"].compact.join("_")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def render(datetime: nil, id: nil, interactive: false, orientation: :vertical, **kwargs, &block)
|
|
14
|
+
@detail_id = self.class.detail_id_for(id || template.sp_dom_id)
|
|
15
|
+
|
|
16
|
+
slots = Timeline::Event::Slots.new
|
|
17
|
+
yield slots if block_given?
|
|
18
|
+
|
|
19
|
+
validate_slots!(slots, datetime: datetime)
|
|
20
|
+
@orientation = orientation
|
|
21
|
+
@interactive = interactive || slots.trigger?
|
|
22
|
+
|
|
23
|
+
html_options = merge_html_options(theme.resolve(:timeline_item, orientation: orientation), kwargs)
|
|
24
|
+
render_event(slots, datetime: datetime, html_options: html_options)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def validate_slots!(slots, datetime:)
|
|
30
|
+
raise ArgumentError, "e.title and e.trigger are mutually exclusive" if slots.title? && slots.trigger?
|
|
31
|
+
raise ArgumentError, "e.detail requires e.trigger" if slots.detail? && !slots.trigger?
|
|
32
|
+
raise ArgumentError, "e.time requires datetime:" if slots.time? && datetime.nil?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def render_event(slots, datetime:, html_options:)
|
|
36
|
+
template.content_tag(:li, **html_options) do
|
|
37
|
+
if @orientation.to_sym == :horizontal
|
|
38
|
+
render_horizontal_event(slots, datetime: datetime)
|
|
39
|
+
else
|
|
40
|
+
render_vertical_event(slots, datetime: datetime)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def render_vertical_event(slots, datetime:)
|
|
46
|
+
content_col = template.content_tag(:div, class: "flex-1 min-w-0") do
|
|
47
|
+
template.safe_join(
|
|
48
|
+
[
|
|
49
|
+
render_time(slots, datetime: datetime),
|
|
50
|
+
render_heading(slots),
|
|
51
|
+
render_description(slots),
|
|
52
|
+
render_detail(slots),
|
|
53
|
+
render_actions(slots)
|
|
54
|
+
].compact
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
template.safe_join([render_indicator(slots), content_col].compact)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def render_horizontal_event(slots, datetime:)
|
|
61
|
+
template.safe_join(
|
|
62
|
+
[
|
|
63
|
+
render_horizontal_indicator_row(slots),
|
|
64
|
+
render_horizontal_content(slots, datetime: datetime)
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def render_horizontal_indicator_row(slots)
|
|
70
|
+
template.content_tag(:div, class: "flex items-center") do
|
|
71
|
+
template.safe_join(
|
|
72
|
+
[
|
|
73
|
+
render_indicator(slots),
|
|
74
|
+
template.content_tag(:div, nil, **merge_html_options(theme.resolve(:timeline_item_connector)))
|
|
75
|
+
].compact
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def render_horizontal_content(slots, datetime:)
|
|
81
|
+
template.content_tag(:div, **merge_html_options(theme.resolve(:timeline_item_content))) do
|
|
82
|
+
template.safe_join(
|
|
83
|
+
[
|
|
84
|
+
render_time(slots, datetime: datetime),
|
|
85
|
+
render_heading(slots),
|
|
86
|
+
render_description(slots),
|
|
87
|
+
render_detail(slots),
|
|
88
|
+
render_actions(slots)
|
|
89
|
+
].compact
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def render_indicator(slots)
|
|
95
|
+
return unless slots.indicator?
|
|
96
|
+
|
|
97
|
+
type = slots.options_for(:indicator)[:type]
|
|
98
|
+
icon_name = slots.options_for(:indicator)[:icon]
|
|
99
|
+
html_options = merge_html_options(
|
|
100
|
+
theme.resolve(:timeline_item_indicator, type: type, orientation: @orientation),
|
|
101
|
+
{ aria: { hidden: "true" } }
|
|
102
|
+
)
|
|
103
|
+
template.content_tag(:div, **html_options) { render_indicator_content(type: type, icon_name: icon_name) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def render_indicator_content(type:, icon_name:)
|
|
107
|
+
if type == :icon && icon_name
|
|
108
|
+
Components::Icon.new(template).render(
|
|
109
|
+
name: icon_name,
|
|
110
|
+
classes: theme.resolve(:timeline_item_indicator_icon_slot).fetch(:classes, ""),
|
|
111
|
+
aria: { hidden: "true" }
|
|
112
|
+
)
|
|
113
|
+
else
|
|
114
|
+
template.content_tag(:span, nil, **merge_html_options(theme.resolve(:timeline_item_indicator_dot)))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def render_time(slots, datetime:)
|
|
119
|
+
return unless datetime
|
|
120
|
+
|
|
121
|
+
content = slots.resolve(:time)
|
|
122
|
+
time_type = slots.options_for(:time)[:type] || :default
|
|
123
|
+
time_target = @interactive ? { data: { "timeline-target": "time" } } : {}
|
|
124
|
+
attrs = merge_html_options(theme.resolve(:timeline_item_time, type: time_type), { datetime: datetime }, time_target)
|
|
125
|
+
template.content_tag(:time, content, **attrs)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def render_heading(slots)
|
|
129
|
+
if slots.trigger?
|
|
130
|
+
render_trigger_heading(slots)
|
|
131
|
+
elsif slots.title?
|
|
132
|
+
content = slots.resolve(:title)
|
|
133
|
+
template.content_tag(:h3, content, **merge_html_options(theme.resolve(:timeline_item_title)))
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def render_trigger_heading(slots)
|
|
138
|
+
content = slots.resolve(:trigger)
|
|
139
|
+
trigger_attrs = if @interactive
|
|
140
|
+
merge_html_options(
|
|
141
|
+
theme.resolve(:timeline_item_trigger),
|
|
142
|
+
{
|
|
143
|
+
data: { "timeline-target": "trigger", action: "timeline#toggle" },
|
|
144
|
+
aria: { expanded: "false", controls: @detail_id }
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
else
|
|
148
|
+
merge_html_options(theme.resolve(:timeline_item_trigger))
|
|
149
|
+
end
|
|
150
|
+
button = template.content_tag(:button, content, type: "button", **trigger_attrs)
|
|
151
|
+
template.content_tag(:h3, button, **merge_html_options(theme.resolve(:timeline_item_heading)))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def render_description(slots)
|
|
155
|
+
return unless slots.description?
|
|
156
|
+
|
|
157
|
+
content = slots.resolve(:description)
|
|
158
|
+
return unless content.present?
|
|
159
|
+
|
|
160
|
+
template.content_tag(:p, content, **merge_html_options(theme.resolve(:timeline_item_description)))
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def render_detail(slots)
|
|
164
|
+
return unless slots.detail?
|
|
165
|
+
|
|
166
|
+
content = slots.resolve(:detail)
|
|
167
|
+
detail_attrs = if @interactive
|
|
168
|
+
merge_html_options(
|
|
169
|
+
theme.resolve(:timeline_item_detail),
|
|
170
|
+
{ id: @detail_id, hidden: "", data: { "timeline-target": "detail" } }
|
|
171
|
+
)
|
|
172
|
+
else
|
|
173
|
+
merge_html_options(theme.resolve(:timeline_item_detail))
|
|
174
|
+
end
|
|
175
|
+
template.content_tag(:div, content, **detail_attrs)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def render_actions(slots)
|
|
179
|
+
return unless slots.actions?
|
|
180
|
+
|
|
181
|
+
content = slots.resolve(:actions)
|
|
182
|
+
return unless content.present?
|
|
183
|
+
|
|
184
|
+
template.content_tag(:div, content, **merge_html_options(theme.resolve(:timeline_item_actions)))
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class Timeline
|
|
6
|
+
class Group < Plumber::Base
|
|
7
|
+
def render(**kwargs, &block)
|
|
8
|
+
content = template.capture(self, &block)
|
|
9
|
+
html_options = merge_html_options(theme.resolve(:timeline_group), kwargs)
|
|
10
|
+
template.content_tag(:div, content, **html_options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def section(date:, datetime: nil, **kwargs, &block)
|
|
14
|
+
inner_tl = Timeline.new(template)
|
|
15
|
+
inner_tl.instance_variable_set(:@orientation, :vertical)
|
|
16
|
+
inner_tl.instance_variable_set(:@interactive, false)
|
|
17
|
+
|
|
18
|
+
events_html = template.capture(inner_tl, &block)
|
|
19
|
+
section_html = template.content_tag(:div, **merge_html_options(theme.resolve(:timeline_group_section), kwargs)) do
|
|
20
|
+
render_section_body(date: date, datetime: datetime, events_html: events_html)
|
|
21
|
+
end
|
|
22
|
+
template.concat(section_html)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def render_section_body(date:, datetime:, events_html:)
|
|
28
|
+
date_attrs = merge_html_options(
|
|
29
|
+
theme.resolve(:timeline_group_section_date),
|
|
30
|
+
datetime ? { datetime: datetime } : {}
|
|
31
|
+
)
|
|
32
|
+
template.safe_join(
|
|
33
|
+
[
|
|
34
|
+
template.content_tag(:time, date, **date_attrs),
|
|
35
|
+
template.content_tag(:ol, events_html, **merge_html_options(theme.resolve(:timeline_group_section_list)))
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class Timeline < Plumber::Base
|
|
6
|
+
def render(orientation: :vertical, interactive: false, **kwargs, &block)
|
|
7
|
+
@interactive = interactive
|
|
8
|
+
@orientation = orientation
|
|
9
|
+
content = template.capture(self, &block)
|
|
10
|
+
stimulus = @interactive ? { data: { controller: "timeline" } } : {}
|
|
11
|
+
ol_options = merge_html_options(theme.resolve(:timeline, orientation: orientation), kwargs, stimulus)
|
|
12
|
+
list = template.content_tag(:ol, content, **ol_options)
|
|
13
|
+
|
|
14
|
+
orientation.to_sym == :vertical ? render_vertical_wrapper(list) : list
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def event(datetime: nil, **kwargs, &block)
|
|
18
|
+
ev = Timeline::Event.new(template)
|
|
19
|
+
html = ev.render(
|
|
20
|
+
datetime: datetime,
|
|
21
|
+
interactive: @interactive,
|
|
22
|
+
orientation: @orientation,
|
|
23
|
+
**kwargs,
|
|
24
|
+
&block
|
|
25
|
+
)
|
|
26
|
+
@interactive ||= ev.interactive
|
|
27
|
+
template.concat(html)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def render_vertical_wrapper(list)
|
|
33
|
+
track_line = template.content_tag(:div, nil, **merge_html_options(theme.resolve(:timeline_track_line)))
|
|
34
|
+
template.content_tag(:div, class: "relative") do
|
|
35
|
+
template.safe_join([track_line, list])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -73,7 +73,13 @@ module StimulusPlumbers
|
|
|
73
73
|
field = Field.new(@template, **field_opts)
|
|
74
74
|
field.render(object, attribute, input_id: field_id(attribute)) do |html_opts, opts, error|
|
|
75
75
|
Plumber::Dispatcher.build(
|
|
76
|
-
Fields::Renderer::FIELD.fetch(as),
|
|
76
|
+
Fields::Renderer::FIELD.fetch(as),
|
|
77
|
+
attribute,
|
|
78
|
+
html_opts,
|
|
79
|
+
opts,
|
|
80
|
+
error,
|
|
81
|
+
floating: field.floating,
|
|
82
|
+
**input_opts
|
|
77
83
|
).call(self)
|
|
78
84
|
end
|
|
79
85
|
end
|
|
@@ -110,8 +116,10 @@ module StimulusPlumbers
|
|
|
110
116
|
Fields::Fieldset.new(@template).render(object, attribute, field_id(attribute), field, &block)
|
|
111
117
|
end
|
|
112
118
|
|
|
113
|
-
def render_input_group(error:, leading: nil, trailing: nil, **
|
|
114
|
-
Components::InputGroup.new(@template).render(
|
|
119
|
+
def render_input_group(error:, floating: nil, leading: nil, trailing: nil, **group_options, &block)
|
|
120
|
+
Components::InputGroup.new(@template).render(
|
|
121
|
+
leading: leading, trailing: trailing, error: error, floating: floating, **group_options, &block
|
|
122
|
+
)
|
|
115
123
|
end
|
|
116
124
|
|
|
117
125
|
# rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "base"
|
|
4
|
+
require_relative "../themes/schema/form/floating/ranges"
|
|
4
5
|
|
|
5
6
|
module StimulusPlumbers
|
|
6
7
|
module Form
|
|
@@ -10,7 +11,6 @@ module StimulusPlumbers
|
|
|
10
11
|
text_area file password date time select search
|
|
11
12
|
].freeze
|
|
12
13
|
COLLECTION_TYPES = %i[radio check_box collection_select grouped_collection_select].freeze
|
|
13
|
-
FLOATING_TYPES = %i[standard filled outlined].freeze
|
|
14
14
|
OPTIONS = (Base::OPTIONS + %i[hide_label]).freeze
|
|
15
15
|
|
|
16
16
|
attr_reader :hide_label
|
|
@@ -31,7 +31,7 @@ module StimulusPlumbers
|
|
|
31
31
|
def render(object, attribute, input_id:, &block)
|
|
32
32
|
@label ||= attribute.to_s.humanize
|
|
33
33
|
case @floating
|
|
34
|
-
when *
|
|
34
|
+
when *StimulusPlumbers::Themes::Schema::Form::Floating::Ranges::TYPE
|
|
35
35
|
render_floating_field(object, attribute, input_id, &block)
|
|
36
36
|
else
|
|
37
37
|
render_default_field(object, attribute, input_id, &block)
|
|
@@ -70,8 +70,7 @@ module StimulusPlumbers
|
|
|
70
70
|
def render_floating_field(object, attribute, input_id, &block)
|
|
71
71
|
error_override = error?(object, attribute)
|
|
72
72
|
aria = build_aria(object, attribute, input_id)
|
|
73
|
-
|
|
74
|
-
field_opts = build_html_options(input_id, aria).merge(class: input_classes, placeholder: " ")
|
|
73
|
+
field_opts = build_html_options(input_id, aria).merge(placeholder: " ")
|
|
75
74
|
Fields::Group.new(@template).render(layout: @layout, error: error_override) do
|
|
76
75
|
@template.safe_join(
|
|
77
76
|
[
|
|
@@ -90,7 +89,7 @@ module StimulusPlumbers
|
|
|
90
89
|
text: @label,
|
|
91
90
|
for_id: input_id,
|
|
92
91
|
id: self.class.label_id(input_id),
|
|
93
|
-
|
|
92
|
+
floating: @floating,
|
|
94
93
|
required: @required,
|
|
95
94
|
error: error,
|
|
96
95
|
&block
|
|
@@ -104,7 +104,7 @@ module StimulusPlumbers
|
|
|
104
104
|
def build_check_box_label(field, attribute, input_id, check_box_html)
|
|
105
105
|
label_opts = merge_html_options(theme.resolve(:form_field_checkbox_label))
|
|
106
106
|
label_text = field.label || attribute.to_s.humanize
|
|
107
|
-
@template.content_tag(:label, for: input_id
|
|
107
|
+
@template.content_tag(:label, **label_opts, for: input_id) do
|
|
108
108
|
@template.safe_join([check_box_html, label_text])
|
|
109
109
|
end
|
|
110
110
|
end
|
|
@@ -7,13 +7,13 @@ module StimulusPlumbers
|
|
|
7
7
|
module Combobox
|
|
8
8
|
private
|
|
9
9
|
|
|
10
|
-
def render_combobox(attribute, input_id:, opts:, error:, **kwargs, &block)
|
|
10
|
+
def render_combobox(attribute, input_id:, opts:, error:, floating: nil, **kwargs, &block)
|
|
11
11
|
combobox_opts = opts.deep_merge(input: { name: field_name(attribute) })
|
|
12
12
|
|
|
13
13
|
Components::Combobox.new(@template).render(
|
|
14
14
|
id: input_id,
|
|
15
15
|
**combobox_opts,
|
|
16
|
-
**merge_html_options(theme.resolve(:form_field_input_combobox, error: error), kwargs),
|
|
16
|
+
**merge_html_options(theme.resolve(:form_field_input_combobox, floating: floating, error: error), kwargs),
|
|
17
17
|
&block
|
|
18
18
|
)
|
|
19
19
|
end
|
|
@@ -21,7 +21,16 @@ module StimulusPlumbers
|
|
|
21
21
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
|
-
def render_combobox_date(
|
|
24
|
+
def render_combobox_date(
|
|
25
|
+
attribute,
|
|
26
|
+
html_opts,
|
|
27
|
+
opts,
|
|
28
|
+
error,
|
|
29
|
+
floating: nil,
|
|
30
|
+
icon_leading: nil,
|
|
31
|
+
icon_trailing: nil,
|
|
32
|
+
**kwargs
|
|
33
|
+
)
|
|
25
34
|
current_value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
|
|
26
35
|
labelledby = Field.label_id(html_opts[:id])
|
|
27
36
|
combobox_opts = {
|
|
@@ -34,6 +43,7 @@ module StimulusPlumbers
|
|
|
34
43
|
input_id: html_opts[:id],
|
|
35
44
|
opts: combobox_opts,
|
|
36
45
|
error: error,
|
|
46
|
+
floating: floating,
|
|
37
47
|
**kwargs
|
|
38
48
|
) do |c|
|
|
39
49
|
c.date(value: current_value, labelledby: labelledby)
|
|
@@ -45,6 +55,7 @@ module StimulusPlumbers
|
|
|
45
55
|
html_opts,
|
|
46
56
|
opts,
|
|
47
57
|
error,
|
|
58
|
+
floating: nil,
|
|
48
59
|
format: :h12,
|
|
49
60
|
step: 1,
|
|
50
61
|
icon_leading: nil,
|
|
@@ -63,6 +74,7 @@ module StimulusPlumbers
|
|
|
63
74
|
input_id: html_opts[:id],
|
|
64
75
|
opts: combobox_opts,
|
|
65
76
|
error: error,
|
|
77
|
+
floating: floating,
|
|
66
78
|
**kwargs
|
|
67
79
|
) do |c|
|
|
68
80
|
c.time(format: format, step: step, value: current_value, labelledby: labelledby)
|
|
@@ -5,15 +5,20 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module File
|
|
8
|
-
def file_field(attribute,
|
|
9
|
-
html_options = merge_html_options(theme.resolve(:form_field_input_file), options)
|
|
8
|
+
def file_field(attribute, floating: nil, **options)
|
|
9
|
+
html_options = merge_html_options(theme.resolve(:form_field_input_file, floating: floating), options)
|
|
10
10
|
super(attribute, html_options)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
private
|
|
14
14
|
|
|
15
|
-
def render_file_input(attribute, html_opts, opts, error, **kwargs)
|
|
16
|
-
html_options = merge_html_options(
|
|
15
|
+
def render_file_input(attribute, html_opts, opts, error, floating: nil, **kwargs)
|
|
16
|
+
html_options = merge_html_options(
|
|
17
|
+
theme.resolve(:form_field_input_file, floating: floating, error: error),
|
|
18
|
+
opts,
|
|
19
|
+
html_opts,
|
|
20
|
+
kwargs
|
|
21
|
+
)
|
|
17
22
|
@template.file_field(@object_name, attribute, objectify_options(html_options))
|
|
18
23
|
end
|
|
19
24
|
end
|