forked from jaredpalmer/formik
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from jawnstreams/johnrom/downstream
Consolidate State and Add Tutorial + Fixtures.
- Loading branch information
Showing
27 changed files
with
803 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import * as React from 'react'; | ||
|
||
export const Collapse: React.FC = props => { | ||
const [collapsed, setCollapsed] = React.useState(false); | ||
|
||
return ( | ||
<div> | ||
<button type="button" onClick={() => setCollapsed(!collapsed)}> | ||
Collapse | ||
</button> | ||
<div | ||
style={{ | ||
overflow: 'hidden', | ||
height: collapsed ? 0 : 'auto', | ||
}} | ||
> | ||
{props.children} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import * as React from 'react'; | ||
import { UseFieldProps, useField } from 'formik'; | ||
import { DebugProps } from './DebugProps'; | ||
|
||
export const DebugFieldState = (props: UseFieldProps) => { | ||
const [field, meta, helpers] = useField(props); | ||
|
||
return <DebugProps {...{ ...field, ...meta, ...helpers }} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import * as React from 'react'; | ||
import { useFormikContext } from 'formik'; | ||
import { DebugProps } from './DebugProps'; | ||
|
||
export const DebugFormikState = () => { | ||
const formikState = useFormikContext(); | ||
|
||
return <DebugProps {...formikState} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import * as React from 'react'; | ||
|
||
export const DebugProps = (props?: any) => { | ||
const renderCount = React.useRef(0); | ||
return ( | ||
<div style={{ margin: '1rem 0' }}> | ||
<pre | ||
style={{ | ||
background: '#f6f8fa', | ||
fontSize: '.65rem', | ||
padding: '.5rem', | ||
}} | ||
> | ||
<strong>props</strong> = {JSON.stringify(props, null, 2)} | ||
<strong>renders</strong> = {renderCount.current++} | ||
</pre> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { selectRandomInt } from './random-helpers'; | ||
|
||
export const selectRange = (count: number) => Array.from(Array(count).keys()); | ||
|
||
export const selectRandomArrayItem = <T extends any>(array: T[]) => { | ||
const index = selectRandomInt(array.length); | ||
|
||
return array[index]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { FormikApi } from 'formik'; | ||
import { useMemo, useEffect } from 'react'; | ||
import { selectRandomInt } from './random-helpers'; | ||
|
||
export type DynamicValues = Record<string, string>; | ||
|
||
export const useChaosHelpers = ( | ||
formik: FormikApi<DynamicValues>, | ||
array: number[] | ||
) => { | ||
return useMemo( | ||
() => [ | ||
() => | ||
formik.setValues( | ||
array.reduce<Record<string, string>>((prev, id) => { | ||
prev[`Input ${id}`] = selectRandomInt(500).toString(); | ||
|
||
if (prev[`Input ${id}`]) { | ||
} | ||
|
||
return prev; | ||
}, {}) | ||
), | ||
() => | ||
formik.setErrors( | ||
array.reduce<Record<string, string>>((prev, id) => { | ||
const error = selectRandomInt(500); | ||
|
||
// leave some errors empty | ||
prev[`Input ${id}`] = error % 5 === 0 ? '' : error.toString(); | ||
|
||
return prev; | ||
}, {}) | ||
), | ||
() => | ||
formik.setTouched( | ||
array.reduce<Record<string, boolean>>((prev, id) => { | ||
prev[`Input ${id}`] = selectRandomInt(500) % 2 === 0; | ||
|
||
return prev; | ||
}, {}) | ||
), | ||
() => formik.submitForm(), | ||
() => | ||
formik.setFieldValue( | ||
`Input ${selectRandomInt(array.length)}`, | ||
selectRandomInt(500).toString() | ||
), | ||
() => | ||
formik.setFieldError( | ||
`Input ${selectRandomInt(array.length)}`, | ||
selectRandomInt(500).toString() | ||
), | ||
() => | ||
formik.setFieldTouched( | ||
`Input ${selectRandomInt(array.length)}`, | ||
selectRandomInt(2) % 2 === 0 | ||
), | ||
() => formik.setStatus(selectRandomInt(500).toString()), | ||
() => formik.resetForm(), | ||
], | ||
[array, formik] | ||
); | ||
}; | ||
|
||
let skipCount = 0; | ||
|
||
/** | ||
* https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-mode | ||
*/ | ||
export const useAutoUpdate = () => { | ||
useEffect(() => { | ||
if (typeof document !== 'undefined') { | ||
skipCount += 1; | ||
|
||
if (skipCount % 10 === 0) { | ||
document.getElementById('update-without-transition')?.click(); | ||
} | ||
} | ||
}, []); | ||
|
||
// SSR | ||
if (typeof performance !== 'undefined') { | ||
const start = performance?.now(); | ||
while (performance?.now() - start < 2) { | ||
// empty | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* @param minOrMax // The maximum is exclusive and the minimum is inclusive | ||
* @param max | ||
*/ | ||
export const selectRandomInt = (minOrMax: number, max?: number) => { | ||
const min = max ? minOrMax : 0; | ||
max = max ? max : minOrMax; | ||
return Math.floor(Math.random() * (max - min)) + min; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { selectRange } from './array-helpers'; | ||
import { useState, useCallback, useMemo } from 'react'; | ||
import { useEffect } from 'react'; | ||
|
||
/** | ||
* Check if all elements show the same number. | ||
* https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-mode | ||
*/ | ||
export const useCheckTearing = (elementCount: number, skip = 0) => { | ||
const ids = useMemo(() => selectRange(elementCount).slice(skip), [ | ||
elementCount, | ||
skip, | ||
]); | ||
const checkMatches = useCallback(() => { | ||
const [first, ...rest] = ids; | ||
const firstValue = document.querySelector(`#input-${first} code`) | ||
?.innerHTML; | ||
return rest.every(id => { | ||
const thisValue = document.querySelector(`#input-${id} code`)?.innerHTML; | ||
const tore = thisValue !== firstValue; | ||
if (tore) { | ||
console.log('useCheckTearing: tore'); | ||
console.log(thisValue); | ||
console.log(firstValue); | ||
} | ||
return !tore; | ||
}); | ||
}, [ids]); | ||
const [didTear, setDidTear] = useState(false); | ||
|
||
// We won't create an infinite loop switching this boolean once, I promise. | ||
// (famous last words) | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
useEffect(() => { | ||
if (!didTear && !checkMatches()) { | ||
setDidTear(true); | ||
} | ||
}); | ||
|
||
return didTear; | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as React from 'react'; | ||
import { Formik, Field, Form, FieldProps } from 'formik'; | ||
import { DebugProps } from '../../components/debugging/DebugProps'; | ||
|
||
const initialValues = { | ||
name: '', | ||
}; | ||
|
||
const RenderComponent = (props: FieldProps<string, typeof initialValues>) => ( | ||
<> | ||
<input data-testid="child" {...props.field} /> | ||
<DebugProps {...props} /> | ||
</> | ||
); | ||
const ComponentComponent = ( | ||
props: FieldProps<string, typeof initialValues> | ||
) => ( | ||
<> | ||
<input data-testid="child" {...props.field} /> | ||
<DebugProps {...props} /> | ||
</> | ||
); | ||
const AsComponent = ( | ||
props: FieldProps<string, typeof initialValues>['field'] | ||
) => ( | ||
<> | ||
<input data-testid="child" {...props} /> | ||
<DebugProps {...props} /> | ||
</> | ||
); | ||
|
||
const ComponentsPage = () => ( | ||
<div> | ||
<h1>Test Components</h1> | ||
<Formik | ||
initialValues={initialValues} | ||
validate={values => { | ||
console.log(values); | ||
}} | ||
onSubmit={async values => { | ||
await new Promise(r => setTimeout(r, 500)); | ||
alert(JSON.stringify(values, null, 2)); | ||
}} | ||
> | ||
<Form> | ||
<Field name="name" children={RenderComponent} /> | ||
<Field name="name" render={RenderComponent} /> | ||
<Field name="name" component={ComponentComponent} /> | ||
<Field name="name" as={AsComponent} /> | ||
<button type="submit">Submit</button> | ||
</Form> | ||
</Formik> | ||
</div> | ||
); | ||
|
||
export default ComponentsPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import * as React from 'react'; | ||
import { Formik, Field, Form, ErrorMessage } from 'formik'; | ||
import * as Yup from 'yup'; | ||
|
||
let renderCount = 0; | ||
|
||
const PerfPage = () => ( | ||
<div> | ||
<h1>Sign Up</h1> | ||
<Formik | ||
initialValues={{ | ||
firstName: '', | ||
lastName: '', | ||
email: '', | ||
favorite: '', | ||
checked: [], | ||
picked: '', | ||
lastName2: '', | ||
lastName3: '', | ||
lastName4: '', | ||
lastName5: '', | ||
lastName6: '', | ||
lastName7: '', | ||
lastName8: '', | ||
lastName9: '', | ||
lastName10: '', | ||
lastName11: '', | ||
lastName12: '', | ||
lastName13: '', | ||
lastName14: '', | ||
lastName15: '', | ||
lastName16: '', | ||
lastName17: '', | ||
lastName18: '', | ||
lastName19: '', | ||
lastName20: '', | ||
}} | ||
validationSchema={Yup.object().shape({ | ||
email: Yup.string().email('Invalid email address').required('Required'), | ||
firstName: Yup.string().required('Required'), | ||
lastName: Yup.string() | ||
.min(2, 'Must be longer than 2 characters') | ||
.max(20, 'Nice try, nobody has a last name that long') | ||
.required('Required'), | ||
})} | ||
onSubmit={async values => { | ||
await new Promise(r => setTimeout(r, 500)); | ||
alert(JSON.stringify(values, null, 2)); | ||
}} | ||
> | ||
<Form> | ||
<Field name="firstName" placeholder="Jane" /> | ||
<ErrorMessage name="firstName" component="p" /> | ||
|
||
<Field name="lastName" placeholder="Doe" /> | ||
<Field name="lastName2" placeholder="Doe" /> | ||
<Field name="lastName3" placeholder="Doe" /> | ||
<Field name="lastName4" placeholder="Doe" /> | ||
<Field name="lastName5" placeholder="Doe" /> | ||
<Field name="lastName6" placeholder="Doe" /> | ||
<Field name="lastName7" placeholder="Doe" /> | ||
<Field name="lastName8" placeholder="Doe" /> | ||
<Field name="lastName9" placeholder="Doe" /> | ||
<Field name="lastName10" placeholder="Doe" /> | ||
<Field name="lastName11" placeholder="Doe" /> | ||
<Field name="lastName12" placeholder="Doe" /> | ||
<Field name="lastName13" placeholder="Doe" /> | ||
<Field name="lastName14" placeholder="Doe" /> | ||
<Field name="lastName15" placeholder="Doe" /> | ||
<Field name="lastName16" placeholder="Doe" /> | ||
<Field name="lastName17" placeholder="Doe" /> | ||
<Field name="lastName18" placeholder="Doe" /> | ||
<Field name="lastName19" placeholder="Doe" /> | ||
<Field name="lastName20" placeholder="Doe" /> | ||
<ErrorMessage name="lastName" component="p" /> | ||
|
||
<Field | ||
id="email" | ||
name="email" | ||
placeholder="jane@acme.com" | ||
type="email" | ||
/> | ||
<ErrorMessage name="email" component="p" /> | ||
|
||
<label> | ||
<Field type="checkbox" name="toggle" /> | ||
<span style={{ marginLeft: 3 }}>Toggle</span> | ||
</label> | ||
|
||
<div id="checkbox-group">Checkbox Group </div> | ||
<div role="group" aria-labelledby="checkbox-group"> | ||
<label> | ||
<Field type="checkbox" name="checked" value="One" /> | ||
One | ||
</label> | ||
<label> | ||
<Field type="checkbox" name="checked" value="Two" /> | ||
Two | ||
</label> | ||
<label> | ||
<Field type="checkbox" name="checked" value="Three" /> | ||
Three | ||
</label> | ||
</div> | ||
<div id="my-radio-group">Picked</div> | ||
<div role="group" aria-labelledby="my-radio-group"> | ||
<label> | ||
<Field type="radio" name="picked" value="One" /> | ||
One | ||
</label> | ||
<label> | ||
<Field type="radio" name="picked" value="Two" /> | ||
Two | ||
</label> | ||
</div> | ||
<button type="submit">Submit</button> | ||
<div id="renderCounter">{renderCount++}</div> | ||
</Form> | ||
</Formik> | ||
</div> | ||
); | ||
|
||
export default PerfPage; |
Oops, something went wrong.