persist a advance filter obj

This commit is contained in:
pramod.mahajan 2025-12-24 21:00:17 +05:30
parent c51c6978e9
commit a5bfad7214
5 changed files with 290 additions and 259 deletions

View File

@ -0,0 +1,119 @@
import { useState, useEffect } from "react";
const OPERATORS = {
number: [
{ key: "eq", label: "Equals" },
{ key: "neq", label: "Not Equal" },
{ key: "gt", label: "Greater Than" },
{ key: "gte", label: "Greater or Equal" },
{ key: "lt", label: "Less Than" },
{ key: "lte", label: "Less or Equal" },
{ key: "between", label: "Between" },
],
text: [
{ key: "contains", label: "Contains" },
{ key: "starts", label: "Starts With" },
{ key: "ends", label: "Ends With" },
{ key: "eq", label: "Equals" },
],
date: [
{ key: "before", label: "Before" },
{ key: "after", label: "After" },
{ key: "between", label: "Between" },
],
};
export function AdvanceFilter({
type = "number",
value,
onApply,
onClear,
}) {
const [operation, setOperation] = useState("");
const [v1, setV1] = useState("");
const [v2, setV2] = useState("");
useEffect(() => {
if (!value) {
setOperation("");
setV1("");
setV2("");
return;
}
setOperation(value.operation);
setV1(value.value ?? value.from ?? "");
setV2(value.to ?? "");
}, [value]);
const apply = () => {
if (!operation) return;
onApply(
operation === "between"
? { operation, from: v1, to: v2 }
: { operation, value: v1 }
);
};
return (
<div style={{ width: 240 }} onClick={(e) => e.stopPropagation()}>
<div className="mb-2">
<label className="form-label">Condition</label>
<select
className="form-select form-select-sm"
value={operation}
onChange={(e) => setOperation(e.target.value)}
>
<option value="">Select</option>
{OPERATORS[type].map((o) => (
<option key={o.key} value={o.key}>
{o.label}
</option>
))}
</select>
</div>
{operation && (
<div className="mb-2">
<label className="form-label">Value</label>
{operation !== "between" ? (
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
value={v1}
onChange={(e) => setV1(e.target.value)}
/>
) : (
<div className="d-flex gap-2">
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
placeholder="From"
value={v1}
onChange={(e) => setV1(e.target.value)}
/>
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
placeholder="To"
value={v2}
onChange={(e) => setV2(e.target.value)}
/>
</div>
)}
</div>
)}
<div className="d-flex justify-content-between mt-3">
<button className="btn btn-label-secondary btn-xs" onClick={onClear}>
Clear
</button>
<button className="btn btn-primary btn-xs" onClick={apply}>
Apply
</button>
</div>
</div>
);
}

View File

@ -23,7 +23,7 @@ export default function PmsGrid({
features = {}, features = {},
renderExpanded, renderExpanded,
}) { }) {
const [isFullScreen,setFullScreen] = useState(false) const [isFullScreen, setFullScreen] = useState(false);
const grid = useGridCore({ const grid = useGridCore({
data, data,
serverMode, serverMode,
@ -59,8 +59,11 @@ export default function PmsGrid({
expanded, expanded,
toggleExpand, toggleExpand,
setColState, setColState,
onAdvanceFilters, // onAdvanceFilters,
setAdanceFilter, // setAdanceFilter,
advanceFilters,
setColumnAdvanceFilter,
} = grid; } = grid;
// --- Pin / Unpin helpers --- // --- Pin / Unpin helpers ---
@ -149,7 +152,11 @@ export default function PmsGrid({
const currentRows = rows; const currentRows = rows;
return ( return (
<div className={`pms-grid ${isFullScreen ? "card card-action card-fullscreen p-4":""}`}> <div
className={`pms-grid ${
isFullScreen ? "card card-action card-fullscreen p-4" : ""
}`}
>
<div className="row px-4"> <div className="row px-4">
<div className="col-8"> <div className="col-8">
<div className="d-flex flex-row gap-2 gap-2 "> <div className="d-flex flex-row gap-2 gap-2 ">
@ -218,14 +225,22 @@ export default function PmsGrid({
} }
/> />
)} )}
<i className={`bx bx-${isFullScreen ? "exit-fullscreen":"fullscreen"} cursor-pointer`} onClick={()=>setFullScreen(!isFullScreen)}></i> <i
className={`bx bx-${
isFullScreen ? "exit-fullscreen" : "fullscreen"
} cursor-pointer`}
onClick={() => setFullScreen(!isFullScreen)}
></i>
</div> </div>
</div> </div>
</div> </div>
<div className="d-flex"> <div className="d-flex">
<FilterApplied groupBy={groupBy} removeGroupby={()=>setGroupBy(null)} advance={onAdvanceFilters} /> <FilterApplied
groupBy={groupBy}
removeGroupby={() => setGroupBy(null)}
advance={advanceFilters}
/>
</div> </div>
{/* Table-Start*/} {/* Table-Start*/}
<div <div
@ -322,7 +337,8 @@ export default function PmsGrid({
onPinLeft={() => pinColumn(col.key, "left")} onPinLeft={() => pinColumn(col.key, "left")}
onPinRight={() => pinColumn(col.key, "right")} onPinRight={() => pinColumn(col.key, "right")}
onUnpin={() => unpinColumn(col.key)} onUnpin={() => unpinColumn(col.key)}
onAdvancedFilter={setAdanceFilter} advanceFilters={advanceFilters}
setColumnAdvanceFilter={setColumnAdvanceFilter}
/> />
)} )}
{features.resizing && ( {features.resizing && (
@ -411,7 +427,8 @@ export default function PmsGrid({
</option> </option>
))} ))}
</select> </select>
)} <small>{totalRows} rows</small> )}{" "}
<small>{totalRows} rows</small>
</div> </div>
<div> <div>
<button <button

