DEV;Forms

This commit is contained in:
Roman Jaroš 2019-04-21 20:27:51 +02:00
parent b2d239fbba
commit 0eb9f98aaf
52 changed files with 15338 additions and 14490 deletions

View file

@ -43,6 +43,8 @@
"tab" "tab"
], ],
"@typescript-eslint/interface-name-prefix": 0, "@typescript-eslint/interface-name-prefix": 0,
"@typescript-eslint/no-empty-interface:": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-member-accessibility": 2, "@typescript-eslint/explicit-member-accessibility": 2,
"@typescript-eslint/no-explicit-any": 0, "@typescript-eslint/no-explicit-any": 0,
"no-console": [ "no-console": [

View file

@ -8,5 +8,6 @@ server {
index index.html; index index.html;
location / { location / {
} try_files $uri $uri/ /index.html;
}
} }

View file

@ -11,6 +11,16 @@ module.exports = {
'json', 'json',
], ],
'moduleNameMapper': {
'^documentation(.*)$': '<rootDir>/modules/documentation/src/modules/$1',
'^treejs-components(.*)$': '<rootDir>/modules/treejs-components/src/$1',
'^treejs-constants(.*)$': '<rootDir>/modules/treejs-constants/src/$1',
'^treejs-utils$': '<rootDir>/modules/treejs-utils',
'^treejs-forms(.*)$': '<rootDir>/modules/treejs-forms/src/$1',
'^treejs-redux(.*)$': '<rootDir>/modules/treejs-redux/src/$1',
'^types(.*)$': '<rootDir>/modules/types/$1',
},
// enzyme // enzyme
'snapshotSerializers': ['enzyme-to-json/serializer'], 'snapshotSerializers': ['enzyme-to-json/serializer'],
'setupFilesAfterEnv': ['./modules/enzyme.config.ts'], 'setupFilesAfterEnv': ['./modules/enzyme.config.ts'],

View file

@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"treejs-components": "^0.0.1", "treejs-components": "^0.0.1",
"treejs-utils": "^0.0.1", "treejs-utils": "^0.0.1",
"treejs-forms": "^0.0.1",
"treejs-redux": "^0.0.1" "treejs-redux": "^0.0.1"
} }
} }

View file

@ -0,0 +1,149 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`(component) App should match snapshot 1`] = `
<ThemeProvider
theme={
Object {
"black": "#636366",
"disableColor": "#dddddd",
"errorColor": "#ff4444",
"errorDarkColor": "#CC0000",
"focusColor": "#76B3FA",
"gray": "#f5f5f5",
"infoColor": "#33b5e5",
"infoDarkColor": "#0099CC",
"monitorScreenSize": 1024,
"primaryColor": "#DC7633",
"secondaryColor": "#ffffff",
"successColor": "#00C851",
"successDarkColor": "#007E33",
"tabletScreenSize": 480,
"warningColor": "#ffbb33",
"warningDarkColor": "#FF8800",
"white": "#fff",
}
}
>
<styled.div>
<PageLayout
history={
Object {
"action": "POP",
"block": [Function],
"createHref": [Function],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
}
}
leftMenuItems={
Array [
Object {
"href": "/button",
"label": "Button",
},
Object {
"href": "/checkbox",
"label": "Checkbox",
},
Object {
"href": "/grid",
"label": "Grid",
},
Object {
"href": "/modal",
"label": "Modal",
},
Object {
"href": "/radioButton",
"label": "Radio",
},
Object {
"href": "/selectBox",
"label": "SelectBox",
},
Object {
"href": "/textField",
"label": "TextField",
},
Object {
"href": "/forms",
"label": "Forms",
},
]
}
>
<Router
history={
Object {
"action": "POP",
"block": [Function],
"createHref": [Function],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
}
}
>
<Route
component={[Function]}
exact={true}
path="/"
/>
<Route
component={[Function]}
path="/button"
/>
<Route
component={[Function]}
path="/checkbox"
/>
<Route
component={[Function]}
path="/grid"
/>
<Route
component={[Function]}
path="/modal"
/>
<Route
component={[Function]}
path="/radioButton"
/>
<Route
component={[Function]}
path="/selectBox"
/>
<Route
component={[Function]}
path="/textField"
/>
<Route
component={[Function]}
path="/forms"
/>
</Router>
</PageLayout>
</styled.div>
</ThemeProvider>
`;

View file

