import React, { useState, useEffect } from 'react';
import { useArgs } from '@storybook/client-api';
import {
SIZES,
DISPLAY,
COLORS,
ALIGN_ITEMS,
TEXT,
JUSTIFY_CONTENT,
} from '../../../helpers/constants/design-system';
import Box from '../../ui/box/box';
import {
ButtonLink,
ButtonPrimary,
ButtonSecondary,
HelpText,
Icon,
ICON_NAMES,
Label,
Text,
TEXT_FIELD_SIZES,
TEXT_FIELD_TYPES,
} from '..';
import { FormTextField } from './form-text-field';
import README from './README.mdx';
const marginSizeControlOptions = [
undefined,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
'auto',
];
export default {
title: 'Components/ComponentLibrary/FormTextField',
id: __filename,
component: FormTextField,
parameters: {
docs: {
page: README,
},
},
argTypes: {
value: {
control: 'text',
},
onChange: {
action: 'onChange',
},
labelProps: {
control: 'object',
},
textFieldProps: {
control: 'object',
},
helpTextProps: {
control: 'object',
},
showClearButton: {
control: 'boolean',
table: { category: 'text field props' },
},
clearButtonOnClick: {
action: 'clearButtonOnClick',
table: { category: 'text field props' },
},
clearButtonProps: {
control: 'object',
table: { category: 'text field props' },
},
autoComplete: {
control: 'boolean',
table: { category: 'text field base props' },
},
autoFocus: {
control: 'boolean',
table: { category: 'text field base props' },
},
className: {
control: 'text',
table: { category: 'text field base props' },
},
disabled: {
control: 'boolean',
table: { category: 'text field base props' },
},
error: {
control: 'boolean',
table: { category: 'text field base props' },
},
id: {
control: 'text',
table: { category: 'text field base props' },
},
inputProps: {
control: 'object',
table: { category: 'text field base props' },
},
leftAccessory: {
control: 'text',
table: { category: 'text field base props' },
},
maxLength: {
control: 'number',
table: { category: 'text field base props' },
},
name: {
control: 'text',
table: { category: 'text field base props' },
},
onBlur: {
action: 'onBlur',
table: { category: 'text field base props' },
},
onClick: {
action: 'onClick',
table: { category: 'text field base props' },
},
onFocus: {
action: 'onFocus',
table: { category: 'text field base props' },
},
onKeyDown: {
action: 'onKeyDown',
table: { category: 'text field base props' },
},
onKeyUp: {
action: 'onKeyUp',
table: { category: 'text field base props' },
},
placeholder: {
control: 'text',
table: { category: 'text field base props' },
},
readOnly: {
control: 'boolean',
table: { category: 'text field base props' },
},
required: {
control: 'boolean',
table: { category: 'text field base props' },
},
rightAccessory: {
control: 'text',
table: { category: 'text field base props' },
},
size: {
control: 'select',
options: Object.values(TEXT_FIELD_SIZES),
table: { category: 'text field base props' },
},
type: {
control: 'select',
options: Object.values(TEXT_FIELD_TYPES),
table: { category: 'text field base props' },
},
truncate: {
control: 'boolean',
table: { category: 'text field base props' },
},
marginTop: {
options: marginSizeControlOptions,
control: 'select',
table: { category: 'box props' },
},
marginRight: {
options: marginSizeControlOptions,
control: 'select',
table: { category: 'box props' },
},
marginBottom: {
options: marginSizeControlOptions,
control: 'select',
table: { category: 'box props' },
},
marginLeft: {
options: marginSizeControlOptions,
control: 'select',
table: { category: 'box props' },
},
},
args: {
placeholder: 'Form text field',
label: 'Label',
id: 'form-text-field',
helpText: 'Help text',
},
};
const Template = (args) => {
const [{ value }, updateArgs] = useArgs();
const handleOnChange = (e) => {
updateArgs({ value: e.target.value });
};
const handleOnClear = () => {
updateArgs({ value: '' });
};
return (
);
};
export const DefaultStory = Template.bind({});
DefaultStory.storyName = 'Default';
export const Id = Template.bind({});
Id.args = {
id: 'accessible-input-id',
label: 'If label prop exists id prop is required for accessibility',
helpText: '',
};
export const LabelStory = Template.bind({});
LabelStory.storyName = 'Label'; // Need to use LabelStory to avoid conflict with Label component
LabelStory.args = {
id: 'input-with-label',
label: 'Label content appears here',
helpText: '',
};
export const HelpTextStory = (args) => {
const [{ value }, updateArgs] = useArgs();
const handleOnChange = (e) => {
updateArgs({ value: e.target.value });
};
const handleOnClear = () => {
updateArgs({ value: '' });
};
return (
<>
>
);
};
HelpTextStory.storyName = 'HelpText'; // Need to use HelpTextStory to avoid conflict with HelpTextStory component
HelpTextStory.args = {
label: '',
helpText: 'HelpText content appears here',
};
export const FormExample = () => {
const FORM_STATE = {
DEFAULT: 'default',
SUCCESS: 'success',
ERROR: 'error',
};
const VALIDATED_VALUES = {
NETWORK_NAME: 'network name',
NEW_RPC_URL: 'new rpc url',
CHAIN_ID: 'chain id',
};
const ERROR_MESSAGES = {
NETWORK_NAME: `Please enter "${VALIDATED_VALUES.NETWORK_NAME}"`,
NEW_RPC_URL: `Please enter "${VALIDATED_VALUES.NEW_RPC_URL}"`,
CHAIN_ID: `Please enter "${VALIDATED_VALUES.CHAIN_ID}"`,
};
const [submitted, setSubmitted] = useState(FORM_STATE.DEFAULT);
const [values, setValues] = useState({
networkName: '',
newRpcUrl: '',
chainId: '',
});
const [errors, setErrors] = useState({
networkName: '',
newRpcUrl: '',
chainId: '',
});
useEffect(() => {
setErrors({
networkName:
values.networkName &&
values.networkName.toLowerCase() !== VALIDATED_VALUES.NETWORK_NAME
? ERROR_MESSAGES.NETWORK_NAME
: '',
newRpcUrl:
values.newRpcUrl &&
values.newRpcUrl.toLowerCase() !== VALIDATED_VALUES.NEW_RPC_URL
? ERROR_MESSAGES.NEW_RPC_URL
: '',
chainId:
values.chainId &&
values.chainId.toLowerCase() !== VALIDATED_VALUES.CHAIN_ID
? ERROR_MESSAGES.CHAIN_ID
: '',
});
}, [
values,
ERROR_MESSAGES.CHAIN_ID,
ERROR_MESSAGES.NETWORK_NAME,
ERROR_MESSAGES.NEW_RPC_URL,
VALIDATED_VALUES.CHAIN_ID,
VALIDATED_VALUES.NETWORK_NAME,
VALIDATED_VALUES.NEW_RPC_URL,
]);
const handleClearForm = () => {
setValues({ networkName: '', newRpcUrl: '', chainId: '' });
setErrors({ networkName: '', newRpcUrl: '', chainId: '' });
setSubmitted(FORM_STATE.DEFAULT);
};
const handleOnChange = (e) => {
if (submitted === FORM_STATE.ERROR) {
setErrors({ networkName: '', newRpcUrl: '', chainId: '' });
setSubmitted(FORM_STATE.DEFAULT);
}
setValues({
...values,
[e.target.name]: e.target.value,
});
};
const handleOnSubmit = (e) => {
e.preventDefault();
if (errors.networkName || errors.newRpcUrl || errors.chainId) {
setSubmitted(FORM_STATE.ERROR);
} else {
setSubmitted(FORM_STATE.SUCCESS);
}
};
return (
<>
Submit
Clear form
{submitted === FORM_STATE.SUCCESS && (
Form successfully submitted!
)}
>
);
};
export const CustomLabelOrHelpText = () => (
<>
Examples of how one might customize the Label or HelpText within the
FormTextField component
{/* If you need a custom label
or require adding some form of customization
import the Label component separately */}
Use default
Max}
marginBottom={4}
type={TEXT_FIELD_TYPES.NUMBER}
/>
{/* If you need a custom help text
or require adding some form of customization
import the HelpText component separately and handle the error
logic yourself */}
Only enter a number that you're comfortable with the contract
accessing now or in the future. You can always increase the token limit
later.
Max
>
);