DEV;Forms
This commit is contained in:
parent
b2d239fbba
commit
0eb9f98aaf
52 changed files with 15338 additions and 14490 deletions
|
@ -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": [
|
||||||
|
|
|
@ -8,5 +8,6 @@ server {
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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'],
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
`;
|
|
@ -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>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
|
|
||||||
|
|
||||||
import treejsReducer from 'treejs-redux/index';
|
import treejsReducer from 'treejs-redux/index';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,6 @@ export const MainStyle = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
130
modules/documentation/src/modules/FormsPage/components/index.tsx
Normal file
130
modules/documentation/src/modules/FormsPage/components/index.tsx
Normal 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;
|
|
@ -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>
|
||||||
|
|
|
@ -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' },
|
||||||
|
|
|
@ -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' },
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 => (
|
||||||
|
<React.Fragment>
|
||||||
<h2>Welcome</h2>
|
<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;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const THEME = 'theme';
|
|
@ -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'],
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = () => {
|
||||||
|
if (this.props.onClick instanceof Function) {
|
||||||
this.props.onClick();
|
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>
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
4
modules/treejs-components/src/RadioButton/types.ts
Normal file
4
modules/treejs-components/src/RadioButton/types.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface IOption {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
}
|
|
@ -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 => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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,7 +22,7 @@ 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};
|
||||||
}
|
}
|
||||||
|
|
11
modules/treejs-components/src/themes/blue.ts
Normal file
11
modules/treejs-components/src/themes/blue.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { ThemeInterface } from '../styled';
|
||||||
|
|
||||||
|
import main from './main';
|
||||||
|
|
||||||
|
const theme: ThemeInterface = {
|
||||||
|
...main,
|
||||||
|
|
||||||
|
primaryColor: '#7FB3D5',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
11
modules/treejs-components/src/themes/green.ts
Normal file
11
modules/treejs-components/src/themes/green.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { ThemeInterface } from '../styled';
|
||||||
|
|
||||||
|
import main from './main';
|
||||||
|
|
||||||
|
const theme: ThemeInterface = {
|
||||||
|
...main,
|
||||||
|
|
||||||
|
primaryColor: '#52BE80',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
11
modules/treejs-components/src/themes/purple.ts
Normal file
11
modules/treejs-components/src/themes/purple.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { ThemeInterface } from '../styled';
|
||||||
|
|
||||||
|
import main from './main';
|
||||||
|
|
||||||
|
const theme: ThemeInterface = {
|
||||||
|
...main,
|
||||||
|
|
||||||
|
primaryColor: '#9B59B6',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
19
modules/treejs-forms/package.json
Normal file
19
modules/treejs-forms/package.json
Normal 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/**/*"
|
||||||
|
]
|
||||||
|
}
|
59
modules/treejs-forms/src/components/Field.tsx
Normal file
59
modules/treejs-forms/src/components/Field.tsx
Normal 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;
|
36
modules/treejs-forms/src/components/Form.tsx
Normal file
36
modules/treejs-forms/src/components/Form.tsx
Normal 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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
48
modules/treejs-forms/src/components/fields/CheckboxField.tsx
Normal file
48
modules/treejs-forms/src/components/fields/CheckboxField.tsx
Normal 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;
|
|
@ -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;
|
|
@ -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;
|
57
modules/treejs-forms/src/components/fields/TextField.tsx
Normal file
57
modules/treejs-forms/src/components/fields/TextField.tsx
Normal 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;
|
6
modules/treejs-forms/src/constants/index.ts
Normal file
6
modules/treejs-forms/src/constants/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export enum FIELD_TYPE {
|
||||||
|
TEXT_FIELD,
|
||||||
|
CHECKBOX,
|
||||||
|
RADIO_BUTTON,
|
||||||
|
SELECT_BOX,
|
||||||
|
}
|
18
modules/treejs-forms/src/style.ts
Normal file
18
modules/treejs-forms/src/style.ts
Normal 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;
|
||||||
|
`;
|
|
@ -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
3
modules/types/common.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export enum STATUS {
|
||||||
|
error,
|
||||||
|
}
|
11
modules/types/form/form.ts
Normal file
11
modules/types/form/form.ts
Normal 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;
|
||||||
|
}
|
6772
package-lock.json
generated
6772
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -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",
|
||||||
|
|
|
@ -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/*"
|
||||||
],
|
],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue