From bb6fc2ccda74057cc28bddc4cddad480913ad0ac Mon Sep 17 00:00:00 2001 From: Beton Date: Sat, 2 Feb 2019 18:29:26 +0200 Subject: [PATCH 01/12] Implement new context format --- package-lock.json | 99 +++++++++++++------ package.json | 10 +- src/AutoFocus/AutoFocus.tsx | 14 ++- src/AutoFocus/AutoFocusContext.ts | 9 -- src/AutoFocus/AutoFocusProps.ts | 9 +- src/AutoFocus/index.ts | 1 - src/AutoUpdate/AutoUpdate.ts | 55 ----------- src/AutoUpdate/AutoUpdate.tsx | 55 +++++++++++ src/AutoUpdate/AutoUpdateContext.ts | 11 --- src/AutoUpdate/AutoUpdateProps.ts | 10 -- src/AutoUpdate/index.ts | 1 - src/AutoValidate/AutoValidate.tsx | 41 ++++---- src/AutoValidate/AutoValidateContext.ts | 11 --- src/AutoValidate/AutoValidateProps.ts | 15 --- src/Button/BaseButton.tsx | 10 +- src/Button/Button.tsx | 4 +- src/Button/ButtonProps.ts | 6 -- src/Button/Checkbox.tsx | 8 +- src/Button/CheckboxProps.ts | 5 - src/EventInterceptor/EventInterceptor.tsx | 51 ++++------ .../EventInterceptorContext.ts | 8 ++ src/EventInterceptor/index.ts | 1 + src/Form/Form.tsx | 55 +++++------ src/Form/FormContext.ts | 32 +++--- src/Form/FormProps.ts | 25 +---- src/FormGroup/FormGroup.tsx | 89 +++++++++-------- src/FormGroup/FormGroupContext.ts | 33 +++++-- src/FormGroup/FormGroupProps.ts | 10 -- src/Hint/Hint.tsx | 7 +- src/Hint/HintContext.ts | 9 -- src/Hint/index.ts | 1 - src/Input/BaseInput.tsx | 26 ++--- src/Input/BaseInputProps.ts | 7 +- src/Input/Input.tsx | 2 +- src/Input/InputContext.ts | 27 ----- src/Input/PasswordInput.tsx | 17 ++++ src/Input/index.ts | 2 +- src/InputRange/InputRange.tsx | 29 +++--- src/InputRange/InputRangeProps.ts | 8 -- src/Label/Label.tsx | 23 ++--- src/Label/LabelContext.ts | 9 -- src/Label/index.ts | 1 - src/OnValidate/OnValidate.tsx | 31 +++--- src/OnValidate/OnValidateProps.ts | 7 -- src/PasswordGroup/PasswordGroup.tsx | 37 +++---- src/PasswordGroup/PasswordGroupContext.ts | 16 +-- src/ResetButton/ResetButton.tsx | 9 +- src/ResetButton/ResetButtonContext.ts | 10 +- src/ShowPasswordButton/ShowPasswordButton.tsx | 62 +++++------- .../ShowPasswordButtonProps.ts | 6 -- src/SlowSubmitButton/SlowSubmitButton.tsx | 36 +++---- src/SlowSubmitButton/SlowSubmitButtonProps.ts | 9 +- src/SubmitButton/SubmitButton.tsx | 16 ++- src/SubmitButton/SubmitButtonContext.ts | 10 +- src/SubmitButton/SubmitButtonProps.ts | 5 - src/helpers/addError.ts | 4 +- tslint.json | 1 + 57 files changed, 453 insertions(+), 652 deletions(-) delete mode 100644 src/AutoFocus/AutoFocusContext.ts delete mode 100644 src/AutoUpdate/AutoUpdate.ts create mode 100644 src/AutoUpdate/AutoUpdate.tsx delete mode 100644 src/AutoUpdate/AutoUpdateContext.ts delete mode 100644 src/AutoValidate/AutoValidateContext.ts create mode 100644 src/EventInterceptor/EventInterceptorContext.ts delete mode 100644 src/Hint/HintContext.ts delete mode 100644 src/Input/InputContext.ts create mode 100644 src/Input/PasswordInput.tsx delete mode 100644 src/Label/LabelContext.ts diff --git a/package-lock.json b/package-lock.json index d3ee26d..9bd595b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,17 +48,16 @@ "dev": true }, "@types/prop-types": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.3.tgz", - "integrity": "sha512-sfjHrNF4zWRv3fJUGyZW46wVxhYJ/GeWIPdKxbnLIhY3bWR0Ncl2kIhZI7rpjY9KtUQAkDP8jWEmaGQGFFvruA==", - "dev": true + "version": "15.5.8", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz", + "integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==" }, "@types/react": { - "version": "16.3.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.3.17.tgz", - "integrity": "sha512-f2ZTOSF7l9sRdXSbzLI84Z2wsVnj3qUjfJhtDLSi7lTWFMo1WSou7eQ2vkQga8100zhzzDjSyGbj+Viz7i927g==", - "dev": true, + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.1.tgz", + "integrity": "sha512-tD1ETKJcuhANOejRc/p7OgQ16DKnbGi0M3LccelKlPnUCDp2a5koVxZFoRN9HN+A+m84HB5VGN7I+r3nNhS3PA==", "requires": { + "@types/prop-types": "*", "csstype": "^2.2.0" } }, @@ -2074,10 +2073,9 @@ } }, "csstype": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.5.3.tgz", - "integrity": "sha512-G5HnoK8nOiAq3DXIEoY2n/8Vb7Lgrms+jGJl8E4EJpQEeVONEnPFJSl8IK505wPBoxxtrtHhrRm4WX2GgdqarA==", - "dev": true + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz", + "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==" }, "currently-unhandled": { "version": "0.4.1", @@ -3235,7 +3233,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3259,13 +3258,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3282,19 +3283,22 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3425,7 +3429,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3439,6 +3444,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3455,6 +3461,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3463,13 +3470,15 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3490,6 +3499,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3578,7 +3588,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3592,6 +3603,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3687,7 +3699,8 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3729,6 +3742,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3750,6 +3764,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3798,13 +3813,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true + "dev": true, + "optional": true } } }, @@ -5784,6 +5801,7 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -7117,7 +7135,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "optional": true }, "loose-envify": { "version": "1.3.1", @@ -9449,15 +9468,27 @@ } }, "react": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", - "integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", + "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", "dev": true, "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.12.0" + }, + "dependencies": { + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "dev": true, + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + } } }, "react-dom": { @@ -9836,6 +9867,16 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scheduler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", + "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", diff --git a/package.json b/package.json index 70ea4b1..51d1dde 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,7 @@ "@types/enzyme": "^2.8.9", "@types/mocha": "^2.2.48", "@types/node": "^10.3.3", - "@types/prop-types": "^15.5.3", - "@types/react": "^16.3.17", + "@types/react": "^16.8.1", "@types/sinon": "^2.3.3", "awesome-typescript-loader": "^3.5.0", "axios": "^0.18.0", @@ -62,8 +61,7 @@ "mocha": "^5.2.0", "nyc": "^11.9.0", "pre-commit": "^1.2.2", - "prop-types": "^15.6.1", - "react": "^16.4.1", + "react": "^16.7.0", "react-dom": "^16.4.1", "react-test-renderer": "^16.4.1", "sinon": "^6.0.0", @@ -79,8 +77,7 @@ }, "peerDependencies": { "class-validator": "^0.7.2", - "prop-types": "^15.6.0", - "react": "^16.2.0" + "react": "^16.7.0" }, "nyc": { "extension": [ @@ -99,7 +96,6 @@ ], "report-dir": "./tests/output" }, - "dependencies": {}, "pre-commit": [ "lint", "test" diff --git a/src/AutoFocus/AutoFocus.tsx b/src/AutoFocus/AutoFocus.tsx index 2aba4a5..37c0eac 100644 --- a/src/AutoFocus/AutoFocus.tsx +++ b/src/AutoFocus/AutoFocus.tsx @@ -1,16 +1,14 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import { AutoValidate } from "../AutoValidate/AutoValidate"; -import { AutoFocusProps, AutoFocusPropTypes } from "./AutoFocusProps"; -import { AutoFocusContext, AutoFocusContextTypes } from "./AutoFocusContext"; +import { AutoValidate } from "../AutoValidate"; +import { AutoFocusProps } from "./AutoFocusProps"; +import { FormContext, FormContextValue } from "../Form"; -export class AutoFocus extends React.Component { - public static readonly propTypes = AutoFocusPropTypes; - public static readonly contextTypes = AutoFocusContextTypes; +export class AutoFocus extends React.PureComponent { + public static readonly contextType = FormContext; public props: AutoFocusProps; - public context: AutoFocusContext; + public context: FormContextValue; public render(): JSX.Element { const { to, ...childProps } = this.props; diff --git a/src/AutoFocus/AutoFocusContext.ts b/src/AutoFocus/AutoFocusContext.ts deleted file mode 100644 index 8dd6fcb..0000000 --- a/src/AutoFocus/AutoFocusContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as PropTypes from "prop-types"; - -export interface AutoFocusContext { - getDOMElement: (attribute: string) => HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | undefined, -} - -export const AutoFocusContextTypes: {[P in keyof AutoFocusContext]: PropTypes.Validator} = { - getDOMElement: PropTypes.func.isRequired, -}; diff --git a/src/AutoFocus/AutoFocusProps.ts b/src/AutoFocus/AutoFocusProps.ts index bf348d4..ca82f4c 100644 --- a/src/AutoFocus/AutoFocusProps.ts +++ b/src/AutoFocus/AutoFocusProps.ts @@ -1,12 +1,5 @@ -import * as PropTypes from "prop-types"; - -import { AutoValidateProps, AutoValidatePropTypes } from "../AutoValidate/AutoValidateProps"; +import { AutoValidateProps } from "../AutoValidate"; export interface AutoFocusProps extends AutoValidateProps { to: string, } - -export const AutoFocusPropTypes: {[P in keyof AutoFocusProps]: PropTypes.Validator} = { - to: PropTypes.string.isRequired, - ...AutoValidatePropTypes -}; diff --git a/src/AutoFocus/index.ts b/src/AutoFocus/index.ts index 4dcba60..ff6d886 100644 --- a/src/AutoFocus/index.ts +++ b/src/AutoFocus/index.ts @@ -1,3 +1,2 @@ export * from "./AutoFocus"; -export * from "./AutoFocusContext"; export * from "./AutoFocusProps"; diff --git a/src/AutoUpdate/AutoUpdate.ts b/src/AutoUpdate/AutoUpdate.ts deleted file mode 100644 index 6ce00db..0000000 --- a/src/AutoUpdate/AutoUpdate.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as React from "react"; -import * as PropTypes from "prop-types"; - -import { InputContextTypes, InputContext } from "../Input"; -import { AutoUpdateProps, AutoUpdatePropTypes, AutoUpdateDefaultProps } from "./AutoUpdateProps"; -import { AutoUpdateContext, AutoUpdateContextTypes } from "./AutoUpdateContext"; - -export class AutoUpdate extends React.Component { - public static readonly propTypes = AutoUpdatePropTypes; - public static readonly defaultProps = AutoUpdateDefaultProps; - public static readonly contextTypes = { - ...InputContextTypes, - getDOMElement: PropTypes.func.isRequired - }; - - public static readonly childContextTypes = AutoUpdateContextTypes; - - public context: InputContext & { - getDOMElement: (attribute: string) => HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | undefined, - }; - - public getChildContext(): AutoUpdateContext { - return { - onBlur: this.handleBlur, - onChange: this.handleChange, - } - } - - public render(): JSX.Element { - return this.props.children; - } - - protected handleUpdate = (): void => { - this.context.onAttributeChange(this.props.attribute, this.props.value(this.context.value)); - - const element = this.context.getDOMElement(this.props.attribute); - if (element instanceof HTMLElement) { - // blur event does not triggered if element not focused - element.focus(); - element.blur(); - } - } - - protected handleBlur = (): void => { - this.props.onBlur && this.handleUpdate(); - - this.context.onBlur(); - } - - protected handleChange = (value: any): void => { - this.props.onChange && this.context.onAttributeChange(this.props.attribute, this.props.value(value)); - - this.context.onChange(value); - } -} diff --git a/src/AutoUpdate/AutoUpdate.tsx b/src/AutoUpdate/AutoUpdate.tsx new file mode 100644 index 0000000..ef7ec2f --- /dev/null +++ b/src/AutoUpdate/AutoUpdate.tsx @@ -0,0 +1,55 @@ +import * as React from "react"; + +import { FormContext, FormContextValue } from "../Form"; +import { AutoUpdateProps, AutoUpdateDefaultProps } from "./AutoUpdateProps"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; + +class AutoUpdateLayout extends React.PureComponent< + AutoUpdateProps & { getDOMElement: FormContextValue["getDOMElement"]} +> { + public static readonly defaultProps = AutoUpdateDefaultProps; + public static readonly contextType = FormGroupContext; + + public context: FormGroupContextValue; + + public render(): JSX.Element { + return + } + + protected get childContextValue(): FormGroupContextValue { + return { + ...this.context, + onBlur: this.handleBlur, + onChange: this.handleChange, + } + } + + protected handleUpdate = (): void => { + this.context.onAttributeChange(this.props.attribute, this.props.value(this.context.value)); + + const element = this.props.getDOMElement(this.props.attribute); + if (element instanceof HTMLElement) { + // blur event does not triggered if element not focused + element.focus(); + element.blur(); + } + } + + protected handleBlur = (): void => { + this.props.onBlur && this.handleUpdate(); + + this.context.onBlur(); + } + + protected handleChange = (value: any): void => { + this.props.onChange && this.context.onAttributeChange(this.props.attribute, this.props.value(value)); + + this.context.onChange(value); + } +} + +export const AutoUpdate = ((props: AutoUpdateProps) => ( + + {(context: FormContextValue) => } + +)); diff --git a/src/AutoUpdate/AutoUpdateContext.ts b/src/AutoUpdate/AutoUpdateContext.ts deleted file mode 100644 index a942004..0000000 --- a/src/AutoUpdate/AutoUpdateContext.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as PropTypes from "prop-types"; - -export interface AutoUpdateContext { - onBlur: () => void, - onChange: (value: any) => void, -} - -export const AutoUpdateContextTypes: {[P in keyof AutoUpdateContext]: PropTypes.Validator} = { - onBlur: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, -}; diff --git a/src/AutoUpdate/AutoUpdateProps.ts b/src/AutoUpdate/AutoUpdateProps.ts index e7ee0d8..b423123 100644 --- a/src/AutoUpdate/AutoUpdateProps.ts +++ b/src/AutoUpdate/AutoUpdateProps.ts @@ -1,5 +1,3 @@ -import * as PropTypes from "prop-types"; - export interface AutoUpdateProps { value: (value: any) => any, attribute: string, @@ -8,14 +6,6 @@ export interface AutoUpdateProps { onChange?: boolean, } -export const AutoUpdatePropTypes: {[P in keyof AutoUpdateProps]: PropTypes.Validator} = { - value: PropTypes.func.isRequired, - attribute: PropTypes.string.isRequired, - children: PropTypes.element.isRequired, - onBlur: PropTypes.bool, - onChange: PropTypes.bool, -}; - export const AutoUpdateDefaultProps = { onBlur: true, onChange: false, diff --git a/src/AutoUpdate/index.ts b/src/AutoUpdate/index.ts index 145297c..29a789a 100644 --- a/src/AutoUpdate/index.ts +++ b/src/AutoUpdate/index.ts @@ -1,3 +1,2 @@ export * from "./AutoUpdate"; export * from "./AutoUpdateProps"; -export * from "./AutoUpdateContext"; diff --git a/src/AutoValidate/AutoValidate.tsx b/src/AutoValidate/AutoValidate.tsx index da37c49..a855b72 100644 --- a/src/AutoValidate/AutoValidate.tsx +++ b/src/AutoValidate/AutoValidate.tsx @@ -1,39 +1,32 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; +import { FormContext, FormContextValue } from "../Form"; -import { AutoValidateDefaultProps, AutoValidateProps, AutoValidatePropTypes } from "./AutoValidateProps"; -import { AutoValidateContext, AutoValidateContextTypes } from "./AutoValidateContext"; -import { InputContext } from "../Input/InputContext"; -import { InputContextTypes } from "../Input"; +import { AutoValidateDefaultProps, AutoValidateProps } from "./AutoValidateProps"; import { ModelError } from "../Model"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; -export class AutoValidate extends React.Component { - public static readonly propTypes = AutoValidatePropTypes; +class AutoValidateLayout extends React.PureComponent< + AutoValidateProps & { validate: (group: string) => Promise} +> { public static readonly defaultProps = AutoValidateDefaultProps; - public static readonly childContextTypes = AutoValidateContextTypes; + public static readonly contextType = FormGroupContext; - public static readonly contextTypes = { - ...InputContextTypes, - validate: PropTypes.func.isRequired, - }; + public context: FormGroupContextValue; - public context: InputContext & { - readonly validate: (group: string) => Promise; - }; + public render(): JSX.Element { + return ; + } - public getChildContext(): AutoValidateContext { + public get childContextValue(): FormGroupContextValue { const isOnChange = this.props.onChange || this.props.onLength || this.props.on || this.props.always; const isOnBlur = this.props.onBlur || this.props.always; return { + ...this.context, onChange: isOnChange ? this.handleChange : this.context.onChange, onBlur: isOnBlur ? this.handleBlur : this.context.onBlur, }; } - public render(): JSX.Element { - return this.props.children; - } - protected handleChange = (nextValue: any): void => { const previousValue = this.context.value; const onChange = this.context.onChange(nextValue); @@ -54,7 +47,13 @@ export class AutoValidate extends React.Component { }; protected async validate(): Promise { - const errors = await this.context.validate(this.props.groupName || this.context.name); + const errors = await this.props.validate(this.props.groupName || this.context.name); this.props.onValidated && this.props.onValidated(errors.length === 0); } } + +export const AutoValidate = (props: AutoValidateProps) => ( + + {(context: FormContextValue) => } + +); diff --git a/src/AutoValidate/AutoValidateContext.ts b/src/AutoValidate/AutoValidateContext.ts deleted file mode 100644 index 5b38474..0000000 --- a/src/AutoValidate/AutoValidateContext.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as PropTypes from "prop-types"; - -export interface AutoValidateContext { - onChange: (value: any) => void, - onBlur: () => void, -} - -export const AutoValidateContextTypes: {[P in keyof AutoValidateContext]: PropTypes.Validator} = { - onChange: PropTypes.func.isRequired, - onBlur: PropTypes.func.isRequired, -}; diff --git a/src/AutoValidate/AutoValidateProps.ts b/src/AutoValidate/AutoValidateProps.ts index 8a4ad76..cb6e15a 100644 --- a/src/AutoValidate/AutoValidateProps.ts +++ b/src/AutoValidate/AutoValidateProps.ts @@ -1,5 +1,3 @@ -import * as PropTypes from "prop-types"; - export interface AutoValidateProps { groupName?: string, children: JSX.Element, @@ -14,19 +12,6 @@ export interface AutoValidateProps { on?: (nextValue: string, previousValue: string) => boolean } -export const AutoValidatePropTypes: {[P in keyof AutoValidateProps]: PropTypes.Validator} = { - children: PropTypes.element.isRequired, - groupName: PropTypes.string, - - onBlur: PropTypes.bool, - onChange: PropTypes.bool, - onLength: PropTypes.number, - always: PropTypes.bool, - onValidated: PropTypes.func, - - on: PropTypes.func -}; - export const AutoValidateDefaultProps: {[P in keyof AutoValidateProps]?: AutoValidateProps[P]} = { onBlur: true, onChange: false, diff --git a/src/Button/BaseButton.tsx b/src/Button/BaseButton.tsx index b7d2254..3159a1a 100644 --- a/src/Button/BaseButton.tsx +++ b/src/Button/BaseButton.tsx @@ -1,12 +1,10 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; -import { InputContext, InputContextTypes } from "../Input"; +export abstract class BaseButton extends React.Component & T> { + public static contextType = FormGroupContext; -export abstract class BaseButton extends React.Component> { - public static contextTypes = InputContextTypes; - - public context: InputContext; + public context: FormGroupContextValue; public get childProps(): React.HTMLProps { return { diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx index 21e6c6b..c616c2b 100644 --- a/src/Button/Button.tsx +++ b/src/Button/Button.tsx @@ -1,11 +1,9 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; import { BaseButton } from "./BaseButton"; -import { ButtonDefaultProps, ButtonProps, ButtonPropTypes } from "./ButtonProps"; +import { ButtonDefaultProps, ButtonProps } from "./ButtonProps"; export class Button extends BaseButton { - public static readonly propTypes = ButtonPropTypes; public static readonly defaultProps = ButtonDefaultProps; public props: ButtonProps; diff --git a/src/Button/ButtonProps.ts b/src/Button/ButtonProps.ts index f3c6785..8d1582e 100644 --- a/src/Button/ButtonProps.ts +++ b/src/Button/ButtonProps.ts @@ -1,16 +1,10 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; export interface ButtonProps extends React.HTMLProps { action: any, activeClassName?: string } -export const ButtonPropTypes: {[P in keyof ButtonProps]: PropTypes.Validator} = { - action: PropTypes.any.isRequired, - activeClassName: PropTypes.string -}; - export const ButtonDefaultProps: {[P in keyof ButtonProps]?: ButtonProps[P]} = { className: "btn", activeClassName: "is-active" diff --git a/src/Button/Checkbox.tsx b/src/Button/Checkbox.tsx index 408cc84..aa62ee5 100644 --- a/src/Button/Checkbox.tsx +++ b/src/Button/Checkbox.tsx @@ -1,15 +1,11 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; import { BaseButton } from "./BaseButton"; -import { CheckboxDefaultProps, CheckboxProps, CheckboxPropTypes } from "./CheckboxProps"; +import { CheckboxDefaultProps, CheckboxProps } from "./CheckboxProps"; -export class Checkbox extends BaseButton { - public static readonly propTypes = CheckboxPropTypes; +export class Checkbox extends BaseButton { public static readonly defaultProps = CheckboxDefaultProps; - public props: CheckboxProps; - public render(): JSX.Element { const { activeClassName, ...HTMLProps } = this.props; diff --git a/src/Button/CheckboxProps.ts b/src/Button/CheckboxProps.ts index 5dfccd9..829db34 100644 --- a/src/Button/CheckboxProps.ts +++ b/src/Button/CheckboxProps.ts @@ -1,14 +1,9 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; export interface CheckboxProps extends React.HTMLProps { activeClassName?: string } -export const CheckboxPropTypes: {[P in keyof CheckboxProps]: PropTypes.Validator} = { - activeClassName: PropTypes.string -}; - export const CheckboxDefaultProps: {[P in keyof CheckboxProps]?: CheckboxProps[P]} = { className: "checkbox", activeClassName: "is-active" diff --git a/src/EventInterceptor/EventInterceptor.tsx b/src/EventInterceptor/EventInterceptor.tsx index 61e1f3f..b6360a7 100644 --- a/src/EventInterceptor/EventInterceptor.tsx +++ b/src/EventInterceptor/EventInterceptor.tsx @@ -1,8 +1,8 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import { FormContextTypes, FormContext } from "../Form"; +import { FormContext, FormContextValue } from "../Form"; import { ModelValue } from "../Model"; +import { EventInterceptorContext, EventInterceptorContextValue } from "./EventInterceptorContext"; export enum Event { onChange = "onChange", @@ -17,48 +17,37 @@ export interface EventInterceptorProps { events: Event[]; } -export const EventInterceptorPropTypes: {[P in keyof EventInterceptorProps]: PropTypes.Validator} = { - events: PropTypes.arrayOf(PropTypes.oneOf(Object.values(Event))).isRequired, - onChange: PropTypes.func, - onFocus: PropTypes.func, - onBlur: PropTypes.func -}; - -export interface EventInterceptorContext { - onChange: (attribute: string, value: any) => void; - onFocus?: (attribute: string, value: any) => void; - onBlur?: (attribute: string, value: any) => void; -} - -export const EventInterceptorContextTypes: {[P in keyof EventInterceptorContext]: PropTypes.Validator} = { - onChange: PropTypes.func.isRequired, - onFocus: PropTypes.func, - onBlur: PropTypes.func -} - export class EventInterceptor extends React.Component { - public static readonly childContextTypes = EventInterceptorContextTypes; - public static readonly propTypes = EventInterceptorPropTypes; - public static readonly contextTypes = FormContextTypes; + public static readonly contextType = FormContext; + + public readonly context: FormContextValue; - public readonly context: FormContext; + public render(): React.ReactNode { + return ( + + + + ); + } - public getChildContext(): EventInterceptorContext { + protected get formContextValue(): FormContextValue { return { + ...this.context, onChange: this.props.events.includes(Event.onChange) ? this.handleChange : this.context.onChange, - onFocus: this.props.events.includes(Event.onFocus) ? this.props.onFocus : undefined, - onBlur: this.props.events.includes(Event.onBlur) ? this.props.onBlur : undefined }; } - public render(): React.ReactNode { - return this.props.children; + protected get childContextValue(): EventInterceptorContextValue { + return { + onFocus: this.props.events.includes(Event.onFocus) ? this.props.onFocus : undefined, + onBlur: this.props.events.includes(Event.onBlur) ? this.props.onBlur : undefined + }; } protected handleChange = (attribute: string, value: any): void => { this.props.onChange && this.props.onChange(attribute, value, this.getValue(attribute)); this.context.onChange(attribute, value); - } + }; protected getValue = (name: string): string => { const founded = this.context.values.find((value: ModelValue) => value.attribute === name); diff --git a/src/EventInterceptor/EventInterceptorContext.ts b/src/EventInterceptor/EventInterceptorContext.ts new file mode 100644 index 0000000..fc570ab --- /dev/null +++ b/src/EventInterceptor/EventInterceptorContext.ts @@ -0,0 +1,8 @@ +import * as React from "react"; + +export interface EventInterceptorContextValue { + onFocus?: (attribute: string, value: any) => void; + onBlur?: (attribute: string, value: any) => void; +} + +export const EventInterceptorContext = React.createContext({}); diff --git a/src/EventInterceptor/index.ts b/src/EventInterceptor/index.ts index 26571b0..bb2fcab 100644 --- a/src/EventInterceptor/index.ts +++ b/src/EventInterceptor/index.ts @@ -1 +1,2 @@ export * from "./EventInterceptor"; +export * from "./EventInterceptorContext"; diff --git a/src/Form/Form.tsx b/src/Form/Form.tsx index 3c75573..767b872 100644 --- a/src/Form/Form.tsx +++ b/src/Form/Form.tsx @@ -1,9 +1,8 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; import { Model, ModelError } from "../Model"; -import { FormContext, FormContextTypes } from "./FormContext"; -import { FormProps, FormPropTypes, StorageRequiredInterface } from "./FormProps"; +import { FormContext, FormContextValue } from "./FormContext"; +import { FormProps, StorageRequiredInterface } from "./FormProps"; import { addError } from "../helpers"; @@ -16,8 +15,6 @@ export interface FormState { declare const localStorage: StorageRequiredInterface | undefined; export class Form extends React.Component & FormProps, FormState> { - public static readonly childContextTypes = FormContextTypes; - public static readonly propTypes = FormPropTypes; public state: FormState; public storage = this.props.storage || ((typeof window).toLowerCase() !== "undefined" ? localStorage : undefined); @@ -32,24 +29,6 @@ export class Form }; } - public getChildContext(): FormContext { - return { - onChange: this.handleChange, - values: this.state.model.values, - - onMount: this.handleMount, - onUnmount: this.handleUnmount, - onReset: this.handleReset, - - validate: this.validate, - getDOMElement: this.getDOMElement, - - isLoading: this.state.isLoading, - addError: this.handleErrorAdded, - getError: this.state.model.getError, - }; - } - public async componentWillMount() { this.loadFromStorage(); await this.state.model.get(); @@ -74,7 +53,7 @@ export class Form if ("function" === (typeof action).toLowerCase()) { await action() } else if (this.props.onSubmit) { - await this.props.onSubmit(this.state.model, this.getChildContext()); + await this.props.onSubmit(this.state.model, this.childContextValue); } } catch (error) { submitError = error; @@ -90,7 +69,7 @@ export class Form this.forceUpdate(); if (submitError) { - return addError(this.getChildContext(), submitError); + return addError(this.childContextValue, submitError); } this.props.resetAfterSubmit && this.state.model.reset(); @@ -114,9 +93,11 @@ export class Form } return ( -
- {this.props.children} -
+ +
+ {this.props.children} +
+
); } @@ -163,6 +144,24 @@ export class Form this.storage.setItem(this.props.storageKey, JSON.stringify(localStorageValue)); } + protected get childContextValue(): FormContextValue { + return { + onChange: this.handleChange, + values: this.state.model.values, + + onMount: this.handleMount, + onUnmount: this.handleUnmount, + onReset: this.handleReset, + + validate: this.validate, + getDOMElement: this.getDOMElement, + + isLoading: this.state.isLoading, + addError: this.handleErrorAdded, + getError: this.state.model.getError, + }; + } + protected handleChange = (attribute: string, value: any): void => { if (this.state.model[attribute] === value) { return; diff --git a/src/Form/FormContext.ts b/src/Form/FormContext.ts index 562da96..7182901 100644 --- a/src/Form/FormContext.ts +++ b/src/Form/FormContext.ts @@ -1,8 +1,7 @@ -import * as PropTypes from "prop-types"; - +import * as React from "react"; import { ModelValue, ModelInterface, ModelError } from "../Model"; -export interface FormContext { +export interface FormContextValue { values: ModelValue[]; addError: (newError: ModelError) => void, getError: (attribute: string) => ModelError | undefined, @@ -19,18 +18,17 @@ export interface FormContext { isLoading: boolean; } -export const FormContextTypes: {[P in keyof FormContext]: PropTypes.Validator} = { - values: PropTypes.arrayOf(PropTypes.object).isRequired, - addError: PropTypes.func.isRequired, - getError: PropTypes.func.isRequired, - - onChange: PropTypes.func.isRequired, - onMount: PropTypes.func.isRequired, - onUnmount: PropTypes.func.isRequired, - onReset: PropTypes.func.isRequired, - - validate: PropTypes.func.isRequired, - getDOMElement: PropTypes.func.isRequired, - - isLoading: PropTypes.bool.isRequired, +export const FormContextDefaultValue: FormContextValue = { + values: [], + addError: () => undefined, + getError: () => undefined, + onChange: () => undefined, + onMount: () => undefined, + onUnmount: () => undefined, + onReset: () => undefined, + validate: () => Promise.resolve([]), + getDOMElement: () => undefined, + isLoading: false, }; + +export const FormContext = React.createContext(FormContextDefaultValue); diff --git a/src/Form/FormProps.ts b/src/Form/FormProps.ts index 39c1747..3df6fd0 100644 --- a/src/Form/FormProps.ts +++ b/src/Form/FormProps.ts @@ -1,21 +1,12 @@ -import * as React from "react"; -import * as PropTypes from "prop-types"; - -import { FormContext } from "./FormContext"; +import { FormContextValue } from "./FormContext"; import { ModelInterface, ModelValue } from "../Model"; export type StorageRequiredInterface = Pick; -export const StorageRequiredInterfaceTypes: - {[P in keyof StorageRequiredInterface]: PropTypes.Validator} = { - getItem: PropTypes.func.isRequired, - setItem: PropTypes.func.isRequired - }; - export interface FormProps { instantiate: () => M; /* This method will be used for creating model instance in Form state */ method?: string; /* Name of method of model, which will be called on form submit */ - onSubmit?: (model: M, childContext: FormContext) => Promise; // will be called if no method provided + onSubmit?: (model: M, childContext: FormContextValue) => Promise; // will be called if no method provided storageKey?: string; /* If provided Model will be saved to localStorage on unmount and loaded on mount */ resetAfterSubmit?: boolean; afterSubmit?: () => void; @@ -23,15 +14,3 @@ export interface FormProps { onValidate?: (groups: Array<{ name: string, isValid: boolean }>) => void; formRef?: (node: HTMLFormElement) => void; } - -export const FormPropTypes: {[P in keyof FormProps]: PropTypes.Validator} = { - instantiate: PropTypes.func.isRequired, - method: PropTypes.string, - onSubmit: PropTypes.func, - storageKey: PropTypes.string, - resetAfterSubmit: PropTypes.bool, - afterSubmit: PropTypes.func, - storage: PropTypes.shape(StorageRequiredInterfaceTypes), - onValidate: PropTypes.func, - formRef: PropTypes.func, -}; diff --git a/src/FormGroup/FormGroup.tsx b/src/FormGroup/FormGroup.tsx index 88dc77a..ca0ca67 100644 --- a/src/FormGroup/FormGroup.tsx +++ b/src/FormGroup/FormGroup.tsx @@ -1,29 +1,24 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; import { ModelValue } from "../Model"; -import { FormContext, FormContextTypes } from "../Form/FormContext"; -import { FormGroupContext, FormGroupContextTypes } from "./FormGroupContext"; -import { EventInterceptorContext, EventInterceptorContextTypes } from "../EventInterceptor"; -import { FormGroupDefaultProps, FormGroupProps, FormGroupPropTypes } from "./FormGroupProps"; +import { FormContext, FormContextValue } from "../Form"; +import { FormGroupContext, FormGroupContextValue } from "./FormGroupContext"; +import { EventInterceptorContext, EventInterceptorContextValue } from "../EventInterceptor"; +import { FormGroupDefaultProps, FormGroupProps } from "./FormGroupProps"; export interface FormGroupState { isFocused: boolean; } -export class FormGroup extends React.Component { - public static readonly propTypes = FormGroupPropTypes; +class FormGroupLayout extends React.Component< + FormGroupProps & { interceptor: EventInterceptorContextValue }, + FormGroupState +> { public static readonly defaultProps = FormGroupDefaultProps; - public static readonly childContextTypes = FormGroupContextTypes; - public static readonly contextTypes = { - ...FormContextTypes, - ...EventInterceptorContextTypes - }; + public static readonly contextType = FormContext; - public context: FormContext & EventInterceptorContext; - public state: FormGroupState = { - isFocused: false, - }; + public context: FormContextValue; + public state: FormGroupState = { isFocused: false }; public id: string; constructor(props) { @@ -32,24 +27,6 @@ export class FormGroup extends React.Component { this.id = (Date.now() + Math.random()).toString().replace(/\./g, ""); } - public getChildContext(): FormGroupContext { - const value = this.value; - return { - id: `${this.props.idPrefix}_${this.id}`, - name: this.props.name, - - value: value ? value.value : undefined, - - onChange: this.handleChange, - onAttributeChange: this.context.onChange, - onBlur: this.handleBlur, - onFocus: this.handleFocus, - onMount: this.handleMount, - - error: value ? value.error : undefined, - }; - } - public componentWillUnmount() { this.context.onUnmount(this.props.name); } @@ -58,12 +35,18 @@ export class FormGroup extends React.Component { public handleBlur = (): void => { this.setState({ isFocused: false }); - this.context.onBlur && this.context.onBlur(this.props.name, this.value ? this.value.value : undefined); + this.props.interceptor.onBlur && this.props.interceptor.onBlur( + this.props.name, + this.value ? this.value.value : undefined + ); }; public handleFocus = (): void => { this.setState({ isFocused: true }); - this.context.onFocus && this.context.onFocus(this.props.name, this.value ? this.value.value : undefined); + this.props.interceptor.onFocus && this.props.interceptor.onFocus( + this.props.name, + this.value ? this.value.value : undefined + ); }; public handleMount = (ref: HTMLElement): void => this.context.onMount(this.props.name, ref); @@ -82,16 +65,38 @@ export class FormGroup extends React.Component { errorClassName, focusClassName, valueClassName, + interceptor, ...childProps } = this.props; return ( -
- {this.props.children} -
+ +
+ {this.props.children} +
+
); } + protected get childContextValue(): FormGroupContextValue { + const value = this.value; + + return { + id: `${this.props.idPrefix}_${this.id}`, + name: this.props.name, + + value: value ? value.value : undefined, + + onChange: this.handleChange, + onAttributeChange: this.context.onChange, + onBlur: this.handleBlur, + onFocus: this.handleFocus, + onMount: this.handleMount, + + error: value ? value.error : undefined, + }; + } + protected get className(): string { return [ this.props.className, @@ -110,3 +115,9 @@ export class FormGroup extends React.Component { .trim(); } } + +export const FormGroup = (props: FormGroupProps) => ( + + {(context: EventInterceptorContextValue) => } + +); diff --git a/src/FormGroup/FormGroupContext.ts b/src/FormGroup/FormGroupContext.ts index d9353d4..2f552e5 100644 --- a/src/FormGroup/FormGroupContext.ts +++ b/src/FormGroup/FormGroupContext.ts @@ -1,13 +1,28 @@ -import * as PropTypes from "prop-types" +import * as React from "react"; -import { HintContext, HintContextTypes } from "../Hint"; -import { LabelContext, LabelContextTypes } from "../Label"; -import { InputContext, InputContextTypes } from "../Input/InputContext"; +export interface FormGroupContextValue { + error?: string; + id: string; -export interface FormGroupContext extends LabelContext, HintContext, InputContext { } + name: string; + value: TValue; -export const FormGroupContextTypes: {[P in keyof FormGroupContext]: PropTypes.Validator} = { - ...LabelContextTypes, - ...HintContextTypes, - ...InputContextTypes, + onChange: (value: TValue) => void; + onAttributeChange: (attribute: string, value: any) => void; + onFocus: () => void; + onBlur: () => void; + onMount: (ref: HTMLElement) => void; +} + +export const FormGroupContextDefaultValue: FormGroupContextValue = { + id: "", + name: "", + value: "", + onChange: () => undefined, + onAttributeChange: () => undefined, + onFocus: () => undefined, + onBlur: () => undefined, + onMount: () => undefined, }; + +export const FormGroupContext = React.createContext(FormGroupContextDefaultValue); diff --git a/src/FormGroup/FormGroupProps.ts b/src/FormGroup/FormGroupProps.ts index 8096545..6090d2c 100644 --- a/src/FormGroup/FormGroupProps.ts +++ b/src/FormGroup/FormGroupProps.ts @@ -1,5 +1,4 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; export interface FormGroupProps extends React.HTMLProps { name: string; /* field name (will be passed to input) */ @@ -11,15 +10,6 @@ export interface FormGroupProps extends React.HTMLProps { ref?: any; // https://github.com/Microsoft/TypeScript/issues/16019 } -export const FormGroupPropTypes: {[P in keyof FormGroupProps]: PropTypes.Validator} = { - name: PropTypes.string.isRequired, - idPrefix: PropTypes.string, - - errorClassName: PropTypes.string, - focusClassName: PropTypes.string, - valueClassName: PropTypes.string -}; - export const FormGroupDefaultProps: {[P in keyof FormGroupProps]?: FormGroupProps[P]} = { className: "form-group", idPrefix: "rcf", diff --git a/src/Hint/Hint.tsx b/src/Hint/Hint.tsx index c0c015f..562caf1 100644 --- a/src/Hint/Hint.tsx +++ b/src/Hint/Hint.tsx @@ -1,14 +1,13 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; import { HintDefaultProps } from "./HintProps" -import { HintContext, HintContextTypes } from "./HintContext"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; export class Hint extends React.Component> { public static readonly defaultProps = HintDefaultProps; - public static readonly contextTypes = HintContextTypes; + public static readonly contextType = FormGroupContext; - public context: HintContext; + public context: FormGroupContextValue; public get error(): string | undefined { return this.context.error; diff --git a/src/Hint/HintContext.ts b/src/Hint/HintContext.ts deleted file mode 100644 index eecc7ab..0000000 --- a/src/Hint/HintContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as PropTypes from "prop-types"; - -export interface HintContext { - error?: string; -} - -export const HintContextTypes: {[P in keyof HintContext]: PropTypes.Validator} = { - error: PropTypes.string, -}; diff --git a/src/Hint/index.ts b/src/Hint/index.ts index 4934c61..eeb4f97 100644 --- a/src/Hint/index.ts +++ b/src/Hint/index.ts @@ -1,3 +1,2 @@ export * from "./Hint"; -export * from "./HintContext"; export * from "./HintProps"; diff --git a/src/Input/BaseInput.tsx b/src/Input/BaseInput.tsx index a9f6bbe..bbfa851 100644 --- a/src/Input/BaseInput.tsx +++ b/src/Input/BaseInput.tsx @@ -1,33 +1,20 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import { cursorPositionController } from "../helpers/cursorPositionController"; +import { cursorPositionController } from "../helpers"; -import { PasswordGroupContextTypes, PasswordGroupContext } from "../PasswordGroup"; -import { BaseInputDefaultProps, BaseInputProps, BaseInputPropTypes } from "./BaseInputProps"; -import { InputContext, InputContextTypes } from "./InputContext"; +import { BaseInputDefaultProps, BaseInputProps } from "./BaseInputProps"; import { TransformTypes } from "./TransformTypes"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; -export class BaseInput extends React.Component { - public static readonly contextTypes = { - ...InputContextTypes, - ...PasswordGroupContextTypes - }; +export class BaseInput extends React.PureComponent { + public static readonly contextType = FormGroupContext; public static readonly defaultProps = BaseInputDefaultProps; - public static readonly propTypes = BaseInputPropTypes; - public context: InputContext & PasswordGroupContext; + public context: FormGroupContextValue; protected get childProps(): React.HTMLProps & T { const { transform, ...TProps } = this.props as any; // https://github.com/Microsoft/TypeScript/issues/16780 - let passwordInputProps = {}; - if (this.context.isHidden) { - passwordInputProps = { - type: "password" - }; - } - return { ...TProps, @@ -40,7 +27,6 @@ export class BaseInput extends React.Component { onChange: this.handleChange, onBlur: this.handleBlur, onFocus: this.handleFocus, - ...passwordInputProps }; } diff --git a/src/Input/BaseInputProps.ts b/src/Input/BaseInputProps.ts index d86d2fa..e93bfd2 100644 --- a/src/Input/BaseInputProps.ts +++ b/src/Input/BaseInputProps.ts @@ -1,15 +1,10 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import {TransformTypes} from "./TransformTypes"; +import { TransformTypes } from "./TransformTypes"; export interface BaseInputProps extends React.HTMLProps { transform?: TransformTypes; } -export const BaseInputPropTypes: {[P in keyof BaseInputProps]: PropTypes.Validator} = { - transform: PropTypes.oneOf(Object.keys(TransformTypes)) -}; - export const BaseInputDefaultProps: {[P in keyof BaseInputProps]?: BaseInputProps[P]} = { transform: TransformTypes.none, className: "form-control" diff --git a/src/Input/Input.tsx b/src/Input/Input.tsx index 4d2c33a..ccfb2bd 100644 --- a/src/Input/Input.tsx +++ b/src/Input/Input.tsx @@ -1,6 +1,6 @@ import * as React from "react"; -import {BaseInput} from "./BaseInput"; +import { BaseInput } from "./BaseInput"; export class Input extends BaseInput> { diff --git a/src/Input/InputContext.ts b/src/Input/InputContext.ts deleted file mode 100644 index 3cfab6a..0000000 --- a/src/Input/InputContext.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as PropTypes from "prop-types"; - -export interface InputContext { - id: string; - - name: string; - value: TValue; - - onChange: (value: TValue) => void; - onAttributeChange: (attribute: string, value: any) => void; - onFocus: () => void; - onBlur: () => void; - onMount: (ref: HTMLElement) => void; -} - -export const InputContextTypes: {[P in keyof InputContext]: PropTypes.Validator} = { - id: PropTypes.string.isRequired, - - name: PropTypes.string.isRequired, - value: PropTypes.any, - - onChange: PropTypes.func.isRequired, - onAttributeChange: PropTypes.func.isRequired, - onFocus: PropTypes.func.isRequired, - onBlur: PropTypes.func.isRequired, - onMount: PropTypes.func.isRequired, -}; diff --git a/src/Input/PasswordInput.tsx b/src/Input/PasswordInput.tsx new file mode 100644 index 0000000..e26cece --- /dev/null +++ b/src/Input/PasswordInput.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +import { BaseInput } from "./BaseInput"; +import { PasswordGroupContext, PasswordGroupContextValue } from "../PasswordGroup"; + +export class PasswordInput extends BaseInput> { + public render() { + return ( + + {(context: PasswordGroupContextValue) => } + + ); + } + + protected input = (context: PasswordGroupContextValue) => ( + + ) +} diff --git a/src/Input/index.ts b/src/Input/index.ts index 2ce5658..f9afc1d 100644 --- a/src/Input/index.ts +++ b/src/Input/index.ts @@ -1,5 +1,4 @@ export * from "./Input"; -export * from "./InputContext"; export * from "./BaseInputProps"; export * from "./TransformTypes"; @@ -7,3 +6,4 @@ export * from "./TransformTypes"; export * from "./BaseInput"; export * from "./TextArea"; export * from "./NumericInput"; +export * from "./PasswordInput"; diff --git a/src/InputRange/InputRange.tsx b/src/InputRange/InputRange.tsx index b5abe0a..9dcfbfd 100644 --- a/src/InputRange/InputRange.tsx +++ b/src/InputRange/InputRange.tsx @@ -1,32 +1,25 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import { FormGroupContextTypes, FormGroupContext } from "../FormGroup"; -import { InputContextTypes, InputContext } from "../Input"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; import { InputRangeProps } from "./InputRangeProps"; -export class InputRange extends React.Component { - public static contextTypes = FormGroupContextTypes; - public static childContextTypes = InputContextTypes; +export class InputRange extends React.PureComponent { + public static contextType = FormGroupContext; - public context: FormGroupContext; + public context: FormGroupContextValue; - public getChildContext(): InputContext { - const { error, ...context } = this.context; + public render(): JSX.Element { + return ; + } + public get childContextValue(): FormGroupContextValue { return { - ...context, - ...{ - onChange: this.handleChange, - onBlur: this.handleBlur - } + ...this.context, + onChange: this.handleChange, + onBlur: this.handleBlur } } - public render(): JSX.Element { - return this.props.children; - } - protected handleChange = (value: number): void => { const currentLength = value.toString().length; const maxLength = this.props.max.toString().length; diff --git a/src/InputRange/InputRangeProps.ts b/src/InputRange/InputRangeProps.ts index 998bcf5..9b2fef2 100644 --- a/src/InputRange/InputRangeProps.ts +++ b/src/InputRange/InputRangeProps.ts @@ -1,13 +1,5 @@ -import * as PropTypes from "prop-types"; - export interface InputRangeProps { max: number, min?: number, children: JSX.Element } - -export const InputRangePropTypes: {[P in keyof InputRangeProps]: PropTypes.Validator} = { - max: PropTypes.number.isRequired, - min: PropTypes.number, - children: PropTypes.element.isRequired -}; diff --git a/src/Label/Label.tsx b/src/Label/Label.tsx index dc735a0..0b895ea 100644 --- a/src/Label/Label.tsx +++ b/src/Label/Label.tsx @@ -1,20 +1,9 @@ import * as React from "react"; -import * as PropTypes from "prop-types"; -import { LabelContext, LabelContextTypes } from "./LabelContext"; +import { FormGroupContext, FormGroupContextValue } from "../FormGroup"; -export class Label extends React.Component> { - public static contextTypes = LabelContextTypes; - public context: LabelContext; - - public render(): JSX.Element { - const childProps = { - ...this.props, - htmlFor: this.context.id, - }; - - return ( -