@progress/kendo-react-data-tools
Version:
Includes React Pager & React Filter component, an intuitive interface to create complex filter descriptions. KendoReact Data Tools package
224 lines (223 loc) • 9.63 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
*-------------------------------------------------------------------------------------------
*/
"use client";
import * as f from "react";
import g from "prop-types";
import { disableNavigatableContainer as v, focusFirstFocusableChild as y, validatePackage as x, getLicenseMessage as F, Navigation as C, getActiveElement as b, enableNavigatableContainer as A, classNames as T, WatermarkOverlay as G } from "@progress/kendo-react-common";
import { Group as L } from "./Group.mjs";
import { packageMetadata as W } from "../package-metadata.mjs";
const s = {
// Wrapper elements for filter field/operator/value (used in Expression rows)
filterFieldWrapper: ".k-filter-field",
filterOperatorWrapper: ".k-filter-operator",
filterValueWrapper: ".k-filter-value",
// Toolbar container elements
filterToolbar: ".k-filter-toolbar",
toolbarElement: ".k-toolbar",
groupToolbar: ".k-filter-group-main > .k-filter-toolbar > .k-toolbar",
subGroupToolbar: ".k-filter-lines .k-filter-toolbar > .k-toolbar"
}, k = class k extends f.Component {
constructor(r) {
super(r), this.wrapperRef = f.createRef(), this.showLicenseWatermark = !1, this.onFilterChange = (i) => {
const o = {
filter: i.nextFilter,
syntheticEvent: i.syntheticEvent,
nativeEvent: i.nativeEvent,
target: this
};
this.props.onChange.call(void 0, o);
}, this.onGroupRemove = (i) => {
const o = {
filter: { ...this.props.value, filters: [] },
syntheticEvent: i.syntheticEvent,
nativeEvent: i.nativeEvent,
target: this
};
this.props.onChange.call(void 0, o);
}, this.navigateVertical = (i, o, e) => {
if (!e)
return;
const t = e.classList.contains("k-filter-field") || e.classList.contains("k-filter-operator") || e.classList.contains("k-filter-value"), a = e.closest(s.toolbarElement), n = Array.from(o.getElementsByClassName("k-toolbar")), l = n.findIndex((h) => h === a), u = i === "up" ? l - 1 : l + 1, p = n[u];
if (!o.getElementsByClassName("k-filter-lines")[0] || !p)
return;
a && t && v(a, [
s.filterFieldWrapper,
s.filterOperatorWrapper,
s.filterValueWrapper
]), p.querySelectorAll(
`${s.filterFieldWrapper}, ${s.filterOperatorWrapper}, ${s.filterValueWrapper}`
).forEach((h, m) => {
h.tabIndex = m === 0 ? 0 : -1;
});
const d = p.querySelector(
`${s.filterFieldWrapper}, ${s.filterOperatorWrapper}, ${s.filterValueWrapper}`
);
d ? d.focus() : y(p);
}, this.onKeyDown = (i) => {
var o;
(o = this.navigation) == null || o.triggerKeyboardEvent(i);
}, this.showLicenseWatermark = !x(W, { component: "Filter" }), this.licenseMessage = F(W);
}
/**
* @hidden
*/
componentDidMount() {
this.wrapperRef && (this.navigation = new C({
tabIndex: 0,
root: this.wrapperRef,
selectors: [".k-filter"],
keyboardEvents: {
keydown: {
Tab: (r, i, o) => {
const e = r.getElementsByClassName(
"k-filter-lines"
)[0];
e && v(e);
},
Escape: (r, i, o) => {
const e = b(document) || null, t = e == null ? void 0 : e.closest(s.toolbarElement), a = r.querySelector(s.groupToolbar), n = t == null ? void 0 : t.querySelector(".k-toolbar-button-group"), l = t === a || !!n, { isTextInput: u, isCombobox: p } = this.classifyActive(e);
if (!l && t && e !== t)
if (o.preventDefault(), v(t, [
s.filterFieldWrapper,
s.filterOperatorWrapper,
s.filterValueWrapper
]), u || p) {
const c = e == null ? void 0 : e.closest(
`${s.filterFieldWrapper}, ${s.filterOperatorWrapper}, ${s.filterValueWrapper}`
);
c && c.focus();
} else
y(t);
},
ArrowUp: (r, i, o) => {
const e = b(document) || null;
if (!e)
return;
const { isPopup: t, isTextInput: a, isCombobox: n, isWrapper: l } = this.classifyActive(e);
(t || a || n) && !l || (o.preventDefault(), this.navigateVertical("up", r, e));
},
ArrowDown: (r, i, o) => {
const e = b(document) || null;
if (!e)
return;
const { isPopup: t, isTextInput: a, isCombobox: n, isWrapper: l } = this.classifyActive(e);
(t || a || n) && !l || (o.preventDefault(), this.navigateVertical("down", r, e));
},
ArrowRight: (r, i, o) => {
const e = b(document) || null;
if (!e)
return;
const { isTextInput: t } = this.classifyActive(e);
if (t)
return;
o.preventDefault();
const a = e == null ? void 0 : e.nextElementSibling, n = e == null ? void 0 : e.closest(s.toolbarElement), l = r.querySelector(s.groupToolbar), u = n == null ? void 0 : n.querySelector(".k-toolbar-button-group");
e && a && !(n === l || !!u) && a.focus();
},
ArrowLeft: (r, i, o) => {
const e = b(document) || null;
if (!e)
return;
const { isTextInput: t } = this.classifyActive(e);
if (t)
return;
o.preventDefault();
const a = e == null ? void 0 : e.previousElementSibling, n = e == null ? void 0 : e.closest(s.toolbarElement), l = r.querySelector(s.groupToolbar), u = n == null ? void 0 : n.querySelector(".k-toolbar-button-group");
e && a && !(n === l || !!u) && a.focus();
},
Enter: (r, i, o) => {
var p;
o.preventDefault();
const e = b(document) || null;
if (!e)
return;
const t = e == null ? void 0 : e.closest(s.toolbarElement), a = r.getElementsByClassName("k-toolbar"), n = r.querySelector(s.groupToolbar), l = t == null ? void 0 : t.querySelector(
".k-toolbar-button-group"
);
if (t === n || !!l) {
const c = t == null ? void 0 : t.lastElementChild;
c && e === c && c.click();
return;
}
if (t && e) {
const c = e.classList.contains("k-filter-field") || e.classList.contains("k-filter-operator") || e.classList.contains("k-filter-value"), w = t.querySelector('button[title="Remove"]');
if (e === w) {
const h = Array.from(a).findIndex((R) => R === t) - 1, m = (p = a[h]) == null ? void 0 : p.lastElementChild;
e.click(), m && m.focus();
} else c && (A(t, [
s.filterFieldWrapper,
s.filterOperatorWrapper,
s.filterValueWrapper
]), y(e));
}
}
}
}
}));
}
/**
* @hidden
*/
render() {
return /* @__PURE__ */ f.createElement(
"div",
{
className: T("k-filter", this.props.className),
style: this.props.style,
ref: this.wrapperRef,
onKeyDown: this.onKeyDown
},
/* @__PURE__ */ f.createElement("ul", { role: "tree", className: "k-filter-container", "aria-label": this.props.ariaLabel }, /* @__PURE__ */ f.createElement("li", { role: "treeitem", "aria-selected": !1, className: "k-filter-group-main" }, /* @__PURE__ */ f.createElement(
L,
{
filter: this.props.value,
fields: this.props.fields,
ariaLabel: this.props.ariaLabelGroup,
ariaLabelExpression: this.props.ariaLabelExpression,
onChange: this.onFilterChange,
onRemove: this.onGroupRemove,
defaultGroupFilter: this.props.defaultGroupFilter || { logic: "and", filters: [] }
}
))),
this.showLicenseWatermark && /* @__PURE__ */ f.createElement(G, { message: this.licenseMessage })
);
}
/**
* Classifies the currently active element for navigation decisions.
*/
classifyActive(r) {
var n, l;
if (!r)
return { isTextInput: !1, isCombobox: !1, isWrapper: !1, isPopup: !1 };
const i = r.tagName === "INPUT" || r.tagName === "TEXTAREA", o = ((n = r.getAttribute) == null ? void 0 : n.call(r, "role")) === "combobox", e = r.classList, t = !!e && (e.contains("k-filter-field") || e.contains("k-filter-operator") || e.contains("k-filter-value")), a = !!((l = r.closest) != null && l.call(r, ".k-animation-container, .k-popup"));
return { isTextInput: i, isCombobox: o, isWrapper: t, isPopup: a };
}
};
k.propTypes = {
className: g.string,
style: g.object,
fields: function(r, i) {
const o = r[i];
if (o === void 0)
return new Error(`Property '${i}' is missing.`);
if (Array.isArray(o)) {
if (Object.keys(o.reduce((e, t) => ({ ...e, [t.name]: 1 }), {})).length !== o.length)
return new Error(`Property '${i}' needs to contain objects with unique 'name' field.`);
} else return new Error(`Property '${i}' needs to be Array<FieldSettings>.`);
return null;
},
ariaLabelGroup: g.string,
ariaLabelExpression: g.string,
value: g.object.isRequired,
onChange: g.func.isRequired
};
let E = k;
export {
E as Filter,
s as selectors
};