hotwire_combobox 0.1.33 → 0.1.35
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 +0 -4
- data/app/assets/javascripts/controllers/hw_combobox_controller.js +10 -4
- data/app/assets/javascripts/hw_combobox/helpers.js +1 -7
- data/app/assets/javascripts/hw_combobox/models/combobox/autocomplete.js +6 -6
- data/app/assets/javascripts/hw_combobox/models/combobox/dialog.js +2 -2
- data/app/assets/javascripts/hw_combobox/models/combobox/filtering.js +14 -16
- data/app/assets/javascripts/hw_combobox/models/combobox/selection.js +15 -12
- data/app/assets/javascripts/hw_combobox/models/combobox/toggle.js +0 -4
- data/app/presenters/hotwire_combobox/component.rb +1 -1
- data/app/presenters/hotwire_combobox/listbox/option.rb +6 -6
- data/app/views/hotwire_combobox/_pagination.html.erb +1 -1
- 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: 4b9f936869948e6767d3cdf4f02f226bfe4c3954d57172b37388239884b69ae6
|
4
|
+
data.tar.gz: b5495f56d66183c5ebb6c54a6a8e5278391df921f304b36b9da9ffb3bf752576
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bb2f124171055bc2b46c7584f31b3ae6426979dd9485645e8364bef559aa86cfa905f62f0db47e79d48db98f42d422b9c8fd9f342729e7da4704385d8544e3b
|
7
|
+
data.tar.gz: 27e49fa1cfd828d23f7dcf82b75a2ba7d7edc4adc8fcff88d35cab8cc41e666f39dffb82209c68740e8b4d9ec9236b1db3513e7c2952cf80cf6f96dc7608a39e
|
data/README.md
CHANGED
@@ -22,10 +22,6 @@ Only apps that use importmaps are currently supported. Suport for other JS solut
|
|
22
22
|
|
23
23
|
## Docs
|
24
24
|
|
25
|
-
<p align="center">
|
26
|
-
<img src="docs/assets/images/docs-preview.png" height=500>
|
27
|
-
</p>
|
28
|
-
|
29
25
|
Visit [the docs site](https://hotwirecombobox.com/) for a demo and detailed documentation.
|
30
26
|
If the site is down, you can run the docs locally by cloning [the docs repo](https://github.com/josefarias/hotwire_combobox_docs).
|
31
27
|
|
@@ -29,10 +29,10 @@ export default class HwComboboxController extends Concerns(...concerns) {
|
|
29
29
|
"dialogCombobox",
|
30
30
|
"dialogFocusTrap",
|
31
31
|
"dialogListbox",
|
32
|
+
"endOfOptionsStream",
|
32
33
|
"handle",
|
33
34
|
"hiddenField",
|
34
|
-
"listbox"
|
35
|
-
"paginationFrame"
|
35
|
+
"listbox"
|
36
36
|
]
|
37
37
|
|
38
38
|
static values = {
|
@@ -70,7 +70,13 @@ export default class HwComboboxController extends Concerns(...concerns) {
|
|
70
70
|
}
|
71
71
|
}
|
72
72
|
|
73
|
-
|
74
|
-
|
73
|
+
endOfOptionsStreamTargetConnected(element) {
|
74
|
+
const inputType = element.dataset.inputType
|
75
|
+
|
76
|
+
if (inputType && inputType !== "hw:ensureSelection") {
|
77
|
+
this._commitFilter({ inputType })
|
78
|
+
} else {
|
79
|
+
this._preselectOption()
|
80
|
+
}
|
75
81
|
}
|
76
82
|
}
|
@@ -1,5 +1,3 @@
|
|
1
|
-
export const nullEvent = new Event("NULL")
|
2
|
-
|
3
1
|
export function Concerns(Base, ...mixins) {
|
4
2
|
return mixins.reduce((accumulator, current) => current(accumulator), Base)
|
5
3
|
}
|
@@ -39,11 +37,7 @@ export function startsWith(string, substring) {
|
|
39
37
|
return string.toLowerCase().startsWith(substring.toLowerCase())
|
40
38
|
}
|
41
39
|
|
42
|
-
export function
|
43
|
-
return new Promise(requestAnimationFrame)
|
44
|
-
}
|
45
|
-
|
46
|
-
export function debounce(fn, delay = 150) {
|
40
|
+
export function debounce(fn, delay = 300) {
|
47
41
|
let timeoutId = null
|
48
42
|
|
49
43
|
return (...args) => {
|
@@ -8,17 +8,17 @@ Combobox.Autocomplete = Base => class extends Base {
|
|
8
8
|
}
|
9
9
|
}
|
10
10
|
|
11
|
-
|
11
|
+
_autocompleteWith(option, { force }) {
|
12
12
|
if (!this._autocompletesInline && !force) return
|
13
13
|
|
14
|
-
const typedValue = this.
|
14
|
+
const typedValue = this._query
|
15
15
|
const autocompletedValue = option.getAttribute(this.autocompletableAttributeValue)
|
16
16
|
|
17
17
|
if (force) {
|
18
|
-
this.
|
18
|
+
this._query = autocompletedValue
|
19
19
|
this._actingCombobox.setSelectionRange(autocompletedValue.length, autocompletedValue.length)
|
20
20
|
} else if (startsWith(autocompletedValue, typedValue)) {
|
21
|
-
this.
|
21
|
+
this._query = autocompletedValue
|
22
22
|
this._actingCombobox.setSelectionRange(typedValue.length, autocompletedValue.length)
|
23
23
|
}
|
24
24
|
}
|
@@ -30,14 +30,14 @@ Combobox.Autocomplete = Base => class extends Base {
|
|
30
30
|
}
|
31
31
|
|
32
32
|
get _isExactAutocompleteMatch() {
|
33
|
-
return this._immediatelyAutocompletableValue === this.
|
33
|
+
return this._immediatelyAutocompletableValue === this._query
|
34
34
|
}
|
35
35
|
|
36
36
|
// All `_isExactAutocompleteMatch` matches are `_isPartialAutocompleteMatch` matches
|
37
37
|
// but not all `_isPartialAutocompleteMatch` matches are `_isExactAutocompleteMatch` matches.
|
38
38
|
get _isPartialAutocompleteMatch() {
|
39
39
|
return !!this._immediatelyAutocompletableValue &&
|
40
|
-
startsWith(this._immediatelyAutocompletableValue, this.
|
40
|
+
startsWith(this._immediatelyAutocompletableValue, this._query)
|
41
41
|
}
|
42
42
|
|
43
43
|
get _autocompletesList() {
|
@@ -14,7 +14,7 @@ Combobox.Dialog = Base => class extends Base {
|
|
14
14
|
}
|
15
15
|
|
16
16
|
_moveArtifactsToDialog() {
|
17
|
-
this.dialogComboboxTarget.value = this.
|
17
|
+
this.dialogComboboxTarget.value = this._query
|
18
18
|
|
19
19
|
this._actingCombobox = this.dialogComboboxTarget
|
20
20
|
this._actingListbox = this.dialogListboxTarget
|
@@ -23,7 +23,7 @@ Combobox.Dialog = Base => class extends Base {
|
|
23
23
|
}
|
24
24
|
|
25
25
|
_moveArtifactsInline() {
|
26
|
-
this.comboboxTarget.value = this.
|
26
|
+
this.comboboxTarget.value = this._query
|
27
27
|
|
28
28
|
this._actingCombobox = this.comboboxTarget
|
29
29
|
this._actingListbox = this.listboxTarget
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
import Combobox from "hw_combobox/models/combobox/base"
|
3
|
-
import { applyFilter,
|
3
|
+
import { applyFilter, debounce, isDeleteEvent } from "hw_combobox/helpers"
|
4
4
|
import { get } from "hw_combobox/vendor/requestjs"
|
5
5
|
|
6
6
|
Combobox.Filtering = Base => class extends Base {
|
@@ -21,20 +21,13 @@ Combobox.Filtering = Base => class extends Base {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
async _filterAsync(event) {
|
24
|
-
const
|
25
|
-
|
26
|
-
await get(this.asyncSrcValue, { responseKind: "turbo-stream", query: { q } })
|
27
|
-
|
28
|
-
this._afterTurboStreamRender(() => this._commitFilter(event))
|
24
|
+
const query = { q: this._query, input_type: event.inputType }
|
25
|
+
await get(this.asyncSrcValue, { responseKind: "turbo-stream", query })
|
29
26
|
}
|
30
27
|
|
31
28
|
_filterSync(event) {
|
32
|
-
const query = this._actingCombobox.value.trim()
|
33
|
-
|
34
29
|
this.open()
|
35
|
-
|
36
|
-
this._allOptionElements.forEach(applyFilter(query, { matching: this.filterableAttributeValue }))
|
37
|
-
|
30
|
+
this._allOptionElements.forEach(applyFilter(this._query, { matching: this.filterableAttributeValue }))
|
38
31
|
this._commitFilter(event)
|
39
32
|
}
|
40
33
|
|
@@ -48,12 +41,17 @@ Combobox.Filtering = Base => class extends Base {
|
|
48
41
|
}
|
49
42
|
}
|
50
43
|
|
51
|
-
|
52
|
-
|
53
|
-
callback()
|
44
|
+
get _isQueried() {
|
45
|
+
return this._query.length > 0
|
54
46
|
}
|
55
47
|
|
56
|
-
|
57
|
-
|
48
|
+
// Consider +_query+ will contain the full autocompleted value
|
49
|
+
// after a certain point in the call chain.
|
50
|
+
get _query() {
|
51
|
+
return this._actingCombobox.value
|
52
|
+
}
|
53
|
+
|
54
|
+
set _query(value) {
|
55
|
+
this._actingCombobox.value = value
|
58
56
|
}
|
59
57
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Combobox from "hw_combobox/models/combobox/base"
|
2
|
-
import { wrapAroundAccess
|
2
|
+
import { wrapAroundAccess } from "hw_combobox/helpers"
|
3
3
|
|
4
4
|
Combobox.Selection = Base => class extends Base {
|
5
5
|
selectOption(event) {
|
@@ -10,7 +10,7 @@ Combobox.Selection = Base => class extends Base {
|
|
10
10
|
|
11
11
|
_connectSelection() {
|
12
12
|
if (this.hasPrefilledDisplayValue) {
|
13
|
-
this.
|
13
|
+
this._query = this.prefilledDisplayValue
|
14
14
|
}
|
15
15
|
}
|
16
16
|
|
@@ -19,7 +19,7 @@ Combobox.Selection = Base => class extends Base {
|
|
19
19
|
|
20
20
|
if (option) {
|
21
21
|
this._markValid()
|
22
|
-
this.
|
22
|
+
this._autocompleteWith(option, { force })
|
23
23
|
this._commitSelection(option, { selected: true })
|
24
24
|
} else {
|
25
25
|
this._markInvalid()
|
@@ -32,8 +32,6 @@ Combobox.Selection = Base => class extends Base {
|
|
32
32
|
if (selected) {
|
33
33
|
this.hiddenFieldTarget.value = option.dataset.value
|
34
34
|
option.scrollIntoView({ block: "nearest" })
|
35
|
-
} else {
|
36
|
-
this.hiddenFieldTarget.value = null
|
37
35
|
}
|
38
36
|
}
|
39
37
|
|
@@ -48,11 +46,12 @@ Combobox.Selection = Base => class extends Base {
|
|
48
46
|
_deselect() {
|
49
47
|
const option = this._selectedOptionElement
|
50
48
|
if (option) this._commitSelection(option, { selected: false })
|
49
|
+
this.hiddenFieldTarget.value = null
|
51
50
|
}
|
52
51
|
|
53
52
|
_selectNew() {
|
54
53
|
this._resetOptions()
|
55
|
-
this.hiddenFieldTarget.value = this.
|
54
|
+
this.hiddenFieldTarget.value = this._query
|
56
55
|
this.hiddenFieldTarget.name = this.nameWhenNewValue
|
57
56
|
}
|
58
57
|
|
@@ -71,10 +70,10 @@ Combobox.Selection = Base => class extends Base {
|
|
71
70
|
}
|
72
71
|
}
|
73
72
|
|
74
|
-
|
75
|
-
if (this.
|
76
|
-
this._select(this.
|
77
|
-
this.filter(
|
73
|
+
_ensureSelection() {
|
74
|
+
if (this._shouldEnsureSelection) {
|
75
|
+
this._select(this._ensurableOption, { force: true })
|
76
|
+
this.filter({ inputType: "hw:ensureSelection" })
|
78
77
|
}
|
79
78
|
}
|
80
79
|
|
@@ -82,7 +81,11 @@ Combobox.Selection = Base => class extends Base {
|
|
82
81
|
return this.hiddenFieldTarget.value && !this._selectedOptionElement
|
83
82
|
}
|
84
83
|
|
85
|
-
get
|
86
|
-
return this._isQueried && !!this.
|
84
|
+
get _shouldEnsureSelection() {
|
85
|
+
return this._isQueried && !!this._ensurableOption && !this._isNewOptionWithPotentialMatches
|
86
|
+
}
|
87
|
+
|
88
|
+
get _ensurableOption() {
|
89
|
+
return this._selectedOptionElement || this._visibleOptionElements[0]
|
87
90
|
}
|
88
91
|
}
|
@@ -50,10 +50,6 @@ Combobox.Toggle = Base => class extends Base {
|
|
50
50
|
return clientX >= left && clientX <= right && clientY >= top && clientY <= bottom
|
51
51
|
}
|
52
52
|
|
53
|
-
_ensureSelection() {
|
54
|
-
this._selectFuzzyMatch()
|
55
|
-
}
|
56
|
-
|
57
53
|
_openByFocusing() {
|
58
54
|
this._actingCombobox.focus()
|
59
55
|
}
|
@@ -171,7 +171,7 @@ class HotwireCombobox::Component
|
|
171
171
|
if async_src && associated_object
|
172
172
|
associated_object.to_combobox_display
|
173
173
|
elsif hidden_field_value
|
174
|
-
options.find { |option| option.value == hidden_field_value }&.
|
174
|
+
options.find { |option| option.value == hidden_field_value }&.autocompletable_as
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
@@ -11,8 +11,8 @@ class HotwireCombobox::Listbox::Option
|
|
11
11
|
option.try(:value) || option.id
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
option.try(:
|
14
|
+
def autocompletable_as
|
15
|
+
option.try(:autocompletable_as) || option.try(:display)
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -42,11 +42,11 @@ class HotwireCombobox::Listbox::Option
|
|
42
42
|
}
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
option.try(:
|
45
|
+
def content
|
46
|
+
option.try(:content) || option.try(:display)
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
50
|
-
option.try(:
|
49
|
+
def filterable_as
|
50
|
+
option.try(:filterable_as) || option.try(:display)
|
51
51
|
end
|
52
52
|
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.35
|
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-02-
|
11
|
+
date: 2024-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|