UNPKG

@1771technologies/lytenyte-pro

Version:

1,039 lines (1,038 loc) 35 kB
import { jsxs, jsx } from "react/jsx-runtime"; import React__default, { useRef, useCallback, useEffect, memo, useMemo, createContext, useContext } from "react"; import { clsx, sizeFromCoord, getClientY, getClientX, getRelativeXPosition } from "@1771technologies/js-utils"; import { refCompat, useEvent } from "@1771technologies/react-utils"; import { getHoveredRowIndex } from "@1771technologies/grid-core"; import { useDraggable } from "@1771technologies/react-dragon"; const ROW_LEAF_KIND = 1; const ROW_GROUP_KIND = 2; const COLUMN_GROUP_ID_DELIMITER = "-->"; const ROW_DEFAULT_PATH_SEPARATOR = "-->"; const COLUMN_EMPTY_PREFIX = "lytenyte-empty:"; const COLUMN_MARKER_ID = "lytenyte-marker-column"; const GROUP_COLUMN_PREFIX = "lytenyte-group-column:"; const GROUP_COLUMN_MULTI_PREFIX = `${GROUP_COLUMN_PREFIX}:multi:`; const GROUP_COLUMN_SINGLE_ID = `${GROUP_COLUMN_PREFIX}:single`; const GROUP_COLUMN_TREE_DATA = `${GROUP_COLUMN_PREFIX}:tree`; const COLUMN_GROUP_HEADER_HEIGHT = 28; const COLUMN_HEADER_HEIGHT = 32; const COLUMN_SCAN_DISTANCE = 20; const PAGINATE_PAGE_SIZE = 50; const ROW_BLANK_GROUP_KEY = "lytenyte-blank"; const ROW_HEIGHT = 32; const ROW_DETAIL_HEIGHT = 300; const ROW_UPDATE_STACK_SIZE = 20; const DEFAULT_MAX_WIDTH = 1e3; const DEFAULT_MIN_WIDTH = 80; const DEFAULT_WIDTH = 150; const DEFAULT_SORT_CYCLE = ["asc", "desc", null]; const GRID_CELL_POSITION = 1; const FULL_WIDTH_POSITION = 2; const HEADER_CELL_POSITION = 3; const HEADER_GROUP_CELL_POSITION = 4; const FLOATING_CELL_POSITION = 5; const FULL_ENCODING = -2; const END_ENCODING = -1; const transformCache = {}; function getTransform(x, y) { transformCache[x] ??= {}; transformCache[x][y] ??= `translate3d(${x}px, ${y}px, 0px)`; return transformCache[x][y]; } function Checkbox({ isDisabled, isChecked, isDeterminate, onCheckChange, isLoading, ...props }) { return /* @__PURE__ */ jsxs("div", { className: clsx("lng1771-checkbox", !isDisabled && "lng1771-checkbox--disabled"), children: [ /* @__PURE__ */ jsx( "input", { ...props, className: "lng1771-checkbox__input", checked: isChecked, onPointerDownCapture: (e) => { e.stopPropagation(); e.preventDefault(); }, onChange: (e) => { onCheckChange?.(e.target.checked, e); }, type: "checkbox", disabled: isDisabled } ), /* @__PURE__ */ jsxs( "div", { className: clsx( "lng1771-checkbox__mark", isDisabled && "lng1771-checkbox__mark--disabled", !isDisabled && isChecked && "lng1771-checkbox__mark--checked", isLoading && "lng1771-checkbox__mark--loading" ), children: [ isChecked && !isDeterminate && /* @__PURE__ */ jsx(CheckMark, {}), isChecked && isDeterminate && /* @__PURE__ */ jsx(CheckIndeterminate, {}), !isChecked && isDisabled && /* @__PURE__ */ jsx(CheckboxDisabled, {}) ] } ) ] }); } function CheckMark() { return /* @__PURE__ */ jsx("svg", { width: "12", height: "9", viewBox: "0 0 11 9", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx( "path", { d: "M1.38721 4.34783C2.92567 5.26087 4.15644 7.08696 4.46413 8C6.00259 4.34783 8.15644 1.91304 9.38721 1", stroke: "currentcolor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" } ) }); } function CheckIndeterminate() { return /* @__PURE__ */ jsx("svg", { width: "12", height: "2", viewBox: "0 0 11 2", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx( "path", { d: "M1.38721 1H9.38721", stroke: "currentcolor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" } ) }); } function CheckboxDisabled() { return /* @__PURE__ */ jsx("svg", { width: "15", height: "14", viewBox: "0 0 15 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx( "path", { fillRule: "evenodd", clipRule: "evenodd", d: "M0.720459 6.99967C0.720459 10.6812 3.70564 13.6663 7.38713 13.6663C11.0686 13.6663 14.0538 10.6812 14.0538 6.99967C14.0538 3.31745 11.0686 0.333008 7.38713 0.333008C3.70564 0.333008 0.720459 3.31745 0.720459 6.99967ZM4.29527 2.84412C5.15972 2.20042 6.22713 1.81449 7.38713 1.81449C10.2508 1.81449 12.5723 4.13597 12.5723 6.99967C12.5723 8.16042 12.1871 9.22782 11.5427 10.0915L4.29527 2.84412ZM2.20194 6.99967C2.20194 5.83079 2.59379 4.75597 3.24564 3.8893L10.4975 11.1412C9.63009 11.7937 8.55527 12.1849 7.38713 12.1849C4.52342 12.1849 2.20194 9.86338 2.20194 6.99967Z", fill: "currentcolor" } ) }); } const ButtonImpl = ({ buttonRef, ...props }) => { return /* @__PURE__ */ jsx( "button", { tabIndex: -1, ...props, ref: buttonRef, className: clsx("lng1771-icon-button", props.className), children: props.children } ); }; const GridButton = refCompat(ButtonImpl, "Button"); function CollapseButton(props) { return /* @__PURE__ */ jsx(GridButton, { ...props, children: "-" }); } function ExpandButton(props) { return /* @__PURE__ */ jsx(GridButton, { ...props, children: "+" }); } function useCellFullWidthFocus(api, rowIndex) { const ref = useRef(null); const skipRef = useRef(false); const onFocus = useEvent(() => { if (skipRef.current) { skipRef.current = false; return; } api.getState().internal.navigatePosition.set({ kind: FULL_WIDTH_POSITION, columnIndex: 0, rowIndex }); }); const tryFocus = useEvent((element) => { const sx = api.getState(); const position = sx.internal.navigatePosition.peek(); if (!element || !position || position.kind !== FULL_WIDTH_POSITION) return; const posRow = position.rowIndex; if (rowIndex === posRow && !element.contains(document.activeElement) && element !== document.activeElement) { api.navigateScrollIntoView(posRow); skipRef.current = true; element.focus(); } }); const handleRef = useCallback( (el) => { tryFocus(el); ref.current = el; }, [tryFocus] ); useEffect(() => { const sx = api.getState(); const unsub = sx.internal.navigatePosition.watch(() => { tryFocus(ref.current); }, false); return () => { unsub(); }; }, [api, ref, rowIndex, tryFocus]); return { handleRef, onFocus }; } function handleRowSelection(api, row, bulk, meta, ignoreActivator = false, expectedActivator = "single-click") { const sx = api.getState(); const mode = sx.rowSelectionMode.peek(); const activator = sx.rowSelectionPointerActivator.peek(); if (mode === "none" || activator !== expectedActivator && !ignoreActivator) return; const canSelect = canSelectRow(api, row); if (!canSelect) return; const isSelected = sx.rowSelectionSelectedIds.peek().has(row.id); if (mode === "single") { api.rowSelectionClear(); if (!isSelected) api.rowSelectionSelect([row.id]); return; } const pivotIndex = sx.internal.rowSelectionPivotIndex.peek(); const lastWasDeselect = sx.internal.rowSelectionLastWasDeselect.peek(); const childrenAsWell = sx.rowSelectionSelectChildren.peek(); const rowIndex = row.rowIndex; if (bulk && pivotIndex != null) { const idsToChange = []; const start = Math.min(rowIndex, pivotIndex); const end = Math.max(rowIndex, pivotIndex) + 1; for (let i = start; i < end; i++) { const row2 = api.rowByIndex(i); if (!row2 || !canSelectRow(api, row2)) continue; idsToChange.push(row2.id); } if (lastWasDeselect) api.rowSelectionDeselect(idsToChange, childrenAsWell); else api.rowSelectionSelect(idsToChange, childrenAsWell); return; } const additive = meta || sx.rowSelectionMultiSelectOnClick.peek(); if (additive) { if (isSelected) api.rowSelectionDeselect([row.id], sx.rowSelectionSelectChildren.peek()); else api.rowSelectionSelect([row.id], sx.rowSelectionSelectChildren.peek()); sx.internal.rowSelectionPivotIndex.set(rowIndex); sx.internal.rowSelectionLastWasDeselect.set(isSelected); return; } sx.internal.rowSelectionPivotIndex.set(rowIndex); sx.internal.rowSelectionLastWasDeselect.set(isSelected); api.rowSelectionClear(); if (!isSelected) api.rowSelectionSelect([row.id]); } function canSelectRow(api, row) { const predicate = api.getState().rowSelectionPredicate.peek(); const canSelect = predicate === "all" ? true : predicate === "group-only" ? api.rowIsGroup(row) : predicate === "leaf-only" ? api.rowIsLeaf(row) : predicate({ row, api }); return canSelect; } function useFullWidthEvents(api, row) { const onClick = useEvent((event) => { handleRowSelection( api, row, event.shiftKey, event.metaKey || event.ctrlKey, false, "single-click" ); }); const onDoubleClick = useEvent((event) => { handleRowSelection( api, row, event.shiftKey, event.metaKey || event.ctrlKey, false, "double-click" ); }); return { onClick, onDoubleClick }; } function CellFullWidthImpl({ row, rowIndex, rowPin, colCount, yPositions, api, paginateOffset }) { const sx = api.getState(); const width = sx.internal.viewportInnerWidth.use(); const cx = useMemo(() => { const isTop = rowPin === "top"; const isBot = rowPin === "bottom"; const height = sizeFromCoord(rowIndex, yPositions); const rowCount = sx.internal.rowCount.peek(); const rowTopCount = sx.internal.rowTopCount.peek(); const rowBotCount = sx.internal.rowBottomCount.peek(); const firstBotIndex = rowCount - rowBotCount; const y = isBot ? yPositions[rowIndex] - yPositions[firstBotIndex] : isTop ? yPositions[rowIndex] : yPositions[rowIndex] - yPositions[rowTopCount] - paginateOffset; const transform = getTransform(0, y); return { style: { transform, height } }; }, [ paginateOffset, rowIndex, rowPin, sx.internal.rowBottomCount, sx.internal.rowCount, sx.internal.rowTopCount, yPositions ]); const Renderer = sx.rowFullWidthRenderer.use() ?? DefaultRenderer; const selected = sx.rowSelectionSelectedIds.use(); const isSelected = selected.has(row.id); const { handleRef, onFocus } = useCellFullWidthFocus(api, rowIndex); const events = useFullWidthEvents(api, row); return /* @__PURE__ */ jsx( "div", { role: "gridcell", ref: handleRef, "aria-colindex": 1, "aria-colspan": colCount, "aria-rowindex": rowIndex + 1, "aria-rowspan": 1, "data-lng1771-rowid": row.id, "data-lng1771-rowindex": rowIndex, tabIndex: -1, style: { width, ...cx.style }, ...events, onFocus, className: clsx( "lng1771-cell__full-width", rowIndex % 2 === 1 && "lng1771-cell__full-width--alternate", isSelected && "lng1771-cell__full-width--selected" ), children: /* @__PURE__ */ jsx(Renderer, { api, row }) } ); } const CellFullWidth = memo(CellFullWidthImpl); function DefaultRenderer() { return /* @__PURE__ */ jsx("div", { children: "Not Implemented" }); } function useCellStyle(api, xPositions, yPositions, columnIndex, rowIndex, columnSpan, rowSpan, column, rowPin, rowId, paginateOffset) { const sx = api.getState(); const vpWidth = sx.internal.viewportInnerWidth.use(); const rowDetailHeight = sx.internal.rowDetailHeight.use(); const height = sizeFromCoord(rowIndex, yPositions, rowSpan) - rowDetailHeight(rowIndex); const width = sizeFromCoord(columnIndex, xPositions, columnSpan); const selectedIds = sx.rowSelectionSelectedIds.use(); const rtl = sx.rtl.use(); const styleAndCss = useMemo(() => { const isStart = column.pin === "start"; const isEnd = column.pin == "end"; const isTop = rowPin === "top"; const isBot = rowPin === "bottom"; const isLastStart = sx.columnVisibleStartCount.peek() - 1 === columnIndex && columnIndex > 0; const isFirstEnd = sx.columnVisibleCenterCount.peek() + sx.columnVisibleStartCount.peek() === columnIndex; const rowCount = sx.internal.rowCount.peek(); const rowTopCount = sx.internal.rowTopCount.peek(); const rowBotCount = sx.internal.rowBottomCount.peek(); const firstBotIndex = rowCount - rowBotCount; const x = isEnd ? xPositions[columnIndex] - xPositions.at(-1) + vpWidth : xPositions[columnIndex]; const y = isBot ? yPositions[rowIndex] - yPositions[firstBotIndex] : isTop ? yPositions[rowIndex] : yPositions[rowIndex] - yPositions[rowTopCount] - paginateOffset; const transform = getTransform(x * (rtl ? -1 : 1), y); const style = { height, width, transform }; if (isStart || isEnd) { style.insetInlineStart = "0px"; style.position = "sticky"; style.zIndex = 2; } if (isTop || isBot) { style.position = "sticky"; style.top = "0px"; style.zIndex = column.pin === "start" ? 4 : 3; } const selected = selectedIds.has(rowId); const className = clsx( selected && "lng1771-cell--selected", isLastStart && "lng1771-cell--last-start", isFirstEnd && "lng1771-cell--first-end" ); return { style, className }; }, [ column.pin, columnIndex, height, paginateOffset, rowId, rowIndex, rowPin, rtl, selectedIds, sx.columnVisibleCenterCount, sx.columnVisibleStartCount, sx.internal.rowBottomCount, sx.internal.rowCount, sx.internal.rowTopCount, vpWidth, width, xPositions, yPositions ]); return styleAndCss; } function CellRendererDefault({ api, row, column }) { const field = api.columnField(row, column); return /* @__PURE__ */ jsx( "div", { style: { width: "100%", height: "100%", boxSizing: "border-box", display: "flex", alignItems: "center", paddingInline: 12, overflow: "hidden" }, children: /* @__PURE__ */ jsx( "span", { style: { width: "100%", textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden" }, children: String(field ?? "") } ) } ); } function useDragControl(api, row) { const draggable = useDraggable({ dragData: () => { const sx = api.getState(); const rows = sx.rowDragMultiRow.peek() ? [row, ...api.rowSelectionGetSelected().filter((r) => r !== row)] : [row]; return { rows, api }; }, dragTags: () => { const sx = api.getState(); const id = sx.gridId.peek(); const externalGrids = sx.rowDragExternalGrids.peek(); const externalIds = externalGrids.map((c) => c.getState().gridId.peek()); return [id, ...externalIds].map((c) => `${c}:row-drag`); }, onDragStart: (ev) => { const controller = new AbortController(); const startY = getClientY(ev.event); const updates = [startY, startY]; let anim = null; const sx = api.getState(); sx.internal.rowDragStartIndex.set(row.rowIndex); const rows = sx.rowDragMultiRow.peek() ? [row, ...api.rowSelectionGetSelected().filter((r) => r !== row)] : [row]; const ref = { event: ev.event, api, rows, overIndex: -1 }; api.eventFire("onRowDragStart", ref); const externalGrids = sx.rowDragExternalGrids.peek(); const apis = [api, ...externalGrids]; document.addEventListener( "drag", (ev2) => { const clientX = getClientX(ev2); const clientY = getClientY(ev2); ev2.preventDefault(); [updates[0], updates[1]] = [updates[1], clientY]; if (updates[0] === clientY) return; if (anim) cancelAnimationFrame(anim); anim = requestAnimationFrame(() => { for (let i = 0; i < apis.length; i++) { const api2 = apis[i]; const sx2 = api2.getState(); const viewport = sx2.internal.viewport.peek(); if (!viewport) continue; const relative = getRelativeXPosition(viewport, clientX); const isOutOfBounds = relative.left < 0 || relative.right < 0; const rowDragOverIndex = isOutOfBounds ? null : getHoveredRowIndex(api2, updates[0]); ref.event = ev2; if (rowDragOverIndex != null) { sx2.internal.rowDragOverIndex.set(rowDragOverIndex); ref.overIndex = rowDragOverIndex; api2.eventFire("onRowDragMove", ref); } else { sx2.internal.rowDragOverIndex.set(-1); ref.overIndex = -1; api2.eventFire("onRowDragMove", ref); } } }); }, { signal: controller.signal } ); window.addEventListener("dragend", (event) => { controller.abort(); const overIndex = sx.internal.rowDragOverIndex.peek(); ref.overIndex = overIndex; ref.event = event; const isValid = event.dataTransfer?.dropEffect !== "none"; if (!isValid) api.eventFire("onRowDragCancel", ref); else api.eventFire("onRowDragEnd", ref); for (const api2 of apis) { const sx2 = api2.getState(); sx2.internal.rowDragOverIndex.set(-1); sx2.internal.rowDragStartIndex.set(-1); } }); }, placeholder: () => { const sx = api.getState(); const rows = sx.rowDragMultiRow.peek() ? [row, ...api.rowSelectionGetSelected().filter((r) => r !== row)] : [row]; return /* @__PURE__ */ jsx(DragPlaceholder, { rows }); } }); return draggable; } const DragPlaceholder = (p) => { const label = p.rows.length === 1 ? `Moving row ${p.rows[0].rowIndex}` : `Moving ${p.rows.length} rows`; return /* @__PURE__ */ jsx("div", { className: "lng1771-drag-placeholder", children: label }); }; function DragButton({ api, row }) { const draggable = useDragControl(api, row); return ( // We need to stop propagation on capture to prevent other drag events like // range cell selection from occurring. /* @__PURE__ */ jsx(GridButton, { ...draggable, onPointerDownCapture: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(DragDots, { width: 10, height: 10 }) }) ); } const DragDots = (p) => { return /* @__PURE__ */ jsxs("svg", { width: "8", height: "12", viewBox: "0 0 8 12", fill: "currentcolor", ...p, children: [ /* @__PURE__ */ jsx("circle", { cx: "1.75", cy: "1.7146", r: "1.25" }), /* @__PURE__ */ jsx("circle", { cx: "1.75", cy: "6.2146", r: "1.25" }), /* @__PURE__ */ jsx("circle", { cx: "1.75", cy: "10.7146", r: "1.25" }), /* @__PURE__ */ jsx("circle", { cx: "6.25", cy: "1.7146", r: "1.25" }), /* @__PURE__ */ jsx("circle", { cx: "6.25", cy: "6.2146", r: "1.25" }), /* @__PURE__ */ jsx("circle", { cx: "6.25", cy: "10.7146", r: "1.25" }) ] }); }; function SelectionCheckbox({ api, row }) { const sx = api.getState(); const isSelect = sx.rowSelectionPredicate.use(); const isSelectable = useMemo(() => { return isSelect === "all" ? true : isSelect === "leaf-only" ? api.rowIsLeaf(row) : isSelect === "group-only" ? api.rowIsGroup(row) : isSelect({ api, row }); }, [api, isSelect, row]); const displayMode = sx.rowSelectionCheckbox.use(); const selectedIds = sx.rowSelectionSelectedIds.use(); if (displayMode === "hide" || !isSelectable && displayMode === "hide-for-disabled") return null; const isChecked = selectedIds.has(row.id); const isIndeterminate = api.rowSelectionIsIndeterminate(row.id); return /* @__PURE__ */ jsx( Checkbox, { tabIndex: -1, isChecked: isChecked || isIndeterminate, isDeterminate: isIndeterminate, isDisabled: !isSelectable, onClick: (event) => { event.preventDefault(); event.stopPropagation(); handleRowSelection(api, row, event.shiftKey, true, true); } } ); } function CellMarkerRenderer({ row, api }) { const doesRowHaveDetail = api.rowDetailRowPredicate(row.id); const isExpanded = api.rowDetailIsExpanded(row.id); const isRowDraggable = api.rowIsDraggable(row.id); const toggleDetail = useEvent(() => api.rowDetailToggle(row.id)); const rowSelectionEnabled = api.getState().rowSelectionMode.use() !== "none"; return /* @__PURE__ */ jsxs("div", { className: "lng1771-cell__marker", children: [ rowSelectionEnabled && /* @__PURE__ */ jsx(SelectionCheckbox, { api, row }), isRowDraggable && /* @__PURE__ */ jsx(DragButton, { api, row }), doesRowHaveDetail && (isExpanded ? /* @__PURE__ */ jsx(CollapseButton, { onClick: toggleDetail }) : /* @__PURE__ */ jsx(ExpandButton, { onClick: toggleDetail })) ] }); } const LoadingSpinner = () => { return /* @__PURE__ */ jsx("div", { className: "lng1771-spinner", children: /* @__PURE__ */ jsx("div", { className: "lng1771-circle" }) }); }; function CellGroupRendererDefault({ api, row, column }) { if (!api.rowIsGroup(row)) { return /* @__PURE__ */ jsx("div", {}); } const key = row.pathKey; const displayMode = api.getState().rowGroupDisplayMode.peek(); if (displayMode === "custom") return null; const isMulti = displayMode === "multi-column"; const rowDepth = api.rowDepth(row.rowIndex); const depth = isMulti ? 0 : rowDepth; const columnDepth = Number.parseInt(column.id.split(":").pop()); if (isMulti && columnDepth !== rowDepth) { return /* @__PURE__ */ jsx("div", {}); } const isLoading = !!row.loading; return /* @__PURE__ */ jsxs( "div", { style: { paddingInlineStart: depth * 24 + 4, whiteSpace: "nowrap", display: "grid", alignItems: "center", gridTemplateColumns: "24px 1fr", height: "100%" }, children: [ !isLoading && !row.error && /* @__PURE__ */ jsx( GridButton, { onClick: () => api.rowGroupToggle(row), style: { width: 20, height: 20, transform: api.rowGroupIsExpanded(row) ? "rotate(90deg)" : void 0 }, children: "›" } ), row.error && !isLoading && /* @__PURE__ */ jsx( GridButton, { onClick: () => api.rowReloadExpansion?.(row), style: { width: 20, height: 20, color: "red" }, children: /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", width: 20, height: 20, children: /* @__PURE__ */ jsx( "path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" } ) } ) } ), isLoading && /* @__PURE__ */ jsx(LoadingSpinner, {}), /* @__PURE__ */ jsx( "div", { style: { width: "100%", overflow: "hidden", textOverflow: "ellipsis" }, children: key } ) ] } ); } function useCellRenderer(api, column) { const renderers = api.getState().cellRenderers.peek(); const Renderer = useMemo(() => { if (column.id === COLUMN_MARKER_ID) return CellMarkerRenderer; const base = api.getState().columnBase.peek(); const renderKey = column.cellRenderer ?? base.cellRenderer; if (!renderKey) return api.columnIsGroupAutoColumn(column) ? CellGroupRendererDefault : CellRendererDefault; if (typeof renderKey === "string") { const El = renderers[renderKey]; if (!El) throw new Error(`Renderer with name ${renderKey} is not present in grid renderers.`); return El; } return renderKey; }, [api, column, renderers]); return Renderer; } function useCellEvents(api, column, row, rowIndex, columnIndex) { const onPointerEnter = useEvent(() => { api.getState().internal.hoveredRow.set(rowIndex); api.getState().internal.hoveredCol.set(columnIndex); }); const onPointerLeave = useEvent(() => { api.getState().internal.hoveredRow.set(null); api.getState().internal.hoveredCol.set(null); }); const onKeyDown = useEvent((event) => { const sx = api.getState(); const mode = sx.rowSelectionMode.peek(); if (mode !== "none") { if (event.key === " ") { handleRowSelection(api, row, false, true, true, "single-click"); event.preventDefault(); } } }); const onClick = useEvent((event) => { handleRowSelection( api, row, event.shiftKey, event.metaKey || event.ctrlKey, false, "single-click" ); }); const onDoubleClick = useEvent((event) => { handleRowSelection( api, row, event.shiftKey, event.metaKey || event.ctrlKey, false, "double-click" ); }); return { onClick, onDoubleClick, onPointerEnter, onPointerLeave, onKeyDown }; } function useCellPositionChange(api, rowIndex, columnIndex, rowSpan, columnSpan) { const ref = useRef(null); const skipRef = useRef(false); const onFocus = useEvent(() => { if (skipRef.current) { skipRef.current = false; return; } api.getState().internal.navigatePosition.set({ kind: GRID_CELL_POSITION, columnIndex, rowIndex, root: { columnIndex, columnSpan, rowIndex, rowSpan } }); }); const tryFocus = useEvent((element, skip = true) => { const sx = api.getState(); const position = sx.internal.navigatePosition.peek(); if (!element || !position || position.kind !== GRID_CELL_POSITION) return; const posRow = position.root?.rowIndex ?? position.rowIndex; const posCol = position.root?.columnIndex ?? position.columnIndex; if (rowIndex === posRow && posCol === columnIndex && !element.contains(document.activeElement) && element !== document.activeElement) { api.navigateScrollIntoView(posRow, posCol); skipRef.current = skip; element.focus(); } }); const handleRef = useCallback( (el) => { tryFocus(el); ref.current = el; }, [tryFocus] ); useEffect(() => { const sx = api.getState(); const unsub = sx.internal.navigatePosition.watch(() => { tryFocus(ref.current); }, false); const unsubFocus = sx.internal.cellFocusQueue.watch(() => { const focus = sx.internal.cellFocusQueue.peek(); if (!focus) return; if (rowIndex === focus.rowIndex && columnIndex === focus.columnIndex) { ref.current?.focus(); } }, false); return () => { unsub(); unsubFocus(); }; }, [api, columnIndex, ref, rowIndex, tryFocus]); return { handleRef, onFocus }; } const skeletonStyle = { display: "block", width: "80%", height: "60%", backgroundColor: "var(--lng1771-gray-05)", borderRadius: "8px", position: "relative", overflow: "hidden" }; const shimmerStyle = { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", backgroundImage: "linear-gradient(90deg, var(--lng1771-gray-05) 0%, var(--lng1771-primary-10) 50%, var(--lng1771-gray-05) 100%)", animation: "lng1771-shimmer 1.5s infinite" }; const Skeleton = ({ className = "" }) => { return /* @__PURE__ */ jsx( "div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx("div", { style: skeletonStyle, className, children: /* @__PURE__ */ jsx("div", { style: shimmerStyle }) }) } ); }; function ErrorCellRenderer({ api }) { return /* @__PURE__ */ jsxs( "button", { style: { color: "red", display: "flex", alignItems: "center", padding: 4, width: "100%", height: "100%", justifyContent: "center", border: "none", backgroundColor: "transparent", gap: 4 }, onClick: () => { api.rowReload(); }, children: [ /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", width: 20, height: 20, children: /* @__PURE__ */ jsx( "path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" } ) } ), "Retry" ] } ); } function CellImpl({ rowIndex, columnIndex, rowSpan, colSpan, yPositions, xPositions, column, rowNode, rowPin, api, paginateOffset }) { const Renderer = useCellRenderer(api, column); const cx = useCellStyle( api, xPositions, yPositions, columnIndex, rowIndex, colSpan, rowSpan, column, rowPin, rowNode.id, paginateOffset ); const events = useCellEvents(api, column, rowNode, rowIndex, columnIndex); const isGroup = api.rowIsGroup(rowNode); const isExpanded = isGroup && api.rowGroupIsExpanded(rowNode); const { handleRef, onFocus } = useCellPositionChange( api, rowIndex, columnIndex, rowSpan, colSpan ); const isLoading = rowNode.loading && rowNode.data == null; const isError = rowNode.error && rowNode.data === null; return /* @__PURE__ */ jsxs( "div", { style: cx.style, ref: handleRef, role: "gridcell", "aria-expanded": isGroup ? isExpanded : void 0, "aria-rowspan": rowSpan, "aria-colspan": colSpan, "aria-rowindex": rowIndex + 1, "aria-colindex": columnIndex + 1, "data-lng1771-colid": column.id, "data-lng1771-rowid": rowNode.id, "data-lng1771-rowindex": rowIndex, "data-lng1771-colindex": rowIndex, className: clsx( "lng1771-cell", rowIndex % 2 === 1 && "lng1771-cell--alternate", cx.className ), tabIndex: -1, ...events, onFocus, children: [ !isLoading && !isError && /* @__PURE__ */ jsx(Renderer, { api, column, columnIndex, row: rowNode }), isLoading && /* @__PURE__ */ jsx(Skeleton, {}), isError && (columnIndex === 0 && column.id !== COLUMN_MARKER_ID || api.getState().columnsVisible.peek()?.[0].id === COLUMN_MARKER_ID && columnIndex === 1) && /* @__PURE__ */ jsx(ErrorCellRenderer, { api }) ] } ); } const Cell = memo(CellImpl); function InputImpl({ className, error, small, ghost, disabled, icon: Icon, ...props }) { return /* @__PURE__ */ jsxs( "div", { className: clsx( "lng1771-input", error && "lng1771-input--error", small && "lng1771-input--small", disabled && "lng1771-input--disabled", ghost && "lng1771-input--ghost", className ), children: [ Icon && /* @__PURE__ */ jsx(Icon, { width: small ? 16 : 20, height: small ? 16 : 20 }), /* @__PURE__ */ jsx("input", { ...props, disabled, className: clsx("lng1771-input__inner") }) ] } ); } const Input = refCompat(InputImpl, "Input"); const createStoreImpl = (createState) => { let state; const listeners = /* @__PURE__ */ new Set(); const setState = (partial, replace) => { const nextState = typeof partial === "function" ? partial(state) : partial; if (!Object.is(nextState, state)) { const previousState = state; state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState); listeners.forEach((listener) => listener(state, previousState)); } }; const getState = () => state; const getInitialState = () => initialState; const subscribe = (listener) => { listeners.add(listener); return () => listeners.delete(listener); }; const api = { setState, getState, getInitialState, subscribe }; const initialState = state = createState(setState, getState, api); return api; }; const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl; const identity = (arg) => arg; function useStore(api, selector = identity) { const slice = React__default.useSyncExternalStore( api.subscribe, () => selector(api.getState()), () => selector(api.getInitialState()) ); React__default.useDebugValue(slice); return slice; } const createImpl = (createState) => { const api = createStore(createState); const useBoundStore = (selector) => useStore(api, selector); Object.assign(useBoundStore, api); return useBoundStore; }; const create = (createState) => createImpl; const store = create()(() => { return { active: null, mounted: [] }; }); const DragContext = createContext(store); function DragProvider({ children }) { const localStore = useRef(null); if (!localStore.current) { localStore.current = create()(() => { return { active: null, mounted: [] }; }); } return /* @__PURE__ */ jsx(DragContext.Provider, { value: localStore.current, children }); } const useDragStore = () => useContext(DragContext); const useDrag = useStore; export { ROW_UPDATE_STACK_SIZE as A, DEFAULT_MAX_WIDTH as B, Checkbox as C, DragProvider as D, END_ENCODING as E, FLOATING_CELL_POSITION as F, GRID_CELL_POSITION as G, HEADER_CELL_POSITION as H, Input as I, DEFAULT_MIN_WIDTH as J, DEFAULT_WIDTH as K, DEFAULT_SORT_CYCLE as L, FULL_WIDTH_POSITION as M, PAGINATE_PAGE_SIZE as P, ROW_LEAF_KIND as R, useDrag as a, useStore as b, CheckMark as c, COLUMN_MARKER_ID as d, COLUMN_EMPTY_PREFIX as e, HEADER_GROUP_CELL_POSITION as f, getTransform as g, CollapseButton as h, FULL_ENCODING as i, CellFullWidth as j, Cell as k, GridButton as l, ROW_GROUP_KIND as m, COLUMN_GROUP_ID_DELIMITER as n, ROW_DEFAULT_PATH_SEPARATOR as o, GROUP_COLUMN_PREFIX as p, GROUP_COLUMN_MULTI_PREFIX as q, GROUP_COLUMN_SINGLE_ID as r, GROUP_COLUMN_TREE_DATA as s, COLUMN_GROUP_HEADER_HEIGHT as t, useDragStore as u, COLUMN_HEADER_HEIGHT as v, COLUMN_SCAN_DISTANCE as w, ROW_BLANK_GROUP_KEY as x, ROW_HEIGHT as y, ROW_DETAIL_HEIGHT as z };