@progress/kendo-react-dropdowns
Version:
React DropDowns offer an interface for users to select different items from a list and more. KendoReact Dropdowns package
713 lines (712 loc) • 32.8 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as f from "react";
import g from "prop-types";
import { Keys as u, classNames as I, IconWrap as R, WatermarkOverlay as X, canUseDOM as L, validatePackage as Z, createPropsContext as tt, withIdHOC as et, withPropsContext as st, withAdaptiveModeContext as it, kendoThemeMaps as ot } from "@progress/kendo-react-common";
import { plusIcon as at } from "@progress/kendo-svg-icons";
import { FloatingLabel as nt } from "@progress/kendo-react-labels";
import lt from "../common/ListContainer.mjs";
import dt from "../common/List.mjs";
import rt from "../common/GroupStickyHeader.mjs";
import ht from "./TagList.mjs";
import pt from "../common/SearchBar.mjs";
import D from "../common/DropDownBase.mjs";
import { ActiveDescendant as k } from "../common/settings.mjs";
import { getFilteredData as b, areSame as M, removeDataItems as w, isPresent as E, getItemValue as O, preventDefaultNonInputs as ct, matchTags as z, itemIndexStartsWith as ut } from "../common/utils.mjs";
import { packageMetadata as ft } from "../package-metadata.mjs";
import mt from "../common/ClearButton.mjs";
import { AdaptiveMode as gt } from "../common/AdaptiveMode.mjs";
import { ActionSheetContent as vt } from "@progress/kendo-react-layout";
import { provideLocalizationService as bt } from "@progress/kendo-react-intl";
import { adaptiveModeFooterCancel as B, messages as V, adaptiveModeFooterApply as A } from "../messages/index.mjs";
import It from "../common/ListFilter.mjs";
import H from "../common/withCustomComponent.mjs";
const { sizeMap: T, roundedMap: yt } = ot, xt = "Please enter a valid value!", $ = (F) => F.preventDefault(), W = (F) => F === 2, y = class y extends f.Component {
constructor(n) {
super(n), this.state = {
activedescendant: k.PopupList,
currentValue: []
}, this._element = null, this._valueItemsDuringOnChange = null, this.base = new D(this), this._tags = [], this._input = null, this._adaptiveInput = null, this._skipFocusEvent = !1, this._lastSelectedOrDeslectedItemIndex = null, this.itemHeight = 0, this.scrollToFocused = !1, this.localization = null, this.showLicenseWatermark = !1, this.focus = () => {
this._input && this._input.focus();
}, this.handleItemSelect = (t, e) => {
const { dataItemKey: o, virtual: s } = this.props, a = b(this.props), p = s ? s.skip : 0, c = a[t - p], r = this.value.findIndex((m) => M(m, c, o));
this._lastSelectedOrDeslectedItemIndex = a.findIndex((m) => M(m, c, o));
let i = [];
r !== -1 ? (i = this.value, i.splice(r, 1)) : i = [...this.value, c], (this.props.filter !== void 0 ? this.props.filter : this.state.text) && !this.mobileMode && (this.state.text && (e.data.text = ""), this.base.filterChanged("", e)), this._adaptiveInput && this._adaptiveInput.blur(), this.state.focusedIndex !== void 0 && (e.data.focusedIndex = void 0), this.triggerOnChange(i, e), this.base.triggerPageChangeCornerItems(c, e);
}, this.onTagDelete = (t, e) => {
const o = this.base.initState();
o.syntheticEvent = e, this.opened && this.base.togglePopup(o), !this.state.focused && !this.mobileMode && (o.data.focused = !0, this.focus());
const s = this.value;
w(s, t, this.props.dataItemKey), this.triggerOnChange(s, o), this.applyState(o);
}, this.itemFocus = (t, e) => {
const { allowCustom: o, virtual: s } = this.props, a = b(this.props), p = s ? s.skip : 0, c = this.props.filter !== void 0 ? this.props.filter : this.state.text, { focusedIndex: r } = this.getFocusedState(), i = o && c, l = a[t - p];
l && r !== t ? this.state.focusedIndex !== t && (e.data.focusedIndex = t, e.data.activedescendant = k.PopupList) : i && t === -1 && this.state.focusedIndex !== void 0 && (e.data.focusedIndex = void 0), this.base.triggerPageChangeCornerItems(l, e);
}, this.componentRef = (t) => {
this._element = t, this.base.wrapper = t;
}, this.searchbarRef = (t) => {
const e = this._input = t && t.input;
e && this.state.focused && window.setTimeout(() => e.focus(), 0);
}, this.onChangeHandler = (t) => {
const e = this.base.initState(), o = t.target.value;
e.syntheticEvent = t, this.props.filter === void 0 && (e.data.text = o), e.data.focusedIndex = void 0, this.opened || (this.base.togglePopup(e), this.setState({ currentValue: this.value })), this.base.filterChanged(o, e), this.applyState(e), this.setState({ group: void 0 });
}, this.clearButtonClick = (t) => {
const e = this.base.initState();
e.syntheticEvent = t, t.stopPropagation(), this.value.length > 0 && this.triggerOnChange([], e), this.state.focusedIndex !== void 0 && (e.data.focusedIndex = void 0), this.opened && this.base.togglePopup(e);
const o = this.props.filter !== void 0 ? this.props.filter : this.state.text;
E(o) && o !== "" && this.base.filterChanged("", e), this.state.text && (e.data.text = ""), this._lastSelectedOrDeslectedItemIndex = null, this.applyState(e);
}, this.onInputKeyDown = (t) => {
const { textField: e, groupField: o } = this.props, s = b(this.props), a = t.keyCode, p = this.props.filter !== void 0 ? this.props.filter : this.state.text, c = this.props.opened !== void 0 ? this.props.opened : this.state.opened, { focusedItem: r, focusedIndex: i } = this.getFocusedState(), l = this.base.initState();
if (l.syntheticEvent = t, !p && this.value.length > 0 && (a === u.left || a === u.right || a === u.home || a === u.end || a === u.delete || a === u.backspace) && !t.shiftKey)
return this.onTagsNavigate(t, l);
const m = () => {
t.preventDefault(), this.base.togglePopup(l), this.applyState(l);
};
if (this.opened)
if (a === u.pageUp)
t.preventDefault(), this.base.scrollPopupByPageSize(-1);
else if (a === u.pageDown)
t.preventDefault(), this.base.scrollPopupByPageSize(1);
else if ((t.ctrlKey || t.metaKey) && t.code === "KeyA") {
const h = (this.state.value && this.state.value.length) === s.length ? [] : s;
this.updateStateOnKeyboardNavigation(h, l);
} else if ((t.ctrlKey || t.metaKey) && t.shiftKey && t.keyCode === u.end) {
const d = s.slice(this.getFocusedState().focusedIndex);
this.itemFocus(s.length - 1, l), this.updateStateOnKeyboardNavigation(d, l);
} else if ((t.ctrlKey || t.metaKey) && t.shiftKey && t.keyCode === u.home) {
const d = s.slice(0, this.getFocusedState().focusedIndex + 1);
this.itemFocus(0, l), this.updateStateOnKeyboardNavigation(d, l);
} else if (t.shiftKey && t.keyCode === u.up) {
let d;
const h = this.getLastSelectedOrDeselectedIndex(1, i);
h === null ? d = i !== 0 ? s.slice(i - 1, i) : [s[i]] : h === i ? d = [s[h - 1]] : i >= 0 && (d = h > i ? s.slice(i - 1, h) : s.slice(h - 1, i)), d && d.length > 0 && (i >= 1 && this.itemFocus(i - 1, l), this.updateStateOnKeyboardNavigation(d, l));
} else if (t.shiftKey && t.keyCode === u.down) {
let d;
const h = this.getLastSelectedOrDeselectedIndex(0, i);
h === null ? d = i !== s.length - 1 ? s.slice(i, i + 1) : [s[i]] : h === i ? d = s.slice(i, i + 2) : i >= 0 && (d = h > i ? s.slice(i + 1, h + 1) : s.slice(h, i + 2)), d && d.length >= 1 && (this.itemFocus(i + 1, l), this.updateStateOnKeyboardNavigation(d, l));
} else if (t.altKey && a === u.up)
m();
else if (a === u.up || a === u.down) {
if (o !== "" && e)
if (!this.props.skipDisabledItems && c)
this.onNavigate(l, a);
else {
let d = 0;
if (a === u.down || a === u.right) {
const h = s.slice(i + 1).find((v) => !v.disabled && v[e]);
d = h && s.findIndex((v) => v[e] === h[e]);
} else if (a === u.up || a === u.left) {
let h;
if (i === -1)
h = s, d = s.findIndex((v) => !v.disabled && v[e]);
else {
h = s.slice(0, i);
let v = h.pop();
for (; v && v.disabled; )
v = h.pop();
d = v && s.findIndex((x) => x[e] === v[e]);
}
}
if (d) {
const h = d - i;
this.onNavigate(l, a, h);
} else d !== void 0 && this.onNavigate(l, a);
}
else if (!this.props.skipDisabledItems && c)
this.onNavigate(l, a);
else {
let d = null;
if (a === u.down || a === u.right)
d = s.slice(i + 1).find((h) => !h.disabled);
else if (a === u.up || a === u.left) {
const h = s.slice(0, i);
for (d = h.pop(); d && d.disabled; )
d = h.pop();
}
if (d) {
const h = d.id - i - 1;
this.onNavigate(l, a, h);
} else
this.onNavigate(l, a);
}
this.applyState(l), t.preventDefault();
} else a === u.enter ? (t.preventDefault(), this.props.allowCustom && p && r === null ? this.customItemSelect(t) : r && r.disabled ? m() : this.selectFocusedItem(t)) : a === u.esc && m();
else t.altKey && a === u.down ? m() : a === u.esc && this.clearButtonClick(t);
}, this.listContainerContent = () => {
const { header: t, footer: e, allowCustom: o, size: s, groupStickyHeaderItemRender: a, groupField: p, list: c } = this.props, r = b(this.props), i = this.props.filter !== void 0 ? this.props.filter : this.state.text, { focusedType: l } = this.getFocusedState(), m = o && i && /* @__PURE__ */ f.createElement(
"div",
{
className: I("k-list", {
[`k-list-${T[s] || s}`]: s
}),
key: "customitem",
onClick: this.customItemSelect,
onMouseDown: $
},
/* @__PURE__ */ f.createElement(
"div",
{
className: I("k-list-item k-custom-item", { "k-focus": W(l) }),
style: { fontStyle: "italic" }
},
i,
/* @__PURE__ */ f.createElement(R, { name: "plus", icon: at, style: { position: "absolute", right: "0.5em" } })
)
);
let { group: d } = this.state;
return d === void 0 && p !== void 0 && (d = O(r[0], p)), /* @__PURE__ */ f.createElement(f.Fragment, null, t && /* @__PURE__ */ f.createElement("div", { className: "k-list-header" }, t), m, /* @__PURE__ */ f.createElement(
"div",
{
className: I("k-list", {
[`k-list-${this.mobileMode ? "lg" : T[s] || s}`]: s,
"k-virtual-list": this.base.vs.enabled
})
},
!c && d && r.length !== 0 && /* @__PURE__ */ f.createElement(rt, { group: d, groupMode: "modern", render: a }),
this.renderList()
), this.showLicenseWatermark && /* @__PURE__ */ f.createElement(X, null), e && /* @__PURE__ */ f.createElement("div", { className: "k-list-footer" }, e));
}, this.renderListContainer = () => {
const t = this.base, { dir: e } = this.props, o = b(this.props), s = this.base.getPopupSettings(), a = s.width !== void 0 ? s.width : t.popupWidth, p = {
dir: e !== void 0 ? e : t.dirCalculated,
width: a,
popupSettings: {
...s,
popupClass: I(s.popupClass, "k-list-container", "k-multiselect-popup"),
anchor: s.anchor || this.element,
show: this.opened,
onOpen: this.onPopupOpened,
onClose: this.onPopupClosed
},
itemsCount: [o.length, this.value.length]
};
return /* @__PURE__ */ f.createElement(lt, { ...p }, this.listContainerContent());
}, this.renderAdaptiveListContainer = () => {
const { adaptiveTitle: t, filterable: e, filter: o } = this.props, { windowWidth: s = 0 } = this.state, a = o !== void 0 ? o : this.state.text;
this.localization = bt(this);
const p = e ? /* @__PURE__ */ f.createElement(
It,
{
value: a,
ref: (r) => this._adaptiveInput = r && r.element,
onChange: this.onChangeHandler,
onKeyDown: this.onInputKeyDown,
size: this.props.size,
rounded: this.props.rounded,
fillMode: this.props.fillMode
}
) : null, c = {
title: t,
expand: this.opened,
onClose: (r) => this.onCancel(r),
windowWidth: s,
mobileFilter: p,
footer: {
cancelText: this.localization.toLanguageString(
B,
V[B]
),
onCancel: this.onCancel,
applyText: this.localization.toLanguageString(
A,
V[A]
),
onApply: this.closePopup
}
};
return /* @__PURE__ */ f.createElement(gt, { ...c }, /* @__PURE__ */ f.createElement(vt, { overflowHidden: !0 }, /* @__PURE__ */ f.createElement("div", { className: "k-list-container" }, this.listContainerContent())));
}, this.closePopup = (t) => {
const e = this.base.initState();
e.syntheticEvent = t, t.stopPropagation(), this.state.focusedIndex !== void 0 && (e.data.focusedIndex = void 0), this.opened && this.base.togglePopup(e), e.events.push({ type: "onClose" });
const o = this.props.filter !== void 0 ? this.props.filter : this.state.text;
E(o) && o !== "" && this.base.filterChanged("", e), this.state.text && (e.data.text = ""), this.applyState(e);
}, this.onCancel = (t) => {
const e = this.base.initState();
e.syntheticEvent = t, t.stopPropagation(), this.state.focusedIndex !== void 0 && (e.data.focusedIndex = void 0), this.opened && this.base.togglePopup(e), e.events.push({ type: "onCancel" });
const o = this.props.filter !== void 0 ? this.props.filter : this.state.text;
E(o) && o !== "" && this.base.filterChanged("", e), this.state.text && (e.data.text = ""), this.applyState(e);
}, this.renderList = () => {
const {
textField: t,
listNoDataRender: e,
itemRender: o,
groupHeaderItemRender: s,
dataItemKey: a,
virtual: p = { skip: 0, total: void 0 }
} = this.props, c = b(this.props), r = this.base.vs, { focusedIndex: i } = this.getFocusedState(), l = this.base.getPopupSettings(), m = `translateY(${r.translate}px)`;
return /* @__PURE__ */ f.createElement(
dt,
{
id: this.base.listBoxId,
show: this.opened,
data: c.slice(),
focusedIndex: i - p.skip,
value: this.value,
textField: t,
valueField: a,
optionsGuid: this.base.guid,
groupField: this.props.groupField,
groupMode: "modern",
listRef: (d) => {
r.list = this.base.list = d;
},
wrapperStyle: this.mobileMode ? {} : { maxHeight: l.height },
wrapperCssClass: "k-list-content",
listStyle: r.enabled ? { transform: m } : void 0,
key: "listKey",
skip: p.skip,
onClick: this.handleItemClick,
itemRender: o,
groupHeaderItemRender: s,
noDataRender: e,
onMouseDown: $,
onBlur: this.handleBlur,
onScroll: this.onScroll,
wrapperRef: r.scrollerRef,
scroller: this.base.renderScrollElement(),
ariaSetSize: p.total
}
);
}, this.onScroll = (t) => {
const { vs: e, list: o } = this.base;
e.scrollHandler(t);
const { groupField: s } = this.props;
let a = b(this.props);
if (!(!s || !a.length) && s) {
const p = this.itemHeight = this.itemHeight || (e.enabled ? e.itemHeight : o ? o.children[0].offsetHeight : 0), r = t.target.scrollTop - e.skip * p;
a = this.base.getGroupedDataModernMode(a, s);
let i = a[0][s];
for (let l = 1; l < a.length && !(p * l > r); l++)
a[l] && a[l][s] && (i = a[l][s]);
i !== this.state.group && this.setState({
group: i
});
}
}, this.customItemSelect = (t) => {
const e = this.props.filter !== void 0 ? this.props.filter : this.state.text, { textField: o } = this.props;
if (!e)
return;
const s = this.base.initState();
s.syntheticEvent = t;
const a = o ? { [o]: e } : e;
this.state.text !== void 0 && (s.data.text = ""), s.data.focusedIndex = void 0, this.base.filterChanged("", s);
const p = [...this.value, a];
this.triggerOnChange(p, s), this.base.togglePopup(s), this.applyState(s);
}, this.handleWrapperClick = (t) => {
const e = this._input;
!this.opened && e && this.focusElement(e);
const o = this.base.initState();
o.syntheticEvent = t, !this.state.focused && !this.mobileMode && (o.events.push({ type: "onFocus" }), o.data.focused = !0), this.mobileMode && (this.setState({ currentValue: this.tagsToRender }), this.mobileMode && window.setTimeout(() => this._adaptiveInput && this._adaptiveInput.focus(), 300)), this.base.togglePopup(o), this.applyState(o);
}, this.handleItemClick = (t, e) => {
const o = this.base.initState();
o.syntheticEvent = e, this.handleItemSelect(t, o), this.props.autoClose && !this.mobileMode && this.base.togglePopup(o), e.stopPropagation(), this.applyState(o);
}, this.handleBlur = (t) => {
if (!this.state.focused || this._skipFocusEvent)
return;
const e = this.base.initState(), { allowCustom: o, filterable: s } = this.props;
e.syntheticEvent = t, e.data.focused = !1, e.events.push({ type: "onBlur" }), this.opened && !this.mobileMode && (this.state.opened && (e.data.opened = !1), e.events.push({ type: "onClose" })), !o && !s && this.state.text && (e.data.text = ""), this.applyState(e);
}, this.handleFocus = (t) => {
this._skipFocusEvent || this.base.handleFocus(t);
}, this.onPopupOpened = () => {
this._input && this.state.focused && !this.mobileMode && this.focusElement(this._input);
}, this.onPopupClosed = () => {
this.state.focused && window.setTimeout(() => {
this.state.focused && this.focusElement(this._input);
}, 0);
}, this.setValidity = () => {
this._input && this._input.setCustomValidity && this._input.setCustomValidity(
this.validity.valid ? "" : this.props.validationMessage || xt
);
}, this.validate(n);
}
get _inputId() {
return this.props.id;
}
get document() {
if (L)
return this.element && this.element.ownerDocument || document;
}
validate(n) {
if (n.filterable || n.virtual) {
const t = [];
n.filterable && t.push("filterable"), n.virtual && t.push("virtualization"), this.showLicenseWatermark = !Z(ft, {
component: "MultiSelect",
features: t
});
}
}
/** @hidden */
get element() {
return this._element;
}
/** @hidden */
get opened() {
return !!(this.props.opened !== void 0 ? this.props.opened : this.state.opened);
}
/** @hidden */
get tagsToRender() {
const { tags: n, textField: t } = this.props, e = [];
return n === void 0 ? this.value.forEach((o) => {
e.push({ text: O(o, t), data: [o] });
}) : e.push(...n), e;
}
/**
* The mobile mode of the MultiSelect.
*/
get mobileMode() {
var t;
return !!(this.state.windowWidth && this.props._adaptiveMode && this.state.windowWidth <= ((t = this.props._adaptiveMode) == null ? void 0 : t.medium) && this.props.adaptive);
}
/**
* Represents the value of the MultiSelect.
*/
get value() {
const n = [];
return this._valueItemsDuringOnChange ? n.push(...this._valueItemsDuringOnChange) : this.props.value ? n.push(...this.props.value) : this.state.value ? n.push(...this.state.value) : this.props.defaultValue && n.push(...this.props.defaultValue), n;
}
/**
* Gets the `name` property of the MultiSelect.
*/
get name() {
return this.props.name;
}
/**
* Represents the validity state into which the MultiSelect is set.
*/
get validity() {
const n = this.props.validationMessage !== void 0, t = !this.required || this.value !== null && this.value.length > 0 && this.value !== void 0, e = this.props.valid !== void 0 ? this.props.valid : t;
return {
customError: n,
valid: e,
valueMissing: this.value === null
};
}
/** @hidden */
get required() {
return this.props.required !== void 0 ? this.props.required : y.defaultProps.required;
}
get validityStyles() {
return this.props.validityStyles !== void 0 ? this.props.validityStyles : y.defaultProps.validityStyles;
}
/** @hidden */
componentDidUpdate(n, t) {
var m;
const { virtual: e, groupField: o = "" } = this.props, s = b(this.props), a = e ? e.skip : 0, p = n.virtual ? n.virtual.total : 0, c = n.opened !== void 0 ? n.opened : t.opened, r = !c && this.opened, i = c && !this.opened, l = this.base.getPopupSettings();
if (this.validate(this.props), this.base.didUpdate(), !l.animate && i && this.onPopupClosed(), e && e.total !== p)
this.base.vs.calcScrollElementHeight(), this.base.vs.reset();
else {
let { focusedItem: d, focusedIndex: h } = this.getFocusedState();
o !== "" && (h = (m = this.base.getGroupedDataModernMode(s, o)) == null ? void 0 : m.indexOf(d)), r && e ? this.base.scrollToVirtualItem(e, h - a) : r && !e ? (s && s.length !== 0 && this.base.resetGroupStickyHeader(s[0][o], this), this.base.scrollToItem(h)) : this.opened && c && d && this.scrollToFocused && this.base.scrollToItem(h - a);
}
this.scrollToFocused = !1, this.setValidity();
}
/** @hidden */
componentDidMount() {
var n;
this.observerResize = L && window.ResizeObserver && new window.ResizeObserver(this.calculateMedia.bind(this)), this.base.didMount(), this.setValidity(), (n = this.document) != null && n.body && this.observerResize && this.observerResize.observe(this.document.body);
}
/** @hidden */
componentWillUnmount() {
var n;
(n = this.document) != null && n.body && this.observerResize && this.observerResize.disconnect();
}
/** @hidden */
onNavigate(n, t, e) {
const { allowCustom: o } = this.props, s = b(this.props), a = this.props.filter !== void 0 ? this.props.filter : this.state.text, { focusedType: p, focusedIndex: c } = this.getFocusedState(), r = o && a, i = W(p), l = this.base, m = l.vs;
if (this.opened && t === u.up && i)
this.state.focusedIndex !== void 0 && (n.data.focusedIndex = void 0);
else {
const d = l.navigation.navigate({
keyCode: t,
current: c,
max: (m.enabled ? m.total : s.length) - 1,
min: r ? -1 : 0,
skipItems: e || void 0
});
d !== void 0 && (this.itemFocus(d, n), this.scrollToFocused = !0);
}
this.applyState(n);
}
/** @hidden */
render() {
const {
style: n,
className: t,
label: e,
dir: o,
disabled: s,
textField: a,
dataItemKey: p,
virtual: c,
size: r,
rounded: i,
fillMode: l,
loading: m,
filter: d
} = this.props, { text: h, focused: v, focusedTag: x, currentValue: q } = this.state, C = this.base.vs, _ = this.props.id || this._inputId;
C.enabled = c !== void 0, c !== void 0 && (C.skip = c.skip, C.total = c.total, C.pageSize = c.pageSize);
const S = this.mobileMode && this.opened ? q : this.tagsToRender;
this.setItems(this.tagsToRender, this._tags);
const K = !this.validityStyles || this.validity.valid, G = !!(d !== void 0 ? d : h) || S && S.length > 0, [U, j] = H(this.props.prefix || f.Fragment), [Y, J] = H(this.props.suffix || f.Fragment), N = /* @__PURE__ */ f.createElement(f.Fragment, null, /* @__PURE__ */ f.createElement(
"div",
{
ref: this.componentRef,
className: I("k-multiselect k-input", t, {
[`k-input-${T[r] || r}`]: r,
[`k-rounded-${yt[i] || i}`]: i,
[`k-input-${l}`]: l,
"k-focus": v && !s,
"k-invalid": !K,
"k-disabled": s,
"k-loading": m,
"k-required": this.required
}),
style: e ? { ...n, width: void 0 } : n,
dir: o,
onFocus: this.handleFocus,
onBlur: this.handleBlur,
onClick: this.handleWrapperClick,
onMouseDown: ct
},
this.props.prefix && /* @__PURE__ */ f.createElement(U, { ...j }),
/* @__PURE__ */ f.createElement("div", { className: I("k-input-values") }, /* @__PURE__ */ f.createElement(
"div",
{
className: I("k-chip-list", { [`k-chip-list-${T[r] || r}`]: r }),
role: "listbox",
id: "tagslist-" + this.base.guid
},
S && S.length > 0 && /* @__PURE__ */ f.createElement(
ht,
{
tagRender: this.props.tagRender,
onTagDelete: this.onTagDelete,
data: S,
guid: this.base.guid,
focused: x ? S.find((Q) => z(Q, x, p)) : void 0,
size: r
}
)
), this.renderSearchBar(_)),
m && /* @__PURE__ */ f.createElement(R, { className: "k-input-loading-icon", name: "loading" }),
this.props.suffix && /* @__PURE__ */ f.createElement(Y, { ...J }),
G && /* @__PURE__ */ f.createElement(mt, { onClick: this.clearButtonClick }),
!this.mobileMode && this.renderListContainer()
), this.mobileMode && this.renderAdaptiveListContainer());
return e ? /* @__PURE__ */ f.createElement(
nt,
{
label: e,
editorId: _,
editorValue: h || O(this.value[0], a),
editorValid: K,
editorDisabled: s,
style: { width: n ? n.width : void 0 },
children: N
}
) : N;
}
renderSearchBar(n) {
const { activedescendant: t, focusedTag: e, currentValue: o } = this.state, { disabled: s, placeholder: a, ariaDescribedBy: p, ariaLabelledBy: c, ariaLabel: r, inputAttributes: i } = this.props, l = !this.mobileMode && (this.props.filter !== void 0 ? this.props.filter : this.state.text) || "", { focusedIndex: m } = this.getFocusedState(), d = this.value.length === 0 && !l ? a : void 0, h = o && o.length > 0 ? void 0 : a, v = t === k.TagsList && e !== void 0 ? `tag-${this.base.guid}-${e.text.replace(/\s+/g, "-")}` : `option-${this.base.guid}-${m}`, x = {
accessKey: this.props.accessKey,
tabIndex: this.props.tabIndex
};
return /* @__PURE__ */ f.createElement(
pt,
{
id: n,
size: Math.max((d || "").length, l.length, 1),
placeholder: this.mobileMode && this.opened ? h : d,
value: l,
onChange: this.onChangeHandler,
onKeyDown: this.onInputKeyDown,
ref: this.searchbarRef,
disabled: s,
expanded: this.opened,
owns: this.base.listBoxId,
role: "combobox",
activedescendant: v,
ariaDescribedBy: `tagslist-${this.base.guid}${p ? " " + p : ""}`,
ariaLabelledBy: c,
ariaRequired: this.required,
ariaLabel: r,
inputAttributes: i,
...x
}
);
}
onTagsNavigate(n, t) {
const e = n.keyCode, { focusedTag: o } = this.state, s = this._tags, a = this.props.dataItemKey;
let p = o ? s.findIndex((i) => z(i, o, a)) : -1, c;
const r = p !== -1;
if (e === u.left)
r ? p = Math.max(0, p - 1) : p = s.length - 1, c = s[p];
else if (e === u.right)
p === s.length - 1 ? c = void 0 : r && (p = Math.min(s.length - 1, p + 1), c = s[p]);
else if (e === u.home && !n.shiftKey)
c = s[0];
else if (e === u.end && !n.shiftKey)
c = s[s.length - 1];
else if (e === u.delete) {
if (r) {
const i = this.value;
w(i, s[p].data, a), this.triggerOnChange(i, t);
}
} else if (e === u.backspace) {
const i = this.value;
if (r)
w(i, s[p].data, a), this.triggerOnChange(i, t);
else if (!r && s.length) {
const l = s.pop();
w(i, l.data, a), this.triggerOnChange(i, t);
}
}
c !== o && (t.data.focusedTag = c, t.data.activedescendant = k.TagsList), this.applyState(t);
}
triggerOnChange(n, t) {
this.props.value === void 0 && (t.data.value = [...n]), this._valueItemsDuringOnChange = [], this.setItems(n, this._valueItemsDuringOnChange), t.events.push({ type: "onChange" });
}
selectFocusedItem(n, t) {
const { virtual: e } = this.props, o = b(this.props), { focusedIndex: s } = t || this.getFocusedState(), a = e ? e.skip : 0;
o[s - a] !== void 0 && this.handleItemClick(s, n);
}
setItems(n, t) {
t.length = 0, t.push(...n);
}
getFocusedState() {
const { focusedIndex: n } = this.state, t = this.props.filter !== void 0 ? this.props.filter : this.state.text, {
allowCustom: e,
dataItemKey: o,
virtual: s,
textField: a,
focusedItemIndex: p = ut,
skipDisabledItems: c
} = this.props, r = b(this.props), i = s && s.skip || 0;
let l;
if (n !== void 0)
return {
focusedIndex: n,
focusedItem: r[n - i],
focusedType: 1
/* ListItem */
};
const m = this.value;
if (e && t)
return {
focusedItem: null,
focusedIndex: -1,
focusedType: 2
/* CustomItem */
};
if (t)
return l = p(r, t, a), {
focusedItem: r[l],
focusedIndex: l + i,
focusedType: 1
/* ListItem */
};
if (m.length) {
const d = m[m.length - 1];
return l = r.findIndex((h) => M(h, d, o)), r[l] !== void 0 ? {
focusedIndex: l + i,
focusedItem: r[l],
focusedType: 1
/* ListItem */
} : { focusedType: 0, focusedIndex: -1 };
} else if (c && a && !t && i === 0) {
const d = r.findIndex((h) => !h.disabled && h[a]);
return {
focusedIndex: d,
focusedItem: r[d - i],
focusedType: 1
/* ListItem */
};
}
return i === 0 ? {
focusedItem: r[0],
focusedIndex: 0,
focusedType: 1
/* ListItem */
} : { focusedType: 0, focusedIndex: -1 };
}
focusElement(n) {
this._skipFocusEvent = !0, n.focus(), window.setTimeout(() => this._skipFocusEvent = !1, 0);
}
applyState(n) {
this.base.applyState(n), this._valueItemsDuringOnChange = null;
}
calculateMedia(n) {
for (const t of n)
this.setState({ windowWidth: t.target.clientWidth });
}
/**
* Updates the state of the MultiSelect when the complex keyboard navigation that
* includes key combinations with the Ctrl/Command, Shift, Home and End keys
*
* @param {Array<string | Object>} dataToSet Defines the array of new values that will be applied to the MultiSelect
* @param {MultiSelectInternalState} state The current state of the MultiSelect
*/
updateStateOnKeyboardNavigation(n, t) {
this.setState({ value: n }), this.triggerOnChange(n, t), this.applyState(t);
}
/**
* Returns the last element that was selected or deselected. Needed for the keyboard navigation specifications
*
* @param {number} correction A correction is needed depending on if UP or DOWN key is pressed
*/
getLastSelectedOrDeselectedIndex(n, t) {
return this._lastSelectedOrDeslectedItemIndex === null && (this._lastSelectedOrDeslectedItemIndex = t), this._lastSelectedOrDeslectedItemIndex !== null ? this._lastSelectedOrDeslectedItemIndex + n : null;
}
};
y.displayName = "MultiSelect", y.propTypes = {
...D.propTypes,
autoClose: g.bool,
value: g.arrayOf(g.any),
defaultValue: g.arrayOf(g.any),
dataItemKey: g.string,
placeholder: g.string,
tags: g.arrayOf(
g.shape({
text: g.string,
data: g.arrayOf(g.any)
})
),
tagRender: g.func,
id: g.string,
ariaLabelledBy: g.string,
ariaDescribedBy: g.string,
groupField: g.string,
list: g.any,
adaptive: g.bool,
adaptiveTitle: g.string,
onCancel: g.func,
skipDisabledItems: g.bool,
inputAttributes: g.object
}, y.defaultProps = {
...D.defaultProps,
autoClose: !0,
required: !1,
size: "medium",
rounded: "medium",
fillMode: "solid",
groupMode: "modern",
skipDisabledItems: !0,
prefix: void 0,
suffix: void 0
};
let P = y;
const St = tt(), Ct = et(
st(
St,
it(P)
)
);
Ct.displayName = "KendoReactMultiSelect";
export {
Ct as MultiSelect,
St as MultiSelectPropsContext,
P as MultiSelectWithoutContext
};