impulse_view_components 0.7.2 → 0.9.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.
@@ -1,57 +1,73 @@
1
1
  module Impulse
2
- class SelectComponent < ApplicationComponent
3
- renders_one :blankslate
4
- renders_many :options, Impulse::Autocomplete::OptionComponent
5
-
2
+ class SelectComponent < AutocompleteComponent
3
+ # No longer used here. Kept for apps that build one to pass to `AutocompleteComponent` as `selected:`.
6
4
  OptionStruct = Struct.new(:value, :text, :html_attributes)
7
5
 
8
6
  def initialize(object_name, method_name, choices = [], selected: nil, **system_args)
9
- @object_name = object_name
10
- @method_name = method_name
7
+ super(object_name, method_name, **system_args)
11
8
  @choices = choices
12
- @selected = selected
13
- @system_args = system_args
9
+ @selected_value = selected
10
+ end
11
+
12
+ def before_render
13
+ add_options_from_choices unless options?
14
+ super
15
+ end
16
+
17
+ # The flat `options` slot this component used to declare came with `with_options`.
18
+ def with_options(collection, &block)
19
+ collection.map { |arguments| with_option(**arguments, &block) }
14
20
  end
15
21
 
16
22
  private
17
23
 
18
- def value
19
- return if @selected.nil?
20
- return @selected.map { |value| find_option(value) }.compact if multiple?
21
- find_option(@selected)
24
+ # The choices the options are built from when the block adds none. Subclasses override it to supply their own.
25
+ attr_reader :choices
26
+
27
+ def selection
28
+ return @selection if defined?(@selection)
29
+
30
+ # A group runs its `with_option` block only when it renders, so the options render before the selection is looked
31
+ # up among them. Each slot keeps what it rendered, so the template doesn't render them again.
32
+ options.each(&:to_s)
33
+ @selection =
34
+ if @selected_value.blank?
35
+ nil
36
+ elsif multiple?
37
+ @selected_value.map { |value| find_option(value) }.compact
38
+ else
39
+ find_option(@selected_value)
40
+ end
22
41
  end
23
42
 
24
- def options_from_choices
25
- return [] if @choices.nil?
26
- return grouped_options_for_select(@choices) if grouped_choices?
27
- options_for_select(@choices)
43
+ def find_option(value)
44
+ options
45
+ .flat_map { |option| option.respond_to?(:options) ? option.options.to_a : [option] }
46
+ .find { |option| option.value.to_s == value.to_s }
28
47
  end
29
48
 
30
- def options_for_select(choices)
31
- choices.map do |choice|
32
- html_attributes = option_html_attributes(choice)
33
- text, value = option_text_and_value(choice)
34
- OptionStruct.new(value, text, html_attributes)
35
- end
49
+ def add_options_from_choices
50
+ return if choices.blank?
51
+ return choices.each { |title, group_choices| add_group(title, group_choices) } if grouped_choices?
52
+
53
+ option_arguments(choices).each { |arguments| with_option(**arguments) }
36
54
  end
37
55
 
38
- def grouped_options_for_select(grouped_choices)
39
- grouped_choices.map do |grouped_choice|
40
- title, container = grouped_choice
41
- [title, options_for_select(container)]
56
+ def add_group(title, group_choices)
57
+ with_group(title:) do |group|
58
+ option_arguments(group_choices).each { |arguments| group.with_option(**arguments) }
42
59
  end
43
60
  end
44
61
 
45
- def find_option(value)
46
- (options.presence || options_from_choices).flatten.find { |option| option.try(:value)&.to_s == value.to_s }
62
+ def option_arguments(list)
63
+ list.map do |choice|
64
+ text, value = option_text_and_value(choice)
65
+ { value:, text:, **option_html_attributes(choice) }
66
+ end
47
67
  end
48
68
 
49
69
  def grouped_choices?
50
- @choices.present? && @choices.first.respond_to?(:last) && Array === @choices.first.last
51
- end
52
-
53
- def multiple?
54
- !!@system_args[:multiple]
70
+ choices.first.respond_to?(:last) && Array === choices.first.last
55
71
  end
56
72
  end
57
73
  end
@@ -1,66 +1,67 @@
1
1
  module Impulse
2
- class TimeZoneSelectComponent < ApplicationComponent
3
- renders_one :blankslate
4
-
2
+ class TimeZoneSelectComponent < SelectComponent
3
+ # No longer used here. Kept for apps that refer to it.
5
4
  OptionStruct = Struct.new(:value, :text)
6
5
 
7
6
  def initialize(object_name, method_name, priority_zones = nil, selected: nil, default: nil, model: ::ActiveSupport::TimeZone, priority_zones_title: "Prioritized time zones", **system_args)
8
- @object_name = object_name
9
- @method_name = method_name
7
+ super(object_name, method_name, selected: selected || default, **system_args)
10
8
  @priority_zones = priority_zones
