stimulus_plumbers 0.3.3 → 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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -0
  3. data/README.md +11 -4
  4. data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +386 -0
  5. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.es.js +756 -304
  6. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.umd.js +1 -1
  7. data/app/assets/stylesheets/stimulus_plumbers/tokens.css +66 -26
  8. data/config/locales/en.yml +31 -0
  9. data/lib/stimulus_plumbers/components/avatar.rb +22 -13
  10. data/lib/stimulus_plumbers/components/button/group.rb +9 -4
  11. data/lib/stimulus_plumbers/components/button/slots.rb +11 -0
  12. data/lib/stimulus_plumbers/components/button.rb +30 -34
  13. data/lib/stimulus_plumbers/components/calendar/turbo/days_of_month.rb +191 -0
  14. data/lib/stimulus_plumbers/components/calendar/turbo/days_of_week.rb +62 -0
  15. data/lib/stimulus_plumbers/components/calendar/turbo/months_of_year.rb +137 -0
  16. data/lib/stimulus_plumbers/components/calendar/turbo/years_of_decade.rb +114 -0
  17. data/lib/stimulus_plumbers/components/calendar/turbo.rb +112 -0
  18. data/lib/stimulus_plumbers/components/calendar.rb +57 -32
  19. data/lib/stimulus_plumbers/components/card/slots.rb +26 -0
  20. data/lib/stimulus_plumbers/components/card.rb +53 -13
  21. data/lib/stimulus_plumbers/components/combobox/builder.rb +45 -0
  22. data/lib/stimulus_plumbers/components/combobox/date/navigation.rb +80 -0
  23. data/lib/stimulus_plumbers/components/combobox/date/navigator.rb +27 -0
  24. data/lib/stimulus_plumbers/components/combobox/date.rb +55 -28
  25. data/lib/stimulus_plumbers/components/combobox/dropdown.rb +27 -24
  26. data/lib/stimulus_plumbers/components/combobox/options/option.rb +1 -1
  27. data/lib/stimulus_plumbers/components/combobox/options/option_group.rb +1 -1
  28. data/lib/stimulus_plumbers/components/combobox/time.rb +83 -78
  29. data/lib/stimulus_plumbers/components/combobox/trigger.rb +17 -12
  30. data/lib/stimulus_plumbers/components/combobox/typeahead.rb +63 -16
  31. data/lib/stimulus_plumbers/components/combobox.rb +58 -38
  32. data/lib/stimulus_plumbers/components/divider.rb +9 -8
  33. data/lib/stimulus_plumbers/components/icon.rb +5 -1
  34. data/lib/stimulus_plumbers/components/input_group.rb +2 -2
  35. data/lib/stimulus_plumbers/components/link/slots.rb +11 -0
  36. data/lib/stimulus_plumbers/components/link.rb +63 -0
  37. data/lib/stimulus_plumbers/components/list/item/slots.rb +13 -0
  38. data/lib/stimulus_plumbers/components/list/item.rb +83 -0
  39. data/lib/stimulus_plumbers/components/list/section.rb +73 -0
  40. data/lib/stimulus_plumbers/components/list.rb +31 -0
  41. data/lib/stimulus_plumbers/components/popover/panel.rb +32 -0
  42. data/lib/stimulus_plumbers/components/popover/trigger.rb +27 -0
  43. data/lib/stimulus_plumbers/components/popover.rb +44 -18
  44. data/lib/stimulus_plumbers/components/timeline/event/slots.rb +18 -0
  45. data/lib/stimulus_plumbers/components/timeline/event.rb +189 -0
  46. data/lib/stimulus_plumbers/components/timeline/group.rb +42 -0
  47. data/lib/stimulus_plumbers/components/timeline.rb +40 -0
  48. data/lib/stimulus_plumbers/engine.rb +1 -0
  49. data/lib/stimulus_plumbers/form/base.rb +103 -0
  50. data/lib/stimulus_plumbers/form/builder.rb +78 -23
  51. data/lib/stimulus_plumbers/form/field.rb +55 -88
  52. data/lib/stimulus_plumbers/form/fields/error.rb +1 -1
  53. data/lib/stimulus_plumbers/form/fields/fieldset.rb +11 -8
  54. data/lib/stimulus_plumbers/form/fields/hint.rb +1 -1
  55. data/lib/stimulus_plumbers/form/fields/inputs/checkbox.rb +115 -0
  56. data/lib/stimulus_plumbers/form/fields/inputs/combobox.rb +24 -0
  57. data/lib/stimulus_plumbers/form/fields/inputs/datetime.rb +52 -58
  58. data/lib/stimulus_plumbers/form/fields/inputs/file.rb +15 -9
  59. data/lib/stimulus_plumbers/form/fields/inputs/password.rb +46 -28
  60. data/lib/stimulus_plumbers/form/fields/inputs/radio.rb +72 -0
  61. data/lib/stimulus_plumbers/form/fields/inputs/search.rb +73 -65
  62. data/lib/stimulus_plumbers/form/fields/inputs/select/grouped.rb +22 -33
  63. data/lib/stimulus_plumbers/form/fields/inputs/select/timezone.rb +3 -46
  64. data/lib/stimulus_plumbers/form/fields/inputs/select/weekday.rb +3 -26
  65. data/lib/stimulus_plumbers/form/fields/inputs/select.rb +64 -61
  66. data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +10 -7
  67. data/lib/stimulus_plumbers/form/fields/inputs/text.rb +34 -22
  68. data/lib/stimulus_plumbers/form/fields/inputs/text_area.rb +15 -9
  69. data/lib/stimulus_plumbers/form/fields/label/floating.rb +41 -0
  70. data/lib/stimulus_plumbers/form/fields/label.rb +9 -3
  71. data/lib/stimulus_plumbers/form/fields/renderer.rb +39 -0
  72. data/lib/stimulus_plumbers/helpers/button_helper.rb +1 -1
  73. data/lib/stimulus_plumbers/helpers/calendar_helper.rb +2 -2
  74. data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +76 -4
  75. data/lib/stimulus_plumbers/helpers/card_helper.rb +1 -11
  76. data/lib/stimulus_plumbers/helpers/combobox_helper.rb +27 -60
  77. data/lib/stimulus_plumbers/helpers/icon_helper.rb +11 -0
  78. data/lib/stimulus_plumbers/helpers/link_helper.rb +11 -0
  79. data/lib/stimulus_plumbers/helpers/list_helper.rb +11 -0
  80. data/lib/stimulus_plumbers/helpers/plumber_helper.rb +3 -6
  81. data/lib/stimulus_plumbers/helpers/timeline_helper.rb +15 -0
  82. data/lib/stimulus_plumbers/helpers.rb +8 -2
  83. data/lib/stimulus_plumbers/logger.rb +4 -3
  84. data/lib/stimulus_plumbers/plumber/base.rb +6 -1
  85. data/lib/stimulus_plumbers/plumber/dispatcher/klass_proxy.rb +4 -3
  86. data/lib/stimulus_plumbers/plumber/dispatcher/method_call.rb +4 -3
  87. data/lib/stimulus_plumbers/plumber/dispatcher.rb +4 -4
  88. data/lib/stimulus_plumbers/plumber/options/aria.rb +17 -0
  89. data/lib/stimulus_plumbers/plumber/options/html.rb +29 -0
  90. data/lib/stimulus_plumbers/plumber/options/stimulus.rb +29 -0
  91. data/lib/stimulus_plumbers/plumber/options/theme.rb +19 -0
  92. data/lib/stimulus_plumbers/plumber/options/token_list.rb +29 -0
  93. data/lib/stimulus_plumbers/plumber/renderer.rb +136 -41
  94. data/lib/stimulus_plumbers/plumber/slots.rb +74 -0
  95. data/lib/stimulus_plumbers/themes/base.rb +6 -7
  96. data/lib/stimulus_plumbers/themes/schema/avatar/ranges.rb +13 -0
  97. data/lib/stimulus_plumbers/themes/schema/button/ranges.rb +16 -0
  98. data/lib/stimulus_plumbers/themes/schema/card/ranges.rb +13 -0
  99. data/lib/stimulus_plumbers/themes/schema/form/checkbox/ranges.rb +16 -0
  100. data/lib/stimulus_plumbers/themes/schema/form/floating/ranges.rb +15 -0
  101. data/lib/stimulus_plumbers/themes/schema/form/radio/ranges.rb +16 -0
  102. data/lib/stimulus_plumbers/themes/schema/form/ranges.rb +1 -2
  103. data/lib/stimulus_plumbers/themes/schema/link/ranges.rb +14 -0
  104. data/lib/stimulus_plumbers/themes/schema/ranges.rb +1 -5
  105. data/lib/stimulus_plumbers/themes/schema.rb +169 -51
  106. data/lib/stimulus_plumbers/version.rb +1 -1
  107. data/lib/stimulus_plumbers.rb +24 -16
  108. metadata +48 -16
  109. data/lib/stimulus_plumbers/components/action_list/item.rb +0 -30
  110. data/lib/stimulus_plumbers/components/action_list/section.rb +0 -28
  111. data/lib/stimulus_plumbers/components/action_list.rb +0 -29
  112. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_month.rb +0 -149
  113. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_week.rb +0 -43
  114. data/lib/stimulus_plumbers/components/calendar/month/turbo.rb +0 -59
  115. data/lib/stimulus_plumbers/components/card/section.rb +0 -31
  116. data/lib/stimulus_plumbers/components/combobox/popover.rb +0 -47
  117. data/lib/stimulus_plumbers/components/combobox/time/drum.rb +0 -43
  118. data/lib/stimulus_plumbers/components/date_picker/navigation.rb +0 -41
  119. data/lib/stimulus_plumbers/components/date_picker/navigator.rb +0 -23
  120. data/lib/stimulus_plumbers/components/popover/builder.rb +0 -25
  121. data/lib/stimulus_plumbers/form/fields/inputs/choice.rb +0 -69
  122. data/lib/stimulus_plumbers/helpers/action_list_helper.rb +0 -25
  123. data/lib/stimulus_plumbers/plumber/html_options.rb +0 -52
