diff --git a/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar-large.tsx b/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar-large.tsx index f4329bff6..b8682c524 100644 --- a/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar-large.tsx +++ b/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar-large.tsx @@ -15,6 +15,7 @@ const NavigationBarTest = (): JSX.Element => ( title, to: `/${title}`, }))} + logo={LOGO} right={ {}} aria-label="shopping cart with 2 items"> diff --git a/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar.tsx b/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar.tsx index 41cc4ddd8..0bbb17cb0 100644 --- a/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar.tsx +++ b/src/__acceptance_tests__/__ssr_pages__/main-navigation-bar.tsx @@ -14,6 +14,7 @@ const NavigationBarTest = (): JSX.Element => ( title, to: `/${title}`, }))} + logo={LOGO} right={ {}} aria-label="shopping cart with 2 items"> diff --git a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-android-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-android-1-snap.png index c54cdc969..dbb8d4ee1 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-android-1-snap.png and b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-android-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-ios-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-ios-1-snap.png index 6852de7de..bf3195471 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-ios-1-snap.png and b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-danger-spinner-mobile-ios-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-android-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-android-1-snap.png index 923bcff39..33d4ff099 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-android-1-snap.png and b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-android-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-ios-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-ios-1-snap.png index 4b41d242e..3bab0e659 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-ios-1-snap.png and b/src/__screenshot_tests__/__image_snapshots__/button-screenshot-test-tsx-buttons-link-button-spinner-mobile-ios-1-snap.png differ diff --git a/src/button-layout.css.ts b/src/button-layout.css.ts index bb3d2d9be..3c2aff0e7 100644 --- a/src/button-layout.css.ts +++ b/src/button-layout.css.ts @@ -1,7 +1,7 @@ import {style, globalStyle, styleVariants} from '@vanilla-extract/css'; import {sprinkles} from './sprinkles.css'; import * as mq from './media-queries.css'; -import {PADDING_X_LINK} from './button.css'; +import {buttonPaddingX, borderSize} from './button.css'; const buttonLayoutSpacing = 16; @@ -78,8 +78,12 @@ globalStyle(`${alignVariant['full-width']} > *:not(${linkBase})`, { }, }); -const bleedLeft = {marginLeft: buttonLayoutSpacing / 2 - PADDING_X_LINK}; -const bleedRight = {marginRight: buttonLayoutSpacing / 2 - PADDING_X_LINK}; +const bleedLeft = { + marginLeft: `calc(${buttonLayoutSpacing}px / 2 - (${buttonPaddingX.small} + ${borderSize}))`, +}; +const bleedRight = { + marginRight: `calc(${buttonLayoutSpacing}px / 2 - (${buttonPaddingX.small} + ${borderSize}))`, +}; export const link = style([ linkBase, diff --git a/src/button.css.ts b/src/button.css.ts index 270e4cd6c..6800c99b5 100644 --- a/src/button.css.ts +++ b/src/button.css.ts @@ -1,27 +1,50 @@ -import {style, globalStyle, styleVariants} from '@vanilla-extract/css'; +import {style, globalStyle, styleVariants, createVar} from '@vanilla-extract/css'; import {sprinkles} from './sprinkles.css'; import {vars} from './skins/skin-contract.css'; import * as mq from './media-queries.css'; +import {pxToRem} from './utils/css'; import type {ComplexStyleRule} from '@vanilla-extract/css'; +const minWidth = createVar(); +export const buttonVars = {minWidth}; + const colorTransitionTiming = '0.1s ease-in-out'; const contentTransitionTiming = '0.3s cubic-bezier(0.77, 0, 0.175, 1)'; -export const BUTTON_MIN_WIDTH = 104; -const BORDER_PX = 1.5; -export const ICON_MARGIN_PX = 8; -export const X_PADDING_PX = 16 - BORDER_PX; -const Y_PADDING_PX = 12 - BORDER_PX; -export const X_SMALL_PADDING_PX = 12 - BORDER_PX; -const Y_SMALL_PADDING_PX = 6 - BORDER_PX; -export const ICON_SIZE = 24; -export const SMALL_ICON_SIZE = 20; -export const SPINNER_SIZE = 20; -export const SMALL_SPINNER_SIZE = 16; -export const PADDING_Y_LINK = 6; -export const PADDING_X_LINK = 12; -export const CHEVRON_MARGIN_LEFT_LINK = 2; +export const buttonMinWidth = { + default: '104px', + small: '80px', +}; + +export const linkMinWidth = { + default: '40px', + small: '40px', +}; + +export const borderSize = '1.5px'; +export const iconMargin = '8px'; +export const chevronMarginLeft = '2px'; + +export const iconSize = { + default: pxToRem(24), + small: pxToRem(20), +}; + +export const spinnerSize = { + default: pxToRem(20), + small: pxToRem(16), +}; + +export const buttonPaddingX = { + default: `calc(16px - ${borderSize})`, + small: `calc(12px - ${borderSize})`, +}; + +export const buttonPaddingY = { + default: `calc(12px - ${borderSize})`, + small: `calc(6px - ${borderSize})`, +}; const disabledStyle = {opacity: 0.5}; @@ -37,8 +60,8 @@ const button = style([ padding: 0, }), { - border: `${BORDER_PX}px solid transparent`, - minWidth: BUTTON_MIN_WIDTH, + minWidth: buttonVars.minWidth, + border: `${borderSize} solid transparent`, transition: `background-color ${colorTransitionTiming}, color ${colorTransitionTiming}, border-color ${colorTransitionTiming}`, selectors: { @@ -52,6 +75,15 @@ const button = style([ }, ]); +const link = style([ + button, + { + fontWeight: 500, + }, +]); + +export const small = style({}); + export const loadingFiller = style([ sprinkles({ display: 'block', @@ -63,10 +95,6 @@ export const loadingFiller = style([ }, ]); -export const small = style({ - minWidth: 80, -}); - export const loadingContent = style([ sprinkles({ display: 'inline-flex', @@ -77,16 +105,16 @@ export const loadingContent = style([ alignItems: 'center', }), { - left: X_PADDING_PX, - right: X_PADDING_PX, + left: buttonPaddingX.default, + right: buttonPaddingX.default, opacity: 0, transform: 'translateY(2rem)', transition: `opacity ${contentTransitionTiming}, transform ${contentTransitionTiming}`, selectors: { [`${small} &`]: { - left: X_SMALL_PADDING_PX, - right: X_SMALL_PADDING_PX, + left: buttonPaddingX.small, + right: buttonPaddingX.small, }, [`${isLoading} &`]: { transform: 'translateY(0)', @@ -103,13 +131,13 @@ export const textContent = style([ justifyContent: 'center', }), { - padding: `${Y_PADDING_PX}px ${X_PADDING_PX}px`, // height 48 + padding: `${buttonPaddingY.default} ${buttonPaddingX.default}`, // height 48 opacity: 1, transition: `opacity ${contentTransitionTiming}, transform ${contentTransitionTiming}`, selectors: { [`${small} &`]: { - padding: `${Y_SMALL_PADDING_PX}px ${X_SMALL_PADDING_PX}px`, // height 32 + padding: `${buttonPaddingY.small} ${buttonPaddingX.small}`, // height 32 }, [`${isLoading} &`]: { transform: 'translateY(-2rem)', @@ -282,58 +310,6 @@ const danger: ComplexStyleRule = [ }, ]; -const link = style([ - sprinkles({ - display: 'inline-block', - width: 'auto', - position: 'relative', - borderRadius: vars.borderRadii.button, - paddingX: PADDING_X_LINK, - border: 'none', - overflow: 'hidden', - minWidth: 40, - }), - { - paddingTop: PADDING_Y_LINK, - paddingBottom: PADDING_Y_LINK, - fontWeight: 500, - transition: `background-color ${colorTransitionTiming}`, - - selectors: { - [`&[disabled]:not(${isLoading})`]: disabledStyle, - }, - - '@media': { - [mq.touchableOnly]: { - transition: 'none', - }, - }, - }, -]); - -export const textContentLink = style([ - sprinkles({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }), - { - opacity: 1, - transition: `opacity ${contentTransitionTiming}, transform ${contentTransitionTiming}`, - - selectors: { - [`${isLoading} &`]: { - transform: 'translateY(-2rem)', - opacity: 0, - }, - }, - }, -]); - -globalStyle(`${textContentLink} svg`, { - display: 'block', -}); - export const defaultLink: ComplexStyleRule = [ link, sprinkles({ @@ -478,22 +454,16 @@ export const buttonVariants = styleVariants({ primary: lightPrimary, secondary: lightSecondary, danger, + link: defaultLink, + linkDanger: dangerLink, + linkDangerDark: dangerLink, }); export const inverseButtonVariants = styleVariants({ primary: lightPrimaryInverse, secondary: lightSecondaryInverse, danger, -}); - -export const linkVariants = styleVariants({ - default: defaultLink, - danger: dangerLink, - dangerDark: dangerLink, -}); - -export const inverseLinkVariants = styleVariants({ - default: defaultLinkInverse, - danger: dangerLinkInverse, - dangerDark: dangerLinkInverseDark, + link: defaultLinkInverse, + linkDanger: dangerLinkInverse, + linkDangerDark: dangerLinkInverseDark, }); diff --git a/src/button.tsx b/src/button.tsx index 13b6ac3d7..b3676fcd4 100644 --- a/src/button.tsx +++ b/src/button.tsx @@ -5,7 +5,7 @@ import Spinner from './spinner'; import {BaseTouchable} from './touchable'; import {useIsInverseVariant} from './theme-variant-context'; import {useForm} from './form-context'; -import {pxToRem} from './utils/css'; +import {applyCssVars, pxToRem} from './utils/css'; import {Text, Text2, Text3} from './text'; import Box from './box'; import {getTextFromChildren} from './utils/common'; @@ -27,13 +27,15 @@ import type {Location} from 'history'; import type {ExclusifyUnion} from './utils/utility-types'; const renderButtonElement = ({ + small, content, defaultIconSize, - renderText, + TextContentRenderer, }: { + small?: boolean; content: React.ReactNode; - defaultIconSize: number; - renderText: (text: React.ReactNode) => React.ReactNode; + defaultIconSize: string; + TextContentRenderer: (element: React.ReactNode, small?: boolean) => JSX.Element; }): React.ReactNode => { const childrenArr = flattenChildren(content); const length = childrenArr.length; @@ -41,7 +43,9 @@ const renderButtonElement = ({ let accText: Array = []; const flushAccText = () => { resultChildrenArr.push( - {renderText(accText)} + + {TextContentRenderer(accText, small)} + ); accText = []; }; @@ -56,19 +60,19 @@ const renderButtonElement = ({ if (accText.length) { flushAccText(); } - const sizeInPx = element.props.size ?? defaultIconSize; + const sizeInPx = element.props.size !== undefined ? pxToRem(element.props.size) : defaultIconSize; resultChildrenArr.push(
{React.cloneElement(element as React.ReactElement, { - size: pxToRem(sizeInPx), + size: sizeInPx, })}
); @@ -114,8 +118,7 @@ const renderButtonContent = ({ loadingText, shouldRenderSpinner, setShouldRenderSpinner, - renderText, - textContentStyle, + TextContentRenderer, StartIcon, EndIcon, withChevron, @@ -126,42 +129,42 @@ const renderButtonContent = ({ loadingText?: string; shouldRenderSpinner: boolean; setShouldRenderSpinner: (value: boolean) => void; - renderText: (text: React.ReactNode) => React.ReactNode; - textContentStyle?: string; + TextContentRenderer: (element: React.ReactNode, small?: boolean) => JSX.Element; StartIcon?: React.FC; EndIcon?: React.FC; withChevron?: boolean; }): React.ReactNode => { - const defaultIconSize = small ? styles.SMALL_ICON_SIZE : styles.ICON_SIZE; - const spinnerSizeRem = pxToRem(small ? styles.SMALL_SPINNER_SIZE : styles.SPINNER_SIZE); + const defaultIconSize = small ? styles.iconSize.small : styles.iconSize.default; + const spinnerSizeRem = small ? styles.spinnerSize.small : styles.spinnerSize.default; return ( <> {/* text content */} -
+
{StartIcon && (
- +
)}
{renderButtonElement({ + small, content: children, defaultIconSize, - renderText, + TextContentRenderer, })} {withChevron && (
@@ -173,10 +176,10 @@ const renderButtonContent = ({ style={{ display: 'flex', alignItems: 'center', - marginLeft: styles.ICON_MARGIN_PX, + marginLeft: styles.iconMargin, }} > - +
)}
@@ -189,14 +192,17 @@ const renderButtonContent = ({ loadingText ? { paddingLeft: spinnerSizeRem, - paddingRight: - styles.ICON_MARGIN_PX + - 2 * (small ? styles.X_SMALL_PADDING_PX : styles.X_PADDING_PX), + paddingRight: `calc(${styles.iconMargin} + 2 * ${small ? styles.buttonPaddingX.small : styles.buttonPaddingX.default})`, } : undefined } > - {renderButtonElement({content: loadingText, defaultIconSize, renderText})} + {renderButtonElement({ + small, + content: loadingText, + defaultIconSize, + TextContentRenderer, + })}
{/* loading content */} @@ -227,7 +233,12 @@ const renderButtonContent = ({ )} {loadingText ? ( - {renderButtonElement({content: loadingText, defaultIconSize, renderText})} + {renderButtonElement({ + small, + content: loadingText, + defaultIconSize, + TextContentRenderer, + })} ) : null}
@@ -235,7 +246,7 @@ const renderButtonContent = ({ ); }; -type ButtonType = 'primary' | 'secondary' | 'danger'; +type ButtonType = 'primary' | 'secondary' | 'danger' | 'link' | 'linkDanger'; interface CommonProps { children: React.ReactNode; @@ -260,44 +271,59 @@ interface CommonProps { role?: string; } -export interface ToButtonProps extends CommonProps { +interface ToButtonProps extends CommonProps { to: string | Location; newTab?: boolean; fullPageOnWebView?: boolean; onNavigate?: () => void | Promise; } -export interface OnPressButtonProps extends CommonProps { +interface OnPressButtonProps extends CommonProps { onPress: (event: React.MouseEvent) => void | undefined | Promise; } -export interface HrefButtonProps extends CommonProps { +interface HrefButtonProps extends CommonProps { href: string; newTab?: boolean; loadOnTop?: boolean; - onNavigate?: () => void | Promise; } -export interface FakeButtonProps extends CommonProps { +interface FakeButtonProps extends CommonProps { fake: true; } -export interface SubmitButtonProps extends CommonProps { +interface SubmitButtonProps extends CommonProps { submit: true; } -export type ButtonProps = ExclusifyUnion< +type ButtonProps = ExclusifyUnion< FakeButtonProps | SubmitButtonProps | ToButtonProps | OnPressButtonProps | HrefButtonProps >; -const Button = React.forwardRef((props, ref) => { - const {textPresets} = useTheme(); +type ButtonLinkProps = ExclusifyUnion & { + bleedLeft?: boolean; + bleedRight?: boolean; + bleedY?: boolean; + small?: true; +}; + +const BaseButton = React.forwardRef< + TouchableElement, + ExclusifyUnion & { + buttonType: ButtonType; + withChevron?: boolean; + TextContentRenderer: (element: React.ReactNode, small?: boolean) => JSX.Element; + } +>((props, ref) => { const {eventFormat} = useTrackingConfig(); const {formStatus, formId} = useForm(); const isInverse = useIsInverseVariant(); const {loadingText} = props; const isSubmitButton = !!props.submit; const isFormSending = formStatus === 'sending'; + const {isDarkMode} = useTheme(); const [isOnPressPromiseResolving, setIsOnPressPromiseResolving] = React.useState(false); const showSpinner = props.showSpinner || (isFormSending && isSubmitButton) || isOnPressPromiseResolving; + const showChevron = + props.withChevron ?? (props.buttonType.startsWith('link') && (!!props.href || !!props.to)); // This state is needed to not render the spinner when hidden (because it causes high CPU usage // specially in iPhone). But we want the spinner to be visible during the show/hide animation. @@ -312,50 +338,82 @@ const Button = React.forwardRef { + let component_type; + let action; + + switch (props.buttonType) { + case 'link': + component_type = 'link'; + action = eventActions.linkTapped; + break; + case 'linkDanger': + component_type = 'danger_link'; + action = eventActions.linkTapped; + break; + default: + component_type = `${props.buttonType}_button`; + action = `${props.buttonType}_button_tapped`; + break; + } + if (eventFormat === 'google-analytics-4') { return { name: eventNames.userInteraction, - component_type: `${props.type}_button`, + component_type, component_copy: getTextFromChildren(props.children), }; } else { return { category: eventCategories.userInteraction, - action: `${props.type}_button_tapped`, + action, label: getTextFromChildren(props.children), }; } }; - const renderText = (element: React.ReactNode) => - props.small ? ( - - {element} - - ) : ( - - {element} - - ); + const minWidthProps = props.buttonType.startsWith('link') ? styles.linkMinWidth : styles.buttonMinWidth; + const finalType = + props.buttonType === 'linkDanger' && isDarkMode && isInverse ? 'linkDangerDark' : props.buttonType; const commonProps = { ref, className: classnames( - isInverse ? styles.inverseButtonVariants[props.type] : styles.buttonVariants[props.type], + isInverse ? styles.inverseButtonVariants[finalType] : styles.buttonVariants[finalType], props.className, { [styles.small]: props.small, [styles.isLoading]: showSpinner, } ), - style: {cursor: props.fake ? 'pointer' : undefined, ...props.style}, + style: { + ...applyCssVars({ + [styles.buttonVars.minWidth]: props.small ? minWidthProps.small : minWidthProps.default, + }), + + /** + * Setting bleed classes with style to override the margin:0 set by the Touchable component. + * If we set it using className, it may not work depending on the order in which the styles are applied. + */ + ...(props.bleedLeft + ? { + marginLeft: `calc(-1 * (${styles.borderSize} + ${props.small ? styles.buttonPaddingX.small : styles.buttonPaddingX.default}))`, + } + : undefined), + ...(props.bleedRight + ? { + marginRight: `calc(-1 * (${styles.borderSize} + ${props.small ? styles.buttonPaddingX.small : styles.buttonPaddingX.default}))`, + } + : undefined), + ...(props.bleedY + ? { + marginTop: `calc(-1 * (${styles.borderSize} + ${props.small ? styles.buttonPaddingY.small : styles.buttonPaddingY.default}))`, + marginBottom: `calc(-1 * (${styles.borderSize} + ${props.small ? styles.buttonPaddingY.small : styles.buttonPaddingY.default}))`, + } + : undefined), + + cursor: props.fake ? 'pointer' : undefined, + ...props.style, + }, trackingEvent: props.trackingEvent ?? (props.trackEvent ? createDefaultTrackingEvent() : undefined), dataAttributes: props.dataAttributes, 'aria-label': props['aria-label'], @@ -370,10 +428,10 @@ const Button = React.forwardRef; - trackEvent?: boolean; - /** "data-" prefix is automatically added. For example, use "testid" instead of "data-testid" */ - dataAttributes?: DataAttributes; - showSpinner?: boolean; - loadingText?: string; - StartIcon?: React.FC; - EndIcon?: React.FC; - bleedLeft?: boolean; - bleedRight?: boolean; - bleedY?: boolean; - 'aria-label'?: string; - 'aria-controls'?: string; - 'aria-expanded'?: 'true' | 'false' | boolean; - 'aria-haspopup'?: 'true' | 'false' | 'menu' | 'dialog' | boolean; - /** IMPORTANT: try to avoid using role="link" with onPress and first consider other alternatives like to/href + onNavigate */ - role?: string; -} - -interface ButtonLinkOnPressProps extends ButtonLinkCommonProps { - onPress: (event: React.MouseEvent) => void | undefined | Promise; - to?: undefined; - href?: undefined; - onNavigate?: undefined; -} - -interface ButtonLinkHrefProps extends ButtonLinkCommonProps { - href: string; - newTab?: boolean; - onPress?: undefined; - to?: undefined; - onNavigate?: () => void | Promise; -} - -interface ButtonLinkToProps extends ButtonLinkCommonProps { - to: string; - newTab?: boolean; - fullPageOnWebView?: boolean; - onPress?: undefined; - href?: undefined; - onNavigate?: () => void | Promise; -} - -export type ButtonLinkProps = ButtonLinkOnPressProps | ButtonLinkHrefProps | ButtonLinkToProps; - -const BaseButtonLink = React.forwardRef< - TouchableElement, - ButtonLinkProps & {type: ButtonLinkType; withChevron?: boolean} ->(({type, ...props}, ref) => { - const {formStatus} = useForm(); - const isInverse = useIsInverseVariant(); +const ButtonTextRenderer = (element: React.ReactNode, small?: boolean): JSX.Element => { const {textPresets} = useTheme(); - const {eventFormat} = useTrackingConfig(); - const {isDarkMode} = useTheme(); - - const {loadingText} = props; - const isFormSending = formStatus === 'sending'; - const [isOnPressPromiseResolving, setIsOnPressPromiseResolving] = React.useState(false); - - const showSpinner = props.showSpinner || isOnPressPromiseResolving; - const showChevron = props.withChevron ?? (!!props.href || !!props.to); - - // This state is needed to not render the spinner when hidden (because it causes high CPU usage - // specially in iPhone). But we want the spinner to be visible during the show/hide animation. - // * When showSpinner prop is true, state is changed immediately. - // * When the transition ends this state is updated again if needed - const [shouldRenderSpinner, setShouldRenderSpinner] = React.useState(!!showSpinner); - - React.useEffect(() => { - if (showSpinner && !shouldRenderSpinner) { - setShouldRenderSpinner(true); - } - }, [showSpinner, shouldRenderSpinner, formStatus]); - - const createDefaultTrackingEvent = (): TrackingEvent => { - if (eventFormat === 'google-analytics-4') { - return { - name: eventNames.userInteraction, - component_type: type === 'danger' ? 'danger_link' : 'link', - component_copy: getTextFromChildren(props.children), - }; - } else { - return { - category: eventCategories.userInteraction, - action: eventActions.linkTapped, - label: getTextFromChildren(props.children), - }; - } - }; - - const renderText = (element: React.ReactNode) => ( - + return small ? ( + + {element} + + ) : ( + {element} - + ); +}; - const finalType = type === 'danger' && isDarkMode && isInverse ? 'dangerDark' : type; - - const commonProps = { - className: classnames( - isInverse ? styles.inverseLinkVariants[finalType] : styles.linkVariants[finalType], - { - [styles.isLoading]: showSpinner, - } - ), - /** - * Setting bleed classes with style to override the margin:0 set by the Touchable component. - * If we set it using className, it may not work depending on the order in which the styles are applied. - */ - style: { - ...(props.bleedLeft ? {marginLeft: -styles.PADDING_X_LINK} : undefined), - ...(props.bleedRight ? {marginRight: -styles.PADDING_X_LINK} : undefined), - ...(props.bleedY - ? {marginTop: -styles.PADDING_Y_LINK, marginBottom: -styles.PADDING_Y_LINK} - : undefined), - }, - trackingEvent: props.trackingEvent ?? (props.trackEvent ? createDefaultTrackingEvent() : undefined), - dataAttributes: props.dataAttributes, - 'aria-label': props['aria-label'], - 'aria-controls': props['aria-controls'], - 'aria-expanded': props['aria-expanded'], - 'aria-haspopup': props['aria-haspopup'], - children: renderButtonContent({ - showSpinner, - shouldRenderSpinner, - setShouldRenderSpinner, - children: props.children, - loadingText, - small: true, - renderText, - textContentStyle: styles.textContentLink, - StartIcon: props.StartIcon, - EndIcon: props.EndIcon, - withChevron: showChevron, - }), - disabled: props.disabled || showSpinner || isFormSending, - role: props.role, - }; - - if (process.env.NODE_ENV !== 'production') { - if (props.to === '' || props.href === '') { - throw Error('to or href props are empty strings'); - } - } - - if (props.onPress) { - return ( - { - const result = props.onPress(e); - if (result) { - setIsOnPressPromiseResolving(true); - result.finally(() => setIsOnPressPromiseResolving(false)); - } - }} - /> - ); - } - - if (props.to || props.to === '') { - return ( - - ); - } - - if (props.href || props.href === '') { - return ( - - ); - } - - if (process.env.NODE_ENV !== 'production') { - // this cannot happen - throw Error('Bad button props'); - } - - return null; -}); +const LinkTextRenderer = (element: React.ReactNode, small?: boolean): JSX.Element => { + const {textPresets} = useTheme(); + const TextComponent = small ? Text2 : Text3; + return ( + + {element} + + ); +}; export const ButtonLink = React.forwardRef< TouchableElement, ButtonLinkProps & { withChevron?: boolean; } ->(({dataAttributes, ...props}, ref) => { +>(({dataAttributes, small, ...props}, ref) => { return ( - ); }); export const ButtonLinkDanger = React.forwardRef( - ({dataAttributes, ...props}, ref) => { + ({dataAttributes, small, ...props}, ref) => { return ( - ); } @@ -673,11 +566,12 @@ export const ButtonLinkDanger = React.forwardRef( ({dataAttributes, ...props}, ref) => { return ( -