Skip to content

Commit

Permalink
feat(fields): add Checkbox (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivangabriele committed Nov 28, 2022
1 parent cf27491 commit 37a1746
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 67 deletions.
35 changes: 35 additions & 0 deletions src/fields/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useCallback, useMemo } from 'react'
import { Checkbox as RsuiteCheckbox } from 'rsuite'

import type { CheckboxProps as RsuiteCheckboxProps } from 'rsuite'
import type { ValueType } from 'rsuite/esm/Checkbox'
import type { Promisable } from 'type-fest'

export type CheckboxProps = Omit<RsuiteCheckboxProps, 'checked' | 'onChange'> & {
label: string
name: string
onChange?: (isCheched: boolean) => Promisable<void>
}
export function Checkbox({ label, onChange, ...originalProps }: CheckboxProps) {
const key = useMemo(
() => `${originalProps.name}-${String(originalProps.defaultChecked)}`,
[originalProps.defaultChecked, originalProps.name]
)

const handleChange = useCallback(
(_: ValueType | undefined, isChecked: boolean) => {
if (!onChange) {
return
}

onChange(isChecked)
},
[onChange]
)

return (
<RsuiteCheckbox key={key} onChange={handleChange} {...originalProps}>
{label}
</RsuiteCheckbox>
)
}
4 changes: 2 additions & 2 deletions src/fields/DatePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type DatePickerProps = {
*
* @param nextUtcDateRange - A utcized date to be used as is to interact with the API.
*/
onChange: (nextUtcDate: Date) => Promisable<void>
onChange?: (nextUtcDate: Date) => Promisable<void>
withTime?: boolean
}
export function DatePicker({
Expand Down Expand Up @@ -66,7 +66,7 @@ export function DatePicker({
)

const submit = useCallback(() => {
if (!selectedDateRef.current) {
if (!onChange || !selectedDateRef.current) {
return
}

Expand Down
4 changes: 2 additions & 2 deletions src/fields/DateRangePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export type DateRangePickerProps = {
*
* @param nextUtcDateRange - A utcized date to be used as is to interact with the API.
*/
onChange: (nextUtcDateRange: DateRange) => Promisable<void>
onChange?: (nextUtcDateRange: DateRange) => Promisable<void>
withTime?: boolean
}
export function DateRangePicker({
Expand Down Expand Up @@ -79,7 +79,7 @@ export function DateRangePicker({
)

const submit = useCallback(() => {
if (!selectedStartDateRef.current || !selectedEndDateRef.current) {
if (!onChange || !selectedStartDateRef.current || !selectedEndDateRef.current) {
return
}

Expand Down
41 changes: 22 additions & 19 deletions src/fields/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
import { useCallback } from 'react'
import { useCallback, useMemo } from 'react'
import { SelectPicker, TagPicker } from 'rsuite'
import styled from 'styled-components'

import type { Option } from '../types'
import type { TagPickerProps } from 'rsuite'
import type { SelectPickerProps as RsuiteSelectPickerProps, TagPickerProps } from 'rsuite'
import type { Promisable } from 'type-fest'

export type SelectProps = Omit<TagPickerProps, 'as' | 'data' | 'onChange' | 'placeholder'> & {
isMulti?: boolean
label: string
type SelectCommonProps = {
name: string
onChange: (valueOrValues: string | string[] | undefined) => Promisable<void>
options: Option[]
}
export type MultiSelectProps = Omit<TagPickerProps, 'as' | 'data' | 'onChange' | 'value'> &
SelectCommonProps & {
isMulti: true
onChange?: (values: string[] | undefined) => Promisable<void>
}
export type SingleSelectProps = Omit<RsuiteSelectPickerProps<any>, 'as' | 'data' | 'onChange' | 'value'> &
SelectCommonProps & {
isMulti?: false
onChange?: (value: string | undefined) => Promisable<void>
}
export type SelectProps = MultiSelectProps | SingleSelectProps
export function Select({
isMulti = false,
label,
name,
onChange,
options,
// eslint-disable-next-line @typescript-eslint/naming-convention
searchable = false,
...originalProps
}: SelectProps) {
const key = useMemo(
() => `${originalProps.name}-${JSON.stringify(originalProps.defaultValue)}`,
[originalProps.defaultValue, originalProps.name]
)

const handleChange = useCallback(
(valueOrValues: string | string[] | null) => {
if (!onChange) {
Expand All @@ -32,30 +43,22 @@ export function Select({
const normalizedValueOrValues =
!valueOrValues || (Array.isArray(valueOrValues) && !valueOrValues.length) ? undefined : valueOrValues

onChange(normalizedValueOrValues)
;(onChange as (valueOrValues: string | string[] | undefined) => Promisable<void>)(normalizedValueOrValues)
},
[onChange]
)

if (isMulti) {
return (
<StyledTagPicker
data={options}
onChange={handleChange}
placeholder={label}
searchable={searchable}
{...originalProps}
/>
)
return <StyledTagPicker data={options} onChange={handleChange} searchable={searchable} {...originalProps} />
}

return (
<StyledSelectPicker
key={key}
data={options}
// The `unknown` type from Rsuite library is wrong. It should be inferred from `data` prop type.
// `onChange: ((value: unknown, event: React.SyntheticEvent<Element, Event>) => void) | undefined`
onChange={handleChange as any}
placeholder={label}
searchable={searchable}
{...originalProps}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/formiks/FormikSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Select } from '../fields/Select'

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

export type FormikSelectProps = Omit<SelectProps, 'name' | 'onChange'> & {
export type FormikSelectProps = Omit<SelectProps, 'defaultValue' | 'onChange'> & {
name: string
}
export function FormikSelect({ name, ...originalProps }: FormikSelectProps) {
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export * as MUI from './constants'
export { THEME } from './theme'

export { Checkbox } from './fields/Checkbox'
export { DateRangePicker } from './fields/DateRangePicker'
export { DatePicker } from './fields/DatePicker'
export { Select } from './fields/Select'

// export { FormikCheckbox } from './formiks/FormikCheckbox'
export { FormikDatePicker } from './formiks/FormikDatePicker'
export { FormikDateRangePicker } from './formiks/FormikDateRangePicker'
export { FormikEffect } from './formiks/FormikEffect'
Expand All @@ -14,10 +16,12 @@ export { ThemeProvider } from './ThemeProvider'

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

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

// export type { FormikCheckboxProps } from './formiks/FormikCheckbox'
export type { FormikDatePickerProps } from './formiks/FormikDatePicker'
export type { FormikDateRangePickerProps } from './formiks/FormikDateRangePicker'
export type { FormikEffectProps } from './formiks/FormikEffect'
Expand Down
31 changes: 31 additions & 0 deletions stories/fields/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState } from 'react'

import { Checkbox } from '../../src'
import { Output } from '../_components/Output'

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

export default {
title: 'Fields/Checkbox',
component: Checkbox,

argTypes: {},

args: {
defaultChecked: false,
label: 'Check me',
name: 'myCheckbox'
} as CheckboxProps
}

export const _Checkbox = (props: CheckboxProps) => {
const [outputValue, setOutputValue] = useState<boolean | '∅'>('∅')

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

{outputValue !== '∅' && <Output value={outputValue} />}
</>
)
}
14 changes: 8 additions & 6 deletions stories/fields/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ import { Output } from '../_components/Output'

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

const args: DatePickerProps = {
isHistorical: false,
isLabelHidden: false,
label: 'A Date',
withTime: true
}

export default {
title: 'Fields/DatePicker',
component: DatePicker,

argTypes: {},

args: {
isHistorical: false,
isLabelHidden: false,
label: 'DatePicker Label',
withTime: true
}
args
}

export const _DatePicker = (props: DatePickerProps) => {
Expand Down
14 changes: 8 additions & 6 deletions stories/fields/DateRangePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import { Output } from '../_components/Output'
import type { DateRangePickerProps } from '../../src'
import type { DateRange } from '../../src/types'

const args: DateRangePickerProps = {
isHistorical: false,
isLabelHidden: false,
label: 'A Date Range',
withTime: true
}

export default {
title: 'Fields/DateRangePicker',
component: DateRangePicker,

argTypes: {},

args: {
isHistorical: false,
isLabelHidden: false,
label: 'DateRangePicker Label',
withTime: true
}
args
}

export const _DateRangePicker = (props: DateRangePickerProps) => {
Expand Down
21 changes: 13 additions & 8 deletions stories/fields/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@ import { Output } from '../_components/Output'

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

const args: SelectProps = {
defaultValue: 'FIRST_OPTION',
isMulti: false,
placeholder: 'Pick an option',
name: 'mySelect',
options: [
{ label: 'First Option', value: 'FIRST_OPTION' },
{ label: 'Second Option', value: 'SECOND_OPTION' },
{ label: 'Third Option', value: 'THIRD_OPTION' }
]
}

export default {
title: 'Fields/Select',
component: Select,

argTypes: {},

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

export const _Select = (props: SelectProps) => {
Expand Down
16 changes: 9 additions & 7 deletions stories/formiks/FormikDatePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ import { noop } from '../_utils/noop'

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

const args: FormikDatePickerProps = {
isHistorical: false,
isLabelHidden: false,
label: 'A Date',
name: 'myDate',
withTime: false
}

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

argTypes: {},

args: {
isHistorical: false,
isLabelHidden: false,
label: 'FormikDatePicker Label',
name: 'myDate',
withTime: false
}
args
}

export const _FormikDatePicker = (props: FormikDatePickerProps) => {
Expand Down
16 changes: 9 additions & 7 deletions stories/formiks/FormikDateRangePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ import { noop } from '../_utils/noop'
import type { FormikDateRangePickerProps } from '../../src'
import type { DateRange } from '../../src/types'

const args: FormikDateRangePickerProps = {
isHistorical: false,
isLabelHidden: false,
label: 'A Date Range',
name: 'myDateRange',
withTime: false
}

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

argTypes: {},

args: {
isHistorical: false,
isLabelHidden: false,
label: 'FormikDateRangePicker Label',
name: 'myDateRange',
withTime: false
}
args
}

export const _FormikDateRangePicker = (props: FormikDateRangePickerProps) => {
Expand Down
Loading

0 comments on commit 37a1746

Please sign in to comment.