Skip to content

Commit

Permalink
feat: AppForm component
Browse files Browse the repository at this point in the history
feat: Auth forms
feat: Prettier
feat: additiona scripts
fix: AppButton
refactor: AppIcon with additional icons
  • Loading branch information
karpolan committed Apr 22, 2021
1 parent eb15e2b commit 8e3d59c
Show file tree
Hide file tree
Showing 55 changed files with 1,749 additions and 1,077 deletions.
12 changes: 12 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
printWidth: 120, // max 120 chars in line, code is easy to read
useTabs: false, // use spaces instead of tabs
tabWidth: 2, // "visual width" of of the "tab"
trailingComma: 'es5', // add trailing commas in objects, arrays, etc.
semi: true, // add ; when needed
singleQuote: true, // '' for stings instead of ""
bracketSpacing: true, // import { some } ... instead of import {some} ...
arrowParens: 'always', // braces even for single param in arrow functions (a) => { }
jsxSingleQuote: false, // "" for react props, like in html
jsxBracketSameLine: false, // pretty JSX
};
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7"
"@types/react-router-dom": "^5.1.7",
"prettier": "^2.2.1"
},
"scripts": {
"start": "react-scripts start",
"dev": "npm install -s && react-scripts start",
"build": "react-scripts build",
"type": "tsc",
"format": "node_modules/.bin/prettier src --write",
"test": "react-scripts test"
},
"eslintConfig": {
Expand Down
26 changes: 13 additions & 13 deletions src/components/AppAlert/AppAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ const APP_ALERT_SEVERITY = 'info'; // 'error' | 'info'| 'success' | 'warning'
const APP_ALERT_VARIANT = 'standard'; // 'filled' | 'outlined' | 'standard'

const useStyles = makeStyles((theme: Theme) => ({
root: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
root: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
}));

/**
* Application styled Alert component
*/
const AppAlert: React.FC<MuiAlertProps> = ({
severity = APP_ALERT_SEVERITY,
variant = APP_ALERT_VARIANT,
className,
onClose,
...restOfProps
severity = APP_ALERT_SEVERITY,
variant = APP_ALERT_VARIANT,
className,
onClose,
...restOfProps
}) => {
const classes = useStyles();
const classRoot = clsx(classes.root, className);
const classes = useStyles();
const classRoot = clsx(classes.root, className);

return <MuiAlert className={classRoot} severity={severity} variant={variant} onClose={onClose} {...restOfProps} />;
return <MuiAlert className={classRoot} severity={severity} variant={variant} onClose={onClose} {...restOfProps} />;
};

export default AppAlert;
export default AppAlert;
118 changes: 59 additions & 59 deletions src/components/AppButton/AppButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,73 +9,73 @@ import { ColorName } from '../../utils/style';
* @param {boolean} [ignoreClassName] - optional flag to ignore className (color "inherit" doesn't use any class name)
*/
function testButtonColor(colorName: string, expectedClassName = colorName, ignoreClassName = false) {
it(`supports "${colorName}" color`, async () => {
let text = `${colorName} button`;
await render(<AppButton color={colorName as ColorName}>{text}</AppButton>);
it(`supports "${colorName}" color`, async () => {
let text = `${colorName} button`;
await render(<AppButton color={colorName as ColorName}>{text}</AppButton>);

let span = await screen.getByText(text); // <span> with specific text
expect(span).toBeDefined();
let span = await screen.getByText(text); // <span> with specific text
expect(span).toBeDefined();

let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
if (!ignoreClassName) {
expect(button?.className?.includes(`makeStyles-${expectedClassName}`)).toBeTruthy(); // There is "makeStyles-[expectedClassName]-xxx" class
}
});
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
if (!ignoreClassName) {
expect(button?.className?.includes(`makeStyles-${expectedClassName}`)).toBeTruthy(); // There is "makeStyles-[expectedClassName]-xxx" class
}
});
}

describe('AppButton component', () => {
// beforeEach(() => {});
// beforeEach(() => {});

it('renders itself', async () => {
let text = 'sample button';
await render(<AppButton>{text}</AppButton>);
let span = await screen.getByText(text);
expect(span).toBeDefined();
expect(span).toHaveTextContent(text);
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
expect(button).toHaveAttribute('type', 'button'); // not "submit" or "input" by default
});
it('renders itself', async () => {
let text = 'sample button';
await render(<AppButton>{text}</AppButton>);
let span = await screen.getByText(text);
expect(span).toBeDefined();
expect(span).toHaveTextContent(text);
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
expect(button).toHaveAttribute('type', 'button'); // not "submit" or "input" by default
});

testButtonColor('primary');
testButtonColor('secondary');
testButtonColor('error');
testButtonColor('warning');
testButtonColor('info');
testButtonColor('success');
testButtonColor('true');
testButtonColor('false');
testButtonColor('primary');
testButtonColor('secondary');
testButtonColor('error');
testButtonColor('warning');
testButtonColor('info');
testButtonColor('success');
testButtonColor('true');
testButtonColor('false');

testButtonColor('default');
testButtonColor('inherit', 'default', true);
testButtonColor('default');
testButtonColor('inherit', 'default', true);

it('supports className property', async () => {
let text = 'button with specific class';
let className = 'someClassName';
await render(<AppButton className={className}>{text}</AppButton>);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
expect(button).toHaveClass(className);
});
it('supports className property', async () => {
let text = 'button with specific class';
let className = 'someClassName';
await render(<AppButton className={className}>{text}</AppButton>);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
expect(button).toHaveClass(className);
});

it('supports label property', async () => {
let text = 'button with label';
await render(<AppButton label={text} />);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
});
it('supports label property', async () => {
let text = 'button with label';
await render(<AppButton label={text} />);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
});

it('supports text property', async () => {
let text = 'button with text';
await render(<AppButton text={text} />);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
});
});
it('supports text property', async () => {
let text = 'button with text';
await render(<AppButton text={text} />);
let span = await screen.getByText(text);
expect(span).toBeDefined();
let button = await span.closest('button'); // parent <button> element
expect(button).toBeDefined();
});
});
78 changes: 40 additions & 38 deletions src/components/AppButton/AppButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,27 @@ import { buttonStylesByNames, ColorName } from '../../utils/style';
const APP_BUTTON_VARIANT = 'contained'; // | 'text' | 'outlined'

