gp-grid-react 0.1.5 → 0.1.6
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/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -952,12 +952,8 @@ function Grid(props) {
|
|
|
952
952
|
const srcMaxCol = Math.max(fillSourceRange.startCol, fillSourceRange.endCol);
|
|
953
953
|
const fillDown = fillTarget.row > srcMaxRow;
|
|
954
954
|
const fillUp = fillTarget.row < srcMinRow;
|
|
955
|
-
const fillRight = fillTarget.col > srcMaxCol;
|
|
956
|
-
const fillLeft = fillTarget.col < srcMinCol;
|
|
957
955
|
if (fillDown) return row > srcMaxRow && row <= fillTarget.row && col >= srcMinCol && col <= srcMaxCol;
|
|
958
956
|
if (fillUp) return row < srcMinRow && row >= fillTarget.row && col >= srcMinCol && col <= srcMaxCol;
|
|
959
|
-
if (fillRight) return col > srcMaxCol && col <= fillTarget.col && row >= srcMinRow && row <= srcMaxRow;
|
|
960
|
-
if (fillLeft) return col < srcMinCol && col >= fillTarget.col && row >= srcMinRow && row <= srcMaxRow;
|
|
961
957
|
return false;
|
|
962
958
|
}, [
|
|
963
959
|
isDraggingFill,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["stateChanges: Partial<GridState>","createDataSourceFromArray","createClientDataSource","newDirection: SortDirection | null","value: unknown","rowData","params: CellRendererParams","params: EditRendererParams","params: HeaderRendererParams","row: number","col: number","minCol: number","maxCol: number","cellTop: number | null"],"sources":["../src/styles.ts","../src/Grid.tsx"],"sourcesContent":["// packages/react/src/styles.ts\n// Dynamic CSS injection for gp-grid-react\n\nconst STYLE_ID = \"gp-grid-styles\";\n\nexport const gridStyles = `\n/* =============================================================================\n GP Grid - CSS Variables for Theming\n ============================================================================= */\n\n.gp-grid-container {\n /* Colors - Light Mode (default) */\n --gp-grid-bg: #ffffff;\n --gp-grid-bg-alt: #f8f9fa;\n --gp-grid-text: #212529;\n --gp-grid-text-secondary: #6c757d;\n --gp-grid-text-muted: #adb5bd;\n --gp-grid-border: #dee2e6;\n --gp-grid-border-light: #e9ecef;\n \n /* Header */\n --gp-grid-header-bg: #f1f3f5;\n --gp-grid-header-text: #212529;\n \n /* Selection */\n --gp-grid-primary: #228be6;\n --gp-grid-primary-light: #e7f5ff;\n --gp-grid-primary-border: #74c0fc;\n --gp-grid-hover: #f1f3f5;\n \n /* Filter */\n --gp-grid-filter-bg: #f8f9fa;\n --gp-grid-input-bg: #ffffff;\n --gp-grid-input-border: #ced4da;\n \n /* Error */\n --gp-grid-error-bg: #fff5f5;\n --gp-grid-error-text: #c92a2a;\n \n /* Loading */\n --gp-grid-loading-bg: rgba(255, 255, 255, 0.95);\n --gp-grid-loading-text: #495057;\n \n /* Scrollbar */\n --gp-grid-scrollbar-track: #f1f3f5;\n --gp-grid-scrollbar-thumb: #ced4da;\n --gp-grid-scrollbar-thumb-hover: #adb5bd;\n}\n\n/* Dark Mode */\n.gp-grid-container--dark {\n --gp-grid-bg: #1a1b1e;\n --gp-grid-bg-alt: #25262b;\n --gp-grid-text: #c1c2c5;\n --gp-grid-text-secondary: #909296;\n --gp-grid-text-muted: #5c5f66;\n --gp-grid-border: #373a40;\n --gp-grid-border-light: #2c2e33;\n \n /* Header */\n --gp-grid-header-bg: #25262b;\n --gp-grid-header-text: #c1c2c5;\n \n /* Selection */\n --gp-grid-primary: #339af0;\n --gp-grid-primary-light: #1c3d5a;\n --gp-grid-primary-border: #1c7ed6;\n --gp-grid-hover: #2c2e33;\n \n /* Filter */\n --gp-grid-filter-bg: #25262b;\n --gp-grid-input-bg: #1a1b1e;\n --gp-grid-input-border: #373a40;\n \n /* Error */\n --gp-grid-error-bg: #2c1a1a;\n --gp-grid-error-text: #ff6b6b;\n \n /* Loading */\n --gp-grid-loading-bg: rgba(26, 27, 30, 0.95);\n --gp-grid-loading-text: #c1c2c5;\n \n /* Scrollbar */\n --gp-grid-scrollbar-track: #25262b;\n --gp-grid-scrollbar-thumb: #373a40;\n --gp-grid-scrollbar-thumb-hover: #4a4d52;\n}\n\n/* =============================================================================\n GP Grid - Clean Flat Design\n ============================================================================= */\n\n/* Grid Container */\n.gp-grid-container {\n outline: none;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n font-size: 13px;\n line-height: 1.5;\n color: var(--gp-grid-text);\n background-color: var(--gp-grid-bg);\n border: 1px solid var(--gp-grid-border);\n border-radius: 6px;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.gp-grid-container:focus {\n outline: none;\n border-color: var(--gp-grid-primary);\n}\n\n/* =============================================================================\n Header\n ============================================================================= */\n\n.gp-grid-header {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 100;\n background-color: var(--gp-grid-header-bg);\n border-bottom: 1px solid var(--gp-grid-border);\n}\n\n.gp-grid-container .gp-grid-header-cell {\n position: absolute;\n box-sizing: border-box;\n border-right: 1px solid var(--gp-grid-border);\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--gp-grid-header-text);\n cursor: pointer;\n user-select: none;\n display: flex;\n align-items: center;\n padding: 0 12px;\n background-color: transparent;\n transition: background-color 0.1s ease;\n}\n\n.gp-grid-container .gp-grid-header-cell:hover {\n background-color: var(--gp-grid-hover);\n}\n\n.gp-grid-container .gp-grid-header-cell:active {\n background-color: var(--gp-grid-border-light);\n}\n\n.gp-grid-container .gp-grid-header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--gp-grid-header-text);\n}\n\n.gp-grid-sort-indicator {\n margin-left: 6px;\n font-size: 10px;\n color: var(--gp-grid-primary);\n display: flex;\n align-items: center;\n}\n\n.gp-grid-sort-index {\n font-size: 9px;\n margin-left: 2px;\n color: var(--gp-grid-text-secondary);\n}\n\n/* =============================================================================\n Filter Row\n ============================================================================= */\n\n.gp-grid-filter-row {\n position: sticky;\n left: 0;\n z-index: 99;\n background-color: var(--gp-grid-filter-bg);\n border-bottom: 1px solid var(--gp-grid-border);\n}\n\n.gp-grid-filter-cell {\n position: absolute;\n box-sizing: border-box;\n border-right: 1px solid var(--gp-grid-border);\n padding: 6px 8px;\n display: flex;\n align-items: center;\n background-color: var(--gp-grid-filter-bg);\n}\n\n.gp-grid-filter-input {\n width: 100%;\n height: 28px;\n padding: 0 10px;\n font-family: inherit;\n font-size: 12px;\n border: 1px solid var(--gp-grid-input-border);\n border-radius: 4px;\n background-color: var(--gp-grid-input-bg);\n color: var(--gp-grid-text);\n transition: border-color 0.15s ease;\n}\n\n.gp-grid-filter-input:focus {\n outline: none;\n border-color: var(--gp-grid-primary);\n}\n\n.gp-grid-filter-input::placeholder {\n color: var(--gp-grid-text-muted);\n}\n\n/* =============================================================================\n Data Cells\n ============================================================================= */\n\n.gp-grid-row {\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.gp-grid-cell {\n position: absolute;\n top: 0;\n box-sizing: border-box;\n padding: 0 12px;\n display: flex;\n align-items: center;\n cursor: cell;\n color: var(--gp-grid-text);\n border-right: 1px solid var(--gp-grid-border-light);\n border-bottom: 1px solid var(--gp-grid-border-light);\n background-color: var(--gp-grid-bg);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n}\n\n/* Alternating row colors */\n.gp-grid-row--even .gp-grid-cell {\n background-color: var(--gp-grid-bg-alt);\n}\n\n.gp-grid-cell:hover {\n background-color: var(--gp-grid-hover) !important;\n}\n\n/* Active cell (focused) */\n.gp-grid-cell--active {\n background-color: var(--gp-grid-primary-light) !important;\n border: 2px solid var(--gp-grid-primary) !important;\n outline: none;\n z-index: 5;\n padding: 0 11px;\n}\n\n/* Selected cells (range selection) */\n.gp-grid-cell--selected {\n background-color: var(--gp-grid-primary-light) !important;\n}\n\n/* Editing cell */\n.gp-grid-cell--editing {\n background-color: var(--gp-grid-bg) !important;\n border: 2px solid var(--gp-grid-primary) !important;\n padding: 0 !important;\n z-index: 10;\n}\n\n/* =============================================================================\n Fill Handle (drag to fill)\n ============================================================================= */\n\n.gp-grid-fill-handle {\n position: absolute;\n width: 8px;\n height: 8px;\n background-color: var(--gp-grid-primary);\n border: 2px solid var(--gp-grid-bg);\n cursor: crosshair;\n z-index: 100;\n pointer-events: auto;\n box-sizing: border-box;\n border-radius: 1px;\n}\n\n.gp-grid-fill-handle:hover {\n transform: scale(1.2);\n}\n\n/* Fill preview (cells being filled) */\n.gp-grid-cell--fill-preview {\n background-color: var(--gp-grid-primary-light) !important;\n border: 1px dashed var(--gp-grid-primary) !important;\n}\n\n/* =============================================================================\n Edit Input\n ============================================================================= */\n\n.gp-grid-edit-input {\n width: 100%;\n height: 100%;\n padding: 0 11px;\n font-family: inherit;\n font-size: inherit;\n color: var(--gp-grid-text);\n border: none;\n background-color: transparent;\n}\n\n.gp-grid-edit-input:focus {\n outline: none;\n}\n\n/* =============================================================================\n Loading & Error States\n ============================================================================= */\n\n.gp-grid-loading {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 12px 20px;\n background-color: var(--gp-grid-loading-bg);\n color: var(--gp-grid-loading-text);\n border-radius: 6px;\n border: 1px solid var(--gp-grid-border);\n font-weight: 500;\n font-size: 13px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.gp-grid-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid var(--gp-grid-border);\n border-top-color: var(--gp-grid-primary);\n border-radius: 50%;\n animation: gp-grid-spin 0.7s linear infinite;\n}\n\n@keyframes gp-grid-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.gp-grid-error {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 12px 20px;\n background-color: var(--gp-grid-error-bg);\n color: var(--gp-grid-error-text);\n border-radius: 6px;\n border: 1px solid var(--gp-grid-error-text);\n font-weight: 500;\n font-size: 13px;\n z-index: 1000;\n max-width: 80%;\n text-align: center;\n}\n\n/* =============================================================================\n Empty State\n ============================================================================= */\n\n.gp-grid-empty {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: var(--gp-grid-text-muted);\n font-size: 14px;\n text-align: center;\n}\n\n/* =============================================================================\n Scrollbar Styling\n ============================================================================= */\n\n.gp-grid-container::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.gp-grid-container::-webkit-scrollbar-track {\n background-color: var(--gp-grid-scrollbar-track);\n}\n\n.gp-grid-container::-webkit-scrollbar-thumb {\n background-color: var(--gp-grid-scrollbar-thumb);\n border-radius: 4px;\n}\n\n.gp-grid-container::-webkit-scrollbar-thumb:hover {\n background-color: var(--gp-grid-scrollbar-thumb-hover);\n}\n\n.gp-grid-container::-webkit-scrollbar-corner {\n background-color: var(--gp-grid-scrollbar-track);\n}\n`;\n\nlet stylesInjected = false;\n\n/**\n * Inject grid styles into the document head.\n * This is called automatically when the Grid component mounts.\n * Styles are only injected once, even if multiple Grid instances exist.\n */\nexport function injectStyles(): void {\n if (stylesInjected) return;\n if (typeof document === \"undefined\") return; // SSR safety\n\n // Check if styles already exist (e.g., from a previous mount)\n if (document.getElementById(STYLE_ID)) {\n stylesInjected = true;\n return;\n }\n\n const styleElement = document.createElement(\"style\");\n styleElement.id = STYLE_ID;\n styleElement.textContent = gridStyles;\n document.head.appendChild(styleElement);\n stylesInjected = true;\n}\n","// packages/react/src/Grid.tsx\n\nimport React, {\n useEffect,\n useRef,\n useReducer,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport {\n GridCore,\n createClientDataSource,\n createDataSourceFromArray,\n} from \"gp-grid-core\";\nimport type {\n GridInstruction,\n ColumnDefinition,\n DataSource,\n Row,\n CellRendererParams,\n EditRendererParams,\n HeaderRendererParams,\n CellPosition,\n CellRange,\n CellValue,\n SortDirection,\n} from \"gp-grid-core\";\nimport { injectStyles } from \"./styles\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** React cell renderer: A function that renders a cell */\nexport type ReactCellRenderer = (params: CellRendererParams) => React.ReactNode;\n/** React edit renderer: A function that renders the cell while in edit mode */\nexport type ReactEditRenderer = (params: EditRendererParams) => React.ReactNode;\n/** React header renderer: A function that renders a header cell */\nexport type ReactHeaderRenderer = (\n params: HeaderRendererParams,\n) => React.ReactNode;\n\n/** Grid component props */\nexport interface GridProps<TData extends Row = Row> {\n /** Column definitions */\n columns: ColumnDefinition[];\n /** Data source for the grid */\n dataSource?: DataSource<TData>;\n /** Legacy: Raw row data (will be wrapped in a client data source) */\n rowData?: TData[];\n /** Row height in pixels */\n rowHeight: number;\n /** Header height in pixels: Default to row height */\n headerHeight?: number;\n /** Overscan: How many rows to render outside the viewport */\n overscan?: number;\n /** Show filter row below headers: Default to false */\n showFilters?: boolean;\n /** Debounce time for filter input (ms): Default to 300 */\n filterDebounce?: number;\n /** Enable dark mode styling: Default to false */\n darkMode?: boolean;\n /** Wheel scroll dampening factor when virtual scrolling is active (0-1): Default 0.1 */\n wheelDampening?: number;\n\n /** Renderer registries */\n cellRenderers?: Record<string, ReactCellRenderer>;\n /** Edit renderer registries */\n editRenderers?: Record<string, ReactEditRenderer>;\n /** Header renderer registries */\n headerRenderers?: Record<string, ReactHeaderRenderer>;\n\n /** Global cell renderer */\n cellRenderer?: ReactCellRenderer;\n /** Global edit renderer */\n editRenderer?: ReactEditRenderer;\n /** Global header renderer */\n headerRenderer?: ReactHeaderRenderer;\n}\n\n// =============================================================================\n// State Types\n// =============================================================================\n\ninterface SlotData {\n slotId: string;\n rowIndex: number;\n rowData: Row;\n translateY: number;\n}\n\ninterface GridState {\n slots: Map<string, SlotData>;\n activeCell: CellPosition | null;\n selectionRange: CellRange | null;\n editingCell: { row: number; col: number; initialValue: CellValue } | null;\n contentWidth: number;\n contentHeight: number;\n headers: Map<\n number,\n {\n column: ColumnDefinition;\n sortDirection?: SortDirection;\n sortIndex?: number;\n }\n >;\n isLoading: boolean;\n error: string | null;\n totalRows: number;\n}\n\ntype GridAction =\n | { type: \"BATCH_INSTRUCTIONS\"; instructions: GridInstruction[] }\n | { type: \"RESET\" };\n\n// =============================================================================\n// Reducer\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 */\nfunction applyInstruction(\n instruction: GridInstruction,\n slots: Map<string, SlotData>,\n headers: Map<\n number,\n {\n column: ColumnDefinition;\n sortDirection?: SortDirection;\n sortIndex?: number;\n }\n >,\n): Partial<GridState> | null {\n switch (instruction.type) {\n case \"CREATE_SLOT\":\n slots.set(instruction.slotId, {\n slotId: instruction.slotId,\n rowIndex: -1,\n rowData: {},\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,\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 \"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 };\n\n case \"UPDATE_HEADER\":\n headers.set(instruction.colIndex, {\n column: instruction.column,\n sortDirection: instruction.sortDirection,\n sortIndex: instruction.sortIndex,\n });\n return 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 default:\n return null;\n }\n}\n\nfunction gridReducer(state: GridState, action: GridAction): GridState {\n if (action.type === \"RESET\") {\n return createInitialState();\n }\n\n // Process batch of instructions in one state update\n const { instructions } = action;\n // console.log(\"[GP-Grid Reducer] Processing batch:\", instructions.map(i => i.type));\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> = {};\n\n // Apply all instructions\n for (const instruction of instructions) {\n const changes = applyInstruction(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\nfunction createInitialState(): GridState {\n return {\n slots: new Map(),\n activeCell: null,\n selectionRange: null,\n editingCell: null,\n contentWidth: 0,\n contentHeight: 0,\n headers: new Map(),\n isLoading: false,\n error: null,\n totalRows: 0,\n };\n}\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 showFilters = false,\n filterDebounce = 300,\n darkMode = false,\n wheelDampening = 0.1,\n cellRenderers = {},\n editRenderers = {},\n headerRenderers = {},\n cellRenderer,\n editRenderer,\n headerRenderer,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<GridCore<TData> | null>(null);\n const [state, dispatch] = useReducer(gridReducer, null, createInitialState);\n const [filterValues, setFilterValues] = useState<Record<string, string>>({});\n const filterTimeoutRef = useRef<\n Record<string, ReturnType<typeof setTimeout>>\n >({});\n const [isDraggingFill, setIsDraggingFill] = useState(false);\n const [fillTarget, setFillTarget] = useState<{\n row: number;\n col: number;\n } | null>(null);\n const [fillSourceRange, setFillSourceRange] = useState<{\n startRow: number;\n startCol: number;\n endRow: number;\n endCol: number;\n } | null>(null);\n const autoScrollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(\n null,\n );\n const [isDraggingSelection, setIsDraggingSelection] = useState(false);\n\n // Computed heights\n const filterRowHeight = showFilters ? 40 : 0;\n const totalHeaderHeight = headerHeight + filterRowHeight;\n\n // Create data source from rowData if not provided\n const dataSource = useMemo(() => {\n if (providedDataSource) {\n return providedDataSource;\n }\n if (rowData) {\n return createDataSourceFromArray(rowData);\n }\n // Empty data source\n return createClientDataSource<TData>([]);\n }, [providedDataSource, rowData]);\n\n // Compute column positions\n const columnPositions = useMemo(() => {\n const positions = [0];\n let pos = 0;\n for (const col of columns) {\n pos += col.width;\n positions.push(pos);\n }\n return positions;\n }, [columns]);\n\n const totalWidth = columnPositions[columnPositions.length - 1] ?? 0;\n\n // Initialize GridCore\n useEffect(() => {\n const core = new GridCore<TData>({\n columns,\n dataSource,\n rowHeight,\n headerHeight: totalHeaderHeight,\n overscan,\n });\n\n coreRef.current = core;\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 return () => {\n unsubscribe();\n coreRef.current = null;\n };\n }, [columns, dataSource, rowHeight, totalHeaderHeight, overscan]);\n\n // Handle scroll\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 // Handle wheel with reduced sensitivity for large datasets\n const handleWheel = useCallback(\n (e: React.WheelEvent) => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\n\n // Only apply dampening when scaling is active (large datasets)\n if (!core.isScalingActive()) return;\n\n // Prevent default scroll and apply dampened scroll\n e.preventDefault();\n container.scrollTop += e.deltaY * wheelDampening;\n container.scrollLeft += e.deltaX * wheelDampening;\n },\n [wheelDampening],\n );\n\n // Initial measurement\n useEffect(() => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\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 // Handle filter change with debounce\n const handleFilterChange = useCallback(\n (colId: string, value: string) => {\n setFilterValues((prev) => ({ ...prev, [colId]: value }));\n\n // Clear existing timeout\n if (filterTimeoutRef.current[colId]) {\n clearTimeout(filterTimeoutRef.current[colId]);\n }\n\n // Debounce the actual filter application\n filterTimeoutRef.current[colId] = setTimeout(() => {\n const core = coreRef.current;\n if (core) {\n core.setFilter(colId, value);\n }\n }, filterDebounce);\n },\n [filterDebounce],\n );\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n const core = coreRef.current;\n if (!core) return;\n\n // Don't handle keyboard events when editing\n if (\n state.editingCell &&\n e.key !== \"Enter\" &&\n e.key !== \"Escape\" &&\n e.key !== \"Tab\"\n ) {\n return;\n }\n\n const { selection } = core;\n const isShift = e.shiftKey;\n const isCtrl = e.ctrlKey || e.metaKey;\n\n switch (e.key) {\n case \"ArrowUp\":\n e.preventDefault();\n selection.moveFocus(\"up\", isShift);\n break;\n case \"ArrowDown\":\n e.preventDefault();\n selection.moveFocus(\"down\", isShift);\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n selection.moveFocus(\"left\", isShift);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n selection.moveFocus(\"right\", isShift);\n break;\n case \"Enter\":\n e.preventDefault();\n if (state.editingCell) {\n core.commitEdit();\n } else if (state.activeCell) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n if (state.editingCell) {\n core.cancelEdit();\n } else {\n selection.clearSelection();\n }\n break;\n case \"Tab\":\n e.preventDefault();\n if (state.editingCell) {\n core.commitEdit();\n }\n selection.moveFocus(isShift ? \"left\" : \"right\", false);\n break;\n case \"a\":\n if (isCtrl) {\n e.preventDefault();\n selection.selectAll();\n }\n break;\n case \"c\":\n if (isCtrl) {\n e.preventDefault();\n selection.copySelectionToClipboard();\n }\n break;\n case \"F2\":\n e.preventDefault();\n if (state.activeCell && !state.editingCell) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n case \"Delete\":\n case \"Backspace\":\n // Start editing with empty value on delete/backspace\n if (state.activeCell && !state.editingCell) {\n e.preventDefault();\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n default:\n // Start editing on any printable character\n if (\n state.activeCell &&\n !state.editingCell &&\n !isCtrl &&\n e.key.length === 1\n ) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n }\n },\n [state.activeCell, state.editingCell],\n );\n\n // Scroll active cell into view when navigating with keyboard\n useEffect(() => {\n // Skip scrolling when editing - the user just clicked on the cell so it's already visible\n if (!state.activeCell || !containerRef.current || state.editingCell) return;\n\n const { row, col } = state.activeCell;\n const container = containerRef.current;\n const core = coreRef.current;\n if (!core) return;\n\n // Get actually visible rows (not including overscan)\n const { start: visibleStart, end: visibleEnd } = core.getVisibleRowRange();\n\n // Only scroll if row is outside visible range\n if (row < visibleStart) {\n // Row is above viewport - scroll to put it at TOP\n container.scrollTop = core.getScrollTopForRow(row);\n } else if (row > visibleEnd) {\n // Row is below viewport - scroll to put it at BOTTOM\n // We want the row to be the last visible row\n // visibleEnd - visibleStart = number of fully visible rows\n const visibleRows = Math.max(1, visibleEnd - visibleStart);\n // The first row that makes 'row' the last visible is (row - visibleRows)\n const targetFirstRow = Math.max(0, row - visibleRows);\n container.scrollTop = core.getScrollTopForRow(targetFirstRow);\n }\n\n // Horizontal scrolling (unchanged - no scaling on X axis)\n const cellLeft = columnPositions[col] ?? 0;\n const cellRight = cellLeft + (columns[col]?.width ?? 0);\n const visibleLeft = container.scrollLeft;\n const visibleRight = container.scrollLeft + container.clientWidth;\n\n if (cellLeft < visibleLeft) {\n container.scrollLeft = cellLeft;\n } else if (cellRight > visibleRight) {\n container.scrollLeft = cellRight - container.clientWidth;\n }\n }, [state.activeCell, state.editingCell, columnPositions, columns]);\n\n // Cell mouse down handler (starts selection and drag)\n const handleCellMouseDown = useCallback(\n (rowIndex: number, colIndex: number, e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Cell mousedown:\", { rowIndex, colIndex, coreExists: !!coreRef.current });\n const core = coreRef.current;\n if (!core || core.getEditState() !== null) {\n // console.warn(\"[GP-Grid] Core not initialized on cell mousedown\");\n return;\n }\n\n // Only handle left mouse button\n if (e.button !== 0) return;\n\n // Focus the container to enable keyboard navigation\n containerRef.current?.focus();\n\n core.selection.startSelection(\n { row: rowIndex, col: colIndex },\n { shift: e.shiftKey, ctrl: e.ctrlKey || e.metaKey },\n );\n\n // Start drag selection (unless shift is held - that's a one-time extend)\n if (!e.shiftKey) {\n setIsDraggingSelection(true);\n }\n },\n [],\n );\n\n // Cell double-click handler\n const handleCellDoubleClick = useCallback(\n (rowIndex: number, colIndex: number) => {\n const core = coreRef.current;\n if (!core) return;\n\n core.startEdit(rowIndex, colIndex);\n },\n [],\n );\n\n // Header click handler (sort)\n const handleHeaderClick = useCallback(\n (colIndex: number, e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Header click:\", { colIndex, coreExists: !!coreRef.current });\n const core = coreRef.current;\n if (!core) {\n // console.warn(\"[GP-Grid] Core not initialized on header click\");\n return;\n }\n\n const column = columns[colIndex];\n if (!column) {\n // console.warn(\"[GP-Grid] Column not found for index:\", colIndex);\n return;\n }\n\n const colId = column.colId ?? column.field;\n const headerInfo = state.headers.get(colIndex);\n const currentDirection = headerInfo?.sortDirection;\n\n // Cycle: none -> asc -> desc -> none\n let newDirection: SortDirection | null;\n if (!currentDirection) {\n newDirection = \"asc\";\n } else if (currentDirection === \"asc\") {\n newDirection = \"desc\";\n } else {\n newDirection = null;\n }\n\n // console.log(\"[GP-Grid] Setting sort:\", { colId, newDirection });\n core.setSort(colId, newDirection, e.shiftKey);\n },\n [columns, state.headers],\n );\n\n // Fill handle drag handlers\n const handleFillHandleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Fill handle mousedown triggered\");\n e.preventDefault();\n e.stopPropagation();\n\n const core = coreRef.current;\n if (!core) return;\n\n const { activeCell, selectionRange } = state;\n if (!activeCell && !selectionRange) return;\n\n // Create source range from selection or active cell\n const sourceRange = selectionRange ?? {\n startRow: activeCell!.row,\n startCol: activeCell!.col,\n endRow: activeCell!.row,\n endCol: activeCell!.col,\n };\n\n // console.log(\"[GP-Grid] Starting fill drag with source range:\", sourceRange);\n core.fill.startFillDrag(sourceRange);\n setFillSourceRange(sourceRange);\n setFillTarget({\n row: Math.max(sourceRange.startRow, sourceRange.endRow),\n col: Math.max(sourceRange.startCol, sourceRange.endCol),\n });\n setIsDraggingFill(true);\n },\n [state.activeCell, state.selectionRange],\n );\n\n // Handle mouse move during fill drag\n useEffect(() => {\n if (!isDraggingFill) return;\n\n // Auto-scroll configuration\n const SCROLL_THRESHOLD = 40; // pixels from edge to trigger scroll\n const SCROLL_SPEED = 10; // pixels per frame\n\n const handleMouseMove = (e: MouseEvent) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core || !container) return;\n\n // Get container bounds\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n // Calculate mouse position relative to grid content\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop - totalHeaderHeight;\n\n // Find the row under the mouse (use core method to handle scaling)\n const targetRow = Math.max(\n 0,\n core.getRowIndexAtDisplayY(mouseY, scrollTop),\n );\n\n // Find column by checking column positions\n let targetCol = 0;\n for (let i = 0; i < columnPositions.length - 1; i++) {\n if (mouseX >= columnPositions[i]! && mouseX < columnPositions[i + 1]!) {\n targetCol = i;\n break;\n }\n if (mouseX >= columnPositions[columnPositions.length - 1]!) {\n targetCol = columnPositions.length - 2;\n }\n }\n\n core.fill.updateFillDrag(targetRow, targetCol);\n setFillTarget({ row: targetRow, col: targetCol });\n\n // Auto-scroll logic\n const mouseYInContainer = e.clientY - rect.top;\n const mouseXInContainer = e.clientX - rect.left;\n\n // Clear any existing auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n // Check if we need to auto-scroll\n let scrollDeltaX = 0;\n let scrollDeltaY = 0;\n\n // Vertical scrolling\n if (mouseYInContainer < SCROLL_THRESHOLD + totalHeaderHeight) {\n scrollDeltaY = -SCROLL_SPEED;\n } else if (mouseYInContainer > rect.height - SCROLL_THRESHOLD) {\n scrollDeltaY = SCROLL_SPEED;\n }\n\n // Horizontal scrolling\n if (mouseXInContainer < SCROLL_THRESHOLD) {\n scrollDeltaX = -SCROLL_SPEED;\n } else if (mouseXInContainer > rect.width - SCROLL_THRESHOLD) {\n scrollDeltaX = SCROLL_SPEED;\n }\n\n // Start auto-scroll if needed\n if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {\n autoScrollIntervalRef.current = setInterval(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop += scrollDeltaY;\n containerRef.current.scrollLeft += scrollDeltaX;\n }\n }, 16); // ~60fps\n }\n };\n\n const handleMouseUp = () => {\n // Clear auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n const core = coreRef.current;\n if (core) {\n core.fill.commitFillDrag();\n // Refresh slots to show updated values\n core.refreshSlotData();\n }\n setIsDraggingFill(false);\n setFillTarget(null);\n setFillSourceRange(null);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n // Clear auto-scroll on cleanup\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isDraggingFill, totalHeaderHeight, rowHeight, columnPositions]);\n\n // Handle mouse move/up during selection drag\n useEffect(() => {\n if (!isDraggingSelection) return;\n\n // Auto-scroll configuration\n const SCROLL_THRESHOLD = 40;\n const SCROLL_SPEED = 10;\n\n const handleMouseMove = (e: MouseEvent) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core || !container) return;\n\n // Get container bounds\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n // Calculate mouse position relative to grid content\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop - totalHeaderHeight;\n\n // Find the row under the mouse (use core method to handle scaling)\n const targetRow = Math.max(\n 0,\n Math.min(\n core.getRowIndexAtDisplayY(mouseY, scrollTop),\n core.getRowCount() - 1,\n ),\n );\n\n // Find column by checking column positions\n let targetCol = 0;\n for (let i = 0; i < columnPositions.length - 1; i++) {\n if (mouseX >= columnPositions[i]! && mouseX < columnPositions[i + 1]!) {\n targetCol = i;\n break;\n }\n if (mouseX >= columnPositions[columnPositions.length - 1]!) {\n targetCol = columnPositions.length - 2;\n }\n }\n targetCol = Math.max(0, Math.min(targetCol, columns.length - 1));\n\n // Extend selection to target cell (like shift+click)\n core.selection.startSelection(\n { row: targetRow, col: targetCol },\n { shift: true },\n );\n\n // Auto-scroll logic\n const mouseYInContainer = e.clientY - rect.top;\n const mouseXInContainer = e.clientX - rect.left;\n\n // Clear any existing auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n // Check if we need to auto-scroll\n let scrollDeltaX = 0;\n let scrollDeltaY = 0;\n\n // Vertical scrolling\n if (mouseYInContainer < SCROLL_THRESHOLD + totalHeaderHeight) {\n scrollDeltaY = -SCROLL_SPEED;\n } else if (mouseYInContainer > rect.height - SCROLL_THRESHOLD) {\n scrollDeltaY = SCROLL_SPEED;\n }\n\n // Horizontal scrolling\n if (mouseXInContainer < SCROLL_THRESHOLD) {\n scrollDeltaX = -SCROLL_SPEED;\n } else if (mouseXInContainer > rect.width - SCROLL_THRESHOLD) {\n scrollDeltaX = SCROLL_SPEED;\n }\n\n // Start auto-scroll if needed\n if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {\n autoScrollIntervalRef.current = setInterval(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop += scrollDeltaY;\n containerRef.current.scrollLeft += scrollDeltaX;\n }\n }, 16); // ~60fps\n }\n };\n\n const handleMouseUp = () => {\n // Clear auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n setIsDraggingSelection(false);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isDraggingSelection, totalHeaderHeight, columnPositions, columns.length]);\n\n // Render helpers\n const isSelected = useCallback(\n (row: number, col: number): boolean => {\n const { selectionRange } = state;\n if (!selectionRange) return false;\n\n const minRow = Math.min(selectionRange.startRow, selectionRange.endRow);\n const maxRow = Math.max(selectionRange.startRow, selectionRange.endRow);\n const minCol = Math.min(selectionRange.startCol, selectionRange.endCol);\n const maxCol = Math.max(selectionRange.startCol, selectionRange.endCol);\n\n return row >= minRow && row <= maxRow && col >= minCol && col <= maxCol;\n },\n [state.selectionRange],\n );\n\n const isActiveCell = useCallback(\n (row: number, col: number): boolean => {\n return state.activeCell?.row === row && state.activeCell?.col === col;\n },\n [state.activeCell],\n );\n\n const isEditingCell = useCallback(\n (row: number, col: number): boolean => {\n return state.editingCell?.row === row && state.editingCell?.col === col;\n },\n [state.editingCell],\n );\n\n // Check if cell is in fill preview range\n const isInFillPreview = useCallback(\n (row: number, col: number): boolean => {\n if (!isDraggingFill || !fillSourceRange || !fillTarget) return false;\n\n const srcMinRow = Math.min(\n fillSourceRange.startRow,\n fillSourceRange.endRow,\n );\n const srcMaxRow = Math.max(\n fillSourceRange.startRow,\n fillSourceRange.endRow,\n );\n const srcMinCol = Math.min(\n fillSourceRange.startCol,\n fillSourceRange.endCol,\n );\n const srcMaxCol = Math.max(\n fillSourceRange.startCol,\n fillSourceRange.endCol,\n );\n\n // Determine fill direction and range\n const fillDown = fillTarget.row > srcMaxRow;\n const fillUp = fillTarget.row < srcMinRow;\n const fillRight = fillTarget.col > srcMaxCol;\n const fillLeft = fillTarget.col < srcMinCol;\n\n // Check if cell is in the fill preview area (not the source area)\n if (fillDown) {\n return (\n row > srcMaxRow &&\n row <= fillTarget.row &&\n col >= srcMinCol &&\n col <= srcMaxCol\n );\n }\n if (fillUp) {\n return (\n row < srcMinRow &&\n row >= fillTarget.row &&\n col >= srcMinCol &&\n col <= srcMaxCol\n );\n }\n if (fillRight) {\n return (\n col > srcMaxCol &&\n col <= fillTarget.col &&\n row >= srcMinRow &&\n row <= srcMaxRow\n );\n }\n if (fillLeft) {\n return (\n col < srcMinCol &&\n col >= fillTarget.col &&\n row >= srcMinRow &&\n row <= srcMaxRow\n );\n }\n\n return false;\n },\n [isDraggingFill, fillSourceRange, fillTarget],\n );\n\n // Get cell value from row data\n const getCellValue = useCallback((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\n // Render cell content\n const renderCell = useCallback(\n (\n column: ColumnDefinition,\n rowData: Row,\n rowIndex: number,\n colIndex: number,\n ): React.ReactNode => {\n const value = getCellValue(rowData, column.field);\n const params: CellRendererParams = {\n value,\n rowData,\n column,\n rowIndex,\n colIndex,\n isActive: isActiveCell(rowIndex, colIndex),\n isSelected: isSelected(rowIndex, colIndex),\n isEditing: isEditingCell(rowIndex, colIndex),\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 (cellRenderer) {\n return cellRenderer(params);\n }\n\n // Default text rendering\n return value == null ? \"\" : String(value);\n },\n [\n getCellValue,\n isActiveCell,\n isSelected,\n isEditingCell,\n cellRenderers,\n cellRenderer,\n ],\n );\n\n // Render edit cell\n const renderEditCell = useCallback(\n (\n column: ColumnDefinition,\n rowData: Row,\n rowIndex: number,\n colIndex: number,\n initialValue: CellValue,\n ): React.ReactNode => {\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 (editRenderer) {\n return editRenderer(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 [getCellValue, editRenderers, editRenderer],\n );\n\n // Render header\n const renderHeader = useCallback(\n (\n column: ColumnDefinition,\n colIndex: number,\n sortDirection?: SortDirection,\n sortIndex?: number,\n ): React.ReactNode => {\n const core = coreRef.current;\n const params: HeaderRendererParams = {\n column,\n colIndex,\n sortDirection,\n sortIndex,\n onSort: (direction, addToExisting) => {\n if (core) {\n core.setSort(\n column.colId ?? column.field,\n direction,\n addToExisting,\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 (headerRenderer) {\n return headerRenderer(params);\n }\n\n // Default header\n return (\n <>\n <span className=\"gp-grid-header-text\">\n {column.headerName ?? column.field}\n </span>\n {sortDirection && (\n <span className=\"gp-grid-sort-indicator\">\n {sortDirection === \"asc\" ? \"▲\" : \"▼\"}\n {sortIndex !== undefined && sortIndex > 0 && (\n <span className=\"gp-grid-sort-index\">{sortIndex}</span>\n )}\n </span>\n )}\n </>\n );\n },\n [headerRenderers, headerRenderer],\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 // Get the bottom-right corner and column range of selection or active cell\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\n for (let c = minCol; c <= maxCol; c++) {\n const column = columns[c];\n if (!column || column.editable !== true) {\n return null; // Don't show fill handle if any column is not editable\n }\n }\n\n // Find the slot for this row and use its actual translateY\n // This ensures the fill handle stays in sync with the rendered slot\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 row isn't in a visible slot, don't show the fill handle\n if (cellTop === null) return null;\n\n const cellLeft = columnPositions[col] ?? 0;\n const cellWidth = columns[col]?.width ?? 0;\n\n return {\n top: cellTop + rowHeight - 5,\n left: cellLeft + cellWidth - 20, // Move significantly left to avoid scrollbar overlap\n };\n }, [\n state.activeCell,\n state.selectionRange,\n state.slots,\n rowHeight,\n columnPositions,\n columns,\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 onWheel={handleWheel}\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 zIndex: 100,\n }}\n >\n {columns.map((column, colIndex) => {\n const headerInfo = state.headers.get(colIndex);\n return (\n <div\n key={column.colId ?? column.field}\n className=\"gp-grid-header-cell\"\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${headerHeight}px`,\n background: \"transparent\",\n }}\n onClick={(e) => handleHeaderClick(colIndex, e)}\n >\n {renderHeader(\n column,\n colIndex,\n headerInfo?.sortDirection,\n headerInfo?.sortIndex,\n )}\n </div>\n );\n })}\n </div>\n\n {/* Filter Row */}\n {showFilters && (\n <div\n className=\"gp-grid-filter-row\"\n style={{\n position: \"sticky\",\n top: headerHeight,\n left: 0,\n height: filterRowHeight,\n width: Math.max(state.contentWidth, totalWidth),\n minWidth: \"100%\",\n zIndex: 99,\n }}\n >\n {columns.map((column, colIndex) => {\n const colId = column.colId ?? column.field;\n return (\n <div\n key={`filter-${colId}`}\n className=\"gp-grid-filter-cell\"\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${filterRowHeight}px`,\n }}\n >\n <input\n className=\"gp-grid-filter-input\"\n type=\"text\"\n placeholder={`Filter ${column.headerName ?? column.field}...`}\n value={filterValues[colId] ?? \"\"}\n onChange={(e) => handleFilterChange(colId, e.target.value)}\n onKeyDown={(e) => e.stopPropagation()}\n />\n </div>\n );\n })}\n </div>\n )}\n\n {/* Row slots */}\n {slotsArray.map((slot) => {\n if (slot.rowIndex < 0) return null;\n\n const isEvenRow = slot.rowIndex % 2 === 0;\n\n return (\n <div\n key={slot.slotId}\n className={`gp-grid-row ${isEvenRow ? \"gp-grid-row--even\" : \"\"}`}\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 {columns.map((column, colIndex) => {\n const isEditing = isEditingCell(slot.rowIndex, colIndex);\n const active = isActiveCell(slot.rowIndex, colIndex);\n const selected = isSelected(slot.rowIndex, colIndex);\n const inFillPreview = isInFillPreview(slot.rowIndex, colIndex);\n\n const cellClasses = [\n \"gp-grid-cell\",\n active && \"gp-grid-cell--active\",\n selected && !active && \"gp-grid-cell--selected\",\n isEditing && \"gp-grid-cell--editing\",\n inFillPreview && \"gp-grid-cell--fill-preview\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={`${slot.slotId}-${colIndex}`}\n className={cellClasses}\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${rowHeight}px`,\n }}\n onMouseDown={(e) =>\n handleCellMouseDown(slot.rowIndex, colIndex, e)\n }\n onDoubleClick={() =>\n handleCellDoubleClick(slot.rowIndex, colIndex)\n }\n >\n {isEditing && state.editingCell\n ? renderEditCell(\n column,\n slot.rowData,\n slot.rowIndex,\n colIndex,\n state.editingCell.initialValue,\n )\n : renderCell(\n column,\n slot.rowData,\n slot.rowIndex,\n colIndex,\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 </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["stateChanges: Partial<GridState>","createDataSourceFromArray","createClientDataSource","newDirection: SortDirection | null","value: unknown","rowData","params: CellRendererParams","params: EditRendererParams","params: HeaderRendererParams","row: number","col: number","minCol: number","maxCol: number","cellTop: number | null"],"sources":["../src/styles.ts","../src/Grid.tsx"],"sourcesContent":["// packages/react/src/styles.ts\n// Dynamic CSS injection for gp-grid-react\n\nconst STYLE_ID = \"gp-grid-styles\";\n\nexport const gridStyles = `\n/* =============================================================================\n GP Grid - CSS Variables for Theming\n ============================================================================= */\n\n.gp-grid-container {\n /* Colors - Light Mode (default) */\n --gp-grid-bg: #ffffff;\n --gp-grid-bg-alt: #f8f9fa;\n --gp-grid-text: #212529;\n --gp-grid-text-secondary: #6c757d;\n --gp-grid-text-muted: #adb5bd;\n --gp-grid-border: #dee2e6;\n --gp-grid-border-light: #e9ecef;\n \n /* Header */\n --gp-grid-header-bg: #f1f3f5;\n --gp-grid-header-text: #212529;\n \n /* Selection */\n --gp-grid-primary: #228be6;\n --gp-grid-primary-light: #e7f5ff;\n --gp-grid-primary-border: #74c0fc;\n --gp-grid-hover: #f1f3f5;\n \n /* Filter */\n --gp-grid-filter-bg: #f8f9fa;\n --gp-grid-input-bg: #ffffff;\n --gp-grid-input-border: #ced4da;\n \n /* Error */\n --gp-grid-error-bg: #fff5f5;\n --gp-grid-error-text: #c92a2a;\n \n /* Loading */\n --gp-grid-loading-bg: rgba(255, 255, 255, 0.95);\n --gp-grid-loading-text: #495057;\n \n /* Scrollbar */\n --gp-grid-scrollbar-track: #f1f3f5;\n --gp-grid-scrollbar-thumb: #ced4da;\n --gp-grid-scrollbar-thumb-hover: #adb5bd;\n}\n\n/* Dark Mode */\n.gp-grid-container--dark {\n --gp-grid-bg: #1a1b1e;\n --gp-grid-bg-alt: #25262b;\n --gp-grid-text: #c1c2c5;\n --gp-grid-text-secondary: #909296;\n --gp-grid-text-muted: #5c5f66;\n --gp-grid-border: #373a40;\n --gp-grid-border-light: #2c2e33;\n \n /* Header */\n --gp-grid-header-bg: #25262b;\n --gp-grid-header-text: #c1c2c5;\n \n /* Selection */\n --gp-grid-primary: #339af0;\n --gp-grid-primary-light: #1c3d5a;\n --gp-grid-primary-border: #1c7ed6;\n --gp-grid-hover: #2c2e33;\n \n /* Filter */\n --gp-grid-filter-bg: #25262b;\n --gp-grid-input-bg: #1a1b1e;\n --gp-grid-input-border: #373a40;\n \n /* Error */\n --gp-grid-error-bg: #2c1a1a;\n --gp-grid-error-text: #ff6b6b;\n \n /* Loading */\n --gp-grid-loading-bg: rgba(26, 27, 30, 0.95);\n --gp-grid-loading-text: #c1c2c5;\n \n /* Scrollbar */\n --gp-grid-scrollbar-track: #25262b;\n --gp-grid-scrollbar-thumb: #373a40;\n --gp-grid-scrollbar-thumb-hover: #4a4d52;\n}\n\n/* =============================================================================\n GP Grid - Clean Flat Design\n ============================================================================= */\n\n/* Grid Container */\n.gp-grid-container {\n outline: none;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n font-size: 13px;\n line-height: 1.5;\n color: var(--gp-grid-text);\n background-color: var(--gp-grid-bg);\n border: 1px solid var(--gp-grid-border);\n border-radius: 6px;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.gp-grid-container:focus {\n outline: none;\n border-color: var(--gp-grid-primary);\n}\n\n/* =============================================================================\n Header\n ============================================================================= */\n\n.gp-grid-header {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 100;\n background-color: var(--gp-grid-header-bg);\n border-bottom: 1px solid var(--gp-grid-border);\n}\n\n.gp-grid-container .gp-grid-header-cell {\n position: absolute;\n box-sizing: border-box;\n border-right: 1px solid var(--gp-grid-border);\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--gp-grid-header-text);\n cursor: pointer;\n user-select: none;\n display: flex;\n align-items: center;\n padding: 0 12px;\n background-color: transparent;\n transition: background-color 0.1s ease;\n}\n\n.gp-grid-container .gp-grid-header-cell:hover {\n background-color: var(--gp-grid-hover);\n}\n\n.gp-grid-container .gp-grid-header-cell:active {\n background-color: var(--gp-grid-border-light);\n}\n\n.gp-grid-container .gp-grid-header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--gp-grid-header-text);\n}\n\n.gp-grid-sort-indicator {\n margin-left: 6px;\n font-size: 10px;\n color: var(--gp-grid-primary);\n display: flex;\n align-items: center;\n}\n\n.gp-grid-sort-index {\n font-size: 9px;\n margin-left: 2px;\n color: var(--gp-grid-text-secondary);\n}\n\n/* =============================================================================\n Filter Row\n ============================================================================= */\n\n.gp-grid-filter-row {\n position: sticky;\n left: 0;\n z-index: 99;\n background-color: var(--gp-grid-filter-bg);\n border-bottom: 1px solid var(--gp-grid-border);\n}\n\n.gp-grid-filter-cell {\n position: absolute;\n box-sizing: border-box;\n border-right: 1px solid var(--gp-grid-border);\n padding: 6px 8px;\n display: flex;\n align-items: center;\n background-color: var(--gp-grid-filter-bg);\n}\n\n.gp-grid-filter-input {\n width: 100%;\n height: 28px;\n padding: 0 10px;\n font-family: inherit;\n font-size: 12px;\n border: 1px solid var(--gp-grid-input-border);\n border-radius: 4px;\n background-color: var(--gp-grid-input-bg);\n color: var(--gp-grid-text);\n transition: border-color 0.15s ease;\n}\n\n.gp-grid-filter-input:focus {\n outline: none;\n border-color: var(--gp-grid-primary);\n}\n\n.gp-grid-filter-input::placeholder {\n color: var(--gp-grid-text-muted);\n}\n\n/* =============================================================================\n Data Cells\n ============================================================================= */\n\n.gp-grid-row {\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.gp-grid-cell {\n position: absolute;\n top: 0;\n box-sizing: border-box;\n padding: 0 12px;\n display: flex;\n align-items: center;\n cursor: cell;\n color: var(--gp-grid-text);\n border-right: 1px solid var(--gp-grid-border-light);\n border-bottom: 1px solid var(--gp-grid-border-light);\n background-color: var(--gp-grid-bg);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n}\n\n/* Alternating row colors */\n.gp-grid-row--even .gp-grid-cell {\n background-color: var(--gp-grid-bg-alt);\n}\n\n.gp-grid-cell:hover {\n background-color: var(--gp-grid-hover) !important;\n}\n\n/* Active cell (focused) */\n.gp-grid-cell--active {\n background-color: var(--gp-grid-primary-light) !important;\n border: 2px solid var(--gp-grid-primary) !important;\n outline: none;\n z-index: 5;\n padding: 0 11px;\n}\n\n/* Selected cells (range selection) */\n.gp-grid-cell--selected {\n background-color: var(--gp-grid-primary-light) !important;\n}\n\n/* Editing cell */\n.gp-grid-cell--editing {\n background-color: var(--gp-grid-bg) !important;\n border: 2px solid var(--gp-grid-primary) !important;\n padding: 0 !important;\n z-index: 10;\n}\n\n/* =============================================================================\n Fill Handle (drag to fill)\n ============================================================================= */\n\n.gp-grid-fill-handle {\n position: absolute;\n width: 8px;\n height: 8px;\n background-color: var(--gp-grid-primary);\n border: 2px solid var(--gp-grid-bg);\n cursor: crosshair;\n z-index: 100;\n pointer-events: auto;\n box-sizing: border-box;\n border-radius: 1px;\n}\n\n.gp-grid-fill-handle:hover {\n transform: scale(1.2);\n}\n\n/* Fill preview (cells being filled) */\n.gp-grid-cell--fill-preview {\n background-color: var(--gp-grid-primary-light) !important;\n border: 1px dashed var(--gp-grid-primary) !important;\n}\n\n/* =============================================================================\n Edit Input\n ============================================================================= */\n\n.gp-grid-edit-input {\n width: 100%;\n height: 100%;\n padding: 0 11px;\n font-family: inherit;\n font-size: inherit;\n color: var(--gp-grid-text);\n border: none;\n background-color: transparent;\n}\n\n.gp-grid-edit-input:focus {\n outline: none;\n}\n\n/* =============================================================================\n Loading & Error States\n ============================================================================= */\n\n.gp-grid-loading {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 12px 20px;\n background-color: var(--gp-grid-loading-bg);\n color: var(--gp-grid-loading-text);\n border-radius: 6px;\n border: 1px solid var(--gp-grid-border);\n font-weight: 500;\n font-size: 13px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.gp-grid-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid var(--gp-grid-border);\n border-top-color: var(--gp-grid-primary);\n border-radius: 50%;\n animation: gp-grid-spin 0.7s linear infinite;\n}\n\n@keyframes gp-grid-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.gp-grid-error {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 12px 20px;\n background-color: var(--gp-grid-error-bg);\n color: var(--gp-grid-error-text);\n border-radius: 6px;\n border: 1px solid var(--gp-grid-error-text);\n font-weight: 500;\n font-size: 13px;\n z-index: 1000;\n max-width: 80%;\n text-align: center;\n}\n\n/* =============================================================================\n Empty State\n ============================================================================= */\n\n.gp-grid-empty {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: var(--gp-grid-text-muted);\n font-size: 14px;\n text-align: center;\n}\n\n/* =============================================================================\n Scrollbar Styling\n ============================================================================= */\n\n.gp-grid-container::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.gp-grid-container::-webkit-scrollbar-track {\n background-color: var(--gp-grid-scrollbar-track);\n}\n\n.gp-grid-container::-webkit-scrollbar-thumb {\n background-color: var(--gp-grid-scrollbar-thumb);\n border-radius: 4px;\n}\n\n.gp-grid-container::-webkit-scrollbar-thumb:hover {\n background-color: var(--gp-grid-scrollbar-thumb-hover);\n}\n\n.gp-grid-container::-webkit-scrollbar-corner {\n background-color: var(--gp-grid-scrollbar-track);\n}\n`;\n\nlet stylesInjected = false;\n\n/**\n * Inject grid styles into the document head.\n * This is called automatically when the Grid component mounts.\n * Styles are only injected once, even if multiple Grid instances exist.\n */\nexport function injectStyles(): void {\n if (stylesInjected) return;\n if (typeof document === \"undefined\") return; // SSR safety\n\n // Check if styles already exist (e.g., from a previous mount)\n if (document.getElementById(STYLE_ID)) {\n stylesInjected = true;\n return;\n }\n\n const styleElement = document.createElement(\"style\");\n styleElement.id = STYLE_ID;\n styleElement.textContent = gridStyles;\n document.head.appendChild(styleElement);\n stylesInjected = true;\n}\n","// packages/react/src/Grid.tsx\n\nimport React, {\n useEffect,\n useRef,\n useReducer,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport {\n GridCore,\n createClientDataSource,\n createDataSourceFromArray,\n} from \"gp-grid-core\";\nimport type {\n GridInstruction,\n ColumnDefinition,\n DataSource,\n Row,\n CellRendererParams,\n EditRendererParams,\n HeaderRendererParams,\n CellPosition,\n CellRange,\n CellValue,\n SortDirection,\n} from \"gp-grid-core\";\nimport { injectStyles } from \"./styles\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** React cell renderer: A function that renders a cell */\nexport type ReactCellRenderer = (params: CellRendererParams) => React.ReactNode;\n/** React edit renderer: A function that renders the cell while in edit mode */\nexport type ReactEditRenderer = (params: EditRendererParams) => React.ReactNode;\n/** React header renderer: A function that renders a header cell */\nexport type ReactHeaderRenderer = (\n params: HeaderRendererParams,\n) => React.ReactNode;\n\n/** Grid component props */\nexport interface GridProps<TData extends Row = Row> {\n /** Column definitions */\n columns: ColumnDefinition[];\n /** Data source for the grid */\n dataSource?: DataSource<TData>;\n /** Legacy: Raw row data (will be wrapped in a client data source) */\n rowData?: TData[];\n /** Row height in pixels */\n rowHeight: number;\n /** Header height in pixels: Default to row height */\n headerHeight?: number;\n /** Overscan: How many rows to render outside the viewport */\n overscan?: number;\n /** Show filter row below headers: Default to false */\n showFilters?: boolean;\n /** Debounce time for filter input (ms): Default to 300 */\n filterDebounce?: number;\n /** Enable dark mode styling: Default to false */\n darkMode?: boolean;\n /** Wheel scroll dampening factor when virtual scrolling is active (0-1): Default 0.1 */\n wheelDampening?: number;\n\n /** Renderer registries */\n cellRenderers?: Record<string, ReactCellRenderer>;\n /** Edit renderer registries */\n editRenderers?: Record<string, ReactEditRenderer>;\n /** Header renderer registries */\n headerRenderers?: Record<string, ReactHeaderRenderer>;\n\n /** Global cell renderer */\n cellRenderer?: ReactCellRenderer;\n /** Global edit renderer */\n editRenderer?: ReactEditRenderer;\n /** Global header renderer */\n headerRenderer?: ReactHeaderRenderer;\n}\n\n// =============================================================================\n// State Types\n// =============================================================================\n\ninterface SlotData {\n slotId: string;\n rowIndex: number;\n rowData: Row;\n translateY: number;\n}\n\ninterface GridState {\n slots: Map<string, SlotData>;\n activeCell: CellPosition | null;\n selectionRange: CellRange | null;\n editingCell: { row: number; col: number; initialValue: CellValue } | null;\n contentWidth: number;\n contentHeight: number;\n headers: Map<\n number,\n {\n column: ColumnDefinition;\n sortDirection?: SortDirection;\n sortIndex?: number;\n }\n >;\n isLoading: boolean;\n error: string | null;\n totalRows: number;\n}\n\ntype GridAction =\n | { type: \"BATCH_INSTRUCTIONS\"; instructions: GridInstruction[] }\n | { type: \"RESET\" };\n\n// =============================================================================\n// Reducer\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 */\nfunction applyInstruction(\n instruction: GridInstruction,\n slots: Map<string, SlotData>,\n headers: Map<\n number,\n {\n column: ColumnDefinition;\n sortDirection?: SortDirection;\n sortIndex?: number;\n }\n >,\n): Partial<GridState> | null {\n switch (instruction.type) {\n case \"CREATE_SLOT\":\n slots.set(instruction.slotId, {\n slotId: instruction.slotId,\n rowIndex: -1,\n rowData: {},\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,\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 \"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 };\n\n case \"UPDATE_HEADER\":\n headers.set(instruction.colIndex, {\n column: instruction.column,\n sortDirection: instruction.sortDirection,\n sortIndex: instruction.sortIndex,\n });\n return 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 default:\n return null;\n }\n}\n\nfunction gridReducer(state: GridState, action: GridAction): GridState {\n if (action.type === \"RESET\") {\n return createInitialState();\n }\n\n // Process batch of instructions in one state update\n const { instructions } = action;\n // console.log(\"[GP-Grid Reducer] Processing batch:\", instructions.map(i => i.type));\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> = {};\n\n // Apply all instructions\n for (const instruction of instructions) {\n const changes = applyInstruction(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\nfunction createInitialState(): GridState {\n return {\n slots: new Map(),\n activeCell: null,\n selectionRange: null,\n editingCell: null,\n contentWidth: 0,\n contentHeight: 0,\n headers: new Map(),\n isLoading: false,\n error: null,\n totalRows: 0,\n };\n}\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 showFilters = false,\n filterDebounce = 300,\n darkMode = false,\n wheelDampening = 0.1,\n cellRenderers = {},\n editRenderers = {},\n headerRenderers = {},\n cellRenderer,\n editRenderer,\n headerRenderer,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<GridCore<TData> | null>(null);\n const [state, dispatch] = useReducer(gridReducer, null, createInitialState);\n const [filterValues, setFilterValues] = useState<Record<string, string>>({});\n const filterTimeoutRef = useRef<\n Record<string, ReturnType<typeof setTimeout>>\n >({});\n const [isDraggingFill, setIsDraggingFill] = useState(false);\n const [fillTarget, setFillTarget] = useState<{\n row: number;\n col: number;\n } | null>(null);\n const [fillSourceRange, setFillSourceRange] = useState<{\n startRow: number;\n startCol: number;\n endRow: number;\n endCol: number;\n } | null>(null);\n const autoScrollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(\n null,\n );\n const [isDraggingSelection, setIsDraggingSelection] = useState(false);\n\n // Computed heights\n const filterRowHeight = showFilters ? 40 : 0;\n const totalHeaderHeight = headerHeight + filterRowHeight;\n\n // Create data source from rowData if not provided\n const dataSource = useMemo(() => {\n if (providedDataSource) {\n return providedDataSource;\n }\n if (rowData) {\n return createDataSourceFromArray(rowData);\n }\n // Empty data source\n return createClientDataSource<TData>([]);\n }, [providedDataSource, rowData]);\n\n // Compute column positions\n const columnPositions = useMemo(() => {\n const positions = [0];\n let pos = 0;\n for (const col of columns) {\n pos += col.width;\n positions.push(pos);\n }\n return positions;\n }, [columns]);\n\n const totalWidth = columnPositions[columnPositions.length - 1] ?? 0;\n\n // Initialize GridCore\n useEffect(() => {\n const core = new GridCore<TData>({\n columns,\n dataSource,\n rowHeight,\n headerHeight: totalHeaderHeight,\n overscan,\n });\n\n coreRef.current = core;\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 return () => {\n unsubscribe();\n coreRef.current = null;\n };\n }, [columns, dataSource, rowHeight, totalHeaderHeight, overscan]);\n\n // Handle scroll\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 // Handle wheel with reduced sensitivity for large datasets\n const handleWheel = useCallback(\n (e: React.WheelEvent) => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\n\n // Only apply dampening when scaling is active (large datasets)\n if (!core.isScalingActive()) return;\n\n // Prevent default scroll and apply dampened scroll\n e.preventDefault();\n container.scrollTop += e.deltaY * wheelDampening;\n container.scrollLeft += e.deltaX * wheelDampening;\n },\n [wheelDampening],\n );\n\n // Initial measurement\n useEffect(() => {\n const container = containerRef.current;\n const core = coreRef.current;\n if (!container || !core) return;\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 // Handle filter change with debounce\n const handleFilterChange = useCallback(\n (colId: string, value: string) => {\n setFilterValues((prev) => ({ ...prev, [colId]: value }));\n\n // Clear existing timeout\n if (filterTimeoutRef.current[colId]) {\n clearTimeout(filterTimeoutRef.current[colId]);\n }\n\n // Debounce the actual filter application\n filterTimeoutRef.current[colId] = setTimeout(() => {\n const core = coreRef.current;\n if (core) {\n core.setFilter(colId, value);\n }\n }, filterDebounce);\n },\n [filterDebounce],\n );\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n const core = coreRef.current;\n if (!core) return;\n\n // Don't handle keyboard events when editing\n if (\n state.editingCell &&\n e.key !== \"Enter\" &&\n e.key !== \"Escape\" &&\n e.key !== \"Tab\"\n ) {\n return;\n }\n\n const { selection } = core;\n const isShift = e.shiftKey;\n const isCtrl = e.ctrlKey || e.metaKey;\n\n switch (e.key) {\n case \"ArrowUp\":\n e.preventDefault();\n selection.moveFocus(\"up\", isShift);\n break;\n case \"ArrowDown\":\n e.preventDefault();\n selection.moveFocus(\"down\", isShift);\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n selection.moveFocus(\"left\", isShift);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n selection.moveFocus(\"right\", isShift);\n break;\n case \"Enter\":\n e.preventDefault();\n if (state.editingCell) {\n core.commitEdit();\n } else if (state.activeCell) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n if (state.editingCell) {\n core.cancelEdit();\n } else {\n selection.clearSelection();\n }\n break;\n case \"Tab\":\n e.preventDefault();\n if (state.editingCell) {\n core.commitEdit();\n }\n selection.moveFocus(isShift ? \"left\" : \"right\", false);\n break;\n case \"a\":\n if (isCtrl) {\n e.preventDefault();\n selection.selectAll();\n }\n break;\n case \"c\":\n if (isCtrl) {\n e.preventDefault();\n selection.copySelectionToClipboard();\n }\n break;\n case \"F2\":\n e.preventDefault();\n if (state.activeCell && !state.editingCell) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n case \"Delete\":\n case \"Backspace\":\n // Start editing with empty value on delete/backspace\n if (state.activeCell && !state.editingCell) {\n e.preventDefault();\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n default:\n // Start editing on any printable character\n if (\n state.activeCell &&\n !state.editingCell &&\n !isCtrl &&\n e.key.length === 1\n ) {\n core.startEdit(state.activeCell.row, state.activeCell.col);\n }\n break;\n }\n },\n [state.activeCell, state.editingCell],\n );\n\n // Scroll active cell into view when navigating with keyboard\n useEffect(() => {\n // Skip scrolling when editing - the user just clicked on the cell so it's already visible\n if (!state.activeCell || !containerRef.current || state.editingCell) return;\n\n const { row, col } = state.activeCell;\n const container = containerRef.current;\n const core = coreRef.current;\n if (!core) return;\n\n // Get actually visible rows (not including overscan)\n const { start: visibleStart, end: visibleEnd } = core.getVisibleRowRange();\n\n // Only scroll if row is outside visible range\n if (row < visibleStart) {\n // Row is above viewport - scroll to put it at TOP\n container.scrollTop = core.getScrollTopForRow(row);\n } else if (row > visibleEnd) {\n // Row is below viewport - scroll to put it at BOTTOM\n // We want the row to be the last visible row\n // visibleEnd - visibleStart = number of fully visible rows\n const visibleRows = Math.max(1, visibleEnd - visibleStart);\n // The first row that makes 'row' the last visible is (row - visibleRows)\n const targetFirstRow = Math.max(0, row - visibleRows);\n container.scrollTop = core.getScrollTopForRow(targetFirstRow);\n }\n\n // Horizontal scrolling (unchanged - no scaling on X axis)\n const cellLeft = columnPositions[col] ?? 0;\n const cellRight = cellLeft + (columns[col]?.width ?? 0);\n const visibleLeft = container.scrollLeft;\n const visibleRight = container.scrollLeft + container.clientWidth;\n\n if (cellLeft < visibleLeft) {\n container.scrollLeft = cellLeft;\n } else if (cellRight > visibleRight) {\n container.scrollLeft = cellRight - container.clientWidth;\n }\n }, [state.activeCell, state.editingCell, columnPositions, columns]);\n\n // Cell mouse down handler (starts selection and drag)\n const handleCellMouseDown = useCallback(\n (rowIndex: number, colIndex: number, e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Cell mousedown:\", { rowIndex, colIndex, coreExists: !!coreRef.current });\n const core = coreRef.current;\n if (!core || core.getEditState() !== null) {\n // console.warn(\"[GP-Grid] Core not initialized on cell mousedown\");\n return;\n }\n\n // Only handle left mouse button\n if (e.button !== 0) return;\n\n // Focus the container to enable keyboard navigation\n containerRef.current?.focus();\n\n core.selection.startSelection(\n { row: rowIndex, col: colIndex },\n { shift: e.shiftKey, ctrl: e.ctrlKey || e.metaKey },\n );\n\n // Start drag selection (unless shift is held - that's a one-time extend)\n if (!e.shiftKey) {\n setIsDraggingSelection(true);\n }\n },\n [],\n );\n\n // Cell double-click handler\n const handleCellDoubleClick = useCallback(\n (rowIndex: number, colIndex: number) => {\n const core = coreRef.current;\n if (!core) return;\n\n core.startEdit(rowIndex, colIndex);\n },\n [],\n );\n\n // Header click handler (sort)\n const handleHeaderClick = useCallback(\n (colIndex: number, e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Header click:\", { colIndex, coreExists: !!coreRef.current });\n const core = coreRef.current;\n if (!core) {\n // console.warn(\"[GP-Grid] Core not initialized on header click\");\n return;\n }\n\n const column = columns[colIndex];\n if (!column) {\n // console.warn(\"[GP-Grid] Column not found for index:\", colIndex);\n return;\n }\n\n const colId = column.colId ?? column.field;\n const headerInfo = state.headers.get(colIndex);\n const currentDirection = headerInfo?.sortDirection;\n\n // Cycle: none -> asc -> desc -> none\n let newDirection: SortDirection | null;\n if (!currentDirection) {\n newDirection = \"asc\";\n } else if (currentDirection === \"asc\") {\n newDirection = \"desc\";\n } else {\n newDirection = null;\n }\n\n // console.log(\"[GP-Grid] Setting sort:\", { colId, newDirection });\n core.setSort(colId, newDirection, e.shiftKey);\n },\n [columns, state.headers],\n );\n\n // Fill handle drag handlers\n const handleFillHandleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n // console.log(\"[GP-Grid] Fill handle mousedown triggered\");\n e.preventDefault();\n e.stopPropagation();\n\n const core = coreRef.current;\n if (!core) return;\n\n const { activeCell, selectionRange } = state;\n if (!activeCell && !selectionRange) return;\n\n // Create source range from selection or active cell\n const sourceRange = selectionRange ?? {\n startRow: activeCell!.row,\n startCol: activeCell!.col,\n endRow: activeCell!.row,\n endCol: activeCell!.col,\n };\n\n // console.log(\"[GP-Grid] Starting fill drag with source range:\", sourceRange);\n core.fill.startFillDrag(sourceRange);\n setFillSourceRange(sourceRange);\n setFillTarget({\n row: Math.max(sourceRange.startRow, sourceRange.endRow),\n col: Math.max(sourceRange.startCol, sourceRange.endCol),\n });\n setIsDraggingFill(true);\n },\n [state.activeCell, state.selectionRange],\n );\n\n // Handle mouse move during fill drag\n useEffect(() => {\n if (!isDraggingFill) return;\n\n // Auto-scroll configuration\n const SCROLL_THRESHOLD = 40; // pixels from edge to trigger scroll\n const SCROLL_SPEED = 10; // pixels per frame\n\n const handleMouseMove = (e: MouseEvent) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core || !container) return;\n\n // Get container bounds\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n // Calculate mouse position relative to grid content\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop - totalHeaderHeight;\n\n // Find the row under the mouse (use core method to handle scaling)\n const targetRow = Math.max(\n 0,\n core.getRowIndexAtDisplayY(mouseY, scrollTop),\n );\n\n // Find column by checking column positions\n let targetCol = 0;\n for (let i = 0; i < columnPositions.length - 1; i++) {\n if (mouseX >= columnPositions[i]! && mouseX < columnPositions[i + 1]!) {\n targetCol = i;\n break;\n }\n if (mouseX >= columnPositions[columnPositions.length - 1]!) {\n targetCol = columnPositions.length - 2;\n }\n }\n\n core.fill.updateFillDrag(targetRow, targetCol);\n setFillTarget({ row: targetRow, col: targetCol });\n\n // Auto-scroll logic\n const mouseYInContainer = e.clientY - rect.top;\n const mouseXInContainer = e.clientX - rect.left;\n\n // Clear any existing auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n // Check if we need to auto-scroll\n let scrollDeltaX = 0;\n let scrollDeltaY = 0;\n\n // Vertical scrolling\n if (mouseYInContainer < SCROLL_THRESHOLD + totalHeaderHeight) {\n scrollDeltaY = -SCROLL_SPEED;\n } else if (mouseYInContainer > rect.height - SCROLL_THRESHOLD) {\n scrollDeltaY = SCROLL_SPEED;\n }\n\n // Horizontal scrolling\n if (mouseXInContainer < SCROLL_THRESHOLD) {\n scrollDeltaX = -SCROLL_SPEED;\n } else if (mouseXInContainer > rect.width - SCROLL_THRESHOLD) {\n scrollDeltaX = SCROLL_SPEED;\n }\n\n // Start auto-scroll if needed\n if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {\n autoScrollIntervalRef.current = setInterval(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop += scrollDeltaY;\n containerRef.current.scrollLeft += scrollDeltaX;\n }\n }, 16); // ~60fps\n }\n };\n\n const handleMouseUp = () => {\n // Clear auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n const core = coreRef.current;\n if (core) {\n core.fill.commitFillDrag();\n // Refresh slots to show updated values\n core.refreshSlotData();\n }\n setIsDraggingFill(false);\n setFillTarget(null);\n setFillSourceRange(null);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n // Clear auto-scroll on cleanup\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isDraggingFill, totalHeaderHeight, rowHeight, columnPositions]);\n\n // Handle mouse move/up during selection drag\n useEffect(() => {\n if (!isDraggingSelection) return;\n\n // Auto-scroll configuration\n const SCROLL_THRESHOLD = 40;\n const SCROLL_SPEED = 10;\n\n const handleMouseMove = (e: MouseEvent) => {\n const core = coreRef.current;\n const container = containerRef.current;\n if (!core || !container) return;\n\n // Get container bounds\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n // Calculate mouse position relative to grid content\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop - totalHeaderHeight;\n\n // Find the row under the mouse (use core method to handle scaling)\n const targetRow = Math.max(\n 0,\n Math.min(\n core.getRowIndexAtDisplayY(mouseY, scrollTop),\n core.getRowCount() - 1,\n ),\n );\n\n // Find column by checking column positions\n let targetCol = 0;\n for (let i = 0; i < columnPositions.length - 1; i++) {\n if (mouseX >= columnPositions[i]! && mouseX < columnPositions[i + 1]!) {\n targetCol = i;\n break;\n }\n if (mouseX >= columnPositions[columnPositions.length - 1]!) {\n targetCol = columnPositions.length - 2;\n }\n }\n targetCol = Math.max(0, Math.min(targetCol, columns.length - 1));\n\n // Extend selection to target cell (like shift+click)\n core.selection.startSelection(\n { row: targetRow, col: targetCol },\n { shift: true },\n );\n\n // Auto-scroll logic\n const mouseYInContainer = e.clientY - rect.top;\n const mouseXInContainer = e.clientX - rect.left;\n\n // Clear any existing auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n\n // Check if we need to auto-scroll\n let scrollDeltaX = 0;\n let scrollDeltaY = 0;\n\n // Vertical scrolling\n if (mouseYInContainer < SCROLL_THRESHOLD + totalHeaderHeight) {\n scrollDeltaY = -SCROLL_SPEED;\n } else if (mouseYInContainer > rect.height - SCROLL_THRESHOLD) {\n scrollDeltaY = SCROLL_SPEED;\n }\n\n // Horizontal scrolling\n if (mouseXInContainer < SCROLL_THRESHOLD) {\n scrollDeltaX = -SCROLL_SPEED;\n } else if (mouseXInContainer > rect.width - SCROLL_THRESHOLD) {\n scrollDeltaX = SCROLL_SPEED;\n }\n\n // Start auto-scroll if needed\n if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {\n autoScrollIntervalRef.current = setInterval(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop += scrollDeltaY;\n containerRef.current.scrollLeft += scrollDeltaX;\n }\n }, 16); // ~60fps\n }\n };\n\n const handleMouseUp = () => {\n // Clear auto-scroll\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n setIsDraggingSelection(false);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n if (autoScrollIntervalRef.current) {\n clearInterval(autoScrollIntervalRef.current);\n autoScrollIntervalRef.current = null;\n }\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isDraggingSelection, totalHeaderHeight, columnPositions, columns.length]);\n\n // Render helpers\n const isSelected = useCallback(\n (row: number, col: number): boolean => {\n const { selectionRange } = state;\n if (!selectionRange) return false;\n\n const minRow = Math.min(selectionRange.startRow, selectionRange.endRow);\n const maxRow = Math.max(selectionRange.startRow, selectionRange.endRow);\n const minCol = Math.min(selectionRange.startCol, selectionRange.endCol);\n const maxCol = Math.max(selectionRange.startCol, selectionRange.endCol);\n\n return row >= minRow && row <= maxRow && col >= minCol && col <= maxCol;\n },\n [state.selectionRange],\n );\n\n const isActiveCell = useCallback(\n (row: number, col: number): boolean => {\n return state.activeCell?.row === row && state.activeCell?.col === col;\n },\n [state.activeCell],\n );\n\n const isEditingCell = useCallback(\n (row: number, col: number): boolean => {\n return state.editingCell?.row === row && state.editingCell?.col === col;\n },\n [state.editingCell],\n );\n\n // Check if cell is in fill preview range\n const isInFillPreview = useCallback(\n (row: number, col: number): boolean => {\n if (!isDraggingFill || !fillSourceRange || !fillTarget) return false;\n\n const srcMinRow = Math.min(\n fillSourceRange.startRow,\n fillSourceRange.endRow,\n );\n const srcMaxRow = Math.max(\n fillSourceRange.startRow,\n fillSourceRange.endRow,\n );\n const srcMinCol = Math.min(\n fillSourceRange.startCol,\n fillSourceRange.endCol,\n );\n const srcMaxCol = Math.max(\n fillSourceRange.startCol,\n fillSourceRange.endCol,\n );\n\n // Determine fill direction (vertical only)\n const fillDown = fillTarget.row > srcMaxRow;\n const fillUp = fillTarget.row < srcMinRow;\n\n // Check if cell is in the fill preview area (not the source area)\n if (fillDown) {\n return (\n row > srcMaxRow &&\n row <= fillTarget.row &&\n col >= srcMinCol &&\n col <= srcMaxCol\n );\n }\n if (fillUp) {\n return (\n row < srcMinRow &&\n row >= fillTarget.row &&\n col >= srcMinCol &&\n col <= srcMaxCol\n );\n }\n\n return false;\n },\n [isDraggingFill, fillSourceRange, fillTarget],\n );\n\n // Get cell value from row data\n const getCellValue = useCallback((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\n // Render cell content\n const renderCell = useCallback(\n (\n column: ColumnDefinition,\n rowData: Row,\n rowIndex: number,\n colIndex: number,\n ): React.ReactNode => {\n const value = getCellValue(rowData, column.field);\n const params: CellRendererParams = {\n value,\n rowData,\n column,\n rowIndex,\n colIndex,\n isActive: isActiveCell(rowIndex, colIndex),\n isSelected: isSelected(rowIndex, colIndex),\n isEditing: isEditingCell(rowIndex, colIndex),\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 (cellRenderer) {\n return cellRenderer(params);\n }\n\n // Default text rendering\n return value == null ? \"\" : String(value);\n },\n [\n getCellValue,\n isActiveCell,\n isSelected,\n isEditingCell,\n cellRenderers,\n cellRenderer,\n ],\n );\n\n // Render edit cell\n const renderEditCell = useCallback(\n (\n column: ColumnDefinition,\n rowData: Row,\n rowIndex: number,\n colIndex: number,\n initialValue: CellValue,\n ): React.ReactNode => {\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 (editRenderer) {\n return editRenderer(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 [getCellValue, editRenderers, editRenderer],\n );\n\n // Render header\n const renderHeader = useCallback(\n (\n column: ColumnDefinition,\n colIndex: number,\n sortDirection?: SortDirection,\n sortIndex?: number,\n ): React.ReactNode => {\n const core = coreRef.current;\n const params: HeaderRendererParams = {\n column,\n colIndex,\n sortDirection,\n sortIndex,\n onSort: (direction, addToExisting) => {\n if (core) {\n core.setSort(\n column.colId ?? column.field,\n direction,\n addToExisting,\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 (headerRenderer) {\n return headerRenderer(params);\n }\n\n // Default header\n return (\n <>\n <span className=\"gp-grid-header-text\">\n {column.headerName ?? column.field}\n </span>\n {sortDirection && (\n <span className=\"gp-grid-sort-indicator\">\n {sortDirection === \"asc\" ? \"▲\" : \"▼\"}\n {sortIndex !== undefined && sortIndex > 0 && (\n <span className=\"gp-grid-sort-index\">{sortIndex}</span>\n )}\n </span>\n )}\n </>\n );\n },\n [headerRenderers, headerRenderer],\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 // Get the bottom-right corner and column range of selection or active cell\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\n for (let c = minCol; c <= maxCol; c++) {\n const column = columns[c];\n if (!column || column.editable !== true) {\n return null; // Don't show fill handle if any column is not editable\n }\n }\n\n // Find the slot for this row and use its actual translateY\n // This ensures the fill handle stays in sync with the rendered slot\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 row isn't in a visible slot, don't show the fill handle\n if (cellTop === null) return null;\n\n const cellLeft = columnPositions[col] ?? 0;\n const cellWidth = columns[col]?.width ?? 0;\n\n return {\n top: cellTop + rowHeight - 5,\n left: cellLeft + cellWidth - 20, // Move significantly left to avoid scrollbar overlap\n };\n }, [\n state.activeCell,\n state.selectionRange,\n state.slots,\n rowHeight,\n columnPositions,\n columns,\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 onWheel={handleWheel}\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 zIndex: 100,\n }}\n >\n {columns.map((column, colIndex) => {\n const headerInfo = state.headers.get(colIndex);\n return (\n <div\n key={column.colId ?? column.field}\n className=\"gp-grid-header-cell\"\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${headerHeight}px`,\n background: \"transparent\",\n }}\n onClick={(e) => handleHeaderClick(colIndex, e)}\n >\n {renderHeader(\n column,\n colIndex,\n headerInfo?.sortDirection,\n headerInfo?.sortIndex,\n )}\n </div>\n );\n })}\n </div>\n\n {/* Filter Row */}\n {showFilters && (\n <div\n className=\"gp-grid-filter-row\"\n style={{\n position: \"sticky\",\n top: headerHeight,\n left: 0,\n height: filterRowHeight,\n width: Math.max(state.contentWidth, totalWidth),\n minWidth: \"100%\",\n zIndex: 99,\n }}\n >\n {columns.map((column, colIndex) => {\n const colId = column.colId ?? column.field;\n return (\n <div\n key={`filter-${colId}`}\n className=\"gp-grid-filter-cell\"\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${filterRowHeight}px`,\n }}\n >\n <input\n className=\"gp-grid-filter-input\"\n type=\"text\"\n placeholder={`Filter ${column.headerName ?? column.field}...`}\n value={filterValues[colId] ?? \"\"}\n onChange={(e) => handleFilterChange(colId, e.target.value)}\n onKeyDown={(e) => e.stopPropagation()}\n />\n </div>\n );\n })}\n </div>\n )}\n\n {/* Row slots */}\n {slotsArray.map((slot) => {\n if (slot.rowIndex < 0) return null;\n\n const isEvenRow = slot.rowIndex % 2 === 0;\n\n return (\n <div\n key={slot.slotId}\n className={`gp-grid-row ${isEvenRow ? \"gp-grid-row--even\" : \"\"}`}\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 {columns.map((column, colIndex) => {\n const isEditing = isEditingCell(slot.rowIndex, colIndex);\n const active = isActiveCell(slot.rowIndex, colIndex);\n const selected = isSelected(slot.rowIndex, colIndex);\n const inFillPreview = isInFillPreview(slot.rowIndex, colIndex);\n\n const cellClasses = [\n \"gp-grid-cell\",\n active && \"gp-grid-cell--active\",\n selected && !active && \"gp-grid-cell--selected\",\n isEditing && \"gp-grid-cell--editing\",\n inFillPreview && \"gp-grid-cell--fill-preview\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={`${slot.slotId}-${colIndex}`}\n className={cellClasses}\n style={{\n position: \"absolute\",\n left: `${columnPositions[colIndex]}px`,\n top: 0,\n width: `${column.width}px`,\n height: `${rowHeight}px`,\n }}\n onMouseDown={(e) =>\n handleCellMouseDown(slot.rowIndex, colIndex, e)\n }\n onDoubleClick={() =>\n handleCellDoubleClick(slot.rowIndex, colIndex)\n }\n >\n {isEditing && state.editingCell\n ? renderEditCell(\n column,\n slot.rowData,\n slot.rowIndex,\n colIndex,\n state.editingCell.initialValue,\n )\n : renderCell(\n column,\n slot.rowData,\n slot.rowIndex,\n colIndex,\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 </div>\n );\n}\n"],"mappings":"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"}
|
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.1.
|
|
4
|
+
"version": "0.1.6",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|