diff --git a/.babelrc.js b/.babelrc.js index c2c1b28f..585f0fe0 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -75,8 +75,8 @@ module.exports = { transform: './src', preventFullImport: true }, - '@material-ui/icons': { - transform: '@material-ui/icons/${member}', + '@mui/icons-material': { + transform: '@mui/icons-material/${member}', preventFullImport: true }, '@material-ui/core': { @@ -88,7 +88,7 @@ module.exports = { preventFullImport: true }, '../icons': { - transform: '@material-ui/icons/${member}', + transform: '@mui/icons-material/${member}', preventFullImport: true }, '../charts': { diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index a58d2d2c..00000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -18.18.2 \ No newline at end of file diff --git a/package.json b/package.json index 10692d3c..85c88e7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flipper-ui", - "version": "0.30.7", + "version": "0.30.8", "description": "", "main": "dist/index.js", "homepage": "https://flipper-ui.ngi.com.br/", @@ -34,10 +34,15 @@ "license": "MIT", "dependencies": { "@date-io/date-fns": "1.3.6", + "@emotion/react": "11.11.3", + "@emotion/styled": "11.11.0", "@material-ui/core": "4.12.4", "@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", "date-fns": "2.30.0", "faker": "5.5.3", "material-table": "1.69.3", @@ -47,33 +52,34 @@ "react-loading-skeleton": "3.3.1", "react-number-format": "4.4.1", "sprintf-js": "1.1.3", + "stylis": "4.3.1", "uuid": "9.0.1" }, "devDependencies": { "@babel/cli": "7.23.4", - "@babel/core": "7.23.6", - "@babel/plugin-transform-runtime": "7.23.6", - "@babel/preset-env": "7.23.6", + "@babel/core": "7.23.7", + "@babel/plugin-transform-runtime": "7.23.7", + "@babel/preset-env": "7.23.7", "@babel/preset-typescript": "7.23.3", - "@storybook/addon-essentials": "7.6.6", - "@storybook/addon-styling-webpack": "0.0.5", - "@storybook/react": "7.6.6", - "@storybook/react-webpack5": "7.6.6", - "@testing-library/react": "14.0.0", - "@testing-library/user-event": "14.5.1", + "@storybook/addon-essentials": "7.6.7", + "@storybook/addon-styling-webpack": "0.0.6", + "@storybook/react": "7.6.7", + "@storybook/react-webpack5": "7.6.7", + "@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.5", + "@types/node": "20.10.6", "@types/ramda": "0.25.36", - "@types/react": "18.2.45", + "@types/react": "18.2.46", "@types/react-router": "5.1.20", "@types/react-router-dom": "5.3.3", "@types/sprintf-js": "1.1.4", "@types/styled-components": "5.1.34", "@types/uuid": "9.0.7", - "@typescript-eslint/eslint-plugin": "6.15.0", - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/eslint-plugin": "6.17.0", + "@typescript-eslint/parser": "6.17.0", "babel-loader": "9.1.3", "babel-plugin-module-resolver": "5.0.0", "babel-plugin-transform-class-properties": "6.24.1", @@ -82,7 +88,7 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-prettier": "5.1.0", + "eslint-plugin-prettier": "5.1.2", "eslint-plugin-ramda": "2.5.1", "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", @@ -95,19 +101,19 @@ "prettier": "3.1.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-router": "6.21.0", - "react-router-dom": "6.21.0", - "storybook": "7.6.6", - "styled-components": "6.1.2", + "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", "ts-loader": "9.5.1", "typescript": "5.3.3", "webpack": "5.89.0" }, "peerDependencies": { - "date-fns": "2.30.0", - "react": "16.8.0", - "styled-components": "5.0.0" + "date-fns": "^2.30.0", + "react": "16.x || 17.x || 18.x", + "styled-components": "5.x || 6.x" }, "publishConfig": { "ignore": [ diff --git a/src/colors.ts b/src/colors.ts deleted file mode 100644 index 61d96653..00000000 --- a/src/colors.ts +++ /dev/null @@ -1,33 +0,0 @@ -export const primary = { - dark: '#00695C', - light: '#B2DFDB', - normal: '#009688' -} - -export const background = { - dark: '#BDBDBD', - light: '#EEEEEE', - normal: '#E5E5E5' -} - -export const silver = { - medium: '#666666', - light: '#D3D3D3' -} - -export const white = '#FFFFFF' -export const black = '#000000' -export const transparent = '#FFFFFF00' -export const text = '#424242' -export const error = { - dark: '#B71C1C', - light: '#F44336', - normal: '#D32F2F' -} - -export const warning = '#FFC107' -export const success = '#4CAF50' - -// Table gradient hover colors with opacity -export const DARK = 'rgba(189,189,189,0)' -export const GREY = 'rgba(189,189,189,1)' 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 228f791e..77696936 100644 --- a/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap +++ b/src/core/data-display/advertise/__snapshots__/advertise.spec.tsx.snap @@ -3,19 +3,19 @@ exports[`Advertise should match snapshot 1`] = `

comment

author diff --git a/src/core/data-display/advertise/index.tsx b/src/core/data-display/advertise/index.tsx index 0d5a5e02..a920cd9c 100644 --- a/src/core/data-display/advertise/index.tsx +++ b/src/core/data-display/advertise/index.tsx @@ -1,9 +1,11 @@ import React from 'react' -import { background } from '@/colors' +import styled from 'styled-components' import MuiPaper from '@/core/surfaces/paper' import Typography from '@/core/data-display/typography' -import styled from 'styled-components' import type { DefaultProps } from '../../types' +import { theme } from '@/theme' + +const { grays } = theme.colors export interface AdvertiseProps extends DefaultProps { /** @@ -28,7 +30,7 @@ export interface AdvertiseProps extends DefaultProps { const styles = { border: { - borderLeft: `1px solid ${background.dark}` + borderLeft: `1px solid ${grays.g5}` } } diff --git a/src/core/data-display/chip/chip.stories.tsx b/src/core/data-display/chip/chip.stories.tsx index 170fb240..8375c821 100644 --- a/src/core/data-display/chip/chip.stories.tsx +++ b/src/core/data-display/chip/chip.stories.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Meta, StoryFn } from '@storybook/react' import Chip from '.' import Avatar from '@/core/data-display/avatar' -import FaceIcon from '@material-ui/icons/Face' +import { Face } from '../../../icons' export default { title: 'DataDisplay/Chip', @@ -37,7 +37,7 @@ WithIconAvatar.args = { ...commonArgs, avatar: ( - + ) } 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 a4c2ed06..a9395c23 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,9 +1,11 @@ import React from 'react' import IconButton from '@/core/inputs/icon-button' -import FirstPageIcon from '@material-ui/icons/FirstPage' -import LastPageIcon from '@material-ui/icons/LastPage' -import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft' -import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight' +import { + FirstPage, + LastPage, + KeyboardArrowLeft, + KeyboardArrowRight +} from '../../../icons' interface DataTablePaginationActionsProps { count: number @@ -68,7 +70,7 @@ export const makeDataTablePaginationActions = onClick={handleFirstPageButtonClick} disabled={page === 0 || clickable} aria-label='first page'> - + )} = totalPages || clickable} aria-label='last page'> - + )}
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 d5dad31a..e7d9a9d4 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,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable max-lines */ import { TableCell, TableRow, Typography } from '@material-ui/core' -import { Skeleton } from '@material-ui/lab' +import { Skeleton } from '@mui/material' import { Meta } from '@storybook/react' import format from 'date-fns/format' import React, { ReactNode, useMemo, useRef, useState } from 'react' diff --git a/src/core/data-display/editable-table/index.tsx b/src/core/data-display/editable-table/index.tsx index 3308126f..45a84436 100644 --- a/src/core/data-display/editable-table/index.tsx +++ b/src/core/data-display/editable-table/index.tsx @@ -32,7 +32,6 @@ import AutoComplete from '@/core/inputs/auto-complete' import ListItem from '@/core/data-display/list-item' import TextField from '@/core/inputs/text-field' import MaskField from '@/core/inputs/mask-field' -import { DARK, GREY } from '@/colors' import { getLocalization } from '@/lib/localization' export interface EditableTableProps { @@ -99,6 +98,9 @@ export interface EditableTableProps { export type TSuggestion = { label: string; value: string } +export const DARK = 'rgba(189,189,189,0)' +export const GREY = 'rgba(189,189,189,1)' + const AddRowButton = styled.div` display: flex; align-items: center; diff --git a/src/core/data-display/line/__snapshots__/line.spec.tsx.snap b/src/core/data-display/line/__snapshots__/line.spec.tsx.snap index d8118724..0636f841 100644 --- a/src/core/data-display/line/__snapshots__/line.spec.tsx.snap +++ b/src/core/data-display/line/__snapshots__/line.spec.tsx.snap @@ -3,7 +3,7 @@ exports[`Line should match snapshot 1`] = `
`; diff --git a/src/core/data-display/line/index.tsx b/src/core/data-display/line/index.tsx index 53043dd3..48a52c23 100644 --- a/src/core/data-display/line/index.tsx +++ b/src/core/data-display/line/index.tsx @@ -1,6 +1,8 @@ import React from 'react' -import { background, primary as primaryColor } from '@/colors' import { DefaultProps } from '../../types' +import { theme } from '@/theme' + +const { grays, secondary } = theme.colors export interface LineProps extends DefaultProps { /** @@ -22,9 +24,7 @@ export const Line = ({ flex: 1, padding, margin, - border: `1px solid ${ - primary ? primaryColor.normal : background.normal - }`, + border: `1px solid ${primary ? secondary.light : grays.g6}`, ...style }} {...otherProps} diff --git a/src/core/data-display/line/line.spec.tsx b/src/core/data-display/line/line.spec.tsx index b9600f00..cdd18542 100644 --- a/src/core/data-display/line/line.spec.tsx +++ b/src/core/data-display/line/line.spec.tsx @@ -1,7 +1,9 @@ import * as React from 'react' import { render, screen } from '@testing-library/react' import Line from '.' -import { background, primary as primaryColor } from '@/colors' +import { theme } from '@/theme' + +const { grays, secondary } = theme.colors describe('Line', () => { it('should render closed', () => { @@ -30,7 +32,7 @@ describe('Line', () => { expect(element).toHaveProperty('style.padding', '5px') expect(element).toHaveProperty( 'style.border', - `1px solid ${background.normal.toLowerCase()}` + `1px solid ${grays.g6.toLowerCase()}` ) }) @@ -41,7 +43,7 @@ describe('Line', () => { expect(element).toHaveProperty( 'style.border', - `1px solid ${primaryColor.normal}` + `1px solid ${secondary.light.toLowerCase()}` ) }) diff --git a/src/core/data-display/list/list.stories.tsx b/src/core/data-display/list/list.stories.tsx index 38e5f062..6a19d66f 100644 --- a/src/core/data-display/list/list.stories.tsx +++ b/src/core/data-display/list/list.stories.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Meta, StoryFn } from '@storybook/react' import List from '.' import ListItem from '@/core/data-display/list-item' -import IconBackup from '@material-ui/icons/Backup' +import { Backup } from '../../../icons' import Avatar from '../avatar' export default { @@ -34,14 +34,14 @@ WithIcons.args = { title: 'My beautiful list"', children: ( <> - } title='Item 1' /> - } title='Item 2' /> - } title='Item 3' /> - } title='Item 4' /> - } title='Item 5' /> - } title='Item 6' /> - } title='Item 7' /> - } title='Item 8' /> + } title='Item 1' /> + } title='Item 2' /> + } title='Item 3' /> + } title='Item 4' /> + } title='Item 5' /> + } title='Item 6' /> + } title='Item 7' /> + } title='Item 8' /> ) } diff --git a/src/core/data-display/menu-item/index.tsx b/src/core/data-display/menu-item/index.tsx new file mode 100644 index 00000000..906d2edd --- /dev/null +++ b/src/core/data-display/menu-item/index.tsx @@ -0,0 +1,49 @@ +import React, { MouseEvent } from 'react' +import { DefaultProps } from '../../types' +import { Omit } from 'ramda' +import styled from 'styled-components' +import { MenuItem as MuiMenuItem } from '@mui/material' +import { MenuItemClassKey } from '@material-ui/core/MenuItem' +import { ClassNameMap } from '@material-ui/core/styles/withStyles' + +export interface ListItemProps extends Omit { + title?: string + value?: string | number + selected?: boolean + disabled?: boolean + onClick?: (event?: MouseEvent) => void + children?: string + ref?: React.MutableRefObject + classes?: Partial> | undefined +} + +const MenuItems = styled(MuiMenuItem)` + && { + outline: none; + cursor: pointer; + font-family: Roboto, Helvetica, Arial, sans-serif; + + &:hover { + background-color: #e0e0e0; + } + } +` + +const MenuItem = (props: ListItemProps) => { + const { padding, margin, style } = props + + return ( + + {props.children} + + ) +} + +export default MenuItem diff --git a/src/core/data-display/menu-item/menu-item.spec.tsx b/src/core/data-display/menu-item/menu-item.spec.tsx new file mode 100644 index 00000000..c142f095 --- /dev/null +++ b/src/core/data-display/menu-item/menu-item.spec.tsx @@ -0,0 +1,13 @@ +import * as React from 'react' +import { render, screen } from '@testing-library/react' +import MenuItem from '.' + +describe('MenuItem', () => { + it('should render', () => { + render() + + const menuItem = screen.getByRole('menuitem', { name: 'Item 1' }) + + expect(menuItem).toBeDefined() + }) +}) diff --git a/src/core/data-display/node/index.tsx b/src/core/data-display/node/index.tsx index e73daffd..5ac86692 100644 --- a/src/core/data-display/node/index.tsx +++ b/src/core/data-display/node/index.tsx @@ -1,11 +1,13 @@ import React from 'react' import styled from 'styled-components' -import { background, primary, transparent } from '@/colors' +import { DefaultProps } from '../../types' import { KeyboardArrowDown as IconArrowDown, KeyboardArrowUp as IconArrowUp } from '@/icons' -import { DefaultProps } from '../../types' +import { theme } from '@/theme' + +const { grays } = theme.colors export interface NodeProps extends DefaultProps { name: string @@ -29,19 +31,19 @@ const Ul = styled.ul` const Li = styled.li` font-size: 16px; margin: 12px; - background: ${transparent}; + background: #ffffff00; padding: 12px; padding-left: ${props => (props.inset ? '12px' : '48px')}; list-style: none; border-radius: 6px; - border: 1px solid ${background.dark}; + border: 1px solid ${grays.g5}; transition: all 500ms ease; cursor: pointer; align-items: center; display: flex; &:hover { - background: ${background.light}; - border: 1px solid ${primary.normal}; + background: ${grays.g7}; + border: 1px solid #009688; } ` diff --git a/src/core/data-display/table/index.tsx b/src/core/data-display/table/index.tsx index 25ef898b..d10e5040 100644 --- a/src/core/data-display/table/index.tsx +++ b/src/core/data-display/table/index.tsx @@ -1,7 +1,9 @@ import MuiTable, { TableProps as MuiTableProps } from '@material-ui/core/Table' import React from 'react' import { DefaultProps } from '../../types' -import { silver } from '@/colors' +import { theme } from '@/theme' + +const { grays } = theme.colors export interface TableProps extends DefaultProps, @@ -21,7 +23,7 @@ export const Table = ({ {...otherProps} padding={spacing} style={{ - border: `1px solid ${silver.light}`, + border: `1px solid ${grays.g6}`, padding, margin, ...style diff --git a/src/core/data-display/table/table-row.tsx b/src/core/data-display/table/table-row.tsx index 4c44ea18..7d62f5fb 100644 --- a/src/core/data-display/table/table-row.tsx +++ b/src/core/data-display/table/table-row.tsx @@ -1,9 +1,11 @@ +import React, { MouseEvent } from 'react' +import { DefaultProps } from '../../types' import MuiTableRow, { TableRowProps as MuiTableRowProps } from '@material-ui/core/TableRow' -import React, { MouseEvent } from 'react' -import { background as backgroundColor } from '@/colors' -import { DefaultProps } from '../../types' +import { theme } from '@/theme' + +const { grays } = theme.colors export interface TableRowProps extends DefaultProps { selected?: boolean @@ -24,7 +26,7 @@ const TableRow = ({ {...otherProps} style={{ background, - borderColor: backgroundColor.light, + borderColor: grays.g7, margin, padding, ...style diff --git a/src/core/feedback/snackbar/index.tsx b/src/core/feedback/snackbar/index.tsx index 1249e08b..e4a09474 100644 --- a/src/core/feedback/snackbar/index.tsx +++ b/src/core/feedback/snackbar/index.tsx @@ -11,7 +11,7 @@ import { Error as IconError, Info as IconInfo, Warning as IconWarning -} from '@material-ui/icons' +} from '../../../icons' import React, { ReactNode, FunctionComponent, MouseEvent } from 'react' import { DefaultProps } from '../../types' import { TransitionProps } from '@material-ui/core/transitions/transition' diff --git a/src/core/feedback/validation-dialog/index.tsx b/src/core/feedback/validation-dialog/index.tsx new file mode 100644 index 00000000..a931f12e --- /dev/null +++ b/src/core/feedback/validation-dialog/index.tsx @@ -0,0 +1,184 @@ +import React from 'react' +import styled from 'styled-components' +import Dialog from '../dialog' +import Button from '@/core/inputs/button' +import Actions from '../../../experimental/actions' +import Typography from '../../data-display/typography' + +export interface IValidateProps { + open: boolean + failed: boolean + success: boolean + title: ITitles + responses: string[] + validations: IValidations[] + icons: { + success: React.ReactNode + error: React.ReactNode + loading: React.ReactNode + } + onClose(): void + onCancel(): void + handleCreate(): void +} + +export interface ITitles { + success: string + error: string + loading: string +} + +export interface IValidations { + description: { + loading: string + success: string + error: string + } + status: string +} + +interface IIcon { + status: string + icons: { + success: React.ReactNode + error: React.ReactNode + loading: React.ReactNode + } +} + +export enum ValidationStatus { + Loading = 'Loading', + Success = 'Success', + Error = 'Error' +} + +const MuiDialog = styled(Dialog)` + div > div > h2 { + margin-top: 20px; + } +` + +const DialogTypography = styled(Typography)` + && { + font-size: 16px; + } +` + +const ValidationWrapper = styled.div` + display: flex; + align-items: center; + padding: 15px 0; + gap: 15px; +` + +const ValidationDialog: React.FC = ({ + open, + failed, + success, + title, + responses, + validations, + icons, + onClose, + onCancel, + handleCreate +}) => { + const renderTitle = (stepsTitle: ITitles, responses: string[]) => { + if (responses.every(item => item === 'Success')) { + return stepsTitle.success + } + + if (responses.some(item => item === 'Loading')) { + return stepsTitle.loading + } + + if (responses.includes('Error')) { + return stepsTitle.error + } + + return stepsTitle.loading + } + + const renderIcon = ({ status, icons }: IIcon) => { + if (status === 'Success') { + return icons.success + } + + if (status === 'Error') { + return icons.error + } + + return icons.loading + } + + const renderDescription = ( + status: string, + description: { + loading: string + success: string + error: string + } + ) => { + if (status === 'Success') { + return {description.success} + } + + if (status === 'Error') { + return {description.error} + } + + return {description.loading} + } + + const renderContent = ( + validations: IValidations[], + icons: { + success: React.ReactNode + error: React.ReactNode + loading: React.ReactNode + } + ) => { + return validations.map((item, i) => { + return ( + + {renderIcon({ status: item.status, icons })} + {renderDescription(item.status, item.description)} + + ) + }) + } + + return ( + + VOLTAR + + ) : ( + + ) + } + content={renderContent(validations, icons)} + onClose={onClose} + /> + ) +} + +export default ValidationDialog diff --git a/src/core/feedback/validation-dialog/validation-dialog.spec.tsx b/src/core/feedback/validation-dialog/validation-dialog.spec.tsx new file mode 100644 index 00000000..680079a3 --- /dev/null +++ b/src/core/feedback/validation-dialog/validation-dialog.spec.tsx @@ -0,0 +1,277 @@ +import React from 'react' +import { render, screen, fireEvent } from '@testing-library/react' +import ValidationDialog, { ITitles, ValidationStatus } from '.' +import CircularProgress from '@mui/material/CircularProgress' +import { CheckCircleOutline, CancelOutlined } from '../../../icons' +import { theme } from '@/theme' + +const { action, secondary } = theme.colors + +const renderTitle = (stepsTitle: ITitles, responses: string[]) => { + if (responses.every(item => item === 'Success')) { + return stepsTitle.success + } + + if (responses.some(item => item === 'Loading')) { + return stepsTitle.loading + } + + if (responses.includes('Error')) { + return stepsTitle.error + } + + return stepsTitle.loading +} + +describe('ValidationDialog', () => { + const stepsTitle = { + success: 'Success', + loading: 'Loading', + error: 'Error' + } + + const stepsIcons = { + success: , + error: , + loading: + } + + it('should render title "Loading" by default', () => { + const responses = ['Should', 'render', 'default', 'case'] + + render( + item === 'Success')} + responses={responses} + validations={[]} + icons={stepsIcons} + onCancel={jest.fn()} + handleCreate={jest.fn()} + /> + ) + + const result = renderTitle(stepsTitle, responses) + expect(result).toBe(stepsTitle.loading) + }) + + it('should render title "Success" when all items are "Success"', () => { + const responses = ['Success', 'Success', 'Success', 'Success'] + + render( + item === 'Success')} + responses={responses} + validations={[]} + icons={stepsIcons} + onCancel={jest.fn()} + handleCreate={jest.fn()} + /> + ) + + const result = renderTitle(stepsTitle, responses) + expect(result).toBe(stepsTitle.success) + }) + + it('should render title "Loading" when at least one item is "Loading"', () => { + const responses = ['Success', 'Success', 'Success', 'Loading'] + + render( + item === 'Success')} + responses={responses} + validations={[]} + icons={stepsIcons} + onCancel={jest.fn()} + handleCreate={jest.fn()} + /> + ) + + const result = renderTitle(stepsTitle, responses) + expect(result).toBe(stepsTitle.loading) + }) + + it('should render title "Error" when at least one item is "Error"', () => { + const responses = ['Success', 'Success', 'Success', 'Error'] + + render( + item === 'Success')} + responses={responses} + validations={[]} + icons={stepsIcons} + onCancel={jest.fn()} + handleCreate={jest.fn()} + /> + ) + + const result = renderTitle(stepsTitle, responses) + expect(result).toBe(stepsTitle.error) + }) + + it('should render onCancel when all responses are "Success"', () => { + const responses = ['Success', 'Success', 'Success', 'Success'] + + render( + item === 'Success')} + responses={responses} + validations={[]} + icons={stepsIcons} + onCancel={jest.fn()} + handleCreate={jest.fn()} + /> + ) + + const closeButton = screen.getByRole('button', { name: 'Cancelar' }) + fireEvent.click(closeButton) + + expect(closeButton).toBeDefined() + }) + + it('should render success description when status is "Success"', () => { + render( + + ) + + const successDescription = screen.getByText('Success description') + expect(successDescription).toBeDefined() + }) + + it('should render error description when status is "Error"', () => { + render( + + ) + + const errorDescription = screen.getByText('Error description') + expect(errorDescription).toBeDefined() + }) + + it('should render loading description when status is "Loading"', () => { + render( + + ) + + const loadingDescription = screen.getByText('Loading description') + expect(loadingDescription).toBeDefined() + }) + + it('should render handleCreate when all responses are "Success"', () => { + const handleCreateMock = jest.fn() + const responses = ['Success', 'Success', 'Success', 'Success'] + + render( + + ) + + const createButton = screen.getByRole('button', { name: 'Confirmar' }) + fireEvent.click(createButton) + + expect(handleCreateMock).toHaveBeenCalled() + }) +}) diff --git a/src/core/feedback/validation-dialog/validaton-dialog.stories.tsx b/src/core/feedback/validation-dialog/validaton-dialog.stories.tsx new file mode 100644 index 00000000..02d2b66a --- /dev/null +++ b/src/core/feedback/validation-dialog/validaton-dialog.stories.tsx @@ -0,0 +1,184 @@ +import React, { useCallback, useState } from 'react' +import type { Meta, StoryObj } from '@storybook/react' +import { ThemeProvider } from 'styled-components' +import { muiThemeOptions, theme } from '../../../theme' +import ThemeProviderFlipper from '../../context/theme-provider' +import CircularProgress from '@mui/material/CircularProgress' +import Button from '@/core/inputs/button' +import ValidationDialog, { ValidationStatus } from '.' +import { CheckCircleOutline, CancelOutlined } from '../../../icons' + +const { action, secondary } = theme.colors + +const meta: Meta = { + title: 'Feedback/Validation Dialog', + component: ValidationDialog, + argTypes: { + title: { + control: 'object', + description: `The dialog title. + An object with the three possible scenarios, Loading, Success or Error.` + }, + validations: { + control: 'array', + description: `The dialog validation phrases. + An array of objects with the three possible scenarios, + Loading, Success or Error.` + }, + icons: { + control: 'object', + description: `The dialog icons. + An object with the three possible scenarios, Loading, Success or Error. + The icon accepts a ReactNode child.` + } + } +} + +export default meta + +type Story = StoryObj + +const ValidationDialogStorie = () => { + const [open, setOpen] = useState(false) + const [validationResponses, setValidationResponses] = useState([]) + + const stepsTitle = { + success: 'Sua configuração foi validada com sucesso!', + error: 'Houve algum problema ao configurar', + loading: 'Validando Integrações' + } + + const stepsIcons = { + success: , + error: , + loading: + } + + const validationSteps = [ + { + description: { + loading: 'Validando URL, Porta e Forma de Autenticação', + success: 'URL, Porta e Forma de Autenticação válidas', + error: 'URL, Porta e Forma de Autenticação inválidas' + }, + status: validationResponses[0] + }, + { + description: { + loading: 'Validando Usuário e Senha', + success: 'Usuário e Senha válidas', + error: 'Usuário e Senha inválidas' + }, + status: validationResponses[1] + }, + { + description: { + loading: 'Validando Tipos de Integração', + success: 'Tipos de Integração válidas', + error: 'Tipos de Integração inválidas' + }, + status: validationResponses[2] + }, + { + description: { + loading: 'Validando Filiais', + success: 'Filiais válidas', + error: 'Filiais inválidas' + }, + status: validationResponses[3] + } + ] + + const useSubscriptionValidationState = () => { + const initLoading = useCallback((condition: boolean = true) => { + if (condition) { + setValidationResponses( + Array(validationSteps.length).fill(ValidationStatus.Loading) + ) + } + }, []) + + const stepState = useCallback( + (condition: boolean = true, step: number, value: string) => { + if (condition) { + setValidationResponses(prevResponses => { + const newResponses = [...prevResponses] + newResponses[step] = value + + return newResponses + }) + } + }, + [] + ) + + return { + initLoading, + stepState + } + } + + const validationStatus = useSubscriptionValidationState() + + const handleClose = () => { + setOpen(false) + setValidationResponses([]) + } + + const handleConfirm = () => { + alert('chama a mutation') + } + + const openDialog = () => { + setOpen(true) + validationStatus.initLoading() + + setTimeout(() => { + validationStatus.stepState(true, 0, 'Success') + + setTimeout(() => { + validationStatus.stepState(true, 1, 'Error') + + setTimeout(() => { + validationStatus.stepState(true, 2, 'Success') + + setTimeout(() => { + validationStatus.stepState(true, 3, 'Success') + }, 2000) + }, 2000) + }, 2000) + }, 3000) + } + + return ( + + + + + item === 'Success' + )} + onCancel={handleClose} + onClose={handleClose} + handleCreate={handleConfirm} + /> + + + ) +} + +export const validationDialog: Story = { + render: () => { + return + } +} diff --git a/src/core/inputs/select/index.tsx b/src/core/inputs/select/index.tsx index 6e7b0597..7a19ef64 100644 --- a/src/core/inputs/select/index.tsx +++ b/src/core/inputs/select/index.tsx @@ -5,7 +5,7 @@ import { SelectProps as MuiSelectProps } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' -import { Clear } from '@material-ui/icons' +import { Clear } from '../../../icons' import React, { ChangeEvent } from 'react' import { DefaultProps } from '../../types' diff --git a/src/core/inputs/text-field/index.tsx b/src/core/inputs/text-field/index.tsx index 943c4ec2..5f6cb24d 100644 --- a/src/core/inputs/text-field/index.tsx +++ b/src/core/inputs/text-field/index.tsx @@ -15,12 +15,7 @@ import React, { MouseEvent } from 'react' import { DefaultProps } from '../../types' -import { - Clear, - Help as ContactSupportIcon, - Edit, - Save -} from '@material-ui/icons' +import { Clear, Help as ContactSupportIcon, Edit, Save } from '../../../icons' import IconButton from '../icon-button' import styled from 'styled-components' import { when, is, pipe, split, map, zipObj, reject, propEq } from 'ramda' diff --git a/src/core/navigation/menu/menu.spec.tsx b/src/core/navigation/menu/menu.spec.tsx index 8d245515..f05e15c1 100644 --- a/src/core/navigation/menu/menu.spec.tsx +++ b/src/core/navigation/menu/menu.spec.tsx @@ -2,13 +2,14 @@ import * as React from 'react' import { render, screen } from '@testing-library/react' import Menu from '.' import ListItem from '@/core/data-display/list-item' -import IconBackup from '@material-ui/icons/Backup' +import { Backup } from '../../../icons' + describe('Menu', () => { it('should render opened', () => { render( - } title='Menu 1' /> - } title='Menu 2' /> + } title='Menu 1' /> + } title='Menu 2' /> ) @@ -22,8 +23,8 @@ describe('Menu', () => { it('should render closed', () => { render( - } title='Menu 1' /> - } title='Menu 2' /> + } title='Menu 1' /> + } title='Menu 2' /> ) diff --git a/src/core/navigation/menu/menu.stories.tsx b/src/core/navigation/menu/menu.stories.tsx index e0a4aa33..ee9abd69 100644 --- a/src/core/navigation/menu/menu.stories.tsx +++ b/src/core/navigation/menu/menu.stories.tsx @@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/react' import Menu from '.' import Button from '@/core/inputs/button' import ListItem from '@/core/data-display/list-item' -import IconBackup from '@material-ui/icons/Backup' +import { Backup } from '../../../icons' export default { title: 'Navigation/Menu', @@ -31,14 +31,14 @@ Default.args = { title: 'My beautiful Menu"', children: ( <> - } title='Menu 1' /> - } title='Menu 2' /> - } title='Menu 3' /> - } title='Menu 4' /> - } title='Menu 5' /> - } title='Menu 6' /> - } title='Menu 7' /> - } title='Menu 8' /> + } title='Menu 1' /> + } title='Menu 2' /> + } title='Menu 3' /> + } title='Menu 4' /> + } title='Menu 5' /> + } title='Menu 6' /> + } title='Menu 7' /> + } title='Menu 8' /> ) } diff --git a/src/core/navigation/sidebar/sidebar.spec.tsx b/src/core/navigation/sidebar/sidebar.spec.tsx index 6d64a68e..d826683c 100644 --- a/src/core/navigation/sidebar/sidebar.spec.tsx +++ b/src/core/navigation/sidebar/sidebar.spec.tsx @@ -3,15 +3,15 @@ import { render, screen } from '@testing-library/react' import Sidebar from '.' import List from '@/core/data-display/list' import ListItem from '@/core/data-display/list-item' -import IconBackup from '@material-ui/icons/Backup' +import { Backup } from '../../../icons' describe('Sidebar', () => { it('should render', () => { render( - } /> - } /> + } /> + } /> ) @@ -27,8 +27,8 @@ describe('Sidebar', () => { render( - } /> - } /> + } /> + } /> ) @@ -44,8 +44,8 @@ describe('Sidebar', () => { render( - } /> - } /> + } /> + } /> ) @@ -61,8 +61,8 @@ describe('Sidebar', () => { render( - } /> - } /> + } /> + } /> ) diff --git a/src/core/navigation/sidebar/sidebar.stories.tsx b/src/core/navigation/sidebar/sidebar.stories.tsx index 2afd19aa..79ffd0cb 100644 --- a/src/core/navigation/sidebar/sidebar.stories.tsx +++ b/src/core/navigation/sidebar/sidebar.stories.tsx @@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/react' import Sidebar from '.' import List from '@/core/data-display/list' import ListItem from '@/core/data-display/list-item' -import IconBackup from '@material-ui/icons/Backup' +import { Backup } from '../../../icons' export default { title: 'Navigation/Sidebar', @@ -19,10 +19,10 @@ Default.args = { children: ( <> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> ) diff --git a/src/core/surfaces/content/__snapshots__/content.spec.tsx.snap b/src/core/surfaces/content/__snapshots__/content.spec.tsx.snap index d51aab21..e10d0ec8 100644 --- a/src/core/surfaces/content/__snapshots__/content.spec.tsx.snap +++ b/src/core/surfaces/content/__snapshots__/content.spec.tsx.snap @@ -3,7 +3,7 @@ exports[`Content should match snapshot 1`] = `
diff --git a/src/core/surfaces/expansion-panel/expansion-panel.stories.tsx b/src/core/surfaces/expansion-panel/expansion-panel.stories.tsx index 751a0b88..bddde481 100644 --- a/src/core/surfaces/expansion-panel/expansion-panel.stories.tsx +++ b/src/core/surfaces/expansion-panel/expansion-panel.stories.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Meta, StoryFn } from '@storybook/react' import ExpansionPanel from '.' import Typography from '@/core/data-display/typography' -import ExpandMore from '@material-ui/icons/ExpandMore' +import { ExpandMore } from '../../../icons' import Button from '@/core/inputs/button' import TextField from '@/core/inputs/text-field' diff --git a/src/core/surfaces/step-card/step-card-skeleton.tsx b/src/core/surfaces/step-card/step-card-skeleton.tsx index b40f27df..a50475e6 100644 --- a/src/core/surfaces/step-card/step-card-skeleton.tsx +++ b/src/core/surfaces/step-card/step-card-skeleton.tsx @@ -1,6 +1,6 @@ import { Box } from '@material-ui/core' import MuiAccordion from '@material-ui/core/Accordion' -import { Skeleton } from '@material-ui/lab' +import { Skeleton } from '@mui/material' import React from 'react' import { Container, @@ -63,7 +63,7 @@ const StepCardSkeleton = (props: IStepCardPanelProps) => { {showIcon && ( diff --git a/src/experimental/auto-complete-lab/index.tsx b/src/experimental/auto-complete-lab/index.tsx index d58c7159..6371d060 100644 --- a/src/experimental/auto-complete-lab/index.tsx +++ b/src/experimental/auto-complete-lab/index.tsx @@ -1,13 +1,15 @@ import React from 'react' +import { makeStyles } from '@material-ui/core/styles' import { default as MuiAutocomplete } from '@material-ui/lab/Autocomplete' export { AutocompleteRenderInputParams, AutocompleteProps, AutocompleteCloseReason, AutocompleteChangeReason, - AutocompleteInputChangeReason + AutocompleteInputChangeReason, + AutocompleteGetTagProps, + AutocompleteRenderOptionState } from '@material-ui/lab/Autocomplete' -import { makeStyles } from '@material-ui/core/styles' const useStyles = makeStyles({ inputRoot: { diff --git a/src/experimental/fab/fab.spec.tsx b/src/experimental/fab/fab.spec.tsx index 514a87a9..4195dd81 100644 --- a/src/experimental/fab/fab.spec.tsx +++ b/src/experimental/fab/fab.spec.tsx @@ -3,13 +3,13 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import Fab from './fab' import FabWrapper from './fab-wrapper' -import FileCopyIcon from '@material-ui/icons/FileCopy' +import { FileCopy } from '../../icons' describe('Fab', () => { it('should render correctly', () => { render( - + ) @@ -21,7 +21,7 @@ describe('Fab', () => { it('should render large correctly', () => { render( - + ) @@ -34,7 +34,7 @@ describe('Fab', () => { const onClickSpy = jest.fn() render( - + ) @@ -51,7 +51,7 @@ describe('Fab', () => { const onClickSpy = jest.fn() render( - + ) diff --git a/src/experimental/fab/fab.stories.tsx b/src/experimental/fab/fab.stories.tsx index f1fd96c7..7468c717 100644 --- a/src/experimental/fab/fab.stories.tsx +++ b/src/experimental/fab/fab.stories.tsx @@ -1,14 +1,14 @@ import React from 'react' import FabV2 from './fab' import FabWrapper from './fab-wrapper' -import FileCopyIcon from '@material-ui/icons/FileCopy' +import { FileCopy } from '../../icons' import { Meta, StoryFn } from '@storybook/react' const Template: StoryFn = args => export const Default = Template.bind({}) Default.args = { - children: + children: } export default { diff --git a/src/experimental/sidebar/index.tsx b/src/experimental/sidebar/index.tsx index 69d1344c..5fb12654 100644 --- a/src/experimental/sidebar/index.tsx +++ b/src/experimental/sidebar/index.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useState, useCallback } from 'react' import styled from 'styled-components' import { theme } from 'nginformatica-styleguide' import { times, map } from 'ramda' -import { Skeleton } from '@material-ui/lab' +import { Skeleton } from '@mui/material' export interface ISidebarOption { icon: React.ReactElement diff --git a/src/experimental/sidebar/sidebar.stories.tsx b/src/experimental/sidebar/sidebar.stories.tsx index fe694ad3..930d77a0 100644 --- a/src/experimental/sidebar/sidebar.stories.tsx +++ b/src/experimental/sidebar/sidebar.stories.tsx @@ -1,6 +1,6 @@ import React from 'react' import Sidebar from '.' -import { Home, Computer, Edit } from '@material-ui/icons' +import { Home, Computer, Edit } from '../../icons' import { Meta, StoryFn } from '@storybook/react' export default { diff --git a/src/experimental/skeleton/__snapshots__/skeleton.spec.tsx.snap b/src/experimental/skeleton/__snapshots__/skeleton.spec.tsx.snap index 7e9c0428..28b078d5 100644 --- a/src/experimental/skeleton/__snapshots__/skeleton.spec.tsx.snap +++ b/src/experimental/skeleton/__snapshots__/skeleton.spec.tsx.snap @@ -12,7 +12,7 @@ exports[`Skeleton should match snapshot - Circle 1`] = ` > @@ -28,7 +28,7 @@ exports[`Skeleton should match snapshot - Circle 1`] = ` > @@ -101,7 +101,7 @@ exports[`Skeleton should match snapshot - Simple 1`] = ` > @@ -117,7 +117,7 @@ exports[`Skeleton should match snapshot - Simple 1`] = ` > @@ -190,7 +190,7 @@ exports[`Skeleton should match snapshot - WithCustomHeight 1`] = ` > @@ -206,7 +206,7 @@ exports[`Skeleton should match snapshot - WithCustomHeight 1`] = ` > diff --git a/src/experimental/skeleton/index.tsx b/src/experimental/skeleton/index.tsx index 033978bb..850d3838 100644 --- a/src/experimental/skeleton/index.tsx +++ b/src/experimental/skeleton/index.tsx @@ -1,16 +1,15 @@ -import { theme } from 'nginformatica-styleguide' import React from 'react' import SkeletonLoading, { SkeletonProps } from 'react-loading-skeleton' import 'react-loading-skeleton/dist/skeleton.css' +import { theme } from '@/theme' -const mainColor = theme.colors.grays.g7 -const subColor = '#CFCFCF' +const { grays } = theme.colors export const Skeleton = (props: SkeletonProps) => ( ) diff --git a/src/icons/index.ts b/src/icons/index.ts index f918243a..eac5eb09 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -1 +1 @@ -export * from '@material-ui/icons' +export * from '@mui/icons-material' diff --git a/src/index.ts b/src/index.ts index bca7810e..d2948a60 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,6 +33,7 @@ export { default as ListItem } from './core/data-display/list-item' export { default as Menu } from './core/navigation/menu' export { default as MaskField } from './core/inputs/mask-field' export { default as Node } from './core/data-display/node' +export { default as MenuItem } from './core/data-display/menu-item' export { default as Pagination } from './core/navigation/pagination' export { default as Paper } from './core/surfaces/paper' export { default as Progress } from './core/feedback/progress' @@ -63,5 +64,6 @@ export { default as Chapter } from './core/data-display/chapter' export { default as DataTable } from './core/data-display/data-table' export { default as StepCard } from './core/surfaces/step-card' export { default as StepCardSkeleton } from './core/surfaces/step-card/step-card-skeleton' +export { default as ValidationDialog } from './core/feedback/validation-dialog/' export * as Experimental from './experimental' export * as Icons from './icons' diff --git a/src/stories/Theme.stories.mdx b/src/stories/Theme.stories.mdx new file mode 100644 index 00000000..17e47d01 --- /dev/null +++ b/src/stories/Theme.stories.mdx @@ -0,0 +1,181 @@ +import { Meta, ColorPalette, ColorItem } from '@storybook/blocks'; + + + +## Usage + +Here is a quick example to set the ThemeProvider: + +```tsx +import React from 'react' +import { Button } from 'flipper-ui' +import { ThemeProviderFlipper } from 'flipper-ui' +import { ThemeProvider } from 'styled-components' +import { muiThemeOptions, theme } from 'nginformatica-styleguide' + +const App = () => ( + + +