stimulus_plumbers 0.3.3 → 0.4.0

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +273 -0
  4. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.es.js +228 -145
  5. data/app/assets/javascripts/stimulus-plumbers/stimulus-plumbers-controllers.umd.js +1 -1
  6. data/app/assets/stylesheets/stimulus_plumbers/tokens.css +43 -7
  7. data/config/locales/en.yml +10 -0
  8. data/lib/stimulus_plumbers/components/avatar.rb +14 -13
  9. data/lib/stimulus_plumbers/components/button/group.rb +9 -4
  10. data/lib/stimulus_plumbers/components/button/slots.rb +11 -0
  11. data/lib/stimulus_plumbers/components/button.rb +30 -34
  12. data/lib/stimulus_plumbers/components/calendar/turbo/days_of_month.rb +151 -0
  13. data/lib/stimulus_plumbers/components/calendar/turbo/days_of_week.rb +62 -0
  14. data/lib/stimulus_plumbers/components/calendar/turbo/months_of_year.rb +99 -0
  15. data/lib/stimulus_plumbers/components/calendar/turbo/years_of_decade.rb +86 -0
  16. data/lib/stimulus_plumbers/components/calendar/turbo.rb +65 -0
  17. data/lib/stimulus_plumbers/components/calendar.rb +70 -29
  18. data/lib/stimulus_plumbers/components/card/slots.rb +26 -0
  19. data/lib/stimulus_plumbers/components/card.rb +54 -14
  20. data/lib/stimulus_plumbers/components/combobox/builder.rb +45 -0
  21. data/lib/stimulus_plumbers/components/combobox/date/navigation.rb +72 -0
  22. data/lib/stimulus_plumbers/components/combobox/date/navigator.rb +25 -0
  23. data/lib/stimulus_plumbers/components/combobox/date.rb +34 -24
  24. data/lib/stimulus_plumbers/components/combobox/dropdown.rb +27 -24
  25. data/lib/stimulus_plumbers/components/combobox/options/option.rb +1 -1
  26. data/lib/stimulus_plumbers/components/combobox/options/option_group.rb +1 -1
  27. data/lib/stimulus_plumbers/components/combobox/time/drum.rb +1 -1
  28. data/lib/stimulus_plumbers/components/combobox/time.rb +48 -49
  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/link/slots.rb +11 -0
  35. data/lib/stimulus_plumbers/components/link.rb +63 -0
  36. data/lib/stimulus_plumbers/components/list/item/slots.rb +13 -0
  37. data/lib/stimulus_plumbers/components/list/item.rb +83 -0
  38. data/lib/stimulus_plumbers/components/list/section.rb +73 -0
  39. data/lib/stimulus_plumbers/components/list.rb +31 -0
  40. data/lib/stimulus_plumbers/components/popover/panel.rb +32 -0
  41. data/lib/stimulus_plumbers/components/popover/trigger.rb +27 -0
  42. data/lib/stimulus_plumbers/components/popover.rb +44 -18
  43. data/lib/stimulus_plumbers/engine.rb +1 -0
  44. data/lib/stimulus_plumbers/form/base.rb +103 -0
  45. data/lib/stimulus_plumbers/form/builder.rb +71 -24
  46. data/lib/stimulus_plumbers/form/field.rb +56 -88
  47. data/lib/stimulus_plumbers/form/fields/error.rb +1 -1
  48. data/lib/stimulus_plumbers/form/fields/fieldset.rb +11 -8
  49. data/lib/stimulus_plumbers/form/fields/hint.rb +1 -1
  50. data/lib/stimulus_plumbers/form/fields/inputs/checkbox.rb +115 -0
  51. data/lib/stimulus_plumbers/form/fields/inputs/combobox.rb +24 -0
  52. data/lib/stimulus_plumbers/form/fields/inputs/datetime.rb +40 -58
  53. data/lib/stimulus_plumbers/form/fields/inputs/file.rb +9 -8
  54. data/lib/stimulus_plumbers/form/fields/inputs/password.rb +30 -23
  55. data/lib/stimulus_plumbers/form/fields/inputs/radio.rb +60 -0
  56. data/lib/stimulus_plumbers/form/fields/inputs/search.rb +31 -54
  57. data/lib/stimulus_plumbers/form/fields/inputs/select/grouped.rb +22 -33
  58. data/lib/stimulus_plumbers/form/fields/inputs/select/timezone.rb +3 -46
  59. data/lib/stimulus_plumbers/form/fields/inputs/select/weekday.rb +3 -26
  60. data/lib/stimulus_plumbers/form/fields/inputs/select.rb +62 -61
  61. data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +10 -7
  62. data/lib/stimulus_plumbers/form/fields/inputs/text.rb +29 -22
  63. data/lib/stimulus_plumbers/form/fields/inputs/text_area.rb +9 -8
  64. data/lib/stimulus_plumbers/form/fields/label/floating.rb +41 -0
  65. data/lib/stimulus_plumbers/form/fields/label.rb +9 -3
  66. data/lib/stimulus_plumbers/form/fields/renderer.rb +39 -0
  67. data/lib/stimulus_plumbers/helpers/button_helper.rb +1 -1
  68. data/lib/stimulus_plumbers/helpers/calendar_helper.rb +2 -2
  69. data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +56 -4
  70. data/lib/stimulus_plumbers/helpers/card_helper.rb +1 -11
  71. data/lib/stimulus_plumbers/helpers/combobox_helper.rb +27 -60
  72. data/lib/stimulus_plumbers/helpers/icon_helper.rb +11 -0
  73. data/lib/stimulus_plumbers/helpers/link_helper.rb +11 -0
  74. data/lib/stimulus_plumbers/helpers/list_helper.rb +11 -0
  75. data/lib/stimulus_plumbers/helpers/plumber_helper.rb +3 -6
  76. data/lib/stimulus_plumbers/helpers.rb +6 -2
  77. data/lib/stimulus_plumbers/logger.rb +4 -3
  78. data/lib/stimulus_plumbers/plumber/base.rb +6 -1
  79. data/lib/stimulus_plumbers/plumber/dispatcher/klass_proxy.rb +4 -3
  80. data/lib/stimulus_plumbers/plumber/dispatcher/method_call.rb +4 -3
  81. data/lib/stimulus_plumbers/plumber/dispatcher.rb +4 -4
  82. data/lib/stimulus_plumbers/plumber/options/aria.rb +17 -0
  83. data/lib/stimulus_plumbers/plumber/options/html.rb +29 -0
  84. data/lib/stimulus_plumbers/plumber/options/stimulus.rb +29 -0
  85. data/lib/stimulus_plumbers/plumber/options/theme.rb +19 -0
  86. data/lib/stimulus_plumbers/plumber/options/token_list.rb +29 -0
  87. data/lib/stimulus_plumbers/plumber/renderer.rb +136 -41
  88. data/lib/stimulus_plumbers/plumber/slots.rb +74 -0
  89. data/lib/stimulus_plumbers/themes/base.rb +5 -7
  90. data/lib/stimulus_plumbers/themes/schema/avatar/ranges.rb +13 -0
  91. data/lib/stimulus_plumbers/themes/schema/button/ranges.rb +16 -0
  92. data/lib/stimulus_plumbers/themes/schema/card/ranges.rb +13 -0
  93. data/lib/stimulus_plumbers/themes/schema/form/checkbox/ranges.rb +16 -0
  94. data/lib/stimulus_plumbers/themes/schema/form/radio/ranges.rb +16 -0
  95. data/lib/stimulus_plumbers/themes/schema/form/ranges.rb +1 -2
  96. data/lib/stimulus_plumbers/themes/schema/link/ranges.rb +14 -0
  97. data/lib/stimulus_plumbers/themes/schema/ranges.rb +1 -5
  98. data/lib/stimulus_plumbers/themes/schema.rb +119 -48
  99. data/lib/stimulus_plumbers/version.rb +1 -1
  100. data/lib/stimulus_plumbers.rb +20 -15
  101. metadata +42 -15
  102. data/lib/stimulus_plumbers/components/action_list/item.rb +0 -30
  103. data/lib/stimulus_plumbers/components/action_list/section.rb +0 -28
  104. data/lib/stimulus_plumbers/components/action_list.rb +0 -29
  105. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_month.rb +0 -149
  106. data/lib/stimulus_plumbers/components/calendar/month/turbo/days_of_week.rb +0 -43
  107. data/lib/stimulus_plumbers/components/calendar/month/turbo.rb +0 -59
  108. data/lib/stimulus_plumbers/components/card/section.rb +0 -31
  109. data/lib/stimulus_plumbers/components/combobox/popover.rb +0 -47
  110. data/lib/stimulus_plumbers/components/date_picker/navigation.rb +0 -41
  111. data/lib/stimulus_plumbers/components/date_picker/navigator.rb +0 -23
  112. data/lib/stimulus_plumbers/components/popover/builder.rb +0 -25
  113. data/lib/stimulus_plumbers/form/fields/inputs/choice.rb +0 -69
  114. data/lib/stimulus_plumbers/helpers/action_list_helper.rb +0 -25
  115. data/lib/stimulus_plumbers/plumber/html_options.rb +0 -52
