@progress/kendo-react-buttons
Version:
All you need in React Button in one package: disabled/enabled states, built-in styles and more. KendoReact Buttons package
295 lines (294 loc) • 10.4 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 p from "react";
import s from "prop-types";
import { Button as N } from "../Button.mjs";
import { Keys as r, dispatchEvent as l, getActiveElement as f, validatePackage as K, svgIconPropType as A, classNames as u, uDropDownButton as c, WatermarkOverlay as R, ZIndexContext as M, createPropsContext as T, withIdHOC as L, withPropsContext as z, withUnstyledHOC as U, withZIndexContext as Z } from "@progress/kendo-react-common";
import { navigate as $ } from "./utils/navigation.mjs";
import { DropDownButtonItem as W } from "./DropDownButtonItem.mjs";
import { ButtonItem as _ } from "./ButtonItem.mjs";
import { Popup as H } from "@progress/kendo-react-popup";
import { getAnchorAlign as X, getPopupAlign as j } from "./utils/popup.mjs";
import { packageMetadata as q } from "../package-metadata.mjs";
const G = 12e3, J = 2e3, m = class m extends p.Component {
constructor(i) {
super(i), this.state = {
opened: !1,
focused: !1,
focusedIndex: -1
}, this.mainButton = null, this.list = null, this.skipFocus = !1, this.showLicenseWatermark = !1, this.buttonsData = [], this.onKeyDown = (t) => {
const { focusedIndex: e } = this.state;
if (t.altKey) {
!this.opened && t.keyCode === r.down ? (t.preventDefault(), this.setOpen(!0, t), this.setState({ focusedIndex: 0 })) : this.opened && t.keyCode === r.up && (t.preventDefault(), this.setState({ focusedIndex: -1 }), this.setOpen(!1, t));
return;
}
const o = { ...this.state };
if (t.keyCode === r.enter || t.keyCode === r.space) {
t.preventDefault(), e >= 0 && this.dispatchClickEvent(t, e);
const a = !this.opened;
this.setState({
focused: !0,
focusedIndex: a ? 0 : -1
}), this.setOpen(a, t);
return;
}
if (this.opened && t.keyCode === r.esc) {
this.setState({ focusedIndex: -1 }), this.setOpen(!1, t);
return;
}
if (this.opened) {
const a = $(e, t.keyCode, t.altKey, this.buttonsData.length);
o.focusedIndex = a;
const h = t.keyCode === r.up || t.keyCode === r.down || t.keyCode === r.left || t.keyCode === r.right;
!t.altKey && (h || t.keyCode === r.home || t.keyCode === r.end) && t.preventDefault();
}
this.setState(o);
}, this.switchFocus = (t) => {
this.skipFocus = !0, t(), window.setTimeout(() => this.skipFocus = !1, 0);
}, this.handleFocus = (t) => {
this.skipFocus || (this.setState({ focused: !0, focusedIndex: this.opened ? 0 : -1 }), l(this.props.onFocus, t, this, void 0));
}, this.handleButtonBlur = (t) => {
this.opened || (this.setState({ focused: !1 }), l(this.props.onBlur, t, this, void 0));
}, this.handleMenuBlur = (t) => {
this.skipFocus || (this.setState({ focused: !1, focusedIndex: -1 }), l(this.props.onBlur, t, this, void 0), setTimeout(() => {
this.setOpen(!1, t);
}, 0));
}, this.setOpen = (t, e) => {
this.opened !== t && (this.openedDuringOnChange = t, this.setState({ opened: t }), e ? this.dispatchPopupEvent(e, t) : this.openedDuringOnChange = void 0);
}, this.onItemClick = (t, e) => {
this.setState({ focusedIndex: -1 }), this.dispatchClickEvent(t, e), this.setOpen(!1, t);
}, this.onItemDown = (t) => {
f(document) === this.list && t.preventDefault();
}, this.mouseDown = (t) => {
t.preventDefault();
const e = f(document);
this.element && e !== this.element && e !== this.list && this.element.focus();
}, this.onPopupClose = (t) => {
var o;
const e = f(document);
this.element && this.element.removeAttribute("tabindex"), (e === this.list || (o = this.list) != null && o.contains(e)) && this.switchFocus(() => {
this.element && this.element.focus({ preventScroll: !0 });
}), this.props.popupSettings && this.props.popupSettings.onClose && this.props.popupSettings.onClose.call(void 0, t);
}, this.listRef = (t) => {
this.list = t, t && this.state.focused && this.switchFocus(() => {
t.focus({ preventScroll: !0 }), this.element && (this.element.tabIndex = -1);
});
}, this.onClickMainButton = (t) => {
if (!this.buttonsData.length)
return;
const e = !this.opened;
this.setState({
focused: !0,
focusedIndex: e ? 0 : -1
}), this.setOpen(e, t);
}, this.dispatchPopupEvent = (t, e) => {
l(e ? this.props.onOpen : this.props.onClose, t, this, void 0), this.openedDuringOnChange = void 0;
}, this.showLicenseWatermark = !K(q, { component: "DropDownButton" });
}
get guid() {
return this.props.id + "-accessibility-id";
}
get opened() {
return this.openedDuringOnChange !== void 0 ? this.openedDuringOnChange : this.props.opened === void 0 ? this.state.opened : this.props.opened;
}
/**
* @hidden
*/
render() {
const i = this.isRtl(), t = this.props.unstyled && this.props.unstyled.uDropDownButton, e = i ? "rtl" : void 0, {
id: o,
style: a,
tabIndex: h,
disabled: n,
size: C,
rounded: D,
fillMode: y,
themeColor: I,
ariaLabel: k,
title: b,
accessKey: w,
icon: B,
svgIcon: O,
iconClass: x,
buttonClass: E,
className: S,
imageUrl: P,
startIcon: F,
endIcon: v
} = this.props;
return this.buttonsData = this.props.items || p.Children.toArray(this.props.children).filter((d) => d && d.type === W).map((d) => d.props), /* @__PURE__ */ p.createElement(p.Fragment, null, /* @__PURE__ */ p.createElement(
N,
{
id: o,
size: C,
style: a,
rounded: D,
fillMode: y,
themeColor: I,
onClick: this.onClickMainButton,
onMouseDown: this.mouseDown,
onKeyDown: this.onKeyDown,
onFocus: this.handleFocus,
onBlur: this.handleButtonBlur,
"aria-disabled": n ? "true" : void 0,
tabIndex: h,
accessKey: w,
icon: B,
svgIcon: O,
iconClass: x,
className: u(
E,
S,
c.wrapper({
c: t,
focused: this.state.focused,
disabled: n
})
),
imageUrl: P,
dir: e,
ref: (d) => this.mainButton = d && d.element,
type: "button",
"aria-expanded": this.opened ? "true" : "false",
"aria-label": k,
"aria-controls": this.opened ? this.guid : void 0,
title: b,
startIcon: F,
endIcon: v
},
this.props.text
), this.showLicenseWatermark && /* @__PURE__ */ p.createElement(R, null), this.renderPopup(i));
}
/**
* @hidden
*/
componentDidMount() {
(this.props.dir === void 0 && this.isRtl() || this.opened) && this.forceUpdate();
}
/**
* The DOM element of main button.
*/
get element() {
return this.mainButton;
}
dispatchClickEvent(i, t) {
this.isItemDisabled(t) || l(this.props.onItemClick, i, this, {
item: this.buttonsData[t],
itemIndex: t
});
}
renderPopup(i) {
const { popupSettings: t = {}, _zIndex: e, unstyled: o } = this.props, a = e ? e + J : G, h = o && o.uDropDownButton, { focusedIndex: n } = this.state;
return /* @__PURE__ */ p.createElement(M.Provider, { value: a }, /* @__PURE__ */ p.createElement(
H,
{
anchor: this.mainButton,
show: this.opened,
animate: t.animate,
popupClass: u(c.popup({ c: h }), t.popupClass),
anchorAlign: t.anchorAlign || X(i),
popupAlign: t.popupAlign || j(i),
style: i ? { direction: "rtl" } : void 0,
onClose: this.onPopupClose
},
/* @__PURE__ */ p.createElement(
"ul",
{
role: "list",
id: this.guid,
tabIndex: -1,
"aria-activedescendant": n >= 0 ? `${this.guid}-${n}` : void 0,
ref: this.listRef,
onKeyDown: this.onKeyDown,
onBlur: this.handleMenuBlur,
className: u(
c.ul({
c: h,
size: this.props.size
})
)
},
this.renderChildItems()
)
));
}
renderChildItems() {
const { item: i, itemRender: t, textField: e, unstyled: o } = this.props, a = o && o.uDropDownButton;
return this.buttonsData.length > 0 ? this.buttonsData.map((h, n) => /* @__PURE__ */ p.createElement(
_,
{
className: u(
c.item({
c: a
}),
h.className,
{ "k-first": n === 0 },
{ "k-last": n === this.buttonsData.length - 1 }
),
dataItem: h,
textField: e,
focused: this.state.focusedIndex === n,
onClick: this.onItemClick,
onDown: this.onItemDown,
render: t,
item: i,
index: n,
key: n,
id: `${this.guid}-${n}`
}
)) : null;
}
isItemDisabled(i) {
return this.buttonsData[i] ? this.buttonsData[i].disabled : this.props.disabled;
}
isRtl() {
return this.props.dir !== void 0 ? this.props.dir === "rtl" : !!this.mainButton && getComputedStyle(this.mainButton).direction === "rtl";
}
};
m.propTypes = {
accessKey: s.string,
ariaLabel: s.string,
title: s.string,
onFocus: s.func,
onBlur: s.func,
onItemClick: s.func,
onOpen: s.func,
onClose: s.func,
items: s.arrayOf(s.any),
textField: s.string,
tabIndex: s.number,
disabled: s.bool,
icon: s.string,
svgIcon: A,
iconClass: s.string,
imageUrl: s.string,
popupSettings: s.object,
itemRender: s.func,
item: s.func,
className: s.string,
buttonClass: s.string,
dir: s.string
}, m.defaultProps = {
size: "medium",
rounded: "medium",
fillMode: "solid",
themeColor: "base"
};
let g = m;
const Q = T(), V = L(
z(
Q,
U(Z(g))
)
);
V.displayName = "KendoReactDropDownButton";
export {
V as DropDownButton,
Q as DropDownButtonPropsContext,
g as DropDownButtonWithoutContext
};