@progress/kendo-vue-buttons
Version:
285 lines (284 loc) • 9.58 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2026 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import { defineComponent as k, createVNode as o, ref as y } from "vue";
import { Button as l } from "../Button.mjs";
import { canUseDOM as O, Keys as s, getDefaultSlots as I, guid as a, validatePackage as S, classNames as D, templateRendering as h, getListeners as f } from "@progress/kendo-vue-common";
import { ButtonItem as x } from "./ButtonItem.mjs";
import w from "./utils/navigation.mjs";
import { Popup as v } from "@progress/kendo-vue-popup";
import { getPopupAlign as P, getAnchorAlign as B } from "./utils/popup.mjs";
import { chevronDownIcon as E } from "@progress/kendo-svg-icons";
import { packageMetadata as K } from "../package-metadata.mjs";
const L = /* @__PURE__ */ k({
name: "KendoSplitButton",
emits: {
focus: (t) => !0,
blur: (t) => !0,
buttonclick: (t) => !0,
itemclick: (t) => !0,
open: (t) => !0,
close: (t) => !0
},
props: {
accessKey: String,
ariaLabel: String,
text: String,
items: {
type: Array,
default: function() {
return [];
}
},
textField: String,
tabIndex: Number,
disabled: Boolean,
icon: String,
svgIcon: Object,
size: String,
rounded: String,
fillMode: {
type: String,
validator: function(t) {
return ["flat", "link", "outline", "solid"].includes(t);
}
},
themeColor: {
type: String,
validator: function(t) {
return ["base", "error", "info", "inverse", "primary", "secondary", "success", "tertiary", "warning"].includes(t);
}
},
opened: {
type: Boolean,
default: void 0
},
iconClass: String,
imageUrl: String,
popupSettings: Object,
itemRender: [String, Function, Object],
item: [String, Function, Object],
className: String,
buttonClass: String,
dir: String
},
data() {
return {
focused: !1,
focusedIndex: -1,
currentOpened: !1
};
},
created() {
this._blurTimeout = null, this._anchor = a(), this.mainButton = null, this.guid = a(), this.buttonsData = [], S(K);
},
mounted() {
this.mainButton = this.$refs[this._anchor], (this.$props.dir === void 0 && this.isRtl() || this.computedOpened) && this.$forceUpdate();
},
updated() {
this.focused && this.element() && (this.mainButton = this.$refs[this._anchor], this.mainButton.focus());
},
computed: {
computedOpened() {
return this.$props.opened === void 0 ? this.currentOpened : this.$props.opened;
},
wrapperClass() {
return {
"k-split-button": !0,
"k-button-group": !0,
"k-focus": this.focused
};
}
},
setup() {
return {
kendoAnchorRef: y(null)
};
},
render() {
this.buttonsData = this.$props.items;
const t = this.isRtl(), e = t ? "rtl" : void 0, {
tabIndex: i,
disabled: r
} = this.$props, p = I(this), m = function() {
const {
item: n,
itemRender: c,
textField: C
} = this.$props;
return this.buttonsData.length > 0 ? this.buttonsData.map(function(d, u) {
const $ = typeof d != "string" ? {
...d,
render: h.call(this, d.render, f.call(this))
} : d;
return o(x, {
role: "menuitem",
dataItem: $,
textField: C,
focused: this.focusedIndex === u,
onClick: this.onItemClick,
onDown: this.onItemDown,
render: h.call(this, c, f.call(this)),
item: n,
key: u,
index: u,
id: `${this.guid}-${u}`
}, null);
}, this) : null;
}, g = function() {
const {
popupSettings: n = {},
size: c
} = this.$props;
return o(v, {
anchor: this._anchor,
show: this.computedOpened,
animate: n.animate,
popupClass: D("k-menu-popup", n.popupClass),
anchorAlign: n.anchorAlign || B(t),
popupAlign: n.popupAlign || P(t),
style: t ? {
direction: "rtl"
} : void 0
}, {
default: () => [o("ul", {
class: "k-menu-group",
role: "menu",
id: this.guid
}, [m.call(this)])]
});
}, b = this.$props.text || p ? {
default: () => [this.$props.text, p]
} : {};
return o("div", {
class: this.wrapperClass,
onKeydown: this.onKeyDown,
onFocusin: this.onFocus,
onFocusout: this.onBlur,
dir: e
}, [o(l, {
size: this.$props.size,
rounded: this.$props.rounded,
fillMode: this.$props.fillMode,
themeColor: this.$props.themeColor,
onClick: (n) => this.onItemClick(n, -1),
disabled: r || void 0,
tabIndex: i,
accessKey: this.$props.accessKey,
class: this.$props.buttonClass,
icon: this.$props.icon,
svgIcon: this.$props.svgIcon,
iconClass: this.$props.iconClass,
imageUrl: this.$props.imageUrl,
dir: e,
id: this._anchor,
ref: this._anchor,
type: "button",
"aria-disabled": r || void 0,
"aria-label": this.$props.ariaLabel || (!this.$props.text && !p && (this.$props.svgIcon || this.$props.icon || this.$props.iconClass) ? "Action" : void 0)
}, b), o(l, {
svgIcon: E,
size: this.$props.size,
rounded: this.$props.rounded,
fillMode: this.$props.fillMode,
themeColor: this.$props.themeColor,
icon: "chevron-down",
class: "k-split-button-arrow",
disabled: r || void 0,
tabIndex: -1,
onClick: this.onSplitPartClick,
onMousedown: this.onDownSplitPart,
onPointerdown: this.onDownSplitPart,
dir: e,
"aria-label": "Toggle dropdown",
"aria-expanded": this.computedOpened,
"aria-controls": this.computedOpened ? this.guid : void 0
}, null), g.call(this)]);
},
methods: {
element() {
return this.mainButton;
},
onKeyDown(t) {
if (t.altKey) {
!this.computedOpened && t.keyCode === s.down ? (this.dispatchPopupEvent(t, !0), this.focusedIndex = 0, this.currentOpened = !0) : this.computedOpened && t.keyCode === s.up && (this.dispatchPopupEvent(t, !1), this.focusedIndex = -1, this.currentOpened = !1);
return;
}
let e;
if (t.keyCode === s.enter || t.keyCode === s.space ? (t.preventDefault(), this.dispatchClickEvent(t, this.focusedIndex), this.focusedIndex !== void 0 && this.focusedIndex >= 0 && (e = {
focusedIndex: this.computedOpened ? -1 : 0,
currentOpened: !this.computedOpened
}, this.dispatchPopupEvent(t, e.currentOpened))) : this.computedOpened && t.keyCode === s.esc && (e = {
focusedIndex: -1,
currentOpened: !1
}, this.dispatchPopupEvent(t, e.currentOpened)), this.computedOpened) {
const i = w(this.focusedIndex, t.keyCode, t.altKey, this.buttonsData.length);
i !== this.focusedIndex && (e = e || {}, e.focusedIndex = i);
const r = t.keyCode === s.up || t.keyCode === s.down || t.keyCode === s.left || t.keyCode === s.right;
!t.altKey && r && t.preventDefault();
}
e && (this.focusedIndex = e.focusedIndex, this.focused = e.focused, e.currentOpened !== void 0 && (this.currentOpened = e.currentOpened));
},
onFocus(t) {
this.focused || (this.$emit("focus", {
event: t
}), this.focused = !0), this.focusedIndex = -1, clearTimeout(this._blurTimeout);
},
onItemClick(t, e) {
const i = this.computedOpened;
i && (this.focusedIndex = 0, this.currentOpened = !1), this.dispatchClickEvent(t, e), i && this.dispatchPopupEvent(t, !1);
},
onBlur(t) {
clearTimeout(this._blurTimeout), this.createBlurTimeout(t);
},
createBlurTimeout(t) {
const e = this;
this._blurTimeout = setTimeout(() => {
O && document.activeElement !== e.mainButton && (e.focused = !1, e.focusedIndex = -1, e.$emit("blur", {
event: t
}), e.computedOpened && (e.currentOpened = !1, e.dispatchPopupEvent(t, !1)));
}, 200);
},
dispatchClickEvent(t, e) {
this.isItemDisabled(e) || (e === -1 ? this.$emit("buttonclick", {
event: t
}) : this.$emit("itemclick", {
event: t,
component: this,
item: this.buttonsData[e],
itemIndex: e
}));
},
onSplitPartClick(t) {
if (this.buttonsData.length) {
const e = !this.computedOpened;
this.dispatchPopupEvent(t, e), this.focusedIndex = e ? 0 : -1, this.currentOpened = e, this.focused = !0;
}
},
onDownSplitPart(t) {
t.preventDefault(), this.element() && document.activeElement !== this.element() && this.element().focus();
},
onItemDown(t) {
document.activeElement === this.element() && t.preventDefault();
},
dispatchPopupEvent(t, e) {
const i = {
event: t
};
this.$emit(e ? "open" : "close", i);
},
isItemDisabled(t) {
return this.buttonsData[t] ? this.buttonsData[t].disabled : this.$props.disabled;
},
isRtl() {
return this.$props.dir !== void 0 ? this.$props.dir === "rtl" : !!this.$el && getComputedStyle(this.$el).direction === "rtl";
}
}
});
export {
L as SplitButton
};