@@ -1,90 +1,84 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "combobox"
4
+
3
5
  module StimulusPlumbers
4
6
  module Form
5
7
  module Fields
6
8
  module Inputs
7
9
  module Datetime
10
+ include Combobox
11
+
8
12
  def date_field(attribute, options = {})
9
- html_native = options.delete(:html_native) { false }
10
- icon_leading = options.delete(:icon_leading)
11
- icon_trailing = options.delete(:icon_trailing) { "calendar" }
12
- Field.new(@template, **options).render(
13
- object,
14
- attribute,
15
- input_id: field_id(attribute)
16
- ) do |html_opts, opts, error|
17
- if html_native
18
- html_options = merge_html_options(opts, html_opts, field_theme(:form_input, error: error))
19
- super(attribute, html_options)
20
- else
21
- render_date_combobox(attribute, html_opts, error, icon_leading: icon_leading, icon_trailing: icon_trailing)
22
- end
23
- end
13
+ html_options = merge_html_options(theme.resolve(:form_field_input), options)
14
+ super(attribute, html_options)
24
15
  end
25
16
 
26
17
  def time_field(attribute, options = {})
27
- html_native = options.delete(:html_native) { false }
28
- format = options.delete(:format) { :h12 }
29
- step = options.delete(:step) { 1 }
30
- icon_leading = options.delete(:icon_leading)
31
- icon_trailing = options.delete(:icon_trailing) { "clock" }
32
- Field.new(@template, **options).render(
33
- object,
34
- attribute,
35
- input_id: field_id(attribute)
36
- ) do |html_opts, opts, error|
37
- if html_native
38
- html_options = merge_html_options(opts, html_opts, field_theme(:form_input, error: error))
39
- super(attribute, html_options)
40
- else
41
- render_time_combobox(
42
- attribute,
43
- html_opts,
44
- error,
45
- format: format,
46
- step: step,
47
- icon_leading: icon_leading,
48
- icon_trailing: icon_trailing
49
- )
50
- end
51
- end
18
+ html_options = merge_html_options(theme.resolve(:form_field_input), options)
19
+ super(attribute, html_options)
52
20
  end
