Skip to content

Commit

Permalink
feat(adaptive-cards): enable default browser validation of input fields
Browse files Browse the repository at this point in the history
  • Loading branch information
karinasigartau0798 committed Apr 5, 2022
1 parent 0c88533 commit a593e5f
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 7 deletions.
23 changes: 22 additions & 1 deletion src/components/adaptive-cards/AdaptiveCard/AdaptiveCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,25 @@ export default function AdaptiveCard({
};

const setInput = useCallback((input) => {
setInputs((prevInputs) => ({...prevInputs, [input.id]: input}));
setInputs((prevInputs) => {
const prevInput = prevInputs[input.id];

return {
...prevInputs,
[input.id]: {...prevInput, ...input},
};
});
}, [setInputs]);

const setNativeInputRef = useCallback((id, nativeRef) => {
setInputs((prevInputs) => {
const input = prevInputs[id];

return {
...prevInputs,
[id]: {...input, nativeRef},
};
});
}, [setInputs]);

const getValue = (id, defval = '') => ((id in inputs && inputs[id].value !== undefined) ? inputs[id].value : defval);
Expand Down Expand Up @@ -197,6 +215,8 @@ export default function AdaptiveCard({
error = input.errorMessage || `The value you entered must match the pattern ${input.regex}`;
} else if (String(input.value).length > input.maxLength) {
error = `Maximum length is ${input.maxLength}`;
} else if (input.nativeRef && !input.nativeRef.checkValidity()) {
error = 'The value you entered is invalid.';
}

return {...input, error};
Expand All @@ -220,6 +240,7 @@ export default function AdaptiveCard({
getError,
validate,
submit,
setNativeInputRef,
invalidSubmit,
setElement,
setIsVisible,
Expand Down
8 changes: 7 additions & 1 deletion src/components/adaptive-cards/InputDate/InputDate.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useEffect} from 'react';
import React, {useCallback, useContext, useEffect} from 'react';
import PropTypes from 'prop-types';
import webexComponentClasses from '../../helpers';
import {formatDateTime} from '../util';
Expand All @@ -22,6 +22,7 @@ export default function InputDate({data, className, style}) {
setValue,
getValue,
setInput,
setNativeInputRef,
getError,
} = useContext(AdaptiveCardContext);

Expand All @@ -44,6 +45,10 @@ export default function InputDate({data, className, style}) {
setInput,
]);

const nativeRefCallback = useCallback((nativeRef) => {
setNativeInputRef(data.id, nativeRef);
}, [data.id, setNativeInputRef]);

return (
<DateInput
className={cssClasses}
Expand All @@ -54,6 +59,7 @@ export default function InputDate({data, className, style}) {
error={getError(data.id)}
required={data.isRequired}
label={formatDateTime(data.label)}
nativeRef={nativeRefCallback}
onChange={(value) => setValue(data.id, value)}
/>
);
Expand Down
8 changes: 7 additions & 1 deletion src/components/adaptive-cards/InputNumber/InputNumber.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useEffect} from 'react';
import React, {useCallback, useContext, useEffect} from 'react';
import PropTypes from 'prop-types';
import webexComponentClasses from '../../helpers';
import AdaptiveCardContext from '../context/adaptive-card-context';
Expand All @@ -22,6 +22,7 @@ export default function InputNumber({data, className, style}) {
setValue,
getValue,
setInput,
setNativeInputRef,
getError,
} = useContext(AdaptiveCardContext);

Expand All @@ -44,13 +45,18 @@ export default function InputNumber({data, className, style}) {
setInput,
]);

const nativeRefCallback = useCallback((nativeRef) => {
setNativeInputRef(data.id, nativeRef);
}, [data.id, setNativeInputRef]);

return (
<NumberInput
className={cssClasses}
error={getError(data.id)}
label={formatDateTime(data.label)}
max={data.max}
min={data.min}
nativeRef={nativeRefCallback}
onChange={(value) => setValue(data.id, value)}
placeholder={data.placeholder}
required={data.isRequired}
Expand Down
8 changes: 7 additions & 1 deletion src/components/adaptive-cards/InputText/InputText.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useEffect} from 'react';
import React, {useCallback, useContext, useEffect} from 'react';
import PropTypes from 'prop-types';
import webexComponentClasses from '../../helpers';
import AdaptiveCardContext from '../context/adaptive-card-context';
Expand All @@ -24,6 +24,7 @@ export default function InputText({data, className, style}) {
setValue,
getValue,
setInput,
setNativeInputRef,
getError,
} = useContext(AdaptiveCardContext);
const [cssClasses, sc] = webexComponentClasses('adaptive-cards-input-text', className);
Expand All @@ -49,6 +50,10 @@ export default function InputText({data, className, style}) {
setInput,
]);