@@ -6,14 +6,15 @@ module StimulusPlumbers
6
6
  module Inputs
7
7
  module File
8
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
9
+ html_options = merge_html_options(theme.resolve(:form_field_input_file), options)
10
+ super(attribute, html_options)
11
+ end
12
+
13
+ private
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)
17
+ @template.file_field(@object_name, attribute, objectify_options(html_options))
17
18
  end
18
19
  end
19
20
  end
@@ -6,47 +6,54 @@ module StimulusPlumbers
6
6
  module Inputs
7
7
  module Password
8
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)
9
+ revealable = options.delete(:revealable) { false }
10
+ html_options = merge_html_options(theme.resolve(:form_field_input), options)
11
+ if revealable
12
+ render_revealable_password(false) do
13
+ super(attribute, merge_html_options(html_options, { data: { input_formatter_target: "input" } }))
22
14
  end
15
+ else
16
+ super(attribute, html_options)
23
17
  end
24
18
  end
25
19
 
26
20
  private
27
21
 
28
- def render_reveal_password(html_opts, error, &block)
29
- html_options = merge_html_options(
30
- html_opts,
31
- field_theme(:form_input, error: error),
32
- { data: { input_formatter_target: "input" } }
33
- )
22
+ def render_password_input(attribute, html_opts, opts, error, revealable: false, **kwargs)
23
+ if revealable
24
+ html_options = merge_html_options(
25
+ theme.resolve(:form_field_input, error: error),
26
+ opts,
27
+ html_opts,
28
+ kwargs,
29
+ { data: { input_formatter_target: "input" } }
30
+ )
31
+ render_revealable_password(error) do
32
+ @template.password_field(@object_name, attribute, objectify_options(html_options))
33
+ end
34
+ else
35
+ html_options = merge_html_options(theme.resolve(:form_field_input, error: error), opts, html_opts, kwargs)
36
+ @template.password_field(@object_name, attribute, objectify_options(html_options))
37
+ end
38
+ end
39
+
40
+ def render_revealable_password(error, &block)
34
41
  render_input_group(
35
42
  error: error,
36
43
  trailing: method(:reveal_button),
37
44
  **merge_html_options(
38
- field_theme(:form_input_reveal, error: error),
45
+ theme.resolve(:form_field_input_reveal, error: error),
39
46
  { data: { controller: "input-formatter", input_formatter_format_value: "password" } }
40
47
  )
41
- ) { @template.capture(html_options, &block) }
48
+ ) { @template.capture(&block) }
42
49
  end