53
21
 
54
22
  private
55
23
 
56
- def render_date_combobox(attribute, html_opts, error, icon_leading:, icon_trailing:)
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
+ )
57
34
  current_value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
58
- opts = Components::Combobox::Date.default_opts.deep_merge(
59
- input: { value: current_value, data: { combobox_date_date_value: current_value } },
35
+ labelledby = Field.label_id(html_opts[:id])
36
+ combobox_opts = {
37
+ input: { value: current_value },
60
38
  trigger: { aria: html_opts[:aria], icon_leading: icon_leading, icon_trailing: icon_trailing }.compact,
61
- popover: { labelledby: Field.label_id(html_opts[:id]) }
62
- )
39
+ **opts
40
+ }
63
41
  render_combobox(
64
42
  attribute,
65
43
  input_id: html_opts[:id],
66
- opts: opts,
67
- err: error,
68
- data: { input_formatter_format_value: "date" }
69
- ) do |popover_id|
70
- Components::Combobox::Date.new(@template).render(value: current_value, popover_id: popover_id)
44
+ opts: combobox_opts,
45
+ error: error,
46
+ floating: floating,
47
+ **kwargs
48
+ ) do |c|
49
+ c.date(value: current_value, labelledby: labelledby)
71
50
  end
72
51
  end
