Commit 1dfdcef2 authored by tom's avatar tom

fix floating labels

parent 5969ae25
import { formAnatomy as parts } from '@chakra-ui/anatomy';
import {
createMultiStyleConfigHelpers,
} from '@chakra-ui/styled-system';
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { getColor, mode } from '@chakra-ui/theme-tools';
import type { Dict } from '@chakra-ui/utils';
import getDefaultFormColors from '../utils/getDefaultFormColors';
import FormLabel from './FormLabel';
import Input from './Input';
import Textarea from './Textarea';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
const getActiveLabelStyles = (theme: Dict, fc: string, bc: string, size: 'md' | 'lg') => {
const baseStyles = {
backgroundColor: bc,
color: getColor(theme, fc),
fontSize: 'xs',
lineHeight: '16px',
borderTopRightRadius: 'none',
};
switch (size) {
case 'md': {
return {
...baseStyles,
padding: '10px 16px 2px 16px',
};
}
case 'lg': {
return {
...baseStyles,
padding: '16px 24px 2px 24px',
};
}
}
};
const getDefaultLabelStyles = (size: 'md' | 'lg') => {
switch (size) {
case 'md': {
return {
fontSize: 'md',
lineHeight: '20px',
padding: '18px 16px',
right: '18px',
};
}
case 'lg': {
return {
fontSize: 'md',
lineHeight: '24px',
padding: '28px 24px',
right: '26px',
};
}
}
};
const getPaddingX = (size: 'md' | 'lg') => {
switch (size) {
case 'md': {
return '16px';
}
function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunctionProps) {
const { theme } = props;
const { focusColor: fc, errorColor: ec } = getDefaultFormColors(props);
case 'lg': {
return '24px';
const activeLabelStyles = {
...FormLabel.variants?.floating?.(props)._focusWithin,
...FormLabel.sizes?.[size](props)._focusWithin,
} || {};
const activeInputStyles = (() => {
switch (size) {
case 'md': {
return {
paddingTop: '26px',
paddingBottom: '10px',
};
}
case 'lg': {
return {
paddingTop: '38px',
paddingBottom: '18px',
};
}
}
}
};
})();
const getActiveInputStyles = (size: 'md' | 'lg') => {
switch (size) {
case 'md': {
return {
paddingTop: '26px',
paddingBottom: '10px',
};
}
const inputPx = (() => {
switch (size) {
case 'md': {
return '16px';
}
case 'lg': {
return {
paddingTop: '38px',
paddingBottom: '18px',
};
case 'lg': {
return '24px';
}
}
}
};
const variantFloating = definePartsStyle((props) => {
const { theme, backgroundColor, size = 'md' } = props;
const { focusColor: fc, errorColor: ec } = getDefaultFormColors(props);
const bc = backgroundColor || mode('white', 'black')(props);
const px = getPaddingX(size);
const activeInputStyles = getActiveInputStyles(size);
const activeLabelStyles = getActiveLabelStyles(theme, fc, bc, size);
})();
return {
container: {
// active styles
_focusWithin: {
label: {
...activeLabelStyles,
},
'input, textarea': {
...activeInputStyles,
},
'label .chakra-form__required-indicator': {
color: getColor(theme, fc),
},
},
// label's styles
label: {
...getDefaultLabelStyles(size),
left: '2px',
top: '2px',
zIndex: 2,
position: 'absolute',
borderRadius: 'base',
boxSizing: 'border-box',
color: 'gray.500',
backgroundColor: 'transparent',
pointerEvents: 'none',
margin: 0,
transformOrigin: 'top left',
transitionProperty: 'font-size, line-height, padding, top, background-color',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': {
...activeLabelStyles,
label: activeLabelStyles,
'input, textarea': activeInputStyles,
},
// label styles
label: FormLabel.sizes?.[size](props) || {},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': activeLabelStyles,
'input[aria-invalid=true] + label, textarea[aria-invalid=true] + label': {
color: getColor(theme, ec),
},
// input's styles
// input styles
input: Input.sizes?.[size].field,
textarea: Textarea.sizes?.[size],
'input, textarea': {
padding: px,
padding: inputPx,
},
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': activeInputStyles,
'input[disabled] + label, textarea[disabled] + label': {
backgroundColor: 'transparent',
},
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': {
...activeInputStyles,
},
// indicator's styles
// indicator styles
'input:not(:placeholder-shown) + label .chakra-form__required-indicator, textarea:not(:placeholder-shown) + label .chakra-form__required-indicator': {
color: getColor(theme, fc),
},
......@@ -153,6 +84,11 @@ const variantFloating = definePartsStyle((props) => {
color: getColor(theme, ec),
},
},
};
}
const baseStyle = definePartsStyle((props) => {
return {
requiredIndicator: {
marginStart: 0,
color: mode('gray.500', 'whiteAlpha.400')(props),
......@@ -160,12 +96,42 @@ const variantFloating = definePartsStyle((props) => {
};
});
const variantFloating = definePartsStyle((props) => {
return {
container: {
label: FormLabel.variants?.floating(props) || {},
},
};
});
const sizes = {
lg: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('lg', props);
}
return {};
}),
md: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('md', props);
}
return {};
}),
};
const variants = {
floating: variantFloating,
};
const Form = defineMultiStyleConfig({
baseStyle,
variants,
sizes,
defaultProps: {
size: 'md',
},
});
export default Form;
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { getColor, mode } from '@chakra-ui/theme-tools';
import getDefaultFormColors from '../utils/getDefaultFormColors';
const baseStyle = defineStyle({
fontSize: 'md',
marginEnd: '3',
mb: '2',
fontWeight: 'medium',
transitionProperty: 'common',
transitionDuration: 'normal',
opacity: 1,
_disabled: {
opacity: 0.4,
},
});
const variantFloating = defineStyle((props) => {
const { theme, backgroundColor } = props;
const { focusColor: fc } = getDefaultFormColors(props);
const bc = backgroundColor || mode('white', 'black')(props);
return {
left: '2px',
top: '2px',
zIndex: 2,
position: 'absolute',
borderRadius: 'base',
boxSizing: 'border-box',
color: 'gray.500',
backgroundColor: 'transparent',
pointerEvents: 'none',
margin: 0,
transformOrigin: 'top left',
transitionProperty: 'font-size, line-height, padding, top, background-color',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
_focusWithin: {
backgroundColor: bc,
color: getColor(theme, fc),
fontSize: 'xs',
lineHeight: '16px',
borderTopRightRadius: 'none',
},
};
});
const variants = {
floating: variantFloating,
};
const sizes = {
lg: defineStyle((props) => {
if (props.variant === 'floating') {
return {
fontSize: 'md',
lineHeight: '24px',
padding: '28px 24px',
right: '26px',
_focusWithin: {
padding: '16px 24px 2px 24px',
},
};
}
return {};
}),
md: defineStyle((props) => {
if (props.variant === 'floating') {
return {
fontSize: 'md',
lineHeight: '20px',
padding: '18px 16px',
right: '18px',
_focusWithin: {
padding: '10px 16px 2px 16px',
},
};
}
return {};
}),
};
const FormLabel = defineStyleConfig({
variants,
baseStyle,
sizes,
});
export default FormLabel;
......@@ -4,6 +4,7 @@ import Button from './Button';
import Checkbox from './Checkbox';
import Drawer from './Drawer';
import Form from './Form';
import FormLabel from './FormLabel';
import Heading from './Heading';
import Input from './Input';
import Link from './Link';
......@@ -27,6 +28,7 @@ const components = {
Heading,
Input,
Form,
FormLabel,
Link,
Modal,
Popover,
......
......@@ -25,7 +25,6 @@ const MyProfile = () => {
<UserAvatar size={ 64 } data={ data }/>
<FormControl variant="floating" id="name" isRequired size="lg">
<Input
size="lg"
required
disabled
value={ data.name || '' }
......@@ -34,7 +33,6 @@ const MyProfile = () => {
</FormControl>
<FormControl variant="floating" id="nickname" isRequired size="lg">
<Input
size="lg"
required
disabled
value={ data.nickname || '' }
......@@ -43,7 +41,6 @@ const MyProfile = () => {
</FormControl>
<FormControl variant="floating" id="email" isRequired size="lg">
<Input
size="lg"
required
disabled
value={ data.email }
......
import type { InputProps } from '@chakra-ui/react';
import { IconButton, Icon, Flex } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form';
......@@ -17,7 +18,7 @@ interface Props {
error?: FieldError;
onAddFieldClick: (e: React.SyntheticEvent) => void;
onRemoveFieldClick: (index: number) => (e: React.SyntheticEvent) => void;
size?: string;
size?: InputProps['size'];
}
const MAX_INPUTS_NUM = 10;
......
import type { InputProps } from '@chakra-ui/react';
import { FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form';
......@@ -12,7 +13,7 @@ const TEXT_INPUT_MAX_LENGTH = 255;
interface Props {
control: Control<Inputs>;
error?: FieldError;
size?: string;
size?: InputProps['size'];
}
export default function PublicTagFormComment({ control, error, size }: Props) {
......@@ -22,7 +23,6 @@ export default function PublicTagFormComment({ control, error, size }: Props) {
<Textarea
{ ...field }
isInvalid={ Boolean(error) }
size={ size }
/>
<FormLabel>
{ getPlaceholderWithError('Specify the reason for adding tags and color preference(s)', error?.message) }
......
......@@ -16,7 +16,6 @@ import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types
import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile';
import { EMAIL_REGEXP } from 'lib/validations/email';
import FormSubmitAlert from 'ui/shared/FormSubmitAlert';
......@@ -57,9 +56,8 @@ const ADDRESS_INPUT_BUTTONS_WIDTH = 100;
const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
const queryClient = useQueryClient();
const isMobile = useIsMobile();
const fetch = useFetch();
const inputSize = isMobile ? 'md' : 'lg';
const inputSize = { base: 'md', lg: 'lg' };
const { control, handleSubmit, formState: { errors, isValid }, setError } = useForm<Inputs>({
defaultValues: {
......
import type { InputProps } from '@chakra-ui/react';
import { FormControl, FormLabel, Input } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, FieldError, FieldValues, Path, Control } from 'react-hook-form';
......@@ -14,7 +15,7 @@ interface Props<TInputs extends FieldValues> {
control: Control<TInputs, object>;
pattern?: RegExp;
error?: FieldError;
size?: string;
size?: InputProps['size'];
}
export default function PublicTagsFormInput<Inputs extends FieldValues>({
......@@ -31,7 +32,6 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
<FormControl variant="floating" id={ field.name } isRequired={ required } size={ size }>
<Input
{ ...field }
size={ size }
required={ required }
isInvalid={ Boolean(error) }
maxLength={ TEXT_INPUT_MAX_LENGTH }
......
import type { InputProps } from '@chakra-ui/react';
import {
Input,
FormControl,
......@@ -11,7 +12,7 @@ import { ADDRESS_LENGTH } from 'lib/validations/address';
type Props<TInputs extends FieldValues, TInputName extends Path<TInputs>> = {
field: ControllerRenderProps<TInputs, TInputName>;
size?: string;
size?: InputProps['size'];
placeholder?: string;
backgroundColor?: string;
error?: FieldError;
......@@ -31,7 +32,6 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa
{ ...field }
isInvalid={ Boolean(error) }
maxLength={ ADDRESS_LENGTH }
size={ size }
/>
<FormLabel>{ getPlaceholderWithError(placeholder, error?.message) }</FormLabel>
</FormControl>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment