@gp-grid/react 0.7.2 → 0.7.4

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gp-grid/react",
3
3
  "description": "A high-performance React data grid component with virtual scrolling, cell selection, sorting, filtering, and Excel-like editing",
4
- "version": "0.7.2",
4
+ "version": "0.7.4",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -45,20 +45,12 @@
45
45
  "link-workspace-packages": false
46
46
  },
47
47
  "dependencies": {
48
- "@gp-grid/core": "workspace:*"
48
+ "@gp-grid/core": "0.7.4"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": "^19.0.0",
52
52
  "react-dom": "^19.1.1"
53
53
  },
54
- "scripts": {
55
- "dev": "tsdown --watch",
56
- "build": "tsdown --clean --sourcemap",
57
- "build:production": "tsdown --clean --minify --treeshake --dts",
58
- "test": "vitest",
59
- "test:ui": "vitest --ui",
60
- "bench": "vitest bench"
61
- },
62
54
  "devDependencies": {
63
55
  "@testing-library/react": "^16.3.0",
64
56
  "@testing-library/user-event": "^14.6.1",
@@ -69,5 +61,13 @@
69
61
  "react-dom": "^19.2.0",
70
62
  "tsdown": "0.19.0-beta.5",
71
63
  "typescript": "^5.9.3"
64
+ },
65
+ "scripts": {
66
+ "dev": "tsdown --watch",
67
+ "build": "tsdown --clean --sourcemap",
68
+ "build:production": "tsdown --clean --minify --treeshake --dts",
69
+ "test": "vitest",
70
+ "test:ui": "vitest --ui",
71
+ "bench": "vitest bench"
72
72
  }
