├── .prettierignore ├── @axboot-datagrid ├── store │ └── index.ts ├── index.tsx ├── utils │ ├── number │ │ ├── index.ts │ │ ├── toFixed.ts │ │ ├── toNumber.ts │ │ └── toMoney.ts │ ├── delay.ts │ ├── useForceUpdate.tsx │ ├── getLineNumber.ts │ ├── index.ts │ ├── getCellValue.tsx │ ├── getFrozenColumnsWidth.ts │ ├── mouseEventSubscribe.ts │ ├── common.ts │ └── useBodyData.ts ├── components │ ├── TableColGroup.tsx │ ├── GripVertical.tsx │ ├── TableColGroupFrozen.tsx │ ├── TableFooter.tsx │ ├── TableBodyCell.tsx │ ├── TableSummaryFronzen.tsx │ ├── Loading.tsx │ ├── TableHeadColumn.tsx │ ├── Pagination.tsx │ ├── TableSummary.tsx │ ├── RowSelector.tsx │ ├── ColResizer.tsx │ ├── TableHeadFrozen.tsx │ ├── TableHead.tsx │ ├── TableBody.tsx │ └── TableBodyFrozen.tsx ├── style.css ├── AXDataGrid.tsx └── types.ts ├── public ├── favicon.ico └── vercel.svg ├── examples ├── editors │ ├── index.ts │ ├── InputEditor.tsx │ ├── SelectEditor.tsx │ └── DateEditor.tsx ├── ScrollExample.tsx ├── PagingExample.tsx ├── FocusExample.tsx ├── BasicExample.tsx ├── GetRowClassName.tsx ├── LineNumberExample.tsx ├── LoadingExample.tsx ├── ColumnsGroupExample.tsx ├── CellMergeExample.tsx ├── ReorderExample.tsx ├── EditorExample.tsx ├── useEditorGrid.tsx ├── SummaryExample.tsx ├── SortExample.tsx ├── CheckedExample.tsx └── ColumnSortExample.tsx ├── .prettierrc ├── components ├── BodyRoot.tsx ├── ExampleContainer.tsx ├── Layouts.tsx ├── Spinner.tsx └── Nav.tsx ├── pages ├── _document.tsx ├── api │ └── hello.ts ├── _app.tsx ├── focus.tsx ├── paging.tsx ├── index.tsx ├── sort.tsx ├── loading.tsx ├── summary.tsx ├── reorder.tsx ├── cellMerge.tsx ├── columnSort.tsx ├── lineNumber.tsx ├── radioBox.tsx ├── virtualScroll.tsx ├── propsChange.tsx ├── getRowClassName.tsx ├── editor.tsx └── columnGroup.tsx ├── .eslintrc.json ├── test └── index.test.tsx ├── styles └── globals.css ├── .npmignore ├── next.config.js ├── tsconfigs ├── tsconfig.es6.json └── tsconfig.es5.json ├── .gitignore ├── tsconfig.json ├── jest.config.js ├── tsconfig.build.json ├── LICENSE ├── hooks └── useContainerSize.ts ├── package.json └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | build/* 2 | node_modules/* 3 | public/* 4 | -------------------------------------------------------------------------------- /@axboot-datagrid/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createAppStore'; 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axisj/axboot-datagrid/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /@axboot-datagrid/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './AXDataGrid'; 2 | export * from './types'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/number/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./toFixed"; 2 | export * from "./toMoney"; 3 | export * from "./toNumber"; 4 | -------------------------------------------------------------------------------- /examples/editors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InputEditor'; 2 | export * from './SelectEditor'; 3 | export * from './DateEditor'; 4 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/number/toFixed.ts: -------------------------------------------------------------------------------- 1 | export function toFixed(value: number): number { 2 | return parseFloat(value.toFixed(2)); 3 | } 4 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/delay.ts: -------------------------------------------------------------------------------- 1 | export const delay = (ms: number, result?: T): Promise => 2 | new Promise(res => setTimeout(() => res(result as T), ms)); 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 120, 4 | "singleQuote": true, 5 | "jsxSingleQuote": true, 6 | "trailingComma": "all", 7 | "arrowParens": "avoid" 8 | } 9 | -------------------------------------------------------------------------------- /components/BodyRoot.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from '@emotion/styled'; 3 | 4 | const BodyRoot = styled.div` 5 | padding: 20px; 6 | `; 7 | 8 | export default BodyRoot; 9 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/number/toNumber.ts: -------------------------------------------------------------------------------- 1 | export function toNumber(value: unknown): number { 2 | let n: number = value as number; 3 | try { 4 | n = typeof value === 'number' ? value : Number(value || 0); 5 | } finally { 6 | } 7 | return n; 8 | } 9 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/useForceUpdate.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export function useForceUpdate() { 4 | const [value, setValue] = React.useState(0); // integer state 5 | return () => setValue(value => ++value); // update the state to force render 6 | } 7 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/getLineNumber.ts: -------------------------------------------------------------------------------- 1 | interface Props { 2 | dataLength: number; 3 | reorderable?: boolean; 4 | } 5 | 6 | export function getLineNumberWidth({ dataLength, reorderable }: Props) { 7 | return Math.max(`${dataLength}`.length * 9 + 7 * 2 + (reorderable ? 5 : 0), 30); 8 | } 9 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getCellValue'; 2 | export * from './getFrozenColumnsWidth'; 3 | export * from './mouseEventSubscribe'; 4 | export * from './common'; 5 | export * from './useForceUpdate'; 6 | export * from './delay'; 7 | export * from './getLineNumber'; 8 | export * from './useBodyData'; 9 | -------------------------------------------------------------------------------- /components/ExampleContainer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from '@emotion/styled'; 3 | 4 | const ExampleContainer = styled.div` 5 | font-size: 13px; 6 | position: absolute; 7 | overflow: hidden; 8 | width: 100%; 9 | height: 400px; 10 | `; 11 | 12 | export default ExampleContainer; 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "plugins": [ 4 | // ... 5 | "react-hooks" 6 | ], 7 | "rules": { 8 | // ... 9 | "react-hooks/rules-of-hooks": "error", // For checking rules of hooks 10 | "react-hooks/exhaustive-deps": "warn" // For checking hook dependencies 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/index.test.tsx: -------------------------------------------------------------------------------- 1 | // __tests__/index.test.jsx 2 | 3 | import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; 4 | import Home from '../pages/index'; 5 | import '@testing-library/jest-dom'; 6 | 7 | let container; 8 | 9 | describe('Home', () => { 10 | it('renders a heading', async () => {}); 11 | }); 12 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/number/toMoney.ts: -------------------------------------------------------------------------------- 1 | import { toNumber } from './'; 2 | 3 | export function toMoney(value: unknown): string { 4 | const n = toNumber(value); 5 | 6 | return Number.isNaN(n) 7 | ? String(value) 8 | : n 9 | .toFixed(0) 10 | .toString() 11 | .replace(/\B(?=(\d{3})+(?!\d))/g, ','); 12 | } 13 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.next 3 | /components 4 | /examples 5 | /node_modules 6 | /pages 7 | /public 8 | /@axboot-datagrid 9 | /styles 10 | /test 11 | /tsconfigs 12 | .eslintrc.json 13 | .gitignore 14 | .npmignore 15 | .prettierignore 16 | .prettierrc 17 | jest.config.js 18 | next.config.js 19 | next-env.d.ts 20 | package-lock.json 21 | tsconfig.build.json 22 | tsconfig.json 23 | -------------------------------------------------------------------------------- /pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const withLess = require('next-with-less'); 2 | 3 | module.exports = withLess({ 4 | lessLoaderOptions: { 5 | lessOptions: { 6 | javascriptEnabled: true, 7 | }, 8 | }, 9 | webpack(config, options) { 10 | config.module.rules.push({ 11 | test: /\.md$/, 12 | use: 'raw-loader', 13 | }); 14 | return config; 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /@axboot-datagrid/utils/getCellValue.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function getCellValueByRowKey(rowKey: React.Key | React.Key[], values: T) { 4 | if (Array.isArray(rowKey)) { 5 | return rowKey.reduce((acc, cur) => { 6 | if (!acc) return acc; 7 | if (cur in acc) return acc[cur]; 8 | return ''; 9 | }, values as Record); 10 | } else { 11 | return (values as Record)[rowKey]; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /components/Layouts.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import React from 'react'; 3 | import Nav from './Nav'; 4 | 5 | interface ContainerProps { 6 | children?: React.ReactNode; 7 | } 8 | 9 | export const Container: React.FC = ({ children }) => { 10 | return ( 11 | 12 |