43
50
 
44
51
  def reveal_button
45
52
  html_options = merge_html_options(
46
- field_theme(:form_button_reveal),
53
+ theme.resolve(:form_field_input_button_reveal),
47
54
  {
48
55
  type: "button",
49
- aria: { label: "Show password", pressed: "false" },
56
+ aria: { label: I18n.t("stimulus_plumbers.form.password.show", default: "Show password"), pressed: "false" },
50
57
  data: { input_formatter_target: "toggle", action: "click->input-formatter#toggle" }
51
58
  }
52
59
  )
@@ -0,0 +1,60 @@
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))
48
+ end
49
+ end
50
+ end
51
+
52
+ def render_radio_button_label(builder, label_opts)
53
+ html_options = merge_html_options(label_opts)
54
+ builder.label(**html_options) { @template.safe_join([builder.radio_button, builder.text]) }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,94 +1,71 @@
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
36
-
37
- private
10
+ include Combobox
38
11
 
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
-
15
+ html_options = merge_html_options(theme.resolve(:form_field_input), options, data)
16
+ input_html = super(attribute, html_options)
44
17
  return input_html unless clearable
45
18
 
46
19
  render_input_group(
47
20
  trailing: method(:clear_button),
48
- error: !!error,
49
- **merge_html_options(field_theme(:form_input_clearable), { data: { controller: "input-clearable" } })
21
+ error: false,
22
+ **merge_html_options(theme.resolve(:form_field_input_clearable), { data: { controller: "input-clearable" } })
50
23
  ) { input_html }
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(attribute, html_opts, opts, error, url: nil, clearable: false, choices: [], **kwargs)
54
29
  current_value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
