@unabridged/midwest 0.16.0 → 0.16.1
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.
- package/app/assets/javascript/midwest.js +192 -92
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest.css +1 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/components/midwest/form/autocomplete_component/autocomplete_component_controller.js +180 -92
- package/dist/javascript/collection/app/components/midwest/form/autocomplete_component/autocomplete_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js +12 -0
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js.map +1 -1
- package/dist/javascript/midwest.js +192 -92
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +1 -1
|
@@ -3465,10 +3465,12 @@ class FormLiveSummary extends Controller {
|
|
|
3465
3465
|
this.render();
|
|
3466
3466
|
this.form?.addEventListener("input", this.render);
|
|
3467
3467
|
this.form?.addEventListener("change", this.render);
|
|
3468
|
+
this.form?.addEventListener("midwest-autocomplete:change", this.render);
|
|
3468
3469
|
}
|
|
3469
3470
|
disconnect() {
|
|
3470
3471
|
this.form?.removeEventListener("input", this.render);
|
|
3471
3472
|
this.form?.removeEventListener("change", this.render);
|
|
3473
|
+
this.form?.removeEventListener("midwest-autocomplete:change", this.render);
|
|
3472
3474
|
}
|
|
3473
3475
|
get form() {
|
|
3474
3476
|
return this.element.closest("form");
|
|
@@ -3551,6 +3553,16 @@ class FormLiveSummary extends Controller {
|
|
|
3551
3553
|
value: element.value
|
|
3552
3554
|
});
|
|
3553
3555
|
});
|
|
3556
|
+
form.querySelectorAll(".midwest-autocomplete").forEach((ac) => {
|
|
3557
|
+
if (this.element.contains(ac))
|
|
3558
|
+
return;
|
|
3559
|
+
if (!ac.querySelector('[role="combobox"]'))
|
|
3560
|
+
return;
|
|
3561
|
+
const labelEl = ac.querySelector("label");
|
|
3562
|
+
const label = labelEl?.textContent?.trim() || this.prettifyName((ac.dataset.name ?? "").replace(/\[.*\]$/, ""));
|
|
3563
|
+
const selected = Array.from(ac.querySelectorAll(".midwest-autocomplete-tokens .value")).map((el) => el.textContent?.trim()).filter(Boolean).join(", ");
|
|
3564
|
+
fields.push({ label, value: selected || "\u2014" });
|
|
3565
|
+
});
|
|
3554
3566
|
return fields;
|
|
3555
3567
|
}
|
|
3556
3568
|
// Finds the label associated with a specific element via `for` attribute,
|
|
@@ -3820,22 +3832,75 @@ class Rating extends Controller {
|
|
|
3820
3832
|
}
|
|
3821
3833
|
|
|
3822
3834
|
class Autocomplete extends Controller {
|
|
3823
|
-
static targets = ["input", "dropdown", "list", "tokens", "
|
|
3835
|
+
static targets = ["input", "dropdown", "list", "tokens", "multipleTokenTemplate", "singleTokenTemplate", "status", "turboList", "loader"];
|
|
3824
3836
|
static values = {
|
|
3825
3837
|
options: { type: Array, default: [] },
|
|
3826
3838
|
url: { type: String, default: "" },
|
|
3827
|
-
multiple: { type: Boolean, default: true }
|
|
3839
|
+
multiple: { type: Boolean, default: true },
|
|
3840
|
+
turboFrameUrl: { type: String, default: "" }
|
|
3828
3841
|
};
|
|
3829
|
-
selectedValues = /* @__PURE__ */ new Map();
|
|
3830
3842
|
highlightedIndex = -1;
|
|
3831
3843
|
fetchAbort = null;
|
|
3844
|
+
searchTimer;
|
|
3845
|
+
// ── Named handlers ─────────────────────────────────────────────────────────
|
|
3846
|
+
// Arrow-function class properties preserve `this` and produce a stable
|
|
3847
|
+
// reference so addEventListener/removeEventListener pairs always match.
|
|
3848
|
+
onFrameLoad = () => {
|
|
3849
|
+
this.syncSelectedState();
|
|
3850
|
+
this.loading = false;
|
|
3851
|
+
this.showDropdown();
|
|
3852
|
+
};
|
|
3853
|
+
onToggle = (e) => {
|
|
3854
|
+
const opened = e.newState === "open";
|
|
3855
|
+
this.inputTarget.setAttribute("aria-expanded", String(opened));
|
|
3856
|
+
if (!opened) {
|
|
3857
|
+
this.inputTarget.removeAttribute("aria-activedescendant");
|
|
3858
|
+
this.highlightedIndex = -1;
|
|
3859
|
+
}
|
|
3860
|
+
};
|
|
3861
|
+
onFocusOut = (e) => {
|
|
3862
|
+
if (!this.element.contains(e.relatedTarget)) {
|
|
3863
|
+
this.hideDropdown();
|
|
3864
|
+
}
|
|
3865
|
+
};
|
|
3866
|
+
onListMouseDown = (e) => {
|
|
3867
|
+
const option = e.target.closest(".midwest-autocomplete-option");
|
|
3868
|
+
if (option) {
|
|
3869
|
+
e.preventDefault();
|
|
3870
|
+
this.pickItem(option);
|
|
3871
|
+
}
|
|
3872
|
+
};
|
|
3873
|
+
// ── Lifecycle ───────────────────────────────────────────────────────────────
|
|
3832
3874
|
connect() {
|
|
3833
|
-
this.
|
|
3875
|
+
this.element.addEventListener("focusout", this.onFocusOut);
|
|
3834
3876
|
}
|
|
3835
3877
|
disconnect() {
|
|
3836
3878
|
this.fetchAbort?.abort();
|
|
3879
|
+
clearTimeout(this.searchTimer);
|
|
3880
|
+
this.element.removeEventListener("focusout", this.onFocusOut);
|
|
3881
|
+
}
|
|
3882
|
+
// Target callbacks — Stimulus calls these automatically when targets connect
|
|
3883
|
+
// or disconnect, including after the initial connect(). This replaces manual
|
|
3884
|
+
// hasTurboListTarget guards and addEventListener calls inside connect().
|
|
3885
|
+
dropdownTargetConnected(el) {
|
|
3886
|
+
el.addEventListener("toggle", this.onToggle);
|
|
3887
|
+
}
|
|
3888
|
+
dropdownTargetDisconnected(el) {
|
|
3889
|
+
el.removeEventListener("toggle", this.onToggle);
|
|
3890
|
+
}
|
|
3891
|
+
listTargetConnected(el) {
|
|
3892
|
+
el.addEventListener("mousedown", this.onListMouseDown);
|
|
3893
|
+
}
|
|
3894
|
+
listTargetDisconnected(el) {
|
|
3895
|
+
el.removeEventListener("mousedown", this.onListMouseDown);
|
|
3896
|
+
}
|
|
3897
|
+
turboListTargetConnected(el) {
|
|
3898
|
+
el.addEventListener("turbo:frame-load", this.onFrameLoad);
|
|
3899
|
+
}
|
|
3900
|
+
turboListTargetDisconnected(el) {
|
|
3901
|
+
el.removeEventListener("turbo:frame-load", this.onFrameLoad);
|
|
3837
3902
|
}
|
|
3838
|
-
// ── Public actions
|
|
3903
|
+
// ── Public actions ──────────────────────────────────────────────────────────
|
|
3839
3904
|
focusInput() {
|
|
3840
3905
|
this.inputTarget.focus();
|
|
3841
3906
|
this.open();
|
|
@@ -3843,21 +3908,20 @@ class Autocomplete extends Controller {
|
|
|
3843
3908
|
open() {
|
|
3844
3909
|
if (this.dropdownTarget.matches(":popover-open"))
|
|
3845
3910
|
return;
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
this.fetch(query);
|
|
3849
|
-
} else {
|
|
3850
|
-
this.renderOptions(this.filteredOptions(query));
|
|
3851
|
-
}
|
|
3911
|
+
clearTimeout(this.searchTimer);
|
|
3912
|
+
this.resolve(this.inputTarget.value.trim());
|
|
3852
3913
|
}
|
|
3853
|
-
|
|
3914
|
+
search() {
|
|
3854
3915
|
const query = this.inputTarget.value.trim();
|
|
3855
|
-
if (this.urlValue) {
|
|
3856
|
-
await this.fetch(query);
|
|
3857
|
-
} else {
|
|
3916
|
+
if (!this.hasTurboListTarget && !this.urlValue) {
|
|
3858
3917
|
this.renderOptions(this.filteredOptions(query));
|
|
3918
|
+
return;
|
|
3859
3919
|
}
|
|
3860
|
-
this.
|
|
3920
|
+
clearTimeout(this.searchTimer);
|
|
3921
|
+
this.searchTimer = window.setTimeout(() => {
|
|
3922
|
+
this.searchTimer = void 0;
|
|
3923
|
+
this.resolve(query);
|
|
3924
|
+
}, 200);
|
|
3861
3925
|
}
|
|
3862
3926
|
navigate(event) {
|
|
3863
3927
|
switch (event.key) {
|
|
@@ -3872,6 +3936,8 @@ class Autocomplete extends Controller {
|
|
|
3872
3936
|
}
|
|
3873
3937
|
case "ArrowUp": {
|
|
3874
3938
|
event.preventDefault();
|
|
3939
|
+
if (!this.dropdownTarget.matches(":popover-open"))
|
|
3940
|
+
break;
|
|
3875
3941
|
const items = this.visibleOptions();
|
|
3876
3942
|
this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
|
|
3877
3943
|
this.syncHighlight(items);
|
|
@@ -3879,6 +3945,8 @@ class Autocomplete extends Controller {
|
|
|
3879
3945
|
}
|
|
3880
3946
|
case "Enter": {
|
|
3881
3947
|
event.preventDefault();
|
|
3948
|
+
if (!this.dropdownTarget.matches(":popover-open"))
|
|
3949
|
+
break;
|
|
3882
3950
|
const items = this.visibleOptions();
|
|
3883
3951
|
if (this.highlightedIndex >= 0 && items[this.highlightedIndex]) {
|
|
3884
3952
|
this.pickItem(items[this.highlightedIndex]);
|
|
@@ -3890,19 +3958,14 @@ class Autocomplete extends Controller {
|
|
|
3890
3958
|
break;
|
|
3891
3959
|
case "Backspace":
|
|
3892
3960
|
if (this.inputTarget.value === "" && this.multipleValue) {
|
|
3893
|
-
const
|
|
3894
|
-
|
|
3895
|
-
|
|
3961
|
+
const tokens = this.tokensTarget.querySelectorAll("[data-value]");
|
|
3962
|
+
const last = tokens[tokens.length - 1];
|
|
3963
|
+
if (last?.dataset.value)
|
|
3964
|
+
this.deselect(last.dataset.value);
|
|
3896
3965
|
}
|
|
3897
3966
|
break;
|
|
3898
3967
|
}
|
|
3899
3968
|
}
|
|
3900
|
-
visibleOptions() {
|
|
3901
|
-
return this.listTarget.querySelectorAll('.midwest-autocomplete-option:not([aria-selected="true"])');
|
|
3902
|
-
}
|
|
3903
|
-
handleBlur() {
|
|
3904
|
-
setTimeout(() => this.hideDropdown(), 150);
|
|
3905
|
-
}
|
|
3906
3969
|
removeToken(event) {
|
|
3907
3970
|
event.stopPropagation();
|
|
3908
3971
|
const btn = event.currentTarget;
|
|
@@ -3910,16 +3973,31 @@ class Autocomplete extends Controller {
|
|
|
3910
3973
|
if (value)
|
|
3911
3974
|
this.deselect(value);
|
|
3912
3975
|
}
|
|
3913
|
-
//
|
|
3976
|
+
// Public action used by turbo-frame option items via data-action.
|
|
3977
|
+
// Each server-rendered <li> should have:
|
|
3978
|
+
// data-action="mousedown->midwest-autocomplete#selectOption"
|
|
3979
|
+
selectOption(event) {
|
|
3980
|
+
event.preventDefault();
|
|
3981
|
+
this.pickItem(event.currentTarget);
|
|
3982
|
+
}
|
|
3983
|
+
// ── Private ─────────────────────────────────────────────────────────────────
|
|
3914
3984
|
get optionIdPrefix() {
|
|
3915
3985
|
return `ac-opt-${(this.element.dataset.name ?? "field").replace(/\W/g, "-")}`;
|
|
3916
3986
|
}
|
|
3917
|
-
|
|
3918
|
-
this.
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3987
|
+
isSelected(value) {
|
|
3988
|
+
return !!this.tokensTarget.querySelector(`[data-value="${CSS.escape(value)}"]`);
|
|
3989
|
+
}
|
|
3990
|
+
// Routes to the correct data source. Shared by open() and the debounced search path.
|
|
3991
|
+
resolve(query) {
|
|
3992
|
+
if (this.hasTurboListTarget) {
|
|
3993
|
+
this.navigateFrame(query);
|
|
3994
|
+
return;
|
|
3995
|
+
}
|
|
3996
|
+
if (this.urlValue) {
|
|
3997
|
+
this.fetch(query);
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
4000
|
+
this.renderOptions(this.filteredOptions(query));
|
|
3923
4001
|
}
|
|
3924
4002
|
filteredOptions(query) {
|
|
3925
4003
|
const q = query.toLowerCase();
|
|
@@ -3927,10 +4005,36 @@ class Autocomplete extends Controller {
|
|
|
3927
4005
|
(o) => q === "" || o.label.toLowerCase().includes(q) || (o.support?.toLowerCase().includes(q) ?? false)
|
|
3928
4006
|
);
|
|
3929
4007
|
}
|
|
4008
|
+
navigateFrame(query) {
|
|
4009
|
+
const url = new URL(this.turboFrameUrlValue, window.location.href);
|
|
4010
|
+
if (query)
|
|
4011
|
+
url.searchParams.set("q", query);
|
|
4012
|
+
this.tokensTarget.querySelectorAll("input[type=hidden]").forEach((input) => {
|
|
4013
|
+
url.searchParams.append("selected[]", input.value);
|
|
4014
|
+
});
|
|
4015
|
+
this.loading = true;
|
|
4016
|
+
this.turboListTarget.setAttribute("src", url.toString());
|
|
4017
|
+
this.showDropdown();
|
|
4018
|
+
}
|
|
4019
|
+
// After a turbo frame loads, mark already-selected items and update the live region.
|
|
4020
|
+
// The empty state element is always present in the frame and CSS shows/hides it
|
|
4021
|
+
// based on whether any non-selected options exist.
|
|
4022
|
+
syncSelectedState() {
|
|
4023
|
+
const options = this.turboListTarget.querySelectorAll(".midwest-autocomplete-option");
|
|
4024
|
+
options.forEach((option) => {
|
|
4025
|
+
const val = option.dataset.value ?? "";
|
|
4026
|
+
option.setAttribute("aria-selected", this.isSelected(val) ? "true" : "false");
|
|
4027
|
+
});
|
|
4028
|
+
const visibleCount = this.visibleOptions().length;
|
|
4029
|
+
this.announce(visibleCount > 0 ? `${visibleCount} option${visibleCount === 1 ? "" : "s"} available` : "No more options");
|
|
4030
|
+
}
|
|
3930
4031
|
async fetch(query) {
|
|
3931
4032
|
this.fetchAbort?.abort();
|
|
3932
4033
|
this.fetchAbort = new AbortController();
|
|
3933
|
-
this.
|
|
4034
|
+
this.listTarget.replaceChildren();
|
|
4035
|
+
this.loading = true;
|
|
4036
|
+
this.announce("Loading");
|
|
4037
|
+
this.showDropdown();
|
|
3934
4038
|
try {
|
|
3935
4039
|
const url = new URL(this.urlValue, window.location.href);
|
|
3936
4040
|
if (query)
|
|
@@ -3948,11 +4052,6 @@ class Autocomplete extends Controller {
|
|
|
3948
4052
|
}
|
|
3949
4053
|
}
|
|
3950
4054
|
select(option) {
|
|
3951
|
-
if (!this.multipleValue) {
|
|
3952
|
-
this.selectedValues.forEach((_, val) => this.removeTokenElement(val));
|
|
3953
|
-
this.selectedValues.clear();
|
|
3954
|
-
}
|
|
3955
|
-
this.selectedValues.set(option.value, option);
|
|
3956
4055
|
this.appendToken(option);
|
|
3957
4056
|
this.hideDropdown();
|
|
3958
4057
|
this.inputTarget.value = "";
|
|
@@ -3961,102 +4060,106 @@ class Autocomplete extends Controller {
|
|
|
3961
4060
|
this.dispatch("change", { detail: { value: option.value, label: option.label } });
|
|
3962
4061
|
}
|
|
3963
4062
|
deselect(value) {
|
|
3964
|
-
const
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
if (
|
|
3968
|
-
this.announce(`${
|
|
4063
|
+
const token = this.tokensTarget.querySelector(`[data-value="${CSS.escape(value)}"]`);
|
|
4064
|
+
const label = token?.querySelector(".value")?.textContent?.trim();
|
|
4065
|
+
token?.remove();
|
|
4066
|
+
if (label)
|
|
4067
|
+
this.announce(`${label} removed`);
|
|
3969
4068
|
this.dispatch("change", { detail: { value: null } });
|
|
3970
4069
|
}
|
|
3971
4070
|
appendToken(option) {
|
|
3972
|
-
|
|
4071
|
+
if (!this.multipleValue) {
|
|
4072
|
+
this.tokensTarget.querySelectorAll("[data-value]").forEach((el) => el.remove());
|
|
4073
|
+
}
|
|
4074
|
+
const template = this.multipleValue ? this.multipleTokenTemplateTarget : this.singleTokenTemplateTarget;
|
|
4075
|
+
const fragment = template.content.cloneNode(true);
|
|
4076
|
+
const badge = fragment.querySelector(".midwest-badge");
|
|
4077
|
+
if (!badge)
|
|
4078
|
+
return;
|
|
4079
|
+
badge.dataset.value = option.value;
|
|
4080
|
+
const valueEl = badge.querySelector(".value");
|
|
4081
|
+
if (valueEl)
|
|
4082
|
+
valueEl.textContent = option.label;
|
|
3973
4083
|
if (this.multipleValue) {
|
|
3974
|
-
const fragment = this.multipleTokenTemplateTarget.content.cloneNode(true);
|
|
3975
|
-
const badge = fragment.querySelector(".midwest-badge");
|
|
3976
|
-
badge.dataset.value = option.value;
|
|
3977
|
-
badge.querySelector(".value").textContent = option.label;
|
|
3978
4084
|
const removeBtn = badge.querySelector(".remove");
|
|
3979
|
-
removeBtn
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
this.
|
|
3987
|
-
const fragment = this.singleTokenTemplateTarget.content.cloneNode(true);
|
|
3988
|
-
const badge = fragment.querySelector(".midwest-badge");
|
|
3989
|
-
badge.dataset.value = option.value;
|
|
3990
|
-
badge.querySelector(".value").textContent = option.label;
|
|
3991
|
-
const input = badge.querySelector("input[type=hidden]");
|
|
3992
|
-
input.name = name;
|
|
4085
|
+
if (removeBtn) {
|
|
4086
|
+
removeBtn.dataset.value = option.value;
|
|
4087
|
+
removeBtn.setAttribute("aria-label", `Remove ${option.label}`);
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
const input = badge.querySelector("input[type=hidden]");
|
|
4091
|
+
if (input) {
|
|
4092
|
+
input.name = this.element.dataset.name ?? "";
|
|
3993
4093
|
input.value = option.value;
|
|
3994
|
-
this.tokensTarget.appendChild(fragment);
|
|
3995
4094
|
}
|
|
3996
|
-
|
|
3997
|
-
removeTokenElement(value) {
|
|
3998
|
-
const token = this.tokensTarget.querySelector(`[data-value="${CSS.escape(value)}"]`);
|
|
3999
|
-
token?.remove();
|
|
4095
|
+
this.tokensTarget.appendChild(fragment);
|
|
4000
4096
|
}
|
|
4001
4097
|
renderOptions(options) {
|
|
4002
|
-
this.listTarget.innerHTML = "";
|
|
4003
4098
|
this.highlightedIndex = -1;
|
|
4004
4099
|
if (options.length === 0) {
|
|
4005
4100
|
this.renderEmpty();
|
|
4006
4101
|
return;
|
|
4007
4102
|
}
|
|
4103
|
+
this.listTarget.replaceChildren();
|
|
4008
4104
|
options.forEach((option, index) => {
|
|
4009
4105
|
const li = document.createElement("li");
|
|
4010
4106
|
li.id = `${this.optionIdPrefix}-${index}`;
|
|
4011
4107
|
li.className = "midwest-autocomplete-option";
|
|
4012
4108
|
li.setAttribute("role", "option");
|
|
4013
|
-
li.setAttribute("aria-selected", this.
|
|
4109
|
+
li.setAttribute("aria-selected", this.isSelected(option.value) ? "true" : "false");
|
|
4014
4110
|
li.dataset.value = option.value;
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4111
|
+
const label = document.createElement("span");
|
|
4112
|
+
label.className = "midwest-autocomplete-option-label";
|
|
4113
|
+
label.textContent = option.label;
|
|
4114
|
+
li.appendChild(label);
|
|
4115
|
+
if (option.support) {
|
|
4116
|
+
const support = document.createElement("span");
|
|
4117
|
+
support.className = "midwest-autocomplete-option-support";
|
|
4118
|
+
support.textContent = option.support;
|
|
4119
|
+
li.appendChild(support);
|
|
4120
|
+
}
|
|
4023
4121
|
this.listTarget.appendChild(li);
|
|
4024
4122
|
});
|
|
4025
|
-
const availableCount = options.filter((o) => !this.
|
|
4123
|
+
const availableCount = options.filter((o) => !this.isSelected(o.value)).length;
|
|
4026
4124
|
if (availableCount === 0) {
|
|
4027
4125
|
this.renderEmpty("No more options");
|
|
4028
4126
|
return;
|
|
4029
4127
|
}
|
|
4128
|
+
this.loading = false;
|
|
4030
4129
|
this.announce(`${availableCount} option${availableCount === 1 ? "" : "s"} available`);
|
|
4031
4130
|
this.showDropdown();
|
|
4032
4131
|
}
|
|
4033
4132
|
renderEmpty(message = "No results") {
|
|
4034
|
-
|
|
4133
|
+
const li = document.createElement("li");
|
|
4134
|
+
li.className = "midwest-autocomplete-empty";
|
|
4135
|
+
li.setAttribute("aria-hidden", "true");
|
|
4136
|
+
li.textContent = message;
|
|
4137
|
+
this.listTarget.replaceChildren(li);
|
|
4138
|
+
this.loading = false;
|
|
4035
4139
|
this.announce(message);
|
|
4036
4140
|
this.showDropdown();
|
|
4037
4141
|
}
|
|
4038
|
-
|
|
4039
|
-
this.
|
|
4040
|
-
|
|
4041
|
-
this.showDropdown();
|
|
4142
|
+
set loading(on) {
|
|
4143
|
+
if (this.hasLoaderTarget)
|
|
4144
|
+
this.loaderTarget.hidden = !on;
|
|
4042
4145
|
}
|
|
4043
4146
|
showDropdown() {
|
|
4044
4147
|
if (!this.dropdownTarget.matches(":popover-open"))
|
|
4045
4148
|
this.dropdownTarget.showPopover();
|
|
4046
|
-
this.inputTarget.setAttribute("aria-expanded", "true");
|
|
4047
4149
|
}
|
|
4048
4150
|
hideDropdown() {
|
|
4049
4151
|
if (this.dropdownTarget.matches(":popover-open"))
|
|
4050
4152
|
this.dropdownTarget.hidePopover();
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
this.
|
|
4153
|
+
}
|
|
4154
|
+
visibleOptions() {
|
|
4155
|
+
const container = this.hasTurboListTarget ? this.turboListTarget : this.listTarget;
|
|
4156
|
+
return container.querySelectorAll('.midwest-autocomplete-option:not([aria-selected="true"])');
|
|
4054
4157
|
}
|
|
4055
4158
|
syncHighlight(items) {
|
|
4056
4159
|
items.forEach((item, i) => item.classList.toggle("is-highlighted", i === this.highlightedIndex));
|
|
4057
4160
|
const active = items[this.highlightedIndex];
|
|
4058
4161
|
active?.scrollIntoView({ block: "nearest" });
|
|
4059
|
-
if (active) {
|
|
4162
|
+
if (active?.id) {
|
|
4060
4163
|
this.inputTarget.setAttribute("aria-activedescendant", active.id);
|
|
4061
4164
|
} else {
|
|
4062
4165
|
this.inputTarget.removeAttribute("aria-activedescendant");
|
|
@@ -4064,7 +4167,7 @@ class Autocomplete extends Controller {
|
|
|
4064
4167
|
}
|
|
4065
4168
|
pickItem(item) {
|
|
4066
4169
|
const value = item.dataset.value ?? "";
|
|
4067
|
-
const label = item.querySelector(".midwest-autocomplete-option-label")?.textContent?.trim()
|
|
4170
|
+
const label = item.dataset.label?.trim() || item.querySelector(".midwest-autocomplete-option-label")?.textContent?.trim() || value;
|
|
4068
4171
|
const support = item.querySelector(".midwest-autocomplete-option-support")?.textContent?.trim();
|
|
4069
4172
|
this.select({ value, label, support });
|
|
4070
4173
|
}
|
|
@@ -4072,9 +4175,6 @@ class Autocomplete extends Controller {
|
|
|
4072
4175
|
if (this.hasStatusTarget)
|
|
4073
4176
|
this.statusTarget.textContent = message;
|
|
4074
4177
|
}
|
|
4075
|
-
escapeHtml(str) {
|
|
4076
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
4077
|
-
}
|
|
4078
4178
|
}
|
|
4079
4179
|
|
|
4080
4180
|
function registerMidwestControllers(application) {
|