From 0c9efc46cf56b1837191b2a6de0f4057da210846 Mon Sep 17 00:00:00 2001 From: Anastasiya Haidanovich Date: Fri, 17 Apr 2026 12:51:33 +0300 Subject: [PATCH 1/4] feat: [EV-8779] add alwaysShowMask to InputMask --- src/components/text-field/TextField.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/text-field/TextField.tsx b/src/components/text-field/TextField.tsx index 87fdc12..5f291e6 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, ...indentationProps } = props; const [isFocused, setIsFocused] = useState(false); @@ -127,6 +129,7 @@ export const TextField = forwardRef((props, ref) => { // @ts-ignore mask={mask} maskChar={maskChar} + alwaysShowMask={alwaysShowMask} ref={ref} inputRef={ref} name={name} From 26723e2b6113f1966294bd627c8e1f21c98bd837 Mon Sep 17 00:00:00 2001 From: Anastasiya Haidanovich Date: Fri, 17 Apr 2026 14:42:45 +0300 Subject: [PATCH 2/4] feat: [EV-8779] add alwaysShowMask to TextFieldV2 & fix styles --- .../text-field-v2/TextFieldV2.helper.ts | 30 +++++++++---------- src/components/text-field-v2/TextFieldV2.tsx | 11 +++++-- src/components/text-field/TextField.tsx | 15 ++++++---- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/components/text-field-v2/TextFieldV2.helper.ts b/src/components/text-field-v2/TextFieldV2.helper.ts index 191e488..200cfcb 100644 --- a/src/components/text-field-v2/TextFieldV2.helper.ts +++ b/src/components/text-field-v2/TextFieldV2.helper.ts @@ -11,30 +11,28 @@ 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 +40,16 @@ 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.tsx b/src/components/text-field-v2/TextFieldV2.tsx index bef1369..55c543a 100644 --- a/src/components/text-field-v2/TextFieldV2.tsx +++ b/src/components/text-field-v2/TextFieldV2.tsx @@ -32,12 +32,14 @@ export interface TextFieldV2Props | ((args: { isFocused: boolean; value?: string | ReadonlyArray | 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,9 @@ export const TextFieldV2 = forwardRef((props, ref) => { ref ?? inputRef, ); + const isLabelFloated = + isFocused || !!inputProps.value || alwaysShowMask; + const spacing = useSpacing({ m: { p: rest.p, @@ -145,7 +151,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 +168,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { {...getLabelProps({ variant, isFocused, - value: inputProps.value, + isLabelFloated, })} > {label} @@ -176,6 +182,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { ...rest, ...inputProps, ref, + alwaysShowMask: 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.tsx b/src/components/text-field/TextField.tsx index 5f291e6..d6f42e4 100644 --- a/src/components/text-field/TextField.tsx +++ b/src/components/text-field/TextField.tsx @@ -33,7 +33,7 @@ export const TextField = forwardRef((props, ref) => { className, mask, maskChar, - alwaysShowMask, + alwaysShowMask = false, ...indentationProps } = props; const [isFocused, setIsFocused] = useState(false); @@ -46,6 +46,9 @@ export const TextField = forwardRef((props, ref) => { ref ?? inputRef, ); + const isLabelFloated = + isFocused || !!inputProps.value || alwaysShowMask; + const InputComponent = mask ? InputMask : "input"; // border @@ -98,24 +101,24 @@ export const TextField = forwardRef((props, ref) => { > Date: Fri, 17 Apr 2026 14:45:31 +0300 Subject: [PATCH 3/4] feat: [EV-8779] lint fix --- src/components/text-field-v2/TextFieldV2.tsx | 5 ++--- src/components/text-field/TextField.tsx | 19 ++++--------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/components/text-field-v2/TextFieldV2.tsx b/src/components/text-field-v2/TextFieldV2.tsx index 55c543a..3765547 100644 --- a/src/components/text-field-v2/TextFieldV2.tsx +++ b/src/components/text-field-v2/TextFieldV2.tsx @@ -72,8 +72,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { ref ?? inputRef, ); - const isLabelFloated = - isFocused || !!inputProps.value || alwaysShowMask; + const isLabelFloated = isFocused || !!inputProps.value || alwaysShowMask; const spacing = useSpacing({ m: { @@ -182,7 +181,7 @@ export const TextFieldV2 = forwardRef((props, ref) => { ...rest, ...inputProps, ref, - alwaysShowMask: alwaysShowMask, + 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.tsx b/src/components/text-field/TextField.tsx index d6f42e4..99be541 100644 --- a/src/components/text-field/TextField.tsx +++ b/src/components/text-field/TextField.tsx @@ -46,8 +46,7 @@ export const TextField = forwardRef((props, ref) => { ref ?? inputRef, ); - const isLabelFloated = - isFocused || !!inputProps.value || alwaysShowMask; + const isLabelFloated = isFocused || !!inputProps.value || alwaysShowMask; const InputComponent = mask ? InputMask : "input"; @@ -108,20 +107,10 @@ export const TextField = forwardRef((props, ref) => { top: isLabelFloated ? "10px" : "50%", }} color={ - isLabelFloated - ? "text-secondary-hovered" - : "text-secondary-default" - } - fontSize={ - isLabelFloated - ? "body.mobile.small" - : "body.mobile.large" - } - lineHeight={ - isLabelFloated - ? "body.mobile.small" - : "body.mobile.large" + isLabelFloated ? "text-secondary-hovered" : "text-secondary-default" } + fontSize={isLabelFloated ? "body.mobile.small" : "body.mobile.large"} + lineHeight={isLabelFloated ? "body.mobile.small" : "body.mobile.large"} > {label} From f1b537823905c48416db9629c0d60c1be791d457 Mon Sep 17 00:00:00 2001 From: Anastasiya Haidanovich Date: Fri, 17 Apr 2026 15:11:16 +0300 Subject: [PATCH 4/4] feat: [EV-8779] add example of inputs with alwaysShowMask to storybook --- src/components/text-field-v2/TextFieldV2.helper.ts | 12 +++++++++--- src/components/text-field-v2/TextFieldV2.stories.tsx | 7 +++++++ src/components/text-field/TextField.stories.tsx | 12 ++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/components/text-field-v2/TextFieldV2.helper.ts b/src/components/text-field-v2/TextFieldV2.helper.ts index 200cfcb..ce334ae 100644 --- a/src/components/text-field-v2/TextFieldV2.helper.ts +++ b/src/components/text-field-v2/TextFieldV2.helper.ts @@ -30,7 +30,9 @@ export const getLabelProps = ({ fontSize: isLabelFloated ? "body.mobile.xsmall" : "body.mobile.large", md: { fontSize: isLabelFloated ? "body.desktop.xsmall" : "body.desktop.large", - lineHeight: isLabelFloated ? "body.desktop.xsmall" : "body.desktop.large", + lineHeight: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.large", }, lineHeight: isLabelFloated ? "body.mobile.small" : "body.mobile.large", }, @@ -46,8 +48,12 @@ export const getLabelProps = ({ color: isFocused ? "text-selection" : "text-secondary-default", fontSize: isLabelFloated ? "body.mobile.xsmall" : "body.mobile.medium", md: { - fontSize: isLabelFloated ? "body.desktop.xsmall" : "body.desktop.medium", - lineHeight: isLabelFloated ? "body.desktop.xsmall" : "body.desktop.medium", + fontSize: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.medium", + lineHeight: isLabelFloated + ? "body.desktop.xsmall" + : "body.desktop.medium", }, lineHeight: isLabelFloated ? "body.mobile.small" : "body.mobile.medium", }, 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={} /> + } + /> + { - return ; + return ( + <> + + + + ); }, };