73
52
 
74
- def render_time_combobox(attribute, html_opts, error, format:, step:, icon_leading:, icon_trailing:)
53
+ def render_combobox_time(
54
+ attribute,
55
+ html_opts,
56
+ opts,
57
+ error,
58
+ floating: nil,
59
+ format: :h12,
60
+ step: 1,
61
+ icon_leading: nil,
62
+ icon_trailing: nil,
63
+ **kwargs
64
+ )
75
65
  current_value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
76
- opts = Components::Combobox::Time.default_opts.deep_merge(
66
+ labelledby = Field.label_id(html_opts[:id])
67
+ combobox_opts = {
77
68
  input: { value: current_value },
78
69
  trigger: { aria: html_opts[:aria], icon_leading: icon_leading, icon_trailing: icon_trailing }.compact,
79
- popover: { labelledby: Field.label_id(html_opts[:id]) }
80
- )
70
+ **opts
71
+ }
81
72
  render_combobox(
82
73
  attribute,
83
74
  input_id: html_opts[:id],
84
- opts: opts,
85
- err: error,
86
- data: { input_formatter_format_value: "time", input_formatter_options_value: { format: format }.to_json }
87
- ) { Components::Combobox::Time.new(@template).render(format: format, step: step, value: current_value) }
75
+ opts: combobox_opts,
76
+ error: error,
77
+ floating: floating,
78
+ **kwargs
79
+ ) do |c|
80
+ c.time(format: format, step: step, value: current_value, labelledby: labelledby)
81
+ end
88
82
  end
89
83
  end
90
84
  end
@@ -5,15 +5,21 @@ module StimulusPlumbers
5
5
  module Fields
6
6
  module Inputs
7
7
  module File
8
- def file_field(attribute, options = {})
9
- Field.new(@template, **options).render(
10
- object,
11
- attribute,
12
- input_id: field_id(attribute)
13
- ) do |html_opts, opts, error|
14
- html_options = merge_html_options(opts, html_opts, field_theme(:form_file, error: error))
15
- super(attribute, html_options)
16
- end
8
+ def file_field(attribute, floating: nil, **options)
9
+ html_options = merge_html_options(theme.resolve(:form_field_input_file, floating: floating), options)
10
+ super(attribute, html_options)
11
+ end
12
+
13
+ private
14
+
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
+ )
22
+ @template.file_field(@object_name, attribute, objectify_options(html_options))
17
23
  end
18
24
  end
19
25
  end
@@ -5,52 +5,70 @@ module StimulusPlumbers
5
5
  module Fields
6
6
  module Inputs
7
7
  module Password
