@gridkitjs/react 0.0.1 → 0.1.0
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.d.ts +4 -4
- package/dist/index.js +14 -29
- package/dist/index.js.map +1 -1
- package/package.json +14 -21
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ColumnDefinition as ColumnDefinition$1, ColumnSizingState, ColumnSizeDefaults, ColumnResizeEvent, ResolvedColumn as ResolvedColumn$1 } from '@gridkitjs/core';
|
|
4
|
-
export { ColumnResizeEvent, ColumnSizeDefaults, ColumnSizingState } from '@gridkitjs/core';
|
|
4
|
+
export { CellTemplateContext, ColumnResizeEvent, ColumnSizeDefaults, ColumnSizingState } from '@gridkitjs/core';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* A column whose header may render arbitrary React content.
|
|
8
|
-
* stays framework-agnostic and so leaves that output type open;
|
|
9
|
-
* binding React consumers want, and the one they should import.
|
|
7
|
+
* A column whose header and cells may render arbitrary React content.
|
|
8
|
+
* @gridkitjs/core stays framework-agnostic and so leaves that output type open;
|
|
9
|
+
* this is the binding React consumers want, and the one they should import.
|
|
10
10
|
*/
|
|
11
11
|
type ColumnDefinition<Row> = ColumnDefinition$1<Row, ReactNode>;
|
|
12
12
|
/** A column paired with the width it renders at. */
|
package/dist/index.js
CHANGED
|
@@ -46,25 +46,7 @@ function GridHeader({
|
|
|
46
46
|
entry,
|
|
47
47
|
event.key === "ArrowLeft" ? -KEYBOARD_STEP : KEYBOARD_STEP
|
|
48
48
|
);
|
|
49
|
-
}
|
|
50
|
-
children: /* @__PURE__ */ jsxs(
|
|
51
|
-
"svg",
|
|
52
|
-
{
|
|
53
|
-
className: "header-resize-grip",
|
|
54
|
-
viewBox: "0 0 6 14",
|
|
55
|
-
width: "6",
|
|
56
|
-
height: "14",
|
|
57
|
-
"aria-hidden": "true",
|
|
58
|
-
children: [
|
|
59
|
-
/* @__PURE__ */ jsx("circle", { cx: "1.5", cy: "4", r: "1" }),
|
|
60
|
-
/* @__PURE__ */ jsx("circle", { cx: "1.5", cy: "7", r: "1" }),
|
|
61
|
-
/* @__PURE__ */ jsx("circle", { cx: "1.5", cy: "10", r: "1" }),
|
|
62
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "4", r: "1" }),
|
|
63
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "7", r: "1" }),
|
|
64
|
-
/* @__PURE__ */ jsx("circle", { cx: "4.5", cy: "10", r: "1" })
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
)
|
|
49
|
+
}
|
|
68
50
|
}
|
|
69
51
|
)
|
|
70
52
|
]
|
|
@@ -83,16 +65,19 @@ function GridBody({
|
|
|
83
65
|
dataSource,
|
|
84
66
|
activeColumnId
|
|
85
67
|
}) {
|
|
86
|
-
return /* @__PURE__ */ jsx2("tbody", { className: "grid-body", children: dataSource?.map((row, index) => /* @__PURE__ */ jsx2("tr", { className: "grid-row", children: columns.map(({ id, column, alignment }) =>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
68
|
+
return /* @__PURE__ */ jsx2("tbody", { className: "grid-body", children: dataSource?.map((row, index) => /* @__PURE__ */ jsx2("tr", { className: "grid-row", children: columns.map(({ id, column, alignment }) => {
|
|
69
|
+
const value = accessDotted(row, column.field);
|
|
70
|
+
return /* @__PURE__ */ jsx2(
|
|
71
|
+
"td",
|
|
72
|
+
{
|
|
73
|
+
"data-gridkit-column": id,
|
|
74
|
+
className: id === activeColumnId ? "grid-cell is-resizing" : "grid-cell",
|
|
75
|
+
style: { textAlign: alignment },
|
|
76
|
+
children: column.cellTemplate ? column.cellTemplate({ value, row, rowIndex: index }) : value
|
|
77
|
+
},
|
|
78
|
+
id
|
|
79
|
+
);
|
|
80
|
+
}) }, index)) });
|
|
96
81
|
}
|
|
97
82
|
|
|
98
83
|
// src/DataGrid/useColumnResize.ts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useElementWidth.ts"],"sourcesContent":["import { useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n defineColumnsFromRows,\n fitColumnsToWidth,\n resolveColumnWidths,\n totalColumnWidth,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport useColumnResize from \"./useColumnResize\";\nimport useElementWidth from \"./useElementWidth\";\n\n/**\n * A column whose header may render arbitrary React content. @gridkitjs/core\n * stays framework-agnostic and so leaves that output type open; this is the\n * binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\nexport interface DataGridProps<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n borders,\n hoverable,\n resizableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n columnSizeDefaults,\n onColumnResize,\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(definedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n definedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n ]);\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n });\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n <table\n ref={tableRef}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={[\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row> columns={resolved} resize={resize} />\n <GridBody<Row>\n columns={resolved}\n dataSource={dataSource}\n activeColumnId={resize.activeColumnId}\n />\n </table>\n </div>\n );\n}\n","import { KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n}: GridHeaderProps<Row>) {\n return (\n <thead>\n <tr className=\"grid-header\">\n {columns.map((entry) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n\n return (\n <th\n key={entry.id}\n data-gridkit-column={entry.id}\n className={resizing ? \"header-cell is-resizing\" : \"header-cell\"}\n >\n {entry.label}\n {entry.resizable && (\n <span\n className=\"header-resize-handle\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize ${column.field}`}\n tabIndex={0}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n onKeyDown={(event) => {\n if (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\")\n return;\n event.preventDefault();\n resize.nudge(\n entry,\n event.key === \"ArrowLeft\"\n ? -KEYBOARD_STEP\n : KEYBOARD_STEP,\n );\n }}\n >\n <svg\n className=\"header-resize-grip\"\n viewBox=\"0 0 6 14\"\n width=\"6\"\n height=\"14\"\n aria-hidden=\"true\"\n >\n <circle cx=\"1.5\" cy=\"4\" r=\"1\" />\n <circle cx=\"1.5\" cy=\"7\" r=\"1\" />\n <circle cx=\"1.5\" cy=\"10\" r=\"1\" />\n <circle cx=\"4.5\" cy=\"4\" r=\"1\" />\n <circle cx=\"4.5\" cy=\"7\" r=\"1\" />\n <circle cx=\"4.5\" cy=\"10\" r=\"1\" />\n </svg>\n </span>\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n );\n}\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n dataSource?: readonly Row[] | undefined;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n}\n\nexport default function GridBody<Row>({\n columns,\n dataSource,\n activeColumnId,\n}: GridBodyProps<Row>) {\n return (\n <tbody className=\"grid-body\">\n {dataSource?.map((row, index) => (\n <tr key={index} className=\"grid-row\">\n {columns.map(({ id, column, alignment }) => (\n <td\n key={id}\n data-gridkit-column={id}\n className={\n id === activeColumnId ? \"grid-cell is-resizing\" : \"grid-cell\"\n }\n style={{ textAlign: alignment }}\n >\n {accessDotted(row, column.field) as ReactNode}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n );\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n handle.setPointerCapture(pointerId);\n setActiveColumnId(session.columnId);\n\n function move(moveEvent: PointerEvent): void {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n }\n\n function stop(): void {\n handle.removeEventListener(\"pointermove\", move);\n handle.removeEventListener(\"pointerup\", end);\n handle.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (handle.hasPointerCapture(pointerId)) {\n handle.releasePointerCapture(pointerId);\n }\n setActiveColumnId(null);\n }\n\n function end(): void {\n stop();\n commit(base, session.columnId, width, \"end\");\n }\n\n /**\n * Escape puts back the state the drag started from, which correctly covers\n * a column that had no stored width at all — merging `startWidth` back in\n * would instead leave it pinned and hidden from auto-fit.\n */\n function cancel(): void {\n stop();\n setSizing(base);\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: base,\n phase: \"end\",\n });\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n handle.addEventListener(\"pointermove\", move);\n handle.addEventListener(\"pointerup\", end);\n handle.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n"],"mappings":"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","names":["useState","jsx","useState","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useElementWidth.ts"],"sourcesContent":["import { useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n defineColumnsFromRows,\n fitColumnsToWidth,\n resolveColumnWidths,\n totalColumnWidth,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport useColumnResize from \"./useColumnResize\";\nimport useElementWidth from \"./useElementWidth\";\n\n/**\n * A column whose header and cells may render arbitrary React content.\n * @gridkitjs/core stays framework-agnostic and so leaves that output type open;\n * this is the binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\nexport interface DataGridProps<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n borders,\n hoverable,\n resizableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n columnSizeDefaults,\n onColumnResize,\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(definedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n definedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n ]);\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n });\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n <table\n ref={tableRef}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={[\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row> columns={resolved} resize={resize} />\n <GridBody<Row>\n columns={resolved}\n dataSource={dataSource}\n activeColumnId={resize.activeColumnId}\n />\n </table>\n </div>\n );\n}\n","import { KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n}: GridHeaderProps<Row>) {\n return (\n <thead>\n <tr className=\"grid-header\">\n {columns.map((entry) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n\n return (\n <th\n key={entry.id}\n data-gridkit-column={entry.id}\n className={resizing ? \"header-cell is-resizing\" : \"header-cell\"}\n >\n {entry.label}\n {entry.resizable && (\n <span\n className=\"header-resize-handle\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize ${column.field}`}\n tabIndex={0}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n onKeyDown={(event) => {\n if (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\")\n return;\n event.preventDefault();\n resize.nudge(\n entry,\n event.key === \"ArrowLeft\"\n ? -KEYBOARD_STEP\n : KEYBOARD_STEP,\n );\n }}\n />\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n );\n}\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n dataSource?: readonly Row[] | undefined;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n}\n\nexport default function GridBody<Row>({\n columns,\n dataSource,\n activeColumnId,\n}: GridBodyProps<Row>) {\n return (\n <tbody className=\"grid-body\">\n {dataSource?.map((row, index) => (\n <tr key={index} className=\"grid-row\">\n {columns.map(({ id, column, alignment }) => {\n // Resolved either way, so a template that only formats the value\n // never has to walk the field path a second time.\n const value = accessDotted(row, column.field);\n\n return (\n <td\n key={id}\n data-gridkit-column={id}\n className={\n id === activeColumnId ? \"grid-cell is-resizing\" : \"grid-cell\"\n }\n style={{ textAlign: alignment }}\n >\n {column.cellTemplate\n ? column.cellTemplate({ value, row, rowIndex: index })\n : (value as ReactNode)}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n );\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n handle.setPointerCapture(pointerId);\n setActiveColumnId(session.columnId);\n\n function move(moveEvent: PointerEvent): void {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n }\n\n function stop(): void {\n handle.removeEventListener(\"pointermove\", move);\n handle.removeEventListener(\"pointerup\", end);\n handle.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (handle.hasPointerCapture(pointerId)) {\n handle.releasePointerCapture(pointerId);\n }\n setActiveColumnId(null);\n }\n\n function end(): void {\n stop();\n commit(base, session.columnId, width, \"end\");\n }\n\n /**\n * Escape puts back the state the drag started from, which correctly covers\n * a column that had no stored width at all — merging `startWidth` back in\n * would instead leave it pinned and hidden from auto-fit.\n */\n function cancel(): void {\n stop();\n setSizing(base);\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: base,\n phase: \"end\",\n });\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n handle.addEventListener(\"pointermove\", move);\n handle.addEventListener(\"pointerup\", end);\n handle.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n"],"mappings":"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","names":["useState","jsx","useState","jsx","jsxs","useState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gridkitjs/react",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "React data-grid components built on @gridkitjs/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blagoja Blazhevski",
|
|
@@ -22,19 +22,12 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=22"
|
|
24
24
|
},
|
|
25
|
-
"main": "./
|
|
26
|
-
"types": "./
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
27
|
"exports": {
|
|
28
|
-
".":
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"main": "./dist/index.js",
|
|
32
|
-
"types": "./dist/index.d.ts",
|
|
33
|
-
"exports": {
|
|
34
|
-
".": {
|
|
35
|
-
"types": "./dist/index.d.ts",
|
|
36
|
-
"import": "./dist/index.js"
|
|
37
|
-
}
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
38
31
|
}
|
|
39
32
|
},
|
|
40
33
|
"files": [
|
|
@@ -42,18 +35,12 @@
|
|
|
42
35
|
"LICENSE",
|
|
43
36
|
"README.md"
|
|
44
37
|
],
|
|
45
|
-
"scripts": {
|
|
46
|
-
"build": "tsup",
|
|
47
|
-
"typecheck": "tsc --noEmit",
|
|
48
|
-
"lint": "eslint src",
|
|
49
|
-
"test": "vitest run --passWithNoTests"
|
|
50
|
-
},
|
|
51
38
|
"peerDependencies": {
|
|
52
39
|
"react": "^19.0.0",
|
|
53
40
|
"react-dom": "^19.0.0"
|
|
54
41
|
},
|
|
55
42
|
"dependencies": {
|
|
56
|
-
"@gridkitjs/core": "
|
|
43
|
+
"@gridkitjs/core": "0.1.0"
|
|
57
44
|
},
|
|
58
45
|
"devDependencies": {
|
|
59
46
|
"@types/react": "^19.2.18",
|
|
@@ -63,5 +50,11 @@
|
|
|
63
50
|
"tsup": "^8.5.1",
|
|
64
51
|
"typescript": "^6.0.3",
|
|
65
52
|
"vitest": "^4.1.10"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"lint": "eslint src",
|
|
58
|
+
"test": "vitest run --passWithNoTests"
|
|
66
59
|
}
|
|
67
|
-
}
|
|
60
|
+
}
|