Skip to content

Commit 70f2583

Browse files
Feature/dom (#19).
1 parent f305aad commit 70f2583

File tree

13 files changed

+274
-84
lines changed

13 files changed

+274
-84
lines changed

packages/simplr-forms-core/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
dist
22
@types
33
coverage
4+
*.js
5+
**/*.d.ts

packages/simplr-forms-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@
6969
"js"
7070
]
7171
}
72-
}
72+
}

packages/simplr-forms-core/src/abstractions/base-form.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import * as React from "react";
22
import * as PropTypes from "prop-types";
33

44
import * as FormContracts from "../contracts/form";
5+
import { FormStore } from "../stores/form-store";
6+
import { FormError } from "../contracts/error";
7+
import { ConstructFormError } from "../utils/form-error-helpers";
58
import { FSHContainer, FormStoresHandler } from "../stores/form-stores-handler";
69

710
export abstract class BaseForm<TProps extends FormContracts.FormProps, TState> extends React.Component<TProps, TState> {
@@ -30,6 +33,33 @@ export abstract class BaseForm<TProps extends FormContracts.FormProps, TState> e
3033
return FSHContainer.FormStoresHandler;
3134
}
3235

36+
protected get FormStore(): FormStore {
37+
return this.FormStoresHandler.GetStore(this.FormId);
38+
}
39+
40+
protected ShouldFormSubmit() {
41+
if (this.props.forceSubmit === true) {
42+
return true;
43+
}
44+
return this.FormStore.GetState().Form.Error == null;
45+
}
46+
47+
protected async Submit(result: Promise<void> | FormError | any): Promise<void> {
48+
let promise: Promise<void>;
49+
if (this.isPromise<void>(result)) {
50+
promise = result;
51+
} else {
52+
promise = new Promise<void>((resolve, reject) => {
53+
const error = ConstructFormError(result);
54+
if (error !== undefined) {
55+
reject(result);
56+
return;
57+
}
58+
resolve(result);
59+
});
60+
}
61+
}
62+
3363
componentWillUnmount() {
3464
if (this.props.destroyOnUnmount) {
3565
this.FormStoresHandler.UnregisterForm(this.FormId);
@@ -66,4 +96,8 @@ export abstract class BaseForm<TProps extends FormContracts.FormProps, TState> e
6696
}
6797
}
6898
}
99+
100+
private isPromise<T>(value: any): value is Promise<T> {
101+
return value != null && value.then != null && value.catch != null;
102+
}
69103
}

packages/simplr-forms-core/src/contracts/form-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { FormStateRecord } from "../contracts/form";
88
export interface FormStoreState {
99
Fields: Immutable.Map<string, FieldStateRecord>;
1010
FieldsGroups: Immutable.Map<string, FieldsGroupStoreState>;
11-
Form?: FormStateRecord;
11+
Form: FormStateRecord;
1212
}
1313

1414
export interface FormStoreStateRecord extends TypedRecord<FormStoreStateRecord>, FormStoreState { }

packages/simplr-forms-core/src/contracts/form.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,21 @@ export interface FormProps {
77
formId?: string;
88
formStore?: FormStore;
99
destroyOnUnmount?: boolean;
10+
forceSubmit?: boolean;
1011
}
1112

1213
export interface FormChildContext {
1314
FormId: string;
1415
}
1516

1617
export interface FormState {
17-
Error: FormError | undefined;
18+
Validating: boolean;
19+
Pristine: boolean;
20+
Error?: FormError;
1821
Submitting: boolean;
1922
SuccessfullySubmitted: boolean;
20-
SubmitCallback: Function | undefined;
21-
ActiveFieldId: string | undefined;
23+
SubmitCallback?: () => void;
24+
ActiveFieldId?: string;
2225
}
2326

2427
export interface FormStateRecord extends TypedRecord<FormStateRecord>, FormState { }

packages/simplr-forms-core/src/stores/form-store.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ export class FormStore extends ActionEmitter {
109109
return this.State.Fields.get(fieldId);
110110
}
111111

112+
public SetSubmitCallback(submitCallback: () => void) {
113+
this.State = this.State.withMutations(state => {
114+
state.Form = state.Form.merge({
115+
SubmitCallback: submitCallback
116+
} as FormState);
117+
});
118+
}
119+
112120
public UpdateProps(fieldId: string, props: FieldStateProps) {
113121
const propsRecord = recordify<FieldStateProps, FieldStatePropsRecord>(props);
114122
const fieldState = this.State.Fields.get(fieldId);
@@ -145,6 +153,12 @@ export class FormStore extends ActionEmitter {
145153
// Skip if it's already validating
146154
if (!field.Validating) {
147155
this.State = this.State.withMutations(state => {
156+
// Set form state to Validating: true
157+
state.Form = state.Form.merge({
158+
Validating: true,
159+
Error: undefined
160+
} as FormState);
161+
148162
const fieldState = state.Fields.get(fieldId);
149163
state.Fields = state.Fields.set(fieldId, fieldState.merge({
150164
Validating: true,
@@ -191,6 +205,13 @@ export class FormStore extends ActionEmitter {
191205
}
192206
}
193207

208+
public InitiateSubmit() {
209+
if (this.State.Form.SubmitCallback == null) {
210+
throw new Error("simplr-forms-core: Submit method is called before SubmitCallback is set.");
211+
}
212+
this.State.Form.SubmitCallback();
213+
}
214+
194215
/**
195216
* ========================
196217
* Local helper methods
@@ -207,7 +228,9 @@ export class FormStore extends ActionEmitter {
207228

208229
protected GetInitialFormState(): FormState {
209230
return {
231+
Validating: false,
210232
Submitting: false,
233+
Pristine: true,
211234
SuccessfullySubmitted: false,
212235
ActiveFieldId: undefined,
213236
Error: undefined,

packages/simplr-forms-core/src/utils/form-error-helpers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ export function IsFormError(error: any): error is FormError {
44
return (error != null && (error as FormError).Message != null);
55
}
66

7-
export function ConstructFormError(error: any) {
7+
export function ConstructFormError(error: any): FormError | undefined {
8+
if (IsFormError(error)) {
9+
return error;
10+
}
811
if (typeof error === "string") {
912
return {
1013
Message: error
1114
};
12-
} else if (IsFormError(error)) {
13-
return error;
1415
}
16+
return undefined;
1517
}

packages/simplr-forms-dom/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.js
2+
**/*d.ts
Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,69 @@
1-
{
2-
"name": "simplr-forms-dom",
3-
"version": "4.0.0-pre-alpha.13",
4-
"description": "DOM components for simplr-forms.",
5-
"repository": "SimplrJS/simplr-forms",
6-
"homepage": "https://github.com/SimplrJS/simplr-forms",
7-
"main": "main.js",
8-
"types": "index.d.ts",
9-
"author": "simplrjs <[email protected]> (https://github.com/simplrjs)",
10-
"scripts": {
11-
"build": "webpack && npm run tslint",
12-
"watch": "webpack -w",
13-
"tslint": "tslint --config ./tslint.json --project . --exclude __tests__/**/* && echo TsLint test successfully passed.",
14-
"uglifyjs": "uglifyjs ./dist/simplr-forms-core.js -o ./dist/simplr-forms-core.min.js --compress --mangle",
15-
"release": "npm run build && npm run uglifyjs",
16-
"test": "jest",
17-
"test-watch": "jest --watchAll",
18-
"test-coverage": "npm test -- --coverage",
19-
"prepublishOnly": "npm run build && node ../simplr-forms-publish/dist/cli.js --from dist --to .",
20-
"postpublish": "git clean -fd"
21-
},
22-
"license": "AGPL-3.0",
23-
"files": [
24-
"**/*.md",
25-
"*.js",
26-
"*.d.ts",
27-
"!*.config.js"
28-
],
29-
"devDependencies": {
30-
"@types/enzyme": "^2.7.7",
31-
"@types/jest": "^19.2.2",
32-
"@types/sinon": "^2.1.2",
33-
"enzyme": "^2.8.0",
34-
"jest": "^19.0.2",
35-
"jest-enzyme": "^3.0.0",
36-
"mkdirp": "^0.5.1",
37-
"mv": "^2.1.1",
38-
"mz": "^2.6.0",
39-
"on-build-webpack": "^0.1.0",
40-
"simplr-mvdir": "0.0.1-beta.6",
41-
"sinon": "^2.1.0",
42-
"ts-jest": "^19.0.8",
43-
"ts-loader": "^2.0.3",
44-
"tslint": "^5.0.0",
45-
"typescript": "2.3.0",
46-
"webpack": "^2.4.1"
47-
},
48-
"dependencies": {
49-
"@types/react": "^15.0.21",
50-
"react": "^15.5.4",
51-
"simplr-forms-core": "^4.0.0-pre-alpha.11"
52-
},
53-
"jest": {
54-
"setupTestFrameworkScriptFile": "./node_modules/jest-enzyme/lib/index.js",
55-
"transform": {
56-
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
57-
},
58-
"testRegex": "/__tests__/.*\\.(test|spec).(ts|tsx|js)$",
59-
"moduleFileExtensions": [
60-
"ts",
61-
"tsx",
62-
"js"
63-
]
64-
}
65-
}
1+
{
2+
"name": "simplr-forms-dom",
3+
"version": "4.0.0-pre-alpha.13",
4+
"description": "DOM components for simplr-forms.",
5+
"repository": "SimplrJS/simplr-forms",
6+
"homepage": "https://github.com/SimplrJS/simplr-forms",
7+
"main": "index.js",
8+
"types": "index.d.ts",
9+
"author": "simplrjs <[email protected]> (https://github.com/simplrjs)",
10+
"scripts": {
11+
"build": "webpack && npm run tslint",
12+
"watch": "webpack -w",
13+
"tslint": "tslint --config ./tslint.json --project . --exclude __tests__/**/* && echo TsLint test successfully passed.",
14+
"uglifyjs": "uglifyjs ./dist/simplr-forms-core.js -o ./dist/simplr-forms-core.min.js --compress --mangle",
15+
"release": "npm run build && npm run uglifyjs",
16+
"test": "jest",
17+
"test-watch": "jest --watchAll",
18+
"test-coverage": "npm test -- --coverage",
19+
"prepublishOnly": "npm run build && node ../simplr-forms-publish/dist/cli.js --from dist --to .",
20+
"postpublish": "git clean -fd"
21+
},
22+
"license": "AGPL-3.0",
23+
"files": [
24+
"**/*.md",
25+
"*.js",
26+
"*.d.ts",
27+
"!*.config.js"
28+
],
29+
"devDependencies": {
30+
"@types/enzyme": "^2.7.7",
31+
"@types/jest": "^19.2.2",
32+
"@types/prop-types": "^15.5.1",
33+
"@types/sinon": "^2.1.2",
34+
"enzyme": "^2.8.0",
35+
"jest": "^19.0.2",
36+
"jest-enzyme": "^3.0.0",
37+
"mkdirp": "^0.5.1",
38+
"mv": "^2.1.1",
39+
"mz": "^2.6.0",
40+
"on-build-webpack": "^0.1.0",
41+
"simplr-mvdir": "0.0.1-beta.6",
42+
"sinon": "^2.1.0",
43+
"ts-jest": "^19.0.8",
44+
"ts-loader": "^2.0.3",
45+
"tslint": "^5.0.0",
46+
"typescript": "2.3.0",
47+
"webpack": "^2.4.1"
48+
},
49+
"dependencies": {
50+
"@types/react": "^15.0.21",
51+
"immutable": "^3.8.1",
52+
"prop-types": "^15.5.8",
53+
"react": "^15.5.4",
54+
"simplr-forms-core": "^4.0.0-pre-alpha.11",
55+
"typed-immutable-record": "0.0.6"
56+
},
57+
"jest": {
58+
"setupTestFrameworkScriptFile": "./node_modules/jest-enzyme/lib/index.js",
59+
"transform": {
60+
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
61+
},
62+
"testRegex": "/__tests__/.*\\.(test|spec).(ts|tsx|js)$",
63+
"moduleFileExtensions": [
64+
"ts",
65+
"tsx",
66+
"js"
67+
]
68+
}
69+
}

packages/simplr-forms-dom/src/components/form.tsx

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,46 @@
11
import * as React from "react";
22
import { BaseForm } from "simplr-forms-core";
3-
import { FormProps } from "simplr-forms-core/contracts";
4-
import { OnChangeCallback } from "../contracts/field";
5-
import { FormOnSubmitCallback } from "../contracts/form";
63

7-
export interface FormProps extends FormProps, React.HTMLProps<HTMLFormElement> {
8-
onSubmit?: FormOnSubmitCallback;
9-
onChange?: OnChangeCallback<any>;
10-
}
4+
import { FormProps, FormOnSubmitCallback } from "../contracts/form";
115

126
export class Form extends BaseForm<FormProps, {}> {
7+
public Element: HTMLFormElement;
8+
9+
static defaultProps: FormProps = {
10+
preventSubmitDefaultAndPropagation: true
11+
};
12+
13+
protected SetElementRef = (element: HTMLFormElement) => {
14+
this.Element = element;
15+
this.FormStore.SetSubmitCallback(() => {
16+
element.dispatchEvent(new Event("submit"));
17+
});
18+
}
19+
20+
protected FormSubmitHandler = (event: React.FormEvent<HTMLFormElement>): void => {
21+
if (this.props.preventSubmitDefaultAndPropagation) {
22+
event.preventDefault();
23+
event.stopPropagation();
24+
}
25+
if (!this.ShouldFormSubmit()) {
26+
return;
27+
}
28+
29+
// TODO: Touch all fields to validate
30+
31+
if (this.props.onSubmit == null) {
32+
return;
33+
}
34+
35+
const result = this.props.onSubmit(event, this.FormStore);
36+
this.Submit(result);
37+
}
38+
1339
render() {
14-
return <form>
40+
return <form
41+
ref={this.SetElementRef}
42+
onSubmit={this.FormSubmitHandler}
43+
>
1544
{this.props.children}
1645
</form>;
1746
}

0 commit comments

Comments
 (0)