55
- input_id = html_opts[:id]
56
- opts = Components::Combobox::Typeahead.default_opts.deep_merge(
57
- 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 } : {} }
30
+ combobox_html = render_typeahead_combobox(
31
+ attribute, html_opts, opts, error, current_value, clearable: clearable, choices: choices, url: url, **kwargs
60
32
  )
61
33
 
62
- combobox_html = @template.capture(opts, input_id, current_value, &block)
63
34
  return combobox_html unless clearable
64
35
 
65
36
  render_input_group(
66
37
  trailing: method(:clear_button),
67
- error: !!error,
68
- **merge_html_options(field_theme(:form_input_clearable), { data: { controller: "input-clearable" } })
38
+ error: error,
39
+ **merge_html_options(theme.resolve(:form_field_input_clearable), { data: { controller: "input-clearable" } })
69
40
  ) { combobox_html }
70
41
  end
71
42
 
72
- def render_search_typeahead(attribute, input_id, combobox_opts, error, choices, current_value)
43
+ def render_typeahead_combobox(attribute, html_opts, opts, error, current_value, clearable:, choices:, url:, **kwargs)
44
+ input_id = html_opts[:id]
45
+ labelledby = Field.label_id(input_id)
46
+ combobox_opts = {
47
+ input: { value: current_value },
48
+ trigger: { data: clearable ? { input_clearable_target: "input" } : {}, aria: html_opts[:aria] },
49
+ **opts
50
+ }
73
51
  render_combobox(
74
52
  attribute,
75
53
  input_id: input_id,
76
54
  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)) }
55
+ error: error,
56
+ **kwargs
57
+ ) do |c|
58
+ c.typeahead(options: choices, value: current_value, labelledby: labelledby, url: url)
59
+ end
83
60
  end
84
61
 
85
62
  def clear_button
