-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(core): render plain Link anchors inline so an ancestor Text clamp can truncate them #6038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3585dd5
9f84e4e
1abf92c
2a36cb1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@astryxdesign/core': patch | ||
| --- | ||
|
|
||
| [fix] Render a plain Link anchor as `inline` so an ancestor `<Text maxLines>` clamp can truncate it; flex layout is kept for the external-link icon and button forms, and Link/Text docs now cover the external-link clamp limitation. (#6021) | ||
| @ManoharPaturi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,9 +52,12 @@ import {useTranslator} from '../i18n'; | |
| */ | ||
| const styles = stylex.create({ | ||
| base: { | ||
| display: 'inline-flex', | ||
| alignItems: 'center', | ||
| gap: spacingVars['--spacing-0-5'], | ||
| // `inline` (not `inline-flex`) so the anchor participates in the | ||
| // surrounding line boxes and an ancestor clamp (e.g. <Text maxLines>) | ||
| // can truncate it. An inline-flex box establishes its own formatting | ||
| // context, which an ancestor -webkit-line-clamp cannot reach — | ||
| // <Text maxLines={2}><Link>...</Link></Text> silently did nothing. | ||
| display: 'inline', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| fontFamily: 'inherit', | ||
| fontSize: 'inherit', | ||
| lineHeight: 'inherit', | ||
|
|
@@ -84,6 +87,17 @@ const styles = stylex.create({ | |
| pointerEvents: 'auto', | ||
| position: 'relative', | ||
| }, | ||
| /** | ||
| * Flex layout for the cases that need it: external links append an icon | ||
| * after the text (icon centering + gap), and the button-rendered form | ||
| * keeps its previous inline-flex layout. On plain anchors this is | ||
| * deliberately NOT applied — see the `base` display note. | ||
| */ | ||
| flexLayout: { | ||
| display: 'inline-flex', | ||
| alignItems: 'center', | ||
| gap: spacingVars['--spacing-0-5'], | ||
| }, | ||
| hasUnderline: { | ||
| textDecoration: 'underline', | ||
| }, | ||
|
|
@@ -329,6 +343,16 @@ export function Link({ | |
| // render as a <button> with link styling for semantic correctness. | ||
| const renderAsButton = | ||
| role === 'button' || (role === 'inert' && href == null); | ||
| const isExternalWithIcon = isExternalLink && !renderAsButton; | ||
| // The plain anchor stays `inline` so an ancestor clamp (<Text maxLines>) | ||
| // can truncate it — that is the composition this PR fixes. But a Link that | ||
| // establishes its own box (`display="block"`, or clamping itself via | ||
| // `maxLines`, or carrying the external-link icon) must keep the inline-flex | ||
| // root: an inline anchor around a block-level child computes a focus | ||
| // outline that paints nothing in Chromium, losing keyboard focus | ||
| // visibility on those forms. | ||
| const needsRootBox = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| isExternalWithIcon || display !== 'inline' || maxLines > 0; | ||
|
|
||
| const sharedContent = ( | ||
| <> | ||
|
|
@@ -341,7 +365,7 @@ export function Link({ | |
| maxLines={maxLines}> | ||
| {children} | ||
| </Text> | ||
| {isExternalLink && !renderAsButton && ( | ||
| {isExternalWithIcon && ( | ||
| <> | ||
| <Icon icon="externalLink" size="xsm" color="inherit" /> | ||
| <VisuallyHidden>{newTabLabel}</VisuallyHidden> | ||
|
|
@@ -366,6 +390,7 @@ export function Link({ | |
| themeProps('link', {color}), | ||
| focusOutlineProps.focusVisible( | ||
| styles.base, | ||
| styles.flexLayout, | ||
| styles.buttonReset, | ||
| linkColorStyles[color], | ||
| hasUnderline && styles.hasUnderline, | ||
|
|
@@ -398,10 +423,11 @@ export function Link({ | |
| themeProps('link', {color}), | ||
| focusOutlineProps.focusVisible( | ||
| styles.base, | ||
| needsRootBox && styles.flexLayout, | ||
| linkColorStyles[color], | ||
| hasUnderline && styles.hasUnderline, | ||
| isStandalone && styles.standalone, | ||
| styles.disabled, | ||
| isDisabled && styles.disabled, | ||
| xstyle, | ||
| ), | ||
| className, | ||
|
|
@@ -426,6 +452,7 @@ export function Link({ | |
| themeProps('link', {color}), | ||
| focusOutlineProps.focusVisible( | ||
| styles.base, | ||
| needsRootBox && styles.flexLayout, | ||
| linkColorStyles[color], | ||
| hasUnderline && styles.hasUnderline, | ||
| isStandalone && styles.standalone, | ||
|
|
||