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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f77cb8280bf5c4483c3d38f73628f8e17f7492f73684d4ced437f903198189b
4
- data.tar.gz: 1baff77c13609cfc3c98770dbc7a8a6a2d67a2166ff04beca10e64aa7405e68c
3
+ metadata.gz: 3268b609f1b4c08af63c6bc791459345dbbdfb1afa3a1e9974569392e27b417a
4
+ data.tar.gz: 525a23db2449fd8867d83fb7b1647d75d6d194a4791971fec0cb55de48a2d1c8
5
5
  SHA512:
6
- metadata.gz: f184de3a7114166e60dd758b6f489191d9e9b469998c2deacb3446ad79992ddbc661f92dd492366acf718e77072b386b7da39c9d11022fac75b31ebfb9257f1e
7
- data.tar.gz: c82e8749636458398cf8d9204cca3986bbff17785504833e18b28d87367209b1e67e99e98d2da07471a07429a8648d0237359d002dc480809190b945f6ea0a01
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">&#8964;</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">&times;</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">&times;</span>
59
62
  </button>
60
63
 
61
64
  <% if tooltip_enabled %>
@@ -2,6 +2,7 @@ module AdvancedSelect
2
2
  class ClassMap
3
3
  DEFAULTS = {
4
4
  root: "ui-advanced-select",
5
+ disabled: "ui-advanced-select-disabled",
5
6
  trigger: "ui-advanced-select-trigger",
6
7
  summary: "ui-advanced-select-summary",
7
8
  placeholder: "ui-advanced-select-placeholder",
@@ -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,
@@ -1,3 +1,3 @@
1
1
  module AdvancedSelect
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: advanced_select
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mehmet Celik