86
63
  Components::Button.new(@template).render(
87
64
  icon_leading: "close",
88
65
  **merge_html_options(
89
- field_theme(:form_button_clear),
66
+ theme.resolve(:form_field_input_button_clear),
90
67
  {
91
- aria: { label: "Clear search" },
68
+ aria: { label: I18n.t("stimulus_plumbers.form.search.clear", default: "Clear search") },
92
69
  hidden: true,
93
70
  data: { input_clearable_target: "clear", action: "click->input-clearable#clear" }
94
71
  }
@@ -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
@@ -7,34 +7,11 @@ module StimulusPlumbers
7
7
  module Select
8
8
  module Weekday
9
9
  if ActionView.version >= Gem::Version.new("7.1")
10
- def weekday_select(attribute, options = {}, html_options = {})
11
- html_native = options.delete(:html_native) { false }
12
- icon_leading = options.delete(:icon_leading)
13
- icon_trailing = options.delete(:icon_trailing) { "chevron-down" }
14
- icons = { icon_leading: icon_leading, icon_trailing: icon_trailing }
15
- with_select_field(attribute, options, html_options) do |opts, merged, error|
16
- if html_native
17
- super(attribute, opts, merged)
18
- else
19
- render_select_dropdown(attribute, opts, merged, err: error, **icons) do
20
- build_weekday_choices(opts)
21
- end
22
- end
23
- end
10
+ def weekday_select(attribute, options = {}, html_opts = {})
11
+ html_options = merge_html_options(theme.resolve(:form_select), html_opts)
12
+ super(attribute, options, html_options)
24
13
  end
25
14
  end
26
-
27
- private
28
-
29
- def build_weekday_choices(opts)
30
- index_as_value = opts.delete(:index_as_value) { false }
31
- day_format = opts.delete(:day_format) { :day_names }
32
- beginning_of_week = opts.delete(:beginning_of_week) { Date.beginning_of_week }
33
-
34
- day_names = I18n.t("date.#{day_format}")
35
- choices = day_names.each_with_index.map { |name, i| index_as_value ? [name, i] : [name, name] }
36
- choices.rotate(Date::DAYS_INTO_WEEK.fetch(beginning_of_week))
37
- end
38
15
  end
39
16
  end
40
17
  end
@@ -1,86 +1,87 @@
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 Select
10
+ include Combobox
11
+
8
12
  def select(attribute, choices = nil, options = {}, html_options = {})
9
- html_native = options.delete(:html_native) { false }
10
- icon_leading = options.delete(:icon_leading)
11
- icon_trailing = options.delete(:icon_trailing) { "chevron-down" }
12
- icons = { icon_leading: icon_leading, icon_trailing: icon_trailing }
13
- with_select_field(attribute, options, html_options) do |opts, merged, error|
14
- if html_native
15
- super(attribute, choices, opts, merged)
16
- else
17
- render_select_dropdown(attribute, opts, merged, err: error, **icons) do
18
- Array(choices)
19
- end
20
- end
21
- end
13
+ merged = merge_html_options(theme.resolve(:form_field_input_select), html_options)
14
+ super(attribute, choices, options, merged)
22
15
  end
23
16
 
24
- def collection_select(
25
- attribute,
26
- collection,
27
- value_method,
28
- text_method,
29
- options = {},
30
- html_options = {}
31
- )
32
- html_native = options.delete(:html_native) { false }
33
- icon_leading = options.delete(:icon_leading)
34
- icon_trailing = options.delete(:icon_trailing) { "chevron-down" }
35
- icons = { icon_leading: icon_leading, icon_trailing: icon_trailing }
36
- with_select_field(attribute, options, html_options) do |opts, merged, error|
37
- if html_native
38
- super(attribute, collection, value_method, text_method, opts, merged)
39
- else
40
- render_select_dropdown(attribute, opts, merged, err: error, **icons) do
41
- collection.map { |item| [item.public_send(text_method), item.public_send(value_method)] }
42
- end
43
- end
44
- end
17
+ def collection_select(attribute, collection, value_method, text_method, options = {}, html_options = {})
18
+ merged = merge_html_options(theme.resolve(:form_field_input_select), html_options)
19
+ super(attribute, collection, value_method, text_method, options, merged)
45
20
  end
46
21
 
47
22
  private
48
23
 
49
- def with_select_field(attribute, options, html_options)
50
- Field.new(@template, **options).render(object, attribute, input_id: field_id(attribute)) do |html_opts, opts, error|
51
- yield opts, merge_html_options(html_options, html_opts, field_theme(:form_select, error: error)), error
52
- end
53
- end
54
-
55
- def render_select_dropdown(attribute, opts, html_opts, err:, icon_leading:, icon_trailing:)
56
- include_blank = opts.delete(:include_blank)
57
- prompt = opts.delete(:prompt)
58
- current_value = opts.delete(:selected) { object.respond_to?(attribute) ? object.public_send(attribute) : nil }
59
- choices = build_select_dropdown_choices(yield(current_value), include_blank: include_blank, prompt: prompt)
24
+ def render_combobox_dropdown(
25
+ attribute,
26
+ html_opts,
27
+ opts,
28
+ error,
29
+ icon_leading: nil,
30
+ icon_trailing: nil,
31
+ choices: [],
32
+ include_blank: nil,
33
+ prompt: nil,
34
+ selected: nil,
35
+ **kwargs
36
+ )
37
+ current_value = selected || (object.respond_to?(attribute) ? object.public_send(attribute) : nil)
38
+ all_choices = build_select_dropdown_choices(Array(choices), include_blank: include_blank, prompt: prompt)
39
+ labelledby = Field.label_id(html_opts[:id])
60
40
  combobox_opts = build_select_dropdown_opts(
61
- html_opts,
62
- current_value,
63
- icon_leading: icon_leading,
64
- icon_trailing: icon_trailing
41
+ html_opts, current_value, opts: opts, icon_leading: icon_leading, icon_trailing: icon_trailing
65
42
  )
66
- render_combobox(attribute, input_id: html_opts[:id], opts: combobox_opts, err: err) do
67
- render_dropdown_component(choices, current_value, html_opts[:id])
43
+ render_combobox(
44
+ attribute,
45
+ input_id: html_opts[:id],
46
+ opts: combobox_opts,
47
+ error: error
48
+ ) do |c|
49
+ c.dropdown(options: all_choices, value: current_value, labelledby: labelledby, **kwargs)
68
50
  end
69
51
  end
70
52
 
71
- def render_dropdown_component(choices, value, input_id)
72
- Components::Combobox::Dropdown.new(@template).render(
73
- options: choices,
74
- value: value,
75
- labelledby: Field.label_id(input_id)
76
- )
53
+ def render_collection_combobox_dropdown(
54
+ attribute,
55
+ collection,
56
+ value_method,
57
+ text_method,
58
+ field_opts,
59
+ **kwargs
60
+ )
61
+ choices = collection.map { |item| [item.public_send(text_method), item.public_send(value_method)] }
62
+ render_field(:select, attribute, field_opts, { choices: choices, **kwargs })
63
+ end
64
+
65
+ def render_grouped_collection_combobox_dropdown(
66
+ attribute,
67
+ collection,
68
+ value_method,
69
+ text_method,
70
+ field_opts,
71
+ group_method:,
72
+ group_label_method:,
73
+ **kwargs
74
+ )
75
+ choices = build_grouped_choices(collection, group_label_method, group_method, value_method, text_method)
76
+ render_field(:select, attribute, field_opts, { choices: choices, **kwargs })
77
77
  end
78
78
 
79
- def build_select_dropdown_opts(html_opts, current_value, icon_leading:, icon_trailing:)
80
- Components::Combobox::Dropdown.default_opts.deep_merge(
79
+ def build_select_dropdown_opts(html_opts, current_value, opts:, icon_leading:, icon_trailing:)
80
+ {
81
81
  input: { value: current_value },
82
- trigger: html_opts.merge({ icon_leading: icon_leading, icon_trailing: icon_trailing }.compact)
83
- )
82
+ trigger: { aria: html_opts[:aria], icon_leading: icon_leading, icon_trailing: icon_trailing }.compact,
83
+ **opts
84
+ }
84
85
  end
85
86
 
86
87
  def build_select_dropdown_choices(choices, include_blank:, prompt:)
@@ -10,13 +10,16 @@ module StimulusPlumbers
10
10
  options = value
11
11
  value = nil
12
12
  end
13
- value ||= submit_default_value
14
- variant = options.delete(:variant) { :default }
15
- @template.tag.input(
16
- type: "submit",
17
- value: value,
18
- **merge_html_options(field_theme(:form_submit, variant: variant), options)
19
- )
13
+ value ||= submit_default_value
14
+ type = options.delete(:type) { :default }
15
+ variant = options.delete(:variant) { :primary }
16
+
17
+ Components::Button.new(@template).build(type: type, variant: variant) do |attrs|
18
+ @template.tag.button(
19
+ type: "submit",
20
+ **merge_html_options(attrs, options)
21
+ ) { value }
22
+ end
20
23
  end
21
24
  end
22
25
  end