Skip to content

Commit

Permalink
Merge 37a01d5 into 5a2753c
Browse files Browse the repository at this point in the history
  • Loading branch information
franleplant committed Nov 21, 2017
2 parents 5a2753c + 37a01d5 commit 319fda8
Show file tree
Hide file tree
Showing 60 changed files with 10,515 additions and 1,900 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 6.0.0

Removed `Reform.reactMixins.classMixin` because there's no easy way to do that we Typescript and it
was too much of headache. Use `objectMixin` instead.
25 changes: 6 additions & 19 deletions docs-src/view/README.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -261,29 +261,16 @@ class MyComp extends React.Component {
}
}

// With Class mixin (not selectively)
// With object mixin (use it in typescript to get type information)
class MyComp extends React.Component {
//All Reform.reactHelper methods are available inside `this`
re = Reform.reactMixins.objectMixin(this);
//All Reform.reactHelper methods are available inside `this.re`
//you can use any other attribute name
}

const MyCompWithReform = Reform.reactMixins.classMixin(MyComp);

// With Class mixin (not selectively) and decorators
@Reform.reactMixins.classMixin
class MyComp extends React.Component {
//All Reform.reactHelper methods are available inside `this`
}

```

The last two are probably the more appropiate to use with Typescript
since they will give you autocomplete and not type errors or at least that's how it's
supposed to work. If you have any problems please report, decorators and mixins are kind of
an untamed beast in Typescript land. You can always use the `functionalMixin` but you are going
to need to express the new attributes by hand.

NOTE: important for typescript users, the class based mixins are broken because the type signature is hard to use,
please the other ways of using reform in your components until we fix this.
objectMixin is the most appropiate with Typescript
since it will give you autocomplete and proper typechecking.

### Triggering Validation

Expand Down
21 changes: 21 additions & 0 deletions examples-ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
2,164 changes: 2,164 additions & 0 deletions examples-ts/README.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions examples-ts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "examples-ts",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react-scripts-ts": "2.8.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
},
"devDependencies": {
"@types/jest": "^21.1.6",
"@types/node": "^8.0.53",
"@types/react": "^16.0.25",
"@types/react-dom": "^16.0.3"
}
}
Binary file added examples-ts/public/favicon.ico
Binary file not shown.
40 changes: 40 additions & 0 deletions examples-ts/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
15 changes: 15 additions & 0 deletions examples-ts/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
8 changes: 8 additions & 0 deletions examples-ts/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
46 changes: 46 additions & 0 deletions examples-ts/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import Form1 from './Form1'
import Form2 from './Form2'
import GettingStarted from './GettingStarted'


const rowStyle = {
display: 'flex',
flexDirection: 'row' as any,
marginBottom: 10,
}

const formContainerStyle = {
border: '1px solid grey',
padding: 10,
flex: 1,
}



export default class App extends React.Component<{}, {}> {
render() {
return (
<div style={{maxWidth: '800px', marginRight: 'auto', marginLeft: 'auto'}}>
<div style={rowStyle}>
<div style={formContainerStyle}>
<h3>Getting Started</h3>
<GettingStarted/>
</div>
</div>
<div style={rowStyle}>
<div style={formContainerStyle}>
<h3>validate onChange</h3>
<Form1/>
</div>
</div>
<div style={rowStyle}>
<div style={formContainerStyle}>
<h3>validate onSubmit</h3>
<Form2/>
</div>
</div>
</div>
);
}
}
68 changes: 43 additions & 25 deletions examples/src/Form1.js → examples-ts/src/Form1.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import React, { Component } from 'react';
import Reform from '../../build/index.js';
import * as React from 'react';
import { reactMixins } from '@franleplant/reform';

export default class Form1 extends Component {
constructor(props) {
super(props)
Reform.reactMixins.functionalMixin(this);
interface State {
fields: {
name: string;
email: string;
password: string;
confirmPassword: string;
}

errors: Partial<{
name: boolean;
email: boolean;
password: boolean;
confirmPassword: boolean;
}>
}

/*
* Validate on every input change
*/
export default class Form1 extends React.Component<{}, State> {
re = reactMixins.objectMixin(this)

state = {
fields: {
name: '',
Expand All @@ -24,49 +40,51 @@ export default class Form1 extends Component {
password: { required: true, minLength: 6},
confirmPassword: {
required: true,
mustMatch: value => value && value !== this.state.fields.password
mustMatch: (value: string) => value && value !== this.state.fields.password
},
};

validationMessages = {
required: _ => 'Field is required',
email: _ => 'Field must be a valid email',
minLength: minLength => `Field must be at least ${minLength} long`,
default: _ => `Invalid field`,
required: () => 'Field is required',
email: () => 'Field must be a valid email',
minLength: (minLength: number) => `Field must be at least ${minLength} long`,
default: () => `Invalid field`,
}


onChangeFactory = (fieldName) => {
return event => {
onChangeFactory = (fieldName: string) => {
return (event: any) => {
const value = event.target.value;
this.setState(state => {
state.fields[fieldName] = value;
return state;
const fields = {
...state.fields,
[fieldName]: value,
};

return {...state, message: '', error: {}, fields};
});
this.validateField(fieldName, value);
this.re.validateField(fieldName, value);
}
}

render() {
console.log(this.state)
return (
<form>
<div>
<p>Validate and if field is invalid the border will be red and an single error message displayed</p>
<input type="text" value={this.state.fields.name} onChange={this.onChangeFactory('name')}
style={{
border: !this.fieldIsValid('name') ? '2px solid red' : undefined,
border: !this.re.fieldIsValid('name') ? '2px solid red' : undefined,
}}
/>
<p>{ !this.fieldIsValid('name') && `Incorrect field! Please do it right` } </p>
<p>{ !this.re.fieldIsValid('name') && `Incorrect field! Please do it right` } </p>
</div>

<div>
<p>Validate and display one error per failed rule with array helper</p>
<input type="email" value={this.state.fields.email} onChange={this.onChangeFactory('email')} />
<ul>
{
this.mapFieldErrors('email').map((message, index) => (
this.re.mapFieldErrors('email').map((message, index) => (
<li key={index}>{message}</li>
))
}
Expand All @@ -78,11 +96,11 @@ export default class Form1 extends Component {
<p>Validate and display one error per failed rule with conditional helper</p>
<input type="password" value={this.state.fields.password} onChange={this.onChangeFactory('password')} />
<ul>
{ this.fieldIfError('password', 'required') &&
{ this.re.fieldIfError('password', 'required') &&
<li>Password is required</li>
}

{ this.fieldIfError('password', 'minLength') &&
{ this.re.fieldIfError('password', 'minLength') &&
<li>Password must be at least 6 characters long</li>
}
</ul>
Expand All @@ -93,13 +111,13 @@ export default class Form1 extends Component {
<input type="password" value={this.state.fields.confirmPassword} onChange={this.onChangeFactory('confirmPassword')} />
<ul>
{
this.mapFieldErrors('confirmPassword').map((message, index) => (
this.re.mapFieldErrors('confirmPassword').map((message, index) => (
<li key={index}>{message}</li>
))
}
</ul>
</div>
<button disabled={!this.formIsValid()}>Submit</button>
<button disabled={!this.re.formIsValid()}>Submit</button>
</form>
);
}
Expand Down
Loading

0 comments on commit 319fda8

Please sign in to comment.