diff --git a/src/components/text-field-v2/TextFieldV2.helper.ts b/src/components/text-field-v2/TextFieldV2.helper.ts index 191e488..ce334ae 100644 --- a/src/components/text-field-v2/TextFieldV2.helper.ts +++ b/src/components/text-field-v2/TextFieldV2.helper.ts @@ -11,30 +11,30 @@ import type { UseOutlineBaseProps } from "~/components/use-outline"; export const getLabelProps = ({ variant, isFocused, - value, + isLabelFloated, }: { variant: TextFieldV2Variant; isFocused: boolean; - value: string | number | ReadonlyArray | undefined; + isLabelFloated: boolean; }): TypographyProps => { - const hasValue = isFocused || !!value; - const variants = { primary: { as: "label", position: { type: "absolute", left: "32px", - top: hasValue ? "6px" : "16px", + top: isLabelFloated ? "6px" : "16px", }, - opacity: hasValue ? 50 : undefined, + opacity: isLabelFloated ? 50 : undefined, color: "text-secondary-default", - fontSize: hasValue ? "body.mobile.xsmall" : "body.mobile.large", + fontSize: isLabelFloated ? "body.mobile.xsmall" : "body.mobile.large", md: { - fontSize: hasValue ? "body.desktop.xsmall" : "body.desktop.large", - lineHeight: hasValue ? "body.desktop.xsmall" : "body.desktop.large", + fontSize: isLabelFloated ? "body.desktop.xsmall" : "body.desktop.large", + lineHeight: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.large", }, - lineHeight: hasValue ? "body.mobile.small" : "body.mobile.large", + lineHeight: isLabelFloated ? "body.mobile.small" : "body.mobile.large", }, secondary: { @@ -42,16 +42,20 @@ export const getLabelProps = ({ position: { type: "absolute", left: "12px", - top: hasValue ? "7px" : "15px", + top: isLabelFloated ? "7px" : "15px", }, - opacity: hasValue ? 50 : undefined, + opacity: isLabelFloated ? 50 : undefined, color: isFocused ? "text-selection" : "text-secondary-default", - fontSize: hasValue ? "body.mobile.xsmall" : "body.mobile.medium", + fontSize: isLabelFloated ? "body.mobile.xsmall" : "body.mobile.medium", md: { - fontSize: hasValue ? "body.desktop.xsmall" : "body.desktop.medium", - lineHeight: hasValue ? "body.desktop.xsmall" : "body.desktop.medium", + fontSize: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.medium", + lineHeight: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.medium", }, - lineHeight: hasValue ? "body.mobile.small" : "body.mobile.medium", + lineHeight: isLabelFloated ? "body.mobile.small" : "body.mobile.medium", }, } as const; diff --git a/src/components/text-field-v2/TextFieldV2.stories.tsx b/src/components/text-field-v2/TextFieldV2.stories.tsx index 0769a71..6d59085 100644 --- a/src/components/text-field-v2/TextFieldV2.stories.tsx +++ b/src/components/text-field-v2/TextFieldV2.stories.tsx @@ -330,6 +330,13 @@ export const Mask: Story = { customInput={} /> + } + /> + | number; + alwaysShowMask?: boolean; }) => ReactNode); icon?: (args: { isDisabled?: boolean }) => ReactNode; errorMessage?: string | ReactNode; className?: string; customInput?: ReactElement; variant?: TextFieldV2Variant; + alwaysShowMask?: boolean; } type Props = TextFieldV2Props & Partial; @@ -53,6 +55,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { onChange: _onChange, spellCheck: _spellCheck, variant = "primary", + alwaysShowMask = false, ...rest } = props; const [isFocused, setIsFocused] = useState(false); @@ -69,6 +72,8 @@ export const TextFieldV2 = forwardRef((props, ref) => { ref ?? inputRef, ); + const isLabelFloated = isFocused || !!inputProps.value || alwaysShowMask; + const spacing = useSpacing({ m: { p: rest.p, @@ -145,7 +150,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { const Label = label && typeof label !== "string" ? ( - label({ isFocused, value: inputProps.value }) + label({ isFocused, value: inputProps.value, alwaysShowMask }) ) : ( <> ); @@ -162,7 +167,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { {...getLabelProps({ variant, isFocused, - value: inputProps.value, + isLabelFloated, })} > {label} @@ -176,6 +181,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { ...rest, ...inputProps, ref, + alwaysShowMask, onClick: inputProps.onClick, className: `${border.className} ${background.className} ${spacing.className} ${dimension.className} ${typography.classNames} ${outline.className} ${className}`, style: { diff --git a/src/components/text-field/TextField.stories.tsx b/src/components/text-field/TextField.stories.tsx index d7edeaf..2e51243 100644 --- a/src/components/text-field/TextField.stories.tsx +++ b/src/components/text-field/TextField.stories.tsx @@ -123,12 +123,20 @@ export const Error: Story = { export const Mask: Story = { args: { - label: "Test mask", mask: "+\\91 9999999999", maskChar: "_", m: { mb: 10 }, }, render: (args) => { - return ; + return ( + <> + + + + ); }, }; diff --git a/src/components/text-field/TextField.tsx b/src/components/text-field/TextField.tsx index 87fdc12..99be541 100644 --- a/src/components/text-field/TextField.tsx +++ b/src/components/text-field/TextField.tsx @@ -17,6 +17,7 @@ export interface TextFieldProps extends AriaTextFieldOptions<"input"> { */ mask?: string; maskChar?: string; + alwaysShowMask?: boolean; } type Props = TextFieldProps & Partial; /** @@ -32,6 +33,7 @@ export const TextField = forwardRef((props, ref) => { className, mask, maskChar, + alwaysShowMask = false, ...indentationProps } = props; const [isFocused, setIsFocused] = useState(false); @@ -44,6 +46,8 @@ export const TextField = forwardRef((props, ref) => { ref ?? inputRef, ); + const isLabelFloated = isFocused || !!inputProps.value || alwaysShowMask; + const InputComponent = mask ? InputMask : "input"; // border @@ -96,27 +100,17 @@ export const TextField = forwardRef((props, ref) => { > {label} @@ -127,6 +121,7 @@ export const TextField = forwardRef((props, ref) => { // @ts-ignore mask={mask} maskChar={maskChar} + alwaysShowMask={alwaysShowMask} ref={ref} inputRef={ref} name={name}