diff --git a/packages/forms/docs/components/MultiInput.story.mdx b/packages/forms/docs/components/MultiInput.story.mdx new file mode 100644 index 00000000..21682e94 --- /dev/null +++ b/packages/forms/docs/components/MultiInput.story.mdx @@ -0,0 +1,19 @@ +import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks'; +import MultiInput from '../../src/components/MultiInput'; +import * as stories from '../stories/MultiInput.story.js'; + + + +# Overview + +`MultiInput` is an component that allows you to enter many input. + +### This is a basic example. + + + {stories.DefaultMultiInput()} + + +# Component props + + diff --git a/packages/forms/docs/components/MultiPhoneNumberInput.story.mdx b/packages/forms/docs/components/MultiPhoneNumberInput.story.mdx index 4cf4dc7b..a3293273 100644 --- a/packages/forms/docs/components/MultiPhoneNumberInput.story.mdx +++ b/packages/forms/docs/components/MultiPhoneNumberInput.story.mdx @@ -11,7 +11,7 @@ import * as stories from '../stories/MultiPhoneNumberInput.story.js'; ### This is a basic example. - {stories.BasicMultiPhoneNumberInput()} + {stories.DefaultMultiPhoneNumberInput()} # Component props diff --git a/packages/forms/docs/stories/MultiInput.story.js b/packages/forms/docs/stories/MultiInput.story.js new file mode 100644 index 00000000..89ba8602 --- /dev/null +++ b/packages/forms/docs/stories/MultiInput.story.js @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; +import { Application, Button, GoogleAddressLookup, PhoneInput } from 'react-rainbow-components'; +import ReactJson from 'react-json-view'; +import { Field, UniversalForm } from '@rainbow-modules/forms'; +import MultiInput from '../../src/components/MultiInput'; + +const GOOGLE_MAPS_APIKEY = process.env.STORYBOOK_GOOGLE_MAPS_APIKEY; + +export const DefaultMultiInput = () => { + const [value, setValue] = useState(); + return ( + + + + + ); +}; + +export const RemoveNoteInput = () => { + const [value, setValue] = useState(); + const onAdd = (index) => { + return [{ label: `Patient #${index + 1}` }]; + }; + return ( + + + + + ); +}; + +export const FormMultiAddressInput = () => { + const [value, setValue] = useState(); + const onAdd = (index) => { + if (index === 0) { + return [{ label: 'Patient primary address', required: true }, { label: 'Note' }]; + } + return [{ label: 'Patient family address' }, { label: 'Note' }]; + }; + return ( + + ( + + )} + /> + + + ); +}; + +export const FormMultiPhoneNumberInput = () => { + const validate = (value) => { + if (value) { + if (value.length < 2) { + return 'Too few phone numbers'; + } + const rowErrors = {}; + value.forEach(([inputValue, note], index) => { + const err = {}; + if (inputValue && inputValue.isoCode !== 'us') { + err.value = 'Only US numbers are accepted'; + } + if (!note || note.length < 3) { + err.note = 'Note is too short'; + } + if (Object.keys(err).length) { + rowErrors[index] = err; + } + }); + if (Object.keys(rowErrors).length) { + return rowErrors; + } + } + return ''; + }; + + const onSubmit = (values) => { + // eslint-disable-next-line no-alert + alert(JSON.stringify(values, null, 2)); + }; + + return ( + + + } + validate={validate} + /> + + + + ); +} + +MultiInput.propTypes = { + label: PropTypes.string.isRequired, + value: PropTypes.any, + onAdd: PropTypes.func, + max: PropTypes.number, + onChange: PropTypes.func, +}; + +MultiInput.defaultProps = { + value: undefined, + onAdd: undefined, + component: undefined, + max: 5, + onChange: () => {}, + onFocus: () => {}, + onBlur: () => {}, + error: undefined, +}; + +export default MultiInput; diff --git a/packages/forms/src/components/MultiInput/styled.ts b/packages/forms/src/components/MultiInput/styled.ts new file mode 100644 index 00000000..2e54aedf --- /dev/null +++ b/packages/forms/src/components/MultiInput/styled.ts @@ -0,0 +1,42 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { Input, ButtonIcon } from 'react-rainbow-components'; +import styled from 'styled-components'; + +export const Container = styled.div``; + +export const Label = styled.label` + font-size: 18px; + color: ${(props) => props.theme.rainbow.palette.text.main}; + margin-bottom: 4px; +`; + +export const Fieldset = styled.fieldset` + display: flex; + flex-direction: row; + width: 100%; + justify-content: space-between; + align-items: flex-start; + gap: 12px; + margin-bottom: 16px; +`; + +export const StyledInput = styled(Input)` + min-width: 65%; + flex: 1 1 auto; +`; + +export const StyledNoteInput = styled(Input)` + flex-grow: 1; +`; + +export const ErrorText = styled.div` + font-size: 0.875rem; + margin-top: 0.5rem; + align-self: start; + color: ${(props) => props.theme.rainbow.palette.error.main}; +`; + +export const StyledButtonIcon = styled(ButtonIcon)` + flex-shrink: 0; + margin-top: 24px; +`; diff --git a/packages/forms/src/components/MultiInput/types.ts b/packages/forms/src/components/MultiInput/types.ts new file mode 100644 index 00000000..8956487b --- /dev/null +++ b/packages/forms/src/components/MultiInput/types.ts @@ -0,0 +1,12 @@ +export interface InputConfig { + label: string; + placeholder?: string; + required?: boolean; + disabled?: boolean; + readOnly?: boolean; +} + +export interface RowError { + value?: string; + note?: string; +}