Skip to content

Commit

Permalink
feat(formiks): add FormikSelect (#10)
Browse files Browse the repository at this point in the history
* feat(formiks): add FormikEffect

* feat(formiks): add FormikSelect
  • Loading branch information
ivangabriele committed Nov 24, 2022
1 parent c78de7c commit cf3938d
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 14 deletions.
10 changes: 9 additions & 1 deletion .storybook/preview.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { ThemeProvider } from 'styled-components'
import { createGlobalStyle, ThemeProvider } from 'styled-components'

import { THEME } from '../src/theme'

import 'rsuite/dist/rsuite.min.css'
import '../src/assets/rsuite-override.css'

const GlobalStyle = createGlobalStyle`
p {
margin-bottom: 1rem;
}
`

export const decorators = [
Story => (
<ThemeProvider theme={THEME}>
<GlobalStyle />

<Story />
</ThemeProvider>
)
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"eslint-plugin-sort-destructure-keys": "1.4.0",
"eslint-plugin-sort-keys-fix": "1.1.2",
"eslint-plugin-typescript-sort-keys": "2.1.0",
"formik": "2.2.9",
"gh-pages": "4.0.0",
"husky": "8.0.1",
"jest": "29.2.0",
Expand All @@ -112,9 +113,10 @@
"webpack": "5.74.0"
},
"peerDependencies": {
"formik": "^2.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^5.3.3"
"styled-components": "^5.0.0"
},
"//": "https://github.com/okonet/lint-staged/issues/825#issuecomment-674575655",
"lint-staged": {
Expand Down
9 changes: 1 addition & 8 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import typescript from '@rollup/plugin-typescript'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'

module.exports = {
external: ['date-fns', 'dayjs', 'ramda', 'rsuite', 'tslib', 'type-fest'],
external: ['date-fns', 'dayjs', 'formik', 'ramda', 'rsuite', 'styled-components', 'tslib', 'type-fest'],

input: './src/index.ts',

Expand All @@ -30,12 +30,5 @@ module.exports = {
typescript({
tsconfig: './tsconfig.dist.json'
})
// Hack to make styled-component compatible with Next.js inability to fully support ESM:
// replace({
// '= styled(': '= (styled.default || styled)(',
// '= styled.': '= (styled.default || styled).',
// delimiters: ['', ''],
// preventAssignment: false
// })
]
}
17 changes: 17 additions & 0 deletions src/formiks/FormikEffect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useFormikContext } from 'formik'
import { useEffect } from 'react'

import type { Promisable } from 'type-fest'

export type FormikEffectProps = {
onChange: (nextValues: Record<string, any>) => Promisable<void>
}
export function FormikEffect({ onChange }: FormikEffectProps) {
const { values } = useFormikContext<Record<string, any>>()

useEffect(() => {
onChange(values)
}, [onChange, values])

return <></>
}
27 changes: 27 additions & 0 deletions src/formiks/FormikSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useField } from 'formik'
import { useCallback, useEffect } from 'react'

import { Select } from '../fields/Select'

import type { SelectProps } from '../fields/Select'

export type FormikSelectProps = Omit<SelectProps, 'name' | 'onChange'> & {
name: string
}
export function FormikSelect({ name, ...originalProps }: FormikSelectProps) {
const [, , helpers] = useField(name)
// We don't include `setValues` in `useCallback()` and `useEffect()` dependencies
// both because it is useless and it will trigger infinite hook calls
const { setValue } = helpers

const handleChange = useCallback((valueOrValues: string | string[] | undefined) => {
setValue(valueOrValues)

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => () => setValue(undefined), [])

return <Select name={name} onChange={handleChange} {...originalProps} />
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ export { DateRangePicker } from './fields/DateRangePicker'
export { DatePicker } from './fields/DatePicker'
export { Select } from './fields/Select'

export { FormikEffect } from './formiks/FormikEffect'
export { FormikSelect } from './formiks/FormikSelect'

export { ThemeProvider } from './ThemeProvider'

export type { PartialTheme, Theme } from './theme'

export type { DateRangePickerProps } from './fields/DateRangePicker'
export type { DatePickerProps } from './fields/DatePicker'
export type { SelectProps } from './fields/Select'

export type { FormikEffectProps } from './formiks/FormikEffect'
export type { FormikSelectProps } from './formiks/FormikSelect'
1 change: 1 addition & 0 deletions stories/_utils/noop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function noop() {}
4 changes: 2 additions & 2 deletions stories/fields/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ export default {
}

export const _Select = (props: SelectProps) => {
const [outputValue, setOutputValue] = useState<string | string[] | undefined>('')
const [outputValue, setOutputValue] = useState<string | string[] | undefined>('')

return (
<>
<Select {...props} onChange={setOutputValue} />

{outputValue !== '' && <Output value={outputValue} />}
{outputValue !== '' && <Output value={outputValue} />}
</>
)
}
45 changes: 45 additions & 0 deletions stories/formiks/FormikEffect.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Field, Formik } from 'formik'
import { useState } from 'react'

import { FormikEffect } from '../../src'
import { Output } from '../_components/Output'
import { noop } from '../_utils/noop'

export default {
title: 'Formiks/FormikEffect',
component: FormikEffect,

argTypes: {},

args: {}
}

export const _FormikEffect = () => {
const [outputValue, setOutputValue] = useState<
| {
aFormikField?: string
}
| '∅'
>('∅')

return (
<>
<Formik initialValues={{}} onSubmit={noop}>
<>
<FormikEffect onChange={setOutputValue} />

<p>
<code>{`<FormikEffect />`}</code> doesn’t show anything. It’s an inner <code>{`<Formik />`}</code> listener
component allowing us to get form values outside of Formik context.
</p>
<p>
Here is an example with a simple <code>{`<Formik.Field />`}</code> input:
</p>
<Field name="aFormikField" placeholder="Fill me!" type="text" />
</>
</Formik>

{outputValue !== '∅' && <Output value={outputValue} />}
</>
)
}
48 changes: 48 additions & 0 deletions stories/formiks/FormikSelect.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Formik } from 'formik'
import { useState } from 'react'

