UNPKG

@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
/** * @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 };