hotwire_combobox 0.1.41 → 0.1.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -0
- data/app/assets/javascripts/hotwire_combobox.esm.js +12 -6
- data/app/assets/javascripts/hotwire_combobox.umd.js +12 -6
- data/app/assets/javascripts/hw_combobox/models/combobox/events.js +10 -5
- data/app/assets/javascripts/hw_combobox/models/combobox/toggle.js +1 -0
- data/lib/hotwire_combobox/engine.rb +2 -2
- data/lib/hotwire_combobox/helper.rb +26 -16
- data/lib/hotwire_combobox/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fc3750ecb7bd58bd28e13d0cc2d543ae4c614535c927c9483e504b643171a8d
|
4
|
+
data.tar.gz: dc6482de8a4344a6d801797d497f6adec8afcc0357e821e1dff8188ecf4c2f68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8884e9e8295b73d37d15762f08c1a69452a7117f99af09dba4369aedea9af2116bc9683127f6f29535813fa5182b21969eb35e4d077edee1f94ce1a6808aadfe
|
7
|
+
data.tar.gz: b58dd5870a0508912c910b387f7970ffc4a08a16e40612b448e7c35ae244d0f8e02f9dd9356e5cdd8ae7f0c45c1bd65513ece94fcbeba38818c39d39c9ecd870
|
data/README.md
CHANGED
@@ -80,6 +80,9 @@ import HwComboboxController from "@josefarias/hotwire_combobox"
|
|
80
80
|
application.register("hw-combobox", HwComboboxController)
|
81
81
|
```
|
82
82
|
|
83
|
+
> [!WARNING]
|
84
|
+
> Keep in mind you need to update both the npm package and the gem every time there's a new version of HotwireCombobox. You should always run the same version number on both sides.
|
85
|
+
|
83
86
|
### Configuring CSS
|
84
87
|
|
85
88
|
This library comes with optional default styles. Follow the instructions below to include them in your app.
|
@@ -109,6 +112,19 @@ Require the styles in `app/assets/stylesheets/application.css`:
|
|
109
112
|
Visit [the docs site](https://hotwirecombobox.com/) for a demo and detailed documentation.
|
110
113
|
If the site is down, you can run the docs locally by cloning [the docs repo](https://github.com/josefarias/hotwire_combobox_docs).
|
111
114
|
|
115
|
+
## Notes about accessibility
|
116
|
+
|
117
|
+
This gem follows the [APG combobox pattern guidelines](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) with some exceptions we feel increase the usefulness of the component without much detriment to the overall accessible experience.
|
118
|
+
|
119
|
+
These are the exceptions:
|
120
|
+
|
121
|
+
1. Users cannot manipulate the combobox while it's closed. As long as the combobox is focused, the listbox is shown.
|
122
|
+
2. The escape key closes the listbox and blurs the combobox. It does not clear the combobox.
|
123
|
+
3. The listbox has wrap-around selection. That is, pressing `Up Arrow` when the user is on the first option will select the last option. And pressing `Down Arrow` when on the last option will select the first option. In paginated comboboxes, the first and last options refer to the currently available options. More options may be loaded after navigating to the last currently available option.
|
124
|
+
4. It is possible to have an unlabled combobox, as that responsibility is delegated to the implementing user.
|
125
|
+
|
126
|
+
It should be noted none of the maintainers use assistive technologies in their daily lives. If you do, and you feel these exceptions are detrimental to your ability to use the component, or if you find an undocumented exception, please [open a GitHub issue](https://github.com/josefarias/hotwire_combobox/issues). We'll get it sorted.
|
127
|
+
|
112
128
|
## Contributing
|
113
129
|
|
114
130
|
Please read [CONTRIBUTING.md](./CONTRIBUTING.md).
|
@@ -237,16 +237,21 @@ Combobox.Dialog = Base => class extends Base {
|
|
237
237
|
|
238
238
|
Combobox.Events = Base => class extends Base {
|
239
239
|
_dispatchSelectionEvent({ isNew }) {
|
240
|
-
|
240
|
+
dispatch("hw-combobox:selection", { target: this.element, detail: { ...this._eventableDetails, isNew } });
|
241
|
+
}
|
242
|
+
|
243
|
+
_dispatchClosedEvent() {
|
244
|
+
dispatch("hw-combobox:closed", { target: this.element, detail: this._eventableDetails });
|
245
|
+
}
|
246
|
+
|
247
|
+
get _eventableDetails() {
|
248
|
+
return {
|
241
249
|
value: this.hiddenFieldTarget.value,
|
242
250
|
display: this._fullQuery,
|
243
251
|
query: this._typedQuery,
|
244
252
|
fieldName: this.hiddenFieldTarget.name,
|
245
|
-
isValid: this._valueIsValid
|
246
|
-
|
247
|
-
};
|
248
|
-
|
249
|
-
dispatch("hw-combobox:selection", { target: this.element, detail });
|
253
|
+
isValid: this._valueIsValid
|
254
|
+
}
|
250
255
|
}
|
251
256
|
};
|
252
257
|
|
@@ -1099,6 +1104,7 @@ Combobox.Toggle = Base => class extends Base {
|
|
1099
1104
|
if (this._isOpen) {
|
1100
1105
|
this._lockInSelection();
|
1101
1106
|
this.expandedValue = false;
|
1107
|
+
this._dispatchClosedEvent();
|
1102
1108
|
}
|
1103
1109
|
}
|
1104
1110
|
|
@@ -241,16 +241,21 @@
|
|
241
241
|
|
242
242
|
Combobox.Events = Base => class extends Base {
|
243
243
|
_dispatchSelectionEvent({ isNew }) {
|
244
|
-
|
244
|
+
dispatch("hw-combobox:selection", { target: this.element, detail: { ...this._eventableDetails, isNew } });
|
245
|
+
}
|
246
|
+
|
247
|
+
_dispatchClosedEvent() {
|
248
|
+
dispatch("hw-combobox:closed", { target: this.element, detail: this._eventableDetails });
|
249
|
+
}
|
250
|
+
|
251
|
+
get _eventableDetails() {
|
252
|
+
return {
|
245
253
|
value: this.hiddenFieldTarget.value,
|
246
254
|
display: this._fullQuery,
|
247
255
|
query: this._typedQuery,
|
248
256
|
fieldName: this.hiddenFieldTarget.name,
|
249
|
-
isValid: this._valueIsValid
|
250
|
-
|
251
|
-
};
|
252
|
-
|
253
|
-
dispatch("hw-combobox:selection", { target: this.element, detail });
|
257
|
+
isValid: this._valueIsValid
|
258
|
+
}
|
254
259
|
}
|
255
260
|
};
|
256
261
|
|
@@ -1103,6 +1108,7 @@
|
|
1103
1108
|
if (this._isOpen) {
|
1104
1109
|
this._lockInSelection();
|
1105
1110
|
this.expandedValue = false;
|
1111
|
+
this._dispatchClosedEvent();
|
1106
1112
|
}
|
1107
1113
|
}
|
1108
1114
|
|
@@ -3,15 +3,20 @@ import { dispatch } from "hw_combobox/helpers"
|
|
3
3
|
|
4
4
|
Combobox.Events = Base => class extends Base {
|
5
5
|
_dispatchSelectionEvent({ isNew }) {
|
6
|
-
|
6
|
+
dispatch("hw-combobox:selection", { target: this.element, detail: { ...this._eventableDetails, isNew } })
|
7
|
+
}
|
8
|
+
|
9
|
+
_dispatchClosedEvent() {
|
10
|
+
dispatch("hw-combobox:closed", { target: this.element, detail: this._eventableDetails })
|
11
|
+
}
|
12
|
+
|
13
|
+
get _eventableDetails() {
|
14
|
+
return {
|
7
15
|
value: this.hiddenFieldTarget.value,
|
8
16
|
display: this._fullQuery,
|
9
17
|
query: this._typedQuery,
|
10
18
|
fieldName: this.hiddenFieldTarget.name,
|
11
|
-
isValid: this._valueIsValid
|
12
|
-
isNew: isNew
|
19
|
+
isValid: this._valueIsValid
|
13
20
|
}
|
14
|
-
|
15
|
-
dispatch("hw-combobox:selection", { target: this.element, detail })
|
16
21
|
}
|
17
22
|
}
|
@@ -9,8 +9,8 @@ module HotwireCombobox
|
|
9
9
|
|
10
10
|
unless HotwireCombobox.bypass_convenience_methods?
|
11
11
|
module FormBuilderExtensions
|
12
|
-
def combobox(*args, **kwargs)
|
13
|
-
@template.hw_combobox_tag(*args, **kwargs.merge(form: self))
|
12
|
+
def combobox(*args, **kwargs, &block)
|
13
|
+
@template.hw_combobox_tag(*args, **kwargs.merge(form: self), &block)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -26,11 +26,9 @@ module HotwireCombobox
|
|
26
26
|
if options.first.is_a? HotwireCombobox::Listbox::Option
|
27
27
|
options
|
28
28
|
else
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
options.unshift(hw_blank_option(include_blank)) if include_blank.present?
|
33
|
-
end
|
29
|
+
opts = hw_parse_combobox_options options, render_in_proc: hw_render_in_proc(render_in), **methods.merge(display: display)
|
30
|
+
opts.unshift(hw_blank_option(include_blank)) if include_blank.present?
|
31
|
+
opts
|
34
32
|
end
|
35
33
|
end
|
36
34
|
hw_alias :hw_combobox_options
|
@@ -85,7 +83,7 @@ module HotwireCombobox
|
|
85
83
|
if include_blank.is_a? Hash
|
86
84
|
text = include_blank.delete(:text)
|
87
85
|
|
88
|
-
[ text, hw_render_in_proc(include_blank)
|
86
|
+
[ text, hw_call_render_in_proc(hw_render_in_proc(include_blank), text, display: text, value: "") ]
|
89
87
|
else
|
90
88
|
[ include_blank, include_blank ]
|
91
89
|
end
|
@@ -102,7 +100,9 @@ module HotwireCombobox
|
|
102
100
|
|
103
101
|
private
|
104
102
|
def hw_render_in_proc(render_in)
|
105
|
-
|
103
|
+
if render_in.present?
|
104
|
+
->(object, locals) { render(**render_in.reverse_merge(object: object, locals: locals)) }
|
105
|
+
end
|
106
106
|
end
|
107
107
|
|
108
108
|
def hw_extract_options_and_src(options_or_src, render_in, include_blank)
|
@@ -113,40 +113,50 @@ module HotwireCombobox
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
def hw_parse_combobox_options(options,
|
116
|
+
def hw_parse_combobox_options(options, render_in_proc: nil, **methods)
|
117
117
|
options.map do |option|
|
118
118
|
HotwireCombobox::Listbox::Option.new \
|
119
|
-
**hw_option_attrs_for(option,
|
119
|
+
**hw_option_attrs_for(option, render_in_proc: render_in_proc, **methods)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
def hw_option_attrs_for(option,
|
123
|
+
def hw_option_attrs_for(option, render_in_proc: nil, **methods)
|
124
124
|
case option
|
125
125
|
when Hash
|
126
|
-
option
|
126
|
+
option.tap do |attrs|
|
127
|
+
attrs[:content] = hw_call_render_in_proc(render_in_proc, attrs[:display], attrs) if render_in_proc
|
128
|
+
end
|
127
129
|
when String
|
128
130
|
{}.tap do |attrs|
|
129
131
|
attrs[:display] = option
|
130
132
|
attrs[:value] = option
|
131
|
-
attrs[:content] =
|
133
|
+
attrs[:content] = hw_call_render_in_proc(render_in_proc, attrs[:display], attrs) if render_in_proc
|
132
134
|
end
|
133
135
|
when Array
|
134
136
|
{}.tap do |attrs|
|
135
137
|
attrs[:display] = option.first
|
136
138
|
attrs[:value] = option.last
|
137
|
-
attrs[:content] =
|
139
|
+
attrs[:content] = hw_call_render_in_proc(render_in_proc, attrs[:display], attrs) if render_in_proc
|
138
140
|
end
|
139
141
|
else
|
140
142
|
{}.tap do |attrs|
|
141
|
-
attrs[:value] = hw_call_method_or_proc(option, methods[:value] || :id)
|
142
|
-
|
143
143
|
attrs[:id] = hw_call_method_or_proc(option, methods[:id]) if methods[:id]
|
144
144
|
attrs[:display] = hw_call_method_or_proc(option, methods[:display]) if methods[:display]
|
145
|
-
attrs[:
|
145
|
+
attrs[:value] = hw_call_method_or_proc(option, methods[:value] || :id)
|
146
|
+
|
147
|
+
if render_in_proc
|
148
|
+
attrs[:content] = hw_call_render_in_proc(render_in_proc, option, attrs)
|
149
|
+
elsif methods[:content]
|
150
|
+
attrs[:content] = hw_call_method_or_proc(option, methods[:content])
|
151
|
+
end
|
146
152
|
end
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
156
|
+
def hw_call_render_in_proc(render_in_proc, object, attrs)
|
157
|
+
render_in_proc.(object, combobox_display: attrs[:display], combobox_value: attrs[:value])
|
158
|
+
end
|
159
|
+
|
150
160
|
def hw_call_method_or_proc(object, method_or_proc)
|
151
161
|
if method_or_proc.is_a? Proc
|
152
162
|
method_or_proc.call object
|
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.42
|
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-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|