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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/README.md +11 -4
  4. data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +125 -12
  5. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.es.js +681 -312
  6. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.umd.js +1 -1
  7. data/app/assets/stylesheets/stimulus_plumbers/tokens.css +26 -22
  8. data/config/locales/en.yml +21 -0
  9. data/lib/stimulus_plumbers/components/avatar.rb +13 -5
  10. data/lib/stimulus_plumbers/components/calendar/turbo/days_of_month.rb +47 -7
  11. data/lib/stimulus_plumbers/components/calendar/turbo/months_of_year.rb +56 -18
  12. data/lib/stimulus_plumbers/components/calendar/turbo/years_of_decade.rb +44 -16
  13. data/lib/stimulus_plumbers/components/calendar/turbo.rb +59 -12
  14. data/lib/stimulus_plumbers/components/calendar.rb +48 -64
  15. data/lib/stimulus_plumbers/components/card.rb +7 -7
  16. data/lib/stimulus_plumbers/components/combobox/date/navigation.rb +16 -8
  17. data/lib/stimulus_plumbers/components/combobox/date/navigator.rb +3 -1
  18. data/lib/stimulus_plumbers/components/combobox/date.rb +35 -18
  19. data/lib/stimulus_plumbers/components/combobox/time.rb +56 -50
  20. data/lib/stimulus_plumbers/components/input_group.rb +2 -2
  21. data/lib/stimulus_plumbers/components/list/item.rb +2 -2
  22. data/lib/stimulus_plumbers/components/list/section.rb +1 -1
  23. data/lib/stimulus_plumbers/components/popover.rb +1 -1
  24. data/lib/stimulus_plumbers/components/timeline/event/slots.rb +18 -0
  25. data/lib/stimulus_plumbers/components/timeline/event.rb +189 -0
  26. data/lib/stimulus_plumbers/components/timeline/group.rb +42 -0
  27. data/lib/stimulus_plumbers/components/timeline.rb +40 -0
  28. data/lib/stimulus_plumbers/form/builder.rb +11 -3
  29. data/lib/stimulus_plumbers/form/field.rb +4 -5
  30. data/lib/stimulus_plumbers/form/fields/inputs/checkbox.rb +1 -1
  31. data/lib/stimulus_plumbers/form/fields/inputs/combobox.rb +2 -2
  32. data/lib/stimulus_plumbers/form/fields/inputs/datetime.rb +13 -1
  33. data/lib/stimulus_plumbers/form/fields/inputs/file.rb +9 -4
  34. data/lib/stimulus_plumbers/form/fields/inputs/password.rb +35 -24
  35. data/lib/stimulus_plumbers/form/fields/inputs/radio.rb +15 -3
  36. data/lib/stimulus_plumbers/form/fields/inputs/search.rb +62 -31
  37. data/lib/stimulus_plumbers/form/fields/inputs/select.rb +3 -1
  38. data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +4 -4
  39. data/lib/stimulus_plumbers/form/fields/inputs/text.rb +9 -4
  40. data/lib/stimulus_plumbers/form/fields/inputs/text_area.rb +9 -4
  41. data/lib/stimulus_plumbers/form/fields/label/floating.rb +3 -3
  42. data/lib/stimulus_plumbers/helpers/calendar_helper.rb +1 -1
  43. data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +22 -2
  44. data/lib/stimulus_plumbers/helpers/timeline_helper.rb +15 -0
  45. data/lib/stimulus_plumbers/helpers.rb +2 -0
  46. data/lib/stimulus_plumbers/plumber/renderer.rb +2 -2
  47. data/lib/stimulus_plumbers/themes/base.rb +2 -1
  48. data/lib/stimulus_plumbers/themes/schema/form/floating/ranges.rb +15 -0
  49. data/lib/stimulus_plumbers/themes/schema.rb +63 -16
  50. data/lib/stimulus_plumbers/version.rb +1 -1
  51. data/lib/stimulus_plumbers.rb +4 -1
  52. metadata +7 -2
  53. 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: "Picker", labelledby: nil)
34
- @format = format
35
- @step = [1, step.to_i].max
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
- panel_attrs,
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(label, labelledby: labelledby),
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 @format == :h12
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 render_drum(target, label, items, selected)
61
- drum.render(
62
- stimulus_controller: STIMULUS_CONTROLLER,
63
- target: target,
64
- label: label,
65
- items: items,
66
- selected: selected
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 hour_drum
71
- render_drum("hour", "Hour", hour_items, current_hour)
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 minute_drum
75
- items = (0...60).step(@step).map { |m| [m.to_s.rjust(2, "0")] * 2 }
76
- selected = @time ? snap_minute(@time.min).to_s.rjust(2, "0") : nil
77
- render_drum("minute", "Minute", items, selected)
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 period_drum
81
- render_drum("period", "Period", [%w[AM AM], %w[PM PM]], @time && (@time.hour < 12 ? "AM" : "PM"))
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
- def current_hour
93
- return nil unless @time
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
- @time.hour.to_s.rjust(2, "0")
84
+ time.hour.to_s.rjust(2, "0")
100
85
  end
101
86
  end
102
87
 
103
- def snap_minute(minute)
104
- return minute if @step == 1
88
+ def round_minute(minute, step)
89
+ return minute if step == 1
105
90
 
106
- ((minute.to_f / @step).round * @step) % 60
91
+ ((minute.to_f / step).round * step) % 60
107
92
  end
108
93
 
109
- def drum
110
- @drum ||= Time::Drum.new(template)
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].compact)
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].compact)
78
+ template.safe_join([icon_leading, content, icon_trailing])
79
79
  end
80
80
  end
81
81
  end
@@ -44,7 +44,7 @@ module StimulusPlumbers
44
44
  **merge_html_options(theme.resolve(:list_section_description))
45
45
  )
46
46
  end)
47
- ].compact
47
+ ]
48
48
  )
49
49
  end
50
50
 
@@ -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].compact)
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), attribute, html_opts, opts, error, **input_opts
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, **wrapper_opts, &block)
114
- Components::InputGroup.new(@template).render(leading: leading, trailing: trailing, error: error, **wrapper_opts, &block)
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 *FLOATING_TYPES
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
- input_classes = theme.resolve(:form_field_floating, type: @floating, error: error_override)[:classes]
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
- type: @floating,
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, **label_opts) do
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(attribute, html_opts, opts, error, icon_leading: nil, icon_trailing: nil, **kwargs)
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, options = {})
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(theme.resolve(:form_field_input_file, error: error), opts, html_opts, kwargs)
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