react-kd-grid 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of react-kd-grid might be problematic. Click here for more details.

Files changed (137) hide show
  1. package/dist/cjs/index.js +2 -0
  2. package/dist/cjs/index.js.map +1 -0
  3. package/dist/esm/CustomGrid.d.ts +3 -0
  4. package/dist/esm/CustomGrid.js +2 -0
  5. package/dist/esm/CustomGrid.js.map +1 -0
  6. package/dist/esm/components/ColumnFilterSelector.d.ts +18 -0
  7. package/dist/esm/components/ColumnFilterSelector.js +2 -0
  8. package/dist/esm/components/ColumnFilterSelector.js.map +1 -0
  9. package/dist/esm/components/CustomSelect.d.ts +14 -0
  10. package/dist/esm/components/CustomSelect.js +2 -0
  11. package/dist/esm/components/CustomSelect.js.map +1 -0
  12. package/dist/esm/components/FooterAggregate.d.ts +16 -0
  13. package/dist/esm/components/FooterAggregate.js +2 -0
  14. package/dist/esm/components/FooterAggregate.js.map +1 -0
  15. package/dist/esm/components/GridHeader.d.ts +33 -0
  16. package/dist/esm/components/GridHeader.js +2 -0
  17. package/dist/esm/components/GridHeader.js.map +1 -0
  18. package/dist/esm/components/GridRows.d.ts +49 -0
  19. package/dist/esm/components/GridRows.js +2 -0
  20. package/dist/esm/components/GridRows.js.map +1 -0
  21. package/dist/esm/components/GroupBar.d.ts +12 -0
  22. package/dist/esm/components/GroupBar.js +2 -0
  23. package/dist/esm/components/GroupBar.js.map +1 -0
  24. package/dist/esm/components/GroupHeader.d.ts +29 -0
  25. package/dist/esm/components/GroupHeader.js +2 -0
  26. package/dist/esm/components/GroupHeader.js.map +1 -0
  27. package/dist/esm/components/NoDataMessage.d.ts +7 -0
  28. package/dist/esm/components/NoDataMessage.js +2 -0
  29. package/dist/esm/components/NoDataMessage.js.map +1 -0
  30. package/dist/esm/components/PaginationControls.d.ts +15 -0
  31. package/dist/esm/components/PaginationControls.js +2 -0
  32. package/dist/esm/components/PaginationControls.js.map +1 -0
  33. package/dist/esm/components/Popover.d.ts +17 -0
  34. package/dist/esm/components/Popover.js +2 -0
  35. package/dist/esm/components/Popover.js.map +1 -0
  36. package/dist/esm/components/RowContextMenu.d.ts +22 -0
  37. package/dist/esm/components/SearchToolbar.d.ts +79 -0
  38. package/dist/esm/components/SearchToolbar.js +2 -0
  39. package/dist/esm/components/SearchToolbar.js.map +1 -0
  40. package/dist/esm/components/filters/BooleanFilter.d.ts +7 -0
  41. package/dist/esm/components/filters/BooleanFilter.js +2 -0
  42. package/dist/esm/components/filters/BooleanFilter.js.map +1 -0
  43. package/dist/esm/components/filters/DateFilter.d.ts +9 -0
  44. package/dist/esm/components/filters/DateFilter.js +2 -0
  45. package/dist/esm/components/filters/DateFilter.js.map +1 -0
  46. package/dist/esm/components/filters/FilterContent.d.ts +9 -0
  47. package/dist/esm/components/filters/FilterContent.js +2 -0
  48. package/dist/esm/components/filters/FilterContent.js.map +1 -0
  49. package/dist/esm/components/filters/FilterPopup.d.ts +2 -0
  50. package/dist/esm/components/filters/MultiselectFilter.d.ts +10 -0
  51. package/dist/esm/components/filters/MultiselectFilter.js +2 -0
  52. package/dist/esm/components/filters/MultiselectFilter.js.map +1 -0
  53. package/dist/esm/components/filters/NumberFilter.d.ts +9 -0
  54. package/dist/esm/components/filters/NumberFilter.js +2 -0
  55. package/dist/esm/components/filters/NumberFilter.js.map +1 -0
  56. package/dist/esm/components/filters/TextFilter.d.ts +8 -0
  57. package/dist/esm/components/filters/TextFilter.js +2 -0
  58. package/dist/esm/components/filters/TextFilter.js.map +1 -0
  59. package/dist/esm/components/filters/index.d.ts +6 -0
  60. package/dist/esm/components/ui/DatePicker.d.ts +10 -0
  61. package/dist/esm/components/ui/DatePicker.js +2 -0
  62. package/dist/esm/components/ui/DatePicker.js.map +1 -0
  63. package/dist/esm/constants.d.ts +1 -0
  64. package/dist/esm/constants.js +2 -0
  65. package/dist/esm/constants.js.map +1 -0
  66. package/dist/esm/hooks/useAdvancedFiltering.d.ts +16 -0
  67. package/dist/esm/hooks/useAdvancedFiltering.js +2 -0
  68. package/dist/esm/hooks/useAdvancedFiltering.js.map +1 -0
  69. package/dist/esm/hooks/useDataWorker.d.ts +10 -0
  70. package/dist/esm/hooks/useDataWorker.js +2 -0
  71. package/dist/esm/hooks/useDataWorker.js.map +1 -0
  72. package/dist/esm/hooks/useExport.d.ts +15 -0
  73. package/dist/esm/hooks/useExport.js +2 -0
  74. package/dist/esm/hooks/useExport.js.map +1 -0
  75. package/dist/esm/hooks/useFilteringAndSorting.d.ts +16 -0
  76. package/dist/esm/hooks/useFilteringAndSorting.js +2 -0
  77. package/dist/esm/hooks/useFilteringAndSorting.js.map +1 -0
  78. package/dist/esm/hooks/useGrouping.d.ts +28 -0
  79. package/dist/esm/hooks/useGrouping.js +2 -0
  80. package/dist/esm/hooks/useGrouping.js.map +1 -0
  81. package/dist/esm/hooks/usePagination.d.ts +28 -0
  82. package/dist/esm/hooks/usePagination.js +2 -0
  83. package/dist/esm/hooks/usePagination.js.map +1 -0
  84. package/dist/esm/hooks/useSelection.d.ts +13 -0
  85. package/dist/esm/hooks/useSelection.js +2 -0
  86. package/dist/esm/hooks/useSelection.js.map +1 -0
  87. package/dist/esm/hooks/useVirtualization.d.ts +17 -0
  88. package/dist/esm/hooks/useVirtualization.js +2 -0
  89. package/dist/esm/hooks/useVirtualization.js.map +1 -0
  90. package/dist/esm/index.d.ts +11 -0
  91. package/dist/esm/index.js +2 -0
  92. package/dist/esm/index.js.map +1 -0
  93. package/dist/esm/types.d.ts +421 -0
  94. package/dist/esm/utils/highlightText.d.ts +15 -0
  95. package/dist/esm/utils/highlightText.js +2 -0
  96. package/dist/esm/utils/highlightText.js.map +1 -0
  97. package/dist/esm/workers/dataWorker.d.ts +16 -0
  98. package/package.json +7 -7
  99. package/dist/index.esm.js +0 -11
  100. package/dist/index.esm.js.map +0 -1
  101. package/dist/index.js +0 -11
  102. package/dist/index.js.map +0 -1
  103. /package/dist/{CustomGrid.d.ts → cjs/CustomGrid.d.ts} +0 -0
  104. /package/dist/{components → cjs/components}/ColumnFilterSelector.d.ts +0 -0
  105. /package/dist/{components → cjs/components}/CustomSelect.d.ts +0 -0
  106. /package/dist/{components → cjs/components}/FooterAggregate.d.ts +0 -0
  107. /package/dist/{components → cjs/components}/GridHeader.d.ts +0 -0
  108. /package/dist/{components → cjs/components}/GridRows.d.ts +0 -0
  109. /package/dist/{components → cjs/components}/GroupBar.d.ts +0 -0
  110. /package/dist/{components → cjs/components}/GroupHeader.d.ts +0 -0
  111. /package/dist/{components → cjs/components}/NoDataMessage.d.ts +0 -0
  112. /package/dist/{components → cjs/components}/PaginationControls.d.ts +0 -0
  113. /package/dist/{components → cjs/components}/Popover.d.ts +0 -0
  114. /package/dist/{components → cjs/components}/RowContextMenu.d.ts +0 -0
  115. /package/dist/{components → cjs/components}/SearchToolbar.d.ts +0 -0
  116. /package/dist/{components → cjs/components}/filters/BooleanFilter.d.ts +0 -0
  117. /package/dist/{components → cjs/components}/filters/DateFilter.d.ts +0 -0
  118. /package/dist/{components → cjs/components}/filters/FilterContent.d.ts +0 -0
  119. /package/dist/{components → cjs/components}/filters/FilterPopup.d.ts +0 -0
  120. /package/dist/{components → cjs/components}/filters/MultiselectFilter.d.ts +0 -0
  121. /package/dist/{components → cjs/components}/filters/NumberFilter.d.ts +0 -0
  122. /package/dist/{components → cjs/components}/filters/TextFilter.d.ts +0 -0
  123. /package/dist/{components → cjs/components}/filters/index.d.ts +0 -0
  124. /package/dist/{components → cjs/components}/ui/DatePicker.d.ts +0 -0
  125. /package/dist/{constants.d.ts → cjs/constants.d.ts} +0 -0
  126. /package/dist/{hooks → cjs/hooks}/useAdvancedFiltering.d.ts +0 -0
  127. /package/dist/{hooks → cjs/hooks}/useDataWorker.d.ts +0 -0
  128. /package/dist/{hooks → cjs/hooks}/useExport.d.ts +0 -0
  129. /package/dist/{hooks → cjs/hooks}/useFilteringAndSorting.d.ts +0 -0
  130. /package/dist/{hooks → cjs/hooks}/useGrouping.d.ts +0 -0
  131. /package/dist/{hooks → cjs/hooks}/usePagination.d.ts +0 -0
  132. /package/dist/{hooks → cjs/hooks}/useSelection.d.ts +0 -0
  133. /package/dist/{hooks → cjs/hooks}/useVirtualization.d.ts +0 -0
  134. /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
  135. /package/dist/{types.d.ts → cjs/types.d.ts} +0 -0
  136. /package/dist/{utils → cjs/utils}/highlightText.d.ts +0 -0
  137. /package/dist/{workers → cjs/workers}/dataWorker.d.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FooterAggregate.js","sources":["../../../../../components/FooterAggregate.tsx"],"sourcesContent":["import React, { useMemo, memo } from \"react\";\nimport { GridColumn, GridRow } from \"../types\";\nimport { SELECT_COL_WIDTH } from \"../constants\";\n\ninterface FooterAggregateProps {\n columns: (GridColumn & { width: number })[];\n data: GridRow[];\n selectable: boolean;\n /** Resolved row height so footer matches density */\n rowHeight: number;\n /** Pinned columns (same semantics as grid body) */\n pinnedColumns?: Set<string>;\n getRowId?: (row: GridRow) => string | number;\n}\n\nconst FooterAggregateComponent: React.FC<FooterAggregateProps> = ({\n columns,\n data,\n selectable,\n rowHeight,\n pinnedColumns = new Set(),\n getRowId,\n}) => {\n const aggregateValues = useMemo(() => {\n const result: Record<string, any> = {};\n\n // Only compute aggregates for columns that have footer_aggregate defined\n const columnsWithFooterAgg = columns.filter((col) => col.footer_aggregate);\n\n if (columnsWithFooterAgg.length === 0) {\n return result;\n }\n\n columnsWithFooterAgg.forEach((col) => {\n const values = data.map((row) => row[col.key]);\n let aggValue: any = null;\n\n if (typeof col.footer_aggregate === \"function\") {\n try {\n aggValue = col.footer_aggregate(values);\n } catch (error) {\n console.warn(\n `Error computing custom footer aggregate for column ${col.key}:`,\n error,\n );\n aggValue = null;\n }\n } else {\n const isDateLike = (s: string) => {\n // Common date formats: YYYY-MM-DD, DD-MM-YYYY, with '/' too\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return true;\n if (/^\\d{2}-\\d{2}-\\d{4}$/.test(s)) return true;\n if (/^\\d{4}\\/\\d{2}\\/\\d{2}$/.test(s)) return true;\n if (/^\\d{2}\\/\\d{2}\\/\\d{4}$/.test(s)) return true;\n // Fallback: if Date.parse works and the string contains '-' or '/'\n if (\n (s.includes(\"-\") || s.includes(\"/\")) &&\n Number.isFinite(Date.parse(s))\n )\n return true;\n return false;\n };\n\n const nums = values\n .map((v) => {\n if (typeof v === \"number\") return v;\n if (v == null) return NaN;\n const sv = String(v);\n // Prevent treating date-like strings as numbers (e.g., \"2025-01-01\" -> 2025)\n if (isDateLike(sv)) return NaN;\n const n = parseFloat(sv.replace(/,/g, \"\"));\n return Number.isFinite(n) ? n : NaN;\n })\n .filter((n) => Number.isFinite(n)) as number[];\n\n const tryDateNumbers = () => {\n // Convert date-like values to timestamps for min/max\n const dateNums = values\n .map((v) => {\n if (v instanceof Date) return v.getTime();\n if (typeof v === \"string\" || typeof v === \"number\") {\n const t = Date.parse(String(v));\n return Number.isFinite(t) ? t : NaN;\n }\n return NaN;\n })\n .filter((t) => Number.isFinite(t)) as number[];\n return dateNums;\n };\n\n switch (col.footer_aggregate) {\n case \"count\":\n aggValue = data.length;\n break;\n case \"sum\":\n if (nums.length) {\n aggValue = nums.reduce((a, b) => a + b, 0);\n }\n break;\n case \"avg\":\n if (nums.length) {\n const sum = nums.reduce((a, b) => a + b, 0);\n aggValue = sum / nums.length;\n }\n break;\n case \"min\":\n if (nums.length) {\n aggValue = Math.min(...nums);\n } else {\n const dateNums = tryDateNumbers();\n if (dateNums.length) {\n aggValue = new Date(Math.min(...dateNums));\n }\n }\n break;\n case \"max\":\n if (nums.length) {\n aggValue = Math.max(...nums);\n } else {\n const dateNums = tryDateNumbers();\n if (dateNums.length) {\n aggValue = new Date(Math.max(...dateNums));\n }\n }\n break;\n default:\n aggValue = null;\n }\n }\n\n if (aggValue !== null && aggValue !== undefined) {\n result[col.key] = aggValue;\n }\n });\n\n return result;\n }, [columns, data]);\n\n // Don't render if no columns have footer aggregates\n const hasFooterAggregates = columns.some((col) => col.footer_aggregate);\n if (!hasFooterAggregates) {\n return null;\n }\n\n const totalWidth = columns.reduce((sum, col) => sum + col.width, 0);\n\n // Precompute left offsets for pinned columns (mirrors GridRows logic)\n const leftOffsetByPinnedKey = useMemo(() => {\n const map = new Map<string, number>();\n const pinnedKeysInOrder = columns\n .filter((c) => pinnedColumns.has(c.key))\n .map((c) => c.key);\n let acc = selectable ? SELECT_COL_WIDTH : 0;\n for (const key of pinnedKeysInOrder) {\n map.set(key, acc);\n const w = columns.find((c) => c.key === key)?.width || 100;\n acc += w;\n }\n return map;\n }, [columns, pinnedColumns, selectable]);\n\n return (\n <div\n className=\"flex h-full\"\n style={{\n minWidth: `${totalWidth + (selectable ? SELECT_COL_WIDTH : 0)}px`,\n height: `${rowHeight}px`,\n }}\n >\n {selectable && (\n <div\n key=\"select-footer-cell\"\n className=\"w-12 p-3 border-r border-gray-200 dark:border-gray-700 flex items-center justify-center sticky left-0 bg-white dark:bg-gray-900 z-30\"\n style={{ height: `${rowHeight}px` }}\n >\n <span className=\"text-xs font-medium text-gray-600 dark:text-gray-300\">\n Total\n </span>\n </div>\n )}\n {columns.map((col) => {\n const width = col.width;\n const rawValue = aggregateValues[col.key];\n const hasAggregate = col.footer_aggregate && rawValue !== undefined;\n\n // Format value\n let displayValue = \"\";\n if (hasAggregate) {\n const formatter = col.footerAggregateFormatter || col.formatter;\n if (formatter) {\n try {\n displayValue = formatter(rawValue);\n } catch {\n displayValue = String(rawValue);\n }\n } else {\n if (typeof rawValue === \"number\") {\n displayValue =\n rawValue % 1 === 0 ? rawValue.toString() : rawValue.toFixed(2);\n } else {\n displayValue = String(rawValue?.toFixed);\n }\n }\n }\n\n const isPinned = pinnedColumns.has(col.key);\n const leftOffset = isPinned\n ? leftOffsetByPinnedKey.get(col.key) || 0\n : 0;\n const alignClass =\n col.align === \"center\"\n ? \"text-center\"\n : col.align === \"right\"\n ? \"text-right\"\n : \"text-left\";\n const justifyClass =\n col.align === \"center\"\n ? \"justify-center\"\n : col.align === \"right\"\n ? \"justify-end\"\n : \"justify-start\";\n const paddingClass = col.noPadding ? \"p-0\" : \"p-3\";\n\n return (\n <div\n key={col.key}\n className={`border-r border-gray-200 dark:border-gray-700 last:border-r-0 ${paddingClass} text-sm flex items-center font-semibold text-gray-700 dark:text-gray-200 overflow-hidden ${justifyClass} ${alignClass} ${\n isPinned ? \"sticky bg-white dark:bg-gray-900 z-20\" : \"\"\n }`}\n style={{\n width: `${width}px`,\n minWidth: `${width}px`,\n maxWidth: `${width}px`,\n left: isPinned ? `${leftOffset}px` : \"auto\",\n height: `${rowHeight}px`,\n }}\n title={hasAggregate ? `${col.header}: ${displayValue}` : undefined}\n >\n {hasAggregate && (\n <span className=\"truncate w-full\">{displayValue}</span>\n )}\n </div>\n );\n })}\n </div>\n );\n};\n\n// Memoize footer to avoid recomputing aggregates unless relevant inputs change\nexport const FooterAggregate = memo(FooterAggregateComponent, (prev, next) => {\n if (prev.selectable !== next.selectable) return false;\n if (prev.rowHeight !== next.rowHeight) return false;\n if (prev.getRowId !== next.getRowId) return false;\n if (prev.columns.length !== next.columns.length) return false;\n // Compare columns by key + width + aggregate spec reference\n for (let i = 0; i < prev.columns.length; i++) {\n const pc = prev.columns[i];\n const nc = next.columns[i];\n if (\n pc.key !== nc.key ||\n pc.width !== nc.width ||\n pc.footer_aggregate !== nc.footer_aggregate\n )\n return false;\n }\n // If data length changed or first/last row id changed, recompute\n if (prev.data.length !== next.data.length) return false;\n\n const extractId = (\n row: any,\n idx: number,\n getRowId?: (r: any) => string | number,\n ) => {\n if (getRowId) return getRowId(row);\n if (row.id !== undefined) return row.id;\n return idx;\n };\n\n const prevFirst =\n prev.data.length > 0\n ? extractId(prev.data[0], 0, prev.getRowId)\n : undefined;\n const nextFirst =\n next.data.length > 0\n ? extractId(next.data[0], 0, next.getRowId)\n : undefined;\n const prevLastIdx = prev.data.length - 1;\n const nextLastIdx = next.data.length - 1;\n const prevLast =\n prev.data.length > 0\n ? extractId(prev.data[prevLastIdx], prevLastIdx, prev.getRowId)\n : undefined;\n const nextLast =\n next.data.length > 0\n ? extractId(next.data[nextLastIdx], nextLastIdx, next.getRowId)\n : undefined;\n if (prevFirst !== nextFirst || prevLast !== nextLast) return false;\n if (prev.pinnedColumns?.size !== next.pinnedColumns?.size) return false;\n return true;\n});\n"],"names":["FooterAggregate","memo","columns","data","selectable","rowHeight","pinnedColumns","Set","getRowId","aggregateValues","useMemo","result","columnsWithFooterAgg","filter","col","footer_aggregate","length","forEach","values","map","row","key","aggValue","error","console","warn","isDateLike","s","test","includes","Number","isFinite","Date","parse","nums","v","NaN","sv","String","n","parseFloat","replace","tryDateNumbers","getTime","t","reduce","a","b","Math","min","dateNums","max","some","totalWidth","sum","width","leftOffsetByPinnedKey","Map","pinnedKeysInOrder","c","has","acc","SELECT_COL_WIDTH","set","find","_jsxs","className","style","minWidth","height","children","_jsx","rawValue","hasAggregate","undefined","displayValue","formatter","footerAggregateFormatter","toString","toFixed","isPinned","leftOffset","get","alignClass","align","justifyClass","paddingClass","noPadding","maxWidth","left","title","header","prev","next","i","pc","nc","extractId","idx","id","prevFirst","nextFirst","prevLastIdx","nextLastIdx","prevLast","nextLast","size"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { GridColumn, SortConfig, ActiveFilters, ColumnFilterValue, GridRow } from "../types";
2
+ interface GridHeaderProps {
3
+ pinnedColumns: GridColumn[];
4
+ unpinnedColumns: GridColumn[];
5
+ hvPadLeft?: number;
6
+ hvPadRight?: number;
7
+ headerHeight: number;
8
+ sortConfig: SortConfig;
9
+ columnFilters: ActiveFilters;
10
+ selectable: boolean;
11
+ selectedRows: Set<string | number>;
12
+ totalRows: number;
13
+ data: GridRow[];
14
+ onSort: (key: string) => void;
15
+ onColumnFilter: (key: string, filter: ColumnFilterValue | null) => void;
16
+ onSelectAll: () => void;
17
+ onColumnResize?: (columnKey: string, width: number) => void;
18
+ pinnedKeySet?: Set<string>;
19
+ onColumnPin?: (columnKey: string, pinned: boolean) => void;
20
+ groupable?: boolean;
21
+ groupedByColumn?: string | null;
22
+ onGroupBy?: (columnKey: string | null) => void;
23
+ groupedByColumns?: string[];
24
+ onGroupToggle?: (columnKey: string, nextGrouped: boolean) => void;
25
+ onAutosizeColumn?: (columnKey: string) => void;
26
+ onAutosizeAllColumns?: () => void;
27
+ onResetColumns?: () => void;
28
+ columnOrder: string[];
29
+ onColumnOrderChange: (order: string[]) => void;
30
+ paginationMode?: "client" | "server" | null;
31
+ }
32
+ export declare const GridHeader: ({ pinnedColumns, unpinnedColumns, hvPadLeft, hvPadRight, headerHeight, sortConfig, columnFilters, selectable, selectedRows, totalRows, data, onSort, onColumnFilter, onSelectAll, onColumnResize, pinnedKeySet, onColumnPin, groupable, groupedByColumn, onGroupBy, groupedByColumns, onGroupToggle, onAutosizeColumn, onAutosizeAllColumns, onResetColumns, columnOrder, onColumnOrderChange, paginationMode, }: GridHeaderProps) => import("react/jsx-runtime").JSX.Element;
33
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsx as e,Fragment as t,jsxs as l}from"react/jsx-runtime";import{useState as r,useEffect as n}from"react";import{ArrowUp as a,ArrowDown as o,Menu as s,Filter as i,ArrowUpDown as d,Pin as c,PinOff as u,Ungroup as m,Group as h,FilterX as b}from"lucide-react";import{SELECT_COL_WIDTH as g}from"../constants.js";import{FilterContent as y}from"./filters/FilterContent.js";const p=({pinnedColumns:p,unpinnedColumns:x,hvPadLeft:f=0,hvPadRight:k=0,headerHeight:v,sortConfig:w,columnFilters:N,selectable:C,selectedRows:D,totalRows:z,data:$,onSort:A,onColumnFilter:j,onSelectAll:R,onColumnResize:T,pinnedKeySet:P=new Set,onColumnPin:E,groupable:S=!1,groupedByColumn:M,onGroupBy:O,groupedByColumns:B=[],onGroupToggle:F,onAutosizeColumn:L,onAutosizeAllColumns:G,onResetColumns:H,columnOrder:U,onColumnOrderChange:X,paginationMode:Y="client"})=>{const K=[...p,...x],[W,q]=r(null),[I,J]=r(null),[Q,V]=r(null),[Z,_]=r(0),[ee,te]=r(0),[le,re]=r("menu"),[ne,ae]=r(null),[oe,se]=r(!1);n(()=>{se("ontouchstart"in window||navigator.maxTouchPoints>0||window.matchMedia("(pointer: coarse)").matches)},[]);const[ie,de]=r(null),[ce,ue]=r(null),me=D.size===z&&z>0,he=D.size>0&&D.size<z,be=(e,t)=>{if(t.stopPropagation(),W===e)q(null);else{q(e),re("menu"),ae(N[e]||null);const l=t.currentTarget.getBoundingClientRect(),r=t.currentTarget.closest("[data-grid-container]"),n=r?r.getBoundingClientRect():new DOMRect(0,0,window.innerWidth,window.innerHeight),a=320,o=10,s=n.left+o,i=n.right-a-o,d=Math.max(s,Math.min(l.left,i));J({top:l.bottom+4,left:d,containerRect:n})}},ge=e=>{j(e,ne||null),q(null)},ye=e=>null!=N[e],pe=(e,t)=>{t.preventDefault(),V(e),_(t.clientX);const l=[...p,...x].find(t=>t.key===e);te(l?.width||100)},xe=e=>{if(!Q||!T)return;const t=e.clientX-Z,l=Math.max(50,ee+t);T(Q,l)},fe=()=>{V(null),_(0),te(0)},[ke,ve]=r(null),[we,Ne]=r(null),Ce=(e,t)=>{ve(e),t.dataTransfer.effectAllowed="move",t.dataTransfer.setData("text/plain",e)},De=(e,t)=>{t.preventDefault(),t.dataTransfer.dropEffect="move";const l=t.currentTarget.getBoundingClientRect(),r=l.left+l.width/2,n=t.clientX<r?"before":"after";Ne({key:e,position:n})},ze=e=>{const t=ke;if(!t||t===e)return;if(P.has(t)!==P.has(e))return ve(null),void Ne(null);const l=we?.key!==e||"before"===we?.position,r=U.filter(e=>e!==t);let n=r.indexOf(e);if(-1===n)return X(r),ve(null),void Ne(null);l||(n+=1),r.splice(n,0,t);X(r),ve(null),Ne(null)},$e=()=>{ve(null),Ne(null)},Ae=(e,t)=>{de(e),t.dataTransfer.effectAllowed="move",t.dataTransfer.setData("text/plain",e)},je=(e,t)=>{t.preventDefault(),t.dataTransfer.dropEffect="move";const l=t.currentTarget.getBoundingClientRect(),r=l.top+l.height/2,n=t.clientY<r?"before":"after";ue({key:e,position:n})},Re=e=>{const t=ie;if(!t||t===e)return;if(P.has(t)!==P.has(e))return de(null),void ue(null);const l=ce?.key!==e||"before"===ce?.position,r=U.filter(e=>e!==t);let n=r.indexOf(e);if(-1===n)return X(r),de(null),void ue(null);l||(n+=1),r.splice(n,0,t),X(r),de(null),ue(null)},Te=()=>{de(null),ue(null)};return n(()=>{if(Q)return document.addEventListener("mousemove",xe),document.addEventListener("mouseup",fe),document.body.style.cursor="col-resize",document.body.style.userSelect="none",()=>{document.removeEventListener("mousemove",xe),document.removeEventListener("mouseup",fe),document.body.style.cursor="",document.body.style.userSelect=""}},[Q,Z,ee,T]),n(()=>{const e=e=>{const t=e.target;W&&!t.closest("[data-column-menu]")&&q(null)};if(W)return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[W]),e(t,{children:e("div",{className:"bg-blue-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",style:{height:v},role:"row","aria-label":"Column headers",children:l("div",{className:"flex h-full",children:[C&&e("div",{className:"px-3 border-r border-gray-200 dark:border-gray-700 flex items-center justify-center bg-blue-50 dark:bg-gray-800 sticky left-0 z-3 h-full",style:{width:g,height:v},role:"columnheader","aria-label":"Select all rows",children:e("input",{type:"checkbox",checked:me,ref:e=>{e&&(e.indeterminate=he)},onChange:R,onKeyDown:e=>{" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),R())},className:"rounded border-gray-300 dark:border-gray-600 text-blue-600 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 h-4 w-4 transition-all duration-150","aria-label":me?"Deselect all rows":he?`${D.size} rows selected. Click to select all`:"Select all rows",title:me?`Deselect all ${z} rows`:he?`${D.size} of ${z} rows selected`:`Select all ${z} rows`})}),p.map((r,n)=>{const x=P.has(r.key),f=p.filter(e=>P.has(e.key)).map(e=>e.key),k=f.indexOf(r.key),N=x?f.slice(0,k).reduce((e,t)=>{const l=p.find(e=>e.key===t);return e+(l?.width||100)},C?g:0):0,D="center"===r.headerAlign?"justify-center":"right"===r.headerAlign?"justify-end":"justify-start",z=!1!==r.sortable;return l("div",{className:`flex-none border-r border-gray-200 dark:border-gray-700 last:border-r-0 relative ${x?"bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-700 sticky z-2":""} `,style:{width:r.width||100,left:x?`${N}px`:"auto",height:v},"data-column-key":r.key,draggable:!0,onDragStart:e=>Ce(r.key,e),onDragOver:e=>De(r.key,e),onDrop:()=>ze(r.key),onDragEnd:$e,children:[we?.key===r.key&&e("div",{className:"absolute top-0 bottom-0 w-0.5 bg-blue-600 z-4",style:{left:"before"===we?.position?0:void 0,right:"after"===we?.position?0:void 0}}),e("div",{className:"px-3 h-full",children:l("div",{className:"flex items-center justify-between gap-1 group h-full",children:[l("div",{className:`flex items-center min-w-0 flex-1 ${D} ${z?"cursor-pointer hover:text-blue-600":""}`,onClick:()=>z&&A(r.key),children:[l("div",{className:"flex items-center gap-2 min-w-0",children:[ye(r.key)&&e("div",{className:"w-2 h-2 bg-red-500 rounded-full shrink-0",title:"Filter applied"}),e("span",{className:"font-medium text-gray-900 dark:text-gray-100 text-sm truncate min-w-0",children:r.header})]}),z&&w.key===r.key&&e("div",{className:"ml-1 shrink-0 pointer-events-none select-none",children:"asc"===w.direction?e(a,{className:"w-3 h-3 text-blue-600 dark:text-blue-400"}):e(o,{className:"w-3 h-3 text-blue-600 dark:text-blue-400"})})]}),(r.filterable||E||S)&&l("div",{className:"relative "+(W===r.key||oe?"block":"hidden group-hover:block"),"data-column-menu":!0,children:[e("button",{className:"p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded shrink-0",onClick:e=>be(r.key,e),"data-menu-trigger":!0,children:e(s,{className:"w-4 h-4 text-gray-500 dark:text-gray-400"})}),W===r.key&&I&&l("div",{className:"fixed bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg z-1000 w-[320px] overflow-auto",style:{top:`${I.top}px`,left:`${I.left}px`,maxHeight:`${Math.max(160,I.containerRect.bottom-12-I.top)}px`},"data-column-menu":!0,children:[l("div",{className:"flex items-center border-b border-gray-200 dark:border-gray-700",children:[e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("menu"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("menu"),children:e(s,{className:"w-4 h-4"})}),r.filterable&&e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("filter"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("filter"),children:e(i,{className:"w-4 h-4"})}),e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("reorder"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("reorder"),children:e(d,{className:"w-4 h-4"})})]}),"menu"===le&&l("div",{className:"py-1",children:[E&&(M===r.key?l("div",{className:"w-full px-3 py-2 text-left text-sm flex items-center gap-2 text-blue-600",children:[e(c,{className:"w-4 h-4"}),"Pinned by grouping"]}):e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2",onClick:e=>{e.stopPropagation(),q(null),E?.(r.key,!P.has(r.key))},children:P.has(r.key)?l(t,{children:[e(u,{className:"w-4 h-4"}),"Unpin Column"]}):l(t,{children:[e(c,{className:"w-4 h-4"}),"Pin Column"]})})),L&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{L?.(r.key),q(null)},children:"Autosize This Column"}),G&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{G?.(),q(null)},children:"Autosize All Columns"}),S&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2",onClick:e=>{e.stopPropagation(),q(null);const t=B?.includes(r.key)||M===r.key;F?F(r.key,!t):O?.(t?null:r.key)},children:M===r.key||B?.includes(r.key)?l(t,{children:[e(m,{className:"w-4 h-4"}),"Ungroup"]}):l(t,{children:[e(h,{className:"w-4 h-4"}),"Group by ",r.header]})}),H&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{H?.(),q(null)},children:"Reset Columns"})]}),"filter"===le&&l("div",{className:"p-3 w-full",children:[ye(r.key)&&l("button",{className:"mb-2 text-xs text-red-600 hover:underline flex items-center gap-1",onClick:()=>{ae(null),j(r.key,null),q(null)},children:[e(b,{className:"w-3 h-3"})," Clear Filter"]}),e("div",{className:"max-h-75 overflow-auto pr-1",children:e(y,{column:r,data:$,value:ne,onChange:e=>{ae(e),"server"!==Y&&j(r.key,e)}})}),"server"===Y?l("div",{className:"flex justify-end gap-2 mt-3",children:[e("button",{className:"px-3 py-1.5 text-sm bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200",onClick:()=>q(null),children:"Cancel"}),e("button",{className:"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700",onClick:()=>ge(r.key),children:"Apply"})]}):e("div",{className:"flex justify-end mt-3",children:e("button",{className:"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700",onClick:()=>q(null),children:"Close"})})]}),"reorder"===le&&l("div",{className:"px-3 py-2",children:[e("div",{className:"text-xs font-medium text-gray-500 mb-1",children:"Reorder Columns"}),e("div",{className:"max-h-60 overflow-auto border border-gray-200 rounded-md",children:[...U.map(e=>K.find(t=>t.key===e)).filter(Boolean),...K.filter(e=>!U.includes(e.key))].map(t=>{const r=P.has(t.key);return l("div",{className:`flex items-center justify-between px-2 py-1 text-sm bg-white hover:bg-gray-50 border-b last:border-b-0 relative ${ie===t.key?"opacity-60":""} ${r?"bg-blue-50/40":""}`,draggable:!0,onDragStart:e=>Ae(t.key,e),onDragOver:e=>je(t.key,e),onDrop:()=>Re(t.key),onDragEnd:Te,children:[ce?.key===t.key&&e("div",{className:"absolute left-0 right-0 h-0.5 bg-blue-600",style:{top:"before"===ce?.position?0:void 0,bottom:"after"===ce?.position?0:void 0}}),l("div",{className:"flex items-center gap-2",children:[e("span",{className:"text-gray-400 select-none",children:"⋮⋮"}),l("span",{className:"text-gray-800 truncate max-w-45",children:[t.header,r&&e("span",{className:"ml-1 text-[10px] text-blue-600",children:"(pinned)"})]})]})]},t.key)})}),e("div",{className:"text-[10px] text-gray-400 mt-1",children:"Tip: You can only reorder within pinned or unpinned groups."})]})]})]})]})}),n<p.length-1&&T&&e("div",{className:"absolute top-0 right-0 w-1 h-full cursor-col-resize hover:bg-blue-300 transition-colors group",onMouseDown:e=>pe(r.key,e),onDoubleClick:e=>{e.preventDefault(),e.stopPropagation(),L?.(r.key)},title:"Drag to resize • Double‑click to autosize",children:e("div",{className:"w-full h-full group-hover:bg-blue-400"})})]},r.key+n)}),f>0&&e("div",{style:{width:f,height:v},className:"flex-none"}),x.map((r,n)=>{const g="center"===r.headerAlign?"justify-center":"right"===r.headerAlign?"justify-end":"justify-start",p=!1!==r.sortable;return l("div",{className:"flex-none border-r border-gray-200 dark:border-gray-700 last:border-r-0 relative",style:{width:r.width||100,height:v},"data-column-key":r.key,draggable:!0,onDragStart:e=>Ce(r.key,e),onDragOver:e=>De(r.key,e),onDrop:()=>ze(r.key),onDragEnd:$e,children:[we?.key===r.key&&e("div",{className:"absolute top-0 bottom-0 w-0.5 bg-blue-600 z-4",style:{left:"before"===we?.position?0:void 0,right:"after"===we?.position?0:void 0}}),e("div",{className:"px-3 h-full",children:l("div",{className:"flex items-center justify-between gap-1 group h-full",children:[l("div",{className:`flex items-center min-w-0 flex-1 ${g} ${p?"cursor-pointer hover:text-blue-600":""}`,onClick:()=>p&&A(r.key),children:[l("div",{className:"flex items-center gap-2 min-w-0",children:[ye(r.key)&&e("div",{className:"w-2 h-2 bg-red-500 rounded-full shrink-0",title:"Filter applied"}),e("span",{className:"font-medium text-gray-900 dark:text-gray-100 text-sm truncate min-w-0",children:r.header})]}),p&&w.key===r.key&&e("div",{className:"ml-1 shrink-0 pointer-events-none select-none",children:"asc"===w.direction?e(a,{className:"w-3 h-3 text-blue-600 dark:text-blue-400"}):e(o,{className:"w-3 h-3 text-blue-600 dark:text-blue-400"})})]}),(r.filterable||E||S)&&l("div",{className:"relative "+(W===r.key||oe?"block":"hidden group-hover:block"),"data-column-menu":!0,children:[e("button",{className:"p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded shrink-0",onClick:e=>be(r.key,e),"data-menu-trigger":!0,children:e(s,{className:"w-4 h-4 text-gray-500 dark:text-gray-400"})}),W===r.key&&I&&l("div",{className:"fixed bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg z-10 w-[320px] overflow-auto",style:{top:`${I.top}px`,left:`${I.left}px`,maxHeight:`${Math.max(160,I.containerRect.bottom-12-I.top)}px`},"data-column-menu":!0,children:[l("div",{className:"flex items-center border-b border-gray-200 dark:border-gray-700",children:[e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("menu"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("menu"),children:e(s,{className:"w-4 h-4"})}),r.filterable&&e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("filter"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("filter"),children:e(i,{className:"w-4 h-4"})}),e("button",{className:"px-3 py-2 text-sm flex items-center gap-2 "+("reorder"===le?"border-b-2 border-blue-600 text-blue-600":"text-gray-600"),onClick:()=>re("reorder"),children:e(d,{className:"w-4 h-4"})})]}),"menu"===le&&l("div",{className:"py-1",children:[E&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2",onClick:e=>{e.stopPropagation(),q(null);const t=!P.has(r.key);E?.(r.key,t)},children:P.has(r.key)?l(t,{children:[e(u,{className:"w-4 h-4"}),"Unpin Column"]}):l(t,{children:[e(c,{className:"w-4 h-4"}),"Pin Column"]})}),L&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{L?.(r.key),q(null)},children:"Autosize This Column"}),G&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{G?.(),q(null)},children:"Autosize All Columns"}),S&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2",onClick:e=>{e.stopPropagation(),q(null);const t=B?.includes(r.key)||M===r.key;F?F(r.key,!t):O?.(t?null:r.key)},children:M===r.key||B?.includes(r.key)?l(t,{children:[e(m,{className:"w-4 h-4"}),"Ungroup"]}):l(t,{children:[e(h,{className:"w-4 h-4"}),"Group by ",r.header]})}),H&&e("button",{className:"w-full px-3 py-2 text-left text-sm hover:bg-gray-50",onClick:()=>{H?.(),q(null)},children:"Reset Columns"})]}),"filter"===le&&l("div",{className:"p-3 w-full",children:[e("div",{className:"max-h-75 overflow-auto pr-1",children:e(y,{column:r,data:$,value:ne,onChange:e=>{ae(e),"server"!==Y&&j(r.key,e)}})}),l("div",{className:"flex justify-end gap-2 mt-3",children:[ye(r.key)&&l("button",{className:"px-3 py-1.5 text-sm bg-red-500 text-white rounded-md hover:bg-red-600 flex items-center gap-2 cursor-pointer",onClick:()=>{ae(null),j(r.key,null),q(null)},children:[e(b,{className:"w-3 h-3"})," Clear Filter"]}),e("button",{className:"px-3 py-1.5 text-sm bg-green-100 text-green-700 rounded-md hover:bg-green-200 cursor-pointer",onClick:()=>q(null),children:"Apply"}),"server"===Y&&e("button",{className:"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700",onClick:()=>ge(r.key),children:"Apply"})]})]}),"reorder"===le&&l("div",{className:"px-3 py-2",children:[e("div",{className:"text-xs font-medium text-gray-500 mb-1",children:"Reorder Columns"}),e("div",{className:"max-h-60 overflow-auto border border-gray-200 rounded-md",children:[...U.map(e=>K.find(t=>t.key===e)).filter(Boolean),...K.filter(e=>!U.includes(e.key))].map(t=>{const r=P.has(t.key);return l("div",{className:`flex items-center justify-between px-2 py-1 text-sm bg-white hover:bg-gray-50 border-b last:border-b-0 relative ${ie===t.key?"opacity-60":""} ${r?"bg-blue-50/40":""}`,draggable:!0,onDragStart:e=>Ae(t.key,e),onDragOver:e=>je(t.key,e),onDrop:()=>Re(t.key),onDragEnd:Te,children:[ce?.key===t.key&&e("div",{className:"absolute left-0 right-0 h-0.5 bg-blue-600",style:{top:"before"===ce?.position?0:void 0,bottom:"after"===ce?.position?0:void 0}}),l("div",{className:"flex items-center gap-2",children:[e("span",{className:"text-gray-400 select-none",children:"⋮⋮"}),l("span",{className:"text-gray-800 truncate max-w-45",children:[t.header,r&&e("span",{className:"ml-1 text-[10px] text-blue-600",children:"(pinned)"})]})]})]},t.key)})}),e("div",{className:"text-[10px] text-gray-400 mt-1",children:"Tip: You can only reorder within pinned or unpinned groups."})]})]})]})]})}),n<x.length-1&&T&&e("div",{className:"absolute top-0 right-0 w-1 h-full cursor-col-resize hover:bg-blue-300 transition-colors group",onMouseDown:e=>pe(r.key,e),onDoubleClick:e=>{e.preventDefault(),e.stopPropagation(),L?.(r.key)},title:"Drag to resize • Double‑click to autosize",children:e("div",{className:"w-full h-full group-hover:bg-blue-400"})})]},r.key+n)}),k>0&&e("div",{style:{width:k,height:v},className:"flex-none"})]})})})};export{p as GridHeader};
2
+ //# sourceMappingURL=GridHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridHeader.js","sources":["../../../../../components/GridHeader.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { MouseEvent as ReactMouseEvent } from \"react\";\nimport {\n Filter,\n FilterX,\n Menu,\n Pin,\n PinOff,\n Group,\n Ungroup,\n ArrowUp,\n ArrowDown,\n ArrowUpDown,\n} from \"lucide-react\";\nimport {\n GridColumn,\n SortConfig,\n ActiveFilters,\n ColumnFilterValue,\n GridRow,\n} from \"../types\";\nimport { SELECT_COL_WIDTH } from \"../constants\";\nimport { FilterContent } from \"./filters/FilterContent\";\n\ninterface GridHeaderProps {\n pinnedColumns: GridColumn[];\n unpinnedColumns: GridColumn[];\n hvPadLeft?: number;\n hvPadRight?: number;\n // Fixed header height in px (use density-controlled row height)\n headerHeight: number;\n sortConfig: SortConfig;\n columnFilters: ActiveFilters;\n selectable: boolean;\n selectedRows: Set<string | number>;\n totalRows: number;\n data: GridRow[];\n onSort: (key: string) => void;\n onColumnFilter: (key: string, filter: ColumnFilterValue | null) => void;\n onSelectAll: () => void;\n onColumnResize?: (columnKey: string, width: number) => void;\n pinnedKeySet?: Set<string>;\n onColumnPin?: (columnKey: string, pinned: boolean) => void;\n groupable?: boolean;\n // Back-compat single grouped column\n groupedByColumn?: string | null;\n onGroupBy?: (columnKey: string | null) => void;\n // New multi-group API\n groupedByColumns?: string[];\n onGroupToggle?: (columnKey: string, nextGrouped: boolean) => void;\n onAutosizeColumn?: (columnKey: string) => void;\n onAutosizeAllColumns?: () => void;\n onResetColumns?: () => void;\n // Reorder props\n columnOrder: string[];\n onColumnOrderChange: (order: string[]) => void;\n // Pagination mode for auto-apply filtering\n paginationMode?: \"client\" | \"server\" | null;\n}\n\nexport const GridHeader = ({\n pinnedColumns,\n unpinnedColumns,\n hvPadLeft = 0,\n hvPadRight = 0,\n headerHeight,\n sortConfig,\n columnFilters,\n selectable,\n selectedRows,\n totalRows,\n data,\n onSort,\n onColumnFilter,\n onSelectAll,\n onColumnResize,\n pinnedKeySet = new Set<string>(),\n onColumnPin,\n groupable = false,\n groupedByColumn,\n onGroupBy,\n groupedByColumns = [],\n onGroupToggle,\n onAutosizeColumn,\n onAutosizeAllColumns,\n onResetColumns,\n columnOrder,\n onColumnOrderChange,\n paginationMode = \"client\",\n}: GridHeaderProps) => {\n const allColumns = [...pinnedColumns, ...unpinnedColumns];\n const [activeColumnMenu, setActiveColumnMenu] = useState<string | null>(null);\n const [menuPosition, setMenuPosition] = useState<{\n top: number;\n left: number;\n containerRect: DOMRect;\n } | null>(null);\n const [isResizing, setIsResizing] = useState<string | null>(null);\n const [startX, setStartX] = useState<number>(0);\n const [startWidth, setStartWidth] = useState<number>(0);\n const [activeTab, setActiveTab] = useState<\"menu\" | \"filter\" | \"reorder\">(\n \"menu\"\n );\n const [tempFilter, setTempFilter] = useState<ColumnFilterValue | null>(null);\n const [isTouchDevice, setIsTouchDevice] = useState(false);\n\n useEffect(() => {\n setIsTouchDevice(\n \"ontouchstart\" in window ||\n navigator.maxTouchPoints > 0 ||\n window.matchMedia(\"(pointer: coarse)\").matches\n );\n }, []);\n\n // Reorder-in-menu state\n const [menuReorderDraggingKey, setMenuReorderDraggingKey] = useState<\n string | null\n >(null);\n const [menuReorderDragOver, setMenuReorderDragOver] = useState<{\n key: string;\n position: \"before\" | \"after\";\n } | null>(null);\n\n const isAllSelected = selectedRows.size === totalRows && totalRows > 0;\n const isIndeterminate =\n selectedRows.size > 0 && selectedRows.size < totalRows;\n\n const handleColumnMenuClick = (\n columnKey: string,\n event: ReactMouseEvent<HTMLButtonElement>\n ) => {\n event.stopPropagation();\n if (activeColumnMenu === columnKey) {\n setActiveColumnMenu(null);\n } else {\n setActiveColumnMenu(columnKey);\n setActiveTab(\"menu\");\n setTempFilter(columnFilters[columnKey] || null);\n\n // Store button position and clamp to grid container bounds\n const rect = event.currentTarget.getBoundingClientRect();\n // Find the nearest grid container for boundary clamping\n const containerEl = event.currentTarget.closest(\n \"[data-grid-container]\"\n ) as HTMLElement | null;\n const containerRect = containerEl\n ? containerEl.getBoundingClientRect()\n : new DOMRect(0, 0, window.innerWidth, window.innerHeight);\n\n const MENU_WIDTH = 320; // matches dropdown width below\n const PADDING = 10;\n\n // Clamp left so the menu stays inside the grid container horizontally\n const minLeft = containerRect.left + PADDING;\n const maxLeft = containerRect.right - MENU_WIDTH - PADDING;\n const clampedLeft = Math.max(minLeft, Math.min(rect.left, maxLeft));\n\n setMenuPosition({\n top: rect.bottom + 4,\n left: clampedLeft,\n containerRect,\n });\n }\n };\n\n const handleApplyFilter = (columnKey: string) => {\n onColumnFilter(columnKey, tempFilter || null);\n setActiveColumnMenu(null);\n };\n\n const hasActiveFilter = (columnKey: string) => {\n return columnFilters[columnKey] != null;\n };\n\n const handleResizeStart = (columnKey: string, event: ReactMouseEvent) => {\n event.preventDefault();\n setIsResizing(columnKey);\n setStartX(event.clientX);\n const column = [...pinnedColumns, ...unpinnedColumns].find(\n (col) => col.key === columnKey\n );\n setStartWidth(column?.width || 100);\n };\n\n const handleResizeMove = (event: globalThis.MouseEvent) => {\n if (!isResizing || !onColumnResize) return;\n\n const deltaX = event.clientX - startX;\n const newWidth = Math.max(50, startWidth + deltaX); // Minimum width of 50px\n onColumnResize(isResizing, newWidth);\n };\n\n const handleResizeEnd = () => {\n setIsResizing(null);\n setStartX(0);\n setStartWidth(0);\n };\n\n // Drag & Drop state for reordering\n const [draggingKey, setDraggingKey] = useState<string | null>(null);\n const [dragOver, setDragOver] = useState<{\n key: string;\n position: \"before\" | \"after\";\n } | null>(null);\n\n // (no-op helper removed; ordering is computed inline in handleDrop)\n\n const handleDragStart = (\n columnKey: string,\n e: React.DragEvent<HTMLDivElement>\n ) => {\n setDraggingKey(columnKey);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", columnKey);\n };\n\n const handleDragOver = (\n targetKey: string,\n e: React.DragEvent<HTMLDivElement>\n ) => {\n // Allow drop\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const midpoint = rect.left + rect.width / 2;\n const position = e.clientX < midpoint ? \"before\" : \"after\";\n setDragOver({ key: targetKey, position });\n };\n\n const handleDrop = (targetKey: string) => {\n const sourceKey = draggingKey;\n if (!sourceKey || sourceKey === targetKey) return;\n\n // Prevent cross pinned/unpinned moves for clearer UX\n const sourcePinned = pinnedKeySet.has(sourceKey);\n const targetPinned = pinnedKeySet.has(targetKey);\n if (sourcePinned !== targetPinned) {\n setDraggingKey(null);\n setDragOver(null);\n return;\n }\n\n const before =\n dragOver?.key === targetKey ? dragOver?.position === \"before\" : true;\n const base = columnOrder.filter((k) => k !== sourceKey);\n let idx = base.indexOf(targetKey);\n if (idx === -1) {\n onColumnOrderChange(base);\n setDraggingKey(null);\n setDragOver(null);\n return;\n }\n if (!before) idx += 1;\n base.splice(idx, 0, sourceKey);\n const next = base;\n onColumnOrderChange(next);\n setDraggingKey(null);\n setDragOver(null);\n };\n\n const handleDragEnd = () => {\n setDraggingKey(null);\n setDragOver(null);\n };\n\n // --- Reorder handlers for the popup list ---\n const handleMenuReorderDragStart = (\n columnKey: string,\n e: React.DragEvent<HTMLDivElement>\n ) => {\n setMenuReorderDraggingKey(columnKey);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", columnKey);\n };\n\n const handleMenuReorderDragOver = (\n targetKey: string,\n e: React.DragEvent<HTMLDivElement>\n ) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const midpoint = rect.top + rect.height / 2;\n const position = e.clientY < midpoint ? \"before\" : \"after\";\n setMenuReorderDragOver({ key: targetKey, position });\n };\n\n const handleMenuReorderDrop = (targetKey: string) => {\n const sourceKey = menuReorderDraggingKey;\n if (!sourceKey || sourceKey === targetKey) return;\n\n // Prevent cross pinned/unpinned moves\n const sourcePinned = pinnedKeySet.has(sourceKey);\n const targetPinned = pinnedKeySet.has(targetKey);\n if (sourcePinned !== targetPinned) {\n setMenuReorderDraggingKey(null);\n setMenuReorderDragOver(null);\n return;\n }\n\n const before =\n menuReorderDragOver?.key === targetKey\n ? menuReorderDragOver?.position === \"before\"\n : true;\n const base = columnOrder.filter((k) => k !== sourceKey);\n let idx = base.indexOf(targetKey);\n if (idx === -1) {\n onColumnOrderChange(base);\n setMenuReorderDraggingKey(null);\n setMenuReorderDragOver(null);\n return;\n }\n if (!before) idx += 1;\n base.splice(idx, 0, sourceKey);\n onColumnOrderChange(base);\n setMenuReorderDraggingKey(null);\n setMenuReorderDragOver(null);\n };\n\n const handleMenuReorderDragEnd = () => {\n setMenuReorderDraggingKey(null);\n setMenuReorderDragOver(null);\n };\n\n // Add global mouse event listeners for resizing\n useEffect(() => {\n if (isResizing) {\n document.addEventListener(\"mousemove\", handleResizeMove);\n document.addEventListener(\"mouseup\", handleResizeEnd);\n document.body.style.cursor = \"col-resize\";\n document.body.style.userSelect = \"none\";\n\n return () => {\n document.removeEventListener(\"mousemove\", handleResizeMove);\n document.removeEventListener(\"mouseup\", handleResizeEnd);\n document.body.style.cursor = \"\";\n document.body.style.userSelect = \"\";\n };\n }\n }, [isResizing, startX, startWidth, onColumnResize]);\n\n // Close menu on outside click\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as Element;\n if (activeColumnMenu && !target.closest(\"[data-column-menu]\")) {\n setActiveColumnMenu(null);\n }\n };\n\n if (activeColumnMenu) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }\n }, [activeColumnMenu]);\n\n return (\n <>\n <div\n className=\"bg-blue-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700\"\n style={{ height: headerHeight }}\n role=\"row\"\n aria-label=\"Column headers\"\n >\n <div className=\"flex h-full\">\n {selectable && (\n <div\n className=\"px-3 border-r border-gray-200 dark:border-gray-700 flex items-center justify-center bg-blue-50 dark:bg-gray-800 sticky left-0 z-3 h-full\"\n style={{ width: SELECT_COL_WIDTH, height: headerHeight }}\n role=\"columnheader\"\n aria-label=\"Select all rows\"\n >\n <input\n type=\"checkbox\"\n checked={isAllSelected}\n ref={(el) => {\n if (el) el.indeterminate = isIndeterminate;\n }}\n onChange={onSelectAll}\n onKeyDown={(e) => {\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault();\n onSelectAll();\n }\n }}\n className=\"rounded border-gray-300 dark:border-gray-600 text-blue-600 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 h-4 w-4 transition-all duration-150\"\n aria-label={\n isAllSelected\n ? \"Deselect all rows\"\n : isIndeterminate\n ? `${selectedRows.size} rows selected. Click to select all`\n : \"Select all rows\"\n }\n title={\n isAllSelected\n ? `Deselect all ${totalRows} rows`\n : isIndeterminate\n ? `${selectedRows.size} of ${totalRows} rows selected`\n : `Select all ${totalRows} rows`\n }\n />\n </div>\n )}\n\n {/* Pinned columns */}\n {pinnedColumns.map((column, index) => {\n const isPinned = pinnedKeySet.has(column.key);\n const pinnedKeysInOrder = pinnedColumns\n .filter((c) => pinnedKeySet.has(c.key))\n .map((c) => c.key);\n const pinnedIndex = pinnedKeysInOrder.indexOf(column.key);\n const leftOffset = isPinned\n ? pinnedKeysInOrder.slice(0, pinnedIndex).reduce(\n (sum, key) => {\n const col = pinnedColumns.find((c) => c.key === key);\n return sum + (col?.width || 100);\n },\n selectable ? SELECT_COL_WIDTH : 0\n )\n : 0;\n\n const headerJustify =\n column.headerAlign === \"center\"\n ? \"justify-center\"\n : column.headerAlign === \"right\"\n ? \"justify-end\"\n : \"justify-start\";\n\n // Determine effective sortable (default true unless explicitly false)\n const colSortable = column.sortable !== false;\n return (\n <div\n key={column.key + index}\n className={`flex-none border-r border-gray-200 dark:border-gray-700 last:border-r-0 relative ${\n isPinned\n ? \"bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-700 sticky z-2\"\n : \"\"\n } `}\n style={{\n width: column.width || 100,\n left: isPinned ? `${leftOffset}px` : \"auto\",\n height: headerHeight,\n }}\n data-column-key={column.key}\n draggable\n onDragStart={(e) => handleDragStart(column.key, e)}\n onDragOver={(e) => handleDragOver(column.key, e)}\n onDrop={() => handleDrop(column.key)}\n onDragEnd={handleDragEnd}\n >\n {/* Drop indicator */}\n {dragOver?.key === column.key && (\n <div\n className=\"absolute top-0 bottom-0 w-0.5 bg-blue-600 z-4\"\n style={{\n left: dragOver?.position === \"before\" ? 0 : undefined,\n right: dragOver?.position === \"after\" ? 0 : undefined,\n }}\n />\n )}\n <div className=\"px-3 h-full\">\n {/* Header with sort */}\n <div className=\"flex items-center justify-between gap-1 group h-full\">\n <div\n className={`flex items-center min-w-0 flex-1 ${headerJustify} ${\n colSortable ? \"cursor-pointer hover:text-blue-600\" : \"\"\n }`}\n onClick={() => colSortable && onSort(column.key)}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Filter indicator */}\n {hasActiveFilter(column.key) && (\n <div\n className=\"w-2 h-2 bg-red-500 rounded-full shrink-0\"\n title=\"Filter applied\"\n />\n )}\n <span className=\"font-medium text-gray-900 dark:text-gray-100 text-sm truncate min-w-0\">\n {column.header}\n </span>\n </div>\n {colSortable && sortConfig.key === column.key && (\n <div className=\"ml-1 shrink-0 pointer-events-none select-none\">\n {sortConfig.direction === \"asc\" ? (\n <ArrowUp className=\"w-3 h-3 text-blue-600 dark:text-blue-400\" />\n ) : (\n <ArrowDown className=\"w-3 h-3 text-blue-600 dark:text-blue-400\" />\n )}\n </div>\n )}\n </div>\n\n {/* Three-dot menu */}\n {(column.filterable || onColumnPin || groupable) && (\n <div\n className={`relative ${\n activeColumnMenu === column.key || isTouchDevice\n ? \"block\"\n : \"hidden group-hover:block\"\n }`}\n data-column-menu\n >\n <button\n className=\"p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded shrink-0\"\n onClick={(e) => handleColumnMenuClick(column.key, e)}\n data-menu-trigger\n >\n <Menu className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" />\n </button>\n\n {/* Dropdown Menu with Tabs */}\n {activeColumnMenu === column.key && menuPosition && (\n <div\n className=\"fixed bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg z-1000 w-[320px] overflow-auto\"\n style={{\n top: `${menuPosition.top}px`,\n left: `${menuPosition.left}px`,\n // Ensure the menu height never exceeds available space within the grid container\n maxHeight: `${Math.max(\n 160,\n menuPosition.containerRect.bottom -\n 12 -\n menuPosition.top\n )}px`,\n }}\n data-column-menu\n >\n {/* Tabs */}\n <div className=\"flex items-center border-b border-gray-200 dark:border-gray-700\">\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"menu\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"menu\")}\n >\n <Menu className=\"w-4 h-4\" />\n </button>\n {column.filterable && (\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"filter\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"filter\")}\n >\n <Filter className=\"w-4 h-4\" />\n </button>\n )}\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"reorder\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"reorder\")}\n >\n <ArrowUpDown className=\"w-4 h-4\" />\n </button>\n </div>\n {/* Tab Content */}\n {activeTab === \"menu\" && (\n <div className=\"py-1\">\n {onColumnPin &&\n (groupedByColumn === column.key ? (\n <div className=\"w-full px-3 py-2 text-left text-sm flex items-center gap-2 text-blue-600\">\n <Pin className=\"w-4 h-4\" />\n Pinned by grouping\n </div>\n ) : (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n setActiveColumnMenu(null);\n onColumnPin?.(\n column.key,\n !pinnedKeySet.has(column.key)\n );\n }}\n >\n {pinnedKeySet.has(column.key) ? (\n <>\n <PinOff className=\"w-4 h-4\" />\n Unpin Column\n </>\n ) : (\n <>\n <Pin className=\"w-4 h-4\" />\n Pin Column\n </>\n )}\n </button>\n ))}\n\n {onAutosizeColumn && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onAutosizeColumn?.(column.key);\n setActiveColumnMenu(null);\n }}\n >\n Autosize This Column\n </button>\n )}\n {onAutosizeAllColumns && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onAutosizeAllColumns?.();\n setActiveColumnMenu(null);\n }}\n >\n Autosize All Columns\n </button>\n )}\n\n {groupable && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n setActiveColumnMenu(null);\n const isGrouped =\n groupedByColumns?.includes(\n column.key\n ) || groupedByColumn === column.key;\n if (onGroupToggle)\n onGroupToggle(column.key, !isGrouped);\n else\n onGroupBy?.(\n isGrouped ? null : column.key\n );\n }}\n >\n {groupedByColumn === column.key ||\n groupedByColumns?.includes(column.key) ? (\n <>\n <Ungroup className=\"w-4 h-4\" />\n Ungroup\n </>\n ) : (\n <>\n <Group className=\"w-4 h-4\" />\n Group by {column.header}\n </>\n )}\n </button>\n )}\n\n {onResetColumns && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onResetColumns?.();\n setActiveColumnMenu(null);\n }}\n >\n Reset Columns\n </button>\n )}\n </div>\n )}\n {activeTab === \"filter\" && (\n <div className=\"p-3 w-full\">\n {/* Filter Tab */}\n {hasActiveFilter(column.key) && (\n <button\n className=\"mb-2 text-xs text-red-600 hover:underline flex items-center gap-1\"\n onClick={() => {\n setTempFilter(null);\n onColumnFilter(column.key, null);\n setActiveColumnMenu(null);\n }}\n >\n <FilterX className=\"w-3 h-3\" /> Clear Filter\n </button>\n )}\n <div className=\"max-h-75 overflow-auto pr-1\">\n <FilterContent\n column={column}\n data={data}\n value={tempFilter}\n onChange={(val) => {\n setTempFilter(val);\n // Auto-apply for client-side or no pagination\n if (paginationMode !== \"server\") {\n onColumnFilter(column.key, val);\n }\n }}\n />\n </div>\n {paginationMode === \"server\" ? (\n <div className=\"flex justify-end gap-2 mt-3\">\n <button\n className=\"px-3 py-1.5 text-sm bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200\"\n onClick={() => setActiveColumnMenu(null)}\n >\n Cancel\n </button>\n <button\n className=\"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700\"\n onClick={() =>\n handleApplyFilter(column.key)\n }\n >\n Apply\n </button>\n </div>\n ) : (\n <div className=\"flex justify-end mt-3\">\n <button\n className=\"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700\"\n onClick={() => setActiveColumnMenu(null)}\n >\n Close\n </button>\n </div>\n )}\n </div>\n )}\n {activeTab === \"reorder\" && (\n <div className=\"px-3 py-2\">\n <div className=\"text-xs font-medium text-gray-500 mb-1\">\n Reorder Columns\n </div>\n <div className=\"max-h-60 overflow-auto border border-gray-200 rounded-md\">\n {(() => {\n // Build ordered array by columnOrder using allColumns\n const ordered = [\n ...columnOrder\n .map((k) =>\n allColumns.find((c) => c.key === k)\n )\n .filter(Boolean),\n // add any missing\n ...allColumns.filter(\n (c) => !columnOrder.includes(c.key)\n ),\n ] as GridColumn[];\n\n return ordered.map((c) => {\n const isPinnedItem = pinnedKeySet.has(\n c.key\n );\n return (\n <div\n key={c.key}\n className={`flex items-center justify-between px-2 py-1 text-sm bg-white hover:bg-gray-50 border-b last:border-b-0 relative ${\n menuReorderDraggingKey === c.key\n ? \"opacity-60\"\n : \"\"\n } ${\n isPinnedItem ? \"bg-blue-50/40\" : \"\"\n }`}\n draggable\n onDragStart={(e) =>\n handleMenuReorderDragStart(c.key, e)\n }\n onDragOver={(e) =>\n handleMenuReorderDragOver(c.key, e)\n }\n onDrop={() =>\n handleMenuReorderDrop(c.key)\n }\n onDragEnd={handleMenuReorderDragEnd}\n >\n {/* drop indicator */}\n {menuReorderDragOver?.key ===\n c.key && (\n <div\n className=\"absolute left-0 right-0 h-0.5 bg-blue-600\"\n style={{\n top:\n menuReorderDragOver?.position ===\n \"before\"\n ? 0\n : undefined,\n bottom:\n menuReorderDragOver?.position ===\n \"after\"\n ? 0\n : undefined,\n }}\n />\n )}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-gray-400 select-none\">\n ⋮⋮\n </span>\n <span className=\"text-gray-800 truncate max-w-45\">\n {c.header}\n {isPinnedItem && (\n <span className=\"ml-1 text-[10px] text-blue-600\">\n (pinned)\n </span>\n )}\n </span>\n </div>\n </div>\n );\n });\n })()}\n </div>\n <div className=\"text-[10px] text-gray-400 mt-1\">\n Tip: You can only reorder within pinned or\n unpinned groups.\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Resize handle */}\n {index < pinnedColumns.length - 1 && onColumnResize && (\n <div\n className=\"absolute top-0 right-0 w-1 h-full cursor-col-resize hover:bg-blue-300 transition-colors group\"\n onMouseDown={(e) => handleResizeStart(column.key, e)}\n onDoubleClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onAutosizeColumn?.(column.key);\n }}\n title=\"Drag to resize • Double‑click to autosize\"\n >\n <div className=\"w-full h-full group-hover:bg-blue-400\" />\n </div>\n )}\n </div>\n );\n })}\n\n {/* Spacer before first visible unpinned col */}\n {hvPadLeft > 0 && (\n <div\n style={{ width: hvPadLeft, height: headerHeight }}\n className=\"flex-none\"\n />\n )}\n\n {/* Unpinned visible columns */}\n {unpinnedColumns.map((column, index) => {\n // unpinned visible segment\n const headerJustify =\n column.headerAlign === \"center\"\n ? \"justify-center\"\n : column.headerAlign === \"right\"\n ? \"justify-end\"\n : \"justify-start\";\n\n const colSortable = column.sortable !== false;\n return (\n <div\n key={column.key + index}\n className={`flex-none border-r border-gray-200 dark:border-gray-700 last:border-r-0 relative`}\n style={{ width: column.width || 100, height: headerHeight }}\n data-column-key={column.key}\n draggable\n onDragStart={(e) => handleDragStart(column.key, e)}\n onDragOver={(e) => handleDragOver(column.key, e)}\n onDrop={() => handleDrop(column.key)}\n onDragEnd={handleDragEnd}\n >\n {/* Drop indicator */}\n {dragOver?.key === column.key && (\n <div\n className=\"absolute top-0 bottom-0 w-0.5 bg-blue-600 z-4\"\n style={{\n left: dragOver?.position === \"before\" ? 0 : undefined,\n right: dragOver?.position === \"after\" ? 0 : undefined,\n }}\n />\n )}\n <div className=\"px-3 h-full\">\n {/* Header with sort */}\n <div className=\"flex items-center justify-between gap-1 group h-full\">\n <div\n className={`flex items-center min-w-0 flex-1 ${headerJustify} ${\n colSortable ? \"cursor-pointer hover:text-blue-600\" : \"\"\n }`}\n onClick={() => colSortable && onSort(column.key)}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Filter indicator */}\n {hasActiveFilter(column.key) && (\n <div\n className=\"w-2 h-2 bg-red-500 rounded-full shrink-0\"\n title=\"Filter applied\"\n />\n )}\n <span className=\"font-medium text-gray-900 dark:text-gray-100 text-sm truncate min-w-0\">\n {column.header}\n </span>\n </div>\n {colSortable && sortConfig.key === column.key && (\n <div className=\"ml-1 shrink-0 pointer-events-none select-none\">\n {sortConfig.direction === \"asc\" ? (\n <ArrowUp className=\"w-3 h-3 text-blue-600 dark:text-blue-400\" />\n ) : (\n <ArrowDown className=\"w-3 h-3 text-blue-600 dark:text-blue-400\" />\n )}\n </div>\n )}\n </div>\n\n {/* Three-dot menu */}\n {(column.filterable || onColumnPin || groupable) && (\n <div\n className={`relative ${\n activeColumnMenu === column.key || isTouchDevice\n ? \"block\"\n : \"hidden group-hover:block\"\n }`}\n data-column-menu\n >\n <button\n className=\"p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded shrink-0\"\n onClick={(e) => handleColumnMenuClick(column.key, e)}\n data-menu-trigger\n >\n <Menu className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" />\n </button>\n\n {/* Dropdown Menu with Tabs */}\n {activeColumnMenu === column.key && menuPosition && (\n <div\n className=\"fixed bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg z-10 w-[320px] overflow-auto\"\n style={{\n top: `${menuPosition.top}px`,\n left: `${menuPosition.left}px`,\n // Ensure the menu height never exceeds available space within the grid container\n maxHeight: `${Math.max(\n 160,\n menuPosition.containerRect.bottom -\n 12 -\n menuPosition.top\n )}px`,\n }}\n data-column-menu\n >\n {/* Tabs */}\n <div className=\"flex items-center border-b border-gray-200 dark:border-gray-700\">\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"menu\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"menu\")}\n >\n <Menu className=\"w-4 h-4\" />\n </button>\n {column.filterable && (\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"filter\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"filter\")}\n >\n <Filter className=\"w-4 h-4\" />\n </button>\n )}\n <button\n className={`px-3 py-2 text-sm flex items-center gap-2 ${\n activeTab === \"reorder\"\n ? \"border-b-2 border-blue-600 text-blue-600\"\n : \"text-gray-600\"\n }`}\n onClick={() => setActiveTab(\"reorder\")}\n >\n <ArrowUpDown className=\"w-4 h-4\" />\n </button>\n </div>\n {/* Tab Content (reusing existing code paths) */}\n {activeTab === \"menu\" && (\n <div className=\"py-1\">\n {onColumnPin && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n setActiveColumnMenu(null);\n const nextPinned = !pinnedKeySet.has(\n column.key\n );\n onColumnPin?.(column.key, nextPinned);\n }}\n >\n {pinnedKeySet.has(column.key) ? (\n <>\n <PinOff className=\"w-4 h-4\" />\n Unpin Column\n </>\n ) : (\n <>\n <Pin className=\"w-4 h-4\" />\n Pin Column\n </>\n )}\n </button>\n )}\n {onAutosizeColumn && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onAutosizeColumn?.(column.key);\n setActiveColumnMenu(null);\n }}\n >\n Autosize This Column\n </button>\n )}\n {onAutosizeAllColumns && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onAutosizeAllColumns?.();\n setActiveColumnMenu(null);\n }}\n >\n Autosize All Columns\n </button>\n )}\n\n {groupable && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50 flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n setActiveColumnMenu(null);\n const isGrouped =\n groupedByColumns?.includes(\n column.key\n ) || groupedByColumn === column.key;\n if (onGroupToggle)\n onGroupToggle(column.key, !isGrouped);\n else\n onGroupBy?.(\n isGrouped ? null : column.key\n );\n }}\n >\n {groupedByColumn === column.key ||\n groupedByColumns?.includes(column.key) ? (\n <>\n <Ungroup className=\"w-4 h-4\" />\n Ungroup\n </>\n ) : (\n <>\n <Group className=\"w-4 h-4\" />\n Group by {column.header}\n </>\n )}\n </button>\n )}\n\n {onResetColumns && (\n <button\n className=\"w-full px-3 py-2 text-left text-sm hover:bg-gray-50\"\n onClick={() => {\n onResetColumns?.();\n setActiveColumnMenu(null);\n }}\n >\n Reset Columns\n </button>\n )}\n </div>\n )}\n {activeTab === \"filter\" && (\n <div className=\"p-3 w-full\">\n <div className=\"max-h-75 overflow-auto pr-1\">\n <FilterContent\n column={column}\n data={data}\n value={tempFilter}\n onChange={(val) => {\n setTempFilter(val);\n // Auto-apply for client-side or no pagination\n if (paginationMode !== \"server\") {\n onColumnFilter(column.key, val);\n }\n }}\n />\n </div>\n <div className=\"flex justify-end gap-2 mt-3\">\n {hasActiveFilter(column.key) && (\n <button\n className=\"px-3 py-1.5 text-sm bg-red-500 text-white rounded-md hover:bg-red-600 flex items-center gap-2 cursor-pointer\"\n onClick={() => {\n setTempFilter(null);\n onColumnFilter(column.key, null);\n setActiveColumnMenu(null);\n }}\n >\n <FilterX className=\"w-3 h-3\" /> Clear\n Filter\n </button>\n )}\n <button\n className=\"px-3 py-1.5 text-sm bg-green-100 text-green-700 rounded-md hover:bg-green-200 cursor-pointer\"\n onClick={() => setActiveColumnMenu(null)}\n >\n Apply\n </button>\n {paginationMode === \"server\" && (\n <button\n className=\"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700\"\n onClick={() =>\n handleApplyFilter(column.key)\n }\n >\n Apply\n </button>\n )}\n </div>\n </div>\n )}\n {activeTab === \"reorder\" && (\n <div className=\"px-3 py-2\">\n <div className=\"text-xs font-medium text-gray-500 mb-1\">\n Reorder Columns\n </div>\n <div className=\"max-h-60 overflow-auto border border-gray-200 rounded-md\">\n {(() => {\n const ordered = [\n ...columnOrder\n .map((k) =>\n allColumns.find((c) => c.key === k)\n )\n .filter(Boolean),\n ...allColumns.filter(\n (c) => !columnOrder.includes(c.key)\n ),\n ] as GridColumn[];\n\n return ordered.map((c) => {\n const isPinnedItem = pinnedKeySet.has(\n c.key\n );\n return (\n <div\n key={c.key}\n className={`flex items-center justify-between px-2 py-1 text-sm bg-white hover:bg-gray-50 border-b last:border-b-0 relative ${\n menuReorderDraggingKey === c.key\n ? \"opacity-60\"\n : \"\"\n } ${\n isPinnedItem ? \"bg-blue-50/40\" : \"\"\n }`}\n draggable\n onDragStart={(e) =>\n handleMenuReorderDragStart(c.key, e)\n }\n onDragOver={(e) =>\n handleMenuReorderDragOver(c.key, e)\n }\n onDrop={() =>\n handleMenuReorderDrop(c.key)\n }\n onDragEnd={handleMenuReorderDragEnd}\n >\n {menuReorderDragOver?.key ===\n c.key && (\n <div\n className=\"absolute left-0 right-0 h-0.5 bg-blue-600\"\n style={{\n top:\n menuReorderDragOver?.position ===\n \"before\"\n ? 0\n : undefined,\n bottom:\n menuReorderDragOver?.position ===\n \"after\"\n ? 0\n : undefined,\n }}\n />\n )}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-gray-400 select-none\">\n ⋮⋮\n </span>\n <span className=\"text-gray-800 truncate max-w-45\">\n {c.header}\n {isPinnedItem && (\n <span className=\"ml-1 text-[10px] text-blue-600\">\n (pinned)\n </span>\n )}\n </span>\n </div>\n </div>\n );\n });\n })()}\n </div>\n <div className=\"text-[10px] text-gray-400 mt-1\">\n Tip: You can only reorder within pinned or\n unpinned groups.\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Resize handle */}\n {index < unpinnedColumns.length - 1 && onColumnResize && (\n <div\n className=\"absolute top-0 right-0 w-1 h-full cursor-col-resize hover:bg-blue-300 transition-colors group\"\n onMouseDown={(e) => handleResizeStart(column.key, e)}\n onDoubleClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onAutosizeColumn?.(column.key);\n }}\n title=\"Drag to resize • Double‑click to autosize\"\n >\n <div className=\"w-full h-full group-hover:bg-blue-400\" />\n </div>\n )}\n </div>\n );\n })}\n\n {/* Spacer after last visible unpinned col */}\n {hvPadRight > 0 && (\n <div\n style={{ width: hvPadRight, height: headerHeight }}\n className=\"flex-none\"\n />\n )}\n </div>\n </div>\n\n {/* Inline filter handled in dropdown tabs */}\n </>\n );\n};\n"],"names":["GridHeader","pinnedColumns","unpinnedColumns","hvPadLeft","hvPadRight","headerHeight","sortConfig","columnFilters","selectable","selectedRows","totalRows","data","onSort","onColumnFilter","onSelectAll","onColumnResize","pinnedKeySet","Set","onColumnPin","groupable","groupedByColumn","onGroupBy","groupedByColumns","onGroupToggle","onAutosizeColumn","onAutosizeAllColumns","onResetColumns","columnOrder","onColumnOrderChange","paginationMode","allColumns","activeColumnMenu","setActiveColumnMenu","useState","menuPosition","setMenuPosition","isResizing","setIsResizing","startX","setStartX","startWidth","setStartWidth","activeTab","setActiveTab","tempFilter","setTempFilter","isTouchDevice","setIsTouchDevice","useEffect","window","navigator","maxTouchPoints","matchMedia","matches","menuReorderDraggingKey","setMenuReorderDraggingKey","menuReorderDragOver","setMenuReorderDragOver","isAllSelected","size","isIndeterminate","handleColumnMenuClick","columnKey","event","stopPropagation","rect","currentTarget","getBoundingClientRect","containerEl","closest","containerRect","DOMRect","innerWidth","innerHeight","MENU_WIDTH","PADDING","minLeft","left","maxLeft","right","clampedLeft","Math","max","min","top","bottom","handleApplyFilter","hasActiveFilter","handleResizeStart","preventDefault","clientX","column","find","col","key","width","handleResizeMove","deltaX","newWidth","handleResizeEnd","draggingKey","setDraggingKey","dragOver","setDragOver","handleDragStart","e","dataTransfer","effectAllowed","setData","handleDragOver","targetKey","dropEffect","midpoint","position","handleDrop","sourceKey","has","before","base","filter","k","idx","indexOf","splice","handleDragEnd","handleMenuReorderDragStart","handleMenuReorderDragOver","height","clientY","handleMenuReorderDrop","handleMenuReorderDragEnd","document","addEventListener","body","style","cursor","userSelect","removeEventListener","handleClickOutside","target","_jsx","_Fragment","children","className","role","_jsxs","SELECT_COL_WIDTH","type","checked","ref","el","indeterminate","onChange","onKeyDown","title","map","index","isPinned","pinnedKeysInOrder","c","pinnedIndex","leftOffset","slice","reduce","sum","headerJustify","headerAlign","colSortable","sortable","draggable","onDragStart","onDragOver","onDrop","onDragEnd","undefined","onClick","header","direction","ArrowUp","ArrowDown","filterable","Menu","maxHeight","Filter","ArrowUpDown","Pin","PinOff","isGrouped","includes","Ungroup","Group","FilterX","FilterContent","value","val","Boolean","isPinnedItem","length","onMouseDown","onDoubleClick","nextPinned"],"mappings":"qXA4Da,MAAAA,EAAa,EACxBC,gBACAC,kBACAC,YAAY,EACZC,aAAa,EACbC,eACAC,aACAC,gBACAC,aACAC,eACAC,YACAC,OACAC,SACAC,iBACAC,cACAC,iBACAC,eAAe,IAAIC,IACnBC,cACAC,aAAY,EACZC,kBACAC,YACAC,mBAAmB,GACnBC,gBACAC,mBACAC,uBACAC,iBACAC,cACAC,sBACAC,iBAAiB,aAEjB,MAAMC,EAAa,IAAI7B,KAAkBC,IAClC6B,EAAkBC,GAAuBC,EAAwB,OACjEC,EAAcC,GAAmBF,EAI9B,OACHG,EAAYC,GAAiBJ,EAAwB,OACrDK,EAAQC,GAAaN,EAAiB,IACtCO,GAAYC,IAAiBR,EAAiB,IAC9CS,GAAWC,IAAgBV,EAChC,SAEKW,GAAYC,IAAiBZ,EAAmC,OAChEa,GAAeC,IAAoBd,GAAS,GAEnDe,EAAU,KACRD,GACE,iBAAkBE,QAChBC,UAAUC,eAAiB,GAC3BF,OAAOG,WAAW,qBAAqBC,UAE1C,IAGH,MAAOC,GAAwBC,IAA6BtB,EAE1D,OACKuB,GAAqBC,IAA0BxB,EAG5C,MAEJyB,GAAgBjD,EAAakD,OAASjD,GAAaA,EAAY,EAC/DkD,GACJnD,EAAakD,KAAO,GAAKlD,EAAakD,KAAOjD,EAEzCmD,GAAwB,CAC5BC,EACAC,KAGA,GADAA,EAAMC,kBACFjC,IAAqB+B,EACvB9B,EAAoB,UACf,CACLA,EAAoB8B,GACpBnB,GAAa,QACbE,GAActC,EAAcuD,IAAc,MAG1C,MAAMG,EAAOF,EAAMG,cAAcC,wBAE3BC,EAAcL,EAAMG,cAAcG,QACtC,yBAEIC,EAAgBF,EAClBA,EAAYD,wBACZ,IAAII,QAAQ,EAAG,EAAGtB,OAAOuB,WAAYvB,OAAOwB,aAE1CC,EAAa,IACbC,EAAU,GAGVC,EAAUN,EAAcO,KAAOF,EAC/BG,EAAUR,EAAcS,MAAQL,EAAaC,EAC7CK,EAAcC,KAAKC,IAAIN,EAASK,KAAKE,IAAIlB,EAAKY,KAAMC,IAE1D3C,EAAgB,CACdiD,IAAKnB,EAAKoB,OAAS,EACnBR,KAAMG,EACNV,iBAEH,GAGGgB,GAAqBxB,IACzBjD,EAAeiD,EAAWlB,IAAc,MACxCZ,EAAoB,OAGhBuD,GAAmBzB,GACY,MAA5BvD,EAAcuD,GAGjB0B,GAAoB,CAAC1B,EAAmBC,KAC5CA,EAAM0B,iBACNpD,EAAcyB,GACdvB,EAAUwB,EAAM2B,SAChB,MAAMC,EAAS,IAAI1F,KAAkBC,GAAiB0F,KACnDC,GAAQA,EAAIC,MAAQhC,GAEvBrB,GAAckD,GAAQI,OAAS,MAG3BC,GAAoBjC,IACxB,IAAK3B,IAAerB,EAAgB,OAEpC,MAAMkF,EAASlC,EAAM2B,QAAUpD,EACzB4D,EAAWjB,KAAKC,IAAI,GAAI1C,GAAayD,GAC3ClF,EAAeqB,EAAY8D,IAGvBC,GAAkB,KACtB9D,EAAc,MACdE,EAAU,GACVE,GAAc,KAIT2D,GAAaC,IAAkBpE,EAAwB,OACvDqE,GAAUC,IAAetE,EAGtB,MAIJuE,GAAkB,CACtB1C,EACA2C,KAEAJ,GAAevC,GACf2C,EAAEC,aAAaC,cAAgB,OAC/BF,EAAEC,aAAaE,QAAQ,aAAc9C,IAGjC+C,GAAiB,CACrBC,EACAL,KAGAA,EAAEhB,iBACFgB,EAAEC,aAAaK,WAAa,OAC5B,MAAM9C,EAAQwC,EAAEvC,cAAiCC,wBAC3C6C,EAAW/C,EAAKY,KAAOZ,EAAK8B,MAAQ,EACpCkB,EAAWR,EAAEf,QAAUsB,EAAW,SAAW,QACnDT,GAAY,CAAET,IAAKgB,EAAWG,cAG1BC,GAAcJ,IAClB,MAAMK,EAAYf,GAClB,IAAKe,GAAaA,IAAcL,EAAW,OAK3C,GAFqB9F,EAAaoG,IAAID,KACjBnG,EAAaoG,IAAIN,GAIpC,OAFAT,GAAe,WACfE,GAAY,MAId,MAAMc,EACJf,IAAUR,MAAQgB,GAAmC,WAAvBR,IAAUW,SACpCK,EAAO3F,EAAY4F,OAAQC,GAAMA,IAAML,GAC7C,IAAIM,EAAMH,EAAKI,QAAQZ,GACvB,IAAa,IAATW,EAIF,OAHA7F,EAAoB0F,GACpBjB,GAAe,WACfE,GAAY,MAGTc,IAAQI,GAAO,GACpBH,EAAKK,OAAOF,EAAK,EAAGN,GAEpBvF,EADa0F,GAEbjB,GAAe,MACfE,GAAY,OAGRqB,GAAgB,KACpBvB,GAAe,MACfE,GAAY,OAIRsB,GAA6B,CACjC/D,EACA2C,KAEAlD,GAA0BO,GAC1B2C,EAAEC,aAAaC,cAAgB,OAC/BF,EAAEC,aAAaE,QAAQ,aAAc9C,IAGjCgE,GAA4B,CAChChB,EACAL,KAEAA,EAAEhB,iBACFgB,EAAEC,aAAaK,WAAa,OAC5B,MAAM9C,EAAQwC,EAAEvC,cAAiCC,wBAC3C6C,EAAW/C,EAAKmB,IAAMnB,EAAK8D,OAAS,EACpCd,EAAWR,EAAEuB,QAAUhB,EAAW,SAAW,QACnDvD,GAAuB,CAAEqC,IAAKgB,EAAWG,cAGrCgB,GAAyBnB,IAC7B,MAAMK,EAAY7D,GAClB,IAAK6D,GAAaA,IAAcL,EAAW,OAK3C,GAFqB9F,EAAaoG,IAAID,KACjBnG,EAAaoG,IAAIN,GAIpC,OAFAvD,GAA0B,WAC1BE,GAAuB,MAIzB,MAAM4D,EACJ7D,IAAqBsC,MAAQgB,GACS,WAAlCtD,IAAqByD,SAErBK,EAAO3F,EAAY4F,OAAQC,GAAMA,IAAML,GAC7C,IAAIM,EAAMH,EAAKI,QAAQZ,GACvB,IAAa,IAATW,EAIF,OAHA7F,EAAoB0F,GACpB/D,GAA0B,WAC1BE,GAAuB,MAGpB4D,IAAQI,GAAO,GACpBH,EAAKK,OAAOF,EAAK,EAAGN,GACpBvF,EAAoB0F,GACpB/D,GAA0B,MAC1BE,GAAuB,OAGnByE,GAA2B,KAC/B3E,GAA0B,MAC1BE,GAAuB,OAoCzB,OAhCAT,EAAU,KACR,GAAIZ,EAMF,OALA+F,SAASC,iBAAiB,YAAapC,IACvCmC,SAASC,iBAAiB,UAAWjC,IACrCgC,SAASE,KAAKC,MAAMC,OAAS,aAC7BJ,SAASE,KAAKC,MAAME,WAAa,OAE1B,KACLL,SAASM,oBAAoB,YAAazC,IAC1CmC,SAASM,oBAAoB,UAAWtC,IACxCgC,SAASE,KAAKC,MAAMC,OAAS,GAC7BJ,SAASE,KAAKC,MAAME,WAAa,KAGpC,CAACpG,EAAYE,EAAQE,GAAYzB,IAGpCiC,EAAU,KACR,MAAM0F,EAAsB3E,IAC1B,MAAM4E,EAAS5E,EAAM4E,OACjB5G,IAAqB4G,EAAOtE,QAAQ,uBACtCrC,EAAoB,OAIxB,GAAID,EAEF,OADAoG,SAASC,iBAAiB,YAAaM,GAChC,IACLP,SAASM,oBAAoB,YAAaC,IAE7C,CAAC3G,IAGF6G,EAAAC,EAAA,CAAAC,SACEF,EACE,MAAA,CAAAG,UAAU,4EACVT,MAAO,CAAEP,OAAQ1H,GACjB2I,KAAK,MAAK,aACC,iBAAgBF,SAE3BG,SAAKF,UAAU,cAAaD,SAAA,CACzBtI,GACCoI,EAAA,MAAA,CACEG,UAAU,2IACVT,MAAO,CAAEvC,MAAOmD,EAAkBnB,OAAQ1H,GAC1C2I,KAAK,eAAc,aACR,kBAAiBF,SAE5BF,EACE,QAAA,CAAAO,KAAK,WACLC,QAAS1F,GACT2F,IAAMC,IACAA,IAAIA,EAAGC,cAAgB3F,KAE7B4F,SAAU1I,EACV2I,UAAYhD,IACI,MAAVA,EAAEX,KAAyB,UAAVW,EAAEX,MACrBW,EAAEhB,iBACF3E,MAGJiI,UAAU,6KAERrF,GACI,oBACAE,GACA,GAAGnD,EAAakD,0CAChB,kBAEN+F,MACEhG,GACI,gBAAgBhD,SAChBkD,GACA,GAAGnD,EAAakD,WAAWjD,kBAC3B,cAAcA,aAOzBT,EAAc0J,IAAI,CAAChE,EAAQiE,KAC1B,MAAMC,EAAW7I,EAAaoG,IAAIzB,EAAOG,KACnCgE,EAAoB7J,EACvBsH,OAAQwC,GAAM/I,EAAaoG,IAAI2C,EAAEjE,MACjC6D,IAAKI,GAAMA,EAAEjE,KACVkE,EAAcF,EAAkBpC,QAAQ/B,EAAOG,KAC/CmE,EAAaJ,EACfC,EAAkBI,MAAM,EAAGF,GAAaG,OACtC,CAACC,EAAKtE,KACJ,MAAMD,EAAM5F,EAAc2F,KAAMmE,GAAMA,EAAEjE,MAAQA,GAChD,OAAOsE,GAAOvE,GAAKE,OAAS,MAE9BvF,EAAa0I,EAAmB,GAElC,EAEEmB,EACmB,WAAvB1E,EAAO2E,YACH,iBACuB,UAAvB3E,EAAO2E,YACP,cACA,gBAGAC,GAAkC,IAApB5E,EAAO6E,SAC3B,OACEvB,EAAA,MAAA,CAEEF,UAAW,oFACTc,EACI,iFACA,MAENvB,MAAO,CACLvC,MAAOJ,EAAOI,OAAS,IACvBlB,KAAMgF,EAAW,GAAGI,MAAiB,OACrClC,OAAQ1H,GACT,kBACgBsF,EAAOG,IACxB2E,WACA,EAAAC,YAAcjE,GAAMD,GAAgBb,EAAOG,IAAKW,GAChDkE,WAAalE,GAAMI,GAAelB,EAAOG,IAAKW,GAC9CmE,OAAQ,IAAM1D,GAAWvB,EAAOG,KAChC+E,UAAWjD,GAAakB,SAAA,CAGvBxC,IAAUR,MAAQH,EAAOG,KACxB8C,SACEG,UAAU,gDACVT,MAAO,CACLzD,KAA6B,WAAvByB,IAAUW,SAAwB,OAAI6D,EAC5C/F,MAA8B,UAAvBuB,IAAUW,SAAuB,OAAI6D,KAIlDlC,EAAK,MAAA,CAAAG,UAAU,cAAaD,SAE1BG,EAAK,MAAA,CAAAF,UAAU,uDAAsDD,SAAA,CACnEG,EACE,MAAA,CAAAF,UAAW,oCAAoCsB,KAC7CE,EAAc,qCAAuC,KAEvDQ,QAAS,IAAMR,GAAe3J,EAAO+E,EAAOG,eAE5CmD,EAAK,MAAA,CAAAF,UAAU,4CAEZxD,GAAgBI,EAAOG,MACtB8C,EAAA,MAAA,CACEG,UAAU,2CACVW,MAAM,mBAGVd,EAAM,OAAA,CAAAG,UAAU,iFACbpD,EAAOqF,YAGXT,GAAejK,EAAWwF,MAAQH,EAAOG,KACxC8C,EAAA,MAAA,CAAKG,UAAU,gDACZD,SAAyB,QAAzBxI,EAAW2K,UACVrC,EAACsC,EAAQ,CAAAnC,UAAU,6CAEnBH,EAACuC,EAAS,CAACpC,UAAU,mDAO3BpD,EAAOyF,YAAclK,GAAeC,IACpC8H,EACE,MAAA,CAAAF,UAAW,aACThH,IAAqB4D,EAAOG,KAAOhD,GAC/B,QACA,4BACJ,oBAAA,EAAAgG,SAAA,CAGFF,YACEG,UAAU,gEACVgC,QAAUtE,GAAM5C,GAAsB8B,EAAOG,IAAKW,mCAGlDmC,EAACyC,GAAKtC,UAAU,+CAIjBhH,IAAqB4D,EAAOG,KAAO5D,GAClC+G,EAAA,MAAA,CACEF,UAAU,kIACVT,MAAO,CACLlD,IAAK,GAAGlD,EAAakD,QACrBP,KAAM,GAAG3C,EAAa2C,SAEtByG,UAAW,GAAGrG,KAAKC,IACjB,IACAhD,EAAaoC,cAAce,OACzB,GACAnD,EAAakD,UAMnB,oBAAA,EAAA0D,SAAA,CAAAG,EAAA,MAAA,CAAKF,UAAU,kEAAiED,SAAA,CAC9EF,EACE,SAAA,CAAAG,UAAW,8CACK,SAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,QAAOmG,SAEnCF,EAACyC,EAAI,CAACtC,UAAU,cAEjBpD,EAAOyF,YACNxC,YACEG,UAAW,8CACK,WAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,UAE5BmG,SAAAF,EAAC2C,EAAM,CAACxC,UAAU,cAGtBH,EAAA,SAAA,CACEG,UAAW,8CACK,YAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,WAAUmG,SAEtCF,EAAC4C,EAAW,CAACzC,UAAU,iBAIZ,SAAdrG,IACCuG,EAAK,MAAA,CAAAF,UAAU,iBACZ7H,IACEE,IAAoBuE,EAAOG,IAC1BmD,EAAA,MAAA,CAAKF,UAAU,2EACbD,SAAA,CAAAF,EAAC6C,EAAI,CAAA1C,UAAU,YAEX,wBAENH,EAAA,SAAA,CACEG,UAAU,8EACVgC,QAAUtE,IACRA,EAAEzC,kBACFhC,EAAoB,MACpBd,IACEyE,EAAOG,KACN9E,EAAaoG,IAAIzB,EAAOG,OAE5BgD,SAEA9H,EAAaoG,IAAIzB,EAAOG,KACvBmD,EACEJ,EAAA,CAAAC,SAAA,CAAAF,EAAC8C,EAAM,CAAC3C,UAAU,YAAY,kBAIhCE,EACEJ,EAAA,CAAAC,SAAA,CAAAF,EAAC6C,EAAG,CAAC1C,UAAU,YAAY,mBAOpCvH,GACCoH,EAAA,SAAA,CACEG,UAAU,sDACVgC,QAAS,KACPvJ,IAAmBmE,EAAOG,KAC1B9D,EAAoB,OAIf8G,SAAA,yBAEVrH,GACCmH,EAAA,SAAA,CACEG,UAAU,sDACVgC,QAAS,KACPtJ,MACAO,EAAoB,yCAOzBb,GACCyH,EACE,SAAA,CAAAG,UAAU,8EACVgC,QAAUtE,IACRA,EAAEzC,kBACFhC,EAAoB,MACpB,MAAM2J,EACJrK,GAAkBsK,SAChBjG,EAAOG,MACJ1E,IAAoBuE,EAAOG,IAC9BvE,EACFA,EAAcoE,EAAOG,KAAM6F,GAE3BtK,IACEsK,EAAY,KAAOhG,EAAOG,MAI/BgD,SAAA1H,IAAoBuE,EAAOG,KAC5BxE,GAAkBsK,SAASjG,EAAOG,KAChCmD,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAACiD,EAAO,CAAC9C,UAAU,yBAIrBE,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAACkD,EAAK,CAAC/C,UAAU,wBACPpD,EAAOqF,YAMxBtJ,GACCkH,EACE,SAAA,CAAAG,UAAU,sDACVgC,QAAS,KACPrJ,MACAM,EAAoB,OAIf8G,SAAA,qBAIA,WAAdpG,IACCuG,EAAK,MAAA,CAAAF,UAAU,aAAYD,SAAA,CAExBvD,GAAgBI,EAAOG,MACtBmD,EAAA,SAAA,CACEF,UAAU,oEACVgC,QAAS,KACPlI,GAAc,MACdhC,EAAe8E,EAAOG,IAAK,MAC3B9D,EAAoB,iBAGtB4G,EAACmD,EAAQ,CAAAhD,UAAU,YACZ,mBAEXH,EAAK,MAAA,CAAAG,UAAU,uCACbH,EAACoD,EACC,CAAArG,OAAQA,EACRhF,KAAMA,EACNsL,MAAOrJ,GACP4G,SAAW0C,IACTrJ,GAAcqJ,GAES,WAAnBrK,GACFhB,EAAe8E,EAAOG,IAAKoG,QAKf,WAAnBrK,EACCoH,EAAA,MAAA,CAAKF,UAAU,wCACbH,EACE,SAAA,CAAAG,UAAU,6EACVgC,QAAS,IAAM/I,EAAoB,MAAK8G,SAAA,WAI1CF,EACE,SAAA,CAAAG,UAAU,0EACVgC,QAAS,IACPzF,GAAkBK,EAAOG,KAIpBgD,SAAA,aAGXF,SAAKG,UAAU,wBACbD,SAAAF,EAAA,SAAA,CACEG,UAAU,0EACVgC,QAAS,IAAM/I,EAAoB,MAG5B8G,SAAA,eAKF,YAAdpG,IACCuG,EAAK,MAAA,CAAAF,UAAU,YACbD,SAAA,CAAAF,EAAA,MAAA,CAAKG,UAAU,yCAETD,SAAA,oBACNF,EAAK,MAAA,CAAAG,UAAU,2DAA0DD,SAGrD,IACXnH,EACAgI,IAAKnC,GACJ1F,EAAW8D,KAAMmE,GAAMA,EAAEjE,MAAQ0B,IAElCD,OAAO4E,YAEPrK,EAAWyF,OACXwC,IAAOpI,EAAYiK,SAAS7B,EAAEjE,OAIpB6D,IAAKI,IAClB,MAAMqC,EAAepL,EAAaoG,IAChC2C,EAAEjE,KAEJ,OACEmD,SAEEF,UAAW,mHACTzF,KAA2ByG,EAAEjE,IACzB,aACA,MAEJsG,EAAe,gBAAkB,KAEnC3B,WACA,EAAAC,YAAcjE,GACZoB,GAA2BkC,EAAEjE,IAAKW,GAEpCkE,WAAalE,GACXqB,GAA0BiC,EAAEjE,IAAKW,GAEnCmE,OAAQ,IACN3C,GAAsB8B,EAAEjE,KAE1B+E,UAAW3C,GAGVY,SAAA,CAAAtF,IAAqBsC,MACpBiE,EAAEjE,KACF8C,EAAA,MAAA,CACEG,UAAU,4CACVT,MAAO,CACLlD,IAEE,WADA5B,IAAqByD,SAEjB,OACA6D,EACNzF,OAEE,UADA7B,IAAqByD,SAEjB,OACA6D,KAIZ7B,EAAA,MAAA,CAAKF,UAAU,0BACbD,SAAA,CAAAF,EAAA,OAAA,CAAMG,UAAU,4BAETD,SAAA,OACPG,UAAMF,UAAU,kCACbD,SAAA,CAAAiB,EAAEiB,OACFoB,GACCxD,EAAM,OAAA,CAAAG,UAAU,iCAAgCD,SAAA,qBA9CjDiB,EAAEjE,SAyDjB8C,EAAA,MAAA,CAAKG,UAAU,iCAGTD,SAAA,8EAWrBc,EAAQ3J,EAAcoM,OAAS,GAAKtL,GACnC6H,EAAA,MAAA,CACEG,UAAU,gGACVuD,YAAc7F,GAAMjB,GAAkBG,EAAOG,IAAKW,GAClD8F,cAAgB9F,IACdA,EAAEhB,iBACFgB,EAAEzC,kBACFxC,IAAmBmE,EAAOG,MAE5B4D,MAAM,qDAENd,EAAK,MAAA,CAAAG,UAAU,8CAhZdpD,EAAOG,IAAM8D,KAwZvBzJ,EAAY,GACXyI,EACE,MAAA,CAAAN,MAAO,CAAEvC,MAAO5F,EAAW4H,OAAQ1H,GACnC0I,UAAU,cAKb7I,EAAgByJ,IAAI,CAAChE,EAAQiE,KAE5B,MAAMS,EACmB,WAAvB1E,EAAO2E,YACH,iBACuB,UAAvB3E,EAAO2E,YACP,cACA,gBAEAC,GAAkC,IAApB5E,EAAO6E,SAC3B,OACEvB,EAEE,MAAA,CAAAF,UAAW,mFACXT,MAAO,CAAEvC,MAAOJ,EAAOI,OAAS,IAAKgC,OAAQ1H,qBAC5BsF,EAAOG,IACxB2E,aACAC,YAAcjE,GAAMD,GAAgBb,EAAOG,IAAKW,GAChDkE,WAAalE,GAAMI,GAAelB,EAAOG,IAAKW,GAC9CmE,OAAQ,IAAM1D,GAAWvB,EAAOG,KAChC+E,UAAWjD,aAGVtB,IAAUR,MAAQH,EAAOG,KACxB8C,EACE,MAAA,CAAAG,UAAU,gDACVT,MAAO,CACLzD,KAA6B,WAAvByB,IAAUW,SAAwB,OAAI6D,EAC5C/F,MAA8B,UAAvBuB,IAAUW,SAAuB,OAAI6D,KAIlDlC,EAAK,MAAA,CAAAG,UAAU,cAAaD,SAE1BG,EAAK,MAAA,CAAAF,UAAU,uDAAsDD,SAAA,CACnEG,EACE,MAAA,CAAAF,UAAW,oCAAoCsB,KAC7CE,EAAc,qCAAuC,KAEvDQ,QAAS,IAAMR,GAAe3J,EAAO+E,EAAOG,eAE5CmD,EAAK,MAAA,CAAAF,UAAU,4CAEZxD,GAAgBI,EAAOG,MACtB8C,EAAA,MAAA,CACEG,UAAU,2CACVW,MAAM,mBAGVd,EAAM,OAAA,CAAAG,UAAU,iFACbpD,EAAOqF,YAGXT,GAAejK,EAAWwF,MAAQH,EAAOG,KACxC8C,EAAA,MAAA,CAAKG,UAAU,gDACZD,SAAyB,QAAzBxI,EAAW2K,UACVrC,EAACsC,EAAQ,CAAAnC,UAAU,6CAEnBH,EAACuC,EAAS,CAACpC,UAAU,mDAO3BpD,EAAOyF,YAAclK,GAAeC,IACpC8H,EACE,MAAA,CAAAF,UAAW,aACThH,IAAqB4D,EAAOG,KAAOhD,GAC/B,QACA,4BACJ,oBAAA,EAAAgG,SAAA,CAGFF,YACEG,UAAU,gEACVgC,QAAUtE,GAAM5C,GAAsB8B,EAAOG,IAAKW,mCAGlDmC,EAACyC,GAAKtC,UAAU,+CAIjBhH,IAAqB4D,EAAOG,KAAO5D,GAClC+G,EAAA,MAAA,CACEF,UAAU,gIACVT,MAAO,CACLlD,IAAK,GAAGlD,EAAakD,QACrBP,KAAM,GAAG3C,EAAa2C,SAEtByG,UAAW,GAAGrG,KAAKC,IACjB,IACAhD,EAAaoC,cAAce,OACzB,GACAnD,EAAakD,UAMnB,oBAAA,EAAA0D,SAAA,CAAAG,EAAA,MAAA,CAAKF,UAAU,kEAAiED,SAAA,CAC9EF,EACE,SAAA,CAAAG,UAAW,8CACK,SAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,QAAOmG,SAEnCF,EAACyC,EAAI,CAACtC,UAAU,cAEjBpD,EAAOyF,YACNxC,YACEG,UAAW,8CACK,WAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,UAE5BmG,SAAAF,EAAC2C,EAAM,CAACxC,UAAU,cAGtBH,EAAA,SAAA,CACEG,UAAW,8CACK,YAAdrG,GACI,2CACA,iBAENqI,QAAS,IAAMpI,GAAa,oBAE5BiG,EAAC4C,GAAYzC,UAAU,iBAIZ,SAAdrG,IACCuG,SAAKF,UAAU,OAAMD,SAAA,CAClB5H,GACC0H,EACE,SAAA,CAAAG,UAAU,8EACVgC,QAAUtE,IACRA,EAAEzC,kBACFhC,EAAoB,MACpB,MAAMwK,GAAcxL,EAAaoG,IAC/BzB,EAAOG,KAET5E,IAAcyE,EAAOG,IAAK0G,IAC3B1D,SAEA9H,EAAaoG,IAAIzB,EAAOG,KACvBmD,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAAC8C,EAAO,CAAA3C,UAAU,YAEjB,kBAEHE,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAAC6C,EAAI,CAAA1C,UAAU,YAEd,kBAIRvH,GACCoH,EAAA,SAAA,CACEG,UAAU,sDACVgC,QAAS,KACPvJ,IAAmBmE,EAAOG,KAC1B9D,EAAoB,OAIf8G,SAAA,yBAEVrH,GACCmH,EAAA,SAAA,CACEG,UAAU,sDACVgC,QAAS,KACPtJ,MACAO,EAAoB,yCAOzBb,GACCyH,EACE,SAAA,CAAAG,UAAU,8EACVgC,QAAUtE,IACRA,EAAEzC,kBACFhC,EAAoB,MACpB,MAAM2J,EACJrK,GAAkBsK,SAChBjG,EAAOG,MACJ1E,IAAoBuE,EAAOG,IAC9BvE,EACFA,EAAcoE,EAAOG,KAAM6F,GAE3BtK,IACEsK,EAAY,KAAOhG,EAAOG,MAI/BgD,SAAA1H,IAAoBuE,EAAOG,KAC5BxE,GAAkBsK,SAASjG,EAAOG,KAChCmD,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAACiD,EAAO,CAAC9C,UAAU,yBAIrBE,EAAAJ,EAAA,CAAAC,SAAA,CACEF,EAACkD,EAAK,CAAC/C,UAAU,wBACPpD,EAAOqF,YAMxBtJ,GACCkH,EACE,SAAA,CAAAG,UAAU,sDACVgC,QAAS,KACPrJ,MACAM,EAAoB,qCAQf,WAAdU,IACCuG,EAAA,MAAA,CAAKF,UAAU,uBACbH,EAAK,MAAA,CAAAG,UAAU,8BAA6BD,SAC1CF,EAACoD,GACCrG,OAAQA,EACRhF,KAAMA,EACNsL,MAAOrJ,GACP4G,SAAW0C,IACTrJ,GAAcqJ,GAES,WAAnBrK,GACFhB,EAAe8E,EAAOG,IAAKoG,QAKnCjD,EAAK,MAAA,CAAAF,UAAU,8BAA6BD,SAAA,CACzCvD,GAAgBI,EAAOG,MACtBmD,EAAA,SAAA,CACEF,UAAU,+GACVgC,QAAS,KACPlI,GAAc,MACdhC,EAAe8E,EAAOG,IAAK,MAC3B9D,EAAoB,iBAGtB4G,EAACmD,EAAQ,CAAAhD,UAAU,YAEZ,mBAEXH,EACE,SAAA,CAAAG,UAAU,+FACVgC,QAAS,IAAM/I,EAAoB,yBAIjB,WAAnBH,GACC+G,EAAA,SAAA,CACEG,UAAU,0EACVgC,QAAS,IACPzF,GAAkBK,EAAOG,KAIpBgD,SAAA,gBAKF,YAAdpG,IACCuG,EAAA,MAAA,CAAKF,UAAU,YACbD,SAAA,CAAAF,EAAA,MAAA,CAAKG,UAAU,yCAETD,SAAA,oBACNF,SAAKG,UAAU,2DACZD,SACiB,IACXnH,EACAgI,IAAKnC,GACJ1F,EAAW8D,KAAMmE,GAAMA,EAAEjE,MAAQ0B,IAElCD,OAAO4E,YACPrK,EAAWyF,OACXwC,IAAOpI,EAAYiK,SAAS7B,EAAEjE,OAIpB6D,IAAKI,IAClB,MAAMqC,EAAepL,EAAaoG,IAChC2C,EAAEjE,KAEJ,OACEmD,SAEEF,UAAW,mHACTzF,KAA2ByG,EAAEjE,IACzB,aACA,MAEJsG,EAAe,gBAAkB,KAEnC3B,WACA,EAAAC,YAAcjE,GACZoB,GAA2BkC,EAAEjE,IAAKW,GAEpCkE,WAAalE,GACXqB,GAA0BiC,EAAEjE,IAAKW,GAEnCmE,OAAQ,IACN3C,GAAsB8B,EAAEjE,KAE1B+E,UAAW3C,GAEVY,SAAA,CAAAtF,IAAqBsC,MACpBiE,EAAEjE,KACF8C,EAAA,MAAA,CACEG,UAAU,4CACVT,MAAO,CACLlD,IAEE,WADA5B,IAAqByD,SAEjB,OACA6D,EACNzF,OAEE,UADA7B,IAAqByD,SAEjB,OACA6D,KAIZ7B,EAAA,MAAA,CAAKF,UAAU,0BACbD,SAAA,CAAAF,EAAA,OAAA,CAAMG,UAAU,4BAETD,SAAA,OACPG,UAAMF,UAAU,kCACbD,SAAA,CAAAiB,EAAEiB,OACFoB,GACCxD,EAAM,OAAA,CAAAG,UAAU,iCAAgCD,SAAA,qBA7CjDiB,EAAEjE,SAwDjB8C,EAAA,MAAA,CAAKG,UAAU,iCAGTD,SAAA,8EAWrBc,EAAQ1J,EAAgBmM,OAAS,GAAKtL,GACrC6H,EAAA,MAAA,CACEG,UAAU,gGACVuD,YAAc7F,GAAMjB,GAAkBG,EAAOG,IAAKW,GAClD8F,cAAgB9F,IACdA,EAAEhB,iBACFgB,EAAEzC,kBACFxC,IAAmBmE,EAAOG,MAE5B4D,MAAM,qDAENd,EAAK,MAAA,CAAAG,UAAU,8CArXdpD,EAAOG,IAAM8D,KA6XvBxJ,EAAa,GACZwI,EAAA,MAAA,CACEN,MAAO,CAAEvC,MAAO3F,EAAY2H,OAAQ1H,GACpC0I,UAAU"}
@@ -0,0 +1,49 @@
1
+ import { CSSProperties, MouseEvent } from "react";
2
+ import { GridRow, GridColumn, VirtualizedRange } from "../types";
3
+ interface GridRowsProps {
4
+ data: GridRow[];
5
+ columns: GridColumn[];
6
+ selectedRows: Set<string | number>;
7
+ virtualized: boolean;
8
+ virtualizedRange: VirtualizedRange;
9
+ rowHeight: number;
10
+ selectable: boolean;
11
+ isRowSelectable?: (row: GridRow) => boolean;
12
+ onRowSelect: (rowId: string | number, isSelected: boolean) => void;
13
+ pinnedColumns?: Set<string>;
14
+ hvPadLeft?: number;
15
+ hvPadRight?: number;
16
+ rowStyle?: (row: GridRow) => CSSProperties | undefined;
17
+ globalFilter?: string;
18
+ onContextMenu?: (row: GridRow, event: MouseEvent) => void;
19
+ onRowDoubleClick?: (row: GridRow, event: MouseEvent) => void;
20
+ onRowClick?: (row: GridRow, event: MouseEvent) => void;
21
+ onCellClick?: (args: {
22
+ row: GridRow;
23
+ column: GridColumn;
24
+ value: any;
25
+ event: MouseEvent;
26
+ }) => void;
27
+ isCellFocused?: (rowId: string | number, columnKey: string) => boolean;
28
+ isCellSelected?: (rowId: string | number, columnKey: string) => boolean;
29
+ onCellContextMenu?: (args: {
30
+ row: GridRow;
31
+ column: GridColumn;
32
+ value: any;
33
+ displayValue: string;
34
+ event: MouseEvent;
35
+ }) => void;
36
+ onCellMouseDown?: (args: {
37
+ row: GridRow;
38
+ column: GridColumn;
39
+ event: MouseEvent;
40
+ }) => void;
41
+ onCellMouseEnter?: (args: {
42
+ row: GridRow;
43
+ column: GridColumn;
44
+ event: MouseEvent;
45
+ }) => void;
46
+ getRowId?: (row: GridRow) => string | number;
47
+ }
48
+ export declare const GridRows: import("react").MemoExoticComponent<({ data, columns, selectedRows, virtualized, virtualizedRange, rowHeight, selectable, isRowSelectable, onRowSelect, pinnedColumns, hvPadLeft, hvPadRight, rowStyle, globalFilter, onContextMenu, onRowDoubleClick, onRowClick, onCellClick, isCellFocused, isCellSelected, onCellContextMenu, onCellMouseDown, onCellMouseEnter, getRowId, }: GridRowsProps) => import("react/jsx-runtime").JSX.Element>;
49
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsx as e,jsxs as t,Fragment as r}from"react/jsx-runtime";import{memo as n,useMemo as o}from"react";import{SELECT_COL_WIDTH as l}from"../constants.js";import{containsSearchQuery as i,highlightText as a}from"../utils/highlightText.js";const d=n(({data:n,columns:d,selectedRows:s,virtualized:u,virtualizedRange:c,rowHeight:g,selectable:f,isRowSelectable:y,onRowSelect:h,pinnedColumns:b=new Set,hvPadLeft:p=0,hvPadRight:w=0,rowStyle:m,globalFilter:v,onContextMenu:k,onRowDoubleClick:x,onRowClick:C,onCellClick:R,isCellFocused:z,isCellSelected:$,onCellContextMenu:I,onCellMouseDown:M,onCellMouseEnter:S,getRowId:D})=>{const N=o(()=>n.length*g,[n.length,g]),{leftOffsetByPinnedKey:j}=o(()=>{if(0===b.size)return{leftOffsetByPinnedKey:new Map};const e=d.filter(e=>b.has(e.key)).map(e=>e.key),t=new Map;for(const e of d)t.set(e.key,e.width||100);const r=new Map;let n=f?l:0;for(const o of e)r.set(o,n),n+=t.get(o)||100;return{leftOffsetByPinnedKey:r}},[d,b,f]),E=o(()=>d.reduce((e,t)=>e+(b.has(t.key)?1:0),0),[d,b]);return e("div",{style:{height:u?`${N}px`:"auto",position:"relative"},children:e("div",{style:{transform:u?`translate3d(0, ${c.offsetY}px, 0)`:"none",position:u?"absolute":"static",top:0,left:0,right:0},children:n.map((n,o)=>{const N=u?c.startIndex+o:o,P=m?.(n),F=((e,t)=>D?D(e):void 0!==e.id?e.id:("development"===process.env.NODE_ENV&&0===t&&console.warn("[CustomDataGrid] No row IDs found. Either:\n 1. Add 'id' property to each row object, or\n 2. Provide 'getRowId' prop to extract a unique identifier.\n Using row index as fallback ID, but this may cause issues with pagination/filtering."),t??0))(n,N),H=N%2==0?"bg-white dark:bg-gray-900":"bg-gray-25 dark:bg-gray-800",K=s.has(F)?"bg-blue-50 dark:bg-blue-900/20":"";return t("div",{className:`flex border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 ${K||(P?"":H)}`,style:{height:`${g}px`,...P},onContextMenu:e=>((e,t)=>{e.preventDefault(),k?.(t,e)})(e,n),onDoubleClick:e=>((e,t)=>{x?.(t,e)})(e,n),onClick:e=>((e,t)=>{C?.(t,e)})(e,n),children:[f&&e("div",{className:"flex items-center justify-center sticky left-0 bg-white dark:bg-gray-900 z-2 border-r border-gray-200 dark:border-gray-700",style:{width:l},children:e("input",{type:"checkbox",checked:s.has(F),disabled:!!y&&!y(n),onChange:e=>h(F,e.target.checked),onKeyDown:e=>{" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),h(F,!s.has(F)))},className:"rounded border-gray-300 dark:border-gray-600 text-blue-600 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 h-4 w-4 transition-all duration-150","aria-label":`Select row ${F}`,tabIndex:0})}),d.map((o,l)=>{const d=b.has(o.key),s=d&&j.get(o.key)||0,u=n[o.key];let c,g;if(o.cellRenderer?(c=o.cellRenderer(u,n),"string"!=typeof u&&"number"!=typeof u&&"boolean"!=typeof u||(g=String(u))):o.formatter?(c=o.formatter(u),g=String(c)):(c=u??"",g=c?String(c):void 0),v&&v.trim()&&!o.cellRenderer&&c){const e=String(c);i(e,v)&&(c=a(e,v))}g&&0===g.trim().length&&(g=void 0);const f="center"===o.align?"text-center":"right"===o.align?"text-right":"text-left",y="center"===o.align?"justify-center":"right"===o.align?"justify-end":"justify-start",h=o.noPadding?"p-0":"p-3",w="function"==typeof o.className?o.className(u,n):o.className||"",m="function"==typeof o.cellStyle?o.cellStyle(u,n):o.cellStyle||void 0,k=t("div",{className:`border-r border-gray-200 last:border-r-0 ${h} text-sm flex items-center ${$?.(F,o.key)?"bg-blue-100/60 dark:bg-blue-900/30":""} ${d?z?.(F,o.key)?"sticky z-2 bg-inherit":"sticky z-1 bg-inherit":""} ${z?.(F,o.key)?"relative":""} ${f} ${y} ${w}`,style:{width:`${o.width||100}px`,left:d?`${s}px`:"auto",...m},title:g,onClick:e=>((e,t,r,n)=>{R?.({row:t,column:r,value:n,event:e})})(e,n,o,n[o.key]),onContextMenu:e=>{n._isGroupHeader||n._isGroupFooter||I&&(e.preventDefault(),e.stopPropagation(),I({row:n,column:o,value:n[o.key],displayValue:g??"",event:e}))},onMouseDown:e=>M?.({row:n,column:o,event:e}),onMouseEnter:e=>S?.({row:n,column:o,event:e}),children:[z?.(F,o.key)&&e("div",{className:"pointer-events-none absolute inset-0 border border-blue-400"}),!1===o.wrapCellContent?e(r,{children:c}):e("div",{className:"truncate w-full",children:c})]},`${o.key}-${l}`);return p>0&&l===E?t(r,{children:[e("div",{style:{width:p},className:"flex-none"}),k]}):k}),w>0&&e("div",{style:{width:w},className:"flex-none"})]},`${F}-${N}`)})})})},(e,t)=>{if(e.rowHeight!==t.rowHeight)return!1;if(e.selectable!==t.selectable)return!1;if(e.virtualized!==t.virtualized)return!1;if(e.globalFilter!==t.globalFilter)return!1;if(e.virtualizedRange.startIndex!==t.virtualizedRange.startIndex)return!1;if(e.virtualizedRange.endIndex!==t.virtualizedRange.endIndex)return!1;if(e.virtualizedRange.offsetY!==t.virtualizedRange.offsetY)return!1;if(e.isCellSelected!==t.isCellSelected)return!1;if(e.isCellFocused!==t.isCellFocused)return!1;if(e.onCellMouseDown!==t.onCellMouseDown)return!1;if(e.onCellMouseEnter!==t.onCellMouseEnter)return!1;if(e.getRowId!==t.getRowId)return!1;if(e.selectedRows.size!==t.selectedRows.size)return!1;if(e.pinnedColumns?.size!==t.pinnedColumns?.size)return!1;if(e.columns.map(e=>e.key).join("|")!==t.columns.map(e=>e.key).join("|"))return!1;if(e.data.length!==t.data.length)return!1;const r=(e,t,r)=>r?r(e):void 0!==e.id?e.id:t,n=e.data.length>0?r(e.data[0],0,e.getRowId):void 0,o=t.data.length>0?r(t.data[0],0,t.getRowId):void 0,l=e.data.length-1,i=t.data.length-1,a=e.data.length>0?r(e.data[l],l,e.getRowId):void 0,d=t.data.length>0?r(t.data[i],i,t.getRowId):void 0;return n===o&&a===d});export{d as GridRows};
2
+ //# sourceMappingURL=GridRows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridRows.js","sources":["../../../../../components/GridRows.tsx"],"sourcesContent":["import { CSSProperties, MouseEvent, memo, useMemo } from \"react\";\nimport { GridRow, GridColumn, VirtualizedRange } from \"../types\";\nimport { SELECT_COL_WIDTH } from \"../constants\";\nimport { highlightText, containsSearchQuery } from \"../utils/highlightText\";\n\ninterface GridRowsProps {\n data: GridRow[];\n columns: GridColumn[];\n selectedRows: Set<string | number>;\n virtualized: boolean;\n virtualizedRange: VirtualizedRange;\n rowHeight: number;\n selectable: boolean;\n isRowSelectable?: (row: GridRow) => boolean;\n onRowSelect: (rowId: string | number, isSelected: boolean) => void;\n pinnedColumns?: Set<string>;\n hvPadLeft?: number;\n hvPadRight?: number;\n rowStyle?: (row: GridRow) => CSSProperties | undefined;\n globalFilter?: string;\n onContextMenu?: (row: GridRow, event: MouseEvent) => void;\n onRowDoubleClick?: (row: GridRow, event: MouseEvent) => void;\n onRowClick?: (row: GridRow, event: MouseEvent) => void;\n onCellClick?: (args: {\n row: GridRow;\n column: GridColumn;\n value: any;\n event: MouseEvent;\n }) => void;\n // Cell focus & selection\n isCellFocused?: (rowId: string | number, columnKey: string) => boolean;\n isCellSelected?: (rowId: string | number, columnKey: string) => boolean;\n // Cell-level context menu (right-click)\n onCellContextMenu?: (args: {\n row: GridRow;\n column: GridColumn;\n value: any;\n displayValue: string;\n event: MouseEvent;\n }) => void;\n onCellMouseDown?: (args: {\n row: GridRow;\n column: GridColumn;\n event: MouseEvent;\n }) => void;\n onCellMouseEnter?: (args: {\n row: GridRow;\n column: GridColumn;\n event: MouseEvent;\n }) => void;\n getRowId?: (row: GridRow) => string | number;\n}\n\nconst GridRowsComponent = ({\n data,\n columns,\n selectedRows,\n virtualized,\n virtualizedRange,\n rowHeight,\n selectable,\n isRowSelectable,\n onRowSelect,\n pinnedColumns = new Set(),\n hvPadLeft = 0,\n hvPadRight = 0,\n rowStyle,\n globalFilter,\n onContextMenu,\n onRowDoubleClick,\n onRowClick,\n onCellClick,\n isCellFocused,\n isCellSelected,\n onCellContextMenu,\n onCellMouseDown,\n onCellMouseEnter,\n getRowId,\n}: GridRowsProps) => {\n // Helper to extract row ID\n const extractRowId = (row: GridRow, rowIndex?: number): string | number => {\n if (getRowId) {\n return getRowId(row);\n }\n if (row.id !== undefined) {\n return row.id;\n }\n // Fallback: use row index\n if (process.env.NODE_ENV === \"development\" && rowIndex === 0) {\n console.warn(\n \"[CustomDataGrid] No row IDs found. Either:\\n\" +\n \" 1. Add 'id' property to each row object, or\\n\" +\n \" 2. Provide 'getRowId' prop to extract a unique identifier.\\n\" +\n \" Using row index as fallback ID, but this may cause issues with pagination/filtering.\",\n );\n }\n return rowIndex ?? 0;\n };\n const totalHeight = useMemo(\n () => data.length * rowHeight,\n [data.length, rowHeight],\n );\n\n // Precompute pinned metadata for left offsets efficiently - OPTIMIZED\n const { leftOffsetByPinnedKey } = useMemo(() => {\n // Early return if no pinned columns\n if (pinnedColumns.size === 0) {\n return { leftOffsetByPinnedKey: new Map<string, number>() };\n }\n\n const pinnedKeysInOrder = columns\n .filter((c) => pinnedColumns.has(c.key))\n .map((c) => c.key);\n\n // Use direct property access instead of Map for better performance\n const widthByKey = new Map<string, number>();\n for (const col of columns) {\n widthByKey.set(col.key, col.width || 100);\n }\n\n const leftOffsetByPinnedKey = new Map<string, number>();\n let acc = selectable ? SELECT_COL_WIDTH : 0;\n\n for (const key of pinnedKeysInOrder) {\n leftOffsetByPinnedKey.set(key, acc);\n acc += widthByKey.get(key) || 100;\n }\n\n return { leftOffsetByPinnedKey };\n }, [columns, pinnedColumns, selectable]);\n\n // Count how many columns are pinned in the provided visible columns list\n const pinnedCount = useMemo(\n () => columns.reduce((n, c) => n + (pinnedColumns.has(c.key) ? 1 : 0), 0),\n [columns, pinnedColumns],\n );\n\n const handleContextMenu = (e: MouseEvent, row: GridRow) => {\n e.preventDefault();\n onContextMenu?.(row, e);\n };\n\n const handleDoubleClick = (e: MouseEvent, row: GridRow) => {\n onRowDoubleClick?.(row, e);\n };\n\n const handleRowClick = (e: MouseEvent, row: GridRow) => {\n onRowClick?.(row, e);\n };\n\n const handleCellClick = (\n e: MouseEvent,\n row: GridRow,\n column: GridColumn,\n value: any,\n ) => {\n onCellClick?.({ row, column, value, event: e });\n };\n\n return (\n <div\n style={{\n height: virtualized ? `${totalHeight}px` : \"auto\",\n position: \"relative\",\n }}\n >\n <div\n style={{\n transform: virtualized\n ? `translate3d(0, ${virtualizedRange.offsetY}px, 0)`\n : \"none\",\n position: virtualized ? \"absolute\" : \"static\",\n top: 0,\n left: 0,\n right: 0,\n }}\n >\n {data.map((row, index) => {\n const actualIndex = virtualized\n ? virtualizedRange.startIndex + index\n : index;\n const customRowStyles = rowStyle?.(row);\n const rowId = extractRowId(row, actualIndex);\n const defaultRowColor =\n actualIndex % 2 === 0\n ? \"bg-white dark:bg-gray-900\"\n : \"bg-gray-25 dark:bg-gray-800\";\n const selectedRowColor = selectedRows.has(rowId)\n ? \"bg-blue-50 dark:bg-blue-900/20\"\n : \"\";\n\n return (\n <div\n key={`${rowId}-${actualIndex}`}\n className={`flex border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 ${\n selectedRowColor || (customRowStyles ? \"\" : defaultRowColor)\n }`}\n style={{\n height: `${rowHeight}px`,\n ...customRowStyles,\n }}\n onContextMenu={(e) => handleContextMenu(e, row)}\n onDoubleClick={(e) => handleDoubleClick(e, row)}\n onClick={(e) => handleRowClick(e, row)}\n >\n {selectable && (\n <div\n className=\"flex items-center justify-center sticky left-0 bg-white dark:bg-gray-900 z-2 border-r border-gray-200 dark:border-gray-700\"\n style={{ width: SELECT_COL_WIDTH }}\n >\n <input\n type=\"checkbox\"\n checked={selectedRows.has(rowId)}\n disabled={isRowSelectable ? !isRowSelectable(row) : false}\n onChange={(e) => onRowSelect(rowId, e.target.checked)}\n onKeyDown={(e) => {\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault();\n onRowSelect(rowId, !selectedRows.has(rowId));\n }\n }}\n className=\"rounded border-gray-300 dark:border-gray-600 text-blue-600 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 h-4 w-4 transition-all duration-150\"\n aria-label={`Select row ${rowId}`}\n tabIndex={0}\n />\n </div>\n )}\n\n {columns.map((column, colIndex) => {\n const isPinned = pinnedColumns.has(column.key);\n const leftOffset = isPinned\n ? leftOffsetByPinnedKey.get(column.key) || 0\n : 0;\n\n // Optimized cell value processing\n const rawCell = row[column.key];\n let renderedValue: React.ReactNode;\n let displayValue: string | undefined;\n\n // Optimize cell renderer calls\n if (column.cellRenderer) {\n renderedValue = column.cellRenderer(rawCell, row);\n // Only compute display value if needed for tooltip\n if (\n typeof rawCell === \"string\" ||\n typeof rawCell === \"number\" ||\n typeof rawCell === \"boolean\"\n ) {\n displayValue = String(rawCell);\n }\n } else if (column.formatter) {\n renderedValue = column.formatter(rawCell);\n displayValue = String(renderedValue);\n } else {\n renderedValue = rawCell ?? \"\";\n displayValue = renderedValue\n ? String(renderedValue)\n : undefined;\n }\n\n // Apply highlighting for global filter if present and no custom renderer\n if (\n globalFilter &&\n globalFilter.trim() &&\n !column.cellRenderer &&\n renderedValue\n ) {\n const textValue = String(renderedValue);\n if (containsSearchQuery(textValue, globalFilter)) {\n renderedValue = highlightText(textValue, globalFilter);\n }\n }\n\n // Clean up empty display values\n if (displayValue && displayValue.trim().length === 0) {\n displayValue = undefined;\n }\n\n // Pre-compute CSS classes for better performance\n const alignClass =\n column.align === \"center\"\n ? \"text-center\"\n : column.align === \"right\"\n ? \"text-right\"\n : \"text-left\";\n const justifyClass =\n column.align === \"center\"\n ? \"justify-center\"\n : column.align === \"right\"\n ? \"justify-end\"\n : \"justify-start\";\n const paddingClass = column.noPadding ? \"p-0\" : \"p-3\";\n\n // Optimize dynamic class/style computation\n const extraCellClass =\n typeof column.className === \"function\"\n ? column.className(rawCell, row)\n : column.className || \"\";\n const extraCellStyle =\n typeof column.cellStyle === \"function\"\n ? column.cellStyle(rawCell, row)\n : column.cellStyle || undefined;\n\n const cell = (\n <div\n key={`${column.key}-${colIndex}`}\n className={`border-r border-gray-200 last:border-r-0 ${paddingClass} text-sm flex items-center ${\n isCellSelected?.(rowId, column.key)\n ? \"bg-blue-100/60 dark:bg-blue-900/30\"\n : \"\"\n } ${\n isPinned\n ? isCellFocused?.(rowId, column.key)\n ? \"sticky z-2 bg-inherit\"\n : \"sticky z-1 bg-inherit\"\n : \"\"\n } ${\n isCellFocused?.(rowId, column.key) ? \"relative\" : \"\"\n } ${alignClass} ${justifyClass} ${extraCellClass}`}\n style={{\n width: `${column.width || 100}px`,\n left: isPinned ? `${leftOffset}px` : \"auto\",\n ...extraCellStyle,\n }}\n // Show native tooltip only when a meaningful value exists (non-empty string after trimming)\n title={displayValue}\n onClick={(e) =>\n handleCellClick(e, row, column, row[column.key])\n }\n onContextMenu={(e) => {\n // Only handle for real data rows\n if (\n (row as any)._isGroupHeader ||\n (row as any)._isGroupFooter\n )\n return;\n if (onCellContextMenu) {\n e.preventDefault();\n e.stopPropagation();\n onCellContextMenu({\n row,\n column,\n value: (row as any)[column.key],\n displayValue: displayValue ?? \"\",\n event: e as any,\n });\n }\n // If no onCellContextMenu prop, fall back to row-level handler (do not stop propagation)\n }}\n onMouseDown={(e) =>\n onCellMouseDown?.({ row, column, event: e })\n }\n onMouseEnter={(e) =>\n onCellMouseEnter?.({ row, column, event: e })\n }\n >\n {isCellFocused?.(rowId, column.key) && (\n <div className=\"pointer-events-none absolute inset-0 border border-blue-400\" />\n )}\n {column.wrapCellContent === false ? (\n <>{renderedValue}</>\n ) : (\n <div className=\"truncate w-full\">{renderedValue}</div>\n )}\n </div>\n );\n // Insert left spacer once before the first unpinned visible column\n if (hvPadLeft > 0 && colIndex === pinnedCount) {\n return (\n <>\n <div style={{ width: hvPadLeft }} className=\"flex-none\" />\n {cell}\n </>\n );\n }\n\n return cell;\n })}\n {/* Spacer after last visible unpinned col */}\n {hvPadRight > 0 && (\n <div style={{ width: hvPadRight }} className=\"flex-none\" />\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nconst areEqual = (prev: GridRowsProps, next: GridRowsProps) => {\n if (prev.rowHeight !== next.rowHeight) return false;\n if (prev.selectable !== next.selectable) return false;\n if (prev.virtualized !== next.virtualized) return false;\n if (prev.globalFilter !== next.globalFilter) return false;\n if (prev.virtualizedRange.startIndex !== next.virtualizedRange.startIndex)\n return false;\n if (prev.virtualizedRange.endIndex !== next.virtualizedRange.endIndex)\n return false;\n if (prev.virtualizedRange.offsetY !== next.virtualizedRange.offsetY)\n return false;\n // Re-render when focus/selection functions change identity (they depend on selection & focus states)\n if (prev.isCellSelected !== next.isCellSelected) return false;\n if (prev.isCellFocused !== next.isCellFocused) return false;\n // Re-render when drag-selection handlers change identity (closure depends on selectionAnchor/end)\n if (prev.onCellMouseDown !== next.onCellMouseDown) return false;\n if (prev.onCellMouseEnter !== next.onCellMouseEnter) return false;\n if (prev.getRowId !== next.getRowId) return false;\n if (prev.selectedRows.size !== next.selectedRows.size) return false;\n if (prev.pinnedColumns?.size !== next.pinnedColumns?.size) return false;\n const prevCols = prev.columns.map((c) => c.key).join(\"|\");\n const nextCols = next.columns.map((c) => c.key).join(\"|\");\n if (prevCols !== nextCols) return false;\n if (prev.data.length !== next.data.length) return false;\n\n // Helper to extract IDs for comparison\n const extractId = (\n row: GridRow,\n idx: number,\n getRowId?: (r: GridRow) => string | number,\n ) => {\n if (getRowId) {\n return getRowId(row);\n }\n if (row.id !== undefined) {\n return row.id;\n }\n return idx;\n };\n\n const prevFirst =\n prev.data.length > 0\n ? extractId(prev.data[0], 0, prev.getRowId)\n : undefined;\n const nextFirst =\n next.data.length > 0\n ? extractId(next.data[0], 0, next.getRowId)\n : undefined;\n const prevLastIdx = prev.data.length - 1;\n const nextLastIdx = next.data.length - 1;\n const prevLast =\n prev.data.length > 0\n ? extractId(prev.data[prevLastIdx], prevLastIdx, prev.getRowId)\n : undefined;\n const nextLast =\n next.data.length > 0\n ? extractId(next.data[nextLastIdx], nextLastIdx, next.getRowId)\n : undefined;\n if (prevFirst !== nextFirst || prevLast !== nextLast) return false;\n return true;\n};\n\nexport const GridRows = memo(GridRowsComponent, areEqual);\n"],"names":["GridRows","memo","data","columns","selectedRows","virtualized","virtualizedRange","rowHeight","selectable","isRowSelectable","onRowSelect","pinnedColumns","Set","hvPadLeft","hvPadRight","rowStyle","globalFilter","onContextMenu","onRowDoubleClick","onRowClick","onCellClick","isCellFocused","isCellSelected","onCellContextMenu","onCellMouseDown","onCellMouseEnter","getRowId","totalHeight","useMemo","length","leftOffsetByPinnedKey","size","Map","pinnedKeysInOrder","filter","c","has","key","map","widthByKey","col","set","width","acc","SELECT_COL_WIDTH","get","pinnedCount","reduce","n","_jsx","style","height","position","children","transform","offsetY","top","left","right","row","index","actualIndex","startIndex","customRowStyles","rowId","rowIndex","undefined","id","process","env","NODE_ENV","console","warn","extractRowId","defaultRowColor","selectedRowColor","_jsxs","className","e","preventDefault","handleContextMenu","onDoubleClick","handleDoubleClick","onClick","handleRowClick","type","checked","disabled","onChange","target","onKeyDown","tabIndex","column","colIndex","isPinned","leftOffset","rawCell","renderedValue","displayValue","cellRenderer","String","formatter","trim","textValue","containsSearchQuery","highlightText","alignClass","align","justifyClass","paddingClass","noPadding","extraCellClass","extraCellStyle","cellStyle","cell","title","value","event","handleCellClick","_isGroupHeader","_isGroupFooter","stopPropagation","onMouseDown","onMouseEnter","wrapCellContent","_Fragment","prev","next","endIndex","join","extractId","idx","prevFirst","nextFirst","prevLastIdx","nextLastIdx","prevLast","nextLast"],"mappings":"gPAqDA,MA+YaA,EAAWC,EA/YE,EACxBC,OACAC,UACAC,eACAC,cACAC,mBACAC,YACAC,aACAC,kBACAC,cACAC,gBAAgB,IAAIC,IACpBC,YAAY,EACZC,aAAa,EACbC,WACAC,eACAC,gBACAC,mBACAC,aACAC,cACAC,gBACAC,iBACAC,oBACAC,kBACAC,mBACAC,eAGA,MAkBMC,EAAcC,EAClB,IAAM1B,EAAK2B,OAAStB,EACpB,CAACL,EAAK2B,OAAQtB,KAIVuB,sBAAEA,GAA0BF,EAAQ,KAExC,GAA2B,IAAvBjB,EAAcoB,KAChB,MAAO,CAAED,sBAAuB,IAAIE,KAGtC,MAAMC,EAAoB9B,EACvB+B,OAAQC,GAAMxB,EAAcyB,IAAID,EAAEE,MAClCC,IAAKH,GAAMA,EAAEE,KAGVE,EAAa,IAAIP,IACvB,IAAK,MAAMQ,KAAOrC,EAChBoC,EAAWE,IAAID,EAAIH,IAAKG,EAAIE,OAAS,KAGvC,MAAMZ,EAAwB,IAAIE,IAClC,IAAIW,EAAMnC,EAAaoC,EAAmB,EAE1C,IAAK,MAAMP,KAAOJ,EAChBH,EAAsBW,IAAIJ,EAAKM,GAC/BA,GAAOJ,EAAWM,IAAIR,IAAQ,IAGhC,MAAO,CAAEP,0BACR,CAAC3B,EAASQ,EAAeH,IAGtBsC,EAAclB,EAClB,IAAMzB,EAAQ4C,OAAO,CAACC,EAAGb,IAAMa,GAAKrC,EAAcyB,IAAID,EAAEE,KAAO,EAAI,GAAI,GACvE,CAAClC,EAASQ,IAyBZ,OACEsC,EACE,MAAA,CAAAC,MAAO,CACLC,OAAQ9C,EAAc,GAAGsB,MAAkB,OAC3CyB,SAAU,YAGZC,SAAAJ,EAAA,MAAA,CACEC,MAAO,CACLI,UAAWjD,EACP,kBAAkBC,EAAiBiD,gBACnC,OACJH,SAAU/C,EAAc,WAAa,SACrCmD,IAAK,EACLC,KAAM,EACNC,MAAO,GAGRL,SAAAnD,EAAKoC,IAAI,CAACqB,EAAKC,KACd,MAAMC,EAAcxD,EAChBC,EAAiBwD,WAAaF,EAC9BA,EACEG,EAAkBhD,IAAW4C,GAC7BK,EAtGO,EAACL,EAAcM,IAC9BvC,EACKA,EAASiC,QAEHO,IAAXP,EAAIQ,GACCR,EAAIQ,IAGgB,gBAAzBC,QAAQC,IAAIC,UAA2C,IAAbL,GAC5CM,QAAQC,KACN,mPAMGP,GAAY,GAsFCQ,CAAad,EAAKE,GAC1Ba,EACJb,EAAc,GAAM,EAChB,4BACA,8BACAc,EAAmBvE,EAAagC,IAAI4B,GACtC,iCACA,GAEJ,OACEY,SAEEC,UAAW,8FACTF,IAAqBZ,EAAkB,GAAKW,KAE9CxB,MAAO,CACLC,OAAQ,GAAG5C,SACRwD,GAEL9C,cAAgB6D,GAhEF,EAACA,EAAenB,KACxCmB,EAAEC,iBACF9D,IAAgB0C,EAAKmB,IA8DWE,CAAkBF,EAAGnB,GAC3CsB,cAAgBH,GA5DF,EAACA,EAAenB,KACxCzC,IAAmByC,EAAKmB,IA2DQI,CAAkBJ,EAAGnB,GAC3CwB,QAAUL,GAzDC,EAACA,EAAenB,KACrCxC,IAAawC,EAAKmB,IAwDQM,CAAeN,EAAGnB,GAEjCN,SAAA,CAAA7C,GACCyC,EACE,MAAA,CAAA4B,UAAU,6HACV3B,MAAO,CAAER,MAAOE,GAAkBS,SAElCJ,EACE,QAAA,CAAAoC,KAAK,WACLC,QAASlF,EAAagC,IAAI4B,GAC1BuB,WAAU9E,IAAmBA,EAAgBkD,GAC7C6B,SAAWV,GAAMpE,EAAYsD,EAAOc,EAAEW,OAAOH,SAC7CI,UAAYZ,IACI,MAAVA,EAAEzC,KAAyB,UAAVyC,EAAEzC,MACrByC,EAAEC,iBACFrE,EAAYsD,GAAQ5D,EAAagC,IAAI4B,MAGzCa,UAAU,iKAAgK,aAC9J,cAAcb,IAC1B2B,SAAU,MAKfxF,EAAQmC,IAAI,CAACsD,EAAQC,KACpB,MAAMC,EAAWnF,EAAcyB,IAAIwD,EAAOvD,KACpC0D,EAAaD,GACfhE,EAAsBe,IAAI+C,EAAOvD,MACjC,EAGE2D,EAAUrC,EAAIiC,EAAOvD,KAC3B,IAAI4D,EACAC,EAwBJ,GArBIN,EAAOO,cACTF,EAAgBL,EAAOO,aAAaH,EAASrC,GAGxB,iBAAZqC,GACY,iBAAZA,GACY,kBAAZA,IAEPE,EAAeE,OAAOJ,KAEfJ,EAAOS,WAChBJ,EAAgBL,EAAOS,UAAUL,GACjCE,EAAeE,OAAOH,KAEtBA,EAAgBD,GAAW,GAC3BE,EAAeD,EACXG,OAAOH,QACP/B,GAKJlD,GACAA,EAAasF,SACZV,EAAOO,cACRF,EACA,CACA,MAAMM,EAAYH,OAAOH,GACrBO,EAAoBD,EAAWvF,KACjCiF,EAAgBQ,EAAcF,EAAWvF,GAE5C,CAGGkF,GAA+C,IAA/BA,EAAaI,OAAOzE,SACtCqE,OAAehC,GAIjB,MAAMwC,EACa,WAAjBd,EAAOe,MACH,cACiB,UAAjBf,EAAOe,MACL,aACA,YACFC,EACa,WAAjBhB,EAAOe,MACH,iBACiB,UAAjBf,EAAOe,MACL,cACA,gBACFE,EAAejB,EAAOkB,UAAY,MAAQ,MAG1CC,EACwB,mBAArBnB,EAAOf,UACVe,EAAOf,UAAUmB,EAASrC,GAC1BiC,EAAOf,WAAa,GACpBmC,EACwB,mBAArBpB,EAAOqB,UACVrB,EAAOqB,UAAUjB,EAASrC,GAC1BiC,EAAOqB,gBAAa/C,EAEpBgD,EACJtC,EAEE,MAAA,CAAAC,UAAW,4CAA4CgC,+BACrDvF,IAAiB0C,EAAO4B,EAAOvD,KAC3B,qCACA,MAEJyD,EACIzE,IAAgB2C,EAAO4B,EAAOvD,KAC5B,wBACA,wBACF,MAEJhB,IAAgB2C,EAAO4B,EAAOvD,KAAO,WAAa,MAChDqE,KAAcE,KAAgBG,IAClC7D,MAAO,CACLR,MAAO,GAAGkD,EAAOlD,OAAS,QAC1Be,KAAMqC,EAAW,GAAGC,MAAiB,UAClCiB,GAGLG,MAAOjB,EACPf,QAAUL,GAhLJ,EACtBA,EACAnB,EACAiC,EACAwB,KAEAhG,IAAc,CAAEuC,MAAKiC,SAAQwB,QAAOC,MAAOvC,KA2KzBwC,CAAgBxC,EAAGnB,EAAKiC,EAAQjC,EAAIiC,EAAOvD,MAE7CpB,cAAgB6D,IAGXnB,EAAY4D,gBACZ5D,EAAY6D,gBAGXjG,IACFuD,EAAEC,iBACFD,EAAE2C,kBACFlG,EAAkB,CAChBoC,MACAiC,SACAwB,MAAQzD,EAAYiC,EAAOvD,KAC3B6D,aAAcA,GAAgB,GAC9BmB,MAAOvC,MAKb4C,YAAc5C,GACZtD,IAAkB,CAAEmC,MAAKiC,SAAQyB,MAAOvC,IAE1C6C,aAAe7C,GACbrD,IAAmB,CAAEkC,MAAKiC,SAAQyB,MAAOvC,IAG1CzB,SAAA,CAAAhC,IAAgB2C,EAAO4B,EAAOvD,MAC7BY,SAAK4B,UAAU,iEAEW,IAA3Be,EAAOgC,gBACN3E,EAAA4E,EAAA,CAAAxE,SAAG4C,IAEHhD,EAAA,MAAA,CAAK4B,UAAU,2BAAmBoB,MAzD/B,GAAGL,EAAOvD,OAAOwD,KA8D1B,OAAIhF,EAAY,GAAKgF,IAAa/C,EAE9B8B,EACEiD,EAAA,CAAAxE,SAAA,CAAAJ,EAAA,MAAA,CAAKC,MAAO,CAAER,MAAO7B,GAAagE,UAAU,cAC3CqC,KAKAA,IAGRpG,EAAa,GACZmC,EAAA,MAAA,CAAKC,MAAO,CAAER,MAAO5B,GAAc+D,UAAU,gBA3L1C,GAAGb,KAASH,YAqMd,CAACiE,EAAqBC,KACrC,GAAID,EAAKvH,YAAcwH,EAAKxH,UAAW,OAAO,EAC9C,GAAIuH,EAAKtH,aAAeuH,EAAKvH,WAAY,OAAO,EAChD,GAAIsH,EAAKzH,cAAgB0H,EAAK1H,YAAa,OAAO,EAClD,GAAIyH,EAAK9G,eAAiB+G,EAAK/G,aAAc,OAAO,EACpD,GAAI8G,EAAKxH,iBAAiBwD,aAAeiE,EAAKzH,iBAAiBwD,WAC7D,OAAO,EACT,GAAIgE,EAAKxH,iBAAiB0H,WAAaD,EAAKzH,iBAAiB0H,SAC3D,OAAO,EACT,GAAIF,EAAKxH,iBAAiBiD,UAAYwE,EAAKzH,iBAAiBiD,QAC1D,OAAO,EAET,GAAIuE,EAAKxG,iBAAmByG,EAAKzG,eAAgB,OAAO,EACxD,GAAIwG,EAAKzG,gBAAkB0G,EAAK1G,cAAe,OAAO,EAEtD,GAAIyG,EAAKtG,kBAAoBuG,EAAKvG,gBAAiB,OAAO,EAC1D,GAAIsG,EAAKrG,mBAAqBsG,EAAKtG,iBAAkB,OAAO,EAC5D,GAAIqG,EAAKpG,WAAaqG,EAAKrG,SAAU,OAAO,EAC5C,GAAIoG,EAAK1H,aAAa2B,OAASgG,EAAK3H,aAAa2B,KAAM,OAAO,EAC9D,GAAI+F,EAAKnH,eAAeoB,OAASgG,EAAKpH,eAAeoB,KAAM,OAAO,EAGlE,GAFiB+F,EAAK3H,QAAQmC,IAAKH,GAAMA,EAAEE,KAAK4F,KAAK,OACpCF,EAAK5H,QAAQmC,IAAKH,GAAMA,EAAEE,KAAK4F,KAAK,KAC1B,OAAO,EAClC,GAAIH,EAAK5H,KAAK2B,SAAWkG,EAAK7H,KAAK2B,OAAQ,OAAO,EAGlD,MAAMqG,EAAY,CAChBvE,EACAwE,EACAzG,IAEIA,EACKA,EAASiC,QAEHO,IAAXP,EAAIQ,GACCR,EAAIQ,GAENgE,EAGHC,EACJN,EAAK5H,KAAK2B,OAAS,EACfqG,EAAUJ,EAAK5H,KAAK,GAAI,EAAG4H,EAAKpG,eAChCwC,EACAmE,EACJN,EAAK7H,KAAK2B,OAAS,EACfqG,EAAUH,EAAK7H,KAAK,GAAI,EAAG6H,EAAKrG,eAChCwC,EACAoE,EAAcR,EAAK5H,KAAK2B,OAAS,EACjC0G,EAAcR,EAAK7H,KAAK2B,OAAS,EACjC2G,EACJV,EAAK5H,KAAK2B,OAAS,EACfqG,EAAUJ,EAAK5H,KAAKoI,GAAcA,EAAaR,EAAKpG,eACpDwC,EACAuE,EACJV,EAAK7H,KAAK2B,OAAS,EACfqG,EAAUH,EAAK7H,KAAKqI,GAAcA,EAAaR,EAAKrG,eACpDwC,EACN,OAAIkE,IAAcC,GAAaG,IAAaC"}
@@ -0,0 +1,12 @@
1
+ import type { GridColumn } from "../types";
2
+ interface GroupBarProps {
3
+ columns: GridColumn[];
4
+ groupedKeys: string[];
5
+ onRemove: (columnKey: string) => void;
6
+ onReorder: (newOrder: string[]) => void;
7
+ onDropColumnKey: (columnKey: string) => void;
8
+ onToggleExpandAll?: () => void;
9
+ isAnyExpanded?: boolean;
10
+ }
11
+ export declare const GroupBar: ({ columns, groupedKeys, onRemove, onReorder, onDropColumnKey, onToggleExpandAll, isAnyExpanded, }: GroupBarProps) => import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsxs as e,jsx as r}from"react/jsx-runtime";import{useState as t}from"react";const l=({columns:l,groupedKeys:a,onRemove:n,onReorder:o,onDropColumnKey:s,onToggleExpandAll:i,isAnyExpanded:p=!1})=>{const[d,u]=t(null),[c,g]=t(null),[m,x]=t(!0),b=e=>l.find(r=>r.key===e)?.header||e,f=e=>r=>{u(e),r.dataTransfer.effectAllowed="move",r.dataTransfer.setData("application/x-group-key",e)},v=e=>r=>{r.preventDefault();const t=r.currentTarget.getBoundingClientRect(),l=r.clientX<t.left+t.width/2;g(e),x(l)};return e("div",{className:"flex items-center gap-2 px-3 py-2 bg-gray-50 border-b border-gray-200 text-sm",onDrop:e=>{e.preventDefault();const r=e.dataTransfer.getData("text/plain");r&&(a.includes(r)||s(r))},onDragOver:e=>{e.preventDefault()},onDragEnd:()=>{u(null),g(null)},children:[r("span",{className:"text-gray-600 whitespace-nowrap",children:"Group by:"}),a.length>0&&r("button",{type:"button",className:"ml-1 px-2 py-1 text-xs border border-gray-300 rounded hover:bg-gray-100",title:p?"Collapse all groups":"Expand all groups",onClick:e=>{e.preventDefault(),e.stopPropagation(),i?.()},children:p?"Collapse All":"Expand All"}),0===a.length&&r("span",{className:"text-gray-400",children:"Drag a column here"}),r("div",{className:"flex items-center gap-2 flex-wrap",children:a.map(t=>{return e("div",{className:"inline-flex items-center gap-2 bg-blue-100 text-blue-800 px-2 py-1 rounded-md border border-blue-200 cursor-move relative",draggable:!0,onDragStart:f(t),onDragOver:v(t),onDrop:(l=t,()=>{if(!d||d===l)return u(null),void g(null);const e=a.filter(e=>e!==d),r=e.indexOf(l);-1!==r&&(m?e.splice(r,0,d):e.splice(r+1,0,d),o(e),u(null),g(null))}),title:b(t),children:[r("span",{className:"text-xs font-medium truncate max-w-[160px]",children:b(t)}),r("button",{className:"text-blue-700 hover:text-blue-900",onClick:()=>n(t),"aria-label":`Remove grouping ${b(t)}`,children:"×"}),c===t&&r("span",{className:"absolute top-0 bottom-0 w-0.5 bg-blue-600 dark:bg-blue-400 animate-pulse",style:{left:m?0:void 0,right:m?void 0:0},"aria-hidden":"true"})]},t);var l})})]})};export{l as GroupBar};
2
+ //# sourceMappingURL=GroupBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupBar.js","sources":["../../../../../components/GroupBar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { GridColumn } from \"../types\";\n\ninterface GroupBarProps {\n columns: GridColumn[];\n groupedKeys: string[];\n onRemove: (columnKey: string) => void;\n onReorder: (newOrder: string[]) => void;\n onDropColumnKey: (columnKey: string) => void;\n onToggleExpandAll?: () => void;\n isAnyExpanded?: boolean;\n}\n\nexport const GroupBar = ({\n columns,\n groupedKeys,\n onRemove,\n onReorder,\n onDropColumnKey,\n onToggleExpandAll,\n isAnyExpanded = false,\n}: GroupBarProps) => {\n const [dragKey, setDragKey] = useState<string | null>(null);\n const [dragOverKey, setDragOverKey] = useState<string | null>(null);\n const [dragOverBefore, setDragOverBefore] = useState<boolean>(true);\n\n const labelFor = (key: string) => columns.find((c) => c.key === key)?.header || key;\n\n const handleDropFromHeader: React.DragEventHandler<HTMLDivElement> = (e) => {\n e.preventDefault();\n const key = e.dataTransfer.getData(\"text/plain\");\n if (!key) return;\n if (!groupedKeys.includes(key)) onDropColumnKey(key);\n };\n\n const onDragOverBar: React.DragEventHandler<HTMLDivElement> = (e) => {\n e.preventDefault();\n };\n\n const handleChipDragStart = (key: string): React.DragEventHandler<HTMLDivElement> => (e) => {\n setDragKey(key);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"application/x-group-key\", key);\n };\n\n const handleChipDragOver = (key: string): React.DragEventHandler<HTMLDivElement> => (e) => {\n e.preventDefault();\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const before = e.clientX < rect.left + rect.width / 2;\n setDragOverKey(key);\n setDragOverBefore(before);\n };\n\n const handleChipDrop = (targetKey: string): React.DragEventHandler<HTMLDivElement> => () => {\n if (!dragKey || dragKey === targetKey) {\n setDragKey(null);\n setDragOverKey(null);\n return;\n }\n const order = groupedKeys.filter((k) => k !== dragKey);\n const idx = order.indexOf(targetKey);\n if (idx === -1) return;\n if (!dragOverBefore) {\n order.splice(idx + 1, 0, dragKey);\n } else {\n order.splice(idx, 0, dragKey);\n }\n onReorder(order);\n setDragKey(null);\n setDragOverKey(null);\n };\n\n const clearDnD = () => {\n setDragKey(null);\n setDragOverKey(null);\n };\n\n return (\n <div\n className=\"flex items-center gap-2 px-3 py-2 bg-gray-50 border-b border-gray-200 text-sm\"\n onDrop={handleDropFromHeader}\n onDragOver={onDragOverBar}\n onDragEnd={clearDnD}\n >\n <span className=\"text-gray-600 whitespace-nowrap\">Group by:</span>\n {groupedKeys.length > 0 && (\n <button\n type=\"button\"\n className=\"ml-1 px-2 py-1 text-xs border border-gray-300 rounded hover:bg-gray-100\"\n title={isAnyExpanded ? \"Collapse all groups\" : \"Expand all groups\"}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onToggleExpandAll?.();\n }}\n >\n {isAnyExpanded ? \"Collapse All\" : \"Expand All\"}\n </button>\n )}\n {groupedKeys.length === 0 && (\n <span className=\"text-gray-400\">Drag a column here</span>\n )}\n <div className=\"flex items-center gap-2 flex-wrap\">\n {groupedKeys.map((key) => (\n <div\n key={key}\n className=\"inline-flex items-center gap-2 bg-blue-100 text-blue-800 px-2 py-1 rounded-md border border-blue-200 cursor-move relative\"\n draggable\n onDragStart={handleChipDragStart(key)}\n onDragOver={handleChipDragOver(key)}\n onDrop={handleChipDrop(key)}\n title={labelFor(key)}\n >\n <span className=\"text-xs font-medium truncate max-w-[160px]\">{labelFor(key)}</span>\n <button\n className=\"text-blue-700 hover:text-blue-900\"\n onClick={() => onRemove(key)}\n aria-label={`Remove grouping ${labelFor(key)}`}\n >\n ×\n </button>\n {dragOverKey === key && (\n <span\n className=\"absolute top-0 bottom-0 w-0.5 bg-blue-600 dark:bg-blue-400 animate-pulse\"\n style={{ left: dragOverBefore ? 0 : undefined, right: dragOverBefore ? undefined : 0 }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n ))}\n </div>\n </div>\n );\n};\n"],"names":["GroupBar","columns","groupedKeys","onRemove","onReorder","onDropColumnKey","onToggleExpandAll","isAnyExpanded","dragKey","setDragKey","useState","dragOverKey","setDragOverKey","dragOverBefore","setDragOverBefore","labelFor","key","find","c","header","handleChipDragStart","e","dataTransfer","effectAllowed","setData","handleChipDragOver","preventDefault","rect","currentTarget","getBoundingClientRect","before","clientX","left","width","_jsxs","className","onDrop","getData","includes","onDragOver","onDragEnd","children","_jsx","length","type","title","onClick","stopPropagation","map","draggable","onDragStart","targetKey","order","filter","k","idx","indexOf","splice","style","undefined","right"],"mappings":"yFAaaA,EAAW,EACtBC,UACAC,cACAC,WACAC,YACAC,kBACAC,oBACAC,iBAAgB,MAEhB,MAAOC,EAASC,GAAcC,EAAwB,OAC/CC,EAAaC,GAAkBF,EAAwB,OACvDG,EAAgBC,GAAqBJ,GAAkB,GAExDK,EAAYC,GAAgBf,EAAQgB,KAAMC,GAAMA,EAAEF,MAAQA,IAAMG,QAAUH,EAa1EI,EAAuBJ,GAAyDK,IACpFZ,EAAWO,GACXK,EAAEC,aAAaC,cAAgB,OAC/BF,EAAEC,aAAaE,QAAQ,0BAA2BR,IAG9CS,EAAsBT,GAAyDK,IACnFA,EAAEK,iBACF,MAAMC,EAAQN,EAAEO,cAAiCC,wBAC3CC,EAAST,EAAEU,QAAUJ,EAAKK,KAAOL,EAAKM,MAAQ,EACpDrB,EAAeI,GACfF,EAAkBgB,IA2BpB,OACEI,EACE,MAAA,CAAAC,UAAU,gFACVC,OApDkEf,IACpEA,EAAEK,iBACF,MAAMV,EAAMK,EAAEC,aAAae,QAAQ,cAC9BrB,IACAd,EAAYoC,SAAStB,IAAMX,EAAgBW,KAiD9CuB,WA9C2DlB,IAC7DA,EAAEK,kBA8CAc,UAVa,KACf/B,EAAW,MACXG,EAAe,OAQM6B,SAAA,CAEnBC,EAAM,OAAA,CAAAP,UAAU,kCAAkDM,SAAA,cACjEvC,EAAYyC,OAAS,GACpBD,EACE,SAAA,CAAAE,KAAK,SACLT,UAAU,0EACVU,MAAOtC,EAAgB,sBAAwB,oBAC/CuC,QAAUzB,IACRA,EAAEK,iBACFL,EAAE0B,kBACFzC,gBAGDC,EAAgB,eAAiB,eAGd,IAAvBL,EAAYyC,QACXD,UAAMP,UAAU,gBAAeM,SAAA,uBAEjCC,EAAA,MAAA,CAAKP,UAAU,oCACZM,SAAAvC,EAAY8C,IAAKhC,IAAG,OACnBkB,EAEE,MAAA,CAAAC,UAAU,4HACVc,WAAS,EACTC,YAAa9B,EAAoBJ,GACjCuB,WAAYd,EAAmBT,GAC/BoB,QAzDce,EAyDSnC,EAzDqD,KACpF,IAAKR,GAAWA,IAAY2C,EAG1B,OAFA1C,EAAW,WACXG,EAAe,MAGjB,MAAMwC,EAAQlD,EAAYmD,OAAQC,GAAMA,IAAM9C,GACxC+C,EAAMH,EAAMI,QAAQL,IACb,IAATI,IACC1C,EAGHuC,EAAMK,OAAOF,EAAK,EAAG/C,GAFrB4C,EAAMK,OAAOF,EAAM,EAAG,EAAG/C,GAI3BJ,EAAUgD,GACV3C,EAAW,MACXG,EAAe,SA0CPiC,MAAO9B,EAASC,GAAIyB,SAAA,CAEpBC,UAAMP,UAAU,6CAA4CM,SAAE1B,EAASC,KACvE0B,EACE,SAAA,CAAAP,UAAU,oCACVW,QAAS,IAAM3C,EAASa,gBACZ,mBAAmBD,EAASC,KAAMyB,SAAA,MAI/C9B,IAAgBK,GACf0B,EACE,OAAA,CAAAP,UAAU,2EACVuB,MAAO,CAAE1B,KAAMnB,EAAiB,OAAI8C,EAAWC,MAAO/C,OAAiB8C,EAAY,iBACvE,WApBX3C,GApDQ,IAACmC"}
@@ -0,0 +1,29 @@
1
+ import { GridRow, CustomDataGridProps } from "../types";
2
+ interface GroupHeaderProps {
3
+ row: GridRow & {
4
+ _isGroupHeader?: boolean;
5
+ _groupKey?: string;
6
+ _groupCount?: number;
7
+ };
8
+ isExpanded: boolean;
9
+ onToggle: (groupKey: string) => void;
10
+ viewportWidth: number;
11
+ selectable: boolean;
12
+ rowHeight?: number;
13
+ /**
14
+ * Optional function to map a column key to its display label (header).
15
+ * If not provided, the raw column key will be used as a fallback.
16
+ */
17
+ getHeaderLabel?: (columnKey: string) => string;
18
+ /**
19
+ * Optional function to map a column key and raw group value to a display label.
20
+ * Useful to apply the column's formatter for group headers.
21
+ */
22
+ getValueLabel?: (columnKey: string, rawValue: any) => string;
23
+ /**
24
+ * Optional custom renderer for actions on grouped rows.
25
+ */
26
+ renderGroupActions?: CustomDataGridProps["renderGroupActions"];
27
+ }
28
+ export declare const GroupHeader: import("react").MemoExoticComponent<({ row, isExpanded, onToggle, viewportWidth, selectable, rowHeight, getHeaderLabel, getValueLabel, renderGroupActions, }: GroupHeaderProps) => import("react/jsx-runtime").JSX.Element>;
29
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsxs as e,jsx as r}from"react/jsx-runtime";import{memo as o}from"react";import{ChevronDown as t,ChevronRight as l}from"lucide-react";import{SELECT_COL_WIDTH as n}from"../constants.js";const u=o(({row:o,isExpanded:u,onToggle:a,viewportWidth:p,selectable:i,rowHeight:s=40,getHeaderLabel:g,getValueLabel:c,renderGroupActions:m})=>{const d=()=>{o._groupKey&&a(o._groupKey)};return e("div",{className:"flex items-center bg-blue-50 dark:bg-blue-900/20 border-b border-gray-200 dark:border-gray-800 hover:bg-blue-100/70 cursor-pointer sticky left-0 z-20 overflow-hidden",style:{minWidth:`${p+(i?n:0)}px`,height:`${s}px`},onClick:d,role:"button",tabIndex:0,"aria-expanded":u,onKeyDown:e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),d())},children:[i&&r("div",{className:"w-12 flex items-center justify-center"}),e("div",{className:"flex items-center px-4 py-2 flex-1",children:[r("div",{className:"flex items-center mr-3",style:{paddingLeft:(o._groupLevel?16*o._groupLevel:0)+"px"},children:r(u?t:l,{className:"w-4 h-4 text-gray-600"})}),e("div",{className:"flex items-center gap-2",children:[e("span",{className:"font-medium text-gray-900",children:[o._groupColumnKey?`${g?g(o._groupColumnKey):o._groupColumnKey}: `:"",c&&o._groupColumnKey?c(o._groupColumnKey,o._groupValue):o._groupValue??(o._groupKey||"Unknown")]}),e("span",{className:"text-sm text-gray-600 bg-gray-200/70 px-2 py-1 rounded-full",children:[o._groupCount," ",1===o._groupCount?"item":"items"]})]}),m&&r("div",{className:"flex items-center px-4",onClick:e=>e.stopPropagation(),children:m({groupKey:o._groupKey||"",columnKey:o._groupColumnKey||"",groupValue:o._groupValue,rows:o._groupRows||[],count:o._groupCount||0,level:o._groupLevel||0})})]})]})});export{u as GroupHeader};
2
+ //# sourceMappingURL=GroupHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupHeader.js","sources":["../../../../../components/GroupHeader.tsx"],"sourcesContent":["import { memo } from \"react\";\nimport { ChevronDown, ChevronRight } from \"lucide-react\";\nimport { GridRow, CustomDataGridProps } from \"../types\";\nimport { SELECT_COL_WIDTH } from \"../constants\";\n\ninterface GroupHeaderProps {\n row: GridRow & {\n _isGroupHeader?: boolean;\n _groupKey?: string;\n _groupCount?: number;\n };\n isExpanded: boolean;\n onToggle: (groupKey: string) => void;\n viewportWidth: number;\n selectable: boolean;\n rowHeight?: number;\n /**\n * Optional function to map a column key to its display label (header).\n * If not provided, the raw column key will be used as a fallback.\n */\n getHeaderLabel?: (columnKey: string) => string;\n /**\n * Optional function to map a column key and raw group value to a display label.\n * Useful to apply the column's formatter for group headers.\n */\n getValueLabel?: (columnKey: string, rawValue: any) => string;\n /**\n * Optional custom renderer for actions on grouped rows.\n */\n renderGroupActions?: CustomDataGridProps[\"renderGroupActions\"];\n}\n\nexport const GroupHeader = memo(\n ({\n row,\n isExpanded,\n onToggle,\n viewportWidth,\n selectable,\n rowHeight = 40,\n getHeaderLabel,\n getValueLabel,\n renderGroupActions,\n }: GroupHeaderProps) => {\n const handleToggle = () => {\n if (row._groupKey) {\n onToggle(row._groupKey);\n }\n };\n\n return (\n <div\n className=\"flex items-center bg-blue-50 dark:bg-blue-900/20 border-b border-gray-200 dark:border-gray-800 hover:bg-blue-100/70 cursor-pointer sticky left-0 z-20 overflow-hidden\"\n style={{\n minWidth: `${viewportWidth + (selectable ? SELECT_COL_WIDTH : 0)}px`,\n height: `${rowHeight}px`,\n }}\n onClick={handleToggle}\n role=\"button\"\n tabIndex={0}\n aria-expanded={isExpanded}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleToggle();\n }\n }}\n >\n {selectable && (\n <div className=\"w-12 flex items-center justify-center\">\n {/* Empty space for checkbox column */}\n </div>\n )}\n\n <div className=\"flex items-center px-4 py-2 flex-1\">\n <div\n className=\"flex items-center mr-3\"\n style={{\n paddingLeft: `${(row as any)._groupLevel ? ((row as any)._groupLevel as number) * 16 : 0}px`,\n }}\n >\n {isExpanded ? (\n <ChevronDown className=\"w-4 h-4 text-gray-600\" />\n ) : (\n <ChevronRight className=\"w-4 h-4 text-gray-600\" />\n )}\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-gray-900\">\n {(row as any)._groupColumnKey\n ? `${getHeaderLabel ? getHeaderLabel((row as any)._groupColumnKey) : (row as any)._groupColumnKey}: `\n : \"\"}\n {getValueLabel && (row as any)._groupColumnKey\n ? getValueLabel(\n (row as any)._groupColumnKey,\n (row as any)._groupValue,\n )\n : ((row as any)._groupValue ?? (row._groupKey || \"Unknown\"))}\n </span>\n <span className=\"text-sm text-gray-600 bg-gray-200/70 px-2 py-1 rounded-full\">\n {row._groupCount} {row._groupCount === 1 ? \"item\" : \"items\"}\n </span>\n </div>\n\n {renderGroupActions && (\n <div\n className=\"flex items-center px-4\"\n onClick={(e) => e.stopPropagation()}\n >\n {renderGroupActions({\n groupKey: row._groupKey || \"\",\n columnKey: (row as any)._groupColumnKey || \"\",\n groupValue: (row as any)._groupValue,\n rows: (row as any)._groupRows || [],\n count: row._groupCount || 0,\n level: (row as any)._groupLevel || 0,\n })}\n </div>\n )}\n </div>\n </div>\n );\n },\n);\n"],"names":["GroupHeader","memo","row","isExpanded","onToggle","viewportWidth","selectable","rowHeight","getHeaderLabel","getValueLabel","renderGroupActions","handleToggle","_groupKey","_jsxs","className","style","minWidth","SELECT_COL_WIDTH","height","onClick","role","tabIndex","onKeyDown","e","key","preventDefault","children","_jsx","paddingLeft","_groupLevel","ChevronDown","ChevronRight","_groupColumnKey","_groupValue","_groupCount","stopPropagation","groupKey","columnKey","groupValue","rows","_groupRows","count","level"],"mappings":"+LAgCO,MAAMA,EAAcC,EACzB,EACEC,MACAC,aACAC,WACAC,gBACAC,aACAC,YAAY,GACZC,iBACAC,gBACAC,yBAEA,MAAMC,EAAe,KACfT,EAAIU,WACNR,EAASF,EAAIU,YAIjB,OACEC,EACE,MAAA,CAAAC,UAAU,wKACVC,MAAO,CACLC,SAAU,GAAGX,GAAiBC,EAAaW,EAAmB,OAC9DC,OAAQ,GAAGX,OAEbY,QAASR,EACTS,KAAK,SACLC,SAAU,EAAC,gBACIlB,EACfmB,UAAYC,IACI,UAAVA,EAAEC,KAA6B,MAAVD,EAAEC,MACzBD,EAAEE,iBACFd,MAEHe,SAAA,CAEApB,GACCqB,SAAKb,UAAU,0CAKjBD,SAAKC,UAAU,qCACbY,SAAA,CAAAC,EAAA,MAAA,CACEb,UAAU,yBACVC,MAAO,CACLa,aAAiB1B,EAAY2B,YAAqD,GAArC3B,EAAY2B,YAA8B,GAA1E,MACdH,SAGCC,EADDxB,EACE2B,EAEAC,EAFW,CAACjB,UAAU,4BAM3BD,SAAKC,UAAU,0BAAyBY,SAAA,CACtCb,UAAMC,UAAU,4BACZY,SAAA,CAAAxB,EAAY8B,gBACV,GAAGxB,EAAiBA,EAAgBN,EAAY8B,iBAAoB9B,EAAY8B,oBAChF,GACHvB,GAAkBP,EAAY8B,gBAC3BvB,EACGP,EAAY8B,gBACZ9B,EAAY+B,aAEb/B,EAAY+B,cAAgB/B,EAAIU,WAAa,cAErDC,EAAM,OAAA,CAAAC,UAAU,8DACbY,SAAA,CAAAxB,EAAIgC,YAAc,IAAoB,IAApBhC,EAAIgC,YAAoB,OAAS,cAIvDxB,GACCiB,EAAA,MAAA,CACEb,UAAU,0BACVK,QAAUI,GAAMA,EAAEY,kBAAiBT,SAElChB,EAAmB,CAClB0B,SAAUlC,EAAIU,WAAa,GAC3ByB,UAAYnC,EAAY8B,iBAAmB,GAC3CM,WAAapC,EAAY+B,YACzBM,KAAOrC,EAAYsC,YAAc,GACjCC,MAAOvC,EAAIgC,aAAe,EAC1BQ,MAAQxC,EAAY2B,aAAe"}
@@ -0,0 +1,7 @@
1
+ interface NoDataMessageProps {
2
+ hasFilters?: boolean;
3
+ hasData?: boolean;
4
+ message?: string;
5
+ }
6
+ export declare const NoDataMessage: ({ hasFilters, hasData, message, }: NoDataMessageProps) => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsxs as t,jsx as e}from"react/jsx-runtime";import{Database as r,Search as a}from"lucide-react";const i=({hasFilters:i=!1,hasData:s=!0,message:c})=>{const{title:o,description:n,icon:l}=c?{title:c,description:"",icon:r}:s?i?{title:"No Results Found",description:"No data matches your current search criteria. Try adjusting your filters.",icon:a}:{title:"No Data to Display",description:"There are no items to show at the moment.",icon:r}:{title:"No Data Available",description:"There is no data to display in this table.",icon:r};return t("div",{className:"flex flex-col items-center justify-center pt-16 pb-10 px-4 text-center",children:[e("div",{className:"w-16 h-16 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center mb-4",children:e(l,{className:"w-8 h-8 text-gray-400 dark:text-gray-500"})}),e("h3",{className:"text-lg font-medium text-gray-900 dark:text-gray-100 mb-2",children:o}),e("p",{className:"text-sm text-gray-500 dark:text-gray-400 max-w-md",children:n})]})};export{i as NoDataMessage};
2
+ //# sourceMappingURL=NoDataMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoDataMessage.js","sources":["../../../../../components/NoDataMessage.tsx"],"sourcesContent":["import { Search, Database } from \"lucide-react\";\n\ninterface NoDataMessageProps {\n hasFilters?: boolean;\n hasData?: boolean;\n message?: string;\n}\n\nexport const NoDataMessage = ({\n hasFilters = false,\n hasData = true,\n message,\n}: NoDataMessageProps) => {\n const getMessage = () => {\n if (message) {\n return {\n title: message,\n description: \"\",\n icon: Database,\n };\n }\n\n if (!hasData) {\n return {\n title: \"No Data Available\",\n description: \"There is no data to display in this table.\",\n icon: Database,\n };\n }\n\n if (hasFilters) {\n return {\n title: \"No Results Found\",\n description:\n \"No data matches your current search criteria. Try adjusting your filters.\",\n icon: Search,\n };\n }\n\n return {\n title: \"No Data to Display\",\n description: \"There are no items to show at the moment.\",\n icon: Database,\n };\n };\n\n const { title, description, icon: Icon } = getMessage();\n\n return (\n <div className=\"flex flex-col items-center justify-center pt-16 pb-10 px-4 text-center\">\n <div className=\"w-16 h-16 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center mb-4\">\n <Icon className=\"w-8 h-8 text-gray-400 dark:text-gray-500\" />\n </div>\n <h3 className=\"text-lg font-medium text-gray-900 dark:text-gray-100 mb-2\">\n {title}\n </h3>\n <p className=\"text-sm text-gray-500 dark:text-gray-400 max-w-md\">\n {description}\n </p>\n </div>\n );\n};\n"],"names":["NoDataMessage","hasFilters","hasData","message","title","description","icon","Icon","Database","Search","_jsxs","className","_jsx","children"],"mappings":"sGAQa,MAAAA,EAAgB,EAC3BC,cAAa,EACbC,WAAU,EACVC,cAEA,MAiCMC,MAAEA,EAAKC,YAAEA,EAAaC,KAAMC,GAhC5BJ,EACK,CACLC,MAAOD,EACPE,YAAa,GACbC,KAAME,GAILN,EAQDD,EACK,CACLG,MAAO,mBACPC,YACE,4EACFC,KAAMG,GAIH,CACLL,MAAO,qBACPC,YAAa,4CACbC,KAAME,GAnBC,CACLJ,MAAO,oBACPC,YAAa,6CACbC,KAAME,GAsBZ,OACEE,EAAK,MAAA,CAAAC,UAAU,mFACbC,EAAK,MAAA,CAAAD,UAAU,qGACbC,EAACL,EAAK,CAAAI,UAAU,+CAElBC,QAAID,UAAU,4DAA2DE,SACtET,IAEHQ,EAAG,IAAA,CAAAD,UAAU,oDAAmDE,SAC7DR"}
@@ -0,0 +1,15 @@
1
+ import { PaginationConfig } from "../types";
2
+ interface PaginationControlsProps {
3
+ paginationConfig: PaginationConfig;
4
+ currentPage: number;
5
+ isServerLoading: boolean;
6
+ selectedRowsCount: number;
7
+ totalDataLength: number;
8
+ filteredDataLength?: number;
9
+ paginationMode?: "client" | "server";
10
+ onPageChange: (page: number, pageSize: number) => void;
11
+ onPageSizeChange: (pageSize: number) => void;
12
+ showNoDataMessage?: boolean;
13
+ }
14
+ export declare const PaginationControls: ({ paginationConfig, currentPage, isServerLoading, selectedRowsCount, totalDataLength, filteredDataLength, paginationMode, onPageChange, onPageSizeChange, }: PaginationControlsProps) => import("react/jsx-runtime").JSX.Element;
15
+ export {};