simple-table-core 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Animate.d.ts +7 -0
- package/dist/components/SimpleTable/SimpleTable.d.ts +18 -0
- package/dist/components/SimpleTable/TableBody.d.ts +19 -0
- package/dist/components/SimpleTable/TableCell.d.ts +14 -0
- package/dist/components/SimpleTable/TableFooter.d.ts +12 -0
- package/dist/components/SimpleTable/TableHeader.d.ts +14 -0
- package/dist/components/SimpleTable/TableHeaderCell.d.ts +15 -0
- package/dist/components/SimpleTable/TableLastColumnCell.d.ts +6 -0
- package/dist/components/SimpleTable/TableRowSeparator.d.ts +2 -0
- package/dist/consts/SampleData.d.ts +19 -0
- package/dist/helpers/calculateBoundingBoxes.d.ts +13 -0
- package/dist/helpers/shuffleArray.d.ts +1 -0
- package/dist/hooks/usePrevious.d.ts +2 -0
- package/dist/hooks/useSelection.d.ts +19 -0
- package/dist/hooks/useTableHeaderCell.d.ts +14 -0
- package/dist/icons/AngleLeftIcon.d.ts +3 -0
- package/dist/icons/AngleRightIcon.d.ts +3 -0
- package/{src/index.tsx → dist/index.d.ts} +0 -1
- package/dist/stories/SimpleTable.stories.d.ts +11 -0
- package/dist/stories/SimpleTableExample.d.ts +1 -0
- package/dist/types/HeaderObject.d.ts +10 -0
- package/dist/utils/performanceUtils.d.ts +1 -0
- package/dist/utils/sortUtils.d.ts +15 -0
- package/package.json +5 -1
- package/.storybook/main.ts +0 -18
- package/.storybook/preview.ts +0 -14
- package/assets/table-example.png +0 -0
- package/rollup.config.js +0 -27
- package/src/components/Animate.tsx +0 -69
- package/src/components/SimpleTable/SimpleTable.tsx +0 -165
- package/src/components/SimpleTable/TableBody.tsx +0 -79
- package/src/components/SimpleTable/TableCell.tsx +0 -51
- package/src/components/SimpleTable/TableFooter.tsx +0 -61
- package/src/components/SimpleTable/TableHeader.tsx +0 -60
- package/src/components/SimpleTable/TableHeaderCell.tsx +0 -129
- package/src/components/SimpleTable/TableLastColumnCell.tsx +0 -17
- package/src/components/SimpleTable/TableRowSeparator.tsx +0 -5
- package/src/consts/SampleData.ts +0 -101
- package/src/helpers/calculateBoundingBoxes.ts +0 -29
- package/src/helpers/shuffleArray.ts +0 -6
- package/src/hooks/usePrevious.ts +0 -15
- package/src/hooks/useSelection.ts +0 -106
- package/src/hooks/useTableHeaderCell.ts +0 -76
- package/src/icons/AngleLeftIcon.tsx +0 -15
- package/src/icons/AngleRightIcon.tsx +0 -15
- package/src/react-app-env.d.ts +0 -1
- package/src/stories/SimpleTable.stories.ts +0 -16
- package/src/stories/SimpleTableExample.tsx +0 -17
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/styles/simple-table.css +0 -242
- package/src/types/HeaderObject.ts +0 -10
- package/src/utils/performanceUtils.ts +0 -17
- package/src/utils/sortUtils.ts +0 -30
- package/tsconfig.json +0 -26
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import HeaderObject from "../../types/HeaderObject";
|
|
3
|
+
import "../../styles/simple-table.css";
|
|
4
|
+
interface SpreadsheetProps {
|
|
5
|
+
defaultHeaders: HeaderObject[];
|
|
6
|
+
enableColumnResizing?: boolean;
|
|
7
|
+
height?: string;
|
|
8
|
+
hideFooter?: boolean;
|
|
9
|
+
nextIcon?: ReactNode;
|
|
10
|
+
prevIcon?: ReactNode;
|
|
11
|
+
rows: {
|
|
12
|
+
[key: string]: string | number | boolean | undefined | null;
|
|
13
|
+
}[];
|
|
14
|
+
rowsPerPage?: number;
|
|
15
|
+
shouldPaginate?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare const SimpleTable: ({ defaultHeaders, enableColumnResizing, height, hideFooter, nextIcon, prevIcon, rows, rowsPerPage, shouldPaginate, }: SpreadsheetProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export default SimpleTable;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import HeaderObject from "../../types/HeaderObject";
|
|
2
|
+
interface TableBodyProps {
|
|
3
|
+
getBorderClass: (rowIndex: number, columnIndex: number) => string;
|
|
4
|
+
handleMouseDown: (rowIndex: number, columnIndex: number) => void;
|
|
5
|
+
handleMouseOver: (rowIndex: number, columnIndex: number) => void;
|
|
6
|
+
headers: HeaderObject[];
|
|
7
|
+
isSelected: (rowIndex: number, columnIndex: number) => boolean;
|
|
8
|
+
isTopLeftCell: (rowIndex: number, columnIndex: number) => boolean;
|
|
9
|
+
isWidthDragging: boolean;
|
|
10
|
+
shouldDisplayLastColumnCell: boolean;
|
|
11
|
+
shouldPaginate: boolean;
|
|
12
|
+
sortedRows: {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}[];
|
|
15
|
+
}
|
|
16
|
+
declare const TableBody: ({ getBorderClass, handleMouseDown, handleMouseOver, headers, isSelected, isTopLeftCell, isWidthDragging, shouldDisplayLastColumnCell, shouldPaginate, sortedRows, }: TableBodyProps & {
|
|
17
|
+
shouldDisplayLastColumnCell: boolean;
|
|
18
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export default TableBody;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
interface TableCellProps {
|
|
3
|
+
rowIndex: number;
|
|
4
|
+
colIndex: number;
|
|
5
|
+
content: any;
|
|
6
|
+
isSelected: boolean;
|
|
7
|
+
isTopLeftCell: boolean;
|
|
8
|
+
borderClass: string;
|
|
9
|
+
onMouseDown: (rowIndex: number, colIndex: number) => void;
|
|
10
|
+
onMouseOver: (rowIndex: number, colIndex: number) => void;
|
|
11
|
+
isLastRow: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const TableCell: import("react").ForwardRefExoticComponent<TableCellProps & import("react").RefAttributes<HTMLTableCellElement>>;
|
|
14
|
+
export default TableCell;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
interface TableFooterProps {
|
|
3
|
+
currentPage: number;
|
|
4
|
+
hideFooter?: boolean;
|
|
5
|
+
nextIcon?: ReactNode;
|
|
6
|
+
onPageChange: (page: number) => void;
|
|
7
|
+
prevIcon?: ReactNode;
|
|
8
|
+
rowsPerPage: number;
|
|
9
|
+
totalRows: number;
|
|
10
|
+
}
|
|
11
|
+
declare const TableFooter: ({ currentPage, hideFooter, nextIcon, onPageChange, prevIcon, rowsPerPage, totalRows, }: TableFooterProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
export default TableFooter;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import HeaderObject from "../../types/HeaderObject";
|
|
3
|
+
interface TableHeaderProps {
|
|
4
|
+
enableColumnResizing: boolean;
|
|
5
|
+
forceUpdate: () => void;
|
|
6
|
+
headersRef: React.RefObject<HeaderObject[]>;
|
|
7
|
+
isWidthDragging: boolean;
|
|
8
|
+
onSort: (columnIndex: number) => void;
|
|
9
|
+
onTableHeaderDragEnd: (newHeaders: HeaderObject[]) => void;
|
|
10
|
+
setIsWidthDragging: Dispatch<SetStateAction<boolean>>;
|
|
11
|
+
shouldDisplayLastColumnCell: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const TableHeader: ({ enableColumnResizing, forceUpdate, headersRef, isWidthDragging, onSort, onTableHeaderDragEnd, setIsWidthDragging, shouldDisplayLastColumnCell, }: TableHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default TableHeader;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SetStateAction, Dispatch } from "react";
|
|
2
|
+
import HeaderObject from "../../types/HeaderObject";
|
|
3
|
+
interface TableHeaderCellProps {
|
|
4
|
+
draggedHeaderRef: React.MutableRefObject<HeaderObject | null>;
|
|
5
|
+
enableColumnResizing: boolean;
|
|
6
|
+
forceUpdate: () => void;
|
|
7
|
+
headersRef: React.RefObject<HeaderObject[]>;
|
|
8
|
+
hoveredHeaderRef: React.MutableRefObject<HeaderObject | null>;
|
|
9
|
+
index: number;
|
|
10
|
+
onSort: (columnIndex: number) => void;
|
|
11
|
+
onTableHeaderDragEnd: (newHeaders: HeaderObject[]) => void;
|
|
12
|
+
setIsWidthDragging: Dispatch<SetStateAction<boolean>>;
|
|
13
|
+
}
|
|
14
|
+
declare const TableHeaderCell: import("react").ForwardRefExoticComponent<TableHeaderCellProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
15
|
+
export default TableHeaderCell;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import HeaderObject from "../types/HeaderObject";
|
|
2
|
+
export declare const SAMPLE_HEADERS: HeaderObject[];
|
|
3
|
+
export declare const inventoryData: {
|
|
4
|
+
id: string;
|
|
5
|
+
productName: string;
|
|
6
|
+
category: string;
|
|
7
|
+
quantity: number;
|
|
8
|
+
price: string;
|
|
9
|
+
supplier: string;
|
|
10
|
+
location: string;
|
|
11
|
+
reorderLevel: number;
|
|
12
|
+
sku: string;
|
|
13
|
+
description: string;
|
|
14
|
+
weight: string;
|
|
15
|
+
dimensions: string;
|
|
16
|
+
barcode: string;
|
|
17
|
+
expirationDate: string;
|
|
18
|
+
manufacturer: string;
|
|
19
|
+
}[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
interface BoundingBox {
|
|
3
|
+
bottom: number;
|
|
4
|
+
height: number;
|
|
5
|
+
left: number;
|
|
6
|
+
right: number;
|
|
7
|
+
top: number;
|
|
8
|
+
width: number;
|
|
9
|
+
}
|
|
10
|
+
declare const calculateBoundingBoxes: (children: ReactNode) => {
|
|
11
|
+
[key: string]: BoundingBox;
|
|
12
|
+
};
|
|
13
|
+
export default calculateBoundingBoxes;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function shuffleArray(array: any[]): any[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import HeaderObject from "../types/HeaderObject";
|
|
3
|
+
interface Cell {
|
|
4
|
+
row: number;
|
|
5
|
+
col: number;
|
|
6
|
+
}
|
|
7
|
+
declare const useSelection: (rows: {
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}[], headers: HeaderObject[]) => {
|
|
10
|
+
selectedCells: Cell[];
|
|
11
|
+
handleMouseDown: (rowIndex: number, colIndex: number) => void;
|
|
12
|
+
handleMouseOver: (rowIndex: number, colIndex: number) => void;
|
|
13
|
+
handleMouseUp: () => void;
|
|
14
|
+
isSelected: (rowIndex: number, colIndex: number) => boolean;
|
|
15
|
+
getBorderClass: (rowIndex: number, colIndex: number) => string;
|
|
16
|
+
isTopLeftCell: (rowIndex: number, colIndex: number) => boolean;
|
|
17
|
+
setSelectedCells: import("react").Dispatch<import("react").SetStateAction<Cell[]>>;
|
|
18
|
+
};
|
|
19
|
+
export default useSelection;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import HeaderObject from "../types/HeaderObject";
|
|
3
|
+
interface UseTableHeaderCellProps {
|
|
4
|
+
draggedHeaderRef: React.MutableRefObject<HeaderObject | null>;
|
|
5
|
+
headersRef: React.RefObject<HeaderObject[]>;
|
|
6
|
+
hoveredHeaderRef: React.MutableRefObject<HeaderObject | null>;
|
|
7
|
+
onTableHeaderDragEnd: (newHeaders: HeaderObject[]) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const useTableHeaderCell: ({ draggedHeaderRef, headersRef, hoveredHeaderRef, onTableHeaderDragEnd, }: UseTableHeaderCellProps) => {
|
|
10
|
+
handleDragStart: (header: HeaderObject) => void;
|
|
11
|
+
handleDragOver: (hoveredHeader: HeaderObject) => void;
|
|
12
|
+
handleDragEnd: () => void;
|
|
13
|
+
};
|
|
14
|
+
export default useTableHeaderCell;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StoryObj } from "@storybook/react";
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: () => import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
parameters: {
|
|
6
|
+
layout: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof meta>;
|
|
11
|
+
export declare const SimpleTable: Story;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SampleTable: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const throttle: (func: (...args: any[]) => void, limit: number) => (this: any, ...args: any[]) => void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import HeaderObject from "../types/HeaderObject";
|
|
2
|
+
export declare const onSort: (headers: HeaderObject[], rows: {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
}[], sortConfig: {
|
|
5
|
+
key: HeaderObject;
|
|
6
|
+
direction: string;
|
|
7
|
+
} | null, columnIndex: number) => {
|
|
8
|
+
sortedData: {
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}[];
|
|
11
|
+
newSortConfig: {
|
|
12
|
+
key: HeaderObject;
|
|
13
|
+
direction: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
package/package.json
CHANGED
package/.storybook/main.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { StorybookConfig } from "@storybook/react-webpack5";
|
|
2
|
-
|
|
3
|
-
const config: StorybookConfig = {
|
|
4
|
-
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
|
5
|
-
addons: [
|
|
6
|
-
"@storybook/preset-create-react-app",
|
|
7
|
-
"@storybook/addon-onboarding",
|
|
8
|
-
"@storybook/addon-links",
|
|
9
|
-
"@storybook/addon-essentials",
|
|
10
|
-
"@chromatic-com/storybook",
|
|
11
|
-
"@storybook/addon-interactions",
|
|
12
|
-
],
|
|
13
|
-
framework: {
|
|
14
|
-
name: "@storybook/react-webpack5",
|
|
15
|
-
options: {},
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
export default config;
|
package/.storybook/preview.ts
DELETED
package/assets/table-example.png
DELETED
|
Binary file
|
package/rollup.config.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import babel from "@rollup/plugin-babel";
|
|
2
|
-
import resolve from "@rollup/plugin-node-resolve";
|
|
3
|
-
import postcss from "rollup-plugin-postcss";
|
|
4
|
-
import typescript from "@rollup/plugin-typescript";
|
|
5
|
-
import { terser } from "rollup-plugin-terser";
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
input: "src/index.tsx",
|
|
9
|
-
output: {
|
|
10
|
-
file: "dist/index.js",
|
|
11
|
-
format: "esm",
|
|
12
|
-
},
|
|
13
|
-
plugins: [
|
|
14
|
-
postcss({
|
|
15
|
-
plugins: [],
|
|
16
|
-
minimize: true,
|
|
17
|
-
}),
|
|
18
|
-
babel({
|
|
19
|
-
exclude: "node_modules/**",
|
|
20
|
-
presets: ["@babel/preset-react"],
|
|
21
|
-
}),
|
|
22
|
-
resolve(),
|
|
23
|
-
typescript(),
|
|
24
|
-
terser(),
|
|
25
|
-
],
|
|
26
|
-
external: ["react", "react/jsx-runtime"],
|
|
27
|
-
};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import React, { useState, useLayoutEffect, useEffect } from "react";
|
|
2
|
-
import usePrevious from "../hooks/usePrevious";
|
|
3
|
-
import calculateBoundingBoxes from "../helpers/calculateBoundingBoxes";
|
|
4
|
-
|
|
5
|
-
interface AnimateProps {
|
|
6
|
-
allowHorizontalAnimate?: boolean;
|
|
7
|
-
children: any;
|
|
8
|
-
pause?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const Animate = ({
|
|
12
|
-
allowHorizontalAnimate = true,
|
|
13
|
-
children,
|
|
14
|
-
pause,
|
|
15
|
-
}: AnimateProps) => {
|
|
16
|
-
const [boundingBox, setBoundingBox] = useState<any>({});
|
|
17
|
-
const [prevBoundingBox, setPrevBoundingBox] = useState<any>({});
|
|
18
|
-
const prevChildren = usePrevious(children);
|
|
19
|
-
|
|
20
|
-
useLayoutEffect(() => {
|
|
21
|
-
const newBoundingBox = calculateBoundingBoxes(children);
|
|
22
|
-
setBoundingBox(newBoundingBox);
|
|
23
|
-
}, [children]);
|
|
24
|
-
|
|
25
|
-
useLayoutEffect(() => {
|
|
26
|
-
const prevBoundingBox = calculateBoundingBoxes(prevChildren);
|
|
27
|
-
setPrevBoundingBox(prevBoundingBox);
|
|
28
|
-
}, [prevChildren]);
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (pause) return;
|
|
32
|
-
const hasPrevBoundingBox = Object.keys(prevBoundingBox).length;
|
|
33
|
-
|
|
34
|
-
if (hasPrevBoundingBox) {
|
|
35
|
-
React.Children.forEach(children, (child) => {
|
|
36
|
-
const domNode = child.ref.current;
|
|
37
|
-
const firstBox = prevBoundingBox[child.key];
|
|
38
|
-
const lastBox = boundingBox[child.key];
|
|
39
|
-
|
|
40
|
-
const changeInX = firstBox.left - lastBox.left;
|
|
41
|
-
const changeInY = !allowHorizontalAnimate
|
|
42
|
-
? firstBox.top - lastBox.top
|
|
43
|
-
: 0;
|
|
44
|
-
|
|
45
|
-
const absoluteChangeInX = Math.abs(changeInX);
|
|
46
|
-
const absoluteChangeInY = Math.abs(changeInY);
|
|
47
|
-
|
|
48
|
-
if (absoluteChangeInX > 10 || absoluteChangeInY > 10) {
|
|
49
|
-
requestAnimationFrame(() => {
|
|
50
|
-
// Before the DOM paints, invert child to old position
|
|
51
|
-
domNode.style.transform = `translate(${changeInX}px, ${changeInY}px)`;
|
|
52
|
-
domNode.style.transition = "transform 0s";
|
|
53
|
-
|
|
54
|
-
requestAnimationFrame(() => {
|
|
55
|
-
// After the previous frame, remove
|
|
56
|
-
// the transition to play the animation
|
|
57
|
-
domNode.style.transform = "";
|
|
58
|
-
domNode.style.transition = "transform 500ms";
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}, [boundingBox, prevBoundingBox, children, pause, allowHorizontalAnimate]);
|
|
65
|
-
|
|
66
|
-
return children;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export default Animate;
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useState,
|
|
3
|
-
useRef,
|
|
4
|
-
useEffect,
|
|
5
|
-
useReducer,
|
|
6
|
-
ReactNode,
|
|
7
|
-
useMemo,
|
|
8
|
-
} from "react";
|
|
9
|
-
import useSelection from "../../hooks/useSelection";
|
|
10
|
-
import TableHeader from "./TableHeader";
|
|
11
|
-
import { onSort } from "../../utils/sortUtils";
|
|
12
|
-
import TableBody from "./TableBody";
|
|
13
|
-
import HeaderObject from "../../types/HeaderObject";
|
|
14
|
-
import TableFooter from "./TableFooter";
|
|
15
|
-
import AngleLeftIcon from "../../icons/AngleLeftIcon";
|
|
16
|
-
import AngleRightIcon from "../../icons/AngleRightIcon";
|
|
17
|
-
import "../../styles/simple-table.css";
|
|
18
|
-
|
|
19
|
-
interface SpreadsheetProps {
|
|
20
|
-
defaultHeaders: HeaderObject[];
|
|
21
|
-
enableColumnResizing?: boolean;
|
|
22
|
-
height?: string;
|
|
23
|
-
hideFooter?: boolean;
|
|
24
|
-
nextIcon?: ReactNode;
|
|
25
|
-
prevIcon?: ReactNode;
|
|
26
|
-
rows: { [key: string]: string | number | boolean | undefined | null }[];
|
|
27
|
-
rowsPerPage?: number;
|
|
28
|
-
shouldPaginate?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const SimpleTable = ({
|
|
32
|
-
defaultHeaders,
|
|
33
|
-
enableColumnResizing = true,
|
|
34
|
-
height,
|
|
35
|
-
hideFooter = false,
|
|
36
|
-
nextIcon = <AngleRightIcon />,
|
|
37
|
-
prevIcon = <AngleLeftIcon />,
|
|
38
|
-
rows,
|
|
39
|
-
rowsPerPage = 10,
|
|
40
|
-
shouldPaginate = true,
|
|
41
|
-
}: SpreadsheetProps) => {
|
|
42
|
-
const [isWidthDragging, setIsWidthDragging] = useState(false);
|
|
43
|
-
const headersRef = useRef(defaultHeaders);
|
|
44
|
-
const [sortedRows, setSortedRows] = useState(rows);
|
|
45
|
-
const [sortConfig, setSortConfig] = useState<{
|
|
46
|
-
key: HeaderObject;
|
|
47
|
-
direction: string;
|
|
48
|
-
} | null>(null);
|
|
49
|
-
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
50
|
-
|
|
51
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
52
|
-
|
|
53
|
-
const tableRef = useRef<HTMLDivElement>(null);
|
|
54
|
-
|
|
55
|
-
const shouldDisplayLastColumnCell = useMemo(() => {
|
|
56
|
-
if (!tableRef.current) return false;
|
|
57
|
-
const totalColumnWidth = headersRef.current.reduce(
|
|
58
|
-
(acc, header) => acc + header.width,
|
|
59
|
-
0
|
|
60
|
-
);
|
|
61
|
-
return totalColumnWidth < tableRef.current.clientWidth;
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
const {
|
|
65
|
-
handleMouseDown,
|
|
66
|
-
handleMouseOver,
|
|
67
|
-
handleMouseUp,
|
|
68
|
-
isSelected,
|
|
69
|
-
getBorderClass,
|
|
70
|
-
isTopLeftCell,
|
|
71
|
-
setSelectedCells,
|
|
72
|
-
} = useSelection(sortedRows, headersRef.current);
|
|
73
|
-
|
|
74
|
-
const handleSort = (columnIndex: number) => {
|
|
75
|
-
const { sortedData, newSortConfig } = onSort(
|
|
76
|
-
headersRef.current,
|
|
77
|
-
sortedRows,
|
|
78
|
-
sortConfig,
|
|
79
|
-
columnIndex
|
|
80
|
-
);
|
|
81
|
-
setSortedRows(sortedData);
|
|
82
|
-
setSortConfig(newSortConfig);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const onTableHeaderDragEnd = (newHeaders: HeaderObject[]) => {
|
|
86
|
-
headersRef.current = newHeaders;
|
|
87
|
-
forceUpdate();
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
const handleClickOutside = (event: MouseEvent) => {
|
|
92
|
-
const target = event.target as HTMLElement;
|
|
93
|
-
if (!target.closest(".st-table-cell")) {
|
|
94
|
-
setSelectedCells([]);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
99
|
-
return () => {
|
|
100
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
101
|
-
};
|
|
102
|
-
}, [setSelectedCells]);
|
|
103
|
-
|
|
104
|
-
const currentRows = shouldPaginate
|
|
105
|
-
? sortedRows.slice(
|
|
106
|
-
(currentPage - 1) * rowsPerPage,
|
|
107
|
-
currentPage * rowsPerPage
|
|
108
|
-
)
|
|
109
|
-
: sortedRows;
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<div
|
|
113
|
-
ref={tableRef}
|
|
114
|
-
className="st-table-wrapper"
|
|
115
|
-
style={height ? { height } : {}}
|
|
116
|
-
>
|
|
117
|
-
<div
|
|
118
|
-
className="st-table"
|
|
119
|
-
onMouseUp={handleMouseUp}
|
|
120
|
-
onMouseLeave={handleMouseUp}
|
|
121
|
-
style={{
|
|
122
|
-
gridTemplateColumns: `${headersRef.current
|
|
123
|
-
?.map((header) => `${header.width}px`)
|
|
124
|
-
.join(" ")} 1fr`,
|
|
125
|
-
}}
|
|
126
|
-
>
|
|
127
|
-
<TableHeader
|
|
128
|
-
enableColumnResizing={enableColumnResizing}
|
|
129
|
-
forceUpdate={forceUpdate}
|
|
130
|
-
headersRef={headersRef}
|
|
131
|
-
isWidthDragging={isWidthDragging}
|
|
132
|
-
onSort={handleSort}
|
|
133
|
-
onTableHeaderDragEnd={onTableHeaderDragEnd}
|
|
134
|
-
setIsWidthDragging={setIsWidthDragging}
|
|
135
|
-
shouldDisplayLastColumnCell={shouldDisplayLastColumnCell}
|
|
136
|
-
/>
|
|
137
|
-
<TableBody
|
|
138
|
-
getBorderClass={getBorderClass}
|
|
139
|
-
handleMouseDown={handleMouseDown}
|
|
140
|
-
handleMouseOver={handleMouseOver}
|
|
141
|
-
headers={headersRef.current}
|
|
142
|
-
isSelected={isSelected}
|
|
143
|
-
isTopLeftCell={isTopLeftCell}
|
|
144
|
-
isWidthDragging={isWidthDragging}
|
|
145
|
-
shouldDisplayLastColumnCell={shouldDisplayLastColumnCell}
|
|
146
|
-
shouldPaginate={shouldPaginate}
|
|
147
|
-
sortedRows={currentRows}
|
|
148
|
-
/>
|
|
149
|
-
</div>
|
|
150
|
-
{shouldPaginate && (
|
|
151
|
-
<TableFooter
|
|
152
|
-
currentPage={currentPage}
|
|
153
|
-
hideFooter={hideFooter}
|
|
154
|
-
onPageChange={setCurrentPage}
|
|
155
|
-
rowsPerPage={rowsPerPage}
|
|
156
|
-
totalRows={sortedRows.length}
|
|
157
|
-
nextIcon={nextIcon}
|
|
158
|
-
prevIcon={prevIcon}
|
|
159
|
-
/>
|
|
160
|
-
)}
|
|
161
|
-
</div>
|
|
162
|
-
);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export default SimpleTable;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { createRef, Fragment } from "react";
|
|
2
|
-
import TableCell from "./TableCell";
|
|
3
|
-
import Animate from "../Animate";
|
|
4
|
-
import HeaderObject from "../../types/HeaderObject";
|
|
5
|
-
import TableLastColumnCell from "./TableLastColumnCell";
|
|
6
|
-
import TableRowSeparator from "./TableRowSeparator";
|
|
7
|
-
|
|
8
|
-
interface TableBodyProps {
|
|
9
|
-
getBorderClass: (rowIndex: number, columnIndex: number) => string;
|
|
10
|
-
handleMouseDown: (rowIndex: number, columnIndex: number) => void;
|
|
11
|
-
handleMouseOver: (rowIndex: number, columnIndex: number) => void;
|
|
12
|
-
headers: HeaderObject[];
|
|
13
|
-
isSelected: (rowIndex: number, columnIndex: number) => boolean;
|
|
14
|
-
isTopLeftCell: (rowIndex: number, columnIndex: number) => boolean;
|
|
15
|
-
isWidthDragging: boolean;
|
|
16
|
-
shouldDisplayLastColumnCell: boolean;
|
|
17
|
-
shouldPaginate: boolean;
|
|
18
|
-
sortedRows: { [key: string]: any }[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const TableBody = ({
|
|
22
|
-
getBorderClass,
|
|
23
|
-
handleMouseDown,
|
|
24
|
-
handleMouseOver,
|
|
25
|
-
headers,
|
|
26
|
-
isSelected,
|
|
27
|
-
isTopLeftCell,
|
|
28
|
-
isWidthDragging,
|
|
29
|
-
shouldDisplayLastColumnCell,
|
|
30
|
-
shouldPaginate,
|
|
31
|
-
sortedRows,
|
|
32
|
-
}: TableBodyProps & { shouldDisplayLastColumnCell: boolean }) => {
|
|
33
|
-
return (
|
|
34
|
-
<>
|
|
35
|
-
{sortedRows.map((row, rowIndex) => {
|
|
36
|
-
return (
|
|
37
|
-
<Fragment key={row.id}>
|
|
38
|
-
<Animate
|
|
39
|
-
allowHorizontalAnimate={shouldPaginate}
|
|
40
|
-
pause={isWidthDragging}
|
|
41
|
-
>
|
|
42
|
-
{headers.map((header, columnIndex) => {
|
|
43
|
-
let content = row[header.accessor];
|
|
44
|
-
|
|
45
|
-
if (header.cellRenderer) {
|
|
46
|
-
content = header.cellRenderer(row);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<TableCell
|
|
51
|
-
borderClass={getBorderClass(rowIndex, columnIndex)}
|
|
52
|
-
colIndex={columnIndex}
|
|
53
|
-
content={content}
|
|
54
|
-
isSelected={isSelected(rowIndex, columnIndex)}
|
|
55
|
-
isTopLeftCell={isTopLeftCell(rowIndex, columnIndex)}
|
|
56
|
-
key={header.accessor}
|
|
57
|
-
onMouseDown={() => handleMouseDown(rowIndex, columnIndex)}
|
|
58
|
-
onMouseOver={() => handleMouseOver(rowIndex, columnIndex)}
|
|
59
|
-
ref={createRef()}
|
|
60
|
-
rowIndex={rowIndex}
|
|
61
|
-
isLastRow={rowIndex === sortedRows.length - 1}
|
|
62
|
-
/>
|
|
63
|
-
);
|
|
64
|
-
})}
|
|
65
|
-
<TableLastColumnCell
|
|
66
|
-
isLastRow={rowIndex === sortedRows.length - 1}
|
|
67
|
-
ref={createRef()}
|
|
68
|
-
visible={shouldDisplayLastColumnCell}
|
|
69
|
-
/>
|
|
70
|
-
</Animate>
|
|
71
|
-
{rowIndex !== sortedRows.length - 1 && <TableRowSeparator />}
|
|
72
|
-
</Fragment>
|
|
73
|
-
);
|
|
74
|
-
})}
|
|
75
|
-
</>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export default TableBody;
|