View File

@ -1,155 +1,42 @@
import { useState, useRef, useEffect } from "react"; import { useState, useRef, useEffect } from "react";
import { useDropdownPosition } from "./useGridCore"; import { useDropdownPosition } from "./useGridCore";
import { AdvanceFilter } from "./AdvanceFilter";
const OPERATORS = {
number: [
{ key: "eq", label: "Equals" },
{ key: "neq", label: "Not Equal" },
{ key: "gt", label: "Greater Than" },
{ key: "gte", label: "Greater or Equal" },
{ key: "lt", label: "Less Than" },
{ key: "lte", label: "Less or Equal" },
{ key: "between", label: "Between" },
],
text: [
{ key: "contains", label: "Contains" },
{ key: "starts", label: "Starts With" },
{ key: "ends", label: "Ends With" },
{ key: "eq", label: "Equals" },
],
date: [
{ key: "before", label: "Before" },
{ key: "after", label: "After" },
{ key: "between", label: "Between" },
],
};
// ----------- FILTER UI COMPONENT ----------
function AdvanceFilter({ type = "number", onApply, onClear }) {
const [operation, setOperator] = useState("");
const [value1, setValue1] = useState("");
const [value2, setValue2] = useState("");
const ops = OPERATORS[type];
const apply = () => {
if (!operation) return;
if (operation === "between") {
onApply({
operation,
from: value1,
to: value2,
});
} else {
onApply({
operation,
value: value1,
});
}
};
return (
<div
className=""
onClick={(e) => e.stopPropagation()}
style={{ width: 240 }}
>
<div className="mb-2">
<label className="form-label text-decoration-none">Condition</label>
<select
className="form-select form-select-sm"
value={operation}
onChange={(e) => setOperator(e.target.value)}
>
<option value="">Select</option>
{ops.map((o) => (
<option key={o.key} value={o.key}>
{o.label}
</option>
))}
</select>
</div>
{/* Values */}
{operation && (
<div className="text-decoration-none">
<label className="form-label">Value</label>
{operation !== "between" ? (
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
value={value1}
onChange={(e) => setValue1(e.target.value)}
/>
) : (
<div className="d-flex gap-2">
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
placeholder="From"
value={value1}
onChange={(e) => setValue1(e.target.value)}
/>
<input
type={type === "date" ? "date" : "number"}
className="form-control form-control-sm"
placeholder="To"
value={value2}
onChange={(e) => setValue2(e.target.value)}
/>
</div>
)}
</div>
)}
{/* Buttons */}
<div className="d-flex flex-row mt-3">
<button className="btn btn-primary btn-xs" onClick={apply}>
Apply
</button>
</div>
</div>
);
}
// -------- HEADER OPTION ---------------
const PmsHeaderOption = ({ const PmsHeaderOption = ({
column, column,
pinned, pinned,
onPinLeft, onPinLeft,
onPinRight, onPinRight,
onUnpin, onUnpin,
onAdvancedFilter,
}) => {
const { key: columnKey, enableAdvancedFilter } = column;
const rootRef = useRef(null);
// from useGridCore
advanceFilters,
setColumnAdvanceFilter,
}) => {
const {
key: columnKey,
enableAdvancedFilter,
filterType = "number",
} = column;
const rootRef = useRef(null);
const btnRef = useRef(null); const btnRef = useRef(null);
const menuRef = useRef(null); const menuRef = useRef(null);
const filterBtnRef = useRef(null); const filterBtnRef = useRef(null);
const filterMenuRef = useRef(null); const filterMenuRef = useRef(null);
const pinBtnRef = useRef(null); const pinBtnRef = useRef(null);
const pinMenuRef = useRef(null); const pinMenuRef = useRef(null);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [openMenu, setOpenMenu] = useState(null); const [openMenu, setOpenMenu] = useState(null);
// Main dropdown position
const mainStyle = useDropdownPosition(btnRef, menuRef, open, 0); const mainStyle = useDropdownPosition(btnRef, menuRef, open, 0);
// Submenus
const filterStyle = useDropdownPosition( const filterStyle = useDropdownPosition(
filterBtnRef, filterBtnRef,
filterMenuRef, filterMenuRef,
openMenu === "filter", openMenu === "filter",
1 1
); );
const pinStyle = useDropdownPosition( const pinStyle = useDropdownPosition(
pinBtnRef, pinBtnRef,
pinMenuRef, pinMenuRef,
@ -159,54 +46,47 @@ const PmsHeaderOption = ({
const toggleMenu = (name, e) => { const toggleMenu = (name, e) => {
e.stopPropagation(); e.stopPropagation();
setOpenMenu((prev) => (prev === name ? null : name)); setOpenMenu((p) => (p === name ? null : name));
}; };
// ----------------------------
// CLOSE WHEN CLICKING OUTSIDE
// ----------------------------
useEffect(() => { useEffect(() => {
const handleOutside = (e) => { const close = (e) => {
if (!rootRef.current) return; if (!rootRef.current?.contains(e.target)) {
if (!rootRef.current.contains(e.target)) {
setOpen(false); setOpen(false);
setOpenMenu(null); setOpenMenu(null);
} }
}; };
if (open) document.addEventListener("mousedown", close);
if (open) document.addEventListener("mousedown", handleOutside); return () => document.removeEventListener("mousedown", close);
return () => document.removeEventListener("mousedown", handleOutside);
}, [open]); }, [open]);
// {}
console.log(advanceFilters);
console.log(columnKey);
return ( return (
<div <div ref={rootRef} style={{ position: "relative", zIndex: 9999 }}>
ref={rootRef}
className="dropdown "
style={{ zIndex: 9999, position: "relative" }}
>
{/* BUTTON */}
<button <button
ref={btnRef} ref={btnRef}
className="btn btn-icon btn-text-secondary rounded-pill p-0" class="btn btn-icon btn-text-secondary rounded-pill d-inline-block"
onClick={() => setOpen((p) => !p)} onClick={() => setOpen((p) => !p)}
> >
<i className="bx bx-dots-vertical-rounded bx-sm text-muted"></i> <span className="icon-base bx bx-dots-vertical-rounded bx-sm"></span>
{advanceFilters[columnKey] && (
<span className="badge rounded-pill bg-info badge-dot badge-notifications"></span>
)}
</button> </button>
{/* MAIN MENU */}
{open && ( {open && (
<ul <ul
ref={menuRef} ref={menuRef}
className="dropdown-menu dropdown-menu-end shadow border rounded-3 py-2 show" className="dropdown-menu dropdown-menu-end shadow rounded-3 py-2 show"
style={mainStyle} style={mainStyle}
> >
{/* ADVANCED FILTER */} {/* ADVANCED FILTER */}
{enableAdvancedFilter && ( {enableAdvancedFilter && (
<li className="dropdown-submenu dropstart position-relative"> <li className="dropdown-submenu dropstart">
<button <button
ref={filterBtnRef} ref={filterBtnRef}
className="dropdown-item d-flex justify-content-between py-1 px-2 " className="dropdown-item d-flex justify-content-between py-1 px-2"
onClick={(e) => toggleMenu("filter", e)} onClick={(e) => toggleMenu("filter", e)}
> >
<span> <span>
@ -218,26 +98,25 @@ const PmsHeaderOption = ({
{openMenu === "filter" && ( {openMenu === "filter" && (
<ul <ul
ref={filterMenuRef} ref={filterMenuRef}
className="dropdown-menu shadow rounded-3 py-2 p-0 show" className="dropdown-menu shadow rounded-3 p-2 show"
style={filterStyle} style={filterStyle}
> >
<li className="p-2"> <AdvanceFilter
<AdvanceFilter type={filterType}
type="number" value={advanceFilters[columnKey]}
onApply={(f) => onAdvancedFilter({ ...f, columnKey })} onApply={(f) => setColumnAdvanceFilter(columnKey, f)}
onClear={() => onAdvancedFilter(null)} onClear={() => setColumnAdvanceFilter(columnKey, null)}
/> />
</li>
</ul> </ul>
)} )}
</li> </li>
)} )}
{/* PIN COLUMN */} {/* PIN */}
<li className="dropdown-submenu dropstart position-relative"> <li className="dropdown-submenu dropstart">
<button <button
ref={pinBtnRef} ref={pinBtnRef}
className="dropdown-item d-flex justify-content-between py-1 px-2 " className="dropdown-item d-flex justify-content-between py-1 px-2"
onClick={(e) => toggleMenu("pin", e)} onClick={(e) => toggleMenu("pin", e)}
> >
<span> <span>
@ -249,39 +128,18 @@ const PmsHeaderOption = ({
{openMenu === "pin" && ( {openMenu === "pin" && (
<ul <ul
ref={pinMenuRef} ref={pinMenuRef}
className=" dropdown-menu dropdown-menu-end shadow border rounded-3 py-2 show" className="dropdown-menu shadow rounded-3 py-2 show"
style={pinStyle} style={pinStyle}
> >
<li> <button className="dropdown-item" onClick={onUnpin}>
<button className="dropdown-item py-1 px-2" onClick={onUnpin}> No Pin
{!pinned && <i className="bx bx-check me-2"></i>} </button>
No Pin <button className="dropdown-item" onClick={onPinLeft}>
</button> Pin Left
</li> </button>
<button className="dropdown-item" onClick={onPinRight}>
<li> Pin Right
<button </button>
className={`dropdown-item py-1 px-2 ${
pinned === "left" ? "active" : ""
}`}
onClick={onPinLeft}
>
{pinned === "left" && <i className="bx bx-check me-2"></i>}
Pin Left
</button>
</li>
<li>
<button
className={`dropdown-item py-1 px-2 ${
pinned === "right" ? "active" : ""
}`}
onClick={onPinRight}
>
{pinned === "right" && <i className="bx bx-check me-2"></i>}
Pin Right
</button>
</li>
</ul> </ul>
)} )}
</li> </li>

View File

@ -6,6 +6,8 @@ import { useState, useMemo, useCallback, useEffect,useLayoutEffect } from "react
- rowKey - rowKey
- initialPageSize - initialPageSize
*/ */
export function useGridCore({ export function useGridCore({
data, data,
serverMode = false, serverMode = false,
@ -19,47 +21,57 @@ export function useGridCore({
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [debouncedSearch, setDebouncedSearch] = useState(""); const [debouncedSearch, setDebouncedSearch] = useState("");
const [groupBy, setGroupBy] = useState(null); const [groupBy, setGroupBy] = useState(null);
const [serverGroupRows, setServerGroupRows] = useState(null);
const [onAdvanceFilter, setAdanceFilter] = useState(null); // FIX: store ADVANCED FILTERS PER COLUMN
// { amount: { columnKey, operation, value } }
const [advanceFilters, setAdvanceFilters] = useState({});
const [sortBy, setSortBy] = useState({ key: null, dir: "asc" }); const [sortBy, setSortBy] = useState({ key: null, dir: "asc" });
const [selected, setSelected] = useState(new Set()); const [selected, setSelected] = useState(new Set());
const [expanded, setExpanded] = useState(new Set()); const [expanded, setExpanded] = useState(new Set());
const [colState, setColState] = useState(() => const [colState, setColState] = useState(() =>
columns.map((c, i) => ({ ...c, visible: c.visible !== false, order: i })) columns.map((c, i) => ({
...c,
visible: c.visible !== false,
order: i,
}))
); );
const [totalRows, setTotalRows] = useState(data ? data.length : 0); const [totalRows, setTotalRows] = useState(data ? data.length : 0);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [serverRows, setServerRows] = useState([]); const [serverRows, setServerRows] = useState([]);
/* ---------------- SEARCH (DEBOUNCE) ---------------- */
useEffect(() => { useEffect(() => {
const handler = setTimeout(() => { const handler = setTimeout(() => {
setDebouncedSearch(search); setDebouncedSearch(search);
setPage(1); // Important — when search changes, go back to page 1 setPage(1);
}, 500); }, 500);
return () => clearTimeout(handler); return () => clearTimeout(handler);
}, [search]); }, [search]);
// client-side derived rows /* ---------------- CLIENT MODE ---------------- */
const clientFiltered = useMemo(() => { const clientFiltered = useMemo(() => {
if (!data) return []; if (!data) return [];
const q = (search || "").toLowerCase();
const filtered = q let filtered = data;
? data.filter((r) =>
Object.values(r).some((v) => if (search) {
String(v ?? "") const q = search.toLowerCase();
.toLowerCase() filtered = filtered.filter((r) =>
.includes(q) Object.values(r).some((v) =>
) String(v ?? "").toLowerCase().includes(q)
) )
: data; );
// sort if needed }
if (sortBy.key) { if (sortBy.key) {
const dir = sortBy.dir === "asc" ? 1 : -1; const dir = sortBy.dir === "asc" ? 1 : -1;
filtered.sort((a, b) => { filtered = [...filtered].sort((a, b) => {
const A = a[sortBy.key], const A = a[sortBy.key];
B = b[sortBy.key]; const B = b[sortBy.key];
if (A == null && B == null) return 0; if (A == null && B == null) return 0;
if (A == null) return -1 * dir; if (A == null) return -1 * dir;
if (B == null) return 1 * dir; if (B == null) return 1 * dir;
@ -68,14 +80,17 @@ export function useGridCore({
return String(A).localeCompare(String(B)) * dir; return String(A).localeCompare(String(B)) * dir;
}); });
} }
setTotalRows(filtered.length); setTotalRows(filtered.length);
const start = (page - 1) * pageSize; const start = (page - 1) * pageSize;
return filtered.slice(start, start + pageSize); return filtered.slice(start, start + pageSize);
}, [data, search, sortBy, page, pageSize]); }, [data, search, sortBy, page, pageSize]);
// server-side fetch /* ---------------- SERVER MODE ---------------- */
const fetchServer = useCallback(async () => { const fetchServer = useCallback(async () => {
// sorting column wise if (!serverMode || typeof fetcher !== "function") return;
const sortFilters = sortBy.key const sortFilters = sortBy.key
? [ ? [
{ {
@ -85,22 +100,15 @@ export function useGridCore({
] ]
: []; : [];
// ----------------------------- // convert map → array
// 3. ADVANCED FILTERS (NUMERIC FILTER POPOVER) const advanceFilterArray = Object.values(advanceFilters);
// The grid will pass "filter" already shaped like:
// filter = { totalAmount: { type: "gt", value: 200 } }
// -----------------------------
let advanceFilters = [];
if (onAdvanceFilter) {
advanceFilters.push(onAdvanceFilter);
}
const filterPayload = JSON.stringify({ const filterPayload = JSON.stringify({
sortFilters, sortFilters,
groupByColumn: groupBy || null, groupByColumn: groupBy || null,
advanceFilters, advanceFilters: advanceFilterArray,
}); });
if (!serverMode || typeof fetcher !== "function") return;
setLoading(true); setLoading(true);
try { try {
const resp = await fetcher({ const resp = await fetcher({
@ -110,9 +118,9 @@ export function useGridCore({
search: debouncedSearch, search: debouncedSearch,
filter: filterPayload, filter: filterPayload,
}); });
// expected: { rows: [], total }
setServerRows(resp.rows || []); setServerRows(resp?.rows || []);
setTotalRows(resp.total || (resp.rows ? resp.rows.length : 0)); setTotalRows(resp?.total ?? resp?.rows?.length ?? 0);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@ -124,14 +132,35 @@ export function useGridCore({
sortBy, sortBy,
debouncedSearch, debouncedSearch,
groupBy, groupBy,
onAdvanceFilter, advanceFilters,
]); ]);
useEffect(() => { useEffect(() => {
if (serverMode) fetchServer(); if (serverMode) fetchServer();
}, [serverMode, fetchServer]); }, [serverMode, fetchServer]);
// selection /* ---------------- ADVANCED FILTER API ---------------- */
const setColumnAdvanceFilter = useCallback((columnKey, filter) => {
setAdvanceFilters((prev) => {
if (!filter) {
const copy = { ...prev };
delete copy[columnKey];
return copy;
}
return {
...prev,
[columnKey]: {
columnKey,
...filter,
},
};
});
setPage(1);
}, []);
/* ---------------- SELECTION ---------------- */
const toggleSelect = useCallback((id) => { const toggleSelect = useCallback((id) => {
setSelected((prev) => { setSelected((prev) => {
const s = new Set(prev); const s = new Set(prev);
@ -162,6 +191,7 @@ export function useGridCore({
[rowKey] [rowKey]
); );
/* ---------------- EXPAND ---------------- */
const toggleExpand = useCallback((id) => { const toggleExpand = useCallback((id) => {
setExpanded((prev) => { setExpanded((prev) => {
const s = new Set(prev); const s = new Set(prev);
@ -170,72 +200,81 @@ export function useGridCore({
}); });
}, []); }, []);
/* ---------------- SORT ---------------- */
const changeSort = useCallback((key) => { const changeSort = useCallback((key) => {
setSortBy((prev) => { setSortBy((prev) => {
// first click = asc if (prev.key !== key) return { key, dir: "asc" };
if (prev.key !== key) { if (prev.dir === "asc") return { key, dir: "desc" };
return { key, dir: "asc" };
}
// second click = desc
if (prev.dir === "asc") {
return { key, dir: "desc" };
}
// third click = remove sort
return { key: null, dir: "asc" }; return { key: null, dir: "asc" };
}); });
setPage(1); setPage(1);
}, []); }, []);
/* ---------------- COLUMNS ---------------- */
const visibleColumns = useMemo( const visibleColumns = useMemo(
() => colState.filter((c) => c.visible).sort((a, b) => a.order - b.order), () => colState.filter((c) => c.visible).sort((a, b) => a.order - b.order),
[colState] [colState]
); );
const rows = serverMode ? serverRows : clientFiltered;
const totalPages = Math.max(1, Math.ceil((totalRows || 0) / pageSize));
// update columns externally (reorder/pin/resize)
const updateColumn = useCallback((key, patch) => { const updateColumn = useCallback((key, patch) => {
setColState((prev) => setColState((prev) =>
prev.map((c) => (c.key === key ? { ...c, ...patch } : c)) prev.map((c) => (c.key === key ? { ...c, ...patch } : c))
); );
}, []); }, []);
/* ---------------- FINAL ---------------- */
const rows = serverMode ? serverRows : clientFiltered;
const totalPages = Math.max(1, Math.ceil(totalRows / pageSize));
return { return {
// state // paging
page, page,
setPage, setPage,
pageSize, pageSize,
setPageSize, setPageSize,
totalRows, totalRows,
totalPages, totalPages,
// loading
loading, loading,
// search
search, search,
setSearch, setSearch,
// sorting
sortBy, sortBy,
changeSort, changeSort,
// selection
selected, selected,
setSelected,
toggleSelect, toggleSelect,
selectAllOnPage, selectAllOnPage,
deselectAllOnPage, deselectAllOnPage,
setSelected,
// expand
expanded, expanded,
toggleExpand, toggleExpand,
// columns
colState, colState,
visibleColumns, visibleColumns,
updateColumn, updateColumn,
setColState, setColState,
// grouping
groupBy, groupBy,
setGroupBy, setGroupBy,
onAdvanceFilter,
setAdanceFilter, // advanced filter
advanceFilters,
setColumnAdvanceFilter,
// data // data
rows, rows,
// mode helpers // mode
serverMode, serverMode,
}; };
} }
@ -247,7 +286,6 @@ export function useGridCore({
export function useDropdownPosition(btnRef, menuRef, isOpen, level = 0) { export function useDropdownPosition(btnRef, menuRef, isOpen, level = 0) {
const [style, setStyle] = useState({}); const [style, setStyle] = useState({});

View File

@ -40,4 +40,3 @@ function autoPositionInsideContainer(triggerEl, dropdownEl, containerEl) {
dropdownEl.classList.remove("open-left"); dropdownEl.classList.remove("open-left");
} }
} }