Skip to content
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

Add play/pause button to LogoSuite #920

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
56 changes: 55 additions & 1 deletion packages/react/src/LogoSuite/LogoSuite.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
}

.LogoSuite__logobar--has-marquee {
position: relative;
display: flex;
flex-direction: column;
gap: var(--base-size-40);
Expand Down Expand Up @@ -140,7 +141,7 @@
}
}

.LogoSuite__logobar--has-marquee:hover .LogoSuite__logobar-marqueeGroup,
.LogoSuite__logobar-marquee:hover .LogoSuite__logobar-marqueeGroup,
.LogoSuite__logobar-marqueeGroup--speed-idle {
animation-play-state: paused;
}
Expand All @@ -160,3 +161,56 @@
);
mask-image: linear-gradient(to right, hsl(0 0% 0% / 0), hsl(0 0% 0% / 1) 20%, hsl(0 0% 0% / 1) 80%, hsl(0 0% 0% / 0));
}

.LogoSuite__logobar--paused * {
animation-play-state: paused !important;
}

.LogoSuite__logobar-playPauseButton {
cursor: pointer;
position: absolute;
right: 0;
bottom: 0;
display: flex;
width: 44px;
height: 44px;
margin: 0;
padding: 0;
border: none;
border-radius: 50%;
justify-content: center;
align-items: center;
background: none;
outline-offset: 2px;
}

.LogoSuite__logobar-playPauseButton:focus-visible {
outline: 4px solid var(--brand-color-focus);
outline-offset: 2px;
}

.LogoSuite__logobar-playPauseButton::before {
position: absolute;
width: 100%;
height: 100%;
content: '';
background: var(--brand-LogoSuite-color-logo-muted);
opacity: 0.6;
border-radius: 50%;
transition: opacity 0.2s ease-out;
}

.LogoSuite__logobar-playPauseButton:hover::before {
opacity: 0.8;
}

.LogoSuite__logobar-playPauseButton svg {
width: var(--base-size-20);
height: var(--base-size-20);
z-index: 1;
color: var(--brand-LogoSuite-color-logo-emphasis);
}

.LogoSuite__logobar-playPauseButton path {
fill: currentColor;
}
4 changes: 3 additions & 1 deletion packages/react/src/LogoSuite/LogoSuite.module.css.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ declare const styles: {
readonly "LogobarScrollX": string;
readonly "LogoSuite__logobar-marqueeGroup--speed-default": string;
readonly "LogoSuite__logobar-marqueeGroup--speed-slow": string;
readonly "LogoSuite__logobar-marqueeGroup--speed-idle": string;
readonly "LogoSuite__logobar-marquee": string;
readonly "LogoSuite__logobar-marqueeGroup--speed-idle": string;
readonly "LogoSuite__logobar--paused": string;
readonly "LogoSuite__logobar-playPauseButton": string;
};
export = styles;

57 changes: 55 additions & 2 deletions packages/react/src/LogoSuite/LogoSuite.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {default as clsx} from 'clsx'
import React, {type PropsWithChildren, type Ref, forwardRef, useEffect, useMemo, useState} from 'react'
import React, {type PropsWithChildren, type Ref, forwardRef, useCallback, useEffect, useMemo, useState} from 'react'
import type {BaseProps} from '../component-helpers'
import {Heading, HeadingProps, defaultHeadingTag, Text, TextProps} from '../'

Expand Down Expand Up @@ -144,6 +144,50 @@ const _Description = forwardRef(
},
)