11
- @selected = selected
12
- @default = default
13
9
  @model = model
14
10
  @priority_zones_title = priority_zones_title
15
- @system_args = system_args
16
11
  end
17
12
 
18
13
  private
19
14
 
20
- def options
21
- priority_zones = @priority_zones
22
-
23
- zones = Hash.new { |h, k| h[k] = [] }.tap do |hash|
24
- model = @model.all
15
+ def choices
16
+ @choices_from_zones ||=
17
+ if prioritized?
18
+ [
19
+ [@priority_zones_title, zone_choices(zones[:priority_zones], test_id: "priority-zones")],
20
+ ["Other", zone_choices(zones[:other], test_id: "unprioritized-zones")]
21
+ ]
22
+ else
23
+ zone_choices(zones[:other])
24
+ end
25
+ end
25
26
 
26
- if priority_zones
27
- if priority_zones.is_a?(Regexp)
28
- priority_zones = model.select { |z| z.match?(priority_zones) }
29
- end
27
+ def zone_choices(time_zones, test_id: nil)
28
+ time_zones.map { |zone| [zone.to_s, zone.name, test_id ? { data: { test_id: } } : {}] }
29
+ end
30
30
 
31
- hash[:priority_zones] = priority_zones
32
- model -= priority_zones
33
- end
31
+ def default_blankslate
32
+ "We couldn't find that time zone!"
33
+ end
34
34
 
35
- hash[:other] = model
36
- end
35
+ def zones
36
+ @zones ||= begin
37
+ priority_zones = @priority_zones
37
38
 
38
- if zones[:other].blank?
39
- zones[:other] = zones[:priority_zones]
40
- zones[:priority_zones] = []
41
- end
39
+ zones = Hash.new { |h, k| h[k] = [] }.tap do |hash|
40
+ model = @model.all
42
41
 
43
- zones
44
- end
42
+ if priority_zones
43
+ if priority_zones.is_a?(Regexp)
44
+ priority_zones = model.select { |z| z.match?(priority_zones) }
45
+ end
45
46
 
46
- def value
47
- find_option(selected) if selected.present?
48
- end
47
+ hash[:priority_zones] = priority_zones
48
+ model -= priority_zones
49
+ end
49
50
 
50
- def options_from_choices
51
- @model.all.map { |option| OptionStruct.new(option.name, option.to_s) }
52
- end
51
+ hash[:other] = model
52
+ end
53
53
 
54
- def find_option(value)
55
- options_from_choices.find { |option| option.value == value }
56
- end
54
+ if zones[:other].blank?
55
+ zones[:other] = zones[:priority_zones]
56
+ zones[:priority_zones] = []
57
+ end
57
58
 
58
- def selected
59
- @selected || @default
59
+ zones
60
+ end
60
61
  end
61
62
 
62
63
  def prioritized?
63
- options[:priority_zones].present?
64
+ zones[:priority_zones].present?
64
65
  end
65
66
  end
66
67
  end
@@ -1,5 +1,5 @@
1
1
  module Impulse
2
2
  module ViewComponents
3
- VERSION = "0.7.2".freeze
3
+ VERSION = "0.9.0".freeze
4
4
  end
5
5
  end
@@ -2,8 +2,6 @@ require "impulse/view_components/version"
2
2
  require "impulse/view_components/engine"
3
3
 
4
4
  module Impulse
5
- autoload :AttributesHelper, "impulse/helpers/attributes_helper"
6
-
7
5
  module ViewComponents
8
6
  end
9
7
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: impulse_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - abeidahmed
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-07-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: view_component
@@ -16,68 +15,70 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '3.11'
18
+ version: 4.17.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '3.11'
25
+ version: 4.17.0
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: actionview
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: 6.1.0
32
+ version: 7.1.0
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
- version: 6.1.0
39
+ version: 7.1.0
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: capybara
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '3.39'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 3.39.2
46
+ version: '3.40'
51
47
  type: :development
52
48
  prerelease: false
53
49
  version_requirements: !ruby/object:Gem::Requirement
54
50
  requirements:
55
51
  - - "~>"
56
52
  - !ruby/object:Gem::Version
57
- version: '3.39'
58
- - - ">="
53
+ version: '3.40'
54
+ - !ruby/object:Gem::Dependency
55
+ name: ostruct
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 3.39.2
60
+ version: '0.6'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.6'
61
68
  - !ruby/object:Gem::Dependency
62
69
  name: byebug
63
70
  requirement: !ruby/object:Gem::Requirement
64
71
  requirements:
65
72
  - - "~>"
66
73
  - !ruby/object:Gem::Version
67
- version: '11.1'
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: 11.1.3
74
+ version: '13.0'
71
75
  type: :development
72
76
  prerelease: false
73
77
  version_requirements: !ruby/object:Gem::Requirement