8
- def password_field(attribute, options = {})
9
- reveal = options.delete(:reveal) { false }
10
- Field.new(@template, **options).render(
11
- object,
12
- attribute,
13
- input_id: field_id(attribute)
14
- ) do |html_opts, opts, error|
15
- if reveal
16
- render_reveal_password(merge_html_options(opts, html_opts), error) do |html_options|
17
- super(attribute, html_options)
18
- end
19
- else
20
- html_options = merge_html_options(opts, html_opts, field_theme(:form_input, error: error))
21
- super(attribute, html_options)
8
+ def password_field(attribute, floating: nil, revealable: false, **options)
9
+ html_options = merge_html_options(theme.resolve(:form_field_input, floating: floating), options)
10
+ if revealable
11
+ render_revealable_password(false) do
12
+ super(attribute, merge_html_options(html_options, { data: { input_formatter_target: "input" } }))
22
13
  end
14
+ else
15
+ super(attribute, html_options)
23
16
  end
24
17
  end
25
18
 
26
19
  private
27
20
 
28
- def render_reveal_password(html_opts, error, &block)
21
+ def render_password_input(attribute, html_opts, opts, error, floating: nil, revealable: false, **kwargs)
29
22
  html_options = merge_html_options(
23
+ theme.resolve(:form_field_input, floating: floating, error: error),
24
+ opts,
30
25
  html_opts,
31
- field_theme(:form_input, error: error),
32
- { data: { input_formatter_target: "input" } }
26
+ kwargs
33
27
  )
28
+ if revealable
29
+ render_revealable_password(error, floating: floating) do
30
+ revealable_html_options = merge_html_options(html_options, { data: { input_formatter_target: "input" } })
31
+ @template.password_field(@object_name, attribute, objectify_options(revealable_html_options))
32
+ end
33
+ else
34
+ @template.password_field(@object_name, attribute, objectify_options(html_options))
35
+ end
36
+ end
37
+
38
+ def render_revealable_password(error, floating: nil, &block)
34
39
  render_input_group(
35
40
  error: error,
41
+ floating: floating,
36
42
  trailing: method(:reveal_button),
37
43
  **merge_html_options(
38
- field_theme(:form_input_reveal, error: error),
44
+ theme.resolve(:form_field_input_reveal, error: error),
39
45
  { data: { controller: "input-formatter", input_formatter_format_value: "password" } }
40
46
  )
41
- ) { @template.capture(html_options, &block) }
47
+ ) { @template.capture(&block) }
42
48
  end
43
49
 
44
50
  def reveal_button
45
- html_options = merge_html_options(
46
- field_theme(:form_button_reveal),
47
- {
48
- type: "button",
49
- aria: { label: "Show password", pressed: "false" },
50
- data: { input_formatter_target: "toggle", action: "click->input-formatter#toggle" }
51
- }
52
- )
53
- @template.content_tag(:button, "", **html_options)
51
+ build_reveal_button do
52
+ Components::Icon.new(@template).render(
53
+ name: "reveal",
54
+ aria: { hidden: "true" },
55
+ **theme.resolve(:button_icon)
56
+ )
57
+ end
58
+ end
59
+
60
+ def build_reveal_button(&block)
61
+ @template.content_tag(
62
+ :button,
63
+ **merge_html_options(
64
+ theme.resolve(:form_field_input_button_reveal),
65
+ {
66
+ type: "button",
67
+ aria: { label: I18n.t("stimulus_plumbers.form.password.show", default: "Show password"), pressed: "false" },
68
+ data: { input_formatter_target: "toggle", action: "click->input-formatter#toggle" }
69
+ }
70
+ )
71
+ ) { @template.capture(&block) }
54
72
  end
55
73
  end