const nativeRefCallback = useCallback((nativeRef) => {
setNativeInputRef(data.id, nativeRef);
}, [data.id, setNativeInputRef]);

return (
<div className={cssClasses} style={style}>
{!data.isMultiline ? (
Expand All @@ -57,6 +62,7 @@ export default function InputText({data, className, style}) {
error={getError(data.id)}
label={formatDateTime(data.label)}
maxLength={data.maxLength}
nativeRef={nativeRefCallback}
onChange={(value) => setValue(data.id, value)}
pattern={data.regex}
placeholder={data.placeholder}
Expand Down
8 changes: 7 additions & 1 deletion src/components/adaptive-cards/InputTime/InputTime.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useEffect} from 'react';
import React, {useCallback, useContext, useEffect} from 'react';
import PropTypes from 'prop-types';
import webexComponentClasses from '../../helpers';
import {acPropTypes, registerComponent} from '../Component/Component';
Expand All @@ -22,6 +22,7 @@ export default function InputTime({data, className, style}) {
setValue,
getValue,
setInput,
setNativeInputRef,
getError,
} = useContext(AdaptiveCardContext);

Expand All @@ -44,6 +45,10 @@ export default function InputTime({data, className, style}) {
setInput,
]);

const nativeRefCallback = useCallback((nativeRef) => {
setNativeInputRef(data.id, nativeRef);
}, [data.id, setNativeInputRef]);

return (
<TimeInput
className={cssClasses}
Expand All @@ -54,6 +59,7 @@ export default function InputTime({data, className, style}) {
error={getError(data.id)}
required={data.isRequired}
label={formatDateTime(data.label)}
nativeRef={nativeRefCallback}
onChange={(value) => setValue(data.id, value)}
/>
);
Expand Down
13 changes: 11 additions & 2 deletions src/components/generic/InputField/InputField.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {useCallback} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import webexComponentClasses from '../../helpers';
Expand All @@ -22,6 +22,7 @@ import Label from '../../inputs/Label/Label';
* @param {number} [props.maxLength] Maximum number of characters allowed
* @param {number} [props.min] Minimum value for the input element
* @param {string} [props.name] Input name
* @param {Function} [props.nativeRef] Action to perform to obtain the native input ref
* @param {Function} [props.onChange] Action to perform on input change
* @param {string} [props.pattern] Specifies a regular expression that the element's value is checked against
* @param {string} [props.placeholder] Input placeholder
Expand All @@ -46,6 +47,7 @@ export default function InputField({
maxLength,
min,
name,
nativeRef,
onChange,
pattern,
placeholder,
Expand Down Expand Up @@ -74,6 +76,11 @@ export default function InputField({
}
};

const ref2 = useCallback((node) => {
inputRef(node);
nativeRef(node);
}, [nativeRef]);

useAutoFocus(inputRef, autoFocus);

return (
Expand Down Expand Up @@ -105,7 +112,7 @@ export default function InputField({
onKeyDown={onKeyDown}
pattern={pattern}
placeholder={placeholder}
ref={inputRef}
ref={ref2}
required={required}
tabIndex={tabIndex}
type={type}
Expand Down Expand Up @@ -138,6 +145,7 @@ InputField.propTypes = {
maxLength: PropTypes.number,
min: PropTypes.number,
name: PropTypes.string,
nativeRef: PropTypes.func,
onChange: PropTypes.func,
pattern: PropTypes.string,
placeholder: PropTypes.string,
Expand Down Expand Up @@ -168,6 +176,7 @@ InputField.defaultProps = {
maxLength: undefined,
min: undefined,
name: undefined,
nativeRef: () => {},
onChange: undefined,
pattern: undefined,
placeholder: undefined,
Expand Down
5 changes: 5 additions & 0 deletions src/components/inputs/DateInput/DateInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {InputField} from '../../generic';
* @param {boolean} [props.required=false] Flag indicating input required
* @param {string} [props.error] Error text
* @param {string} [props.label] Label text
* @param {Function} [props.nativeRef] Action to perform to obtain the native input ref
* @param {Function} props.onChange Action to perform on input change
* @returns {object} JSX of the component
*/
Expand All @@ -27,6 +28,7 @@ export default function DateInput({
required,
error,
label,
nativeRef,
onChange,
}) {
const [cssClasses] = webexComponentClasses('date-input', className);
Expand All @@ -41,6 +43,7 @@ export default function DateInput({
required={required}
error={error}
onChange={onChange}
nativeRef={nativeRef}
value={value}
label={label}
/>
Expand All @@ -56,6 +59,7 @@ DateInput.propTypes = {
required: PropTypes.bool,
error: PropTypes.string,
label: PropTypes.string,
nativeRef: PropTypes.func,
onChange: PropTypes.func.isRequired,
};

Expand All @@ -68,4 +72,5 @@ DateInput.defaultProps = {
required: false,
error: undefined,
label: undefined,
nativeRef: undefined,
};
5 changes: 5 additions & 0 deletions src/components/inputs/NumberInput/NumberInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const HINTS = {
* @param {number} [props.max] Maximum value for the input element
* @param {number} [props.min] Minimum value for the input element
* @param {string} [props.name] Input name
* @param {Function} [props.nativeRef] Action to perform to obtain the native input ref
* @param {Function} props.onChange Action to perform on input change
* @param {string} [props.placeholder] Input placeholder
* @param {boolean} [props.required=false] Flag indicating input required
Expand All @@ -41,6 +42,7 @@ export default function NumberInput({
max,
min,
name,
nativeRef,
onChange,
placeholder,
required,
Expand Down Expand Up @@ -92,6 +94,7 @@ export default function NumberInput({
min={min}
max={max}
name={name}
nativeRef={nativeRef}
onChange={onChange}
placeholder={placeholder}
required={required}
Expand All @@ -114,6 +117,7 @@ NumberInput.propTypes = {
max: PropTypes.number,
min: PropTypes.number,
name: PropTypes.string,
nativeRef: PropTypes.func,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.string,
required: PropTypes.bool,
Expand All @@ -134,6 +138,7 @@ NumberInput.defaultProps = {
max: undefined,
min: undefined,
name: undefined,
nativeRef: undefined,
placeholder: undefined,
required: false,
style: undefined,
Expand Down
5 changes: 5 additions & 0 deletions src/components/inputs/PasswordInput/PasswordInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const HINTS = {
* @param {string} [props.label] Label text
* @param {number} [props.maxLength] Maximum number of characters allowed
* @param {string} [props.name] Input name
* @param {Function} [props.nativeRef] Action to perform to obtain the native input ref
* @param {Function} props.onChange Action to perform on input change
* @param {string} [props.pattern] Specifies a regular expression that the element's value is checked against
* @param {string} [props.placeholder] Input placeholder
Expand All @@ -36,6 +37,7 @@ export default function PasswordInput({
label,
maxLength,
name,
nativeRef,
onChange,
pattern,
placeholder,
Expand Down Expand Up @@ -71,6 +73,7 @@ export default function PasswordInput({
label={label}
maxLength={maxLength}
name={name}
nativeRef={nativeRef}
onChange={onChange}
pattern={pattern}
placeholder={placeholder}
Expand All @@ -92,6 +95,7 @@ PasswordInput.propTypes = {
label: PropTypes.string,
maxLength: PropTypes.number,
name: PropTypes.string,
nativeRef: PropTypes.func,
onChange: PropTypes.func.isRequired,
pattern: PropTypes.string,
placeholder: PropTypes.string,
Expand All @@ -109,6 +113,7 @@ PasswordInput.defaultProps = {
label: undefined,
maxLength: undefined,
name: undefined,
nativeRef: undefined,
pattern: undefined,
placeholder: undefined,
required: false,
Expand Down
5 changes: 5 additions & 0 deletions src/components/inputs/TextInput/TextInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const HINTS = {
* @param {string} [props.label] Label text
* @param {number} [props.maxLength] Maximum number of characters allowed
* @param {string} [props.name] Input name
* @param {Function} [props.nativeRef] Action to perform to obtain the native input ref
* @param {Function} props.onChange Action to perform on input change
* @param {string} [props.pattern] Specifies a regular expression that the element's value is checked against
* @param {string} [props.placeholder] Input placeholder
Expand All @@ -37,6 +38,7 @@ export default function TextInput({
maxLength,
name,
onChange,
nativeRef,
pattern,
placeholder,
required,
Expand All @@ -63,6 +65,7 @@ export default function TextInput({
label={label}
maxLength={maxLength}
name={name}
nativeRef={nativeRef}
onChange={onChange}
pattern={pattern}
placeholder={placeholder}
Expand All @@ -84,6 +87,7 @@ TextInput.propTypes = {
label: PropTypes.string,
maxLength: PropTypes.number,
name: PropTypes.string,
nativeRef: PropTypes.func,
onChange: PropTypes.func.isRequired,
pattern: PropTypes.string,
placeholder: PropTypes.string,
Expand All @@ -102,6 +106,7 @@ TextInput.defaultProps = {
label: undefined,
maxLength: undefined,
name: undefined,
nativeRef: undefined,
pattern: undefined,
placeholder: undefined,
required: false,
Expand Down
Loading

0 comments on commit a593e5f

Please sign in to comment.