advanced_select 0.1.9 → 0.1.10
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 +47 -0
- data/app/assets/stylesheets/advanced_select/advanced_select.css +10 -0
- data/app/javascript/advanced_select/advanced_select_controller.js +41 -1
- data/app/views/advanced_select/_select.html.erb +8 -5
- data/lib/advanced_select/class_map.rb +1 -0
- data/lib/advanced_select/helper.rb +2 -1
- data/lib/advanced_select/version.rb +1 -1
- data/lib/generators/advanced_select/install/templates/advanced_select.css +10 -0
- data/lib/generators/advanced_select/install/templates/advanced_select_controller.js +41 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3268b609f1b4c08af63c6bc791459345dbbdfb1afa3a1e9974569392e27b417a
|
|
4
|
+
data.tar.gz: 525a23db2449fd8867d83fb7b1647d75d6d194a4791971fec0cb55de48a2d1c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f66187ab2d1914f3de4c933fecbf3b9237684b4c8d911de1582426002f6d099820181401137d6c0896d3cdb99b1af38ecf12acbdd8dd29ff7aac6af965e2c587
|
|
7
|
+
data.tar.gz: 3a240d713742fcd791541b4272e499d6036d8ada44eb8697529628d9b1ceb9092678362bf435bcd25bc8b33d95e6f9a95d4a752e23b9b587fe814b738ddb9cd6
|
data/README.md
CHANGED
|
@@ -23,6 +23,7 @@ AdvancedSelect is a small Rails engine for rendering an advanced select input wi
|
|
|
23
23
|
- [Custom Option Content](#custom-option-content)
|
|
24
24
|
- [Option Contract](#option-contract)
|
|
25
25
|
- [Events](#events)
|
|
26
|
+
- [Disabled State](#disabled-state)
|
|
26
27
|
- [API Reference](#api-reference)
|
|
27
28
|
- [Local Development](#local-development)
|
|
28
29
|
- [i18n](#i18n)
|
|
@@ -791,6 +792,49 @@ const select = application.getControllerForElementAndIdentifier(element, "advanc
|
|
|
791
792
|
select.currentValue // => ["3", "7"]
|
|
792
793
|
```
|
|
793
794
|
|
|
795
|
+
### Disabled State
|
|
796
|
+
|
|
797
|
+
Pass `disabled: true` to lock a field. It still renders its current selection —
|
|
798
|
+
the point is to show the value, not to hide it — but it cannot be opened,
|
|
799
|
+
searched, or cleared, and its value is **left out of the form**:
|
|
800
|
+
|
|
801
|
+
```erb
|
|
802
|
+
<%= advanced_select_tag(
|
|
803
|
+
"record[item_id]",
|
|
804
|
+
id: "record_item_id",
|
|
805
|
+
selected: selected_option,
|
|
806
|
+
options: options,
|
|
807
|
+
placeholder: "Choose an item",
|
|
808
|
+
disabled: true
|
|
809
|
+
) %>
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
This matches a native `<select disabled>`: the browser omits a disabled field
|
|
813
|
+
from the submitted params, so an update never writes a value the user was not
|
|
814
|
+
allowed to change.
|
|
815
|
+
|
|
816
|
+
The trigger carries the `disabled` attribute, so mouse and keyboard are both
|
|
817
|
+
blocked by the browser rather than by CSS alone. The root element takes the
|
|
818
|
+
`disabled` class from the class map.
|
|
819
|
+
|
|
820
|
+
To toggle the state after render — from a Stimulus controller, or from a Turbo
|
|
821
|
+
Stream that flips the attribute — set the value on the root element:
|
|
822
|
+
|
|
823
|
+
```js
|
|
824
|
+
element.dataset.advancedSelectDisabledValue = "true"
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
The controller reacts on its own: it disables the hidden inputs, applies the
|
|
828
|
+
class, hides the clear control, and closes the dropdown if it happens to be
|
|
829
|
+
open. The same thing is available as a method:
|
|
830
|
+
|
|
831
|
+
```js
|
|
832
|
+
const select = application.getControllerForElementAndIdentifier(element, "advanced-select")
|
|
833
|
+
|
|
834
|
+
select.disable()
|
|
835
|
+
select.enable()
|
|
836
|
+
```
|
|
837
|
+
|
|
794
838
|
### API Reference
|
|
795
839
|
|
|
796
840
|
`advanced_select_tag`:
|
|
@@ -806,6 +850,7 @@ advanced_select_tag(
|
|
|
806
850
|
multiple: false,
|
|
807
851
|
searchable: true,
|
|
808
852
|
add_mode: false,
|
|
853
|
+
disabled: false,
|
|
809
854
|
dependent_fields: {},
|
|
810
855
|
include_hidden: true,
|
|
811
856
|
auto_select_single: true,
|
|
@@ -823,6 +868,8 @@ advanced_select_tag(
|
|
|
823
868
|
|
|
824
869
|
`tooltip:` / `tooltip_partial:` enable an optional hover tooltip on the trigger (see [Selection Tooltip](#selection-tooltip)).
|
|
825
870
|
|
|
871
|
+
`disabled:` locks the field (see [Disabled State](#disabled-state)).
|
|
872
|
+
|
|
826
873
|
`advanced_select_options_tag`:
|
|
827
874
|
|
|
828
875
|
```ruby
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
display: none !important;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
.ui-advanced-select-disabled .ui-advanced-select-trigger {
|
|
15
|
+
background: #f3f4f6;
|
|
16
|
+
color: #6b7280;
|
|
17
|
+
cursor: not-allowed;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ui-advanced-select-disabled .ui-advanced-select-clear {
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
.ui-advanced-select-trigger {
|
|
15
25
|
align-items: center;
|
|
16
26
|
background: #ffffff;
|
|
@@ -8,6 +8,7 @@ export default class extends Controller {
|
|
|
8
8
|
autoSelectSingle: { type: Boolean, default: true },
|
|
9
9
|
delay: { type: Number, default: 200 },
|
|
10
10
|
dependentFields: Object,
|
|
11
|
+
disabled: Boolean,
|
|
11
12
|
eager: { type: Boolean, default: true },
|
|
12
13
|
emptyText: String,
|
|
13
14
|
errorText: String,
|
|
@@ -65,7 +66,40 @@ export default class extends Controller {
|
|
|
65
66
|
this.expanded ? this.close() : this.open()
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
disable() {
|
|
70
|
+
this.disabledValue = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
enable() {
|
|
74
|
+
this.disabledValue = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
disabledValueChanged() {
|
|
78
|
+
if (!this.hasTriggerTarget) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const disabled = this.disabledValue
|
|
83
|
+
const classes = this.classList(this.element.dataset.advancedSelectDisabledClass || "ui-advanced-select-disabled")
|
|
84
|
+
|
|
85
|
+
this.triggerTarget.disabled = disabled
|
|
86
|
+
this.hiddenFieldsTarget.querySelectorAll("input").forEach((input) => { input.disabled = disabled })
|
|
87
|
+
this.clearTarget.classList.toggle("hidden", disabled || this.selectedValue.length === 0)
|
|
88
|
+
|
|
89
|
+
if (classes.length) {
|
|
90
|
+
disabled ? this.element.classList.add(...classes) : this.element.classList.remove(...classes)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (disabled && this.expanded) {
|
|
94
|
+
this.close()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
68
98
|
open() {
|
|
99
|
+
if (this.disabledValue) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
69
103
|
this.hideTooltip(true)
|
|
70
104
|
this.dropdownTarget.classList.remove("hidden")
|
|
71
105
|
this.triggerTarget.setAttribute("aria-expanded", "true")
|
|
@@ -120,6 +154,11 @@ export default class extends Controller {
|
|
|
120
154
|
clear(event) {
|
|
121
155
|
event.preventDefault()
|
|
122
156
|
event.stopPropagation()
|
|
157
|
+
|
|
158
|
+
if (this.disabledValue) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
123
162
|
this.selectedValue = []
|
|
124
163
|
this.renderSelection()
|
|
125
164
|
this.close()
|
|
@@ -362,7 +401,7 @@ export default class extends Controller {
|
|
|
362
401
|
this.renderTooltip()
|
|
363
402
|
this.renderOptionsState()
|
|
364
403
|
this.caretTarget.classList.toggle("hidden", this.selectedValue.length > 0)
|
|
365
|
-
this.clearTarget.classList.toggle("hidden", this.selectedValue.length === 0)
|
|
404
|
+
this.clearTarget.classList.toggle("hidden", this.disabledValue || this.selectedValue.length === 0)
|
|
366
405
|
this.dispatchValueChange()
|
|
367
406
|
}
|
|
368
407
|
|
|
@@ -515,6 +554,7 @@ export default class extends Controller {
|
|
|
515
554
|
input.type = "hidden"
|
|
516
555
|
input.name = this.nameValue
|
|
517
556
|
input.value = option ? option.value || option.id : ""
|
|
557
|
+
input.disabled = this.disabledValue
|
|
518
558
|
|
|
519
559
|
if (!this.multipleValue) {
|
|
520
560
|
input.id = this.inputIdValue
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
<div class="<%= advanced_select_class(class_map, :root) %>"
|
|
1
|
+
<div class="<%= advanced_select_class(class_map, :root, (:disabled if disabled)) %>"
|
|
2
2
|
data-controller="advanced-select"
|
|
3
|
+
data-advanced-select-disabled-value="<%= disabled %>"
|
|
4
|
+
data-advanced-select-disabled-class="<%= advanced_select_state_class(class_map, :disabled) %>"
|
|
3
5
|
data-advanced-select-url-value="<%= options_url %>"
|
|
4
6
|
data-advanced-select-target-id-value="<%= target_id %>"
|
|
5
7
|
data-advanced-select-name-value="<%= name %>"
|
|
@@ -31,13 +33,13 @@
|
|
|
31
33
|
<div data-advanced-select-target="hiddenFields">
|
|
32
34
|
<% if multiple %>
|
|
33
35
|
<% if include_hidden %>
|
|
34
|
-
<%= hidden_field_tag name, "", id: nil %>
|
|
36
|
+
<%= hidden_field_tag name, "", id: nil, disabled: disabled %>
|
|
35
37
|
<% end %>
|
|
36
38
|
<% selected_options.each do |option| %>
|
|
37
|
-
<%= hidden_field_tag name, option.fetch(:value, option.fetch(:id)) %>
|
|
39
|
+
<%= hidden_field_tag name, option.fetch(:value, option.fetch(:id)), disabled: disabled %>
|
|
38
40
|
<% end %>
|
|
39
41
|
<% else %>
|
|
40
|
-
<%= hidden_field_tag name, selected_options.first&.fetch(:value, selected_options.first&.fetch(:id)), id: id %>
|
|
42
|
+
<%= hidden_field_tag name, selected_options.first&.fetch(:value, selected_options.first&.fetch(:id)), id: id, disabled: disabled %>
|
|
41
43
|
<% end %>
|
|
42
44
|
</div>
|
|
43
45
|
|
|
@@ -49,13 +51,14 @@
|
|
|
49
51
|
aria-haspopup="listbox"
|
|
50
52
|
aria-expanded="false"
|
|
51
53
|
aria-controls="<%= "#{id}_dropdown" %>"
|
|
54
|
+
<%= "disabled" if disabled %>
|
|
52
55
|
data-advanced-select-target="trigger"
|
|
53
56
|
data-action="advanced-select#toggle keydown->advanced-select#keydown<%= " mouseenter->advanced-select#showTooltip mouseleave->advanced-select#hideTooltip" if tooltip_enabled %>">
|
|
54
57
|
<span id="<%= "#{id}_summary" %>" class="<%= advanced_select_class(class_map, :summary) %>" data-advanced-select-target="summary">
|
|
55
58
|
<%= render partial: "advanced_select/summary", locals: { selected_options: selected_options, multiple: multiple, placeholder: placeholder, summary_mode: summary_mode, class_map: class_map } %>
|
|
56
59
|
</span>
|
|
57
60
|
<span id="<%= "#{id}_caret" %>" class="<%= [advanced_select_class(class_map, :caret), ("hidden" if selected_options.any?)].compact.join(" ") %>" data-advanced-select-target="caret">⌄</span>
|
|
58
|
-
<span id="<%= "#{id}_clear" %>" class="<%= [advanced_select_class(class_map, :clear), ("hidden" if selected_options.empty?)].compact.join(" ") %>" data-advanced-select-target="clear" data-action="click->advanced-select#clear">×</span>
|
|
61
|
+
<span id="<%= "#{id}_clear" %>" class="<%= [advanced_select_class(class_map, :clear), ("hidden" if disabled || selected_options.empty?)].compact.join(" ") %>" data-advanced-select-target="clear" data-action="click->advanced-select#clear">×</span>
|
|
59
62
|
</button>
|
|
60
63
|
|
|
61
64
|
<% if tooltip_enabled %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module AdvancedSelect
|
|
2
2
|
module Helper
|
|
3
|
-
def advanced_select_tag(name, id:, selected:, options:, placeholder:, options_url: nil, multiple: false, searchable: true, add_mode: false, dependent_fields: {}, include_hidden: true, auto_select_single: true, eager: true, summary_mode: :tokens, tooltip: false, tooltip_partial: nil, option_content_partial: nil, classes: {}, append_classes: {})
|
|
3
|
+
def advanced_select_tag(name, id:, selected:, options:, placeholder:, options_url: nil, multiple: false, searchable: true, add_mode: false, disabled: false, dependent_fields: {}, include_hidden: true, auto_select_single: true, eager: true, summary_mode: :tokens, tooltip: false, tooltip_partial: nil, option_content_partial: nil, classes: {}, append_classes: {})
|
|
4
4
|
selected_options = advanced_select_selected_options(selected)
|
|
5
5
|
class_map = advanced_select_class_map(classes, append_classes)
|
|
6
6
|
|
|
@@ -14,6 +14,7 @@ module AdvancedSelect
|
|
|
14
14
|
multiple: multiple,
|
|
15
15
|
searchable: searchable,
|
|
16
16
|
add_mode: add_mode,
|
|
17
|
+
disabled: disabled,
|
|
17
18
|
dependent_fields: dependent_fields,
|
|
18
19
|
include_hidden: include_hidden,
|
|
19
20
|
auto_select_single: auto_select_single,
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
display: none !important;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
.ui-advanced-select-disabled .ui-advanced-select-trigger {
|
|
15
|
+
background: #f3f4f6;
|
|
16
|
+
color: #6b7280;
|
|
17
|
+
cursor: not-allowed;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ui-advanced-select-disabled .ui-advanced-select-clear {
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
.ui-advanced-select-trigger {
|
|
15
25
|
align-items: center;
|
|
16
26
|
background: #ffffff;
|
|
@@ -8,6 +8,7 @@ export default class extends Controller {
|
|
|
8
8
|
autoSelectSingle: { type: Boolean, default: true },
|
|
9
9
|
delay: { type: Number, default: 200 },
|
|
10
10
|
dependentFields: Object,
|
|
11
|
+
disabled: Boolean,
|
|
11
12
|
eager: { type: Boolean, default: true },
|
|
12
13
|
emptyText: String,
|
|
13
14
|
errorText: String,
|
|
@@ -65,7 +66,40 @@ export default class extends Controller {
|
|
|
65
66
|
this.expanded ? this.close() : this.open()
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
disable() {
|
|
70
|
+
this.disabledValue = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
enable() {
|
|
74
|
+
this.disabledValue = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
disabledValueChanged() {
|
|
78
|
+
if (!this.hasTriggerTarget) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const disabled = this.disabledValue
|
|
83
|
+
const classes = this.classList(this.element.dataset.advancedSelectDisabledClass || "ui-advanced-select-disabled")
|
|
84
|
+
|
|
85
|
+
this.triggerTarget.disabled = disabled
|
|
86
|
+
this.hiddenFieldsTarget.querySelectorAll("input").forEach((input) => { input.disabled = disabled })
|
|
87
|
+
this.clearTarget.classList.toggle("hidden", disabled || this.selectedValue.length === 0)
|
|
88
|
+
|
|
89
|
+
if (classes.length) {
|
|
90
|
+
disabled ? this.element.classList.add(...classes) : this.element.classList.remove(...classes)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (disabled && this.expanded) {
|
|
94
|
+
this.close()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
68
98
|
open() {
|
|
99
|
+
if (this.disabledValue) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
69
103
|
this.hideTooltip(true)
|
|
70
104
|
this.dropdownTarget.classList.remove("hidden")
|
|
71
105
|
this.triggerTarget.setAttribute("aria-expanded", "true")
|
|
@@ -120,6 +154,11 @@ export default class extends Controller {
|
|
|
120
154
|
clear(event) {
|
|
121
155
|
event.preventDefault()
|
|
122
156
|
event.stopPropagation()
|
|
157
|
+
|
|
158
|
+
if (this.disabledValue) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
123
162
|
this.selectedValue = []
|
|
124
163
|
this.renderSelection()
|
|
125
164
|
this.close()
|
|
@@ -362,7 +401,7 @@ export default class extends Controller {
|
|
|
362
401
|
this.renderTooltip()
|
|
363
402
|
this.renderOptionsState()
|
|
364
403
|
this.caretTarget.classList.toggle("hidden", this.selectedValue.length > 0)
|
|
365
|
-
this.clearTarget.classList.toggle("hidden", this.selectedValue.length === 0)
|
|
404
|
+
this.clearTarget.classList.toggle("hidden", this.disabledValue || this.selectedValue.length === 0)
|
|
366
405
|
this.dispatchValueChange()
|
|
367
406
|
}
|
|
368
407
|
|
|
@@ -515,6 +554,7 @@ export default class extends Controller {
|
|
|
515
554
|
input.type = "hidden"
|
|
516
555
|
input.name = this.nameValue
|
|
517
556
|
input.value = option ? option.value || option.id : ""
|
|
557
|
+
input.disabled = this.disabledValue
|
|
518
558
|
|
|
519
559
|
if (!this.multipleValue) {
|
|
520
560
|
input.id = this.inputIdValue
|