56
74
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Form
5
+ module Fields
6
+ module Inputs
7
+ module Radio
8
+ def radio_button(attribute, tag_value, options = {})
9
+ html_options = merge_html_options(theme.resolve(:form_field_input_radio), options)
10
+ super(attribute, tag_value, html_options)
11
+ end
12
+
13
+ def collection_radio_buttons(
14
+ attribute,
15
+ collection,
16
+ value_method,
17
+ text_method,
18
+ options = {},
19
+ html_options = {},
20
+ &block
21
+ )
22
+ item_opts = merge_html_options(theme.resolve(:form_field_input_radio), html_options)
23
+ if block_given?
24
+ super(attribute, collection, value_method, text_method, options, item_opts, &block)
25
+ else
26
+ super(attribute, collection, value_method, text_method, options, item_opts) do |builder|
27
+ render_radio_button_label(builder, theme.resolve(:form_field_radio_label))
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def render_collection_radio_button(attribute, collection, value_method, text_method, field_opts, **kwargs)
35
+ type = kwargs.delete(:type) { :default }
36
+ variant = kwargs.delete(:variant) { :default }
37
+ field = Field.new(@template, **{ layout: :inline }.deep_merge(field_opts))
38
+ render_fieldset(attribute, field) do |error|
39
+ item_opts = merge_html_options(
40
+ theme.resolve(:form_field_input_radio, error: error, type: type, variant: variant),
41
+ kwargs,
42
+ field.required ? { aria: { required: "true" } } : {}
43
+ )
44
+ @template.collection_radio_buttons(
45
+ @object_name, attribute, collection, value_method, text_method, {}, item_opts
46
+ ) do |builder|
47
+ render_radio_button_label(builder, theme.resolve(:form_field_radio_label, type: type, variant: variant), type)
48
+ end
49
+ end
50
+ end
51
+
52
+ def render_radio_button_label(builder, label_opts, type = :default)
53
+ html_options = merge_html_options(label_opts)
54
+ if %i[button card].include?(type)
55
+ group_options = merge_html_options(theme.resolve(:form_field_radio_item_group))
56
+ @template.content_tag(:div, **group_options) do
57
+ @template.safe_join(
58
+ [
59
+ builder.radio_button,
60
+ builder.label(**html_options) { builder.text }
61
+ ]
62
+ )
63
+ end
64
+ else
65
+ builder.label(**html_options) { @template.safe_join([builder.radio_button, builder.text]) }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,99 +1,107 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "combobox"
4
+
3
5
  module StimulusPlumbers
4
6
  module Form
5
7
  module Fields
6
8
  module Inputs
7
9
  module Search
8
- def search_field(attribute, options = {})
9
- html_native = options.delete(:html_native) { false }
10
- clearable = options.delete(:clearable) { false }
11
- url = options.delete(:url) { nil }
12
- choices = options.delete(:options) { [] }
13
-
14
- Field.new(@template, **options).render(
15
- object,
16
- attribute,
17
- input_id: field_id(attribute)
18
- ) do |html_opts, opts, error|
19
- if html_native
20
- render_search_input(html_opts, opts, error, clearable: clearable) do |html_options|
21
- super(attribute, html_options)
22
- end
23
- else
24
- render_search_combobox(
25
- attribute,
26
- html_opts,
27
- error,
28
- url: url,
29
- clearable: clearable
30
- ) do |combobox_opts, input_id, current_value|
31
- render_search_typeahead(attribute, input_id, combobox_opts, error, choices, current_value)
32
- end
33
- end
34
- end
35
- end
10
+ include Combobox
36
11
 
37
- private
38
-
39
- def render_search_input(html_opts, opts, error, clearable:, &block)
12
+ def search_field(attribute, options = {})
13
+ clearable = options.delete(:clearable) { false }
40
14
  data = clearable ? { data: { input_clearable_target: "input" } } : {}
41
- html_options = merge_html_options(opts, html_opts, field_theme(:form_input, error: error), data)
42
- input_html = @template.capture(html_options, &block)
43
-
44
- return input_html unless clearable
45
-
15
+ html_options = merge_html_options(theme.resolve(:form_field_input), options, data)
46
16
  render_input_group(
47
- trailing: method(:clear_button),
48
- error: !!error,
49
- **merge_html_options(field_theme(:form_input_clearable), { data: { controller: "input-clearable" } })
50
- ) { input_html }
17
+ trailing: clearable ? method(:clear_button) : nil,
18
+ error: false,
19
+ **merge_html_options(
20
+ theme.resolve(:form_field_input_clearable),
21
+ clearable ? { data: { controller: "input-clearable" } } : {}
22
+ )
23
+ ) { super(attribute, html_options) }
51
24
  end
52
25
 
