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