import { FormikEffect, FormikSelect } from '../../src'
import { Output } from '../_components/Output'
import { noop } from '../_utils/noop'

import type { FormikSelectProps } from '../../src'

export default {
title: 'Formiks/FormikSelect',
component: FormikSelect,

argTypes: {},

args: {
isMulti: false,
name: 'mySelect',
options: [
{ label: 'First Option', value: 'FIRST_OPTION' },
{ label: 'Second Option', value: 'SECOND_OPTION' },
{ label: 'Third Option', value: 'THIRD_OPTION' }
]
}
}

export const _FormikSelect = (props: FormikSelectProps) => {
const [outputValue, setOutputValue] = useState<
| {
mySelect?: string | string[]
}
| '∅'
>('∅')

return (
<>
<Formik initialValues={{}} onSubmit={noop}>
<>
<FormikEffect onChange={setOutputValue} />

<FormikSelect {...props} />
</>
</Formik>

{outputValue !== '∅' && <Output value={outputValue} />}
</>
)
}
51 changes: 49 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3386,6 +3386,7 @@ __metadata:
eslint-plugin-sort-destructure-keys: 1.4.0
eslint-plugin-sort-keys-fix: 1.1.2
eslint-plugin-typescript-sort-keys: 2.1.0
formik: 2.2.9
gh-pages: 4.0.0
husky: 8.0.1
jest: 29.2.0
Expand All @@ -3412,9 +3413,10 @@ __metadata:
typescript: 4.8.4
webpack: 5.74.0
peerDependencies:
formik: ^2.0.0
react: ^18.0.0
react-dom: ^18.0.0
styled-components: ^5.3.3
styled-components: ^5.0.0
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -9940,6 +9942,13 @@ __metadata:
languageName: node
linkType: hard

"deepmerge@npm:^2.1.1":
version: 2.2.1
resolution: "deepmerge@npm:2.2.1"
checksum: 284b71065079e66096229f735a9a0222463c9ca9ee9dda7d5e9a0545bf254906dbc7377e3499ca3b2212073672b1a430d80587993b43b87d8de17edc6af649a8
languageName: node
linkType: hard

"deepmerge@npm:^4.2.2":
version: 4.2.2
resolution: "deepmerge@npm:4.2.2"
Expand Down Expand Up @@ -11871,6 +11880,23 @@ __metadata:
languageName: node
linkType: hard

"formik@npm:2.2.9":
version: 2.2.9
resolution: "formik@npm:2.2.9"
dependencies:
deepmerge: ^2.1.1
hoist-non-react-statics: ^3.3.0
lodash: ^4.17.21
lodash-es: ^4.17.21
react-fast-compare: ^2.0.1
tiny-warning: ^1.0.2
tslib: ^1.10.0
peerDependencies:
react: ">=16.8.0"
checksum: f07f80eee8423b4c5560546c48c4093c47530dae7d931a4e0d947d68ae1aab94291b1bf2e99ecaa5854ee50593b415fb5724c624c787338f0577f066009e8812
languageName: node
linkType: hard

"forwarded@npm:0.2.0":
version: 0.2.0
resolution: "forwarded@npm:0.2.0"
Expand Down Expand Up @@ -15351,6 +15377,13 @@ __metadata:
languageName: node
linkType: hard

"lodash-es@npm:^4.17.21":
version: 4.17.21
resolution: "lodash-es@npm:4.17.21"
checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2
languageName: node
linkType: hard

"lodash.camelcase@npm:^4.3.0":
version: 4.3.0
resolution: "lodash.camelcase@npm:4.3.0"
Expand Down Expand Up @@ -18878,6 +18911,13 @@ __metadata:
languageName: node
linkType: hard

"react-fast-compare@npm:^2.0.1":
version: 2.0.4
resolution: "react-fast-compare@npm:2.0.4"
checksum: 06046595f90a4e3e3a56f40a8078c00aa71bdb064ddb98343f577f546aa22e888831fd45f009c93b34707cc842b4c637737e956fd13d6f80607ee92fb9cf9a1c
languageName: node
linkType: hard

"react-inspector@npm:^5.1.0":
version: 5.1.1
resolution: "react-inspector@npm:5.1.1"
Expand Down Expand Up @@ -21451,6 +21491,13 @@ __metadata:
languageName: node
linkType: hard

"tiny-warning@npm:^1.0.2":
version: 1.0.3
resolution: "tiny-warning@npm:1.0.3"
checksum: da62c4acac565902f0624b123eed6dd3509bc9a8d30c06e017104bedcf5d35810da8ff72864400ad19c5c7806fc0a8323c68baf3e326af7cb7d969f846100d71
languageName: node
linkType: hard

"tmpl@npm:1.0.5":
version: 1.0.5
resolution: "tmpl@npm:1.0.5"
Expand Down Expand Up @@ -21686,7 +21733,7 @@ __metadata:
languageName: node
linkType: hard

"tslib@npm:^1.8.1":
"tslib@npm:^1.10.0, tslib@npm:^1.8.1":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
Expand Down

0 comments on commit cf3938d

Please sign in to comment.