-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(button)!: convert to CSS modules (#288)
* refactor(button)!: convert to CSS modules * refactor(button): convert to Typescript * fix(button): fix issue with scrim * fix(button): use -webkit-transform to target Safari only for icon jank bug * chore(button): add changeset file * chore(button): fix release type in changeset * fix(button): delete old .js file * chore(button): clean up duplicate text-icon value, sort theme styles * docs(button): move comment on brand-neutral theme value * fix(button): fix button className test * fix: temporarily backfill g-btn className in consuming packages * fix(case-study-slider): backfill g-btn className * style(hero): fix unnecessary curly braces Co-authored-by: Jeff Escalante <jescalan@users.noreply.github.com> * fix: replace relative imports for product type with imports from product-meta * fix(button): use , not any, to better track TS debt * fix(button): cleanup type issues * fix(button): cleanup type issues again * fix(button): fix issue with typecasting IconProps * fix(button): clean up typecast now that useHover is TS * fix(button): fix inaccuracy in button type * docs(button): add task link to comment on Co-authored-by: Jeff Escalante <jescalan@users.noreply.github.com>
- Loading branch information
Showing
27 changed files
with
626 additions
and
703 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@hashicorp/react-product-downloads-page': patch | ||
--- | ||
|
||
Patches a minor type issue with HashiCorpProduct, which was previously imported from outside the package. Now imports from platform-product-meta. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@hashicorp/react-alert-banner': patch | ||
--- | ||
|
||
Patches a minor type issue with HashiCorpProduct, which was previously imported from outside the package. Now imports from platform-product-meta. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
'@hashicorp/react-button': major | ||
--- | ||
|
||
Converts Button to CSS modules. | ||
|
||
- 💥✨ BREAKING CHANGE: Refactored to CSS modules. | ||
- Consumers will need to remove any `@hashicorp/react-button/style.css` imports. | ||
- No longer renders a `g-btn` className. Does however accept a `className` prop, so that we can continue to meet override use cases. | ||
- 🔨 Converts to Typescript |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { useRef, useState, useEffect, MutableRefObject } from 'react' | ||
|
||
function useHover(): [ | ||
hoverRef: MutableRefObject<$TSFixMe>, | ||
isHovered: boolean | ||
] { | ||
const [value, setValue] = useState(false) | ||
|
||
const ref = useRef(null) | ||
const handleMouseOver = () => setValue(true) | ||
const handleMouseOut = () => setValue(false) | ||
|
||
useEffect(() => { | ||
const node = ref.current | ||
if (node) { | ||
node.addEventListener('mouseover', handleMouseOver) | ||
node.addEventListener('mouseout', handleMouseOut) | ||
|
||
return () => { | ||
node.removeEventListener('mouseover', handleMouseOver) | ||
node.removeEventListener('mouseout', handleMouseOut) | ||
} | ||
} | ||
}, [ref.current]) | ||
|
||
return [ref, value] | ||
} | ||
|
||
export default useHover |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import React from 'react' | ||
import slugify from 'slugify' | ||
import fragment from './fragment.graphql' | ||
import classNames from 'classnames' | ||
import useProductMeta from '@hashicorp/platform-product-meta' | ||
import InlineSvg from '@hashicorp/react-inline-svg' | ||
import svgArrowRight from './icons/arrow-right.svg?include' | ||
import svgExternalLink from './icons/external-link.svg?include' | ||
import svgCornerRightDown from './icons/corner-right-down.svg?include' | ||
import svgDownload from './icons/download.svg?include' | ||
import s from './style.module.css' | ||
import sTheme from './theme.module.css' | ||
import useHover from './hooks/use-hover' | ||
import normalizeButtonTheme from './helpers/normalizeButtonTheme.js' | ||
import { Size, LinkType, IconObject, Theme, IconProps } from './types' | ||
|
||
const linkTypeToIcon = { | ||
inbound: svgArrowRight, | ||
outbound: svgExternalLink, | ||
anchor: svgCornerRightDown, | ||
download: svgDownload, | ||
} | ||
|
||
interface ButtonProps { | ||
title: string | ||
url?: string | ||
label?: string | ||
external?: boolean | ||
theme?: Theme | ||
ga_prefix?: string | ||
onClick?: React.MouseEventHandler<HTMLAnchorElement> & | ||
React.MouseEventHandler<HTMLButtonElement> | ||
disabled?: boolean | ||
className?: string | ||
linkType?: LinkType | ||
icon?: IconObject | ||
size?: Size | ||
/** | ||
* Note: Removing this TS "any" seems like it'll be quite a task. | ||
* One path forward might be to fully separate our | ||
* "ButtonButton" and "AnchorButton", and ask the consumer | ||
* to choose the correct component based on whether they need | ||
* a <a> or <button>. | ||
* Task ref: https://app.asana.com/0/1100423001970639/1200880473915564/f | ||
*/ | ||
[attr: string]: $TSFixMe | ||
} | ||
|
||
function Button({ | ||
title, | ||
url, | ||
label, | ||
external, | ||
theme = { | ||
variant: 'primary', | ||
brand: 'hashicorp', | ||
background: 'light', | ||
}, | ||
ga_prefix, | ||
onClick, | ||
disabled, | ||
className, | ||
linkType, | ||
icon, | ||
size = 'medium', | ||
...attrs | ||
}: ButtonProps): React.ReactElement { | ||
const [hoverRef, isHovered] = useHover() | ||
const themeObj = normalizeButtonTheme(theme) | ||
const { themeClass } = useProductMeta(themeObj.brand) | ||
const gaSlug = slugify(title, { lower: true }) | ||
const isExternal = url && (linkType === 'outbound' || external) | ||
const Elem = url ? 'a' : 'button' | ||
const iconProps = linkTypeToIcon[linkType] | ||
? ({ | ||
svg: linkTypeToIcon[linkType], | ||
position: icon?.position || 'right', | ||
animationId: linkType, | ||
isAnimated: icon?.isAnimated || true, | ||
isHovered, | ||
size, | ||
} as IconProps) | ||
: { ...icon, position: icon?.position || 'right', size, isHovered } | ||
const hasIcon = iconProps && iconProps.svg | ||
const hasRightIcon = hasIcon && iconProps.position !== 'left' | ||
const hasLeftIcon = hasIcon && iconProps.position === 'left' | ||
|
||
return ( | ||
<Elem | ||
className={classNames( | ||
s.root, | ||
themeClass, | ||
s[`size-${size}`], | ||
sTheme[`variant-${themeObj.variant}`], | ||
{ [sTheme['brand-neutral']]: themeObj.brand === 'neutral' }, | ||
sTheme[`background-${themeObj.background}`], | ||
className | ||
)} | ||
data-ga-button={`${ga_prefix ? ga_prefix + ' | ' : ''}${gaSlug}`} | ||
href={url} | ||
ref={hoverRef} | ||
rel={isExternal ? 'noopener' : undefined} | ||
target={isExternal ? '_blank' : undefined} | ||
onClick={onClick} | ||
disabled={disabled} | ||
aria-label={label} | ||
{...attrs} | ||
> | ||
{hasLeftIcon && <Icon {...iconProps} />} | ||
<span className={s.text}>{title}</span> | ||
{hasRightIcon && <Icon {...iconProps} />} | ||
</Elem> | ||
) | ||
} | ||
|
||
function Icon({ | ||
svg, | ||
position, | ||
animationId, | ||
isAnimated, | ||
isHovered, | ||
size, | ||
}: IconProps) { | ||
return ( | ||
<InlineSvg | ||
className={classNames( | ||
s.icon, | ||
s[`size-${size}`], | ||
s[`at-${position}`], | ||
{ [s.isHovered]: isHovered }, | ||
{ [s[`animation-${animationId}`]]: isAnimated } | ||
)} | ||
src={svg} | ||
/> | ||
) | ||
} | ||
|
||
Button.fragmentSpec = { fragment } | ||
|
||
export default Button |
Oops, something went wrong.
b0fd753
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: