From 1a00ee7a1cd367cd98854a529e8a69ee8ae119d3 Mon Sep 17 00:00:00 2001 From: Ernst Kaese Date: Fri, 20 Feb 2026 16:00:44 +0100 Subject: [PATCH] fix: Underlined component styling when nested in Inline Tokens --- pages/token/permutations.page.tsx | 13 ++ .../context/reset-contexts-for-modal.tsx | 5 +- src/internal/context/token-inline-context.ts | 17 +++ src/link/internal.tsx | 5 +- src/link/styles.scss | 4 + src/popover/internal.tsx | 4 +- src/popover/styles.scss | 4 + src/token/internal.tsx | 133 +++++++++--------- 8 files changed, 117 insertions(+), 68 deletions(-) create mode 100644 src/internal/context/token-inline-context.ts diff --git a/pages/token/permutations.page.tsx b/pages/token/permutations.page.tsx index 1249b1b481..4a340dac4a 100644 --- a/pages/token/permutations.page.tsx +++ b/pages/token/permutations.page.tsx @@ -3,6 +3,8 @@ import React from 'react'; import Icon from '~components/icon'; +import Link from '~components/link'; +import Popover from '~components/popover'; import Token, { TokenProps } from '~components/token'; import createPermutations from '../utils/permutations'; @@ -56,6 +58,17 @@ const permutations = createPermutations([ disabled: [true, false], variant: ['normal'], }, + { + label: [ + + link + , + + popover + , + ], + variant: ['inline'], + }, ]); export default function TokenPermutations() { diff --git a/src/internal/context/reset-contexts-for-modal.tsx b/src/internal/context/reset-contexts-for-modal.tsx index 0b63260642..74ce7a5c11 100644 --- a/src/internal/context/reset-contexts-for-modal.tsx +++ b/src/internal/context/reset-contexts-for-modal.tsx @@ -9,6 +9,7 @@ import { CollectionLabelContext } from './collection-label-context'; import { FormFieldContext } from './form-field-context'; import { InfoLinkLabelContext } from './info-link-label-context'; import { defaultValue as linkDefaultValue, LinkDefaultVariantContext } from './link-default-variant-context'; +import { defaultValue as tokenInlineDefaultValue, TokenInlineContext } from './token-inline-context'; /* Use this context-resetter when creating a new modal-type context where typically the contents @@ -20,7 +21,9 @@ const ResetContextsForModal = ({ children }: { children: React.ReactNode }) => ( - {children} + + {children} + diff --git a/src/internal/context/token-inline-context.ts b/src/internal/context/token-inline-context.ts new file mode 100644 index 0000000000..7e8a28916f --- /dev/null +++ b/src/internal/context/token-inline-context.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { createContext, useContext } from 'react'; + +export interface TokenInlineContextProps { + isInlineToken: boolean; +} + +export const defaultValue: TokenInlineContextProps = { + isInlineToken: false, +}; + +export const TokenInlineContext = createContext(defaultValue); + +export function useTokenInlineContext() { + return useContext(TokenInlineContext); +} diff --git a/src/link/internal.tsx b/src/link/internal.tsx index ccf9f38804..198f7c2a5e 100644 --- a/src/link/internal.tsx +++ b/src/link/internal.tsx @@ -19,6 +19,7 @@ import { import { getBaseProps } from '../internal/base-component'; import { InfoLinkLabelContext } from '../internal/context/info-link-label-context'; import { LinkDefaultVariantContext } from '../internal/context/link-default-variant-context'; +import { useTokenInlineContext } from '../internal/context/token-inline-context'; import { fireCancelableEvent, fireNonCancelableEvent, isPlainLeftClick } from '../internal/events'; import useForwardFocus from '../internal/hooks/forward-focus'; import { InternalBaseComponentProps } from '../internal/hooks/use-base-component'; @@ -157,6 +158,7 @@ const InternalLink = React.forwardRef( const linkRef = useRef(null); const isVisualRefresh = useVisualRefresh(); + const { isInlineToken } = useTokenInlineContext(); useForwardFocus(ref, linkRef); // Visual refresh should only add styles to buttons that don't already have unique styles (e.g. primary/secondary variants) @@ -172,7 +174,8 @@ const InternalLink = React.forwardRef( applyButtonStyles ? styles.button : null, styles[getVariantStyle(variant)], styles[getFontSizeStyle(variant, fontSize)], - styles[getColorStyle(variant, color)] + styles[getColorStyle(variant, color)], + isInlineToken && styles['in-inline-token'] ), style: getLinkStyles(style), 'aria-label': ariaLabel, diff --git a/src/link/styles.scss b/src/link/styles.scss index 62a5e3da8a..5a327ce573 100644 --- a/src/link/styles.scss +++ b/src/link/styles.scss @@ -65,6 +65,10 @@ @include styles.link-font-size-style(map.get(constants.$link-font-sizes, $font-size)); } } + + &.in-inline-token { + text-underline-offset: 0.15em; + } } .icon-wrapper { diff --git a/src/popover/internal.tsx b/src/popover/internal.tsx index 0c866d995e..1eb9d1fa2d 100644 --- a/src/popover/internal.tsx +++ b/src/popover/internal.tsx @@ -11,6 +11,7 @@ import { getBaseProps } from '../internal/base-component'; import { getFirstFocusable } from '../internal/components/focus-lock/utils'; import { LinkDefaultVariantContext } from '../internal/context/link-default-variant-context'; import ResetContextsForModal from '../internal/context/reset-contexts-for-modal'; +import { useTokenInlineContext } from '../internal/context/token-inline-context'; import { fireNonCancelableEvent, NonCancelableEventHandler } from '../internal/events/index'; import { InternalBaseComponentProps } from '../internal/hooks/use-base-component'; import { usePortalModeClasses } from '../internal/hooks/use-portal-mode-classes'; @@ -131,13 +132,14 @@ function InternalPopover( }, []); const popoverClasses = usePortalModeClasses(triggerRef, { resetVisualContext: true }); + const { isInlineToken } = useTokenInlineContext(); const triggerProps = { // https://github.com/microsoft/TypeScript/issues/36659 ref: triggerRef as any, onClick: onTriggerClick, onKeyDown: onTriggerKeyDown, - className: clsx(styles.trigger, styles[`trigger-type-${triggerType}`]), + className: clsx(styles.trigger, styles[`trigger-type-${triggerType}`], isInlineToken && styles['in-inline-token']), }; const { tabIndex: triggerTabIndex } = useSingleTabStopNavigation(triggerRef); diff --git a/src/popover/styles.scss b/src/popover/styles.scss index dbacbab0ee..89a179b17c 100644 --- a/src/popover/styles.scss +++ b/src/popover/styles.scss @@ -64,6 +64,10 @@ $trigger-underline-offset: 0.25em; */ padding-block-end: calc(#{$trigger-underline-offset} + #{awsui.$border-divider-list-width}); } + + &.in-inline-token { + text-underline-offset: 0.15em; + } } .trigger-type-text { diff --git a/src/token/internal.tsx b/src/token/internal.tsx index 9c54d87111..0490c438e2 100644 --- a/src/token/internal.tsx +++ b/src/token/internal.tsx @@ -8,6 +8,7 @@ import { useResizeObserver, useUniqueId, warnOnce } from '@cloudscape-design/com import { getBaseProps } from '../internal/base-component'; import Option from '../internal/components/option'; +import { TokenInlineContext } from '../internal/context/token-inline-context'; import { InternalBaseComponentProps } from '../internal/hooks/use-base-component'; import LiveRegion from '../live-region/internal'; import Tooltip from '../tooltip/internal.js'; @@ -98,78 +99,80 @@ function InternalToken({ }; return ( -
{ - setShowTooltip(true); - }} - onBlur={() => { - setShowTooltip(false); - }} - onMouseEnter={() => { - setShowTooltip(true); - }} - onMouseLeave={() => { - setShowTooltip(false); - }} - tabIndex={!!tooltipContent && isInline && isEllipsisActive ? 0 : undefined} - > +
{ + setShowTooltip(true); + }} + onBlur={() => { + setShowTooltip(false); + }} + onMouseEnter={() => { + setShowTooltip(true); + }} + onMouseLeave={() => { + setShowTooltip(false); + }} + tabIndex={!!tooltipContent && isInline && isEllipsisActive ? 0 : undefined} > -
+ {!!tooltipContent && isInline && isEllipsisActive && showTooltip && ( + labelContainerRef.current} + content={ + + {tooltipContent} + + } + onEscape={() => { + setShowTooltip(false); + }} /> )}
- {!!tooltipContent && isInline && isEllipsisActive && showTooltip && ( - labelContainerRef.current} - content={ - - {tooltipContent} - - } - onEscape={() => { - setShowTooltip(false); - }} - /> - )} - + ); }