diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 00000000..2e764cea
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,196 @@
+const rulesReact = {
+ 'react/prop-types': 'off',
+ 'react/display-name': 'off',
+ 'react/no-unescaped-entities': 'off',
+ 'react-perf/jsx-no-new-function-as-prop': 'off',
+
+ 'react/jsx-key': 'warn',
+ 'react/jsx-pascal-case': 'warn',
+ 'react/self-closing-comp': 'warn',
+ 'react/no-unstable-nested-components': 'warn',
+ 'react-perf/jsx-no-new-array-as-prop': 'warn',
+ 'react-perf/jsx-no-new-object-as-prop': 'warn',
+ 'react/jsx-sort-props': [
+ 'warn',
+ {
+ callbacksLast: true,
+ shorthandFirst: true,
+ shorthandLast: false,
+ ignoreCase: true,
+ noSortAlphabetically: true,
+ reservedFirst: false
+ }
+ ],
+
+ 'react/no-danger': 'error',
+ 'react/jsx-boolean-value': 'error',
+ 'react/boolean-prop-naming': 'error'
+}
+
+const rulesEslint = {
+ 'no-redeclare': 'off',
+ 'default-param-last': 'off',
+ 'no-duplicate-imports': 'off',
+ 'no-use-before-define': 'off',
+ 'no-unused-expressions': 'off',
+
+ radix: 'warn',
+ 'no-nested-ternary': 'warn',
+ 'no-else-return': ['warn', { allowElseIf: false }],
+
+ 'no-var': 'error',
+ 'no-sequences': 'error',
+ 'no-console': ['error', { allow: ['error'] }],
+ 'prefer-const': ['error', { destructuring: 'all' }],
+
+ '@stylistic/max-len': ['error', { code: 85 }],
+ '@stylistic/key-spacing': [
+ 'error',
+ { beforeColon: false, afterColon: true }
+ ],
+ '@stylistic/padding-line-between-statements': [
+ 'error',
+ { blankLine: 'always', prev: '*', next: 'return' },
+ { blankLine: 'always', prev: ['const', 'let'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let'],
+ next: ['const', 'let']
+ },
+ {
+ blankLine: 'always',
+ prev: ['if', 'function', 'for'],
+ next: ['if', 'function', 'for']
+ }
+ ]
+}
+
+const rulesImport = {
+ 'import/no-duplicates': 'error',
+ 'import/order': [
+ 'error',
+ {
+ groups: [
+ 'external',
+ 'builtin',
+ 'type',
+ 'internal',
+ 'parent',
+ 'sibling',
+ 'index'
+ ],
+ pathGroups: [
+ {
+ pattern: 'react',
+ group: 'external',
+ position: 'before'
+ },
+ {
+ pattern: 'react-**',
+ group: 'external',
+ position: 'before'
+ },
+ {
+ pattern: 'react-dom/**',
+ group: 'external',
+ position: 'before'
+ },
+ {
+ pattern: '../styles',
+ group: 'index',
+ position: 'after'
+ },
+ {
+ pattern: './styles',
+ group: 'index',
+ position: 'after'
+ },
+ {
+ pattern: '@/theme',
+ group: 'index',
+ position: 'after'
+ }
+ ],
+ pathGroupsExcludedImportTypes: ['react', 'react-dom'],
+ 'newlines-between': 'never',
+ alphabetize: {
+ order: 'asc',
+ caseInsensitive: true
+ }
+ }
+ ]
+}
+
+const rulesTypescript = {
+ '@typescript-eslint/no-namespace': 'off',
+ '@typescript-eslint/no-inferrable-types': 'off',
+ '@typescript-eslint/no-confusing-void-expression': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+
+ '@typescript-eslint/ban-types': 'warn',
+ '@typescript-eslint/no-var-requires': 'warn',
+ '@typescript-eslint/no-unsafe-argument': 'warn',
+ '@typescript-eslint/no-non-null-assertion': 'warn',
+ '@typescript-eslint/no-unused-expressions': 'warn',
+ '@typescript-eslint/prefer-optional-chain': 'warn',
+ '@typescript-eslint/restrict-plus-operands': 'warn',
+ '@typescript-eslint/no-unnecessary-condition': 'warn',
+ '@typescript-eslint/switch-exhaustiveness-check': 'warn',
+ '@typescript-eslint/prefer-reduce-type-parameter': 'warn',
+ '@typescript-eslint/no-unnecessary-type-constraint': 'warn',
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'warn',
+
+ '@typescript-eslint/no-redeclare': 'error',
+ '@typescript-eslint/no-explicit-any': 'error',
+ '@typescript-eslint/default-param-last': 'error',
+ '@typescript-eslint/no-use-before-define': 'error',
+ '@typescript-eslint/consistent-type-imports': 'error'
+}
+
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true
+ },
+ sourceType: 'module',
+ project: ['./tsconfig.json']
+ },
+ settings: {
+ react: {
+ version: 'detect'
+ },
+ 'import/parsers': {
+ '@typescript-eslint/parser': ['.ts', '.tsx']
+ },
+ 'import/resolver': {
+ typescript: true
+ }
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/jsx-runtime',
+ 'plugin:react-hooks/recommended',
+ 'plugin:react/recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
+ 'plugin:prettier/recommended',
+ 'prettier'
+ ],
+ rules: {
+ 'prettier/prettier': 'error',
+ ...rulesReact,
+ ...rulesEslint,
+ ...rulesImport,
+ ...rulesTypescript
+ },
+ plugins: [
+ 'react-hooks',
+ 'react-perf',
+ '@typescript-eslint',
+ 'import',
+ '@stylistic'
+ ],
+ ignorePatterns: ['.eslintrc.js']
+}
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index d4fce68f..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,173 +0,0 @@
-{
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "jsx": true,
- "useJSXTextNode": true
- },
- "extends": [
- "plugin:@typescript-eslint/recommended",
- "plugin:react/recommended",
- "plugin:react-hooks/recommended",
- "plugin:prettier/recommended",
- "eslint:recommended",
- "prettier",
- "plugin:ramda/recommended"
- ],
- "rules": {
- "@typescript-eslint/ban-types": 1,
- "prettier/prettier": [
- "error",
- {
- "singleQuote": true,
- "parser": "typescript",
- "arrowParens": "avoid"
- }
- ],
- "@typescript-eslint/no-use-before-define": "off",
- "template-curly-spacing": "warn",
- "no-sequences": "error",
- "spaced-comment": ["error", "always"],
- "key-spacing": [
- "error",
- {
- "mode": "strict"
- }
- ],
- "max-len": [
- "error",
- {
- "code": 85
- }
- ],
- "max-lines": [
- "error",
- {
- "max": 350,
- "skipBlankLines": true
- }
- ],
- "prefer-const": [
- "error",
- {
- "destructuring": "all"
- }
- ],
- "no-var": "error",
- "newline-before-return": "error",
- "arrow-parens": ["error", "as-needed"],
- "no-bitwise": "error",
- "max-classes-per-file": "error",
- "no-duplicate-imports": "error",
- "lines-between-class-members": ["error", "always"],
- "padding-line-between-statements": [
- "error",
- {
- "blankLine": "always",
- "prev": "*",
- "next": "return"
- }
- ],
- "sort-imports": [
- "error",
- {
- "ignoreCase": true,
- "ignoreDeclarationSort": true,
- "ignoreMemberSort": true,
- "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
- }
- ],
- "no-irregular-whitespace": "error",
- "space-before-blocks": "error",
- "no-multi-spaces": "error",
- "no-trailing-spaces": "error",
- "no-whitespace-before-property": "error",
- "curly": "error",
- "no-undef": "off",
- "no-case-declarations": "off",
- "indent": "off",
- "no-unused-vars": ["off"],
- "no-console": [
- "error",
- {
- "allow": ["log", "error"]
- }
- ],
- "comma-dangle": ["error", "never"],
- "semi": ["error", "never"],
- "no-multiple-empty-lines": [
- "error",
- {
- "max": 1
- }
- ],
- "quotes": ["error", "single"],
- "eol-last": ["error", "always"],
- "no-new-wrappers": "error",
- "arrow-spacing": [
- "error",
- {
- "after": true,
- "before": true
- }
- ],
- "object-curly-spacing": ["error", "always"],
- "react/jsx-closing-bracket-location": [
- 1,
- {
- "selfClosing": "line-aligned",
- "nonEmpty": "after-props"
- }
- ],
- "react/prop-types": "off",
- "react/display-name": "off",
- "react/jsx-boolean-value": "off",
- "react/jsx-wrap-multilines": "off",
- "react/no-unescaped-entities": "off",
- "prefer-arrow/prefer-arrow-functions": [
- "warn",
- {
- "disallowPrototype": true,
- "singleReturnOnly": true,
- "classPropertiesAllowed": false
- }
- ],
- "@typescript-eslint/no-unused-vars": [
- "error",
- {
- "ignoreRestSiblings": true
- }
- ],
- "@typescript-eslint/no-explicit-any": "error",
- "@typescript-eslint/member-ordering": [
- "error",
- {
- "classes": [
- "public-static-field",
- "public-instance-field",
- "private-static-field",
- "private-instance-field",
- "private-constructor",
- "public-constructor",
- "private-instance-method",
- "protected-instance-method",
- "public-instance-method"
- ]
- }
- ],
- "@typescript-eslint/prefer-interface": "off",
- "@typescript-eslint/explicit-member-accessibility": "off",
- "@typescript-eslint/no-var-requires": "off",
- "@typescript-eslint/no-non-null-assertion": "off",
- "@typescript-eslint/no-object-literal-type-assertion": "off",
- "@typescript-eslint/interface-name-prefix": "off",
- "@typescript-eslint/array-type": "off",
- "@typescript-eslint/explicit-function-return-type": "off"
- },
- "plugins": ["react", "prefer-arrow", "@typescript-eslint", "ramda", "eslint-plugin-prettier"],
- "settings": {
- "react": {
- "pragma": "React",
- "version": "16.8.6"
- }
- }
-}
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..04c01ba7
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+node_modules/
+dist/
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index dade0ceb..00000000
--- a/.prettierrc
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "trailingComma": "none",
- "tabWidth": 4,
- "semi": false,
- "jsxBracketSameLine": true,
- "jsxSingleQuote": true,
- "singleQuote": true,
- "parser": "typescript",
- "arrowParens": "avoid"
-}
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 00000000..2d0a7f45
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,11 @@
+singleQuote: true
+semi: false
+trailingComma: none
+bracketSameLine: true
+jsxSingleQuote: true
+tabWidth: 4
+arrowParens: avoid
+printWidth: 80
+parser: typescript
+bracketSpacing: true
+useTabs: false
\ No newline at end of file
diff --git a/package.json b/package.json
index bcf68521..d186afca 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,11 @@
{
"name": "flipper-ui",
- "version": "0.30.10",
+ "version": "0.4.0",
"description": "",
"main": "dist/index.js",
"homepage": "https://flipper-ui.ngi.com.br/",
+ "author": "NG Informática",
+ "license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/nginformatica/flipper-ui.git"
@@ -12,26 +14,26 @@
"wrap-ansi": "7.0.0"
},
"scripts": {
- "test": "jest --silent --passWithNoTests --noStackTrace --runInBand",
- "test:ci": "yarn test --coverage",
"start": "storybook dev -p 6006",
- "clean": "rm -rf ./dist/*",
- "copy:package": "cp package.json dist/",
- "publish:yalc": "cd dist/ && yalc publish && cd ..",
"build": "yarn clean && yarn build:ts && yarn build:babel",
- "build:link": "yarn build && yarn copy:package && yarn publish:yalc",
"build:ts": "tsc --emitDeclarationOnly",
"build:babel": "babel src --out-dir dist --extensions \".ts,.tsx\" --ignore \"**/*.spec.tsx\" --ignore \"**/*.stories.tsx\"",
- "lint": "eslint -c .eslintrc.json 'src/**/*.{ts,tsx}'",
- "lint:fix": "eslint -c .eslintrc.json --fix 'src/**/*.{ts,tsx}'",
- "predeploy": "yarn build && yarn storybook:build",
+ "build:link": "yarn build && yarn copy:package && yarn publish:yalc",
+ "lint": "eslint -c .eslintrc.js 'src/**/*.{ts,tsx}'",
+ "lint:fix": "eslint -c .eslintrc.js --fix 'src/**/*.{ts,tsx}'",
+ "lint:quiet": "eslint --quiet .eslintrc.js 'src/**/*.{ts,tsx}'",
+ "format": "prettier -w 'src/**/*.{ts,tsx}'",
"docs:build": "storybook build -o docs",
+ "clean": "rm -rf ./dist/*",
"type-check": "tsc --noEmit",
+ "copy:package": "cp package.json dist/",
+ "publish:yalc": "cd dist/ && yalc publish && cd ..",
+ "predeploy": "yarn build && yarn storybook:build",
"deploy": "gh-pages -d docs",
- "release": "yarn build && node pre-publish.js && npm publish ./dist --access public"
+ "release": "yarn build && node pre-publish.js && npm publish ./dist --access public",
+ "test:ci": "yarn test --coverage",
+ "test": "jest --silent --passWithNoTests --noStackTrace --runInBand"
},
- "author": "NG Informática",
- "license": "MIT",
"dependencies": {
"@date-io/date-fns": "1.3.6",
"@emotion/react": "11.11.3",
@@ -40,9 +42,9 @@
"@material-ui/icons": "4.11.3",
"@material-ui/lab": "4.0.0-alpha.61",
"@material-ui/pickers": "3.3.11",
- "@mui/icons-material": "5.15.3",
- "@mui/material": "5.15.3",
- "@mui/styles": "5.15.3",
+ "@mui/icons-material": "5.15.6",
+ "@mui/material": "5.15.6",
+ "@mui/styles": "5.15.6",
"date-fns": "2.30.0",
"faker": "5.5.3",
"material-table": "1.69.3",
@@ -58,56 +60,52 @@
"@babel/cli": "7.23.4",
"@babel/core": "7.23.7",
"@babel/plugin-transform-runtime": "7.23.7",
- "@babel/preset-env": "7.23.7",
+ "@babel/preset-env": "7.23.8",
"@babel/preset-typescript": "7.23.3",
- "@storybook/addon-essentials": "7.6.7",
+ "@storybook/addon-essentials": "7.6.10",
"@storybook/addon-styling-webpack": "0.0.6",
- "@storybook/react": "7.6.7",
- "@storybook/react-webpack5": "7.6.7",
+ "@storybook/react": "7.6.10",
+ "@storybook/react-webpack5": "7.6.10",
+ "@stylistic/eslint-plugin": "1.5.4",
"@testing-library/react": "14.1.2",
"@testing-library/user-event": "14.5.2",
"@types/faker": "5.5.3",
"@types/history": "5.0.0",
"@types/jest": "29.5.11",
- "@types/node": "20.10.6",
+ "@types/node": "20.11.6",
"@types/ramda": "0.25.36",
- "@types/react": "18.2.46",
- "@types/react-router": "5.1.20",
- "@types/react-router-dom": "5.3.3",
+ "@types/react": "18.2.48",
"@types/sprintf-js": "1.1.4",
"@types/styled-components": "5.1.34",
"@types/uuid": "9.0.7",
- "@typescript-eslint/eslint-plugin": "6.17.0",
- "@typescript-eslint/parser": "6.17.0",
+ "@typescript-eslint/eslint-plugin": "6.19.1",
+ "@typescript-eslint/parser": "6.19.1",
"babel-loader": "9.1.3",
"babel-plugin-module-resolver": "5.0.0",
"babel-plugin-transform-class-properties": "6.24.1",
"babel-plugin-transform-imports": "2.0.0",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
+ "eslint-import-resolver-typescript": "3.6.1",
"eslint-plugin-import": "2.29.1",
- "eslint-plugin-prefer-arrow": "1.2.3",
- "eslint-plugin-prettier": "5.1.2",
- "eslint-plugin-ramda": "2.5.1",
+ "eslint-plugin-prettier": "5.1.3",
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
- "eslint-plugin-storybook": "0.6.15",
+ "eslint-plugin-react-perf": "3.3.2",
"fs-extra": "11.2.0",
"identity-obj-proxy": "3.0.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"node-fetch": "3.3.2",
- "prettier": "3.1.1",
+ "prettier": "3.2.4",
"react": "18.2.0",
"react-dom": "18.2.0",
- "react-router": "6.21.1",
- "react-router-dom": "6.21.1",
- "storybook": "7.6.7",
- "styled-components": "6.1.6",
- "ts-jest": "29.1.1",
+ "storybook": "7.6.10",
+ "styled-components": "6.1.8",
+ "ts-jest": "29.1.2",
"ts-loader": "9.5.1",
"typescript": "5.3.3",
- "webpack": "5.89.0"
+ "webpack": "5.90.0"
},
"peerDependencies": {
"date-fns": "^2.30.0",
diff --git a/src/core/context/theme-provider/index.tsx b/src/core/context/theme-provider/index.tsx
index e442db72..2cb6e238 100644
--- a/src/core/context/theme-provider/index.tsx
+++ b/src/core/context/theme-provider/index.tsx
@@ -1,13 +1,11 @@
-import {
- createTheme,
- ThemeOptions,
- ThemeProvider
-} from '@material-ui/core/styles'
import React from 'react'
+import type { ReactNode } from 'react'
+import { createTheme, ThemeProvider } from '@material-ui/core/styles'
+import type { ThemeOptions } from '@material-ui/core/styles'
interface ThemeProviderProps {
options?: ThemeOptions
- children: React.ReactNode
+ children: ReactNode
}
const ThemeProviderFlipper = ({
diff --git a/src/core/context/theme-provider/theme-provider.spec.tsx b/src/core/context/theme-provider/theme-provider.spec.tsx
index ea12c80a..1abe4c91 100644
--- a/src/core/context/theme-provider/theme-provider.spec.tsx
+++ b/src/core/context/theme-provider/theme-provider.spec.tsx
@@ -10,6 +10,7 @@ describe('ThemeProvider', () => {
)
const child = screen.getByText('Test')
+
expect(child).toBeDefined()
})
})
diff --git a/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap b/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap
index 77696936..c65d9955 100644
--- a/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap
+++ b/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap
@@ -3,7 +3,7 @@
exports[`Advertise should match snapshot 1`] = `
diff --git a/src/core/data-display/advertise/advertise.spec.tsx b/src/core/data-display/advertise/advertise.spec.tsx
index cdb89cd3..0803b296 100644
--- a/src/core/data-display/advertise/advertise.spec.tsx
+++ b/src/core/data-display/advertise/advertise.spec.tsx
@@ -3,6 +3,9 @@ import { render, screen } from '@testing-library/react'
import Advertise from '.'
describe('Advertise', () => {
+ const newPadding = '10px 10px'
+ const CUSTOM = { padding: newPadding }
+
it('should render', () => {
render(
)
@@ -17,12 +20,9 @@ describe('Advertise', () => {
it('should render with custom author style', () => {
const newPadding = '10px 10px'
+
render(
-
+
)
const author = screen.getByText('author')
@@ -33,11 +33,12 @@ describe('Advertise', () => {
it('should render with custom comment style', () => {
const newPadding = '10px 10px'
+
render(
)
@@ -51,6 +52,7 @@ describe('Advertise', () => {
const { container } = render(
)
+
expect(container).toMatchSnapshot()
})
})
diff --git a/src/core/data-display/advertise/advertise.stories.tsx b/src/core/data-display/advertise/advertise.stories.tsx
index 6dc48ec0..96b81d88 100644
--- a/src/core/data-display/advertise/advertise.stories.tsx
+++ b/src/core/data-display/advertise/advertise.stories.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { Meta, StoryFn } from '@storybook/react'
+import type { Meta, StoryFn } from '@storybook/react'
import Advertise from '.'
export default {
diff --git a/src/core/data-display/advertise/index.tsx b/src/core/data-display/advertise/index.tsx
index a920cd9c..6a0e7e94 100644
--- a/src/core/data-display/advertise/index.tsx
+++ b/src/core/data-display/advertise/index.tsx
@@ -1,8 +1,9 @@
import React from 'react'
-import styled from 'styled-components'
-import MuiPaper from '@/core/surfaces/paper'
-import Typography from '@/core/data-display/typography'
+import type { CSSProperties } from 'react'
+import { default as styled } from 'styled-components'
import type { DefaultProps } from '../../types'
+import { Typography } from '@/core/data-display/typography'
+import MuiPaper from '@/core/surfaces/paper'
import { theme } from '@/theme'
const { grays } = theme.colors
@@ -20,12 +21,12 @@ export interface AdvertiseProps extends DefaultProps {
* The style of the comment
* @optional
*/
- commentStyle?: React.CSSProperties
+ commentStyle?: CSSProperties
/**
* The style of the author
* @optional
*/
- authorStyle?: React.CSSProperties
+ authorStyle?: CSSProperties
}
const styles = {
diff --git a/src/core/data-display/avatar/avatar.spec.tsx b/src/core/data-display/avatar/avatar.spec.tsx
index 4cc58b0b..9c388b1e 100644
--- a/src/core/data-display/avatar/avatar.spec.tsx
+++ b/src/core/data-display/avatar/avatar.spec.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import { render, screen } from '@testing-library/react'
-import Avatar from '.'
-import Typography from '@/core/data-display/typography'
+import { Typography } from '@/core/data-display/typography'
+import { Avatar } from '.'
describe('Avatar', () => {
it('should render first letter', () => {
@@ -30,6 +30,7 @@ describe('Avatar', () => {
it('should render with custom className', () => {
const customClass = 'custom-class'
+
render(
{
it('should render', () => {
@@ -29,6 +29,7 @@ describe('Badge', () => {
describe('Badges - Snapshots', () => {
it('should match snapshot', () => {
const { container } = render(Badge)
+
expect(container).toMatchSnapshot()
})
})
diff --git a/src/core/data-display/badge/badge.stories.tsx b/src/core/data-display/badge/badge.stories.tsx
index bfc6d8c7..0dce0a80 100644
--- a/src/core/data-display/badge/badge.stories.tsx
+++ b/src/core/data-display/badge/badge.stories.tsx
@@ -1,7 +1,7 @@
import React from 'react'
-import { Meta, StoryFn } from '@storybook/react'
-import Badge from '.'
-import Button from '@/core/inputs/button'
+import type { Meta, StoryFn } from '@storybook/react'
+import { Button } from '@/core/inputs/button'
+import { Badge } from '.'
export default {
title: 'DataDisplay/Badge',
diff --git a/src/core/data-display/badge/index.tsx b/src/core/data-display/badge/index.tsx
index 71c941a3..ad2dd811 100644
--- a/src/core/data-display/badge/index.tsx
+++ b/src/core/data-display/badge/index.tsx
@@ -1,11 +1,12 @@
-import { Badge as MuiBadge } from '@material-ui/core'
import React from 'react'
-import { BadgeProps as MuiBadgeProps } from '@material-ui/core/Badge'
+import type { ReactNode } from 'react'
+import { Badge as MuiBadge } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import type { DefaultProps } from '../../types'
+import type { BadgeProps as MuiBadgeProps } from '@material-ui/core/Badge'
export interface BadgeProps extends DefaultProps, MuiBadgeProps {
- children: React.ReactNode
+ children: ReactNode
/**
* The number to display in the badge.
*/
diff --git a/src/core/data-display/chapter/chapter.spec.tsx b/src/core/data-display/chapter/chapter.spec.tsx
index 5f63ea36..03b4a475 100644
--- a/src/core/data-display/chapter/chapter.spec.tsx
+++ b/src/core/data-display/chapter/chapter.spec.tsx
@@ -1,11 +1,12 @@
import * as React from 'react'
import { render, screen } from '@testing-library/react'
-import Chapter from '.'
+import { Chapter } from '.'
describe('Chapter', () => {
it('should render', () => {
render(Chapter)
const chapter = screen.getByText('Chapter')
+
expect(chapter).toBeDefined()
})
@@ -16,6 +17,7 @@ describe('Chapter', () => {
)
const chapter = screen.getByTestId('chapter-container')
+
expect(chapter).toBeDefined()
})
})
diff --git a/src/core/data-display/chapter/chapter.stories.tsx b/src/core/data-display/chapter/chapter.stories.tsx
index e406fdb4..3885f704 100644
--- a/src/core/data-display/chapter/chapter.stories.tsx
+++ b/src/core/data-display/chapter/chapter.stories.tsx
@@ -1,6 +1,6 @@
import React from 'react'
-import { Meta, StoryFn } from '@storybook/react'
-import Chapter from '.'
+import type { Meta, StoryFn } from '@storybook/react'
+import { Chapter } from '.'
export default {
title: 'DataDisplay/Chapter',
diff --git a/src/core/data-display/chapter/index.tsx b/src/core/data-display/chapter/index.tsx
index 1ea56b78..21e793df 100644
--- a/src/core/data-display/chapter/index.tsx
+++ b/src/core/data-display/chapter/index.tsx
@@ -1,8 +1,9 @@
-import React, { CSSProperties } from 'react'
-import styled from 'styled-components'
-import { DefaultProps } from '../../types'
-import Typography from '@/core/data-display/typography'
+import React from 'react'
+import type { CSSProperties, ReactNode } from 'react'
+import { default as styled } from 'styled-components'
+import type { DefaultProps } from '../../types'
import type { TypographyProps } from '@material-ui/core/Typography'
+import { Typography } from '@/core/data-display/typography'
import { theme } from '@/theme'
const { grays } = theme.colors
@@ -27,7 +28,7 @@ export interface LineProps extends DefaultProps {
/**
* The children of the component.
*/
- children?: React.ReactNode
+ children?: ReactNode
'data-testid'?: string
}
diff --git a/src/core/data-display/chip/chip.spec.tsx b/src/core/data-display/chip/chip.spec.tsx
index 286544b0..1a112523 100644
--- a/src/core/data-display/chip/chip.spec.tsx
+++ b/src/core/data-display/chip/chip.spec.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import { render, screen, waitFor } from '@testing-library/react'
-import Chip from '.'
+import { Chip } from '.'
describe('Chip', () => {
it('should render', () => {
@@ -27,6 +27,7 @@ describe('Chip', () => {
it('should call onDelete', () => {
const onDelete = jest.fn()
+
render()
const svg = screen.getByRole('button')
diff --git a/src/core/data-display/chip/chip.stories.tsx b/src/core/data-display/chip/chip.stories.tsx
index 8375c821..d37043a1 100644
--- a/src/core/data-display/chip/chip.stories.tsx
+++ b/src/core/data-display/chip/chip.stories.tsx
@@ -1,8 +1,8 @@
import React from 'react'
-import { Meta, StoryFn } from '@storybook/react'
-import Chip from '.'
-import Avatar from '@/core/data-display/avatar'
-import { Face } from '../../../icons'
+import type { Meta, StoryFn } from '@storybook/react'
+import { Avatar } from '@/core/data-display/avatar'
+import { Face } from '@/icons'
+import { Chip } from '.'
export default {
title: 'DataDisplay/Chip',
diff --git a/src/core/data-display/chip/index.tsx b/src/core/data-display/chip/index.tsx
index 838c4bc3..0a2b76f9 100644
--- a/src/core/data-display/chip/index.tsx
+++ b/src/core/data-display/chip/index.tsx
@@ -1,7 +1,8 @@
-import { Chip as MuiChip, ChipProps as MuiChipProps } from '@material-ui/core'
-import { makeStyles } from '@material-ui/core/styles'
import React from 'react'
-import { DefaultProps } from '../../types'
+import { Chip as MuiChip } from '@material-ui/core'
+import { makeStyles } from '@material-ui/core/styles'
+import type { DefaultProps } from '../../types'
+import type { ChipProps as MuiChipProps } from '@material-ui/core'
export interface IChipProps
extends MuiChipProps,
diff --git a/src/core/data-display/data-table/data-table-action.tsx b/src/core/data-display/data-table/data-table-action.tsx
index 2de5f882..ddf384fa 100644
--- a/src/core/data-display/data-table/data-table-action.tsx
+++ b/src/core/data-display/data-table/data-table-action.tsx
@@ -1,4 +1,5 @@
-import React, { ReactNode } from 'react'
+import type { ReactNode } from 'react'
+import React from 'react'
import IconButton from '@material-ui/core/IconButton'
export type DataTableActionProps = {
diff --git a/src/core/data-display/data-table/data-table-field.tsx b/src/core/data-display/data-table/data-table-field.tsx
new file mode 100644
index 00000000..eafe6758
--- /dev/null
+++ b/src/core/data-display/data-table/data-table-field.tsx
@@ -0,0 +1,268 @@
+// eslint-disable-next-line @typescript-eslint/consistent-type-imports
+import React from 'react'
+import type { ChangeEvent, Dispatch, SetStateAction } from 'react'
+import {
+ Checkbox,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { default as styled } from 'styled-components'
+import { TextField } from '@/index'
+
+interface IHeader {
+ title: string
+ field: string
+ type?: string
+ editable?: boolean
+}
+
+interface ITable> {
+ rows: D[]
+ setRows: Dispatch>
+ header: IHeader[]
+ checkbox?: boolean
+ checkboxProps?: {
+ checkRow?: boolean[]
+ checkAllRows?: boolean
+ setSelectedRow?: Dispatch>
+ setSelectedAllRows?: Dispatch>
+ }
+}
+
+const TableCellRows = styled(TableCell)`
+ && {
+ width: 400px;
+ height: 60px;
+ padding: 0 10px;
+ }
+`
+
+const RowTable = styled(TableRow)`
+ width: 100%;
+ cursor: pointer;
+
+ &:hover {
+ background: -moz-linear-gradient(
+ left,
+ rgba(189, 189, 189, 0) 0%,
+ rgba(189, 189, 189, 1) 100%
+ );
+ background: -webkit-linear-gradient(
+ left,
+ rgba(189, 189, 189, 0) 0%,
+ rgba(189, 189, 189, 1) 100%
+ );
+ background: linear-gradient(
+ to right,
+ rgba(189, 189, 189, 0) 0%,
+ rgba(189, 189, 189, 1) 100%
+ );
+ }
+
+ &.no-hover {
+ background: none;
+ }
+`
+
+export const DataTableField = >(
+ props: ITable
+) => {
+ const { rows, header, checkbox, checkboxProps, setRows } = props
+
+ const handleFieldChange = (
+ event: ChangeEvent,
+ fieldName: keyof D,
+ rowIndex: number,
+ setRows: Dispatch>
+ ) => {
+ const { value } = event.target
+
+ setRows(prevRows => {
+ const updatedRows = prevRows.map((row, i) => {
+ if (i === rowIndex) {
+ return {
+ ...row,
+ [fieldName]: value
+ }
+ }
+
+ return row
+ })
+
+ return updatedRows as D[]
+ })
+ }
+
+ const handleSelectCheckbox = (
+ index: number,
+ setSelected: Dispatch>,
+ setSelectedAll: Dispatch>
+ ) => {
+ setSelected(state => {
+ const newState = state.map((row, i: number) =>
+ index === i ? !row : row
+ )
+
+ if (newState.includes(false)) {
+ setSelectedAll(false)
+ }
+
+ if (newState.every(item => item === true)) {
+ setSelectedAll(true)
+ }
+
+ return newState
+ })
+ }
+
+ const handleSelectAllCheckbox = (
+ setSelected: Dispatch>,
+ setSelectedAll: Dispatch>
+ ) => {
+ setSelectedAll(selectedAll => !selectedAll)
+ setSelected(state =>
+ state.map(() =>
+ checkboxProps !== undefined
+ ? !checkboxProps.checkAllRows
+ : false
+ )
+ )
+ }
+
+ const handleSelect = (index: number) => {
+ if (checkboxProps?.setSelectedRow && checkboxProps.setSelectedAllRows) {
+ handleSelectCheckbox(
+ index,
+ checkboxProps.setSelectedRow,
+ checkboxProps.setSelectedAllRows
+ )
+ }
+ }
+
+ const handleTableRow = (
+ event: React.MouseEvent,
+ index: number
+ ) => {
+ const isCheckboxClick =
+ (event.target as HTMLElement).closest('input[type="checkbox"]') !==
+ null
+
+ if (
+ !isCheckboxClick &&
+ (!checkboxProps?.checkRow || !checkboxProps.checkRow[index])
+ ) {
+ handleSelect(index)
+ }
+ }
+
+ const tableBody = (rows: D[], header: IHeader[]) =>
+ rows.map((row, index) => {
+ const columns = header.map((column, i) => {
+ if (Object.keys(row).includes(column.field)) {
+ return (
+
+ {column.editable &&
+ checkboxProps?.checkRow &&
+ checkboxProps.checkRow[index] ? (
+ event.stopPropagation()}
+ onChange={event =>
+ handleFieldChange(
+ event,
+ column.field,
+ index,
+ setRows
+ )
+ }
+ />
+ ) : (
+
+ {column.editable
+ ? checkboxProps?.checkRow?.[index]
+ ? (row[column.field] as string)
+ : ''
+ : (row[column.field] as string)}
+
+ )}
+
+ )
+ }
+
+ return
+ })
+
+ return (
+ handleTableRow(event, index)}>
+ {checkbox && (
+
+ handleSelect(index)}
+ />
+
+ )}
+ {columns}
+
+ )
+ })
+
+ return (
+
+
+ {checkbox && (
+
+ {
+ if (
+ checkboxProps?.setSelectedRow &&
+ checkboxProps.setSelectedAllRows
+ ) {
+ handleSelectAllCheckbox(
+ checkboxProps.setSelectedRow,
+ checkboxProps.setSelectedAllRows
+ )
+ }
+ }}
+ />
+
+ )}
+ {header.map((item, i) => (
+
+ {item.title}
+
+ ))}
+
+ {tableBody(rows, header)}
+
+ )
+}
diff --git a/src/core/data-display/data-table/data-table-pagination-actions.tsx b/src/core/data-display/data-table/data-table-pagination-actions.tsx
index a9395c23..b94101c8 100644
--- a/src/core/data-display/data-table/data-table-pagination-actions.tsx
+++ b/src/core/data-display/data-table/data-table-pagination-actions.tsx
@@ -1,20 +1,18 @@
import React from 'react'
-import IconButton from '@/core/inputs/icon-button'
+import type { MouseEvent } from 'react'
+import { IconButton } from '@/core/inputs/icon-button'
import {
FirstPage,
LastPage,
KeyboardArrowLeft,
KeyboardArrowRight
-} from '../../../icons'
+} from '@/icons'
interface DataTablePaginationActionsProps {
count: number
page: number
rowsPerPage: number
- onPageChange(
- event: React.MouseEvent,
- newPage: number
- ): void
+ onPageChange(event: MouseEvent, newPage: number): void
}
interface DataTablePaginationActionsBuilder {
@@ -40,25 +38,25 @@ export const makeDataTablePaginationActions =
const totalPages = Math.ceil(count / rowsPerPage) - 1
const handleFirstPageButtonClick = (
- event: React.MouseEvent
+ event: MouseEvent
) => {
onPageChange(event, 0)
}
const handleBackButtonClick = (
- event: React.MouseEvent
+ event: MouseEvent
) => {
onPageChange(event, page - 1)
}
const handleNextButtonClick = (
- event: React.MouseEvent
+ event: MouseEvent
) => {
onPageChange(event, page + 1)
}
const handleLastPageButtonClick = (
- event: React.MouseEvent
+ event: MouseEvent
) => {
onPageChange(event, Math.max(0, totalPages))
}
@@ -67,29 +65,29 @@ export const makeDataTablePaginationActions =
{showFirstButton && (
+ aria-label='first page'
+ onClick={handleFirstPageButtonClick}>
)}
+ aria-label='previous page'
+ onClick={handleBackButtonClick}>
= totalPages || clickable}
- aria-label='next page'>
+ aria-label='next page'
+ onClick={handleNextButtonClick}>
{showLastButton && (
= totalPages || clickable}
- aria-label='last page'>
+ aria-label='last page'
+ onClick={handleLastPageButtonClick}>
)}
diff --git a/src/core/data-display/data-table/data-table-query-paginated.stories.tsx b/src/core/data-display/data-table/data-table-query-paginated.stories.tsx
index e7d9a9d4..78f4b1c4 100644
--- a/src/core/data-display/data-table/data-table-query-paginated.stories.tsx
+++ b/src/core/data-display/data-table/data-table-query-paginated.stories.tsx
@@ -1,15 +1,13 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable max-lines */
+import React, { useMemo, useRef, useState } from 'react'
+import type { ReactNode } from 'react'
import { TableCell, TableRow, Typography } from '@material-ui/core'
import { Skeleton } from '@mui/material'
-import { Meta } from '@storybook/react'
import format from 'date-fns/format'
-import React, { ReactNode, useMemo, useRef, useState } from 'react'
-import Button from '@/core/inputs/button'
-import { DataTableAction } from './data-table-action'
-import DataTableQueryPaginated from './data-table-query-paginated'
-import { ColumnSpec, DataTableController, Identifier, RowMode } from './types'
-import { usePaginated } from './use-paginated'
+import type { ColumnSpec, DataTableController, Identifier } from './types'
+import type { Meta } from '@storybook/react'
+import { Button } from '@/core/inputs/button'
import {
Cancel as CancelIcon,
Check as CheckIcon,
@@ -17,6 +15,10 @@ import {
Edit as EditIcon,
Save as SaveIcon
} from '@/icons'
+import { DataTableAction } from './data-table-action'
+import { DataTableQueryPaginated } from './data-table-query-paginated'
+import { RowMode } from './types'
+import { usePaginated } from './use-paginated'
export default {
title: 'DataDisplay/DataTableQueryPaginated',
@@ -91,6 +93,7 @@ const generateSkeleton = (
))}
)
+
result.push(table)
}
@@ -108,7 +111,7 @@ export const Default = () => {
loading
} = usePaginated()
- const LoadNode: React.ReactNode = useMemo(
+ const LoadNode: ReactNode = useMemo(
() => generateSkeleton(size, columnsData),
[size]
)
@@ -132,6 +135,28 @@ export const Default = () => {
)
}
+const columnsEmpty: ColumnSpec
[] = [
+ {
+ title: 'Product',
+ field: 'product',
+ type: 'text',
+ cellStyle: {
+ maxWidth: '72px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis'
+ },
+ editable: true
+ },
+ {
+ title: 'Price (R$)',
+ field: 'price',
+ type: 'numeric-float',
+ editable: false,
+ getValue: (value: number) => value.toFixed(2).replace('.', ',')
+ }
+]
+
export const Empty = () => {
const {
totalElements,
@@ -142,28 +167,6 @@ export const Empty = () => {
loading
} = usePaginated()
- const columns: ColumnSpec[] = [
- {
- title: 'Product',
- field: 'product',
- type: 'text',
- cellStyle: {
- maxWidth: '72px',
- whiteSpace: 'nowrap',
- overflow: 'hidden',
- textOverflow: 'ellipsis'
- },
- editable: true
- },
- {
- title: 'Price (R$)',
- field: 'price',
- type: 'numeric-float',
- editable: false,
- getValue: (value: number) => value.toFixed(2).replace('.', ',')
- }
- ]
-
const componentForEmpty: ReactNode = (
{
|
)
- const LoadNode: React.ReactNode = loading
+ const LoadNode: ReactNode = loading
? generateSkeleton(size, columnsData)
: componentForEmpty
@@ -202,11 +205,52 @@ export const Empty = () => {
rowsPerPage: 5,
labelRowsPerPage: 'Row per page'
}}
- columns={columns}
+ columns={columnsEmpty}
/>
)
}
+const columnsNoHeader: ColumnSpec[] = [
+ {
+ title: 'Product',
+ field: 'product',
+ type: 'text',
+ cellStyle: {
+ maxWidth: '72px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis'
+ },
+ editable: true
+ },
+ {
+ title: 'Price (R$)',
+ field: 'price',
+ type: 'numeric-float',
+ editable: false,
+ getValue: (value: number) => value.toFixed(2).replace('.', ',')
+ },
+ {
+ title: 'Quantity',
+ field: 'quantity',
+ type: 'numeric-int',
+ editable: true,
+ cellStyle: {
+ width: '82px'
+ }
+ },
+ {
+ title: 'Date',
+ field: 'date',
+ type: 'datetime',
+ editable: true,
+ getValue: (value: Date) => format(value, 'dd/MM/yyyy HH:mm'),
+ cellStyle: {
+ width: '200px'
+ }
+ }
+]
+
export const NoHeader = () => {
const {
totalElements,
@@ -218,61 +262,20 @@ export const NoHeader = () => {
data
} = usePaginated()
- const LoadNode: React.ReactNode = useMemo(
+ const LoadNode: ReactNode = useMemo(
() => generateSkeleton(size, columnsData),
[size]
)
- const columns: ColumnSpec[] = [
- {
- title: 'Product',
- field: 'product',
- type: 'text',
- cellStyle: {
- maxWidth: '72px',
- whiteSpace: 'nowrap',
- overflow: 'hidden',
- textOverflow: 'ellipsis'
- },
- editable: true
- },
- {
- title: 'Price (R$)',
- field: 'price',
- type: 'numeric-float',
- editable: false,
- getValue: (value: number) => value.toFixed(2).replace('.', ',')
- },
- {
- title: 'Quantity',
- field: 'quantity',
- type: 'numeric-int',
- editable: true,
- cellStyle: {
- width: '82px'
- }
- },
- {
- title: 'Date',
- field: 'date',
- type: 'datetime',
- editable: true,
- getValue: (value: Date) => format(value, 'dd/MM/yyyy HH:mm'),
- cellStyle: {
- width: '200px'
- }
- }
- ]
-
return (
{
labelRowsPerPage: 'Row per page',
clickable: !loading
}}
- columns={columns}
+ columns={columnsNoHeader}
/>
)
}
@@ -313,7 +316,7 @@ export const Crud = () => {
}
]
- const LoadNode: React.ReactNode = useMemo(
+ const LoadNode: ReactNode = useMemo(
() => generateSkeleton(size, newData),
[size]
)
diff --git a/src/core/data-display/data-table/data-table-query-paginated.tsx b/src/core/data-display/data-table/data-table-query-paginated.tsx
index 7381b0cd..f842a0e6 100644
--- a/src/core/data-display/data-table/data-table-query-paginated.tsx
+++ b/src/core/data-display/data-table/data-table-query-paginated.tsx
@@ -1,35 +1,34 @@
-import React, {
- useMemo,
- useState,
- useRef,
- useEffect,
+import React, { useMemo, useState, useRef, useEffect } from 'react'
+import type {
+ MouseEvent,
MutableRefObject,
- CSSProperties
+ CSSProperties,
+ ReactNode
} from 'react'
-import { last } from 'ramda'
+import Paper from '@material-ui/core/Paper'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import TableCell from '@material-ui/core/TableCell'
import TableContainer from '@material-ui/core/TableContainer'
+import TableFooter from '@material-ui/core/TableFooter'
import TableHead from '@material-ui/core/TableHead'
-import TableRow from '@material-ui/core/TableRow'
-import Paper from '@material-ui/core/Paper'
import TablePagination from '@material-ui/core/TablePagination'
-import TableFooter from '@material-ui/core/TableFooter'
-import {
+import TableRow from '@material-ui/core/TableRow'
+import { last } from 'ramda'
+import type {
ColumnSpec,
Data,
DataTableController,
Errors,
PaginationOptions,
- RowMode,
RowViewComponent,
StackView,
PartialData
} from './types'
-import { useRowsState } from './use-rows-state'
-import { StatefulRow, NewRow } from './rows'
import { makeDataTablePaginationActions } from './data-table-pagination-actions'
+import { StatefulRow, NewRow } from './rows'
+import { RowMode } from './types'
+import { useRowsState } from './use-rows-state'
export type DataTableProps<
D extends Data,
@@ -75,7 +74,7 @@ export type DataTableProps<
/**
* Component to show when there are no data
*/
- componentForEmpty?: React.ReactNode
+ componentForEmpty?: ReactNode
/**
* Custom style to be applied to the table body
*/
@@ -113,10 +112,7 @@ export type DataTableProps<
* Custom rowViews used as a Stac
*/
rowViews?: Record>
- onRowClick?: (
- event: React.MouseEvent,
- rowData: D
- ) => void
+ onRowClick?: (event: MouseEvent, rowData: D) => void
}
const defaultPagination: PaginationOptions = {
@@ -287,7 +283,8 @@ export const DataTableQueryPaginated = (
height:
hiddenRowHeight &&
`${hiddenRowHeight * hiddenRowsNumber}px`
- }}>
+ }}
+ />
)
@@ -347,6 +344,7 @@ export const DataTableQueryPaginated = (
labelDisplayedRows={
pagination.labelDisplayedRows
}
+ ActionsComponent={paginationActionsComponent}
onPageChange={(_, page) => {
handleChangePage(page)
}}
@@ -355,7 +353,6 @@ export const DataTableQueryPaginated = (
parseInt(event.target.value, 10)
)
}}
- ActionsComponent={paginationActionsComponent}
/>
diff --git a/src/core/data-display/data-table/data-table.spec.tsx b/src/core/data-display/data-table/data-table.spec.tsx
index 86126a0f..a0e611e8 100644
--- a/src/core/data-display/data-table/data-table.spec.tsx
+++ b/src/core/data-display/data-table/data-table.spec.tsx
@@ -1,12 +1,12 @@
import * as React from 'react'
+import { act } from 'react-dom/test-utils'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
-import DataTable from '.'
-import DataTableWithCrud from '@/test/mocks/data-table-mock'
-import DataTableWithHidden from '@/test/mocks/data-table-hidden-mock'
-import { ColumnSpec } from './types'
+import { userEvent } from '@testing-library/user-event'
import format from 'date-fns/format'
-import userEvent from '@testing-library/user-event'
-import { act } from 'react-dom/test-utils'
+import type { ColumnSpec } from './types'
+import DataTableWithHidden from '@/test/mocks/data-table-hidden-mock'
+import DataTableWithCrud from '@/test/mocks/data-table-mock'
+import DataTable from '.'
type Data = {
id: number
diff --git a/src/core/data-display/data-table/data-table.stories.tsx b/src/core/data-display/data-table/data-table.stories.tsx
index 02af1b4c..9b95b10f 100644
--- a/src/core/data-display/data-table/data-table.stories.tsx
+++ b/src/core/data-display/data-table/data-table.stories.tsx
@@ -1,13 +1,13 @@
+/* eslint-disable react-perf/jsx-no-new-array-as-prop */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable max-lines */
import React, { useState, useRef } from 'react'
-import { Meta } from '@storybook/react'
import format from 'date-fns/format'
-import DataTable from './data-table'
-import Button from '@/core/inputs/button'
-import Typography from '@/core/data-display/typography'
-import { DataTableAction } from './data-table-action'
-import { ColumnSpec, DataTableController, Identifier, RowMode } from './types'
+import { v4 as uuid } from 'uuid'
+import type { ColumnSpec, DataTableController, Identifier } from './types'
+import type { Meta } from '@storybook/react'
+import { Typography } from '@/core/data-display/typography'
+import { Button } from '@/core/inputs/button'
import {
Delete as DeleteIcon,
Edit as EditIcon,
@@ -17,7 +17,10 @@ import {
Visibility as VisibilityIcon,
VisibilityOff as VisibilityOffIcon
} from '@/icons'
-import { v4 as uuid } from 'uuid'
+import { DataTable } from './data-table'
+import { DataTableAction } from './data-table-action'
+import { DataTableField } from './data-table-field'
+import { RowMode } from './types'
export default {
title: 'DataDisplay/DataTable',
@@ -32,9 +35,6 @@ type Data = {
date: Date
}
-// const Template: ComponentStory = args =>
-//
-
export const Default = () => {
type Data = {
id: number
@@ -245,8 +245,8 @@ export const NoHeader = () => {
return (
{
(id: Identifier, isNew = false) =>
() => {
const nextItem = controllerRef.current?.getEditedRowData(id)
+
if (!nextItem) {
return
}
@@ -896,3 +897,102 @@ export const CrudWithHidden = () => {
>
)
}
+
+const dataInput = [
+ {
+ branch: 'Keepfy Joinville',
+ local: 'Joiville',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ },
+ {
+ branch: 'Keepfy São Paulo',
+ local: 'São Paulo',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ },
+ {
+ branch: 'Keepfy Rio Grande do Sul',
+ local: 'Rio Grande do Sul',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ },
+ {
+ branch: 'Keepfy Rio de Janeiro',
+ local: 'Rio de Janeiro',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ },
+ {
+ branch: 'Keepfy Curitiba',
+ local: 'Curitiba',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ },
+ {
+ branch: 'Keepfy Teresópolis',
+ local: 'Teresópolis',
+ status: 'Ativo',
+ companyCode: '',
+ branchCode: ''
+ }
+]
+
+const tableHead = [
+ {
+ title: 'Nome da Filial',
+ field: 'branch',
+ type: 'text',
+ editable: false
+ },
+ {
+ title: 'Localidade',
+ field: 'local',
+ type: 'text',
+ editable: false
+ },
+ {
+ title: 'Status',
+ field: 'status',
+ type: 'text',
+ editable: false
+ },
+ {
+ title: 'Código da Empresa',
+ field: 'companyCode',
+ type: 'number',
+ editable: true
+ },
+ {
+ title: 'Código da Filial',
+ field: 'branchCode',
+ type: 'text',
+ editable: true
+ }
+]
+
+export const WithField = () => {
+ const [data, setData] = useState(() => dataInput)
+ const [selectedAll, setSelectedAll] = useState(false)
+ const [selected, setSelected] = useState(Array(data.length).fill(false))
+
+ return (
+
+ )
+}
diff --git a/src/core/data-display/data-table/data-table.tsx b/src/core/data-display/data-table/data-table.tsx
index 7fb45074..d98dbf1f 100644
--- a/src/core/data-display/data-table/data-table.tsx
+++ b/src/core/data-display/data-table/data-table.tsx
@@ -1,35 +1,38 @@
-import React, {
- useMemo,
- useState,
- useRef,
- useEffect,
+/* eslint-disable max-lines */
+import React, { useMemo, useState, useRef, useEffect } from 'react'
+import type {
+ MouseEvent,
MutableRefObject,
- CSSProperties
+ CSSProperties,
+ ReactNode,
+ Dispatch,
+ SetStateAction
} from 'react'
-import { last } from 'ramda'
+import { Checkbox } from '@material-ui/core'
+import Paper from '@material-ui/core/Paper'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import TableCell from '@material-ui/core/TableCell'
import TableContainer from '@material-ui/core/TableContainer'
+import TableFooter from '@material-ui/core/TableFooter'
import TableHead from '@material-ui/core/TableHead'
-import TableRow from '@material-ui/core/TableRow'
-import Paper from '@material-ui/core/Paper'
import TablePagination from '@material-ui/core/TablePagination'
-import TableFooter from '@material-ui/core/TableFooter'
-import {
+import TableRow from '@material-ui/core/TableRow'
+import { last } from 'ramda'
+import type {
ColumnSpec,
Data,
DataTableController,
Errors,
PaginationOptions,
- RowMode,
RowViewComponent,
StackView,
PartialData
} from './types'
-import { useRowsState } from './use-rows-state'
-import { StatefulRow, NewRow } from './rows'
import { makeDataTablePaginationActions } from './data-table-pagination-actions'
+import { StatefulRow, NewRow } from './rows'
+import { RowMode } from './types'
+import { useRowsState } from './use-rows-state'
export type DataTableProps<
D extends Data,
@@ -55,7 +58,7 @@ export type DataTableProps<
/**
* Component to show when there are no data
*/
- componentForEmpty?: React.ReactNode
+ componentForEmpty?: ReactNode
/**
* Custom style to be applied to the table body
*/
@@ -93,10 +96,20 @@ export type DataTableProps<
* Custom rowViews used as a Stac
*/
rowViews?: Record>
- onRowClick?: (
- event: React.MouseEvent,
- rowData: D
- ) => void
+ /**
+ * Hide or show the checkbox
+ */
+ checkbox?: boolean
+ /**
+ * Handle the selected states and values
+ */
+ checkboxProps?: {
+ checkRow?: boolean[]
+ checkAllRows?: boolean
+ setSelectedRow?: Dispatch>
+ setSelectedAllRows?: Dispatch>
+ }
+ onRowClick?: (event: MouseEvent, rowData: D) => void
}
const defaultPagination: PaginationOptions = {
@@ -139,7 +152,9 @@ export const DataTable = (
bodyStyle,
headStyle,
hiddenRowHeight,
- hidden
+ hidden,
+ checkbox,
+ checkboxProps
} = props
const [newRow, setNewRow] = useState | undefined>()
@@ -148,6 +163,7 @@ export const DataTable = (
if (pagination.disabled) {
return data
}
+
// this case is not good for the useRowsMode hook
if (newRow && page === 0) {
return sliceData(data, page, rowsPerPage - 1)
@@ -204,9 +220,45 @@ export const DataTable = (
}
}, [setRowState, pushRowView, popRowView, getRowState, controllerRef])
+ const handleSelectCheckbox = (
+ index: number,
+ setSelected: Dispatch>,
+ setSelectedAll: Dispatch>
+ ) => {
+ setSelected(state => {
+ const newState = state.map((row, i: number) =>
+ index === i ? !row : row
+ )
+
+ if (newState.includes(false)) {
+ setSelectedAll(false)
+ }
+
+ if (newState.every(item => item === true)) {
+ setSelectedAll(true)
+ }
+
+ return newState
+ })
+ }
+
+ const handleSelectAllCheckbox = (
+ setSelected: Dispatch>,
+ setSelectedAll: Dispatch>
+ ) => {
+ setSelectedAll(selectedAll => !selectedAll)
+ setSelected(state =>
+ state.map(() =>
+ checkboxProps !== undefined
+ ? !checkboxProps.checkAllRows
+ : false
+ )
+ )
+ }
+
const rowsList = useMemo(
() =>
- rows.map(row => {
+ rows.map((row, index) => {
const rowState = getRowState(row.id)
const lastView = rowState?.stackView && last(rowState.stackView)
const view = lastView && rowViews?.[lastView]
@@ -219,6 +271,31 @@ export const DataTable = (
data-id={row.id}
style={bodyRowStyle}
onClick={event => onRowClick?.(event, row)}>
+ {checkbox && (
+
+ {
+ if (
+ checkboxProps?.setSelectedRow &&
+ checkboxProps.setSelectedAllRows
+ ) {
+ handleSelectCheckbox(
+ index,
+ checkboxProps.setSelectedRow,
+ checkboxProps.setSelectedAllRows
+ )
+ }
+ }}
+ />
+
+ )}
{view ? (
view({ data: row })
) : (
@@ -237,13 +314,15 @@ export const DataTable = (
[
rows,
getRowState,
- onRowClick,
- setEditableRowState,
- errors,
rowViews,
+ hidden,
bodyRowStyle,
+ checkbox,
columns,
- hidden
+ errors,
+ setEditableRowState,
+ onRowClick,
+ checkboxProps
]
)
@@ -276,7 +355,8 @@ export const DataTable = (
height:
hiddenRowHeight &&
`${hiddenRowHeight * hiddenRowsNumber}px`
- }}>
+ }}
+ />
)
@@ -308,7 +388,33 @@ export const DataTable = (
{!noHeader && (
- {columnsList}
+
+ {checkbox && (
+
+ {
+ if (
+ checkboxProps?.setSelectedRow &&
+ checkboxProps.setSelectedAllRows
+ ) {
+ handleSelectAllCheckbox(
+ checkboxProps.setSelectedRow,
+ checkboxProps.setSelectedAllRows
+ )
+ }
+ }}
+ />
+
+ )}
+ {columnsList}
+
)}
@@ -329,6 +435,7 @@ export const DataTable = (
labelDisplayedRows={
pagination.labelDisplayedRows
}
+ ActionsComponent={paginationActionsComponent}
onPageChange={(_, page) => {
setPage(page)
}}
@@ -338,7 +445,6 @@ export const DataTable = (
)
setPage(0)
}}
- ActionsComponent={paginationActionsComponent}
/>
diff --git a/src/core/data-display/data-table/index.ts b/src/core/data-display/data-table/index.ts
index 73c06a57..d8d2e6ea 100644
--- a/src/core/data-display/data-table/index.ts
+++ b/src/core/data-display/data-table/index.ts
@@ -3,6 +3,7 @@ export { default as DataTableQueryPaginated } from './data-table-query-paginated
export type { DataTableProps } from './data-table'
export { RowMode } from './types'
export { DataTableAction } from './data-table-action'
+export { DataTableField } from './data-table-field'
export type { DataTableActionProps } from './data-table-action'
export type {
ActionsCellProps,
diff --git a/src/core/data-display/data-table/rows.tsx b/src/core/data-display/data-table/rows.tsx
index 8e242b39..9cc031f2 100644
--- a/src/core/data-display/data-table/rows.tsx
+++ b/src/core/data-display/data-table/rows.tsx
@@ -1,10 +1,12 @@
-import { ColumnSpec, Data, Errors, PartialData, RowMode } from './types'
-import TextField from '@/core/inputs/text-field'
-import MaskField from '@/core/inputs/mask-field'
-import DateTime from '@/core/inputs/date-time'
-import React, { ReactNode, useState, useCallback } from 'react'
+import type { ReactNode } from 'react'
+import React, { useState, useCallback } from 'react'
import TableCell from '@material-ui/core/TableCell'
import TableRow from '@material-ui/core/TableRow'
+import type { ColumnSpec, Data, Errors, PartialData } from './types'
+import { DateTime } from '@/core/inputs/date-time'
+import { MaskField } from '@/core/inputs/mask-field'
+import { TextField } from '@/core/inputs/text-field'
+import { RowMode } from './types'
type RowStateUpdater = (
field: keyof D,
@@ -44,9 +46,9 @@ const renderEditMode = (
return (
{
@@ -56,7 +58,7 @@ const renderEditMode = (
)
}
- if (column.type?.includes('numeric')) {
+ if (column.type.includes('numeric')) {
const decimalScale = column.type === 'numeric-int' ? 0 : 2
const numeric = row[column.field] as number
@@ -64,8 +66,8 @@ const renderEditMode = (
return (
(
return (
@@ -169,6 +171,7 @@ export const StatefulRow = ({
[`${String(field)}`]: value
}))
const patch: Partial = {}
+
patch[field] = value
onUpdate?.(patch)
},
diff --git a/src/core/data-display/data-table/types.ts b/src/core/data-display/data-table/types.ts
index 280d38ba..4b509fb4 100644
--- a/src/core/data-display/data-table/types.ts
+++ b/src/core/data-display/data-table/types.ts
@@ -1,5 +1,5 @@
-import { IOption } from '@/core/inputs/text-field'
import type { CSSProperties, FunctionComponent } from 'react'
+import type { IOption } from '@/core/inputs/text-field'
export type RecordUnknown = Record
export type StackView = RecordUnknown
@@ -22,7 +22,7 @@ export type ColumnType =
export type Align = 'right' | 'left' | 'center' | 'justify' | 'inherit'
-type ColumnSpecBase = {
+type ColumnSpecBase = {
title: string
type: string
cellStyle?: CSSProperties
diff --git a/src/core/data-display/data-table/use-paginated.ts b/src/core/data-display/data-table/use-paginated.ts
index 50174c7a..9a08a216 100644
--- a/src/core/data-display/data-table/use-paginated.ts
+++ b/src/core/data-display/data-table/use-paginated.ts
@@ -1,8 +1,8 @@
+import { useState, useMemo, useEffect } from 'react'
import faker from 'faker'
import { splitEvery } from 'ramda'
-import { useState, useMemo, useEffect } from 'react'
// import { v4 as uuid } from 'uuid'
-import { Data } from './types'
+import type { Data } from './types'
export interface IDataProps {
id: string
@@ -21,6 +21,7 @@ interface IPaginated {
export const generateRandomDate = (size: number): Data[] => {
const content: Array = []
+
for (let i = 0; i < size; i++) {
content.push({
id: i,
diff --git a/src/core/data-display/data-table/use-rows-state.ts b/src/core/data-display/data-table/use-rows-state.ts
index c90eb4e3..a18f2070 100644
--- a/src/core/data-display/data-table/use-rows-state.ts
+++ b/src/core/data-display/data-table/use-rows-state.ts
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from 'react'
-import { Data, Identifier, RowState, StackView, RowMode } from './types'
+import type { Data, Identifier, RowState, StackView } from './types'
+import { RowMode } from './types'
export const useRowsState = (
rows: D[],
@@ -16,6 +17,7 @@ export const useRowsState = (
for (const row of rows) {
const elem = state.internal.get(row.id)
+
if (elem) {
nextState.set(row.id, elem)
} else {
@@ -43,6 +45,7 @@ export const useRowsState = (
(id: Identifier, partial: Partial>) => {
setState(state => {
const elem = state.internal.get(id)
+
if (elem) {
state.internal.set(id, { ...elem, ...partial })
}
@@ -56,6 +59,7 @@ export const useRowsState = (
const pushRowView = useCallback((id: Identifier, view: keyof V) => {
setState(state => {
const elem = state.internal.get(id)
+
if (elem) {
elem.stackView.push(view)
state.internal.set(id, elem)
@@ -70,7 +74,7 @@ export const useRowsState = (
const elem = state.internal.get(id)
if (elem) {
- elem?.stackView.pop()
+ elem.stackView.pop()
state.internal.set(id, elem)
}
diff --git a/src/core/data-display/divider/divider.spec.tsx b/src/core/data-display/divider/divider.spec.tsx
index a513f693..f709a622 100644
--- a/src/core/data-display/divider/divider.spec.tsx
+++ b/src/core/data-display/divider/divider.spec.tsx
@@ -1,11 +1,12 @@
import * as React from 'react'
import { render, screen } from '@testing-library/react'
-import Divider from '.'
+import { Divider } from '.'
describe('Divider', () => {
it('should render', () => {
render()
const divider = screen.getByTestId('divider')
+
expect(divider).toBeDefined()
})
@@ -27,6 +28,7 @@ describe('Divider', () => {
it('should match snapshot', () => {
const { container } = render()
+
expect(container).toMatchSnapshot()
})
})
diff --git a/src/core/data-display/divider/divider.stories.tsx b/src/core/data-display/divider/divider.stories.tsx
index 60cefb50..6fd8c082 100644
--- a/src/core/data-display/divider/divider.stories.tsx
+++ b/src/core/data-display/divider/divider.stories.tsx
@@ -1,8 +1,8 @@
import React from 'react'
-import { Meta } from '@storybook/react'
-import Divider from '.'
-import List from '@/core/data-display/list'
+import type { Meta } from '@storybook/react'
+import { List } from '@/core/data-display/list'
import ListItem from '@/core/data-display/list-item'
+import { Divider } from '.'
export default {
title: 'DataDisplay/Divider',
diff --git a/src/core/data-display/divider/index.tsx b/src/core/data-display/divider/index.tsx
index e712fdd7..c1d5cf62 100644
--- a/src/core/data-display/divider/index.tsx
+++ b/src/core/data-display/divider/index.tsx
@@ -1,9 +1,7 @@
-import {
- Divider as MuiDivider,
- DividerProps as MuiDividerProps
-} from '@material-ui/core'
import React from 'react'
-import { DefaultProps } from '../../types'
+import { Divider as MuiDivider } from '@material-ui/core'
+import type { DefaultProps } from '../../types'
+import type { DividerProps as MuiDividerProps } from '@material-ui/core'
export interface DividerProps extends DefaultProps, MuiDividerProps {
'data-testid'?: string
diff --git a/src/core/data-display/editable-table/editTable.stories.tsx b/src/core/data-display/editable-table/editTable.stories.tsx
index d4c9d750..14c43eef 100644
--- a/src/core/data-display/editable-table/editTable.stories.tsx
+++ b/src/core/data-display/editable-table/editTable.stories.tsx
@@ -1,14 +1,16 @@
import React from 'react'
-import { Meta, StoryFn } from '@storybook/react'
-import EditableTable from '.'
+import type { Meta, StoryFn } from '@storybook/react'
+import { EditableTable } from '.'
export default {
title: 'DataDisplay/EditTable',
component: EditableTable,
args: {
title: 'adicionar',
+ // eslint-disable-next-line no-console
onAddRow: (item: object) => Promise.resolve(console.log(item)),
onRowClick: () => window.alert('hello'),
+ // eslint-disable-next-line no-console
onDeleteRow: (item: object) => Promise.resolve(console.log(item)),
onUpdateRow: () => Promise.resolve(),
onClickAdd: () => window.alert('hello')
diff --git a/src/core/data-display/editable-table/editable-table-with-date.spec.tsx b/src/core/data-display/editable-table/editable-table-with-date.spec.tsx
index 83c091d5..8a8fe54a 100644
--- a/src/core/data-display/editable-table/editable-table-with-date.spec.tsx
+++ b/src/core/data-display/editable-table/editable-table-with-date.spec.tsx
@@ -1,10 +1,10 @@
/* eslint-disable max-lines */
-import WithDate from '@/test/mocks/editable-table-date-mock'
-import { render, screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event/'
-import { Column } from 'material-table'
import * as React from 'react'
import { act } from 'react-dom/test-utils'
+import { render, screen } from '@testing-library/react'
+import { userEvent } from '@testing-library/user-event/'
+import type { Column } from 'material-table'
+import WithDate from '@/test/mocks/editable-table-date-mock'
const COLUMNS_WITH_DATE: Column