53
- def render_search_combobox(attribute, html_opts, error, url:, clearable:, &block)
26
+ private
27
+
28
+ def render_combobox_typeahead(
29
+ attribute,
30
+ html_opts,
31
+ opts,
32
+ error,
33
+ floating: nil,
34
+ url: nil,
35
+ clearable: false,
36
+ choices: [],
37
+ **kwargs
38
+ )
54
39
  current_value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
55
40
  input_id = html_opts[:id]
56
- opts = Components::Combobox::Typeahead.default_opts.deep_merge(
41
+ labelledby = Field.label_id(input_id)
42
+ combobox_opts = {
57
43
  input: { value: current_value },
58
- trigger: { data: clearable ? { input_clearable_target: "input" } : {}, aria: html_opts[:aria] },
59
- popover: { data: url ? { combobox_dropdown_url_value: url } : {} }
60
- )
61
-
62
- combobox_html = @template.capture(opts, input_id, current_value, &block)
63
- return combobox_html unless clearable
44
+ trigger: {
45
+ data: clearable ? { input_clearable_target: "input" } : {},
46
+ aria: html_opts[:aria]
47
+ },
48
+ **opts
49
+ }
64
50
 
65
51
  render_input_group(
66
- trailing: method(:clear_button),
67
- error: !!error,
68
- **merge_html_options(field_theme(:form_input_clearable), { data: { controller: "input-clearable" } })
69
- ) { combobox_html }
52
+ trailing: clearable ? method(:clear_button) : nil,
53
+ error: error,
54
+ floating: floating,
55
+ **merge_html_options(theme.resolve(:form_field_input_clearable), { data: { controller: "input-clearable" } })
56
+ ) do
57
+ build_combobox_typeahead(
58
+ attribute,
59
+ combobox_opts,
60
+ input_id: input_id,
61
+ floating: floating,
62
+ error: error,
63
+ **kwargs
64
+ ) do |c|
65
+ c.typeahead(options: choices, value: current_value, labelledby: labelledby, url: url)
66
+ end
67
+ end
70
68
  end
71
69
 
72
- def render_search_typeahead(attribute, input_id, combobox_opts, error, choices, current_value)
70
+ def build_combobox_typeahead(attribute, opts, input_id:, floating:, error:, **kwargs, &block)
73
71
  render_combobox(
74
72
  attribute,
75
73
  input_id: input_id,
76
- opts: combobox_opts,
77
- err: error,
78
- data: {
79
- input_combobox_combobox_dropdown_outlet: "##{Components::Combobox.popover_id_for(input_id)}",
80
- action: "input->input-combobox#onInput"
81
- }
82
- ) { Components::Combobox::Typeahead.new(@template).render(options: choices, value: current_value, labelledby: Field.label_id(input_id)) }
74
+ opts: opts,
75
+ error: error,
76
+ floating: floating,
77
+ **kwargs,
78
+ &block
79
+ )
83
80
  end
84
81
 
85
82
  def clear_button
86
- Components::Button.new(@template).render(
87
- icon_leading: "close",
83
+ build_clear_button do
84
+ Components::Icon.new(@template).render(
85
+ name: "close",
86
+ aria: { hidden: "true" },
87
+ **theme.resolve(:button_icon)
88
+ )
89
+ end
90
+ end
91
+
92
+ def build_clear_button(&block)
93
+ @template.content_tag(
94
+ :button,
88
95
  **merge_html_options(
89
- field_theme(:form_button_clear),
96
+ theme.resolve(:form_field_input_button_clear),
90
97
  {
91
- aria: { label: "Clear search" },
98
+ type: "button",
92
99
  hidden: true,
100
+ aria: { label: I18n.t("stimulus_plumbers.form.search.clear", default: "Clear search") },
93
101
  data: { input_clearable_target: "clear", action: "click->input-clearable#clear" }
94
102
  }
95
103
  )
96
- )
104
+ ) { @template.capture(&block) }
97
105
  end
98
106
  end
99
107
  end
@@ -14,43 +14,32 @@ module StimulusPlumbers
14
14
  option_key_method,
15
15
  option_value_method,
16
16
  options = {},
17
- html_options = {}
17
+ html_opts = {}
18
18
  )
