Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion packages/react/src/BranchName/BranchName.features.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import type {Meta} from '@storybook/react-vite'
import React from 'react'
import BranchName from './BranchName'
import {Stack} from '../Stack'
import Octicon from '../Octicon'
import {GitBranchIcon} from '@primer/octicons-react'
import {GitBranchIcon, CopyIcon, CheckIcon} from '@primer/octicons-react'
import {IconButton} from '../Button'
import {Tooltip} from '../TooltipV2'
import {VisuallyHidden} from '../VisuallyHidden'
import {Announce} from '../live-region'
import {clsx} from 'clsx'

import styles from './BranchName.stories.module.css'

export default {
title: 'Components/BranchName/Features',
Expand All @@ -28,3 +36,47 @@ export const LinkWithoutHref = () => (
)

export const NoProps = () => <BranchName>branch_name_no_props</BranchName>

export const WithTrailingAction = ({
branchName = 'fix/anchored-overlay-outside-top-autogrow',
repo = 'primer/react',
}: {
branchName: string
repo: string
}) => {
const [copied, setCopied] = React.useState(false)

const handleCopy = () => {
setCopied(true)
void navigator.clipboard.writeText(branchName)
setTimeout(() => setCopied(false), 2000)
}

const tooltipText = copied ? 'Copied!' : 'Copy branch name to clipboard'

return (
<span className={styles.BranchNameWithTrailingAction}>
<Tooltip text={`${repo}:${branchName}`}>
<BranchName href={`https://github.com/${repo}/tree/${branchName}`} className={styles.BranchNameTransparent}>
{branchName}
</BranchName>
</Tooltip>
{/* Screen reader announcement for copy success */}
{copied && (
<VisuallyHidden>
<Announce>Copied!</Announce>
</VisuallyHidden>
)}
<Tooltip text={tooltipText} aria-hidden>
<IconButton
icon={copied ? CheckIcon : CopyIcon}
aria-label="Copy branch name to clipboard"
variant="invisible"
size="small"
onClick={handleCopy}
className={clsx(styles.TrailingActionButton, copied && styles.TrailingActionButtonCopied)}
/>
</Tooltip>
</span>
)
}
57 changes: 57 additions & 0 deletions packages/react/src/BranchName/BranchName.stories.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Story-only styles for demonstrating trailing action pattern */

.BranchNameWithTrailingAction {
display: inline-flex;
/* Let items stretch to fill container height */
align-items: stretch;
/* Create room for pseudo-border divider */
gap: var(--borderWidth-default);
flex-wrap: nowrap;
/* Moving the background to the container allows stacking the button hover background over it */
background-color: var(--bgColor-accent-muted);
border-radius: var(--borderRadius-medium);
overflow: hidden;
}

.BranchNameTransparent {
background-color: transparent;
}

.TrailingActionButton {
/* Make the size auto calculated based on icon size and padding */
height: auto;
width: auto;
padding: var(--base-size-2) var(--base-size-6);
position: relative;
/* Center content when button stretches to fill container */
align-items: center;

&:not(:disabled, [aria-disabled='true']) {
--button-invisible-iconColor-rest: var(--fgColor-link);
}

&.TrailingActionButtonCopied:not(:disabled, [aria-disabled='true']) {
--button-invisible-iconColor-rest: var(--fgColor-success);
}

[data-component='Octicon'] {
/* Set icon size to text size to exactly match the branch name component */
height: var(--text-body-size-small);
width: var(--text-body-size-small);
}

/* Dividing line between button and name. Using ::before on button allows for multiple buttons (with a line between each) */
&::before {
content: '';
position: absolute;
width: var(--borderWidth-default);
/* Position _between_ items (offsetting by width) to avoid overlapping with the real button border on hover/focus */
inset: var(--base-size-4) auto var(--base-size-4) calc(-1 * var(--borderWidth-default));
/* stylelint-disable-next-line primer/colors */
background-color: var(--borderColor-accent-muted);
}
}

.TrailingActionButtonCopied {
/* Class exists for JS toggling - styles handled via compound selector above */
}
Loading