UNPKG

@1771technologies/lytenyte-pro

Version:

1,456 lines (1,455 loc) 134 kB
import { C as Checkbox, d as COLUMN_MARKER_ID, H as HEADER_CELL_POSITION, g as getTransform, e as COLUMN_EMPTY_PREFIX, f as HEADER_GROUP_CELL_POSITION, h as CollapseButton, F as FLOATING_CELL_POSITION, i as FULL_ENCODING, j as CellFullWidth, E as END_ENCODING, k as Cell, I as Input, G as GRID_CELL_POSITION, l as GridButton } from "./drag-store-BF4ad65L.js"; import { t, n, v, w, B, J, L, K, M, q, p, r, s, P, x, o, z, m, y, R, A } from "./drag-store-BF4ad65L.js"; import { jsx, jsxs, Fragment } from "react/jsx-runtime"; import { Sizer } from "@1771technologies/react-sizer"; import { useEvent, useIsoEffect } from "@1771technologies/react-utils"; import { context } from "@1771technologies/grid-provider"; import * as React from "react"; import { useContext, useMemo, useEffect, useRef, useState, useCallback, memo } from "react"; import { sizeFromCoord, clsx, getClientX, IsoResizeObserver, getPreciseElementDimensions, getClientY, getFocusableElements, clamp, equal, getRelativeXPosition, getRelativeYPosition } from "@1771technologies/js-utils"; import { useDraggable, useDroppable, dragState } from "@1771technologies/react-dragon"; import { getHoveredRowIndex, getHoveredColumnIndex, getRootCell } from "@1771technologies/grid-core"; import { c as useGrid$1, u as useControlled, a as useTransitionStatus, b as useScrollLock, G as GridProvider } from "./useScrollLock-D4UY33Sb.js"; import * as ReactDOM from "react-dom"; import { createPortal } from "react-dom"; import { cascada, signal } from "@1771technologies/react-cascada"; import { M as MenuRoot, a as MenuPortal, t as translateOpenChangeReason, P as PATIENT_CLICK_THRESHOLD, C as ColumnMenuDriver } from "./column-menu-driver-cG-EZgLa.js"; import { SplitPane, splitPaneAxe } from "@1771technologies/react-split-pane"; import { A as AnchorProvider } from "./anchor-context-Cqr_oiJt.js"; import { F as FloatingPortal, P as PropTypes, H as HTMLElementType, r as refType, j as useEventCallback, n as useOpenChangeComplete, p as useFloatingRootContext, x as useRole, v as useClick, w as useDismiss, L as getTarget, A as useInteractions, m as mergeProps, q as useHover, t as safePolygon } from "./proptypes-BjYr2nFr.js"; import { u as useDialogRootContext, D as DialogPortalContext, b as useOptionalDialogRootContext, c as DialogContext, d as DialogRootContext } from "./DialogPortalContext-C2WZTqJ3.js"; import { P as PopoverRootContext, u as usePopoverRootContext, b as PopoverPortalContext } from "./PopoverPortalContext-BdsDjihw.js"; import { makeGridPro } from "@1771technologies/grid-store-pro"; import { M as MoreDotsIcon } from "./more-dots-icon-CzAH3xHG.js"; import { S as SortAscending, a as SortDescending } from "./sort-descending-BMtfaa2L.js"; import { createClientDataSource } from "@1771technologies/grid-client-data-source-pro"; import { createTreeDataSource } from "@1771technologies/grid-tree-data-source"; function useGrid() { return useContext(context); } function useHeaderDisplayGridTemplate(levelsCount, headerHeight, groupHeaderHeight, floatingRowEnabled, floatingRowHeight) { const gridTemplateRows = useMemo(() => { const groupHeight = typeof groupHeaderHeight === "number" ? `${groupHeaderHeight}px` : "auto"; const height = typeof headerHeight === "number" ? `${headerHeight}px` : "auto"; const template = Array.from({ length: levelsCount }, () => groupHeight); template.push(height); if (floatingRowEnabled) { const floatingHeight = typeof floatingRowHeight === "number" ? `${floatingRowHeight}px` : "auto"; template.push(floatingHeight); } return template.join(" "); }, [floatingRowEnabled, floatingRowHeight, groupHeaderHeight, headerHeight, levelsCount]); return gridTemplateRows; } function HeaderCellMarker({ api }) { const supportsSelectedAll = api.rowSelectionSelectAllSupported(); const allSelected = api.rowSelectionAllRowsSelected(); const selected = api.getState().rowSelectionSelectedIds.use(); const someSelected = useMemo(() => { for (const c of selected) { if (api.rowById(c)) return true; } return false; }, [api, selected]); if (!supportsSelectedAll) return null; return /* @__PURE__ */ jsx( "div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx( Checkbox, { tabIndex: -1, isChecked: allSelected || someSelected, isDeterminate: !allSelected && someSelected, onClick: () => { if (allSelected) api.rowSelectionClear(); else api.rowSelectionSelectAll(); } } ) } ); } function useHeaderCellRenderer(api, column) { const sx = api.getState(); const renderers = sx.columnHeaderRenderers.use(); const base = sx.columnBase.use(); const defaultRenderer = sx.internal.columnHeaderDefaultRenderer.peek(); const Renderer = useMemo(() => { if (column.id === COLUMN_MARKER_ID) return HeaderCellMarker; const fn = column.headerRenderer ?? base.headerRenderer; if (!fn) return defaultRenderer; if (typeof fn === "string") { const cell = renderers[fn]; if (!cell) throw new Error(`Header cell renderer with name ${fn} does not exist.`); return cell; } return fn; }, [base.headerRenderer, column.headerRenderer, column.id, defaultRenderer, renderers]); return Renderer; } function useHeaderMove(api, column, columnIndex, ref) { const gridId = api.getState().gridId.use(); const dragProps = useDraggable({ onDragStart: () => { document.body.classList.add("lng1771-drag-on"); }, onDragEnd: () => { document.body.classList.remove("lng1771-drag-on"); }, onDragCancel: () => { document.body.classList.remove("lng1771-drag-on"); }, dragData: () => ({ columns: [column], columnIndex }), dragTags: () => { const c = [`${gridId}:grid:${column.pin ?? "none"}`]; const groupable = api.columnIsRowGroupable(column); const isGrouped = api.getState().rowGroupModel.peek().includes(column.id); if (groupable && !isGrouped) c.push(`${gridId}:grid:groupable`); return c; }, placeholder: () => /* @__PURE__ */ jsx(DragPlaceholder$1, { column }) }); const { canDrop, isOver, ...dropProps } = useDroppable({ tags: [`${gridId}:grid:${column.pin ?? "none"}`], onDrop: (p2) => { const data2 = p2.getData(); const dragIndex2 = data2.columnIndex; const isBefore2 = columnIndex < dragIndex2; const src = data2.columns.map((c) => c.id); const target = column.id; if (src.includes(target)) return; if (isBefore2) api.columnMoveBefore(src, target); else api.columnMoveAfter(src, target); setTimeout(() => { if (!ref.current) return; const parent = ref.current.parentElement; const movedEl = parent?.querySelector( `[data-lng1771-column-id="${src[0]}"]` ); movedEl?.focus(); }, 10); } }); const dragData = dragState.dragData.use(); const data = dragData?.(); const dragIndex = data?.columnIndex ?? -1; const isBefore = columnIndex < dragIndex; const moveProps = api.columnIsMovable(column) ? dragProps : {}; return { moveProps, dropProps, isBefore, canDrop, isOver, dragIndex }; } function DragPlaceholder$1(c) { return /* @__PURE__ */ jsxs("div", { className: "lng1771-header-drag-placeholder--default", children: [ /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "20px", height: "20px", fill: "currentcolor", viewBox: "0 0 256 256", children: /* @__PURE__ */ jsx("path", { d: "M90.34,61.66a8,8,0,0,1,0-11.32l32-32a8,8,0,0,1,11.32,0l32,32a8,8,0,0,1-11.32,11.32L136,43.31V96a8,8,0,0,1-16,0V43.31L101.66,61.66A8,8,0,0,1,90.34,61.66Zm64,132.68L136,212.69V160a8,8,0,0,0-16,0v52.69l-18.34-18.35a8,8,0,0,0-11.32,11.32l32,32a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Zm83.32-72-32-32a8,8,0,0,0-11.32,11.32L212.69,120H160a8,8,0,0,0,0,16h52.69l-18.35,18.34a8,8,0,0,0,11.32,11.32l32-32A8,8,0,0,0,237.66,122.34ZM43.31,136H96a8,8,0,0,0,0-16H43.31l18.35-18.34A8,8,0,0,0,50.34,90.34l-32,32a8,8,0,0,0,0,11.32l32,32a8,8,0,0,0,11.32-11.32Z" }) } ), /* @__PURE__ */ jsx("span", { children: c.column.headerName ?? c.column.id }) ] }); } function useHeaderFocus(api, ref, columnIndex) { useEffect(() => { const sx = api.getState(); const unsub = sx.internal.navigatePosition.watch(() => { const position = sx.internal.navigatePosition.peek(); if (!ref.current || !position || position.kind !== HEADER_CELL_POSITION) return; if (position.columnIndex === columnIndex && !ref.current.contains(document.activeElement)) { api.navigateScrollIntoView(null, columnIndex); ref.current.focus(); } }); return () => unsub(); }, [api, columnIndex, ref]); const onFocus = useEvent(() => { api.getState().internal.navigatePosition.set({ kind: HEADER_CELL_POSITION, columnIndex }); }); return { onFocus }; } function HeaderCell({ api, column, columnIndex, viewportWidth, rowStart, rowEnd, xPositions }) { const isStart = column.pin === "start"; const isEnd = column.pin === "end"; const rtl = api.getState().rtl.use(); const style = useMemo(() => { const x2 = isEnd ? xPositions[columnIndex] - xPositions.at(-1) + viewportWidth : xPositions[columnIndex]; const width = sizeFromCoord(columnIndex, xPositions); const style2 = { transform: getTransform(x2 * (rtl ? -1 : 1), 0), gridRowStart: rowStart, gridRowEnd: rowEnd, width }; if (isStart || isEnd) { style2.insetInlineStart = "0px"; style2.position = "sticky"; style2.zIndex = 2; } return style2; }, [columnIndex, isEnd, isStart, rowEnd, rowStart, rtl, viewportWidth, xPositions]); const Renderer = useHeaderCellRenderer(api, column); const ref = useRef(null); const { moveProps, dropProps, isBefore, isOver, canDrop, dragIndex } = useHeaderMove( api, column, columnIndex, ref ); const sx = api.getState(); sx.sortModel.use(); const events = useHeaderFocus(api, ref, columnIndex); if (api.columnIsEmpty(column)) { return /* @__PURE__ */ jsx( "button", { ...events, ref, onClick: () => { const id = column.id.replace(COLUMN_EMPTY_PREFIX, "").split("|>").slice(0, -1); api.columnGroupToggle(id.join(api.getState().columnGroupIdDelimiter.peek())); }, style, className: "lng1771-header__cell-expand", children: "+" } ); } const sortDir = api.columnSortDirection(column); return /* @__PURE__ */ jsx( "div", { style, ref, role: "columnheader", "data-lng1771-column-id": column.id, "data-lng1771-kind": "header", "aria-colindex": columnIndex + 1, "aria-colspan": 1, "aria-sort": sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : "none", tabIndex: -1, ...moveProps, ...dropProps, ...events, className: clsx( "lng1771-header__cell", isOver && columnIndex !== dragIndex && "lng1771-header__cell--over", isOver && isBefore && "lng1771-header__cell--over-before", isOver && !isBefore && "lng1771-header__cell--over-after", isOver && !canDrop && "lng1771-header__cell--over-not-allowed" ), children: /* @__PURE__ */ jsx(Renderer, { api, column }) } ); } function useHeaderCells(api) { const sx = api.getState(); const visibleColumns = sx.columnsVisible.use(); const xPositions = sx.columnPositions.use(); const bounds = sx.internal.virtBounds.use(); const hierarchy = sx.columnGroupLevels.use(); const startCount = sx.columnVisibleStartCount.use(); const centerCount = sx.columnVisibleCenterCount.use(); const endCount = sx.columnVisibleEndCount.use(); const viewportWidth = sx.internal.viewportInnerWidth.use(); return useMemo(() => { const cells = []; const columnRowCount = hierarchy.length + 1; function handleCell(i) { const column = visibleColumns[i]; let rowStart = columnRowCount; let level = columnRowCount - 2; while (hierarchy[level]?.[i] === null) { rowStart--; level--; } cells.push( /* @__PURE__ */ jsx( HeaderCell, { api, column, columnIndex: i, viewportWidth, xPositions, rowStart, rowEnd: columnRowCount + 1, startCount, centerCount, endCount }, column.id ) ); } for (let i = 0; i < startCount; i++) { handleCell(i); } for (let i = bounds.columnStart; i < bounds.columnEnd; i++) { handleCell(i); } const first = startCount + centerCount; for (let i = first; i < visibleColumns.length; i++) { handleCell(i); } return cells; }, [ api, bounds.columnEnd, bounds.columnStart, centerCount, endCount, hierarchy, startCount, viewportWidth, visibleColumns, xPositions ]); } function useResizeDivider(api, column) { const isResizable = api.columnIsResizable(column); const [active, setActive] = useState(false); const resizeProps = useMemo(() => { if (!isResizable) return {}; const onPointerDown = (e) => { if (e.pointerType === "mouse" && e.button !== 0) return; const startWidth = api.columnVisualWidth(column); const isRtl = api.getState().rtl.peek(); let startX = null; let anim = null; let delta = 0; e.preventDefault(); e.stopPropagation(); document.body.classList.add("lng1771-column-resize-active"); setActive(true); const controller = new AbortController(); document.addEventListener( "pointermove", (ev) => { if (startX === null) { startX = getClientX(ev); return; } const endAdjust = column.pin === "end" ? -1 : 1; const rtlAdjust = isRtl ? -1 : 1; delta = (getClientX(ev) - startX) * endAdjust * rtlAdjust; if (anim) cancelAnimationFrame(anim); anim = requestAnimationFrame(() => { api.getState().internal.columnWidthDeltas.set({ [column.id]: delta }); }); }, { signal: controller.signal } ); window.addEventListener( "pointerup", () => { if (anim) cancelAnimationFrame(anim); setActive(false); document.body.classList.remove("lng1771-column-resize-active"); const newWidth = startWidth + delta; api.columnResize(column, newWidth); api.getState().internal.columnWidthDeltas.set(null); controller.abort(); }, { signal: controller.signal } ); }; return { onPointerDown }; }, [api, column, isResizable]); return { ...resizeProps, active }; } function HeaderDivider({ api, columnIndex, xPositions, viewportWidth, rowStart, rowEnd, column, startCount, centerCount, endCount }) { const isResizable = api.columnIsResizable(column); const isLastStart = startCount > 0 && columnIndex === startCount - 1; const isFirstEnd = endCount > 0 && startCount + centerCount === columnIndex; const isLast = startCount + centerCount + endCount - 1 === columnIndex; const { onPointerDown, active: resizeActive } = useResizeDivider(api, column); const rtl = api.getState().rtl.use(); const style = useMemo(() => { const isStart = column.pin === "start"; const isEnd = column.pin == "end"; const endAdjustment = centerCount + startCount - 1 === columnIndex && endCount > 0 ? 2 : 0; const x2 = isEnd ? xPositions[columnIndex] - xPositions.at(-1) + viewportWidth - 2 : xPositions[columnIndex] + sizeFromCoord(columnIndex, xPositions) - 3 - endAdjustment; const xAdjustment = isLastStart ? 1 : isFirstEnd ? 0 : isLast ? 1 : 0; const style2 = { transform: getTransform((x2 - xAdjustment) * (rtl ? -1 : 1), 0), gridRowStart: rowStart, gridRowEnd: rowEnd }; if (isStart || isEnd) { style2.insetInlineStart = "0px"; style2.position = "sticky"; style2.zIndex = 2; } if (isLast && !isResizable) style2.opacity = 0; return style2; }, [ centerCount, column.pin, columnIndex, endCount, isFirstEnd, isLast, isLastStart, isResizable, rowEnd, rowStart, rtl, startCount, viewportWidth, xPositions ]); return /* @__PURE__ */ jsx( "div", { onPointerDown, "data-resize-active": resizeActive, onDoubleClick: () => { const autosize = api.getState().autosizeDoubleClickHeader.peek(); if (autosize) api.autosizeColumn(column, { includeHeader: true }); }, className: clsx( "lng1771-header__cell-divider", isResizable && "lng1771-header__cell-divider--resizable" ), style, children: /* @__PURE__ */ jsx("div", {}) } ); } function useHeaderDividers(api) { const sx = api.getState(); const xPositions = sx.columnPositions.use(); const hierarchy = sx.columnGroupLevels.use(); const viewportWidth = sx.internal.viewportInnerWidth.use(); const bounds = sx.internal.virtBounds.use(); const startCount = sx.columnVisibleStartCount.use(); const centerCount = sx.columnVisibleCenterCount.use(); const endCount = sx.columnVisibleEndCount.use(); const columns = sx.columnsVisible.use(); return useMemo(() => { const firstEndIndex = xPositions.length - 1 - endCount; const columnRowCount = hierarchy.length + 1; const dividers = []; const indices = Array.from( { length: bounds.columnEnd - bounds.columnStart }, (_, i) => i + bounds.columnStart ); for (let i = startCount - 1; i >= 0; i--) indices.unshift(i); const first = startCount + centerCount; for (let j = first; j < centerCount + startCount + endCount; j++) indices.push(j); for (let i = 0; i < indices.length - endCount; i++) { const columnIndex = indices[i]; const rowStart = getRowStart(hierarchy, startCount, firstEndIndex, columnIndex); const column = columns[columnIndex]; dividers.push( /* @__PURE__ */ jsx( HeaderDivider, { api, column, xPositions, viewportWidth, rowStart, rowEnd: columnRowCount + 1, columnIndex, startCount, centerCount, endCount }, column.id ) ); } for (let i = indices.length - endCount; i < indices.length; i++) { const columnIndex = indices[i]; const rowStart = getRowStart(hierarchy, startCount, firstEndIndex, columnIndex); const column = columns[columnIndex]; dividers.push( /* @__PURE__ */ jsx( HeaderDivider, { api, column, xPositions, viewportWidth, rowStart, rowEnd: columnRowCount + 1, columnIndex, startCount, centerCount, endCount }, column.id ) ); } return dividers; }, [ api, bounds.columnEnd, bounds.columnStart, centerCount, columns, endCount, hierarchy, startCount, viewportWidth, xPositions ]); } function isPartOfGroup(columnIndex, hierarchy) { if (!hierarchy.length) return false; return hierarchy.length > 0 && hierarchy[0][columnIndex] != null; } function getRowStart(hierarchy, startCount, firstEndIndex, columnIndex) { const isFirstEndIndex = columnIndex === firstEndIndex; const isLastStartIndex = columnIndex === startCount - 1 && startCount > 0; const hasGroup = isPartOfGroup(columnIndex, hierarchy); if (isFirstEndIndex || isLastStartIndex || !hasGroup) return 1; let level = 0; while (level < hierarchy.length && hierarchy[level][columnIndex] != null) { level++; } while (hierarchy[level - 1]?.[columnIndex] && hierarchy[level - 1][columnIndex].end - 1 === columnIndex) { level--; } return level + 1; } function useHeaderGroupMove(api, item, pin) { const sx = api.getState(); const gridId = sx.gridId.use(); const visible = sx.columnsVisible.use(); const columns = useMemo(() => { return visible.slice(item.start, item.end); }, [item.end, item.start, visible]); const move = useDraggable({ dragTags: () => [`${gridId}:grid:${pin ?? "none"}`], dragData: () => ({ columns, columnIndex: item.start }), placeholder: () => /* @__PURE__ */ jsx( DragPlaceholder, { cnt: item.end - item.start, label: item.id.split(sx.columnGroupIdDelimiter.peek()).at(-1) } ) }); const isMovable = columns.every((c) => api.columnIsMovable(c)); return { moveProps: isMovable ? move : {} }; } function DragPlaceholder(c) { return /* @__PURE__ */ jsxs("div", { className: "lng1771-drag-placeholder", children: [ c.label, " | moving ", c.cnt, " columns" ] }); } function HeaderGroupCell({ api, groupItem, pin, viewportWidth, rowStart, xPositions }) { const rtl = api.getState().rtl.use(); const style = useMemo(() => { const isStart = pin === "start"; const isEnd = pin == "end"; const width = sizeFromCoord(groupItem.start, xPositions, groupItem.end - groupItem.start); const columnIndex = groupItem.start; const x2 = isEnd ? xPositions[columnIndex] - xPositions.at(-1) + viewportWidth : xPositions[columnIndex]; const style2 = { transform: getTransform(x2 * (rtl ? -1 : 1), 0), gridRowStart: rowStart, gridRowEnd: rowStart + 1, width }; if (isStart || isEnd) { style2.insetInlineStart = "0px"; style2.position = "sticky"; style2.zIndex = 2; } return style2; }, [groupItem.end, groupItem.start, pin, rowStart, rtl, viewportWidth, xPositions]); const headerMove = useHeaderGroupMove(api, groupItem, pin); const ref = useRef(null); const skipRef = useRef(false); useEffect(() => { const sx = api.getState(); const position = sx.internal.navigatePosition; const unsub = position.watch(() => { const pos = position.peek(); if (!pos || !ref.current || pos.kind !== HEADER_GROUP_CELL_POSITION) return; if (groupItem.start === pos.columnStartIndex && groupItem.end === pos.columnEndIndex && pos.hierarchyRowIndex === rowStart - 1 && !ref.current.contains(document.activeElement) && ref.current !== document.activeElement) { api.navigateScrollIntoView(null, pos.columnIndex); skipRef.current = true; ref.current.focus(); } }); return () => unsub(); }, [api, groupItem.end, groupItem.start, rowStart]); const onFocus = useEvent(() => { if (skipRef.current) { skipRef.current = false; return; } api.getState().internal.navigatePosition.set({ kind: HEADER_GROUP_CELL_POSITION, columnStartIndex: groupItem.start, columnEndIndex: groupItem.end, columnIndex: groupItem.start, hierarchyRowIndex: rowStart - 1 }); }); const Renderer = api.getState().columnGroupHeaderRenderer.use() ?? HeaderGroupDefault; return /* @__PURE__ */ jsx( "div", { ref, onFocus, style, "data-lng1771-group-id": groupItem.id, "data-lng1771-kind": "header-group", "aria-colindex": groupItem.start + 1, "aria-colspan": groupItem.end - groupItem.start, role: "columnheader", tabIndex: -1, ...headerMove.moveProps, className: "lng1771-header__group", children: /* @__PURE__ */ jsx(Renderer, { group: groupItem, api }) } ); } function HeaderGroupDefault({ group, api }) { const label = useMemo(() => { const delimiter = api.getState().columnGroupIdDelimiter.peek(); return group.id.split(delimiter).at(-1); }, [api, group.id]); return /* @__PURE__ */ jsxs( "div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", boxSizing: "border-box", justifyContent: "space-between", paddingInline: 12 }, children: [ label, group.isCollapsible && /* @__PURE__ */ jsx(CollapseButton, { onClick: () => api.columnGroupToggle(group.id), children: "-" }) ] } ); } function useHeaderGroupCells(api) { const sx = api.getState(); const bounds = sx.internal.virtBounds.use(); const hierarchy = sx.columnGroupLevels.use(); const xPositions = sx.columnPositions.use(); const startCount = sx.columnVisibleStartCount.use(); const centerCount = sx.columnVisibleCenterCount.use(); const endCount = sx.columnVisibleEndCount.use(); const viewportWidth = sx.internal.viewportInnerWidth.use(); return useMemo(() => { const cells = []; function handleCell(groupItem, levelIndex, pin) { cells.push( /* @__PURE__ */ jsx( HeaderGroupCell, { api, groupItem, pin, rowStart: levelIndex + 1, viewportWidth, centerCount, startCount, endCount, xPositions }, groupItem.occurrenceKey ) ); } for (let level = 0; level < hierarchy.length; level++) { const processedIndices = /* @__PURE__ */ new Set(); const row = hierarchy[level]; for (let i = 0; i < startCount; i++) { const groupItem = row[i]; if (!groupItem) continue; if (!processedIndices.has(i)) handleCell(groupItem, level, "start"); for (let j = groupItem.start; j < groupItem.end; j++) processedIndices.add(j); } for (let i = bounds.columnStart; i < bounds.columnEnd; i++) { const groupItem = row[i]; if (!groupItem) continue; if (!processedIndices.has(i)) handleCell(groupItem, level, null); for (let j = groupItem.start; j < groupItem.end; j++) processedIndices.add(j); } const first = startCount + centerCount; for (let i = first; i < row.length; i++) { const groupItem = row[i]; if (!groupItem) continue; if (!processedIndices.has(i)) handleCell(groupItem, level, "end"); for (let j = groupItem.start; j < groupItem.end; j++) processedIndices.add(j); } } return cells; }, [ api, bounds.columnEnd, bounds.columnStart, centerCount, endCount, hierarchy, startCount, viewportWidth, xPositions ]); } function useFloatingFocus(api, ref, columnIndex) { useEffect(() => { const sx = api.getState(); const unsub = sx.internal.navigatePosition.watch(() => { const position = sx.internal.navigatePosition.peek(); if (!ref.current || !position || position.kind !== FLOATING_CELL_POSITION) return; if (position.columnIndex === columnIndex && !ref.current.contains(document.activeElement)) { api.navigateScrollIntoView(null, columnIndex); ref.current.focus(); } }); return () => unsub(); }, [api, columnIndex, ref]); const onFocus = useEvent(() => { api.getState().internal.navigatePosition.set({ kind: FLOATING_CELL_POSITION, columnIndex }); }); return { onFocus }; } function FloatingCell({ api, viewportWidth, column, xPositions, columnIndex, rowStart, startCount }) { const isStart = column.pin === "start"; const isEnd = column.pin === "end"; const isLastStart = columnIndex === startCount - 1; const rtl = api.getState().rtl.use(); const style = useMemo(() => { const x2 = isEnd ? xPositions[columnIndex] - xPositions.at(-1) + viewportWidth : xPositions[columnIndex]; const width = sizeFromCoord(columnIndex, xPositions); const style2 = { transform: getTransform(x2 * (rtl ? -1 : 1), 0), gridRowStart: rowStart, gridRowEnd: rowStart + 1, width }; if (isStart || isEnd) { style2.insetInlineStart = "0px"; style2.position = "sticky"; style2.zIndex = 2; } return style2; }, [columnIndex, isEnd, isStart, rowStart, rtl, viewportWidth, xPositions]); const sx = api.getState(); const base = sx.columnBase.use(); const rendererKey = column.floatingCellRenderer ?? base.floatingCellRenderer; const renderers = sx.floatingCellRenderers.use(); const Component = useMemo(() => { if (typeof rendererKey === "string") { if (renderers[rendererKey]) throw new Error(`Failed to find floating renderer: ${rendererKey}`); return renderers[rendererKey]; } if (!rendererKey) return () => /* @__PURE__ */ jsx(Fragment, {}); return rendererKey; }, [rendererKey, renderers]); const ref = useRef(null); const events = useFloatingFocus(api, ref, columnIndex); const hide = api.columnIsGridGenerated(column) && !api.columnIsGroupAutoColumn(column); return /* @__PURE__ */ jsx( "div", { ref, style, ...events, role: "columnheader", "data-lng1771-kind": "floating", "data-lng1771-pin": column.pin ?? "center", "data-lng1771-last-start": isLastStart ? true : void 0, "data-lng1771-column-id": column.id, "aria-colindex": columnIndex, "aria-colspan": 1, tabIndex: -1, className: "lng1771-header__cell-floating", children: !hide && /* @__PURE__ */ jsx(Component, { api, column }) } ); } function useFloatingCells(api, enabled) { const sx = api.getState(); const visibleColumns = sx.columnsVisible.use(); const xPositions = sx.columnPositions.use(); const bounds = sx.internal.virtBounds.use(); const hierarchy = sx.columnGroupLevels.use(); const startCount = sx.columnVisibleStartCount.use(); const centerCount = sx.columnVisibleCenterCount.use(); const endCount = sx.columnVisibleEndCount.use(); const viewportWidth = sx.internal.viewportInnerWidth.use(); return useMemo(() => { if (!enabled) return []; const cells = []; const columnRowCount = hierarchy.length + 1; function handleCell(i) { const column = visibleColumns[i]; const rowStart = columnRowCount + 1; cells.push( /* @__PURE__ */ jsx( FloatingCell, { api, column, columnIndex: i, viewportWidth, xPositions, rowStart, startCount, centerCount, endCount }, column.id ) ); } for (let i = 0; i < startCount; i++) { handleCell(i); } for (let i = bounds.columnStart; i < bounds.columnEnd; i++) { handleCell(i); } const first = startCount + centerCount; for (let i = first; i < visibleColumns.length; i++) { handleCell(i); } return cells; }, [ api, bounds.columnEnd, bounds.columnStart, centerCount, enabled, endCount, hierarchy.length, startCount, viewportWidth, visibleColumns, xPositions ]); } function Header() { const { state, api } = useGrid(); const columnHeaderHeight = state.columnHeaderHeight.use(); const columnGroupHeaderHeight = state.columnGroupHeaderHeight.use(); const floatingRowHeight = state.floatingRowHeight.use(); const floatingRowEnabled = state.floatingRowEnabled.use(); const hierarchy = state.columnGroupLevels.use(); const headerGroupCells = useHeaderGroupCells(api); const headerCells = useHeaderCells(api); const headerDividers = useHeaderDividers(api); const floatingCells = useFloatingCells(api, floatingRowEnabled); const gridTemplateRows = useHeaderDisplayGridTemplate( hierarchy.length, columnHeaderHeight, columnGroupHeaderHeight, floatingRowEnabled, floatingRowHeight ); const headerHeightSetting = state.internal.viewportHeaderHeight.use(); const headerHeight = useMemo(() => { return `${headerHeightSetting - (floatingRowEnabled ? floatingRowHeight : 0)}px`; }, [floatingRowEnabled, floatingRowHeight, headerHeightSetting]); return /* @__PURE__ */ jsxs( "div", { role: "row", className: "lng1771-header", style: { gridTemplateRows, "--lng1771-header-height": headerHeight }, children: [ headerGroupCells, headerCells, headerDividers, floatingCells ] } ); } function HeaderContainer({ style }) { const { state } = useGrid(); const [header, setHeader] = useState(null); useIsoEffect(() => { if (!header) return; const resize = new IsoResizeObserver(() => { if (!header) return; const prec = getPreciseElementDimensions(header); state.internal.viewportHeaderHeight.set(prec.outerHeight); }); resize.observe(header); return () => resize.disconnect(); }, [header]); return /* @__PURE__ */ jsx("div", { ref: setHeader, className: "lng1771-header-container", style, children: /* @__PURE__ */ jsx(Header, {}) }); } function RowDetail({ api, row, rowPin, yPositions, rowIndex, height }) { const sx = api.getState(); const width = sx.internal.viewportInnerWidth.use(); const Renderer = sx.rowDetailRenderer.use() ?? RowDetailDefault; const style = useMemo(() => { const isTop = rowPin === "top"; const isBot = rowPin === "bottom"; const rowCount = sx.internal.rowCount.peek(); const rowTopCount = sx.internal.rowTopCount.peek(); const rowBotCount = sx.internal.rowBottomCount.peek(); const firstBotIndex = rowCount - rowBotCount; const offset = sizeFromCoord(rowIndex, yPositions) - height; const y2 = isBot ? yPositions[rowIndex] - yPositions[firstBotIndex] : isTop ? yPositions[rowIndex] : yPositions[rowIndex] - yPositions[rowTopCount]; const transform = getTransform(0, y2 + offset); return { width, height, transform }; }, [ height, rowIndex, rowPin, sx.internal.rowBottomCount, sx.internal.rowCount, sx.internal.rowTopCount, width, yPositions ]); return /* @__PURE__ */ jsx("div", { style, className: "lng1771-row-detail", children: /* @__PURE__ */ jsx(Renderer, { api, row }) }); } function RowDetailDefault() { return /* @__PURE__ */ jsx("div", { children: "Not Implemented" }); } function RowDragIndicator({ section }) { const { state } = useGrid(); const rowIndex = state.internal.rowDragOverIndex.use(); const dragIndex = state.internal.rowDragStartIndex.use(); const yPositions = state.internal.rowPositions.use(); const width = state.internal.viewportInnerWidth.use(); const topCount = state.internal.rowTopCount.use(); const bottomCount = state.internal.rowBottomCount.use(); const rowCount = state.internal.rowCount.use(); const isBefore = rowIndex < dragIndex; if (rowIndex === -1 || rowIndex == null) return null; if (section === "top" && rowIndex > topCount) return null; if (section === "center" && rowIndex < topCount || rowIndex >= rowCount - bottomCount) return null; if (section === "bottom" && rowIndex < rowCount - bottomCount) return null; const firstBotIndex = rowCount - bottomCount; const height = sizeFromCoord(rowIndex, yPositions); const y2 = section === "bottom" ? yPositions[rowIndex] - yPositions[firstBotIndex] : section === "top" ? yPositions[rowIndex] : yPositions[rowIndex] - yPositions[topCount]; return /* @__PURE__ */ jsx( "div", { style: { transform: getTransform(0, y2 + (isBefore ? 0 : height)), width }, className: "lng1771-row-drag-indicator" } ); } function Rows({ width, ...els }) { const { state, api } = useGrid(); const layout = state.internal.virtLayout.use(); const xPositions = state.columnPositions.use(); const yPositions = state.internal.rowPositions.use(); const columns = state.columnsVisible.use(); const refreshKey = state.internal.rowRefreshCount.use(); const headerHeight = state.internal.viewportHeaderHeight.use(); const rowCount = state.internal.rowCount.use(); const topCount = state.internal.rowTopCount.use(); const botCount = state.internal.rowBottomCount.use(); const topHeight = yPositions[topCount]; const botHeight = yPositions.at(-1) - yPositions[rowCount - botCount]; const detailHeight = state.internal.rowDetailHeight.use(); const [fullWidthCache, cellCache] = useMemo(() => { return [{}, {}]; }, [botCount, columns, headerHeight, refreshKey, rowCount, topCount, xPositions, yPositions]); const firstBotIndex = rowCount - botCount; const paginate = state.paginate.use(); const currentPage = state.paginateCurrentPage.use(); const [top, center, bottom] = useMemo(() => { const top2 = []; const center2 = []; const bottom2 = []; let paginateOffset = 0; if (paginate) { const [rowStart] = api.paginateRowStartAndEndForPage(currentPage); paginateOffset = yPositions[rowStart]; } for (const [rowIndex, cells] of layout) { if (rowIndex >= rowCount) continue; const isTop = rowIndex < topCount; const isBot = rowIndex >= firstBotIndex; const isCenter = !isTop && !isBot; const place = isCenter ? center2 : isTop ? top2 : bottom2; const row = api.rowByIndex(rowIndex); if (!row) continue; let i = 0; while (i < cells.length) { const encoding = cells[i]; if (encoding === FULL_ENCODING) { fullWidthCache[rowIndex] ??= /* @__PURE__ */ jsx( CellFullWidth, { api, row, colCount: columns.length, rowPin: rowIndex < topCount ? "top" : rowIndex >= firstBotIndex ? "bottom" : null, rowIndex, yPositions, paginateOffset }, `${rowIndex}-full` ); place.push(fullWidthCache[rowIndex]); i++; } else if (encoding === END_ENCODING) { break; } else { const rowIndex2 = cells[i++]; const rowSpan = cells[i++]; const colIndex = cells[i++]; const colSpan = cells[i++]; cellCache[rowIndex2] ??= {}; cellCache[rowIndex2][colIndex] = /* @__PURE__ */ jsx( Cell, { api, column: columns[colIndex], rowIndex: rowIndex2, rowSpan, colSpan, rowPin: rowIndex2 < topCount ? "top" : rowIndex2 >= firstBotIndex ? "bottom" : null, rowNode: row, columnIndex: colIndex, yPositions, xPositions, paginateOffset }, `r${rowIndex2}-c${colIndex}` ); place.push(cellCache[rowIndex2][colIndex]); } } const rowDetailHeight = detailHeight(rowIndex); if (rowDetailHeight > 0) { place.push( /* @__PURE__ */ jsx( RowDetail, { api, height: rowDetailHeight, row, rowPin: rowIndex < topCount ? "top" : rowIndex >= firstBotIndex ? "bottom" : null, rowIndex, yPositions } ) ); } } return [top2, center2, bottom2]; }, [ api, cellCache, columns, currentPage, detailHeight, firstBotIndex, fullWidthCache, layout, paginate, rowCount, topCount, xPositions, yPositions ]); const viewportWidth = state.internal.viewportInnerWidth.use(); const endCount = state.columnVisibleEndCount.use(); const minWidth = Math.max(endCount > 0 ? viewportWidth : 0, width); return /* @__PURE__ */ jsxs(Fragment, { children: [ topHeight > 0 && /* @__PURE__ */ jsxs( "div", { style: { width, minWidth, top: headerHeight, height: topHeight, minHeight: topHeight, maxHeight: topHeight }, className: "lng1771-rows__top-section", children: [ top, /* @__PURE__ */ jsx(RowDragIndicator, { section: "top" }), /* @__PURE__ */ jsx(els.top, {}) ] } ), /* @__PURE__ */ jsxs( "div", { style: { width, minWidth }, className: "lng1771-rows__center-section", children: [ center, /* @__PURE__ */ jsx(RowDragIndicator, { section: "center" }), /* @__PURE__ */ jsx(els.center, {}) ] } ), botHeight > 0 && /* @__PURE__ */ jsxs( "div", { style: { bottom: 0, width, minWidth, height: botHeight, minHeight: botHeight, maxHeight: botHeight }, className: "lng1771-rows__bottom-section", children: [ bottom, /* @__PURE__ */ jsx(RowDragIndicator, { section: "bottom" }), /* @__PURE__ */ jsx(els.bottom, {}) ] } ) ] }); } function RowContainer({ totalHeight, totalWidth, children }) { const { api, state } = useGrid(); const gridId = state.gridId.use(); const { onDragOver, onDrop } = useDroppable({ tags: [`${gridId}:row-drag`], onDrop: (p2) => { const overIndex = state.internal.rowDragOverIndex.peek(); const data = p2.getData(); if (!data?.rows || !data?.api) return; const isExternal = data.api !== api; const additional = isExternal ? { externalGridApi: data.api, isExternal: true } : {}; api.eventFire("onRowDragDrop", { api, event: p2.event, overIndex, rows: data.rows, ...additional }); } }); const columns = state.columnsVisible.use(); if (columns.length === 0) return /* @__PURE__ */ jsx(Fragment, {}); return /* @__PURE__ */ jsx( "div", { style: { width: totalWidth, minHeight: totalHeight }, onDrop, onDragOver, className: "lng1771-row-container", children } ); } function NavigationDriver() { const { state, api } = useGrid(); const viewport = state.internal.viewport.use(); const rtl = state.rtl.use(); useEffect(() => { if (!viewport) return; const controller = new AbortController(); viewport.addEventListener( "keydown", (ev) => { const key = ev.key; const startDir = rtl ? "ArrowRight" : "ArrowLeft"; const endDir = rtl ? "ArrowLeft" : "ArrowRight"; const position = state.internal.navigatePosition.peek(); const activeEdit = state.internal.cellEditActiveLocation.peek(); if (activeEdit || ev.shiftKey) return; if (document.activeElement === viewport && (key === "ArrowDown" || key === endDir)) { if (state.columnsVisible.peek().length) { state.internal.navigatePosition.set({ kind: HEADER_CELL_POSITION, columnIndex: 0 }); } ev.preventDefault(); ev.stopPropagation(); } if (!position) return; let handled = false; const meta = ev.ctrlKey || ev.metaKey; if (key === "PageUp") { api.navigatePageUp(); handled = true; } else if (key === "PageDown") { api.navigatePageDown(); handled = true; } else if (key === "Home") { api.navigateToTop(); handled = true; } else if (key === "End") { api.navigateToBottom(); handled = true; } else if (key === "ArrowUp") { if (meta) { api.navigateToTop(); } else { api.navigateUp(); } handled = true; } else if (key === "ArrowDown") { if (meta) { api.navigateToBottom(); } else { api.navigateDown(); } handled = true; } else if (key === startDir) { if (meta) { api.navigateToStart(); } else { api.navigatePrev(); } handled = true; } else if (key === endDir) { if (meta) { api.navigateToEnd(); } else { api.navigateNext(); } handled = true; } if (handled) { ev.preventDefault(); ev.stopPropagation(); } }, { signal: controller.signal } ); const unsub = state.internal.navigatePosition.watch(() => { const position = state.internal.navigatePosition.peek(); if (!position) return; const rowIndex = "rowIndex" in position ? position.rowIndex : null; const columnIndex = position.columnIndex; api.navigateScrollIntoView(rowIndex, columnIndex); }); viewport.addEventListener( "focusout", () => { setTimeout(() => { if (viewport.contains(document.activeElement)) { return; } api.getState().internal.navigatePosition.set(null); }, 100); }, { signal: controller.signal } ); return () => { controller.abort(); unsub(); }; }, [ api, rtl, state.columnsVisible, state.internal.cellEditActiveLocation, state.internal.navigatePosition, viewport ]); return /* @__PURE__ */ jsx(Fragment, {}); } function cellEditLocation(c) { return `r${c.rowIndex}-c${c.columnIndex}`; } function handleBeginCellEditFromEvent(api, event) { if (event.button !== 0) return; const clientY = getClientY(event); const clientX = getClientX(event); const rowIndex = getHoveredRowIndex(api, clientY); const columnIndex = getHoveredColumnIndex(api, clientX); if (rowIndex == null || columnIndex == null) return; const sx = api.getState(); const active = sx.internal.cellEditActiveEdits.peek(); const l = { rowIndex, columnIndex }; const key = cellEditLocation(l); if (active.has(key)) return; api.cellEditBegin(l, true); } function CellEditDriver() { const { state, api } = useGrid(); const viewport = state.internal.viewport.use(); const cellEditActivator = state.cellEditPointerActivator.use(); useEffect(() => { if (!viewport) return; const controller = new AbortController(); const signal2 = controller.signal; if (cellEditActivator === "single-click") { viewport.addEventListener("pointerdown", (ev) => handleBeginCellEditFromEvent(api, ev), { signal: signal2 }); } if (cellEditActivator === "double-click") { viewport.addEventListener( "dblclick", (ev) => { if (state.internal.cellEditActiveEdits.peek().size > 0) return; handleBeginCellEditFromEvent(api, ev); }, { signal: signal2 } ); } return () => controller.abort(); }, [ api, cellEditActivator, state.columnsVisible, state.internal.cellEditActiveEdits, state.internal.cellEditActiveLocation, viewport ]); return /* @__PURE__ */ jsx(Fragment, {}); } function RowHoverDriver() { const s3 = useGrid(); const gridId = s3.state.gridId.use(); const hoveredRow = s3.state.internal.hoveredRow.use(); if (hoveredRow == null) return; return /* @__PURE__ */ jsx("style", { children: ` #${gridId} > div > div > [aria-rowindex="${hoveredRow + 1}"] { background-color: var(--lng1771-gray-10); } ` }); } function Viewport({ children, ...els }) { const { state } = useGrid(); const onSizeChange = useEvent((size) => { state.internal.viewportInnerHeight.set(size.innerHeight); state.internal.viewportInnerWidth.set(size.innerWidth); state.internal.viewportOuterWidth.set(size.outerWidth); state.internal.viewportOuterHeight.set(size.outerHeight); const el = state.internal.viewport.peek(); if (el) { state.internal.viewportXScroll.set(Math.abs(el.scrollLeft)); state.internal.viewportYScroll.set(Math.abs(el.scrollTop)); state.internal.viewportInnerWidth.set(el.clientWidth); state.internal.viewportInnerHeight.set(el.clientHeight); } }); const onInit = useEvent((_, size) => { onSizeChange(size); }); const onScroll = useEvent(() => { const viewport = state.internal.viewport.peek(); if (!viewport) return; state.internal.viewportXScroll.set(Math.abs(viewport.scrollLeft)); state.internal.viewportYScroll.set(Math.abs(viewport.scrollTop)); }); const ref = useEvent((el) => { state.internal.viewport.set(el); }); const paginate = state.paginate.use(); const totalHeight = paginate ? void 0 : state.internal.rowPositions.use().at(-1); const totalWidth = state.columnPositions.use().at(-1); const rtl = state.rtl.use(); const grid = state.gridId.use(); return /* @__PURE__ */ jsxs( Sizer, { onInit, onSizeChange, onScroll, elRef: ref, style: { direction: rtl ? "rtl" : void 0 }, id: grid, className: "lng1771-viewport", children: [ /* @__PURE__ */ jsx(HeaderContainer, { style: { width: totalWidth } }), /* @__PURE__ */ jsx(RowContainer, { totalHeight, totalWidth, children: /* @__PURE__ */ jsx(Rows, { width: totalWidth, ...els }) }), /* @__PURE__ */ jsx(NavigationDriver, {}), /* @__PURE__ */ jsx(CellEditDriver, {}), /* @__PURE__ */ jsx(RowHoverDriver, {}), children ] } ); } function getEditRows(locations, predicate) { const validLocations = Object.groupBy( [...locations].filter(([_, l]) => predicate(l)).map(([_, l]) => l), (l) => l.rowIndex ); return Object.entries(validLocations); } function TextEditor({ value, setValue, isValid, column }) { const opts = column.cellEditParams ?? {}; return /* @__PURE__ */ jsx( Input, { error: !isValid, maxLength: opts.maxLength, className: "lng1771-cell__edit-input",