const useStyles = makeStyles((theme: Theme) => ({
box: {
display: 'inline-block',
},
// Add "filled" styles for Material UI names 'primary', 'secondary', 'warning', and so on
...buttonStylesByNames(theme),
box: {
display: 'inline-block',
},
// Add "filled" styles for Material UI names 'primary', 'secondary', 'warning', and so on
...buttonStylesByNames(theme),
}));

interface Props extends Omit<ButtonProps, 'color'> {
color?: ColorName | 'inherit';
label?: string; // Alternate to text
text?: string; // Alternate to label
m?: number;
mt?: number;
mb?: number;
ml?: number;
mr?: number;
// Missing props
component?: React.ElementType; // Could be RouterLink, AppLink, etc.
to?: string; // Link prop
href?: string; // Link prop
color?: ColorName | 'inherit';
label?: string; // Alternate to text
text?: string; // Alternate to label
m?: number;
mt?: number;
mb?: number;
ml?: number;
mr?: number;
// Missing props
component?: React.ElementType; // Could be RouterLink, AppLink, etc.
to?: string; // Link prop
href?: string; // Link prop
underline?: 'none' | 'hover' | 'always' // Link prop
}

/**
Expand All @@ -38,27 +39,28 @@ interface Props extends Omit<ButtonProps, 'color'> {
* @param {string} [text] - text to render, alternate to .label
*/
const AppButton: React.FC<Props> = ({
className,
children,
color = 'default',
label,
text,
m = 0,
mt = 1,
mb = 1,
ml = 1,
mr = 1,
...restOfProps
className,
children,
color = 'default',
label,
text,
m = 0,
mt = 1,
mb = 1,
ml = 1,
mr = 1,
underline = 'none',
...restOfProps
}) => {
const classes = useStyles();
const classButton = clsx(classes[color as ColorName], className);
return (
<Box {...{ m, mt, mb, ml, mr }} className={classes.box}>
<Button className={classButton} variant={APP_BUTTON_VARIANT} {...restOfProps}>
{children || label || text}
</Button>
</Box>
);
const classes = useStyles();
const classButton = clsx(classes[color as ColorName], className);
return (
<Box {...{ m, mt, mb, ml, mr }} className={classes.box}>
<Button className={classButton} variant={APP_BUTTON_VARIANT} {...{ ...restOfProps, underline }}>
{children || label || text}
</Button>
</Box>
);
};

export default AppButton;
export default AppButton;
32 changes: 32 additions & 0 deletions src/components/AppForm/AppForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ReactNode, FormHTMLAttributes } from 'react';
import { Grid } from '@material-ui/core';
import { Theme, makeStyles } from '@material-ui/core/styles';
import { formStyle } from '../../utils/style';

export const useStyles = makeStyles((theme: Theme) => ({
formBody: {
...formStyle(theme),
},
}));

interface Props extends FormHTMLAttributes<HTMLFormElement> {
children: ReactNode;
}

/**
* Application styled Form container
*/
const AppForm: React.FC<Props> = ({ children, ...resOfProps }) => {
const classes = useStyles();
return (
<form {...resOfProps}>
<Grid container direction="column" alignItems="center">
<Grid item className={classes.formBody}>
{children}
</Grid>
</Grid>
</form>
);
};

export default AppForm;
3 changes: 3 additions & 0 deletions src/components/AppForm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import AppForm from './AppForm';

export { AppForm as default, AppForm };
Loading

0 comments on commit 8e3d59c

Please sign in to comment.