@progress/kendo-react-grid
Version:
React Data Grid (Table) provides 100+ ready-to-use data grid features. KendoReact Grid package
313 lines (312 loc) • 13.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 * as r from "react";
import Ae from "react-dom";
import { useDocument as Le, SvgIcon as Oe, IconWrap as Te, useAsyncFocusBlur as Ge, classNames as Pe, clone as Ve, getActiveElement as qe } from "@progress/kendo-react-common";
import { GridColumnMenuItem as ze } from "../columnMenu/GridColumnMenuItem.mjs";
import { GridColumnMenuItemContent as Ke } from "../columnMenu/GridColumnMenuItemContent.mjs";
import { GridColumnMenuItemGroup as je } from "../columnMenu/GridColumnMenuItemGroup.mjs";
import { GridContext as He } from "../utils/GridContext.mjs";
import { filterIcon as ie, searchIcon as We, xIcon as _e, filterClearIcon as $e } from "@progress/kendo-svg-icons";
import { filterBy as ce } from "@progress/kendo-data-query";
import { Button as b } from "@progress/kendo-react-buttons";
import { Input as Je, Checkbox as se } from "@progress/kendo-react-inputs";
import { filterClearButton as B, messages as g, searchPlaceholder as ue, toolbarCheckboxFilter as D, filterCheckAll as fe, filterSelectedItems as me, filterSubmitButton as de, filterClearAllButton as ge } from "../messages/index.mjs";
import { useLocalization as Qe } from "@progress/kendo-react-intl";
import { getNestedValue as he } from "../utils/index.mjs";
import { isArrayEqual as Ue } from "../columnMenu/GridColumnMenuCheckboxFilter.mjs";
import { GridAdaptiveToolbarCheckboxFilter as Xe } from "./adaptiveContent/GridAdaptiveToolbarCheckboxFilter.mjs";
import { Popup as Ye } from "@progress/kendo-react-popup";
import { BadgeContainer as Ze, Badge as Re } from "@progress/kendo-react-indicators";
import { GridToolbarAdaptiveProvider as et } from "./adaptiveContext/GridToolbarAdaptiveContext.mjs";
const tt = {
uniqueData: !0
}, rt = (a) => {
var ae, oe;
const { uniqueData: h = tt.uniqueData, svgIcon: P, icon: V } = a, i = r.useContext(He), k = i.columnsRef, v = i.defaultFilter, [S, x] = r.useState(!1), p = r.useRef(null), I = r.useRef(null), q = r.useRef(null), N = r.useRef(0), m = Qe(), o = r.useRef(null), ke = Le(p), y = () => v ? Ve(v) : { filters: [], logic: "and" }, Ee = () => {
var n;
const e = (n = o == null ? void 0 : o.current) == null ? void 0 : n.field;
return y().filters.findIndex(
(s) => s.filters && s.filters.length > 0 && s.filters[0].field === e
);
}, E = (e, t) => {
var s;
const l = ((s = o == null ? void 0 : o.current) == null ? void 0 : s.field) || "", n = e.map((u) => he(l, u));
return t ? n.filter((u, w) => n.indexOf(u) === w) : n;
}, c = r.useRef(Ee()), [pe, F] = r.useState(!1), [d, z] = r.useState(
(k == null ? void 0 : k.map((e) => ({ column: e, expanded: !1 }))) || []
), [K, j] = r.useState(""), [M, C] = r.useState(E(a.data, h) || []), [H, W] = r.useState(E(a.data, !1) || []), [f, _] = r.useState(y()), [Ce, $] = r.useState(!1), be = m.toLanguageString(B, g[B]), J = r.useMemo(
() => (k == null ? void 0 : k.filter((e) => {
var t;
return (t = e.title || e.field) == null ? void 0 : t.toLowerCase();
})) || [],
[k]
);
r.useEffect(() => {
v && F(!0);
}, [v]), r.useEffect(() => {
var l;
const e = ((l = o == null ? void 0 : o.current) == null ? void 0 : l.field) || "", t = a.data.map((n) => he(e, n));
Ue(t, H) || (C(t), W(t));
}, [H, a.data]), r.useEffect(() => {
d.find((e) => e.expanded) && C(E(a.data, h) || []);
}, [d, a.data, h]);
const Q = r.useCallback(
(e) => {
const t = f.filters.some((l) => l.field === e.field);
return /* @__PURE__ */ r.createElement(r.Fragment, null, e.title || e.field, t && /* @__PURE__ */ r.createElement("span", { className: "k-columnmenu-indicators" }, /* @__PURE__ */ r.createElement(Oe, { key: 1, icon: ie })));
},
[f]
), U = r.useCallback((e, t) => {
z((l) => (o.current = t, l.map((n) => n.column.field === t.field ? { ...n, expanded: !n.expanded } : { ...n, expanded: !1 }))), C(E(a.data, h) || []), W(E(a.data, h) || []), $(!Ce);
}, []), X = (e) => {
var n;
const t = a.searchBoxFilterOperator ? a.searchBoxFilterOperator : "startswith", l = {
logic: "and",
filters: [
{
field: (n = o == null ? void 0 : o.current) == null ? void 0 : n.field,
operator: t,
value: e.target.value,
ignoreCase: !0
}
]
};
j(e.target.value), C(E(ce(a.data || [], l), h));
}, ve = () => {
var l;
const e = a.searchBoxFilterOperator ? a.searchBoxFilterOperator : "startswith", t = {
logic: "and",
filters: [
{ field: (l = o == null ? void 0 : o.current) == null ? void 0 : l.field, operator: e, value: "", ignoreCase: !0 }
]
};
j(""), C(E(ce(a.data || [], t), h));
}, Y = () => {
let e = !1;
if (f) {
const t = [...f.filters];
return c.current === -1 ? !1 : (e = M.every((l) => c.current !== -1 && t[c.current].filters ? t[c.current].filters.findIndex(
(s) => s.value === l
) >= 0 : !1), e);
}
return e;
}, A = (e, t) => {
var w;
const l = ((w = o == null ? void 0 : o.current) == null ? void 0 : w.field) || "", n = { ...f }, s = [...f.filters];
let u = [];
if (c.current !== -1 && n.filters[c.current].filters && t !== "all" && (u = n.filters[c.current].filters), e.value && t === "all")
M.forEach((G) => {
u.push({ field: l, operator: "eq", value: G });
});
else if (e.value)
u.push({ field: l, operator: "eq", value: t });
else if (f) {
const G = u.findIndex((ye) => ye.value === t);
u.splice(G, 1);
}
n.logic = "and", c.current !== -1 ? s[c.current] = {
logic: "or",
filters: u
} : s.push({
logic: "or",
filters: u
}), (!e.value && t === "all" || u.length === 0) && s.splice(c.current, 1), n.filters = s, _(n);
}, L = [];
if (f) {
const e = [...f.filters];
c.current = e.findIndex((t) => {
var l;
return t.filters && t.filters.length > 0 ? t.filters[0].field === ((l = o == null ? void 0 : o.current) == null ? void 0 : l.field) : !1;
}), c.current !== -1 && e[c.current].filters.length > 0 && e[c.current].filters.forEach((t) => {
var l;
t.field === ((l = o == null ? void 0 : o.current) == null ? void 0 : l.field) && L.push(t.value);
});
}
const O = L.filter((e, t) => L.indexOf(e) === t), Z = (e) => {
if (e.preventDefault(), !i.filterChange)
return;
const t = f || null;
t !== null && t.filters.length > 0 ? (c.current >= 0 && t.filters.splice(c.current, 1), i.filterChange(t, e)) : i.filterChange(null, e), a.onCloseMenu && a.onCloseMenu(), F(!1);
}, R = (e) => {
if (e.preventDefault(), !i.filterChange)
return;
const t = f || null;
i.filterChange(t, e), a.onCloseMenu && a.onCloseMenu(), F(!0), x(!1);
}, ee = a.searchBox ? /* @__PURE__ */ r.createElement(a.searchBox, { value: K, onChange: X }) : /* @__PURE__ */ r.createElement(
"div",
{
className: `k-searchbox k-textbox k-input k-input-solid ${i != null && i.mobileMode ? "k-input-lg" : "k-input-md"}`
},
/* @__PURE__ */ r.createElement(Te, { className: "k-input-icon", name: "search", icon: We }),
/* @__PURE__ */ r.createElement(
Je,
{
className: "k-input-inner",
type: "text",
placeholder: m.toLanguageString(ue, g[ue]),
value: K,
onChange: (e) => X(e.nativeEvent)
}
),
/* @__PURE__ */ r.createElement(
b,
{
type: "button",
rounded: null,
className: "k-input-button",
onClick: ve,
icon: "x",
"aria-label": be,
svgIcon: _e
}
)
), xe = () => {
$(!1);
}, Fe = (e) => {
e.preventDefault(), x(!S);
}, Me = (e) => {
!e.isAnchorClicked && x(!1);
}, T = r.useMemo(() => a.show !== void 0 ? a.show : S, [a.show, S]), we = (e) => {
const t = qe(document);
clearTimeout(N.current), N.current = window.setTimeout(() => {
!i.mobileMode && t && e.relatedTarget !== p.current && I.current && !I.current.contains(t) && te();
});
}, te = () => {
var e;
a.onCloseMenu && a.onCloseMenu(), x(!1), p.current && ((e = p.current.element) == null || e.focus());
}, Be = () => {
clearTimeout(N.current);
}, { onFocus: De, onBlur: Se } = Ge({
onFocus: (e) => Be(),
onBlur: (e) => we(e)
}), Ie = (e) => {
var t;
(t = q.current) == null || t.triggerMouseEvent(e);
}, Ne = (e) => {
var t;
(t = q.current) == null || t.triggerKeyboardEvent(e);
}, re = (e) => {
if (e.preventDefault(), !i.filterChange)
return;
const t = f || null;
t !== null && t.filters.length > 0 ? (t.filters = [], i.filterChange(t, e)) : i.filterChange(null, e), _(y()), F(!1), z(
(l) => l.map((n) => ({
...n,
expanded: !1
}))
);
}, ne = /* @__PURE__ */ r.createElement(
b,
{
ref: p,
togglable: !0,
selected: T,
svgIcon: P || (V ? void 0 : ie),
icon: V,
size: i.mobileMode ? "large" : "medium",
className: Pe("k-toolbar-button", {
"k-icon-button": i.mobileMode
}),
title: m.toLanguageString(D, g[D]),
onClick: Fe
},
!i.mobileMode && m.toLanguageString(D, g[D])
), le = /* @__PURE__ */ r.createElement(r.Fragment, null, J.map((e) => {
var t, l;
return e.filterable && /* @__PURE__ */ r.createElement(je, { key: e.id }, /* @__PURE__ */ r.createElement("div", { className: "k-expander" }, /* @__PURE__ */ r.createElement(
ze,
{
title: Q(e),
expandable: !0,
expanded: !!((t = d == null ? void 0 : d.find((n) => n.column.field === e.field)) != null && t.expanded),
onClick: (n) => U(n, e)
}
)), /* @__PURE__ */ r.createElement(
Ke,
{
show: !!((l = d == null ? void 0 : d.find((n) => n.column.field === e.field)) != null && l.expanded)
},
/* @__PURE__ */ r.createElement("form", { className: "k-filter-menu", onSubmit: R, onReset: Z }, /* @__PURE__ */ r.createElement("div", { className: "k-filter-menu-container" }, ee, /* @__PURE__ */ r.createElement("ul", { className: "k-multicheck-wrap" }, /* @__PURE__ */ r.createElement("li", { className: "k-item k-check-all-wrap" }, /* @__PURE__ */ r.createElement(
se,
{
label: m.toLanguageString(
fe,
g[fe]
),
onChange: (n) => A(n, "all"),
checked: Y()
}
)), M.map((n, s) => /* @__PURE__ */ r.createElement("li", { className: "k-item", key: s }, /* @__PURE__ */ r.createElement(
se,
{
label: String(n),
onChange: (u) => A(u, n),
checked: O.includes(n)
}
)))), /* @__PURE__ */ r.createElement("div", { className: "k-filter-selected-items" }, O.length + " " + m.toLanguageString(
me,
g[me]
)), /* @__PURE__ */ r.createElement("div", { className: "k-actions k-hstack k-justify-content-stretch" }, /* @__PURE__ */ r.createElement(b, { themeColor: "primary", type: "submit" }, m.toLanguageString(
de,
g[de]
)), /* @__PURE__ */ r.createElement(b, { className: "k-button", type: "reset" }, m.toLanguageString(
B,
g[B]
)))))
));
}), /* @__PURE__ */ r.createElement("div", { className: "k-actions k-actions-stretched k-actions-horizontal k-column-menu-footer" }, /* @__PURE__ */ r.createElement(b, { svgIcon: $e, onClick: re }, m.toLanguageString(ge, g[ge]))));
return /* @__PURE__ */ r.createElement(r.Fragment, null, pe ? /* @__PURE__ */ r.createElement(Ze, null, ne, /* @__PURE__ */ r.createElement(Re, { themeColor: "primary" })) : ne, i.mobileMode ? /* @__PURE__ */ r.createElement(et, null, Ae.createPortal(
/* @__PURE__ */ r.createElement(
Xe,
{
filtered: J,
computedShow: T,
expandState: d,
currentData: M,
uniqueFilterValues: O,
searchBox: ee,
renderTitle: Q,
onBackView: xe,
isAllSelected: Y,
handleCheckBoxChange: A,
clear: Z,
submit: R,
onClose: te,
onFilterExpand: U,
handleClearAllFilters: re
},
le
),
(ae = ke()) == null ? void 0 : ae.body
)) : /* @__PURE__ */ r.createElement(
Ye,
{
anchor: (oe = p.current) == null ? void 0 : oe.element,
show: T,
popupClass: "k-grid-columnmenu-popup",
onMouseDownOutside: Me
},
/* @__PURE__ */ r.createElement(
"div",
{
ref: I,
onBlur: Se,
onFocus: De,
onMouseDown: Ie,
onKeyDown: Ne,
className: "k-column-menu k-column-menu-md"
},
le
)
));
};
rt.displayName = "KendoReactGridToolbarCheckboxFilter";
export {
rt as GridToolbarCheckboxFilter
};