73
- }
73
+ }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["OPERATORS","OPERATORS","createDataSourceFromArray","createClientDataSource","GridCore"],"sources":["../src/components/TextFilterContent.tsx","../src/components/NumberFilterContent.tsx","../src/components/DateFilterContent.tsx","../src/components/FilterPopup.tsx","../src/gridState/reducer.ts","../src/hooks/useInputHandler.ts","../src/renderers/cellRenderer.tsx","../src/renderers/editRenderer.tsx","../src/renderers/headerRenderer.tsx","../src/Grid.tsx"],"sourcesContent":["// packages/react/src/components/TextFilterContent.tsx\n\nimport React, { useState, useMemo, useCallback } from \"react\";\nimport type { CellValue, ColumnFilterModel, TextFilterCondition, TextFilterOperator } from \"gp-grid-core\";\n\nexport interface TextFilterContentProps {\n distinctValues: CellValue[];\n currentFilter?: ColumnFilterModel;\n onApply: (filter: ColumnFilterModel | null) => void;\n onClose: () => void;\n}\n\nconst MAX_VALUES_FOR_LIST = 100;\n\nconst OPERATORS: { value: TextFilterOperator; label: string }[] = [\n { value: \"contains\", label: \"Contains\" },\n { value: \"notContains\", label: \"Does not contain\" },\n { value: \"equals\", label: \"Equals\" },\n { value: \"notEquals\", label: \"Does not equal\" },\n { value: \"startsWith\", label: \"Starts with\" },\n { value: \"endsWith\", label: \"Ends with\" },\n { value: \"blank\", label: \"Is blank\" },\n { value: \"notBlank\", label: \"Is not blank\" },\n];\n\ninterface Condition {\n operator: TextFilterOperator;\n value: string;\n nextOperator: \"and\" | \"or\";\n}\n\ntype FilterMode = \"values\" | \"condition\";\n\nexport function TextFilterContent({\n distinctValues,\n currentFilter,\n onApply,\n onClose,\n}: TextFilterContentProps): React.ReactNode {\n // Helper to convert value to display string\n const valueToString = useCallback((v: CellValue): string => {\n if (Array.isArray(v)) {\n return v.join(', ');\n }\n return String(v ?? '');\n }, []);\n\n // Determine if we should use values mode or condition mode\n // distinctValues are already sorted by grid-core for array-type columns\n const uniqueValues = useMemo(() => {\n const values = distinctValues\n .filter((v) => v != null && v !== \"\" && !(Array.isArray(v) && v.length === 0))\n .map((v) => valueToString(v));\n // Use Set to deduplicate string representations\n return Array.from(new Set(values)).sort((a, b) => {\n const numA = parseFloat(a);\n const numB = parseFloat(b);\n // If both are valid numbers, sort numerically\n if (!isNaN(numA) && !isNaN(numB)) {\n return numA - numB;\n }\n // Otherwise, use locale-aware string comparison\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n });\n }, [distinctValues, valueToString]);\n\n const hasTooManyValues = uniqueValues.length > MAX_VALUES_FOR_LIST;\n\n // Detect current filter mode from existing filter\n const initialMode = useMemo((): FilterMode => {\n if (!currentFilter?.conditions[0]) {\n return hasTooManyValues ? \"condition\" : \"values\";\n }\n const cond = currentFilter.conditions[0] as TextFilterCondition;\n // If using selectedValues, it's values mode\n if (cond.selectedValues && cond.selectedValues.size > 0) {\n return \"values\";\n }\n return \"condition\";\n }, [currentFilter, hasTooManyValues]);\n\n const [mode, setMode] = useState<FilterMode>(initialMode);\n\n // ============= VALUES MODE STATE =============\n const initialSelected = useMemo(() => {\n if (!currentFilter?.conditions[0]) return new Set<string>();\n const cond = currentFilter.conditions[0] as TextFilterCondition;\n return cond.selectedValues ?? new Set<string>();\n }, [currentFilter]);\n\n const initialIncludeBlanks = useMemo(() => {\n if (!currentFilter?.conditions[0]) return true;\n const cond = currentFilter.conditions[0] as TextFilterCondition;\n return cond.includeBlank ?? true;\n }, [currentFilter]);\n\n const [searchText, setSearchText] = useState(\"\");\n const [selectedValues, setSelectedValues] = useState<Set<string>>(initialSelected);\n const [includeBlanks, setIncludeBlanks] = useState(initialIncludeBlanks);\n\n // ============= CONDITION MODE STATE =============\n const initialConditions = useMemo((): Condition[] => {\n if (!currentFilter?.conditions.length) {\n return [{ operator: \"contains\", value: \"\", nextOperator: \"and\" }];\n }\n // Check if it's condition mode (not selectedValues)\n const cond = currentFilter.conditions[0] as TextFilterCondition;\n if (cond.selectedValues && cond.selectedValues.size > 0) {\n return [{ operator: \"contains\", value: \"\", nextOperator: \"and\" }];\n }\n const defaultCombination = currentFilter.combination ?? \"and\";\n return currentFilter.conditions.map((c) => {\n const tc = c as TextFilterCondition;\n return {\n operator: tc.operator,\n value: tc.value ?? \"\",\n nextOperator: tc.nextOperator ?? defaultCombination,\n };\n });\n }, [currentFilter]);\n\n const [conditions, setConditions] = useState<Condition[]>(initialConditions);\n\n // ============= VALUES MODE LOGIC =============\n const displayValues = useMemo(() => {\n if (!searchText) return uniqueValues;\n const lower = searchText.toLowerCase();\n return uniqueValues.filter((v) => v.toLowerCase().includes(lower));\n }, [uniqueValues, searchText]);\n\n const hasBlanks = useMemo(() => {\n return distinctValues.some((v) => v == null || v === \"\");\n }, [distinctValues]);\n\n const allSelected = useMemo(() => {\n const allNonBlank = displayValues.every((v) => selectedValues.has(v));\n return allNonBlank && (!hasBlanks || includeBlanks);\n }, [displayValues, selectedValues, hasBlanks, includeBlanks]);\n\n const handleSelectAll = useCallback(() => {\n setSelectedValues(new Set(displayValues));\n if (hasBlanks) setIncludeBlanks(true);\n }, [displayValues, hasBlanks]);\n\n const handleDeselectAll = useCallback(() => {\n setSelectedValues(new Set());\n setIncludeBlanks(false);\n }, []);\n\n const handleValueToggle = useCallback((value: string) => {\n setSelectedValues((prev) => {\n const next = new Set(prev);\n if (next.has(value)) {\n next.delete(value);\n } else {\n next.add(value);\n }\n return next;\n });\n }, []);\n\n // ============= CONDITION MODE LOGIC =============\n const updateCondition = useCallback((index: number, updates: Partial<Condition>) => {\n setConditions((prev) => {\n const next = [...prev];\n next[index] = { ...next[index]!, ...updates };\n return next;\n });\n }, []);\n\n const addCondition = useCallback(() => {\n setConditions((prev) => [...prev, { operator: \"contains\", value: \"\", nextOperator: \"and\" }]);\n }, []);\n\n const removeCondition = useCallback((index: number) => {\n setConditions((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n // ============= APPLY LOGIC =============\n const handleApply = useCallback(() => {\n if (mode === \"values\") {\n // Values mode - use selectedValues\n const allNonBlankSelected = uniqueValues.every((v) => selectedValues.has(v));\n const isAllSelected = allNonBlankSelected && (!hasBlanks || includeBlanks);\n\n if (isAllSelected) {\n onApply(null);\n return;\n }\n\n const filter: ColumnFilterModel = {\n conditions: [\n {\n type: \"text\",\n operator: \"equals\",\n selectedValues: selectedValues,\n includeBlank: includeBlanks,\n },\n ],\n combination: \"and\",\n };\n onApply(filter);\n } else {\n // Condition mode - use operators\n const validConditions = conditions.filter((c) => {\n if (c.operator === \"blank\" || c.operator === \"notBlank\") return true;\n return c.value.trim() !== \"\";\n });\n\n if (validConditions.length === 0) {\n onApply(null);\n return;\n }\n\n const filter: ColumnFilterModel = {\n conditions: validConditions.map((c) => ({\n type: \"text\" as const,\n operator: c.operator,\n value: c.value,\n nextOperator: c.nextOperator,\n })),\n combination: \"and\", // Default combination for backwards compatibility\n };\n onApply(filter);\n }\n }, [mode, uniqueValues, selectedValues, includeBlanks, hasBlanks, conditions, onApply]);\n\n const handleClear = useCallback(() => {\n onApply(null);\n }, [onApply]);\n\n return (\n <div className=\"gp-grid-filter-content gp-grid-filter-text\">\n {/* Mode toggle - only show if not too many values */}\n {!hasTooManyValues && (\n <div className=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n className={mode === \"values\" ? \"active\" : \"\"}\n onClick={() => setMode(\"values\")}\n >\n Values\n </button>\n <button\n type=\"button\"\n className={mode === \"condition\" ? \"active\" : \"\"}\n onClick={() => setMode(\"condition\")}\n >\n Condition\n </button>\n </div>\n )}\n\n {/* Too many values message */}\n {hasTooManyValues && mode === \"condition\" && (\n <div className=\"gp-grid-filter-info\">\n Too many unique values ({uniqueValues.length}). Use conditions to filter.\n </div>\n )}\n\n {/* VALUES MODE */}\n {mode === \"values\" && (\n <>\n {/* Search input */}\n <input\n className=\"gp-grid-filter-search\"\n type=\"text\"\n placeholder=\"Search...\"\n value={searchText}\n onChange={(e) => setSearchText(e.target.value)}\n autoFocus\n />\n\n {/* Select all / Deselect all */}\n <div className=\"gp-grid-filter-actions\">\n <button type=\"button\" onClick={handleSelectAll} disabled={allSelected}>\n Select All\n </button>\n <button type=\"button\" onClick={handleDeselectAll}>\n Deselect All\n </button>\n </div>\n\n {/* Checkbox list */}\n <div className=\"gp-grid-filter-list\">\n {/* Blanks option */}\n {hasBlanks && (\n <label className=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n checked={includeBlanks}\n onChange={() => setIncludeBlanks(!includeBlanks)}\n />\n <span className=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n )}\n\n {/* Values */}\n {displayValues.map((value) => (\n <label key={value} className=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n checked={selectedValues.has(value)}\n onChange={() => handleValueToggle(value)}\n />\n <span>{value}</span>\n </label>\n ))}\n </div>\n </>\n )}\n\n {/* CONDITION MODE */}\n {mode === \"condition\" && (\n <>\n {conditions.map((cond, index) => (\n <div key={index} className=\"gp-grid-filter-condition\">\n {index > 0 && (\n <div className=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"and\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"and\" })}\n >\n AND\n </button>\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"or\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"or\" })}\n >\n OR\n </button>\n </div>\n )}\n\n <div className=\"gp-grid-filter-row\">\n <select\n value={cond.operator}\n onChange={(e) => updateCondition(index, { operator: e.target.value as TextFilterOperator })}\n autoFocus={index === 0}\n >\n {OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n\n {cond.operator !== \"blank\" && cond.operator !== \"notBlank\" && (\n <input\n type=\"text\"\n value={cond.value}\n onChange={(e) => updateCondition(index, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"gp-grid-filter-text-input\"\n />\n )}\n\n {conditions.length > 1 && (\n <button\n type=\"button\"\n className=\"gp-grid-filter-remove\"\n onClick={() => removeCondition(index)}\n >\n ×\n </button>\n )}\n </div>\n </div>\n ))}\n\n <button type=\"button\" className=\"gp-grid-filter-add\" onClick={addCondition}>\n + Add condition\n </button>\n </>\n )}\n\n {/* Apply / Clear buttons */}\n <div className=\"gp-grid-filter-buttons\">\n <button type=\"button\" className=\"gp-grid-filter-btn-clear\" onClick={handleClear}>\n Clear\n </button>\n <button type=\"button\" className=\"gp-grid-filter-btn-apply\" onClick={handleApply}>\n Apply\n </button>\n </div>\n </div>\n );\n}\n","// packages/react/src/components/NumberFilterContent.tsx\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport type { ColumnFilterModel, NumberFilterCondition, NumberFilterOperator } from \"gp-grid-core\";\n\nexport interface NumberFilterContentProps {\n currentFilter?: ColumnFilterModel;\n onApply: (filter: ColumnFilterModel | null) => void;\n onClose: () => void;\n}\n\nconst OPERATORS: { value: NumberFilterOperator; label: string }[] = [\n { value: \"=\", label: \"=\" },\n { value: \"!=\", label: \"\\u2260\" },\n { value: \">\", label: \">\" },\n { value: \"<\", label: \"<\" },\n { value: \">=\", label: \"\\u2265\" },\n { value: \"<=\", label: \"\\u2264\" },\n { value: \"between\", label: \"\\u2194\" },\n { value: \"blank\", label: \"Is blank\" },\n { value: \"notBlank\", label: \"Not blank\" },\n];\n\ninterface Condition {\n operator: NumberFilterOperator;\n value: string;\n valueTo: string;\n nextOperator: \"and\" | \"or\";\n}\n\nexport function NumberFilterContent({\n currentFilter,\n onApply,\n onClose,\n}: NumberFilterContentProps): React.ReactNode {\n // Initialize from current filter\n const initialConditions = useMemo((): Condition[] => {\n if (!currentFilter?.conditions.length) {\n return [{ operator: \"=\", value: \"\", valueTo: \"\", nextOperator: \"and\" }];\n }\n const defaultCombination = currentFilter.combination ?? \"and\";\n return currentFilter.conditions.map((c) => {\n const cond = c as NumberFilterCondition;\n return {\n operator: cond.operator,\n value: cond.value != null ? String(cond.value) : \"\",\n valueTo: cond.valueTo != null ? String(cond.valueTo) : \"\",\n nextOperator: cond.nextOperator ?? defaultCombination,\n };\n });\n }, [currentFilter]);\n\n const [conditions, setConditions] = useState<Condition[]>(initialConditions);\n\n const updateCondition = useCallback((index: number, updates: Partial<Condition>) => {\n setConditions((prev) => {\n const next = [...prev];\n next[index] = { ...next[index]!, ...updates };\n return next;\n });\n }, []);\n\n const addCondition = useCallback(() => {\n setConditions((prev) => [...prev, { operator: \"=\", value: \"\", valueTo: \"\", nextOperator: \"and\" }]);\n }, []);\n\n const removeCondition = useCallback((index: number) => {\n setConditions((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleApply = useCallback(() => {\n // Filter out empty conditions\n const validConditions = conditions.filter((c) => {\n if (c.operator === \"blank\" || c.operator === \"notBlank\") return true;\n if (c.operator === \"between\") {\n return c.value !== \"\" && c.valueTo !== \"\";\n }\n return c.value !== \"\";\n });\n\n if (validConditions.length === 0) {\n onApply(null);\n return;\n }\n\n const filter: ColumnFilterModel = {\n conditions: validConditions.map((c) => ({\n type: \"number\" as const,\n operator: c.operator,\n value: c.value ? parseFloat(c.value) : undefined,\n valueTo: c.valueTo ? parseFloat(c.valueTo) : undefined,\n nextOperator: c.nextOperator,\n })),\n combination: \"and\", // Default combination for backwards compatibility\n };\n onApply(filter);\n }, [conditions, onApply]);\n\n const handleClear = useCallback(() => {\n onApply(null);\n }, [onApply]);\n\n return (\n <div className=\"gp-grid-filter-content gp-grid-filter-number\">\n {conditions.map((cond, index) => (\n <div key={index} className=\"gp-grid-filter-condition\">\n {index > 0 && (\n <div className=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"and\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"and\" })}\n >\n AND\n </button>\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"or\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"or\" })}\n >\n OR\n </button>\n </div>\n )}\n\n <div className=\"gp-grid-filter-row\">\n <select\n value={cond.operator}\n onChange={(e) => updateCondition(index, { operator: e.target.value as NumberFilterOperator })}\n >\n {OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n\n {cond.operator !== \"blank\" && cond.operator !== \"notBlank\" && (\n <input\n type=\"number\"\n value={cond.value}\n onChange={(e) => updateCondition(index, { value: e.target.value })}\n placeholder=\"Value\"\n />\n )}\n\n {cond.operator === \"between\" && (\n <>\n <span className=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n value={cond.valueTo}\n onChange={(e) => updateCondition(index, { valueTo: e.target.value })}\n placeholder=\"Value\"\n />\n </>\n )}\n\n {conditions.length > 1 && (\n <button\n type=\"button\"\n className=\"gp-grid-filter-remove\"\n onClick={() => removeCondition(index)}\n >\n ×\n </button>\n )}\n </div>\n </div>\n ))}\n\n <button type=\"button\" className=\"gp-grid-filter-add\" onClick={addCondition}>\n + Add condition\n </button>\n\n <div className=\"gp-grid-filter-buttons\">\n <button type=\"button\" className=\"gp-grid-filter-btn-clear\" onClick={handleClear}>\n Clear\n </button>\n <button type=\"button\" className=\"gp-grid-filter-btn-apply\" onClick={handleApply}>\n Apply\n </button>\n </div>\n </div>\n );\n}\n","// packages/react/src/components/DateFilterContent.tsx\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport type { ColumnFilterModel, DateFilterCondition, DateFilterOperator } from \"gp-grid-core\";\n\nexport interface DateFilterContentProps {\n currentFilter?: ColumnFilterModel;\n onApply: (filter: ColumnFilterModel | null) => void;\n onClose: () => void;\n}\n\nconst OPERATORS: { value: DateFilterOperator; label: string }[] = [\n { value: \"=\", label: \"=\" },\n { value: \"!=\", label: \"\\u2260\" },\n { value: \">\", label: \">\" },\n { value: \"<\", label: \"<\" },\n { value: \"between\", label: \"\\u2194\" },\n { value: \"blank\", label: \"Is blank\" },\n { value: \"notBlank\", label: \"Not blank\" },\n];\n\ninterface Condition {\n operator: DateFilterOperator;\n value: string;\n valueTo: string;\n nextOperator: \"and\" | \"or\";\n}\n\n// Convert Date to YYYY-MM-DD string for input\nfunction formatDateForInput(date: Date | string | undefined): string {\n if (!date) return \"\";\n const d = typeof date === \"string\" ? new Date(date) : date;\n if (isNaN(d.getTime())) return \"\";\n return d.toISOString().split(\"T\")[0]!;\n}\n\nexport function DateFilterContent({\n currentFilter,\n onApply,\n onClose,\n}: DateFilterContentProps): React.ReactNode {\n const initialConditions = useMemo((): Condition[] => {\n if (!currentFilter?.conditions.length) {\n return [{ operator: \"=\", value: \"\", valueTo: \"\", nextOperator: \"and\" }];\n }\n const defaultCombination = currentFilter.combination ?? \"and\";\n return currentFilter.conditions.map((c) => {\n const cond = c as DateFilterCondition;\n return {\n operator: cond.operator,\n value: formatDateForInput(cond.value),\n valueTo: formatDateForInput(cond.valueTo),\n nextOperator: cond.nextOperator ?? defaultCombination,\n };\n });\n }, [currentFilter]);\n\n const [conditions, setConditions] = useState<Condition[]>(initialConditions);\n\n const updateCondition = useCallback((index: number, updates: Partial<Condition>) => {\n setConditions((prev) => {\n const next = [...prev];\n next[index] = { ...next[index]!, ...updates };\n return next;\n });\n }, []);\n\n const addCondition = useCallback(() => {\n setConditions((prev) => [...prev, { operator: \"=\", value: \"\", valueTo: \"\", nextOperator: \"and\" }]);\n }, []);\n\n const removeCondition = useCallback((index: number) => {\n setConditions((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const handleApply = useCallback(() => {\n const validConditions = conditions.filter((c) => {\n if (c.operator === \"blank\" || c.operator === \"notBlank\") return true;\n if (c.operator === \"between\") {\n return c.value !== \"\" && c.valueTo !== \"\";\n }\n return c.value !== \"\";\n });\n\n if (validConditions.length === 0) {\n onApply(null);\n return;\n }\n\n const filter: ColumnFilterModel = {\n conditions: validConditions.map((c) => ({\n type: \"date\" as const,\n operator: c.operator,\n value: c.value || undefined,\n valueTo: c.valueTo || undefined,\n nextOperator: c.nextOperator,\n })),\n combination: \"and\", // Default combination for backwards compatibility\n };\n onApply(filter);\n }, [conditions, onApply]);\n\n const handleClear = useCallback(() => {\n onApply(null);\n }, [onApply]);\n\n return (\n <div className=\"gp-grid-filter-content gp-grid-filter-date\">\n {conditions.map((cond, index) => (\n <div key={index} className=\"gp-grid-filter-condition\">\n {index > 0 && (\n <div className=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"and\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"and\" })}\n >\n AND\n </button>\n <button\n type=\"button\"\n className={conditions[index - 1]?.nextOperator === \"or\" ? \"active\" : \"\"}\n onClick={() => updateCondition(index - 1, { nextOperator: \"or\" })}\n >\n OR\n </button>\n </div>\n )}\n\n <div className=\"gp-grid-filter-row\">\n <select\n value={cond.operator}\n onChange={(e) => updateCondition(index, { operator: e.target.value as DateFilterOperator })}\n >\n {OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n\n {cond.operator !== \"blank\" && cond.operator !== \"notBlank\" && (\n <input\n type=\"date\"\n value={cond.value}\n onChange={(e) => updateCondition(index, { value: e.target.value })}\n />\n )}\n\n {cond.operator === \"between\" && (\n <>\n <span className=\"gp-grid-filter-to\">to</span>\n <input\n type=\"date\"\n value={cond.valueTo}\n onChange={(e) => updateCondition(index, { valueTo: e.target.value })}\n />\n </>\n )}\n\n {conditions.length > 1 && (\n <button\n type=\"button\"\n className=\"gp-grid-filter-remove\"\n onClick={() => removeCondition(index)}\n >\n ×\n </button>\n )}\n </div>\n </div>\n ))}\n\n <button type=\"button\" className=\"gp-grid-filter-add\" onClick={addCondition}>\n + Add condition\n </button>\n\n <div className=\"gp-grid-filter-buttons\">\n <button type=\"button\" className=\"gp-grid-filter-btn-clear\" onClick={handleClear}>\n Clear\n </button>\n <button type=\"button\" className=\"gp-grid-filter-btn-apply\" onClick={handleApply}>\n Apply\n </button>\n </div>\n </div>\n );\n}\n","// packages/react/src/components/FilterPopup.tsx\n\nimport React, { useEffect, useRef, useCallback } from \"react\";\nimport type { ColumnDefinition, CellValue, ColumnFilterModel } from \"gp-grid-core\";\nimport { TextFilterContent } from \"./TextFilterContent\";\nimport { NumberFilterContent } from \"./NumberFilterContent\";\nimport { DateFilterContent } from \"./DateFilterContent\";\n\nexport interface FilterPopupProps {\n column: ColumnDefinition;\n colIndex: number;\n anchorRect: { top: number; left: number; width: number; height: number };\n distinctValues: CellValue[];\n currentFilter?: ColumnFilterModel;\n onApply: (colId: string, filter: ColumnFilterModel | null) => void;\n onClose: () => void;\n}\n\nexport function FilterPopup({\n column,\n colIndex,\n anchorRect,\n distinctValues,\n currentFilter,\n onApply,\n onClose,\n}: FilterPopupProps): React.ReactNode {\n const popupRef = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n // Ignore clicks on filter icons - let them handle their own toggle logic\n if (target.closest(\".gp-grid-filter-icon\")) {\n return;\n }\n if (popupRef.current && !popupRef.current.contains(target)) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onClose();\n }\n };\n\n // Add listeners after a frame to avoid immediate close from the click that opened the popup\n requestAnimationFrame(() => {\n document.addEventListener(\"mousedown\", handleClickOutside);\n document.addEventListener(\"keydown\", handleKeyDown);\n });\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [onClose]);\n\n const handleApply = useCallback(\n (filter: ColumnFilterModel | null) => {\n const colId = column.colId ?? column.field;\n onApply(colId, filter);\n onClose();\n },\n [column, onApply, onClose],\n );\n\n // Position popup below the header\n const popupStyle: React.CSSProperties = {\n position: \"fixed\",\n top: anchorRect.top + anchorRect.height + 4,\n left: anchorRect.left,\n minWidth: Math.max(200, anchorRect.width),\n zIndex: 10000,\n };\n\n // Determine filter type based on column data type\n const dataType = column.cellDataType;\n const isTextType = dataType === \"text\" || dataType === \"object\";\n const isNumberType = dataType === \"number\";\n const isDateType =\n dataType === \"date\" ||\n dataType === \"dateString\" ||\n dataType === \"dateTime\" ||\n dataType === \"dateTimeString\";\n\n return (\n <div ref={popupRef} className=\"gp-grid-filter-popup\" style={popupStyle}>\n <div className=\"gp-grid-filter-header\">\n Filter: {column.headerName ?? column.field}\n </div>\n\n {isTextType && (\n <TextFilterContent\n distinctValues={distinctValues}\n currentFilter={currentFilter}\n onApply={handleApply}\n onClose={onClose}\n />\n )}\n\n {isNumberType && (\n <NumberFilterContent\n currentFilter={currentFilter}\n onApply={handleApply}\n onClose={onClose}\n />\n )}\n\n {isDateType && (\n <DateFilterContent\n currentFilter={currentFilter}\n onApply={handleApply}\n onClose={onClose}\n />\n )}\n\n {!isTextType && !isNumberType && !isDateType && (\n <TextFilterContent\n distinctValues={distinctValues}\n currentFilter={currentFilter}\n onApply={handleApply}\n onClose={onClose}\n />\n )}\n </div>\n );\n}\n","// packages/react/src/gridState/reducer.ts\n\nimport type { GridInstruction, Row } from \"gp-grid-core\";\nimport type { SlotData, HeaderData, GridState, GridAction } from \"./types\";\n\n// =============================================================================\n// Initial State\n// =============================================================================\n\nexport interface InitialStateArgs {\n initialWidth?: number;\n initialHeight?: number;\n}\n\nexport function createInitialState<TData = Row>(args?: InitialStateArgs): GridState<TData> {\n return {\n slots: new Map(),\n activeCell: null,\n selectionRange: null,\n editingCell: null,\n contentWidth: 0,\n contentHeight: args?.initialHeight ?? 0,\n viewportWidth: args?.initialWidth ?? 0,\n headers: new Map(),\n filterPopup: null,\n isLoading: false,\n error: null,\n totalRows: 0,\n visibleRowRange: null,\n hoverPosition: null,\n };\n}\n\n// =============================================================================\n// Instruction Handler\n// =============================================================================\n\n/**\n * Apply a single instruction to mutable slot maps and return other state changes.\n * This allows batching multiple slot operations efficiently.\n */\nexport function applyInstruction<TData = Row>(\n instruction: GridInstruction,\n slots: Map<string, SlotData<TData>>,\n headers: Map<number, HeaderData>,\n): Partial<GridState<TData>> | null {\n switch (instruction.type) {\n case \"CREATE_SLOT\":\n slots.set(instruction.slotId, {\n slotId: instruction.slotId,\n rowIndex: -1,\n rowData: {} as TData,\n translateY: 0,\n });\n return null; // Slots map is mutated\n\n case \"DESTROY_SLOT\":\n slots.delete(instruction.slotId);\n return null;\n\n case \"ASSIGN_SLOT\": {\n const existing = slots.get(instruction.slotId);\n if (existing) {\n slots.set(instruction.slotId, {\n ...existing,\n rowIndex: instruction.rowIndex,\n rowData: instruction.rowData as TData,\n });\n }\n return null;\n }\n\n case \"MOVE_SLOT\": {\n const existing = slots.get(instruction.slotId);\n if (existing) {\n slots.set(instruction.slotId, {\n ...existing,\n translateY: instruction.translateY,\n });\n }\n return null;\n }\n\n case \"SET_ACTIVE_CELL\":\n return { activeCell: instruction.position };\n\n case \"SET_SELECTION_RANGE\":\n return { selectionRange: instruction.range };\n\n case \"UPDATE_VISIBLE_RANGE\":\n return { visibleRowRange: { start: instruction.start, end: instruction.end } };\n\n case \"SET_HOVER_POSITION\":\n return { hoverPosition: instruction.position };\n\n case \"START_EDIT\":\n return {\n editingCell: {\n row: instruction.row,\n col: instruction.col,\n initialValue: instruction.initialValue,\n },\n };\n\n case \"STOP_EDIT\":\n return { editingCell: null };\n\n case \"SET_CONTENT_SIZE\":\n return {\n contentWidth: instruction.width,\n contentHeight: instruction.height,\n viewportWidth: instruction.viewportWidth,\n };\n\n case \"UPDATE_HEADER\":\n headers.set(instruction.colIndex, {\n column: instruction.column,\n sortDirection: instruction.sortDirection,\n sortIndex: instruction.sortIndex,\n sortable: instruction.sortable,\n filterable: instruction.filterable,\n hasFilter: instruction.hasFilter,\n });\n return null;\n\n case \"OPEN_FILTER_POPUP\":\n return {\n filterPopup: {\n isOpen: true,\n colIndex: instruction.colIndex,\n column: instruction.column,\n anchorRect: instruction.anchorRect,\n distinctValues: instruction.distinctValues,\n currentFilter: instruction.currentFilter,\n },\n };\n\n case \"CLOSE_FILTER_POPUP\":\n return { filterPopup: null };\n\n case \"DATA_LOADING\":\n return { isLoading: true, error: null };\n\n case \"DATA_LOADED\":\n return { isLoading: false, totalRows: instruction.totalRows };\n\n case \"DATA_ERROR\":\n return { isLoading: false, error: instruction.error };\n\n // Transaction instructions\n case \"ROWS_ADDED\":\n case \"ROWS_REMOVED\":\n return { totalRows: instruction.totalRows };\n\n case \"ROWS_UPDATED\":\n case \"TRANSACTION_PROCESSED\":\n // These don't change state directly - slot updates come via ASSIGN_SLOT\n return null;\n\n default:\n return null;\n }\n}\n\n// =============================================================================\n// Reducer\n// =============================================================================\n\nexport function gridReducer<TData = Row>(state: GridState<TData>, action: GridAction): GridState<TData> {\n if (action.type === \"RESET\") {\n return createInitialState<TData>();\n }\n\n // Process batch of instructions in one state update\n const { instructions } = action;\n if (instructions.length === 0) {\n return state;\n }\n\n // Create mutable copies of Maps to batch updates\n const newSlots = new Map(state.slots);\n const newHeaders = new Map(state.headers);\n let stateChanges: Partial<GridState<TData>> = {};\n\n // Apply all instructions\n for (const instruction of instructions) {\n const changes = applyInstruction<TData>(instruction, newSlots, newHeaders);\n if (changes) {\n stateChanges = { ...stateChanges, ...changes };\n }\n }\n\n // Return new state with all changes applied\n return {\n ...state,\n ...stateChanges,\n slots: newSlots,\n headers: newHeaders,\n };\n}\n","// packages/react/src/hooks/useInputHandler.ts\n\nimport { useRef, useEffect, useCallback, useState } from \"react\";\nimport type {\n GridCore,\n Row,\n CellPosition,\n CellRange,\n PointerEventData,\n ContainerBounds,\n DragState,\n} from \"gp-grid-core\";\nimport type { SlotData } from \"../gridState/types\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface VisibleColumnInfo {\n column: { colId?: string; field: string };\n originalIndex: number;\n}\n\nexport interface UseInputHandlerOptions {\n activeCell: CellPosition | null;\n selectionRange: CellRange | null;\n editingCell: { row: number; col: number } | null;\n filterPopupOpen: boolean;\n rowHeight: number;\n headerHeight: number;\n columnPositions: number[];\n /** Visible columns with their original indices (for hidden column support) */\n visibleColumnsWithIndices: VisibleColumnInfo[];\n slots: Map<string, SlotData>;\n}\n\nexport interface UseInputHandlerResult {\n // Event handlers\n handleCellMouseDown: (rowIndex: number, colIndex: number, e: React.MouseEvent) => void;\n handleCellDoubleClick: (rowIndex: number, colIndex: number) => void;\n handleFillHandleMouseDown: (e: React.MouseEvent) => void;\n handleHeaderClick: (colIndex: number, e: React.MouseEvent) => void;\n handleKeyDown: (e: React.KeyboardEvent) => void;\n handleWheel: (e: React.WheelEvent, wheelDampening: number) => void;\n // Drag state for UI rendering\n dragState: DragState;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst AUTO_SCROLL_INTERVAL = 16; // ~60fps\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Find the slot for a given row index\n */\nfunction findSlotForRow(slots: Map<string, SlotData>, rowIndex: number): SlotData | null {\n for (const slot of slots.values()) {\n if (slot.rowIndex === rowIndex) {\n return slot;\n }\n }\n return null;\n}\n\n/**\n * Scroll a cell into view if needed\n */\nfunction scrollCellIntoView<TData extends Row>(\n core: GridCore<TData>,\n container: HTMLDivElement,\n row: number,\n rowHeight: number,\n headerHeight: number,\n slots: Map<string, SlotData>\n): void {\n const slot = findSlotForRow(slots, row);\n const cellTranslateY = slot ? slot.translateY : headerHeight + row * rowHeight;\n const cellViewportTop = cellTranslateY - container.scrollTop;\n const cellViewportBottom = cellViewportTop + rowHeight;\n const visibleTop = headerHeight;\n const visibleBottom = container.clientHeight;\n\n if (cellViewportTop < visibleTop) {\n container.scrollTop = core.getScrollTopForRow(row);\n } else if (cellViewportBottom > visibleBottom) {\n const visibleDataHeight = container.clientHeight - headerHeight;\n const rowsInView = Math.floor(visibleDataHeight / rowHeight);\n const targetRow = Math.max(0, row - rowsInView + 1);\n container.scrollTop = core.getScrollTopForRow(targetRow);\n }\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\n/**\n * Hook for managing all input handling using core's InputHandler\n */\nexport function useInputHandler<TData extends Row>(\n coreRef: React.RefObject<GridCore<TData> | null>,\n containerRef: React.RefObject<HTMLDivElement | null>,\n columns: { colId?: string; field: string }[],\n options: UseInputHandlerOptions\n): UseInputHandlerResult {\n const {\n activeCell,\n selectionRange,\n editingCell,\n filterPopupOpen,\n rowHeight,\n headerHeight,\n columnPositions,\n visibleColumnsWithIndices,\n slots,\n } = options;\n\n // Auto-scroll interval ref\n const autoScrollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Drag state for UI (mirrors core's InputHandler state)\n const [dragState, setDragState] = useState<DragState>({\n isDragging: false,\n dragType: null,\n fillSourceRange: null,\n fillTarget: null,\n });\n\n // Update InputHandler deps when options change\n useEffect(() => {\n const core = coreRef.current;\n if (core?.input) {\n core.input.updateDeps({\n getHeaderHeight: () => headerHeight,\n getRowHeight: () => rowHeight,\n getColumnPositions: () => columnPositions,\n getColumnCount: () => visibleColumnsWithIndices.length,\n getOriginalColumnIndex: (visibleIndex: number) => {\n const info = visibleColumnsWithIndices[visibleIndex];\n return info ? info.originalIndex : visibleIndex;\n },\n });\n }\n }, [coreRef, headerHeight, rowHeight, columnPositions, visibleColumnsWithIndices]);\n\n // Auto-scroll helpers\n const startAutoScroll = useCallback((dx: number, dy: number) => {\n if (autoScrollRef.current) {\n clearInterval(autoScrollRef.current);\n }\n autoScrollRef.current = setInterval(() => {\n const container = containerRef.current;\n if (container) {\n container.scrollTop += dy;\n container.scrollLeft += dx;\n }\n }, AUTO_SCROLL_INTERVAL);\n }, [containerRef]);\n\n const stopAutoScroll = useCallback(() => {\n if (autoScrollRef.current) {\n clearInterval(autoScrollRef.current);\n autoScrollRef.current = null;\n }\n }, []);\n\n // Get container bounds\n const getContainerBounds = useCallback((): ContainerBounds | null => {\n const container = containerRef.current;\n if (!container) return null;\n const rect = container.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n };\n }, [containerRef]);\n\n // Convert React mouse event to PointerEventData\n const toPointerEventData = (e: React.MouseEvent | MouseEvent): PointerEventData => ({\n clientX: e.clientX,\n clientY: e.clientY,\n button: e.button,\n shiftKey: e.shiftKey,\n ctrlKey: e.ctrlKey,\n metaKey: e.metaKey,\n });\n\n // ===========================================================================\n // Global Drag Listeners\n // ===========================================================================\n\n const startGlobalDragListeners = useCallback(() => {\n const handleMouseMove = (e: MouseEvent) => {\n const core = coreRef.current;\n const bounds = getContainerBounds();\n if (!core?.input || !bounds) return;\n\n const result = core.input.handleDragMove(toPointerEventData(e), bounds);\n if (result) {\n if (result.autoScroll) {\n startAutoScroll(result.autoScroll.dx, result.autoScroll.dy);\n } else {\n stopAutoScroll();\n }\n // Update UI drag state\n setDragState(core.input.getDragState());\n }\n };\n\n const handleMouseUp = () => {\n const core = coreRef.current;\n if (core?.input) {\n core.input.handleDragEnd();\n setDragState(core.input.getDragState());\n }\n stopAutoScroll();\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n }, [coreRef, getContainerBounds, startAutoScroll, stopAutoScroll]);\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n const handleCellMouseDown = useCallback(\n (rowIndex: number, colIndex: number, e: React.MouseEvent) => {\n const core = coreRef.current;\n if (!core?.input) return;\n\n const result = core.input.handleCellMouseDown(\n rowIndex,\n colIndex,\n toPointerEventData(e)\n );\n\n if (result.focusContainer) {\n containerRef.current?.focus();\n }\n if (result.startDrag === \"selection\") {\n core.input.startSelectionDrag();\n setDragState(core.input.getDragState());\n startGlobalDragListeners();\n }\n },\n [coreRef, containerRef, startGlobalDragListeners]\n );\n\n const handleCellDoubleClick = useCallback(\n (rowIndex: number, colIndex: number) => {\n const core = coreRef.current;\n if (!core?.input) return;\n core.input.handleCellDoubleClick(rowIndex, colIndex);\n },\n [coreRef]\n );\n\n const handleFillHandleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n const core = coreRef.current;\n if (!core?.input) return;\n\n const result = core.input.handleFillHandleMouseDown(\n activeCell,\n selectionRange,\n toPointerEventData(e)\n );\n\n if (result.preventDefault) e.preventDefault();\n if (result.stopPropagation) e.stopPropagation();\n if (result.startDrag === \"fill\") {\n setDragState(core.input.getDragState());\n startGlobalDragListeners();\n }\n },\n [coreRef, activeCell, selectionRange, startGlobalDragListeners]\n );\n\n const handleHeaderClick = useCallback(\n (colIndex: number, e: React.MouseEvent) => {\n const core = coreRef.current;\n if (!core?.input) return;\n\n const column = columns[colIndex];\n if (!column) return;\n\n const colId = column.colId ?? column.field;\n core.input.handleHeaderClick(colId, e.shiftKey);\n },\n [coreRef, columns]\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core?.input) return;\n\n const result = core.input.handleKeyDown(\n {\n key: e.key,\n shiftKey: e.shiftKey,\n ctrlKey: e.ctrlKey,\n metaKey: e.metaKey,\n },\n activeCell,\n editingCell,\n filterPopupOpen\n );\n\n if (result.preventDefault) {\n e.preventDefault();\n }\n if (result.scrollToCell && container) {\n scrollCellIntoView(\n core,\n container,\n result.scrollToCell.row,\n rowHeight,\n headerHeight,\n slots\n );\n }\n },\n [coreRef, containerRef, activeCell, editingCell, filterPopupOpen, rowHeight, headerHeight, slots]\n );\n\n const handleWheel = useCallback(\n (e: React.WheelEvent, wheelDampening: number) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core?.input || !container) return;\n\n const dampened = core.input.handleWheel(e.deltaY, e.deltaX, wheelDampening);\n if (dampened) {\n e.preventDefault();\n container.scrollTop += dampened.dy;\n container.scrollLeft += dampened.dx;\n }\n },\n [coreRef, containerRef]\n );\n\n // Cleanup auto-scroll on unmount\n useEffect(() => {\n return () => {\n stopAutoScroll();\n };\n }, [stopAutoScroll]);\n\n return {\n handleCellMouseDown,\n handleCellDoubleClick,\n handleFillHandleMouseDown,\n handleHeaderClick,\n handleKeyDown,\n handleWheel,\n dragState,\n };\n}\n","// packages/react/src/renderers/cellRenderer.tsx\n\nimport React from \"react\";\nimport type { ColumnDefinition, Row, CellValue, CellRendererParams } from \"gp-grid-core\";\nimport type { ReactCellRenderer } from \"../types\";\n\n/**\n * Get cell value from row data, supporting dot-notation for nested fields\n */\nexport function getCellValue(rowData: Row, field: string): CellValue {\n const parts = field.split(\".\");\n let value: unknown = rowData;\n\n for (const part of parts) {\n if (value == null || typeof value !== \"object\") {\n return null;\n }\n value = (value as Record<string, unknown>)[part];\n }\n\n return (value ?? null) as CellValue;\n}\n\nexport interface RenderCellOptions {\n column: ColumnDefinition;\n rowData: Row;\n rowIndex: number;\n colIndex: number;\n isActive: boolean;\n isSelected: boolean;\n isEditing: boolean;\n cellRenderers: Record<string, ReactCellRenderer>;\n globalCellRenderer?: ReactCellRenderer;\n}\n\n/**\n * Render cell content based on column configuration and renderer registries\n */\nexport function renderCell(options: RenderCellOptions): React.ReactNode {\n const {\n column,\n rowData,\n rowIndex,\n colIndex,\n isActive,\n isSelected,\n isEditing,\n cellRenderers,\n globalCellRenderer,\n } = options;\n\n const value = getCellValue(rowData, column.field);\n const params: CellRendererParams = {\n value,\n rowData,\n column,\n rowIndex,\n colIndex,\n isActive,\n isSelected,\n isEditing,\n };\n\n // Check for column-specific renderer\n if (column.cellRenderer && typeof column.cellRenderer === \"string\") {\n const renderer = cellRenderers[column.cellRenderer];\n if (renderer) {\n return renderer(params);\n }\n }\n\n // Fall back to global renderer\n if (globalCellRenderer) {\n return globalCellRenderer(params);\n }\n\n // Default text rendering\n return value == null ? \"\" : String(value);\n}\n","// packages/react/src/renderers/editRenderer.tsx\n\nimport React from \"react\";\nimport type { GridCore, ColumnDefinition, Row, CellValue, EditRendererParams } from \"gp-grid-core\";\nimport type { ReactEditRenderer } from \"../types\";\nimport { getCellValue } from \"./cellRenderer\";\n\nexport interface RenderEditCellOptions<TData extends Row> {\n column: ColumnDefinition;\n rowData: Row;\n rowIndex: number;\n colIndex: number;\n initialValue: CellValue;\n coreRef: React.RefObject<GridCore<TData> | null>;\n editRenderers: Record<string, ReactEditRenderer>;\n globalEditRenderer?: ReactEditRenderer;\n}\n\n/**\n * Render edit cell content based on column configuration and renderer registries\n */\nexport function renderEditCell<TData extends Row>(\n options: RenderEditCellOptions<TData>,\n): React.ReactNode {\n const {\n column,\n rowData,\n rowIndex,\n colIndex,\n initialValue,\n coreRef,\n editRenderers,\n globalEditRenderer,\n } = options;\n\n const core = coreRef.current;\n if (!core) return null;\n\n const value = getCellValue(rowData, column.field);\n const params: EditRendererParams = {\n value,\n rowData,\n column,\n rowIndex,\n colIndex,\n isActive: true,\n isSelected: true,\n isEditing: true,\n initialValue,\n onValueChange: (newValue) => core.updateEditValue(newValue),\n onCommit: () => core.commitEdit(),\n onCancel: () => core.cancelEdit(),\n };\n\n // Check for column-specific renderer\n if (column.editRenderer && typeof column.editRenderer === \"string\") {\n const renderer = editRenderers[column.editRenderer];\n if (renderer) {\n return renderer(params);\n }\n }\n\n // Fall back to global renderer\n if (globalEditRenderer) {\n return globalEditRenderer(params);\n }\n\n // Default input\n return (\n <input\n className=\"gp-grid-edit-input\"\n type=\"text\"\n defaultValue={initialValue == null ? \"\" : String(initialValue)}\n autoFocus\n onFocus={(e) => e.target.select()}\n onChange={(e) => core.updateEditValue(e.target.value)}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n core.commitEdit();\n } else if (e.key === \"Escape\") {\n core.cancelEdit();\n } else if (e.key === \"Tab\") {\n e.preventDefault();\n core.commitEdit();\n core.selection.moveFocus(e.shiftKey ? \"left\" : \"right\", false);\n }\n }}\n onBlur={() => core.commitEdit()}\n />\n );\n}\n","// packages/react/src/renderers/headerRenderer.tsx\n\nimport React from \"react\";\nimport type { GridCore, ColumnDefinition, Row, SortDirection, HeaderRendererParams } from \"gp-grid-core\";\nimport type { ReactHeaderRenderer } from \"../types\";\n\nexport interface RenderHeaderOptions<TData extends Row> {\n column: ColumnDefinition;\n colIndex: number;\n sortDirection?: SortDirection;\n sortIndex?: number;\n sortable: boolean;\n filterable: boolean;\n hasFilter: boolean;\n coreRef: React.RefObject<GridCore<TData> | null>;\n containerRef: React.RefObject<HTMLDivElement | null>;\n headerRenderers: Record<string, ReactHeaderRenderer>;\n globalHeaderRenderer?: ReactHeaderRenderer;\n}\n\n/**\n * Render header content based on column configuration and renderer registries\n */\nexport function renderHeader<TData extends Row>(\n options: RenderHeaderOptions<TData>,\n): React.ReactNode {\n const {\n column,\n colIndex,\n sortDirection,\n sortIndex,\n sortable,\n filterable,\n hasFilter,\n coreRef,\n containerRef,\n headerRenderers,\n globalHeaderRenderer,\n } = options;\n\n const core = coreRef.current;\n const params: HeaderRendererParams = {\n column,\n colIndex,\n sortDirection,\n sortIndex,\n sortable,\n filterable,\n hasFilter,\n onSort: (direction, addToExisting) => {\n if (core && sortable) {\n core.setSort(column.colId ?? column.field, direction, addToExisting);\n }\n },\n onFilterClick: () => {\n if (core && filterable) {\n const headerCell = containerRef.current?.querySelector(\n `[data-col-index=\"${colIndex}\"]`,\n ) as HTMLElement | null;\n if (headerCell) {\n const rect = headerCell.getBoundingClientRect();\n core.openFilterPopup(colIndex, {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n });\n }\n }\n },\n };\n\n // Check for column-specific renderer\n if (column.headerRenderer && typeof column.headerRenderer === \"string\") {\n const renderer = headerRenderers[column.headerRenderer];\n if (renderer) {\n return renderer(params);\n }\n }\n\n // Fall back to global renderer\n if (globalHeaderRenderer) {\n return globalHeaderRenderer(params);\n }\n\n // Default header with stacked sort arrows and filter icon\n return (\n <>\n <span className=\"gp-grid-header-text\">\n {column.headerName ?? column.field}\n </span>\n <span className=\"gp-grid-header-icons\">\n {/* Stacked sort arrows - always show when sortable */}\n {sortable && (\n <span className=\"gp-grid-sort-arrows\">\n <span className=\"gp-grid-sort-arrows-stack\">\n <svg\n className={`gp-grid-sort-arrow-up${sortDirection === \"asc\" ? \" active\" : \"\"}`}\n width=\"8\"\n height=\"6\"\n viewBox=\"0 0 8 6\"\n >\n <path d=\"M4 0L8 6H0L4 0Z\" fill=\"currentColor\" />\n </svg>\n <svg\n className={`gp-grid-sort-arrow-down${sortDirection === \"desc\" ? \" active\" : \"\"}`}\n width=\"8\"\n height=\"6\"\n viewBox=\"0 0 8 6\"\n >\n <path d=\"M4 6L0 0H8L4 6Z\" fill=\"currentColor\" />\n </svg>\n </span>\n {sortIndex !== undefined && sortIndex > 0 && (\n <span className=\"gp-grid-sort-index\">{sortIndex}</span>\n )}\n </span>\n )}\n {/* Filter icon - MUI FilterList style */}\n {filterable && (\n <span\n className={`gp-grid-filter-icon${hasFilter ? \" active\" : \"\"}`}\n onMouseDown={(e) => {\n e.stopPropagation();\n e.preventDefault();\n params.onFilterClick();\n }}\n onClick={(e) => {\n // Prevent click from triggering header sort\n e.stopPropagation();\n }}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\" />\n </svg>\n </span>\n )}\n </span>\n </>\n );\n}\n","// packages/react/src/Grid.tsx\n\nimport React, {\n useEffect,\n useRef,\n useReducer,\n useCallback,\n useMemo,\n} from \"react\";\nimport {\n GridCore,\n createClientDataSource,\n createDataSourceFromArray,\n injectStyles,\n calculateScaledColumnPositions,\n getTotalWidth,\n isCellSelected,\n isCellActive,\n isCellEditing,\n isCellInFillPreview,\n buildCellClasses,\n} from \"gp-grid-core\";\nimport type { Row, ColumnFilterModel, DataSource } from \"gp-grid-core\";\nimport { FilterPopup } from \"./components\";\nimport { gridReducer, createInitialState } from \"./gridState\";\nimport type { GridState, GridAction } from \"./gridState/types\";\nimport { useInputHandler } from \"./hooks/useInputHandler\";\nimport { renderCell } from \"./renderers/cellRenderer\";\nimport { renderEditCell } from \"./renderers/editRenderer\";\nimport { renderHeader } from \"./renderers/headerRenderer\";\nimport type { GridProps } from \"./types\";\n\n// Re-export types for backwards compatibility\nexport type {\n ReactCellRenderer,\n ReactEditRenderer,\n ReactHeaderRenderer,\n GridProps,\n} from \"./types\";\n\n// =============================================================================\n// Grid Component\n// =============================================================================\n\n/**\n * Grid component\n * @param props - Grid component props\n * @returns Grid React component\n */\nexport function Grid<TData extends Row = Row>(\n props: GridProps<TData>,\n): React.ReactNode {\n // Inject styles on first render (safe to call multiple times)\n injectStyles();\n\n const {\n columns,\n dataSource: providedDataSource,\n rowData,\n rowHeight,\n headerHeight = rowHeight,\n overscan = 3,\n sortingEnabled = true,\n darkMode = false,\n wheelDampening = 0.1,\n cellRenderers = {},\n editRenderers = {},\n headerRenderers = {},\n cellRenderer,\n editRenderer,\n headerRenderer,\n initialWidth,\n initialHeight,\n gridRef,\n highlighting,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<GridCore<TData> | null>(null);\n const prevDataSourceRef = useRef<DataSource<TData> | null>(null);\n const hasInitializedRef = useRef(false);\n const [state, dispatch] = useReducer(\n gridReducer,\n { initialWidth, initialHeight },\n createInitialState,\n ) as [GridState<TData>, React.Dispatch<GridAction>];\n\n // Computed heights\n const totalHeaderHeight = headerHeight;\n\n // Create data source from rowData if not provided\n // Use a ref to cache the created data source and avoid recreating on StrictMode remounts\n const dataSourceCacheRef = useRef<{\n dataSource: DataSource<TData>;\n ownsDataSource: boolean;\n // Track the inputs that created this data source\n providedDataSource: DataSource<TData> | undefined;\n rowData: TData[] | undefined;\n } | null>(null);\n\n // Determine if we need to create a new data source\n const cache = dataSourceCacheRef.current;\n const needsNewDataSource = !cache ||\n cache.providedDataSource !== providedDataSource ||\n cache.rowData !== rowData;\n\n if (needsNewDataSource) {\n // Cleanup previous owned data source\n if (cache?.ownsDataSource) {\n cache.dataSource.destroy?.();\n }\n\n // Create new data source\n if (providedDataSource) {\n dataSourceCacheRef.current = {\n dataSource: providedDataSource,\n ownsDataSource: false,\n providedDataSource,\n rowData,\n };\n } else if (rowData) {\n dataSourceCacheRef.current = {\n dataSource: createDataSourceFromArray(rowData),\n ownsDataSource: true,\n providedDataSource,\n rowData,\n };\n } else {\n dataSourceCacheRef.current = {\n dataSource: createClientDataSource<TData>([]),\n ownsDataSource: true,\n providedDataSource,\n rowData,\n };\n }\n }\n\n const { dataSource, ownsDataSource } = dataSourceCacheRef.current!;\n\n // Cleanup owned data source on unmount\n useEffect(() => {\n return () => {\n if (dataSourceCacheRef.current?.ownsDataSource) {\n dataSourceCacheRef.current.dataSource.destroy?.();\n dataSourceCacheRef.current = null;\n }\n };\n }, []);\n\n // Handle data source changes: reset state early (before GridCore recreates)\n // Cleanup responsibilities:\n // - This effect: reset state on dataSource change\n // - GridCore effect: destroy old core AND old dataSource in cleanup\n useEffect(() => {\n const prevDataSource = prevDataSourceRef.current;\n\n // On change (not initial mount), reset state to clear slot rowData references\n if (prevDataSource && prevDataSource !== dataSource) {\n dispatch({ type: \"RESET\" });\n }\n\n // Track current data source\n prevDataSourceRef.current = dataSource;\n }, [dataSource]);\n\n // Create visible columns with original index tracking (for hidden column support)\n const visibleColumnsWithIndices = useMemo(\n () =>\n columns\n .map((col, index) => ({ column: col, originalIndex: index }))\n .filter(({ column }) => !column.hidden),\n [columns],\n );\n\n // Compute column positions (scaled to fill container when wider) - only for visible columns\n const { positions: columnPositions, widths: columnWidths } = useMemo(\n () =>\n calculateScaledColumnPositions(\n visibleColumnsWithIndices.map((v) => v.column),\n state.viewportWidth,\n ),\n [visibleColumnsWithIndices, state.viewportWidth],\n );\n const totalWidth = getTotalWidth(columnPositions);\n\n // Unified input handling (replaces useFillDrag, useSelectionDrag, useKeyboardNavigation)\n const {\n handleCellMouseDown,\n handleCellDoubleClick,\n handleFillHandleMouseDown,\n handleHeaderClick,\n handleKeyDown,\n handleWheel,\n dragState,\n } = useInputHandler(coreRef, containerRef, columns, {\n activeCell: state.activeCell,\n selectionRange: state.selectionRange,\n editingCell: state.editingCell,\n filterPopupOpen: state.filterPopup?.isOpen ?? false,\n rowHeight,\n headerHeight: totalHeaderHeight,\n columnPositions,\n visibleColumnsWithIndices,\n slots: state.slots,\n });\n\n // Initialize GridCore\n useEffect(() => {\n // Reset state on re-initialization to clear stale slots from previous core\n // Skip on first initialization (nothing to reset)\n if (hasInitializedRef.current) {\n dispatch({ type: \"RESET\" });\n }\n hasInitializedRef.current = true;\n\n const core = new GridCore<TData>({\n columns,\n dataSource,\n rowHeight,\n headerHeight: totalHeaderHeight,\n overscan,\n sortingEnabled,\n highlighting,\n });\n\n coreRef.current = core;\n\n // Set input handler deps immediately after creation\n // This ensures scaled column positions are used even when the core is recreated\n // (e.g., when highlighting options change)\n core.input.updateDeps({\n getHeaderHeight: () => totalHeaderHeight,\n getRowHeight: () => rowHeight,\n getColumnPositions: () => columnPositions,\n getColumnCount: () => visibleColumnsWithIndices.length,\n getOriginalColumnIndex: (visibleIndex: number) => {\n const info = visibleColumnsWithIndices[visibleIndex];\n return info ? info.originalIndex : visibleIndex;\n },\n });\n\n // Expose core via gridRef prop\n if (gridRef) {\n gridRef.current = { core };\n }\n\n // Subscribe to batched instructions for efficient state updates\n const unsubscribe = core.onBatchInstruction((instructions) => {\n dispatch({ type: \"BATCH_INSTRUCTIONS\", instructions });\n });\n\n // Initialize\n core.initialize();\n\n // Immediately set viewport if container is available\n // This ensures column scaling happens before first paint\n const container = containerRef.current;\n if (container) {\n core.setViewport(\n container.scrollTop,\n container.scrollLeft,\n container.clientWidth,\n container.clientHeight,\n );\n }\n\n return () => {\n unsubscribe();\n // Destroy core to release cached row data\n core.destroy();\n // Note: dataSource cleanup is handled separately via ownedDataSourceRef\n // to avoid issues with React StrictMode double-mounting\n coreRef.current = null;\n if (gridRef) {\n gridRef.current = null;\n }\n };\n }, [\n columns,\n dataSource,\n rowHeight,\n totalHeaderHeight,\n overscan,\n sortingEnabled,\n gridRef,\n highlighting,\n ]);\n\n // Subscribe to data source changes (for MutableDataSource)\n useEffect(() => {\n const mutableDataSource = dataSource as {\n subscribe?: (listener: () => void) => () => void;\n };\n if (mutableDataSource.subscribe) {\n const unsubscribe = mutableDataSource.subscribe(() => {\n coreRef.current?.refresh();\n });\n return unsubscribe;\n }\n }, [dataSource]);\n\n // Handle scroll - just pass DOM values to core, which emits UPDATE_VISIBLE_RANGE instruction\n const handleScroll = useCallback(() => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\n\n core.setViewport(\n container.scrollTop,\n container.scrollLeft,\n container.clientWidth,\n container.clientHeight,\n );\n }, []);\n\n // Initial measurement and resize handling\n useEffect(() => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\n\n // Guard for SSR - ResizeObserver not available in Node.js\n if (typeof ResizeObserver === \"undefined\") {\n handleScroll();\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n core.setViewport(\n container.scrollTop,\n container.scrollLeft,\n container.clientWidth,\n container.clientHeight,\n );\n });\n\n resizeObserver.observe(container);\n handleScroll();\n\n return () => resizeObserver.disconnect();\n }, [handleScroll]);\n\n // Attach wheel event listener with { passive: false } to allow preventDefault\n // React's onWheel uses passive listeners by default, which prevents dampening\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const wheelHandler = (e: WheelEvent) => {\n handleWheel(e as unknown as React.WheelEvent, wheelDampening);\n };\n\n container.addEventListener(\"wheel\", wheelHandler, { passive: false });\n return () => container.removeEventListener(\"wheel\", wheelHandler);\n }, [handleWheel, wheelDampening]);\n\n // Handle filter apply (from popup)\n const handleFilterApply = useCallback(\n (colId: string, filter: ColumnFilterModel | null) => {\n const core = coreRef.current;\n if (core) {\n core.setFilter(colId, filter);\n }\n },\n [],\n );\n\n // Handle filter popup close\n const handleFilterPopupClose = useCallback(() => {\n const core = coreRef.current;\n if (core) {\n core.closeFilterPopup();\n }\n }, []);\n\n // Handle cell mouse enter (for highlighting)\n const handleCellMouseEnter = useCallback(\n (rowIndex: number, colIndex: number) => {\n coreRef.current?.input.handleCellMouseEnter(rowIndex, colIndex);\n },\n [],\n );\n\n // Handle cell mouse leave (for highlighting)\n const handleCellMouseLeave = useCallback(() => {\n coreRef.current?.input.handleCellMouseLeave();\n }, []);\n\n // Convert slots map to array for rendering\n const slotsArray = useMemo(\n () => Array.from(state.slots.values()),\n [state.slots],\n );\n\n // Calculate fill handle position (only show for editable columns)\n const fillHandlePosition = useMemo(() => {\n const { activeCell, selectionRange, slots } = state;\n if (!activeCell && !selectionRange) return null;\n\n let row: number, col: number;\n let minCol: number, maxCol: number;\n\n if (selectionRange) {\n row = Math.max(selectionRange.startRow, selectionRange.endRow);\n col = Math.max(selectionRange.startCol, selectionRange.endCol);\n minCol = Math.min(selectionRange.startCol, selectionRange.endCol);\n maxCol = Math.max(selectionRange.startCol, selectionRange.endCol);\n } else if (activeCell) {\n row = activeCell.row;\n col = activeCell.col;\n minCol = col;\n maxCol = col;\n } else {\n return null;\n }\n\n // Check if ALL columns in the selection are editable (skip hidden columns)\n for (let c = minCol; c <= maxCol; c++) {\n const column = columns[c];\n if (!column || column.hidden) continue; // Skip hidden columns\n if (column.editable !== true) {\n return null;\n }\n }\n\n // Find the visible index for the target column\n const visibleIndex = visibleColumnsWithIndices.findIndex(\n (v) => v.originalIndex === col,\n );\n if (visibleIndex === -1) return null; // Column is hidden\n\n // Find the slot for this row and use its actual translateY\n let cellTop: number | null = null;\n for (const slot of slots.values()) {\n if (slot.rowIndex === row) {\n cellTop = slot.translateY;\n break;\n }\n }\n\n if (cellTop === null) return null;\n\n const cellLeft = columnPositions[visibleIndex] ?? 0;\n const cellWidth = columnWidths[visibleIndex] ?? 0;\n\n return {\n top: cellTop + rowHeight - 5,\n left: cellLeft + cellWidth - 20,\n };\n }, [\n state.activeCell,\n state.selectionRange,\n state.slots,\n rowHeight,\n columnPositions,\n columnWidths,\n columns,\n visibleColumnsWithIndices,\n ]);\n\n return (\n <div\n ref={containerRef}\n className={`gp-grid-container${darkMode ? \" gp-grid-container--dark\" : \"\"}`}\n style={{\n width: \"100%\",\n height: \"100%\",\n overflow: \"auto\",\n position: \"relative\",\n }}\n onScroll={handleScroll}\n onKeyDown={handleKeyDown}\n tabIndex={0}\n >\n {/* Content sizer */}\n <div\n style={{\n width: Math.max(state.contentWidth, totalWidth),\n height: Math.max(state.contentHeight, totalHeaderHeight),\n position: \"relative\",\n minWidth: \"100%\",\n }}\n >\n {/* Headers */}\n <div\n className=\"gp-grid-header\"\n style={{\n position: \"sticky\",\n top: 0,\n left: 0,\n height: headerHeight,\n width: Math.max(state.contentWidth, totalWidth),\n minWidth: \"100%\",\n }}\n >\n {visibleColumnsWithIndices.map(({ column, originalIndex }, visibleIndex) => {\n const headerInfo = state.headers.get(originalIndex);\n return (\n <div\n key={column.colId ?? column.field}\n className=\"gp-grid-header-cell\"\n data-col-index={originalIndex}\n style={{\n position: \"absolute\",\n left: `${columnPositions[visibleIndex]}px`,\n top: 0,\n width: `${columnWidths[visibleIndex]}px`,\n height: `${headerHeight}px`,\n background: \"transparent\",\n }}\n onClick={(e) => handleHeaderClick(originalIndex, e)}\n >\n {renderHeader({\n column,\n colIndex: originalIndex,\n sortDirection: headerInfo?.sortDirection,\n sortIndex: headerInfo?.sortIndex,\n sortable: headerInfo?.sortable ?? true,\n filterable: headerInfo?.filterable ?? true,\n hasFilter: headerInfo?.hasFilter ?? false,\n coreRef,\n containerRef,\n headerRenderers,\n globalHeaderRenderer: headerRenderer,\n })}\n </div>\n );\n })}\n </div>\n\n {/* Row slots */}\n {slotsArray.map((slot) => {\n if (slot.rowIndex < 0) return null;\n\n // Compute row highlight classes (pass rowData for content-based rules)\n const highlightRowClasses =\n coreRef.current?.highlight?.computeRowClasses(slot.rowIndex, slot.rowData) ?? [];\n const rowClassName = [\"gp-grid-row\", ...highlightRowClasses]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={slot.slotId}\n className={rowClassName}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n transform: `translateY(${slot.translateY}px)`,\n width: `${Math.max(state.contentWidth, totalWidth)}px`,\n height: `${rowHeight}px`,\n }}\n >\n {visibleColumnsWithIndices.map(({ column, originalIndex }, visibleIndex) => {\n const isEditing = isCellEditing(\n slot.rowIndex,\n originalIndex,\n state.editingCell,\n );\n const active = isCellActive(\n slot.rowIndex,\n originalIndex,\n state.activeCell,\n );\n const selected = isCellSelected(\n slot.rowIndex,\n originalIndex,\n state.selectionRange,\n );\n const inFillPreview = isCellInFillPreview(\n slot.rowIndex,\n originalIndex,\n dragState.dragType === \"fill\",\n dragState.fillSourceRange,\n dragState.fillTarget,\n );\n\n // Build base cell classes\n const baseCellClasses = buildCellClasses(\n active,\n selected,\n isEditing,\n inFillPreview,\n );\n\n // Compute highlight cell classes\n const highlightCellClasses =\n coreRef.current?.highlight?.computeCombinedCellClasses(\n slot.rowIndex,\n originalIndex,\n column,\n slot.rowData,\n ) ?? [];\n\n const cellClasses = [baseCellClasses, ...highlightCellClasses]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={`${slot.slotId}-${originalIndex}`}\n className={cellClasses}\n style={{\n position: \"absolute\",\n left: `${columnPositions[visibleIndex]}px`,\n top: 0,\n width: `${columnWidths[visibleIndex]}px`,\n height: `${rowHeight}px`,\n }}\n onMouseDown={(e) =>\n handleCellMouseDown(slot.rowIndex, originalIndex, e)\n }\n onDoubleClick={() =>\n handleCellDoubleClick(slot.rowIndex, originalIndex)\n }\n onMouseEnter={() =>\n handleCellMouseEnter(slot.rowIndex, originalIndex)\n }\n onMouseLeave={handleCellMouseLeave}\n >\n {isEditing && state.editingCell\n ? renderEditCell({\n column,\n rowData: slot.rowData,\n rowIndex: slot.rowIndex,\n colIndex: originalIndex,\n initialValue: state.editingCell.initialValue,\n coreRef,\n editRenderers,\n globalEditRenderer: editRenderer,\n })\n : renderCell({\n column,\n rowData: slot.rowData,\n rowIndex: slot.rowIndex,\n colIndex: originalIndex,\n isActive: active,\n isSelected: selected,\n isEditing,\n cellRenderers,\n globalCellRenderer: cellRenderer,\n })}\n </div>\n );\n })}\n </div>\n );\n })}\n\n {/* Fill handle (drag to fill) */}\n {fillHandlePosition && !state.editingCell && (\n <div\n className=\"gp-grid-fill-handle\"\n style={{\n position: \"absolute\",\n top: fillHandlePosition.top,\n left: fillHandlePosition.left,\n zIndex: 200,\n }}\n onMouseDown={handleFillHandleMouseDown}\n />\n )}\n\n {/* Loading indicator */}\n {state.isLoading && (\n <div className=\"gp-grid-loading\">\n <div className=\"gp-grid-loading-spinner\" />\n Loading...\n </div>\n )}\n\n {/* Error message */}\n {state.error && (\n <div className=\"gp-grid-error\">Error: {state.error}</div>\n )}\n\n {/* Empty state */}\n {!state.isLoading && !state.error && state.totalRows === 0 && (\n <div className=\"gp-grid-empty\">No data to display</div>\n )}\n </div>\n\n {/* Filter Popup */}\n {state.filterPopup?.isOpen &&\n state.filterPopup.column &&\n state.filterPopup.anchorRect && (\n <FilterPopup\n column={state.filterPopup.column}\n colIndex={state.filterPopup.colIndex}\n anchorRect={state.filterPopup.anchorRect}\n distinctValues={state.filterPopup.distinctValues}\n currentFilter={state.filterPopup.currentFilter}\n onApply={handleFilterApply}\n onClose={handleFilterPopupClose}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}