@ -2,7 +2,6 @@ import * as React from 'react';
import { hot } from 'react-hot-loader' import { hot } from 'react-hot-loader'
import { Route, Router } from 'react-router'; import { Route, Router } from 'react-router';
import main from 'treejs-components/themes/main';
import { ThemeProvider } from 'treejs-components/styled'; import { ThemeProvider } from 'treejs-components/styled';
import PageLayout from 'treejs-components/Layout/containers'; import PageLayout from 'treejs-components/Layout/containers';
@ -13,7 +12,9 @@ import ModalPage from 'documentation/ModalPage/components';
import RadioButtonPage from 'documentation/RadioButtonPage/components'; import RadioButtonPage from 'documentation/RadioButtonPage/components';
import SelectBoxPage from 'documentation/SelectBoxPage/components'; import SelectBoxPage from 'documentation/SelectBoxPage/components';
import TextFieldPage from 'documentation/TextFieldPage/components'; import TextFieldPage from 'documentation/TextFieldPage/components';
import FormsPage from 'documentation/FormsPage/components';
import WelcomePage from 'documentation/WelcomePage/components'; import WelcomePage from 'documentation/WelcomePage/components';
import { THEME } from 'documentation/WelcomePage/constants';
import { MainStyle } from '../styles/App'; import { MainStyle } from '../styles/App';
import history from '../utils/history'; import history from '../utils/history';
@ -25,13 +26,17 @@ const App = (): React.ReactElement => {
{ label: 'Checkbox', href: '/checkbox' }, { label: 'Checkbox', href: '/checkbox' },
{ label: 'Grid', href: '/grid' }, { label: 'Grid', href: '/grid' },
{ label: 'Modal', href: '/modal' }, { label: 'Modal', href: '/modal' },
{ label: 'RadioButton', href: '/radioButton' }, { label: 'Radio', href: '/radioButton' },
{ label: 'SelectBox', href: '/selectBox' }, { label: 'SelectBox', href: '/selectBox' },
{ label: 'TextField', href: '/textField' }, { label: 'TextField', href: '/textField' },
{ label: 'Forms', href: '/forms' },
]; ];
const themeName = window.localStorage.getItem(THEME) || 'main';
const theme = require(`treejs-components/themes/${themeName}`).default;
return ( return (
<ThemeProvider theme={main}> <ThemeProvider theme={theme}>
<MainStyle> <MainStyle>
<PageLayout leftMenuItems={leftMenuItems} history={history}> <PageLayout leftMenuItems={leftMenuItems} history={history}>
<Router history={history}> <Router history={history}>
@ -43,6 +48,7 @@ const App = (): React.ReactElement => {
<Route path="/radioButton" component={RadioButtonPage} /> <Route path="/radioButton" component={RadioButtonPage} />
<Route path="/selectBox" component={SelectBoxPage} /> <Route path="/selectBox" component={SelectBoxPage} />
<Route path="/textField" component={TextFieldPage} /> <Route path="/textField" component={TextFieldPage} />
<Route path="/forms" component={FormsPage} />
</Router> </Router>
</PageLayout> </PageLayout>
</MainStyle> </MainStyle>

View file

@ -1,6 +1,5 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import treejsReducer from 'treejs-redux/index'; import treejsReducer from 'treejs-redux/index';

View file

@ -11,4 +11,6 @@ export const MainStyle = styled.div`
display: flex; display: flex;
height: 100vh; height: 100vh;
-webkit-tap-highlight-color: transparent;
`; `;

View file

@ -12,7 +12,7 @@ const CheckboxPage = (): React.ReactElement => {
<h3>Normal</h3> <h3>Normal</h3>
<Grid> <Grid>
<GridCol size={3}> <GridCol size={3}>
<Checkbox id="checkbox" title="Checkbox label" /> <Checkbox name="checkbox" title="Checkbox label" />
</GridCol> </GridCol>
</Grid> </Grid>
</React.Fragment> </React.Fragment>

View file

@ -0,0 +1,130 @@
import * as React from 'react';
import { Grid, GridCol } from 'treejs-components/Grid';
import Field from 'treejs-forms/components/Field';
import Button from 'treejs-components/Button';
import { FIELD_TYPE } from 'treejs-forms/constants';
import { Form } from 'treejs-forms/components/Form';
import { FormErrors, IForm } from 'types/form/form';
interface FormValues {
checkbox: boolean;
radiobutton: string;
selectbox: string;
text: string;
}
class ExampleForm extends React.PureComponent implements IForm<FormValues> {
public initialValues: FormValues = {
text: '',
checkbox: null,
radiobutton: '',
selectbox: '',
};
public handleSubmit = (values: FormValues): void => {
console.info(values);
};
public handleValidate = (values: FormValues): FormErrors<FormValues> => {
const errors: FormErrors<FormValues> = {};
if (!values.text) {
errors.text = 'Required';
}
if (!values.radiobutton) {
errors.radiobutton = 'Required';
}
if (!values.selectbox) {
errors.selectbox = 'Required';
}
return errors;
};
public render(): React.ReactElement {
const radioOptions = [
{ name: 'Field 1', code: 'field1' },
{ name: 'Field 2', code: 'field2' }
];
const selectBoxOptions = [
{ name: 'Option 1', code: 'option1' },
{ name: 'Option 2', code: 'option2' }
];
return (
<Form<FormValues>
initialValues={this.initialValues}
onSubmit={this.handleSubmit}
validate={this.handleValidate}
>
{({ errors }): React.ReactElement => (
<React.Fragment>
<Grid>
<GridCol size={3}>
<Field
name="text"
title="Input"
error={errors.text}
component={FIELD_TYPE.TEXT_FIELD}
/>
</GridCol>
<GridCol size={3}>
<Field
name="checkbox"
title="Checkbox"
error={errors.checkbox}
component={FIELD_TYPE.CHECKBOX}
/>
</GridCol>
<GridCol size={3}>
<Field
name="radiobutton"
title="Radio Button"
error={errors.radiobutton}
options={radioOptions}
component={FIELD_TYPE.RADIO_BUTTON}
/>
</GridCol>
<GridCol size={3}>
<Field
name="selectbox"
title="Selectbox"
error={errors.selectbox}
options={selectBoxOptions}
component={FIELD_TYPE.SELECT_BOX}
/>
</GridCol>
</Grid>
<Grid>
<GridCol
size={3}>
<Button
type="submit"
title="Send" />
</GridCol>
</Grid>
</React.Fragment>
)}
</Form>
);
}
}
const FormsPage = (): React.ReactElement => (
<React.Fragment>
<h2>Forms</h2>
<h3>Normal</h3>
<ExampleForm />
</React.Fragment>
);
export default FormsPage;

View file

@ -21,18 +21,18 @@ const ModalPage = (): React.ReactElement => {
<Grid> <Grid>
<GridCol size={4}> <GridCol size={4}>
<AddModalButton <AddModalButton
id="modalName" name="modalName"
title="Open modal" title="Open modal"
name="Modální okno 1" modalTitle="Modální okno 1"
component={<ComponentA />} component={<ComponentA />}
/> />
</GridCol> </GridCol>
<GridCol size={4}> <GridCol size={4}>
<AddModalButton <AddModalButton
id="nextModal" name="nextModal"
width={250} width={250}
title="Open small modal" title="Open small modal"
name="Modální okno 2" modalTitle="Modální okno 2"
component={<ComponentB />} component={<ComponentB />}
/> />
</GridCol> </GridCol>

View file

@ -12,7 +12,7 @@ const RadioButtonPage = (): React.ReactElement => (
<Grid> <Grid>
<GridCol size={3}> <GridCol size={3}>
<RadioButton <RadioButton
id="radioButtons" name="radioButtons"
options={[ options={[
{ name: 'item 1', code: 'item1' }, { name: 'item 1', code: 'item1' },
{ name: 'item 2', code: 'item2' }, { name: 'item 2', code: 'item2' },

View file

@ -12,7 +12,7 @@ const SelectBoxPage = (): React.ReactElement => (
<Grid> <Grid>
<GridCol size={3}> <GridCol size={3}>
<SelectBox <SelectBox
id="selectBox" name="selectBox"
title="Zvolte den v týdnu" title="Zvolte den v týdnu"
options={[ options={[
{ name: 'Pondělí', code: 'po' }, { name: 'Pondělí', code: 'po' },

View file

@ -11,20 +11,20 @@ const TextFieldPage = (): React.ReactElement => (
<h3>Normal</h3> <h3>Normal</h3>
<Grid> <Grid>
<GridCol size={3}> <GridCol size={3}>
<TextField id="normal" title="Uživatelské jméno" /> <TextField name="normal" title="Uživatelské jméno" />
</GridCol> </GridCol>
<GridCol size={3}> <GridCol size={3}>
<TextField id="normal2" title="Heslo" /> <TextField name="normal2" title="Heslo" />
</GridCol> </GridCol>
</Grid> </Grid>
<h3>Disable</h3> <h3>Disable</h3>
<Grid> <Grid>
<GridCol size={3}> <GridCol size={3}>
<TextField id="disable" title="Disable" disabled value="value" /> <TextField name="disable" title="Disable" disabled value="value" />
</GridCol> </GridCol>
<GridCol size={3}> <GridCol size={3}>
<TextField id="disable" title="Disable without value" disabled /> <TextField name="disable" title="Disable without value" disabled />
</GridCol> </GridCol>
</Grid> </Grid>
</React.Fragment> </React.Fragment>

View file

@ -1,8 +1,37 @@
import * as React from 'react'; import * as React from 'react';
import SelectBox from 'treejs-components/SelectBox/containers';
import { IOption } from 'treejs-components/SelectBox/types';
import { Grid, GridCol } from 'treejs-components/Grid';
import { THEME } from '../constants';
const changeTheme = (option: IOption): void => {
window.localStorage.setItem(THEME, option.code);
window.location.reload();
};
const WelcomePage = (): React.ReactElement => ( const WelcomePage = (): React.ReactElement => (
<h2>Welcome</h2> <React.Fragment>
<h2>Welcome</h2>
<Grid>
<GridCol size={2}>
<SelectBox
name="theme"
title="Choose theme"
value={window.localStorage.getItem(THEME)}
options={[
{ code: 'purple', name: 'Purple' },
{ code: 'blue', name: 'Blue' },
{ code: 'green', name: 'Green' },
]}
onChange={changeTheme}
/>
</GridCol>
</Grid>
</React.Fragment>
); );
export default WelcomePage; export default WelcomePage;

View file

@ -0,0 +1 @@
export const THEME = 'theme';

View file

@ -17,12 +17,12 @@ module.exports = (env, args) => {
devtool: 'source-map', devtool: 'source-map',
resolve: { resolve: {
alias: { alias: {
'react-dom': '@hot-loader/react-dom',
documentation: __dirname + '/src/modules', documentation: __dirname + '/src/modules',
types: __dirname + '/../../modules/types', types: __dirname + '/../../modules/types',
'treejs-components': 'treejs-components/src', 'treejs-components': 'treejs-components/src',
'treejs-constants': 'treejs-constants/src', 'treejs-constants': 'treejs-constants/src',
'treejs-redux': 'treejs-redux/src', 'treejs-redux': 'treejs-redux/src',
'treejs-forms': 'treejs-forms/src',
'treejs-utils': 'treejs-utils', 'treejs-utils': 'treejs-utils',
}, },
extensions: ['.ts', '.tsx', '.js', '.json'], extensions: ['.ts', '.tsx', '.js', '.json'],

View file

@ -16,7 +16,6 @@
"react": "^16.8.4", "react": "^16.8.4",
"react-dom": "^16.8.4", "react-dom": "^16.8.4",
"react-redux": "^6.0.1", "react-redux": "^6.0.1",
"treejs-utils": "0.0.1",
"reselect": "^4.0.0" "reselect": "^4.0.0"
} }
} }

View file

@ -12,14 +12,17 @@ export enum ButtonTypes {
interface IProps { interface IProps {
disabled?: boolean; disabled?: boolean;
onClick: (...args: any[]) => void; onClick?: (...args: any[]) => void;
status?: ButtonTypes; status?: ButtonTypes;
title: string; title: string;
type?: "submit" | "reset";
} }
class Button extends React.PureComponent<IProps> { class Button extends React.PureComponent<IProps> {
private handleOnClick = () => { private handleOnClick = () => {
this.props.onClick(); if (this.props.onClick instanceof Function) {
this.props.onClick();
}
}; };
public render(): React.ReactElement { public render(): React.ReactElement {
@ -32,6 +35,7 @@ class Button extends React.PureComponent<IProps> {
onClick={this.handleOnClick} onClick={this.handleOnClick}
disabled={this.props.disabled} disabled={this.props.disabled}
status={this.props.status} status={this.props.status}
type={this.props.type}
> >
{title} {title}
</StyledButton> </StyledButton>

View file

@ -6,7 +6,9 @@ import { StyledCheckbox } from './style';
interface IProps { interface IProps {
checked?: boolean; checked?: boolean;
id: string; name: string;
onBlur?: (e: React.FocusEvent<HTMLInputElement>, checked: boolean) => void;
onChange?: (e: React.MouseEvent<HTMLInputElement>, checked: boolean) => void;
title: string; title: string;
} }
@ -19,30 +21,46 @@ class Checkbox extends React.PureComponent<IProps, IState> {
checked: this.props.checked, checked: this.props.checked,
}; };
private handleClick = () => { private handleClick = (e: React.MouseEvent<HTMLInputElement>): void => {
if (this.props.onChange) {
this.props.onChange(e, !this.state.checked);
}
this.setState({ this.setState({
checked: !this.state.checked, checked: !this.state.checked,
}) });
};
private handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
if (this.props.onBlur) {
this.props.onBlur(e, this.state.checked);
}
}; };
public render(): React.ReactElement { public render(): React.ReactElement {
const { const {
id, name,
title, title,
} = this.props; } = this.props;
return ( return (
<StyledCheckbox> <StyledCheckbox>
<input id={id} type="checkbox" onClick={this.handleClick} /> <label htmlFor={name}>
<label htmlFor={id}> <div>{title}</div>
<FontAwesomeIcon <FontAwesomeIcon
size="lg" size="lg"
icon={ icon={this.state.checked ? 'check-square' : 'square'}
this.state.checked ? 'check-square' : 'square'
}
/> />
<span>{title}</span> <span>Check if yes</span>
</label> </label>
<input
id={name}
name={name}
type="checkbox"
onClick={this.handleClick}
onBlur={this.handleBlur}
/>
</StyledCheckbox> </StyledCheckbox>
); );
} }

View file

@ -2,6 +2,10 @@ import styled from '../styled';
export const StyledCheckbox = styled.div` export const StyledCheckbox = styled.div`
position: relative;
margin-top: 3px;
& input[type=checkbox] { & input[type=checkbox] {
display: none; display: none;
} }
@ -11,6 +15,15 @@ export const StyledCheckbox = styled.div`
color: ${(p) => p.theme.primaryColor}; color: ${(p) => p.theme.primaryColor};
} }
& div {
display: block;
color: ${(p) => p.theme.black};
padding-bottom: 10px;
font-size: 13px;
}
& span { & span {
margin-left: 5px; margin-left: 5px;
color: ${(p) => p.theme.black}; color: ${(p) => p.theme.black};

View file

@ -1,7 +1,9 @@
import styled from '../styled'; import styled from '../styled';
export const Grid = styled.div` export const Grid = styled.div.attrs({
className: 'Grid'
})`
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
`; `;
@ -11,9 +13,13 @@ interface IGridCol {
size?: number; size?: number;
} }
export const GridCol = styled.div<IGridCol>` export const GridCol = styled.div.attrs({
className: 'GridCol'
})<IGridCol>`
margin: 5px; margin: 5px;
align-self: flex-start;
width: calc(100% - 10px); width: calc(100% - 10px);
@media only screen and (min-width: ${(p) => p.theme.tabletScreenSize}px) { @media only screen and (min-width: ${(p) => p.theme.tabletScreenSize}px) {

View file

@ -10,9 +10,9 @@ export const addModal = (options: IModalOptions): IAction<IModalOptions> => ({
payload: options payload: options
}); });
export const closeModal = (id: IModalIdOption): IAction<IModalOptions> => ({ export const closeModal = (name: IModalIdOption): IAction<IModalOptions> => ({
type: MODAL_ACTIONS.REMOVE_MODAL, type: MODAL_ACTIONS.REMOVE_MODAL,
payload: { payload: {
id name,
} }
}); });

View file

@ -12,21 +12,22 @@ import { addModalComponent } from '../utils/registerModal';
interface IProps extends IModalOptions { interface IProps extends IModalOptions {
addModal: (options: IModalOptions) => void; addModal: (options: IModalOptions) => void;
component: React.ReactElement; component: React.ReactElement;
modalTitle: string;
title: string; title: string;
} }
const AddModalButton = (props: IProps): React.ReactElement => { const AddModalButton = (props: IProps): React.ReactElement => {
const { const {
id,
title,
name, name,
title,
modalTitle,
component, component,
width, width,
} = props; } = props;
const handleClick = (): void => { const handleClick = (): void => {
props.addModal({ id, name, width, }); props.addModal({ name, title: modalTitle, width });
addModalComponent(id, component) addModalComponent(name, component)
}; };
return ( return (

View file

@ -63,7 +63,7 @@ class Modals extends React.PureComponent<IProps> {
<FontAwesomeIcon icon="times" /> <FontAwesomeIcon icon="times" />
</StyledCloseButton> </StyledCloseButton>
<StyledModalHeader> <StyledModalHeader>
{modal.name} {modal.title}
</StyledModalHeader> </StyledModalHeader>
<StyledModalBody> <StyledModalBody>
{getModalComponent(key)} {getModalComponent(key)}

View file

@ -19,13 +19,13 @@ const reducer = (state = initialState, { type, payload }: IAction<payloadType>):
case MODAL_ACTIONS.ADD_MODAL: case MODAL_ACTIONS.ADD_MODAL:
return { return {
...state, ...state,
[payload.id]: { [payload.name]: {
visible: true, visible: true,
...payload, ...payload,
}, },
}; };
case MODAL_ACTIONS.REMOVE_MODAL: case MODAL_ACTIONS.REMOVE_MODAL:
return dissoc(payload.id, state); return dissoc(payload.name, state);
default: default:
return state return state
} }

View file

@ -1,8 +1,8 @@
export type IModalIdOption = string; export type IModalIdOption = string;
export interface IModalOptions { export interface IModalOptions {
id: IModalIdOption; name: IModalIdOption;
name?: string; title?: string;
visible?: boolean; visible?: boolean;
width?: number; width?: number;
} }

View file

@ -1,17 +1,18 @@
import * as React from 'react'; import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { StyledRadioButton } from './style'; import { StyledRadioButton, StyledRadioButtonItem } from './style';
import { IOption } from './types';
interface IOption {
code: string;
name: string;
}
interface IProps { interface IProps {
id: string; horizontal?: boolean;
name: string;
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
onClick?: (e: React.MouseEvent<HTMLInputElement>, option: IOption) => void;
options: IOption[]; options: IOption[];
title?: string;
value?: string;
} }
interface IState { interface IState {
@ -19,26 +20,63 @@ interface IState {
} }
class RadioButton extends React.PureComponent<IProps, IState> { class RadioButton extends React.PureComponent<IProps, IState> {
public readonly state = { private static defaultProps = {
value: '', horizontal: false,
}; };
private handleClick = (option: IOption) => () => { public readonly state = {
value: this.props.value,
};
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
let newValue = this.state.value;
if (prevProps.value !== this.props.value) {
newValue = this.props.value;
} else if (prevState.value !== this.state.value) {
newValue = this.state.value;
} else {
return;
}
this.setState({
value: newValue,
});
}
private handleClick = (option: IOption): any => (e: React.MouseEvent<HTMLInputElement>): void => {
if (this.props.onClick) {
this.props.onClick(e, option);
}
this.setState({ this.setState({
value: option.code, value: option.code,
}) })
}; };
private handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
if (this.props.onBlur) {
this.props.onBlur(e);
}
};
public render(): React.ReactElement { public render(): React.ReactElement {
const { const {
id, title,
options, options,
horizontal,
} = this.props; } = this.props;
const optionElements = options.map( const optionElements = options.map(
({ code, name }) => ( ({ code, name }): React.ReactElement => (
<React.Fragment key={code}> <StyledRadioButtonItem horizontal={horizontal} key={code}>
<input id={code} name={id} type="radio" onClick={this.handleClick({ code, name })} /> <input
id={code}
name={name}
type="radio"
onClick={this.handleClick({ code, name })}
onBlur={this.handleBlur}
/>
<label htmlFor={code}> <label htmlFor={code}>
<FontAwesomeIcon <FontAwesomeIcon
size="lg" size="lg"
@ -48,12 +86,13 @@ class RadioButton extends React.PureComponent<IProps, IState> {
/> />
<span>{name}</span> <span>{name}</span>
</label> </label>
</React.Fragment> </StyledRadioButtonItem>
) )
); );
return ( return (
<StyledRadioButton> <StyledRadioButton>
<div>{title}</div>
{optionElements} {optionElements}
</StyledRadioButton> </StyledRadioButton>
); );

View file

@ -2,23 +2,42 @@ import styled from '../styled';
export const StyledRadioButton = styled.div` export const StyledRadioButton = styled.div`
position: relative;
margin-top: 3px;
& div:first-child {
display: block;
color: ${(p) => p.theme.black};
padding-bottom: 10px;
font-size: 13px;
}
`;
interface IStyledRadioButtonItem {
horizontal: boolean;
}
export const StyledRadioButtonItem = styled.div<IStyledRadioButtonItem>`
margin: ${(p) => p.horizontal ? '0 0 0 10px' : '0 0 10px 0'};
display: ${(p) => p.horizontal ? 'inline-block' : 'block'};
&:nth-child(2) {
margin: ${(p) => p.horizontal ? '0' : '0 0 10px 0'};
}
& input[type=radio] { & input[type=radio] {
display: none; display: none;
} }
& label { & label {
cursor: pointer; cursor: pointer;
display: block;
margin-bottom: 10px;
color: ${(p) => p.theme.primaryColor}; color: ${(p) => p.theme.primaryColor};
} }
& span { & span {
margin-left: 5px; margin-left: 5px;
color: ${(p) => p.theme.black}; color: ${(p) => p.theme.black};
} }
`; `;

View file

@ -0,0 +1,4 @@
export interface IOption {
code: string;
name: string;
}

View file

@ -12,7 +12,7 @@ import { isNilOrEmpty } from 'treejs-utils';
interface IProps { interface IProps {
closeModal: (id: IModalIdOption) => void; closeModal: (id: IModalIdOption) => void;
id: IModalIdOption; name: IModalIdOption;
onChange: (options: IOption) => void; onChange: (options: IOption) => void;
onRemove: () => void; onRemove: () => void;
options: IOption[]; options: IOption[];
@ -56,12 +56,12 @@ class SelectBoxModal extends React.Component<IProps, IState> {
private setActiveOption = (option: IOption) => (): void => { private setActiveOption = (option: IOption) => (): void => {
this.props.onChange(option); this.props.onChange(option);
this.props.closeModal(this.props.id); this.props.closeModal(this.props.name);
}; };
private removeActiveOption = (): void => { private removeActiveOption = (): void => {
this.props.onRemove(); this.props.onRemove();
this.props.closeModal(this.props.id); this.props.closeModal(this.props.name);
}; };
private handleKeyUp = (event: KeyboardEvent): void => { private handleKeyUp = (event: KeyboardEvent): void => {

View file

@ -1,7 +1,10 @@
import * as React from 'react'; import * as React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { propOr } from 'ramda'; import { find, propEq, propOr } from 'ramda';
import { isNilOrEmpty, noop } from 'treejs-utils';
import { STATUS } from 'types/common';
import { addModal, closeModal } from '../../Modal/actions'; import { addModal, closeModal } from '../../Modal/actions';
import { IModalIdOption, IModalOptions } from '../../Modal/types'; import { IModalIdOption, IModalOptions } from '../../Modal/types';
@ -14,11 +17,15 @@ import SelectBoxModal from '../components/SelectBoxModal';
interface IProps { interface IProps {
closeModal: (id: IModalIdOption) => void; closeModal: (name: IModalIdOption) => void;
id: string; name: string;
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
onChange?: (option?: IOption) => void;
openModal: (options: IModalOptions) => void; openModal: (options: IModalOptions) => void;
options: IOption[]; options: IOption[];
status?: STATUS;
title: string; title: string;
value?: string;
} }
interface IState { interface IState {
@ -26,6 +33,10 @@ interface IState {
} }
class SelectBox extends React.PureComponent<IProps, IState> { class SelectBox extends React.PureComponent<IProps, IState> {
public static defaultProps = {
onChange: noop,
};
public readonly state = { public readonly state = {
selectedOption: { selectedOption: {
code: null as string, code: null as string,
@ -33,21 +44,55 @@ class SelectBox extends React.PureComponent<IProps, IState> {
}, },
}; };
private handleOptionClick = (option: IOption) => { public componentDidMount(): void {
if (!isNilOrEmpty(this.props.value)) {
if (!isNilOrEmpty(this.props.options)) {
const newValue = find(propEq('code', this.props.value), this.props.options);
this.setState({
selectedOption: newValue,
});
}
}
}
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
if (isNilOrEmpty(prevState.selectedOption)) {
return;
}
if (prevProps.value !== this.props.value) {
if (!isNilOrEmpty(this.props.options)) {
const newValue = find(propEq('code', this.props.value), this.props.options);
this.setState({
selectedOption: newValue,
});
}
}
}
private handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
if (this.props.onBlur) {
this.props.onBlur(e);
}
};
private handleOptionClick = (option: IOption): void => {
this.setState({ this.setState({
selectedOption: option, selectedOption: option,
}); });
this.props.onChange(option);
}; };
private handleOptionRemove = () => { private handleOptionRemove = (): void => {
this.setState({ this.setState({
selectedOption: null, selectedOption: null,
}); });
this.props.onChange();
}; };
private openModal = () => { private openModal = (): void => {
const { const {
id, name,
title, title,
options, options,
closeModal, closeModal,
@ -57,9 +102,9 @@ class SelectBox extends React.PureComponent<IProps, IState> {
} = this.state; } = this.state;
addModalComponent( addModalComponent(
id, name,
<SelectBoxModal <SelectBoxModal
id={id} name={name}
options={options} options={options}
selectedOption={selectedOption} selectedOption={selectedOption}
closeModal={closeModal} closeModal={closeModal}
@ -67,13 +112,14 @@ class SelectBox extends React.PureComponent<IProps, IState> {
onRemove={this.handleOptionRemove} onRemove={this.handleOptionRemove}
/> />
); );
this.props.openModal({ id, name: title, width: 300 }); this.props.openModal({ name, title, width: 300 });
}; };
public render(): React.ReactElement { public render(): React.ReactElement {
const { const {
id, name,
title, title,
status,
} = this.props; } = this.props;
const { const {
@ -81,14 +127,16 @@ class SelectBox extends React.PureComponent<IProps, IState> {
} = this.state; } = this.state;
return ( return (
<StyledSelectBox id={id}> <StyledSelectBox id={name}>
<TextField <TextField
id={id} name={name}
title={title} title={title}
rightIcon={<FontAwesomeIcon icon="caret-square-down" />} rightIcon={<FontAwesomeIcon icon="caret-square-down" />}
onClick={this.openModal} onClick={this.openModal}
onFocus={this.openModal} onFocus={this.openModal}
onBlur={this.handleBlur}
value={propOr('', 'name', selectedOption)} value={propOr('', 'name', selectedOption)}
status={status}
readonly readonly
/> />
</StyledSelectBox> </StyledSelectBox>

View file

@ -1,18 +1,21 @@
import * as React from 'react'; import * as React from 'react';
import { isNilOrEmpty } from 'treejs-utils'; import { isNilOrEmpty } from 'treejs-utils';
import { STATUS } from 'types/common';
import { StyledContainer, StyledTextField, StyledLabel, StyledTextFieldIcon } from './style'; import { StyledContainer, StyledTextField, StyledLabel, StyledTextFieldIcon } from './style';
interface IProps { interface IProps {
defaultValue?: string;
disabled?: boolean; disabled?: boolean;
id: string; name: string;
onBlur?: () => void; onBlur?: (e: React.FocusEvent<HTMLInputElement>, value: string) => void;
onChange?: (e: React.ChangeEvent<HTMLInputElement>, value: string) => void;
onClick?: () => void; onClick?: () => void;
onFocus?: () => void; onFocus?: () => void;
readonly?: boolean; readonly?: boolean;
rightIcon?: React.ReactElement; rightIcon?: React.ReactElement;
status?: STATUS;
title: string; title: string;
type?: 'text' | 'password'; type?: 'text' | 'password';
value?: string; value?: string;
@ -25,50 +28,69 @@ interface IState {
class TextField extends React.PureComponent<IProps, IState> { class TextField extends React.PureComponent<IProps, IState> {
private inputRef = React.createRef<HTMLInputElement>(); private inputRef = React.createRef<HTMLInputElement>();
private static defaultProps = { public static defaultProps = {
type: 'text', type: 'text',
}; };
public static getDerivedStateFromProps(nextProps: IProps, prevState: IState): IState { public componentDidMount(): void {
if (nextProps.value !== prevState.value) { if (!isNilOrEmpty(this.props.defaultValue)) {
return { this.setState({
value: nextProps.value value: this.props.defaultValue
}; });
} }
return null; }
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
let newValue = this.state.value;
if (prevProps.value !== this.props.value) {
newValue = this.props.value;
} else if (prevState.value !== this.state.value) {
newValue = this.state.value;
} else {
return;
}
this.setState({
value: newValue,
});
} }
public readonly state = { public readonly state = {
isActive: false, isActive: false,
value: null as string, value: this.props.value,
}; };
private setFocus = () => { private setFocus = (): void => {
this.inputRef.current.focus(); this.inputRef.current.focus();
}; };
private handleClick = () => { private handleClick = (): void => {
if (this.props.onClick) { if (this.props.onClick) {
this.props.onClick(); this.props.onClick();
} }
}; };
private handleFocus = () => { private handleFocus = (): void => {
if (this.props.onFocus) { if (this.props.onFocus) {
this.props.onFocus(); this.props.onFocus();
} }
}; };
private handleBlur = () => { private handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
if (this.props.onBlur) { if (this.props.onBlur) {
this.props.onBlur(); this.props.onBlur(e, e.currentTarget.value);
} }
}; };
private handleKeyUp = (e: React.FormEvent<HTMLInputElement>) => { private handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
if (this.props.disabled) { if (this.props.disabled) {
return; return;
} }
if (this.props.onChange) {
this.props.onChange(e, e.currentTarget.value);
}
this.setState({ this.setState({
value: e.currentTarget.value, value: e.currentTarget.value,
}); });
@ -76,31 +98,33 @@ class TextField extends React.PureComponent<IProps, IState> {
public render(): React.ReactElement { public render(): React.ReactElement {
const { const {
id, name,
title, title,
type, type,
disabled, disabled,
readonly, readonly,
rightIcon, rightIcon,
status,
} = this.props; } = this.props;
return ( return (
<StyledContainer> <StyledContainer>
<StyledLabel htmlFor={id}>{title}</StyledLabel> <StyledLabel htmlFor={name}>{title}</StyledLabel>
<StyledTextField <StyledTextField
ref={this.inputRef} ref={this.inputRef}
autoComplete="off" autoComplete="off"
id={id} // for click on label id={name} // for click on label
name={id} name={name}
type={type} type={type}
disabled={disabled} disabled={disabled}
readOnly={readonly} readOnly={readonly}
value={this.state.value} value={this.state.value || ''}
noValue={isNilOrEmpty(this.state.value)} noValue={isNilOrEmpty(this.state.value)}
onClick={this.handleClick} onClick={this.handleClick}
onFocus={this.handleFocus} onFocus={this.handleFocus}
onBlur={this.handleBlur} onBlur={this.handleBlur}
onKeyUp={this.handleKeyUp} onChange={this.handleChange}
status={status}
/> />
<StyledTextFieldIcon onClick={this.setFocus}> <StyledTextFieldIcon onClick={this.setFocus}>
{rightIcon} {rightIcon}

View file

@ -1,10 +1,14 @@
import styled, { css } from '../styled';
import { RefObject } from 'react'; import { RefObject } from 'react';
import { STATUS } from 'types/common';
import styled, { css } from '../styled';
interface ITextField { interface ITextField {
noValue: boolean; noValue: boolean;
ref: RefObject<HTMLInputElement>; ref: RefObject<HTMLInputElement>;
status: STATUS;
} }
export const StyledContainer = styled.div.attrs({ export const StyledContainer = styled.div.attrs({
@ -18,8 +22,8 @@ export const StyledContainer = styled.div.attrs({
`; `;
export const StyledTextField = styled.input.attrs({ export const StyledTextField = styled.input.attrs({
className: 'TextField', className: 'RadioButtonField',
})<ITextField>` }) <ITextField>`
border: none; border: none;
border-radius: 2px; border-radius: 2px;
@ -35,6 +39,10 @@ export const StyledTextField = styled.input.attrs({
font-weight: 300; font-weight: 300;
${(p) => p.status === STATUS.error && css`
border-left: 2px solid ${p.theme.errorColor};
`}
&:focus { &:focus {
border-left-color: ${(p) => p.theme.focusColor}; border-left-color: ${(p) => p.theme.focusColor};
} }

View file

@ -0,0 +1,11 @@
import { ThemeInterface } from '../styled';
import main from './main';
const theme: ThemeInterface = {
...main,
primaryColor: '#7FB3D5',
};
export default theme;

View file

@ -0,0 +1,11 @@
import { ThemeInterface } from '../styled';
import main from './main';
const theme: ThemeInterface = {
...main,
primaryColor: '#52BE80',
};
export default theme;

View file

@ -0,0 +1,11 @@
import { ThemeInterface } from '../styled';
import main from './main';
const theme: ThemeInterface = {
...main,
primaryColor: '#9B59B6',
};
export default theme;

View file

@ -0,0 +1,19 @@
{
"name": "treejs-forms",
"version": "0.0.1",
"description": "",
"author": "",
"license": "ISC",
"dependencies": {
"treejs-components": "0.0.1",
"treejs-utils": "0.0.1"
},
"peerDependencies": {
"formik": "^1.5.2"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist/**/*"
]
}

View file

@ -0,0 +1,59 @@
import * as React from 'react';
import { Field as FormikField } from 'formik';
import { IOption } from 'treejs-components/RadioButton/types';
import { FIELD_TYPE } from '../constants';
import TextField from './fields/TextField';
import CheckboxField from './fields/CheckboxField';
import RadioButtonField from './fields/RadioButtonField';
import SelectBoxField from './fields/SelectBoxField';
interface IProps {
component: FIELD_TYPE;
disabled?: boolean;
error?: string;
name: string;
options?: IOption[];
title: string;
}
export class Field extends React.Component<IProps> {
public static defaultProps: IProps = {
component: FIELD_TYPE.TEXT_FIELD,
name: 'field',
title: 'Field',
};
public render(): React.ReactElement {
const {
component,
...other
} = this.props;
switch(component) {
case FIELD_TYPE.TEXT_FIELD:
return (
<FormikField component={TextField} {...other} />
);
case FIELD_TYPE.CHECKBOX:
return (
<FormikField component={CheckboxField} {...other} />
);
case FIELD_TYPE.RADIO_BUTTON:
return (
<FormikField component={RadioButtonField} {...other} />
);
case FIELD_TYPE.SELECT_BOX:
return (
<FormikField component={SelectBoxField} {...other} />
);
}
return null;
}
}
export default Field;

View file

@ -0,0 +1,36 @@
import * as React from 'react';
import { Formik, FormikProps, FormikActions } from 'formik';
import { FormErrors } from 'types/form/form';
interface IProps<FormValues> {
children: (props: FormikProps<FormValues>) => React.ReactElement;
initialValues: FormValues;
onSubmit: (values: FormValues, actions: FormikActions<FormValues>) => void;
validate: (values: FormValues) => FormErrors<FormValues>;
}
export class Form<FormValues> extends React.PureComponent<IProps<FormValues>> {
public render(): React.ReactElement {
const {
children,
onSubmit,
validate,
initialValues,
} = this.props;
return (
<Formik
onSubmit={onSubmit}
validate={validate}
initialValues={initialValues}
render={(props: FormikProps<FormValues>): React.ReactElement => (
<form onSubmit={props.handleSubmit}>
{children(props)}
</form>
)}
/>
);
}
}

View file

@ -0,0 +1,48 @@
import * as React from 'react';
import { FieldProps } from 'formik';
import CheckBoxComponent from 'treejs-components/Checkbox';
import { StyledCheckboxErrorMessageContainer } from '../../style';
interface IProps extends FieldProps {
error: string;
title: string;
value: boolean;
}
const CheckboxField = (props: IProps): React.ReactElement => {
const {
field: {
name,
value,
onChange,
onBlur,
},
title,
error,
} = props;
const handleClick = (e: React.MouseEvent): void => {
onChange(e);
};
const handleBlur = (e: React.FocusEvent): void => {
onBlur(e);
};
return (
<div>
<CheckBoxComponent
name={name}
title={title}
checked={value}
onChange={handleClick}
onBlur={handleBlur}
/>
<StyledCheckboxErrorMessageContainer>{error}</StyledCheckboxErrorMessageContainer>
</div>
);
};
export default CheckboxField;

View file

@ -0,0 +1,56 @@
import * as React from 'react';
import { FieldProps } from 'formik';
import RadioButtonComponent from 'treejs-components/RadioButton';
import { IOption } from 'treejs-components/RadioButton/types';
import { StyledCheckboxErrorMessageContainer } from '../../style';
interface IProps extends FieldProps {
error: string;
options: IOption[];
title: string;
value: boolean;
}
const RadioButtonField = (props: IProps): React.ReactElement => {
const {
field: {
name,
value,
onBlur,
},
form: {
setFieldValue,
},
title,
error,
options,
} = props;
const handleClick = (e: React.MouseEvent, option: IOption): void => {
setFieldValue(name, option.code);
};
const handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
onBlur(e);
};
return (
<div>
<RadioButtonComponent
horizontal
name={name}
title={title}
value={value}
options={options}
onClick={handleClick}
onBlur={handleBlur}
/>
<StyledCheckboxErrorMessageContainer>{error}</StyledCheckboxErrorMessageContainer>
</div>
);
};
export default RadioButtonField;

View file

@ -0,0 +1,65 @@
import * as React from 'react';
import { FieldProps } from 'formik';
import { STATUS } from 'types/common';
import SelectBoxComponent from 'treejs-components/SelectBox/containers';
import { IOption } from 'treejs-components/SelectBox/types';
import { isNilOrEmpty } from 'treejs-utils';
import { StyledTextFieldErrorMessageContainer } from '../../style';
interface IProps extends FieldProps {
error: string;
options: IOption[];
title: string;
value: string;
}
const SelectBox = (props: IProps): React.ReactElement => {
const {
field: {
name,
value,
onBlur,
},
form: {
setFieldValue,
},
title,
error,
options,
} = props;
const handleChange = (option: IOption): void => {
if (isNilOrEmpty(option)) {
setFieldValue(name, undefined);
} else {
setFieldValue(name, option.code);
}
};
const handleBlur = (e: React.FocusEvent<HTMLInputElement>): void => {
onBlur(e);
};
const status = !isNilOrEmpty(error) && STATUS.error;
return (
<div>
<SelectBoxComponent
name={name}
title={title}
value={value}
options={options}
onChange={handleChange}
onBlur={handleBlur}
status={status}
/>
<StyledTextFieldErrorMessageContainer>{error}</StyledTextFieldErrorMessageContainer>
</div>
);
};
export default SelectBox;

View file

@ -0,0 +1,57 @@
import * as React from 'react';
import { FieldProps } from 'formik';
import TextFieldComponent from 'treejs-components/TextField';
import { isNilOrEmpty } from 'treejs-utils';
import { STATUS } from 'types/common';
import { StyledTextFieldErrorMessageContainer } from '../../style';
interface IProps extends FieldProps {
disabled: boolean;
error: string;
title: string;
value: string;
}
const TextField = (props: IProps): React.ReactElement => {
const {
field: {
name,
value,
onChange,
onBlur,
},
title,
error,
disabled,
} = props;
const handleChange = (e: React.ChangeEvent): void => {
onChange(e);
};
const handleBlur = (e: React.FocusEvent): void => {
onBlur(e);
};
const status = !isNilOrEmpty(error) && STATUS.error;
return (
<div>
<TextFieldComponent
name={name}
title={title}
value={value}
onChange={handleChange}
onBlur={handleBlur}
status={status}
disabled={disabled}
/>
{!disabled && <StyledTextFieldErrorMessageContainer>{error}</StyledTextFieldErrorMessageContainer>}
</div>
);
};
export default TextField;

View file

@ -0,0 +1,6 @@
export enum FIELD_TYPE {
TEXT_FIELD,
CHECKBOX,
RADIO_BUTTON,
SELECT_BOX,
}

View file

@ -0,0 +1,18 @@
import styled from 'treejs-components/styled';
const errorMessage = styled.div`
font-size: 12px;
color: ${(p) => p.theme.errorColor}
`;
export const StyledTextFieldErrorMessageContainer = styled(errorMessage)`
text-align: left;
`;
export const StyledCheckboxErrorMessageContainer = styled(errorMessage)`
text-align: left;
margin-top: 8px;
`;

View file

@ -8,6 +8,9 @@
"treejs-components": "^0.0.1", "treejs-components": "^0.0.1",
"treejs-constants": "^0.0.1" "treejs-constants": "^0.0.1"
}, },
"peerDependencies": {
"informed": "2.3.1"
},
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"files": [ "files": [

3
modules/types/common.ts Normal file
View file

@ -0,0 +1,3 @@
export enum STATUS {
error,
}

View file

@ -0,0 +1,11 @@
import { FormikErrors, FormikActions } from 'formik';
export type FormActions<FormValues> = FormikActions<FormValues>
export type FormErrors<FormValues> = FormikErrors<FormValues>;
export interface IForm<FormValues> {
handleSubmit: (values: FormValues, actions: FormActions<FormValues>) => void;
handleValidate: (values?: FormValues) => FormErrors<FormValues>;
initialValues: FormValues;
}

28648
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,14 +16,16 @@
"@fortawesome/free-solid-svg-icons": "^5.7.2", "@fortawesome/free-solid-svg-icons": "^5.7.2",
"@fortawesome/react-fontawesome": "^0.1.4", "@fortawesome/react-fontawesome": "^0.1.4",
"@hot-loader/react-dom": "^16.8.4", "@hot-loader/react-dom": "^16.8.4",
"formik": "^1.5.2",
"ramda": "^0.26.1", "ramda": "^0.26.1",
"react": "^16.8.4", "react": "^16.8.4",
"react-dom": "^16.8.6",
"react-redux": "^6.0.1", "react-redux": "^6.0.1",
"react-router-dom": "^5.0.0", "react-router": "^5.0.0",
"redux": "^4.0.1", "redux": "^4.0.1",
"reselect": "^4.0.0", "reselect": "^4.0.0",
"styled-components": "^4.1.3", "styled-components": "^4.1.3",
"typescript": "^3.3.3333" "typescript": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@types/enzyme": "^3.9.0", "@types/enzyme": "^3.9.0",
@ -32,19 +34,18 @@
"@types/ramda": "^0.25.51", "@types/ramda": "^0.25.51",
"@types/react": "^16.8.7", "@types/react": "^16.8.7",
"@types/react-dom": "^16.8.2", "@types/react-dom": "^16.8.2",
"@types/react-router-dom": "^4.3.1",
"@types/react-redux": "^7.0.3", "@types/react-redux": "^7.0.3",
"@types/redux": "^3.6.0", "@types/react-router": "^4.4.5",
"@types/styled-components": "^4.1.12", "@types/styled-components": "^4.1.12",
"@typescript-eslint/eslint-plugin": "^1.4.2", "@typescript-eslint/eslint-plugin": "^1.6.0",
"@typescript-eslint/parser": "^1.4.2", "@typescript-eslint/parser": "^1.6.0",
"awesome-typescript-loader": "^5.2.1", "awesome-typescript-loader": "^5.2.1",
"copy-webpack-plugin": "^5.0.0", "copy-webpack-plugin": "^5.0.0",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"enzyme": "^3.9.0", "enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.10.0", "enzyme-adapter-react-16": "^1.10.0",
"enzyme-to-json": "^3.3.5", "enzyme-to-json": "^3.3.5",
"eslint": "^5.12.1", "eslint": "^5.16.0",
"eslint-plugin-react": "^7.12.4", "eslint-plugin-react": "^7.12.4",
"eslint-plugin-react-hooks": "^1.5.0", "eslint-plugin-react-hooks": "^1.5.0",
"eslint-plugin-typescript": "^0.14.0", "eslint-plugin-typescript": "^0.14.0",
@ -52,7 +53,7 @@
"file-loader": "^3.0.1", "file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"jest": "^24.3.0", "jest": "^24.3.0",
"lerna": "^3.13.1", "lerna": "^3.13.3",
"react-hot-loader": "^4.8.0", "react-hot-loader": "^4.8.0",
"source-map-loader": "^0.2.4", "source-map-loader": "^0.2.4",
"stylelint": "^9.10.1", "stylelint": "^9.10.1",

View file

@ -13,9 +13,6 @@
], ],
"jsx": "react", "jsx": "react",
"paths": { "paths": {
"react-dom": [
"@hot-loader/react-dom"
],
"documentation/*": [ "documentation/*": [
"./modules/documentation/src/modules/*" "./modules/documentation/src/modules/*"
], ],
@ -28,6 +25,9 @@
"treejs-utils": [ "treejs-utils": [
"./modules/treejs-utils" "./modules/treejs-utils"
], ],
"treejs-forms/*": [
"./modules/treejs-forms/src/*"
],
"treejs-redux/*": [ "treejs-redux/*": [
"./modules/treejs-redux/src/*" "./modules/treejs-redux/src/*"
], ],