74
78
  requirements:
75
79
  - - "~>"
76
80
  - !ruby/object:Gem::Version
77
- version: '11.1'
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: 11.1.3
81
+ version: '13.0'
81
82
  - !ruby/object:Gem::Dependency
82
83
  name: webmock
83
84
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +99,6 @@ dependencies:
98
99
  - - ">="
99
100
  - !ruby/object:Gem::Version
100
101
  version: 3.18.1
101
- description:
102
102
  email:
103
103
  - info@ambiki.com
104
104
  executables: []
@@ -122,6 +122,7 @@ files:
122
122
  - app/components/impulse/autocomplete_component.html.erb
123
123
  - app/components/impulse/autocomplete_component.rb
124
124
  - app/components/impulse/base_renderer.rb
125
+ - app/components/impulse/clipboard_copy_component.rb
125
126
  - app/components/impulse/dialog/body_component.rb
126
127
  - app/components/impulse/dialog/footer_component.rb
127
128
  - app/components/impulse/dialog/header_component.html.erb
@@ -132,10 +133,8 @@ files:
132
133
  - app/components/impulse/popover/header_component.rb
133
134
  - app/components/impulse/popover_component.html.erb
134
135
  - app/components/impulse/popover_component.rb
135
- - app/components/impulse/select_component.html.erb
136
136
  - app/components/impulse/select_component.rb
137
137
  - app/components/impulse/spinner_component.rb
138
- - app/components/impulse/time_zone_select_component.html.erb
139
138
  - app/components/impulse/time_zone_select_component.rb
140
139
  - lib/impulse/forms/builder.rb
141
140
  - lib/impulse/forms/tags/ajax_select.rb
@@ -153,7 +152,6 @@ licenses:
153
152
  metadata:
154
153
  source_code_uri: https://github.com/Ambiki/impulse_view_components
155
154
  changelog_uri: https://github.com/Ambiki/impulse_view_components/blob/main/CHANGELOG.md
156
- post_install_message:
157
155
  rdoc_options: []
158
156
  require_paths:
159
157
  - lib
@@ -161,15 +159,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
159
  requirements:
162
160
  - - ">="
163
161
  - !ruby/object:Gem::Version
164
- version: 3.1.4
162
+ version: '3.4'
165
163
  required_rubygems_version: !ruby/object:Gem::Requirement
166
164
  requirements:
167
165
  - - ">="
168
166
  - !ruby/object:Gem::Version
169
167
  version: '0'
170
168
  requirements: []
171
- rubygems_version: 3.3.26
172
- signing_key:
169
+ rubygems_version: 3.6.9
173
170
  specification_version: 4
174
171
  summary: View components for Ruby on Rails
175
172
  test_files: []
@@ -1,21 +0,0 @@
1
- <%= render(Impulse::AutocompleteComponent.new(@object_name, @method_name, selected: value, **@system_args)) do |c| %>
2
- <% if options? %>
3
- <% options.each do |option| %>
4
- <%= c.with_option(value: option.value, text: option.text, description: option.description, **option.system_args) %>
5
- <% end %>
6
- <% else %>
7
- <% options_from_choices.each do |option| %>
8
- <% if option.is_a?(Array) %>
9
- <% c.with_group(title: option.first) do |group| %>
10
- <% option.second.each do |grouped_option| %>
11
- <% group.with_option(value: grouped_option.value, text: grouped_option.text, **grouped_option.html_attributes) %>
12
- <% end %>
13
- <% end %>
14
- <% else %>
15
- <%= c.with_option(value: option.value, text: option.text, **option.html_attributes) %>
16
- <% end %>
17
- <% end %>
18
- <% end %>
19
-
20
- <%= c.with_blankslate_content(blankslate.presence || "We couldn't find that!") %>
21
- <% end %>
@@ -1,20 +0,0 @@
1
- <%= render(Impulse::AutocompleteComponent.new(@object_name, @method_name, selected: value, **@system_args)) do |c| %>
2
- <% if prioritized? %>
3
- <% c.with_group(title: @priority_zones_title) do |group| %>
4
- <% options[:priority_zones].each do |option| %>
5
- <% group.with_option(value: option.name, text: option.to_s, data: {test_id: "priority-zones"}) %>
6
- <% end %>
7
- <% end %>
8
- <% c.with_group(title: "Other") do |group| %>
9
- <% options[:other].each do |option| %>
10
- <% group.with_option(value: option.name, text: option.to_s, data: {test_id: "unprioritized-zones"}) %>
11
- <% end %>
12
- <% end %>
13
- <% else %>
14
- <% options[:other].each do |option| %>
15
- <% c.with_option(value: option.name, text: option.to_s) %>
16
- <% end %>
17
- <% end %>
18
-
19
- <% c.with_blankslate_content(blankslate.presence || "We couldn't find that time zone!") %>
20
- <% end %>