From b1fe570a8ef06f69b02e593607e4541a1513cd34 Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Thu, 23 Jul 2020 14:17:44 -0500 Subject: [PATCH 1/8] Default Validation story working - add ValidationChecklist, ValidationItem - add validation prop to Alert --- src/components/Alert/Alert.tsx | 3 + .../forms/Validation/Validation.stories.tsx | 88 +++++++++++++++++++ .../forms/Validation/ValidationChecklist.tsx | 23 +++++ .../forms/Validation/ValidationItem.tsx | 30 +++++++ 4 files changed, 144 insertions(+) create mode 100644 src/components/forms/Validation/Validation.stories.tsx create mode 100644 src/components/forms/Validation/ValidationChecklist.tsx create mode 100644 src/components/forms/Validation/ValidationItem.tsx diff --git a/src/components/Alert/Alert.tsx b/src/components/Alert/Alert.tsx index f2136633ea..27dd389288 100644 --- a/src/components/Alert/Alert.tsx +++ b/src/components/Alert/Alert.tsx @@ -10,6 +10,7 @@ interface AlertProps { cta?: React.ReactNode slim?: boolean noIcon?: boolean + validation: boolean } export const Alert = ({ @@ -20,6 +21,7 @@ export const Alert = ({ slim, noIcon, className, + validation, ...props }: AlertProps & React.HTMLAttributes): React.ReactElement => { const classes = classnames( @@ -31,6 +33,7 @@ export const Alert = ({ 'usa-alert--info': type === 'info', 'usa-alert--slim': slim, 'usa-alert--no-icon': noIcon, + 'usa-alert--validation': validation, [styles.alertWithCTA]: !!cta, }, className diff --git a/src/components/forms/Validation/Validation.stories.tsx b/src/components/forms/Validation/Validation.stories.tsx new file mode 100644 index 0000000000..7defb84dd7 --- /dev/null +++ b/src/components/forms/Validation/Validation.stories.tsx @@ -0,0 +1,88 @@ +import React, { useState, ChangeEvent } from 'react' +import { Alert } from '../../Alert/Alert' +import { Button } from '../../Button/Button' +import { Fieldset } from '../Fieldset/Fieldset' +import { Form } from '../Form/Form' +import { Label } from '../Label/Label' +import { TextInput } from '../TextInput/TextInput' +import { ValidationChecklist } from './ValidationChecklist' +import { ValidationItem } from './ValidationItem' + +export default { + title: 'Forms/Validation', + component: ValidationChecklist, + ValidationItem, + parameters: { + info: ` +USWDS 2.0 Validation component + +Source: https://designsystem.digital.gov/components/form-controls/#validation +`, + }, +} + +//This could be a third party util or any function that returns boolean for a specific validation +const validate = (type, value): boolean => { + switch (type) { + case 'uppercase': + return /[A-Z]/.test(value) + case 'numerical': + return /\d/.test(value) + default: + console.warn(`No validation item found for: "${type}"`) + return false + } +} + +export const Default = (): React.ReactElement => { + const [validations, setValidations] = useState({ + uppercase: false, + numerical: false, + }) + + const validateInput = (event: ChangeEvent): void => { + const { + target: { value }, + } = event + const updatedValidations = {} + + Object.keys(validations).forEach((validator) => { + // eslint-disable-next-line security/detect-object-injection + updatedValidations[validator] = validate(validator, value) + }) + + setValidations({ ...validations, ...updatedValidations }) + } + return ( +
{ + console.log('submit') + }}> +
+ + + + Use at least one uppercase character + + + Use at least one number + + + + + + +
+
+ ) +} diff --git a/src/components/forms/Validation/ValidationChecklist.tsx b/src/components/forms/Validation/ValidationChecklist.tsx new file mode 100644 index 0000000000..a68eb099ba --- /dev/null +++ b/src/components/forms/Validation/ValidationChecklist.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import classnames from 'classnames' + +interface ValidationChecklistProps { + id: string + children: React.ReactNode +} + +export const ValidationChecklist = ({ + children, + className, + ...ulProps +}: ValidationChecklistProps & + JSX.IntrinsicElements['ul']): React.ReactElement => { + const classes = classnames(className, 'usa-checklist') + return ( +
    + {children} +
+ ) +} + +export default ValidationChecklist diff --git a/src/components/forms/Validation/ValidationItem.tsx b/src/components/forms/Validation/ValidationItem.tsx new file mode 100644 index 0000000000..ba8eefa9f7 --- /dev/null +++ b/src/components/forms/Validation/ValidationItem.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import classnames from 'classnames' + +interface ValidationItemProps { + children: React.ReactNode + validator: string // unique string representing validation concern- e.g. 'uppercase', 'numerical', 'length' + isValid: boolean +} + +export const ValidationItem = ({ + children, + className, + validator, + isValid, + ...liProps +}: ValidationItemProps & JSX.IntrinsicElements['li']): React.ReactElement => { + const classes = classnames( + 'usa-checklist__item', + { 'usa-checklist__item--checked': isValid }, + className + ) + + return ( +
  • + {children} +
  • + ) +} + +export default ValidationItem From 85f5b3adb81714f0ce8a172f59572b9fb659cb6a Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Thu, 23 Jul 2020 14:39:02 -0500 Subject: [PATCH 2/8] Add tests --- src/components/Alert/Alert.tsx | 2 +- .../Validation/ValidationChecklist.test.tsx | 35 +++++++++++ .../forms/Validation/ValidationItem.test.tsx | 58 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/components/forms/Validation/ValidationChecklist.test.tsx create mode 100644 src/components/forms/Validation/ValidationItem.test.tsx diff --git a/src/components/Alert/Alert.tsx b/src/components/Alert/Alert.tsx index 27dd389288..859e42a68d 100644 --- a/src/components/Alert/Alert.tsx +++ b/src/components/Alert/Alert.tsx @@ -10,7 +10,7 @@ interface AlertProps { cta?: React.ReactNode slim?: boolean noIcon?: boolean - validation: boolean + validation?: boolean } export const Alert = ({ diff --git a/src/components/forms/Validation/ValidationChecklist.test.tsx b/src/components/forms/Validation/ValidationChecklist.test.tsx new file mode 100644 index 0000000000..2f74eabc8f --- /dev/null +++ b/src/components/forms/Validation/ValidationChecklist.test.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { render } from '@testing-library/react' + +import { ValidationChecklist } from './ValidationChecklist' + +describe('ValidationChecklist', () => { + it('renders without errors', () => { + const { queryByTestId } = render( + + Validation message + + ) + + expect(queryByTestId('validationChecklist')).toBeInTheDocument() + }) + + it('renders unordered list with styles', () => { + const { container } = render( + +
  • Validation message
  • +
    + ) + expect(container.querySelector('ul')).toBeInTheDocument() + expect(container.querySelector('ul')).toHaveClass('usa-checklist') + }) + + it('renders its children', () => { + const { queryByText } = render( + +
  • Length is less than 16 characters
  • +
    + ) + expect(queryByText('Length is less than 16 characters')).toBeInTheDocument() + }) +}) diff --git a/src/components/forms/Validation/ValidationItem.test.tsx b/src/components/forms/Validation/ValidationItem.test.tsx new file mode 100644 index 0000000000..e4bc937c98 --- /dev/null +++ b/src/components/forms/Validation/ValidationItem.test.tsx @@ -0,0 +1,58 @@ +import React from 'react' +import { render } from '@testing-library/react' + +import { ValidationItem } from './ValidationItem' + +describe('ValidationItem', () => { + it('renders without errors', () => { + const { container } = render( + + Validation message + + ) + + expect(container.querySelector('li')).toBeInTheDocument() + }) + + it('renders list item with styles', () => { + const { queryByTestId } = render( +
      + + Validation message + + + Validation message + +
    + ) + + expect(queryByTestId('uppercase')).toHaveClass('usa-checklist__item') + expect(queryByTestId('uppercase')).not.toHaveClass( + 'usa-checklist__item--checked' + ) + expect(queryByTestId('lowercase')).toHaveClass( + 'usa-checklist__item--checked usa-checklist__item ' + ) + }) + + it('renders its children', () => { + const { queryByText } = render( +
      + + Length is more than 2 characters + + + Length is less than 16 characters + +
    + ) + expect(queryByText('Length is more than 2 characters')).toBeInTheDocument() + expect(queryByText('Length is less than 16 characters')).toBeInTheDocument() + }) +}) From f4e9b2df239ac30651746a0da7b9e4cdc99285ec Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Mon, 27 Jul 2020 10:35:57 -0500 Subject: [PATCH 3/8] Add forms page to example app --- example/src/App.tsx | 17 ++++++----------- example/src/pages/Example.tsx | 28 +++++++++++++++++++--------- example/src/pages/Forms.tsx | 5 +++++ example/src/pages/Home.tsx | 6 +----- example/src/routes.js | 8 ++++++++ 5 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 example/src/pages/Forms.tsx create mode 100644 example/src/routes.js diff --git a/example/src/App.tsx b/example/src/App.tsx index 5512ef6bcc..0a3793d0d9 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -21,19 +21,14 @@ import { import HomePage from './pages/Home' import ExamplePage from './pages/Example' import ModalsPage from './pages/Modals' +import FormsPage from './pages/Forms' +import { Routes } from './routes' import './App.css' -/* Routes */ -const routes = { - HOME_PAGE: '/', - EXAMPLES_PAGE: '/examples', - MODALS_PAGE: '/modals', -} - const App = () => { const [mobileNavOpen, setMobileNavOpen] = useState(false) - const { HOME_PAGE, EXAMPLES_PAGE, MODALS_PAGE } = routes + const { HOME_PAGE, EXAMPLES_PAGE, MODALS_PAGE, FORMS_PAGE } = Routes const toggleMobileNav = (): void => { setMobileNavOpen((prevOpen) => !prevOpen) @@ -46,9 +41,6 @@ const App = () => { Examples , - - Modals - , ] return ( @@ -85,6 +77,9 @@ const App = () => { + + + diff --git a/example/src/pages/Example.tsx b/example/src/pages/Example.tsx index 0eae8345e3..95bed21871 100644 --- a/example/src/pages/Example.tsx +++ b/example/src/pages/Example.tsx @@ -1,21 +1,31 @@ import React from 'react' +import { Link } from 'react-router-dom' +import { Link as USWDSLink } from '@trussworks/react-uswds' const ExamplePage = (): React.ReactElement => (

    Examples

    -

    - Right now there are no examples! Things that we could add include... -

    +

    Example usage of react-uswds in real life!

      -
    • Modals
    • - Form libraries -
        -
      • Formik
      • -
      • React-hook-form
      • -
      + + Forms + +
    • +
    • + + Modals +
    diff --git a/example/src/pages/Forms.tsx b/example/src/pages/Forms.tsx new file mode 100644 index 0000000000..5573d5ad16 --- /dev/null +++ b/example/src/pages/Forms.tsx @@ -0,0 +1,5 @@ +import React from 'react' + +const FormsPage = (): React.ReactElement =>

    Forms Page

    + +export default FormsPage diff --git a/example/src/pages/Home.tsx b/example/src/pages/Home.tsx index fb6d82b67b..e8e41e3d10 100644 --- a/example/src/pages/Home.tsx +++ b/example/src/pages/Home.tsx @@ -9,11 +9,7 @@ const HomePage = (): React.ReactElement => (

    This is an example application that can be used to demonstrate and test ReactUSWDS functionality. Here's a{' '} - + link to the examples page!

    diff --git a/example/src/routes.js b/example/src/routes.js new file mode 100644 index 0000000000..c879e72498 --- /dev/null +++ b/example/src/routes.js @@ -0,0 +1,8 @@ +const Routes = { + HOME_PAGE: '/', + EXAMPLES_PAGE: '/examples', + FORMS_PAGE: '/forms', + MODALS_PAGE: '/modals', +} + +export { Routes } From a01a0c3cf356b32ad0984539bfe7291bab751409 Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Mon, 27 Jul 2020 14:37:38 -0500 Subject: [PATCH 4/8] Make Alert render children directly for validation style --- src/components/Alert/Alert.test.tsx | 21 +++++++++++++++++++++ src/components/Alert/Alert.tsx | 7 ++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/components/Alert/Alert.test.tsx b/src/components/Alert/Alert.test.tsx index 4e382df5ae..40d807f77a 100644 --- a/src/components/Alert/Alert.test.tsx +++ b/src/components/Alert/Alert.test.tsx @@ -9,6 +9,27 @@ describe('Alert component', () => { expect(queryByTestId('alert')).toBeInTheDocument() }) + it('renders children in

    tag by default', () => { + const { queryByTestId } = render( + + Test children + + ) + expect(queryByTestId('alert')).toHaveTextContent('Test children') + expect(queryByTestId('alert')).toContainHTML('p') + }) + + it('renders validation style alert', () => { + const { queryByTestId } = render( + + Test children + + ) + expect(queryByTestId('alert')).toHaveTextContent('Test children') + expect(queryByTestId('alert')).not.toContainHTML('p') + expect(queryByTestId('alert')).toHaveClass('usa-alert--validation') + }) + it('accepts className prop', () => { const { queryByTestId } = render( diff --git a/src/components/Alert/Alert.tsx b/src/components/Alert/Alert.tsx index 859e42a68d..c26ddb6287 100644 --- a/src/components/Alert/Alert.tsx +++ b/src/components/Alert/Alert.tsx @@ -43,7 +43,12 @@ export const Alert = ({

    {heading &&

    {heading}

    } - {children &&

    {children}

    } + {children && + (validation ? ( + children + ) : ( +

    {children}

    + ))}
    {cta &&
    {cta}
    }
    From 173670943f6a549cede00b80bfc4cb806273e15d Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Mon, 27 Jul 2020 14:57:35 -0500 Subject: [PATCH 5/8] Add example usage with Formik and yup --- example/package.json | 5 +- example/src/pages/Forms.tsx | 103 +++++++++++++++++++++++++++++++++++- example/yarn.lock | 79 ++++++++++++++++++++++++++- src/index.ts | 2 + 4 files changed, 184 insertions(+), 5 deletions(-) diff --git a/example/package.json b/example/package.json index c3be82215d..cdfca42b6d 100644 --- a/example/package.json +++ b/example/package.json @@ -12,13 +12,16 @@ "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", "@types/react-redux": "^7.1.9", + "@types/yup": "^0.29.3", + "formik": "^2.1.5", "react": "^16.13.1", "react-dom": "^16.13.1", "react-redux": "^7.2.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "redux": "^4.0.5", - "typescript": "~3.9.7" + "typescript": "~3.9.7", + "yup": "^0.29.1" }, "scripts": { "start": "SKIP_PREFLIGHT_CHECK=true react-app-rewired start", diff --git a/example/src/pages/Forms.tsx b/example/src/pages/Forms.tsx index 5573d5ad16..f14181b31c 100644 --- a/example/src/pages/Forms.tsx +++ b/example/src/pages/Forms.tsx @@ -1,5 +1,104 @@ -import React from 'react' +import React, { useState } from 'react' +import { Field, Formik } from 'formik' +import * as Yup from 'yup' +import { + Alert, + Button, + Form, + Label, + TextInput, + ValidationChecklist, + ValidationItem, +} from '@trussworks/react-uswds' -const FormsPage = (): React.ReactElement =>

    Forms Page

    +type FormValues = { + email?: string + password?: string +} + +const FormSchema = Yup.object().shape({ + email: Yup.string().email().required(), + password: Yup.string().min(8).max(20).required(), +}) + +const FormsPage = (): React.ReactElement => { + return ( + <> +

    Forms

    +
    +

    Formik

    + { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)) + + setSubmitting(false) + }, 400) + }}> + {({ values, errors, touched, handleSubmit, isSubmitting }) => ( +
    + {touched.email && errors.email && ( + + + 0}> + Include required field. + + + Use only valid email formatting + + {errors.email} + + + )} + + + + {touched.password && errors.password && ( + + + 0}> + Include required field. + + + Length is between 8-20 characters + + + + )} + + + + + + )} +
    +
    + + ) +} export default FormsPage diff --git a/example/yarn.lock b/example/yarn.lock index 3152f32189..8bda834da2 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1067,7 +1067,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@>=7.0.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@>=7.0.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== @@ -1704,6 +1704,11 @@ dependencies: "@types/yargs-parser" "*" +"@types/yup@^0.29.3": + version "0.29.3" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.3.tgz#5a85024796bffe0eb01601bfc180fe218356dba4" + integrity sha512-XxZFKnxzTfm+DR8MMBA35UUXfUPmjPpi8HJ90VZg7q/LIbtiOhVGJ26gNnATcflcpnIyf2Qm9A+oEhswaqoDpA== + "@typescript-eslint/eslint-plugin@^2.10.0": version "2.34.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" @@ -3789,6 +3794,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -4880,6 +4890,11 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +fn-name@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" + integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA== + follow-redirects@^1.0.0: version "1.12.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" @@ -4930,6 +4945,20 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formik@^2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.5.tgz#de5bbbe35543fa6d049fe96b8ee329d6cd6892b8" + integrity sha512-bWpo3PiqVDYslvrRjTq0Isrm0mFXHiO33D8MS6t6dWcqSFGeYF52nlpCM2xwOJ6tRVRznDkL+zz/iHPL4LDuvQ== + dependencies: + deepmerge "^2.1.1" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.14" + lodash-es "^4.17.14" + react-fast-compare "^2.0.1" + scheduler "^0.18.0" + tiny-warning "^1.0.2" + tslib "^1.10.0" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -6874,6 +6903,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.11, lodash-es@^4.17.14: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" + integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -8846,6 +8880,11 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +property-expr@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.2.tgz#fff2a43919135553a3bc2fdd94bdb841965b2330" + integrity sha512-bc/5ggaYZxNkFKj374aLbEDqVADdYaLcFo8XBkishUWbaAdjlphaBFns9TvRA2pUseVL/wMFmui9X3IdNDU37g== + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -9055,6 +9094,11 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -9694,6 +9738,14 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" +scheduler@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" + integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" @@ -10441,6 +10493,11 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +synchronous-promise@^2.0.10: + version "2.0.13" + resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702" + integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA== + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -10561,7 +10618,7 @@ tiny-invariant@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== -tiny-warning@^1.0.0, tiny-warning@^1.0.3: +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -10625,6 +10682,11 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= + tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -11483,6 +11545,19 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" +yup@^0.29.1: + version "0.29.1" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.1.tgz#35d25aab470a0c3950f66040ba0ff4b1b6efe0d9" + integrity sha512-U7mPIbgfQWI6M3hZCJdGFrr+U0laG28FxMAKIgNvgl7OtyYuUoc4uy9qCWYHZjh49b8T7Ug8NNDdiMIEytcXrQ== + dependencies: + "@babel/runtime" "^7.9.6" + fn-name "~3.0.0" + lodash "^4.17.15" + lodash-es "^4.17.11" + property-expr "^2.0.2" + synchronous-promise "^2.0.10" + toposort "^2.0.2" + zip-stream@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b" diff --git a/src/index.ts b/src/index.ts index 138487d77d..12632ea938 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,6 +29,8 @@ export { Radio } from './components/forms/Radio/Radio' export { RangeInput } from './components/forms/RangeInput/RangeInput' export { Textarea } from './components/forms/Textarea/Textarea' export { TextInput } from './components/forms/TextInput/TextInput' +export { ValidationChecklist } from './components/forms/Validation/ValidationChecklist' +export { ValidationItem } from './components/forms/Validation/ValidationItem' /** Header Components */ export { ExtendedNav } from './components/header/ExtendedNav/ExtendedNav' From 900b0a7c17a0862bfb0de9f04af90b466a3cfce6 Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Mon, 27 Jul 2020 17:03:52 -0500 Subject: [PATCH 6/8] Remove unnecessary prop --- example/src/pages/Forms.tsx | 14 +++++--------- .../forms/Validation/Validation.stories.tsx | 8 ++------ src/components/forms/Validation/ValidationItem.tsx | 5 ++--- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/example/src/pages/Forms.tsx b/example/src/pages/Forms.tsx index f14181b31c..8931da91e5 100644 --- a/example/src/pages/Forms.tsx +++ b/example/src/pages/Forms.tsx @@ -24,7 +24,7 @@ const FormSchema = Yup.object().shape({ const FormsPage = (): React.ReactElement => { return ( <> -

    Forms

    +

    Forms Examples

    Formik

    { 0}> Include required field. - + Use only valid email formatting {errors.email} @@ -69,13 +67,11 @@ const FormsPage = (): React.ReactElement => { 0}> Include required field. - + Length is between 8-20 characters diff --git a/src/components/forms/Validation/Validation.stories.tsx b/src/components/forms/Validation/Validation.stories.tsx index 7defb84dd7..96e94a2d00 100644 --- a/src/components/forms/Validation/Validation.stories.tsx +++ b/src/components/forms/Validation/Validation.stories.tsx @@ -61,14 +61,10 @@ export const Default = (): React.ReactElement => {
    - + Use at least one uppercase character - + Use at least one number diff --git a/src/components/forms/Validation/ValidationItem.tsx b/src/components/forms/Validation/ValidationItem.tsx index ba8eefa9f7..6b67e396cb 100644 --- a/src/components/forms/Validation/ValidationItem.tsx +++ b/src/components/forms/Validation/ValidationItem.tsx @@ -3,14 +3,13 @@ import classnames from 'classnames' interface ValidationItemProps { children: React.ReactNode - validator: string // unique string representing validation concern- e.g. 'uppercase', 'numerical', 'length' + id: string isValid: boolean } export const ValidationItem = ({ children, className, - validator, isValid, ...liProps }: ValidationItemProps & JSX.IntrinsicElements['li']): React.ReactElement => { @@ -21,7 +20,7 @@ export const ValidationItem = ({ ) return ( -
  • +
  • {children}
  • ) From a4e6ab9af432cfdb281f00fd9c2c5c3db8f699d1 Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Wed, 29 Jul 2020 12:46:49 -0500 Subject: [PATCH 7/8] Cleanup tests from removed prop --- .../forms/Validation/ValidationItem.test.tsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/components/forms/Validation/ValidationItem.test.tsx b/src/components/forms/Validation/ValidationItem.test.tsx index e4bc937c98..633506f553 100644 --- a/src/components/forms/Validation/ValidationItem.test.tsx +++ b/src/components/forms/Validation/ValidationItem.test.tsx @@ -6,7 +6,7 @@ import { ValidationItem } from './ValidationItem' describe('ValidationItem', () => { it('renders without errors', () => { const { container } = render( - + Validation message ) @@ -17,16 +17,10 @@ describe('ValidationItem', () => { it('renders list item with styles', () => { const { queryByTestId } = render(
      - + Validation message - + Validation message
    @@ -44,10 +38,10 @@ describe('ValidationItem', () => { it('renders its children', () => { const { queryByText } = render(
      - + Length is more than 2 characters - + Length is less than 16 characters
    From e203e14190af5e2995dde6de189f7f957f74d122 Mon Sep 17 00:00:00 2001 From: Hana Worku Date: Thu, 30 Jul 2020 09:49:36 -0500 Subject: [PATCH 8/8] Use storybook subcomponents --- src/components/forms/Validation/Validation.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/forms/Validation/Validation.stories.tsx b/src/components/forms/Validation/Validation.stories.tsx index 96e94a2d00..45ecdb1080 100644 --- a/src/components/forms/Validation/Validation.stories.tsx +++ b/src/components/forms/Validation/Validation.stories.tsx @@ -11,7 +11,7 @@ import { ValidationItem } from './ValidationItem' export default { title: 'Forms/Validation', component: ValidationChecklist, - ValidationItem, + subcomponents: { ValidationItem }, parameters: { info: ` USWDS 2.0 Validation component