@progress/kendo-vue-buttons
Version:
288 lines (287 loc) • 10.2 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 { defineComponent as d, createVNode as a, Fragment as u, cloneVNode as b } from "vue";
import { Keys as h, getDefaultSlots as p, canUseDOM as c, kendoThemeMaps as v, validatePackage as S } from "@progress/kendo-vue-common";
import { internalButtons as w, toolbarButtons as g } from "../util.mjs";
import { packageMetadata as m } from "../package-metadata.mjs";
import { ToolbarScrollable as y } from "./tools/ToolbarScrollable.mjs";
import { ToolbarOverflowSection as T } from "./tools/ToolbarOverflowSection.mjs";
const I = /* @__PURE__ */ d({
name: "KendoToolbar",
props: {
tabIndex: {
type: Number,
default: 0
},
dir: {
type: String,
validator: function(t) {
return [null, "ltr", "rtl"].includes(t);
},
default: "ltr"
},
keyboardNavigation: {
type: Boolean,
default: !0
},
buttons: {
type: Array,
default: function() {
}
},
size: {
type: String,
default: "medium",
validator: function(t) {
return [null, "small", "medium", "large"].includes(t);
}
},
fillMode: {
type: String,
default: "solid",
validator: function(t) {
return [null, "solid", "flat", "outline"].includes(t);
}
},
ariaLabel: String,
overflow: {
type: String,
default: "section",
validator: function(t) {
return [null, "none", "section", "scroll"].includes(t);
}
},
scrollButtons: {
type: String,
default: "auto",
validator: function(t) {
return [null, "hidden", "visible", "auto"].includes(t);
}
},
scrollButtonsPosition: {
type: String,
default: "split",
validator: function(t) {
return [null, "start", "end", "split"].includes(t);
}
},
buttonScrollSpeed: {
type: Number,
default: 100
}
},
emits: {
resize: (t) => !0
},
data() {
return {
defaultSlot: null,
offsetWidth: 0,
offsetHeight: 0,
currentButtons: [],
focusedSelector: "",
isScrollStartPosition: !0,
isScrollEndPosition: !1,
focusableButtons: [],
isOverflowing: !1,
scrollContentRef: null,
lastToolbarWidthRef: 0,
overFlowToolsRef: [],
overFlowOpened: !1,
visibleToolsRef: void 0
};
},
created() {
this.focusedSelector = this.selectors.map((t) => t + ":focus").join(","), S(m);
},
computed: {
selectors() {
return this.$props.buttons || g;
},
wrapperClass() {
const {
size: t,
fillMode: e,
overflow: o,
scrollButtons: s
} = this.$props;
return {
"k-toolbar": !0,
[`k-toolbar-${e}`]: e,
[`k-toolbar-${v.sizeMap[t] || t}`]: t,
"k-toolbar-scrollable": o === "scroll",
"k-toolbar-scrollable-overlay": o === "scroll" && (s === "hidden" || s === void 0),
"k-toolbar-scrollable-start": o === "scroll" && s === "hidden" && this.isScrollStartPosition,
"k-toolbar-scrollable-end": o === "scroll" && s === "hidden" && this.isScrollEndPosition,
"k-toolbar-section": o && o === "section"
};
}
},
mounted() {
c && window.ResizeObserver && (this.observerResize = new window.ResizeObserver(this.onWindowResize), this.observerResize.observe(this.$el));
const t = this.$el;
t && (this.offsetWidth = t.offsetWidth, this.offsetHeight = t.offsetHeight, this.$props.keyboardNavigation !== !1 && (this.currentButtons = this.getCurrentButtons(), this.setTabIndex(0))), this.scrollContentRef = this.$refs.toolbarScrollable && this.$refs.toolbarScrollable.scrollContentRef, this.defaultSlot && (this.visibleToolsRef = this.defaultSlot.filter((e) => e && e.type).map((e, o) => b(e, {
key: e.key || o
})), this.$nextTick(() => {
this.checkOverflow(), this.initOverflow(this.$refs.toolbar);
}));
},
updated() {
!this.$el || this.$props.keyboardNavigation === !1 || (this.currentButtons = this.getCurrentButtons(), this.setTabIndex(this.focusedIndex()));
},
unmounted() {
c && this.observerResize && this.observerResize.disconnect(), this.currentButtons.length = 0;
},
render() {
const {
overflow: t,
scrollButtons: e,
scrollButtonsPosition: o,
prevButton: s,
nextButton: l,
buttonScrollSpeed: n,
dir: f,
fillMode: i,
size: r
} = this.$props;
return this.defaultSlot = p(this), a("div", {
ref: "toolbar",
class: this.wrapperClass,
role: "toolbar",
dir: f,
"aria-label": this.$props.ariaLabel,
onKeydown: this.onKeyDown
}, [t === "scroll" && a(u, null, [a(y, {
ref: "toolbarScrollable",
scrollButtons: e,
scrollButtonsPosition: o,
prevButton: s,
nextButton: l,
isOverflowing: this.isOverflowing,
buttonScrollSpeed: n,
dir: f,
isScrollStartPosition: this.isScrollStartPosition,
isScrollEndPosition: this.isScrollEndPosition,
toolbarItems: this.defaultSlot,
onContentscroll: this.onContentScroll
}, null)]), t === "section" && a(T, {
opened: this.overFlowOpened,
toolbarRef: this.$refs.toolbar,
toolbarWidth: this.offsetWidth,
fillMode: i,
size: r,
visibleTools: this.visibleToolsRef,
overFlowTools: this.overFlowToolsRef,
onToggleoverflow: this.onToggleoverflow,
allTools: this.defaultSlot
}, null), t === "none" && this.defaultSlot]);
},
methods: {
getCurrentButtons() {
return this.$el && this.$el.querySelectorAll ? Array.from(this.$el.querySelectorAll(this.selectors.join(","))) : [];
},
getInternalButtons() {
return this.$el && this.$el.querySelectorAll ? Array.from(this.$el.querySelectorAll(w)) : [];
},
focusedIndex() {
const t = this.$el && this.$el.querySelector && this.$el.querySelector(this.focusedSelector);
return Math.max(0, this.currentButtons.findIndex((e) => e === t));
},
setTabIndex(t) {
const {
tabIndex: e
} = this.$props;
this.currentButtons.forEach((o, s) => {
o.tabIndex = s === t ? e : -1;
}), this.getInternalButtons().forEach((o) => {
o.tabIndex = -1;
});
},
onKeyDown(t) {
if (this.$props.keyboardNavigation === !1)
return;
const e = t.target;
if (!(t.keyCode === h.left || t.keyCode === h.right) || t.defaultPrevented || this.currentButtons.findIndex((l) => l === e) === -1)
return;
const s = this.focusedIndex();
t.keyCode === h.left ? this.focusButton(s, s - 1) : this.focusButton(s, s + 1);
},
focusButton(t, e) {
const {
tabIndex: o
} = this.$props, s = this.currentButtons[e];
if (s) {
s.tabIndex = o, s.focus();
const l = this.currentButtons[t];
l && (l.tabIndex = -1);
}
},
initOverflow(t, e) {
let o = 200;
const s = [], l = [];
Array.from(t.children).forEach((n, f) => {
o += Math.ceil(n.clientWidth), o <= this.$refs.toolbar.offsetWidth - 50 ? s.push(this.visibleToolsRef[f]) : l.push(this.visibleToolsRef[f]);
}), this.visibleToolsRef = s, this.overFlowToolsRef = l;
},
checkOverflow() {
if (this.$props.overflow === "scroll") {
const t = this.scrollContentRef;
t && (this.isOverflowing = t.scrollWidth > t.clientWidth || t.scrollHeight > t.clientHeight, this.isOverflowing ? this.onContentScroll() : (this.isScrollStartPosition = !0, this.isScrollEndPosition = !0));
} else if (this.$props.overflow === "section" || this.$props.overflow === void 0) {
const t = this.$refs.toolbar;
let e = 0;
if (t) {
const o = t.offsetWidth, s = parseInt(window.getComputedStyle(t).gap || "0", 10), l = Array.from(t.children).reduce((i, r) => (i += Math.ceil(r.clientWidth), i), 0), n = Array.from(t.children).length, f = s * 2;
if (e = 36 + Number(l) + n * s + f, e > o) {
const i = [...this.visibleToolsRef], r = i.pop();
this.visibleToolsRef = i, r && (this.overFlowToolsRef = [r, ...this.overFlowToolsRef]), this.lastToolbarWidthRef = o;
} else if (o > this.lastToolbarWidthRef + s * n / 2.75) {
const i = [...this.overFlowToolsRef], r = i.shift();
r && this.lastToolbarWidthRef + s * n > 30 && (this.overFlowToolsRef = i, this.visibleToolsRef = [...this.visibleToolsRef, r]), this.lastToolbarWidthRef = o;
} else
this.$forceUpdate();
}
}
},
onWindowResize(t) {
window.requestAnimationFrame(() => {
const e = this.$el;
if (this.overFlowOpened = !1, !e)
return;
const o = e.offsetWidth, s = e.offsetHeight;
if (this.offsetWidth !== o || this.offsetHeight !== s) {
this.offsetWidth = o, this.offsetHeight = s;
const l = {
offsetWidth: this.offsetWidth,
offsetHeight: this.offsetHeight
};
this.$emit("resize", {
target: this,
...l,
nativeEvent: t
});
}
this.checkOverflow();
});
},
onContentScroll(t) {
const e = this.scrollContentRef;
if (t && e) {
let o, s;
t === "next" ? o = !1 : e.scrollLeft <= this.$props.buttonScrollSpeed ? o = !0 : o = e.scrollLeft === 0, t === "prev" ? s = !1 : e.scrollLeft + e.clientWidth + this.$props.buttonScrollSpeed >= e.scrollWidth ? s = !0 : s = e.scrollLeft + e.clientWidth === e.scrollWidth, this.isScrollStartPosition = !!o, this.isScrollEndPosition = !!s;
} else
this.isScrollStartPosition = !0, this.isScrollEndPosition = !1;
},
onToggleoverflow(t) {
this.overFlowOpened = t;
}
}
});
export {
I as Toolbar
};