19
- html_native = options.delete(:html_native) { false }
20
- icon_leading = options.delete(:icon_leading)
21
- icon_trailing = options.delete(:icon_trailing) { "chevron-down" }
22
- icons = { icon_leading: icon_leading, icon_trailing: icon_trailing }
23
- with_select_field(attribute, options, html_options) do |opts, merged, error|
24
- if html_native
25
- super(
26
- attribute,
27
- collection,
28
- group_method,
29
- group_label_method,
30
- option_key_method,
31
- option_value_method,
32
- opts,
33
- merged
34
- )
35
- else
36
- render_select_dropdown(attribute, opts, merged, err: error, **icons) do
37
- build_grouped_choices(collection, group_label_method, group_method, option_key_method, option_value_method)
38
- end
39
- end
40
- end
19
+ html_options = merge_html_options(theme.resolve(:form_select), html_opts)
20
+ super(
21
+ attribute,
22
+ collection,
23
+ group_method,
24
+ group_label_method,
25
+ option_key_method,
26
+ option_value_method,
27
+ options,
28
+ html_options
29
+ )
41
30
  end
42
- end
43
31
 
44
- private
32
+ private
45
33
 
46
- def build_grouped_choices(collection, group_label_method, group_method, option_key_method, option_value_method)
47
- collection.map do |group|
48
- {
49
- label: group.public_send(group_label_method),
50
- options: group.public_send(group_method).map do |item|
51
- [item.public_send(option_value_method), item.public_send(option_key_method)]
52
- end
53
- }
34
+ def build_grouped_choices(collection, group_label_method, group_method, option_key_method, option_value_method)
35
+ collection.map do |group|
36
+ {
37
+ label: group.public_send(group_label_method),
38
+ options: group.public_send(group_method).map do |item|
39
+ [item.public_send(option_value_method), item.public_send(option_key_method)]
40
+ end
41
+ }
42
+ end
54
43
  end
55
44
  end
56
45
  end
@@ -6,52 +6,9 @@ module StimulusPlumbers
6
6
  module Inputs
7
7
  module Select
8
8
  module Timezone
9
- def time_zone_select(attribute, priority_zones = nil, options = {}, html_options = {})
10
- html_native = options.delete(:html_native) { false }
11
- icon_leading = options.delete(:icon_leading)
12
- icon_trailing = options.delete(:icon_trailing) { "chevron-down" }
13
- icons = { icon_leading: icon_leading, icon_trailing: icon_trailing }
14
- with_select_field(attribute, options, html_options) do |opts, merged, error|
15
- if html_native
16
- super(attribute, priority_zones, opts, merged)
17
- else
18
- render_select_dropdown(attribute, opts, merged, err: error, **icons) do
19
- model = opts.delete(:model) { ActiveSupport::TimeZone }
20
- build_zone_choices(priority_zones, model.all)
21
- end
22
- end
23
- end
24
- end
25
-
26
- private
27
-
28
- def build_zone_choices(priority_zones, all_zones)
29
- return zone_options(all_zones) unless priority_zones
30
-
31
- priority = filter_priority_zones(priority_zones, all_zones)
32
- priority_names = priority.to_set(&:name)
33
- remaining = all_zones.reject { |z| priority_names.include?(z.name) }
34
- [
35
- {
36
- label: I18n.t("helpers.time_zone_select.priority_zones", default: "Suggested"),
37
- options: zone_options(priority)
38
- },
39
- {
40
- label: I18n.t("helpers.time_zone_select.other_zones", default: "Other"),
41
- options: zone_options(remaining)
42
- }
43
- ]
44
- end
45
-
46
- def filter_priority_zones(priority_zones, all_zones)
47
- case priority_zones
48
- when Regexp then all_zones.select { |z| z.name.match?(priority_zones) }
49
- else Array(priority_zones)
50
- end
51
- end
52
-
53
- def zone_options(zones)
54
- zones.map { |z| [z.to_s, z.name] }
9
+ def time_zone_select(attribute, priority_zones = nil, options = {}, html_opts = {})
10
+ html_options = merge_html_options(theme.resolve(:form_select), html_opts)
11
+ super(attribute, priority_zones, options, html_options)
55
12
  end
56
13
  end
57
14
  end