const PauseIcon = () => (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" role="presentation" aria-hidden="true">
<path
d="M4.66148 2.3125C3.83593 2.3125 3.16669 2.98174 3.16669 3.80729V16.1927C3.16669 17.0183 3.83593 17.6875 4.66148 17.6875H7.65106C8.47662 17.6875 9.14586 17.0183 9.14586 16.1927V3.80729C9.14586 2.98174 8.47662 2.3125 7.65106 2.3125H4.66148ZM4.44794 3.80729C4.44794 3.68936 4.54355 3.59375 4.66148 3.59375H7.65106C7.769 3.59375 7.86461 3.68936 7.86461 3.80729V16.1927C7.86461 16.3106 7.769 16.4062 7.65106 16.4062H4.66148C4.54355 16.4062 4.44794 16.3106 4.44794 16.1927V3.80729ZM12.349 2.3125C11.5235 2.3125 10.8542 2.98174 10.8542 3.80729V16.1927C10.8542 17.0183 11.5235 17.6875 12.349 17.6875H15.3386C16.1642 17.6875 16.8334 17.0183 16.8334 16.1927V3.80729C16.8334 2.98174 16.1642 2.3125 15.3386 2.3125H12.349ZM12.1355 3.80729C12.1355 3.68936 12.2311 3.59375 12.349 3.59375H15.3386C15.4565 3.59375 15.5521 3.68936 15.5521 3.80729V16.1927C15.5521 16.3106 15.4565 16.4062 15.3386 16.4062H12.349C12.2311 16.4062 12.1355 16.3106 12.1355 16.1927V3.80729Z"
fill="currentColor"
></path>
</svg>
)

const PlayIcon = () => (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" role="presentation" aria-hidden="true">
<path
d="M6.24905 3.69194C5.82218 3.45967 5.30225 3.76868 5.30225 4.25466V15.7452C5.30225 16.2312 5.82218 16.5402 6.24906 16.3079L16.8079 10.5626C17.2538 10.32 17.2538 9.67983 16.8079 9.4372L6.24905 3.69194ZM4.021 4.25466C4.021 2.79672 5.58078 1.86969 6.86142 2.56651L17.4203 8.31176C18.758 9.03966 18.758 10.9602 17.4203 11.6881L6.86143 17.4333C5.58079 18.1301 4.021 17.2031 4.021 15.7452V4.25466Z"
fill="currentColor"
></path>
</svg>
)

type PlayPauseButtonProps = {
initialPlaying?: boolean
onPlayPause?: (isPlaying: boolean) => void
}

const PlayPauseButton = ({initialPlaying = true, onPlayPause}: PlayPauseButtonProps) => {
const [playing, setPlaying] = useState(initialPlaying)

const onClick = useCallback(() => {
setPlaying(!playing)
onPlayPause?.(!playing)
}, [onPlayPause, playing])

return (
<button
className={styles['LogoSuite__logobar-playPauseButton']}
type="button"
onClick={onClick}
aria-pressed="false"
aria-label={playing ? 'Pause animation' : 'Play animation'}
>
{playing ? <PauseIcon /> : <PlayIcon />}
</button>
)
}

export type LogoSuiteLogoBarProps = BaseProps<HTMLDivElement> & {
children: React.ReactNode | React.ReactNode[]
/**
Expand All @@ -166,6 +210,7 @@ const _LogoBar = forwardRef(
ref: Ref<HTMLDivElement>,
) => {
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false)
const [isPlaying, setIsPlaying] = useState(marquee && !prefersReducedMotion)

const childrenCount = React.Children.toArray(children).length
variant ??= childrenCount <= 5 ? 'emphasis' : 'muted'
Expand Down Expand Up @@ -194,7 +239,14 @@ const _LogoBar = forwardRef(
if (marquee && !prefersReducedMotion) {
const {className: marqueeDefaultClassName, ...restProps} = defaultProps
return (
<div {...restProps} className={clsx(styles['LogoSuite__logobar--has-marquee'], marqueeDefaultClassName)}>
<div
{...restProps}
className={clsx(
styles['LogoSuite__logobar--has-marquee'],
marqueeDefaultClassName,
!isPlaying && styles['LogoSuite__logobar--paused'],
)}
>
<div className={clsx(styles['LogoSuite__logobar-marquee'])}>
<div
className={clsx(
Expand All @@ -215,6 +267,7 @@ const _LogoBar = forwardRef(
{children}
</div>
</div>
<PlayPauseButton onPlayPause={setIsPlaying} />
</div>
)
}
Expand Down
Loading