hotwire_combobox 0.1.37 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +86 -2
- data/app/assets/javascripts/hotwire_combobox.esm.js +1254 -0
- data/app/assets/javascripts/hotwire_combobox.umd.js +1260 -0
- data/app/assets/javascripts/hw_combobox/models/combobox/filtering.js +6 -1
- data/app/assets/stylesheets/hotwire_combobox.css +4 -0
- data/app/presenters/hotwire_combobox/component.rb +8 -2
- data/app/presenters/hotwire_combobox/listbox/option.rb +6 -2
- data/app/views/hotwire_combobox/_next_page.turbo_stream.erb +1 -1
- data/lib/hotwire_combobox/engine.rb +1 -1
- data/lib/hotwire_combobox/helper.rb +83 -18
- data/lib/hotwire_combobox/version.rb +1 -1
- metadata +4 -2
@@ -21,7 +21,12 @@ Combobox.Filtering = Base => class extends Base {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
async _filterAsync(event) {
|
24
|
-
const query = {
|
24
|
+
const query = {
|
25
|
+
q: this._fullQuery,
|
26
|
+
input_type: event.inputType,
|
27
|
+
for_id: this.element.dataset.asyncId
|
28
|
+
}
|
29
|
+
|
25
30
|
await get(this.asyncSrcValue, { responseKind: "turbo-stream", query })
|
26
31
|
}
|
27
32
|
|
@@ -121,6 +121,10 @@
|
|
121
121
|
text-overflow: ellipsis;
|
122
122
|
}
|
123
123
|
|
124
|
+
.hw-combobox__option--blank {
|
125
|
+
border-bottom: var(--hw-border-width--slim) solid var(--hw-border-color);
|
126
|
+
}
|
127
|
+
|
124
128
|
.hw-combobox__option:hover,
|
125
129
|
.hw-combobox__option--selected {
|
126
130
|
background-color: var(--hw-active-bg-color);
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
1
3
|
class HotwireCombobox::Component
|
2
|
-
attr_reader :
|
4
|
+
attr_reader :options, :dialog_label
|
3
5
|
|
4
6
|
def initialize \
|
5
7
|
view, name,
|
@@ -181,9 +183,13 @@ class HotwireCombobox::Component
|
|
181
183
|
form&.object&.class&.reflect_on_association(association_name).present?
|
182
184
|
end
|
183
185
|
|
186
|
+
def async_src
|
187
|
+
view.hw_uri_with_params @async_src, for_id: canonical_id, format: :turbo_stream
|
188
|
+
end
|
189
|
+
|
184
190
|
|
185
191
|
def canonical_id
|
186
|
-
id || form&.field_id(name)
|
192
|
+
id || form&.field_id(name) || SecureRandom.uuid
|
187
193
|
end
|
188
194
|
|
189
195
|
|
@@ -18,7 +18,7 @@ class HotwireCombobox::Listbox::Option
|
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
21
|
-
Data = Struct.new :id, :value, :display, :content, :filterable_as, :autocompletable_as, keyword_init: true
|
21
|
+
Data = Struct.new :id, :value, :display, :content, :blank, :filterable_as, :autocompletable_as, keyword_init: true
|
22
22
|
|
23
23
|
attr_reader :option
|
24
24
|
|
@@ -26,7 +26,7 @@ class HotwireCombobox::Listbox::Option
|
|
26
26
|
{
|
27
27
|
id: id,
|
28
28
|
role: :option,
|
29
|
-
class: "hw-combobox__option",
|
29
|
+
class: [ "hw-combobox__option", { "hw-combobox__option--blank": blank? } ],
|
30
30
|
data: data
|
31
31
|
}
|
32
32
|
end
|
@@ -51,4 +51,8 @@ class HotwireCombobox::Listbox::Option
|
|
51
51
|
def filterable_as
|
52
52
|
option.try(:filterable_as) || option.try(:display)
|
53
53
|
end
|
54
|
+
|
55
|
+
def blank?
|
56
|
+
option.try(:blank).present?
|
57
|
+
end
|
54
58
|
end
|
@@ -2,5 +2,5 @@
|
|
2
2
|
|
3
3
|
<%= turbo_stream.remove hw_pagination_frame_wrapper_id(for_id) %>
|
4
4
|
<%= turbo_stream.append hw_listbox_id(for_id) do %>
|
5
|
-
<%= render "hotwire_combobox/pagination", for_id: for_id, src: hw_combobox_next_page_uri(src, next_page) %>
|
5
|
+
<%= render "hotwire_combobox/pagination", for_id: for_id, src: hw_combobox_next_page_uri(src, next_page, for_id) %>
|
6
6
|
<% end %>
|
@@ -10,7 +10,7 @@ module HotwireCombobox
|
|
10
10
|
unless HotwireCombobox.bypass_convenience_methods?
|
11
11
|
module FormBuilderExtensions
|
12
12
|
def combobox(*args, **kwargs)
|
13
|
-
@template.hw_combobox_tag
|
13
|
+
@template.hw_combobox_tag(*args, **kwargs.merge(form: self))
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -15,27 +15,32 @@ module HotwireCombobox
|
|
15
15
|
end
|
16
16
|
hw_alias :hw_combobox_style_tag
|
17
17
|
|
18
|
-
def hw_combobox_tag(name, options_or_src = [], render_in: {}, **kwargs)
|
19
|
-
options, src = hw_extract_options_and_src(options_or_src, render_in)
|
18
|
+
def hw_combobox_tag(name, options_or_src = [], render_in: {}, include_blank: nil, **kwargs)
|
19
|
+
options, src = hw_extract_options_and_src(options_or_src, render_in, include_blank)
|
20
20
|
component = HotwireCombobox::Component.new self, name, options: options, async_src: src, **kwargs
|
21
21
|
|
22
22
|
render "hotwire_combobox/combobox", component: component
|
23
23
|
end
|
24
24
|
hw_alias :hw_combobox_tag
|
25
25
|
|
26
|
-
def hw_combobox_options(options, render_in: {}, display: :to_combobox_display, **methods)
|
26
|
+
def hw_combobox_options(options, render_in: {}, include_blank: nil, display: :to_combobox_display, **methods)
|
27
27
|
if options.first.is_a? HotwireCombobox::Listbox::Option
|
28
28
|
options
|
29
29
|
else
|
30
|
-
render_in_proc =
|
31
|
-
|
30
|
+
render_in_proc = hw_render_in_proc(render_in) if render_in.present?
|
31
|
+
|
32
|
+
hw_parse_combobox_options(options, render_in: render_in_proc, **methods.merge(display: display)).tap do |options|
|
33
|
+
options.unshift(hw_blank_option(include_blank)) if include_blank.present?
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
hw_alias :hw_combobox_options
|
35
38
|
|
36
|
-
def hw_paginated_combobox_options(options, for_id
|
37
|
-
|
38
|
-
|
39
|
+
def hw_paginated_combobox_options(options, for_id: params[:for_id], src: request.path, next_page: nil, render_in: {}, include_blank: {}, **methods)
|
40
|
+
include_blank = params[:page] ? nil : include_blank
|
41
|
+
options = hw_combobox_options options, render_in: render_in, include_blank: include_blank, **methods
|
42
|
+
this_page = render "hotwire_combobox/paginated_options", for_id: for_id, options: options
|
43
|
+
next_page = render "hotwire_combobox/next_page", for_id: for_id, src: src, next_page: next_page
|
39
44
|
|
40
45
|
safe_join [ this_page, next_page ]
|
41
46
|
end
|
@@ -44,7 +49,7 @@ module HotwireCombobox
|
|
44
49
|
alias_method :hw_async_combobox_options, :hw_paginated_combobox_options
|
45
50
|
hw_alias :hw_async_combobox_options
|
46
51
|
|
47
|
-
|
52
|
+
# private library use only
|
48
53
|
def hw_listbox_id(id)
|
49
54
|
"#{id}-hw-listbox"
|
50
55
|
end
|
@@ -57,9 +62,13 @@ module HotwireCombobox
|
|
57
62
|
"#{id}__hw_combobox_pagination"
|
58
63
|
end
|
59
64
|
|
60
|
-
def hw_combobox_next_page_uri(uri, next_page)
|
65
|
+
def hw_combobox_next_page_uri(uri, next_page, for_id)
|
61
66
|
if next_page
|
62
|
-
hw_uri_with_params uri,
|
67
|
+
hw_uri_with_params uri,
|
68
|
+
page: next_page,
|
69
|
+
q: params[:q],
|
70
|
+
for_id: for_id,
|
71
|
+
format: :turbo_stream
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
@@ -67,12 +76,19 @@ module HotwireCombobox
|
|
67
76
|
params[:page] ? :append : :update
|
68
77
|
end
|
69
78
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
79
|
+
def hw_blank_option(include_blank)
|
80
|
+
display, content = hw_extract_blank_display_and_content include_blank
|
81
|
+
|
82
|
+
HotwireCombobox::Listbox::Option.new display: display, content: content, value: "", blank: true
|
83
|
+
end
|
84
|
+
|
85
|
+
def hw_extract_blank_display_and_content(include_blank)
|
86
|
+
if include_blank.is_a? Hash
|
87
|
+
text = include_blank.delete(:text)
|
88
|
+
|
89
|
+
[ text, hw_render_in_proc(include_blank).(text) ]
|
74
90
|
else
|
75
|
-
[
|
91
|
+
[ include_blank, include_blank ]
|
76
92
|
end
|
77
93
|
end
|
78
94
|
|
@@ -85,9 +101,23 @@ module HotwireCombobox
|
|
85
101
|
url_or_path
|
86
102
|
end
|
87
103
|
|
104
|
+
private
|
105
|
+
def hw_render_in_proc(render_in)
|
106
|
+
->(object) { render(**render_in.reverse_merge(object: object)) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def hw_extract_options_and_src(options_or_src, render_in, include_blank)
|
110
|
+
if options_or_src.is_a? String
|
111
|
+
[ [], options_or_src ]
|
112
|
+
else
|
113
|
+
[ hw_combobox_options(options_or_src, render_in: render_in, include_blank: include_blank), nil ]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
88
117
|
def hw_parse_combobox_options(options, render_in: nil, **methods)
|
89
118
|
options.map do |option|
|
90
|
-
HotwireCombobox::Listbox::Option.new
|
119
|
+
HotwireCombobox::Listbox::Option.new \
|
120
|
+
**hw_option_attrs_for(option, render_in: render_in, **methods)
|
91
121
|
end
|
92
122
|
end
|
93
123
|
|
@@ -122,8 +152,43 @@ module HotwireCombobox
|
|
122
152
|
if method_or_proc.is_a? Proc
|
123
153
|
method_or_proc.call object
|
124
154
|
else
|
125
|
-
object
|
155
|
+
hw_call_method object, method_or_proc
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def hw_call_method(object, method)
|
160
|
+
if object.respond_to? method
|
161
|
+
object.public_send method
|
162
|
+
else
|
163
|
+
hw_raise_no_public_method_error object, method
|
126
164
|
end
|
127
165
|
end
|
166
|
+
|
167
|
+
def hw_raise_no_public_method_error(object, method)
|
168
|
+
if object.respond_to? method, true
|
169
|
+
header = "`#{object.class}` responds to `##{method}` but the method is not public."
|
170
|
+
else
|
171
|
+
header = "`#{object.class}` does not respond to `##{method}`."
|
172
|
+
end
|
173
|
+
|
174
|
+
if method.to_s == "to_combobox_display"
|
175
|
+
header << "\n\nThis method is used to determine how this option should appear in the combobox options list."
|
176
|
+
end
|
177
|
+
|
178
|
+
raise NoMethodError, <<~MSG
|
179
|
+
[ACTION NEEDED] – Message from HotwireCombobox:
|
180
|
+
|
181
|
+
#{header}
|
182
|
+
|
183
|
+
Please add this as a public method and return a string.
|
184
|
+
|
185
|
+
Example:
|
186
|
+
class #{object.class} < ApplicationRecord
|
187
|
+
def #{method}
|
188
|
+
name # or `title`, `to_s`, etc.
|
189
|
+
end
|
190
|
+
end
|
191
|
+
MSG
|
192
|
+
end
|
128
193
|
end
|
129
194
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotwire_combobox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.38
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jose Farias
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -65,6 +65,8 @@ files:
|
|
65
65
|
- Rakefile
|
66
66
|
- app/assets/config/hw_combobox_manifest.js
|
67
67
|
- app/assets/javascripts/controllers/hw_combobox_controller.js
|
68
|
+
- app/assets/javascripts/hotwire_combobox.esm.js
|
69
|
+
- app/assets/javascripts/hotwire_combobox.umd.js
|
68
70
|
- app/assets/javascripts/hw_combobox/helpers.js
|
69
71
|
- app/assets/javascripts/hw_combobox/models/combobox.js
|
70
72
|
- app/assets/javascripts/hw_combobox/models/combobox/actors.js
|