From f53d1c45bd3eb87357bd52a5e438b6c6e9bb90ae Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Tue, 31 Oct 2023 17:07:55 -0700 Subject: [PATCH] [C-3286] Finalize harmony button docs --- package-lock.json | 14 ++ package.json | 1 + packages/eslint-config-audius/package.json | 1 + packages/eslint-config-audius/src/index.js | 10 +- packages/harmony/.eslintrc.js | 19 +- packages/harmony/.storybook/preview-body.html | 3 + .../button/BaseButton/BaseButton.module.css | 13 +- .../button/BaseButton/BaseButton.tsx | 6 +- .../src/components/button/Button/Button.mdx | 43 +++- .../button/Button/Button.module.css | 24 ++- .../button/Button/Button.stories.tsx | 202 ++++++++++++++---- .../src/components/button/Button/Button.tsx | 9 +- .../harmony/src/components/button/types.ts | 18 +- .../harmony/src/components/layout/Box/Box.tsx | 6 +- .../src/components/layout/Box/types.ts | 1 + packages/harmony/tsconfig.json | 1 + 16 files changed, 293 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b84bc91cb0..2254ba962f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "pg": "8.8.0" }, "devDependencies": { + "@emotion/eslint-plugin": "11.11.0", "@types/keyv": "4.2.0", "@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/parser": "5.48.2", @@ -3711,6 +3712,18 @@ "babel-plugin-emotion": "^10.0.27" } }, + "node_modules/@emotion/eslint-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/eslint-plugin/-/eslint-plugin-11.11.0.tgz", + "integrity": "sha512-jCOYqU/0Sqm+g+6D7QuIlG99q8YAF0T7BP98zQF/MPZKfbcm46z5mizXn0YlhZ9AYZfNtZ1DeODXdncYxZzR4Q==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": "6 || 7 || 8" + } + }, "node_modules/@emotion/hash": { "version": "0.8.0", "dev": true, @@ -118714,6 +118727,7 @@ "version": "1.5.48", "license": "ISC", "peerDependencies": { + "@emotion/eslint-plugin": "11.11.0", "@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/parser": "5.48.2", "eslint": "8.25.0", diff --git a/package.json b/package.json index 5c31edd65b7..19d2d5978c6 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "pedalboard:test": "turbo run test --filter='./packages/discovery-provider/plugins/pedalboard/apps/*' --filter='./packages/discovery-provider/plugins/pedalboard/packages/*'" }, "devDependencies": { + "@emotion/eslint-plugin": "11.11.0", "@types/keyv": "4.2.0", "@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/parser": "5.48.2", diff --git a/packages/eslint-config-audius/package.json b/packages/eslint-config-audius/package.json index 92d5b8d1c07..1d7d2fa7108 100644 --- a/packages/eslint-config-audius/package.json +++ b/packages/eslint-config-audius/package.json @@ -21,6 +21,7 @@ "test": "echo \"Error: run tests from root\" && exit 1" }, "peerDependencies": { + "@emotion/eslint-plugin": "11.11.0", "@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/parser": "5.48.2", "eslint": "8.25.0", diff --git a/packages/eslint-config-audius/src/index.js b/packages/eslint-config-audius/src/index.js index dc38fc9ff51..a52a6354fc8 100644 --- a/packages/eslint-config-audius/src/index.js +++ b/packages/eslint-config-audius/src/index.js @@ -23,7 +23,14 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module' }, - plugins: ['react', 'react-hooks', '@typescript-eslint', 'jest', 'import'], + plugins: [ + 'react', + 'react-hooks', + '@typescript-eslint', + '@emotion', + 'jest', + 'import' + ], rules: { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/no-non-null-assertion': 'off', @@ -75,6 +82,7 @@ module.exports = { 'react/prop-types': 'off', 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off', + 'react/no-unknown-property': ['error', { ignore: ['css'] }], 'prettier/prettier': ['error', require('../.prettierrc')], diff --git a/packages/harmony/.eslintrc.js b/packages/harmony/.eslintrc.js index 27486a33de7..e3be07215e9 100644 --- a/packages/harmony/.eslintrc.js +++ b/packages/harmony/.eslintrc.js @@ -1,20 +1,3 @@ module.exports = { - env: { - browser: true, - es6: true - }, - extends: ['audius'], - // settings: { - // 'import/resolver': { - // // NOTE: sk - These aliases are required for the import/order rule. - // // We are using the typescript baseUrl to do absolute import paths - // // relative to /src, which eslint can't tell apart from 3rd party deps - // alias: { - // map: [ - // ['components', './src/components'], - // ], - // extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'] - // } - // } - // }, + extends: ['audius'] } diff --git a/packages/harmony/.storybook/preview-body.html b/packages/harmony/.storybook/preview-body.html index 18ef0e04166..0437d679f1e 100644 --- a/packages/harmony/.storybook/preview-body.html +++ b/packages/harmony/.storybook/preview-body.html @@ -6,4 +6,7 @@ #storybook-docs .sbdocs-wrapper { padding: var(--harmony-spacing-3xl); } + #configuration-options { + margin-bottom: var(--harmony-spacing-2xl); + } ( children, 'aria-label': ariaLabelProp, asChild, + _isHovered, + _isPressed, ...other } = props const { isMatch: isTextHidden } = useMediaQueryListener( @@ -54,7 +56,9 @@ export const BaseButton = forwardRef( styles.button, { [baseStyles.disabled]: disabled || isLoading, - [baseStyles.fullWidth]: fullWidth + [baseStyles.fullWidth]: fullWidth, + [baseStyles.hover]: _isHovered, + [baseStyles.active]: _isPressed }, className )} diff --git a/packages/harmony/src/components/button/Button/Button.mdx b/packages/harmony/src/components/button/Button/Button.mdx index 78d73b27d16..6bd01a621b4 100644 --- a/packages/harmony/src/components/button/Button/Button.mdx +++ b/packages/harmony/src/components/button/Button/Button.mdx @@ -52,7 +52,48 @@ Fixed height: 32px, 48px, 64px - +### States + +Hover: transform scale: 1.04x, ease-out curve, 120ms +Pressed: transform scale: 0.98x, ease-out curve, 120ms + + + + + +### Disabled + + + + + +### Icons + + + + + +### Loading state + + + + + +### Color Prop Applied + +Generate the colors for primary button states using colored overlays rather than distinct hex values for each state. + + + + + +### Link + +A link that looks like a button. Useful for buttons that trigger navigation + + + + ## Use cases and examples diff --git a/packages/harmony/src/components/button/Button/Button.module.css b/packages/harmony/src/components/button/Button/Button.module.css index 81d021b2ad3..936b6cec846 100644 --- a/packages/harmony/src/components/button/Button/Button.module.css +++ b/packages/harmony/src/components/button/Button/Button.module.css @@ -90,12 +90,14 @@ .primary { --text-color: var(--harmony-static-white); --base-color: var(--harmony-primary); - &:hover { + &:hover, + &.hover { --overlay-color: var(--harmony-static-white); --overlay-opacity: 20%; box-shadow: var(--harmony-shadow-mid); } - &:active { + &:active, + &.active { --overlay-color: var(--harmony-static-black); --overlay-opacity: 20%; box-shadow: none; @@ -115,7 +117,8 @@ --text-color: var(--harmony-text-default); background: transparent; box-shadow: none; - &:hover { + &:hover, + &.hover { --base-color: var(--harmony-primary); --text-color: var(--harmony-static-white); background-color: var(--button-color); @@ -123,7 +126,8 @@ --overlay-opacity: 20%; box-shadow: var(--harmony-shadow-mid); } - &:active { + &:active, + &.active { --base-color: var(--harmony-primary); --text-color: var(--harmony-static-white); background-color: var(--button-color); @@ -143,13 +147,15 @@ /* Don't use opacity prop as it affects the text too */ background-color: rgb(255, 255, 255, 0.85); backdrop-filter: blur(6px); - &:hover { + &:hover, + &.hover { --base-color: var(--harmony-border-strong); box-shadow: var(--harmony-shadow-mid); background-color: var(--harmony-bg-white); backdrop-filter: none; } - &:active { + &:active, + &.active { --base-color: var(--harmony-border-strong); background-color: var(--harmony-bg-surface-2); box-shadow: none; @@ -167,13 +173,15 @@ --text-color: var(--harmony-red); background: transparent; box-shadow: none; - &:hover { + &:hover, + &.hover { --base-color: var(--harmony-red); --text-color: var(--harmony-static-white); background-color: var(--button-color); box-shadow: var(--harmony-shadow-mid); } - &:active { + &:active, + &.active { --base-color: var(--harmony-red); --text-color: var(--harmony-static-white); --overlay-color: var(--harmony-static-black); diff --git a/packages/harmony/src/components/button/Button/Button.stories.tsx b/packages/harmony/src/components/button/Button/Button.stories.tsx index 2359c4f353e..e8af0fb6f8a 100644 --- a/packages/harmony/src/components/button/Button/Button.stories.tsx +++ b/packages/harmony/src/components/button/Button/Button.stories.tsx @@ -2,42 +2,16 @@ import { expect } from '@storybook/jest' import type { Meta, StoryObj } from '@storybook/react' import { within } from '@storybook/testing-library' -import { Flex } from 'components/layout' -import { Text } from 'components/typography' +import { Box, Flex } from 'components/layout' +import { IconArrowLeft, IconArrowRight, Text } from 'components/typography' import { ButtonProps, ButtonSize, ButtonType } from '../types' import { Button } from './Button' -const baseProps: ButtonProps = { - children: 'Click Me' -} - const meta: Meta = { title: 'Components/Buttons/Button', - component: Button, - render: (props: ButtonProps) => ( -
-
-
-
-
-
- ) + component: Button } export default meta @@ -51,7 +25,7 @@ export const Primary: Story = { export const Variants: Story = { render: () => ( - + @@ -80,23 +54,169 @@ export const Sizes: Story = { ) } -// Primary w/ color -export const PrimaryWithColor: Story = { args: { hexColor: '#13C65A' } } +export const States: Story = { + render: () => ( + + + Hover + + + + + + + Pressed + + + + + + + ) +} -// Secondary -export const Secondary: Story = { - args: { variant: ButtonType.SECONDARY } +export const Disabled: Story = { + render: () => ( + + + + + + + ) } -// Tertiary -export const Tertiary: Story = { args: { variant: ButtonType.TERTIARY } } +export const Icons: Story = { + render: () => ( + + + + + ) +} + +export const LoadingState: Story = { + render: () => ( + + + + + + + Show loading state on click + + + ) +} -// Destructive -export const Destructive: Story = { args: { variant: ButtonType.DESTRUCTIVE } } +export const ColorPropApplied: Story = { + render: () => ( + + + + + +
    + +
  • Background: Color Value
  • +
    + +
  • Shadow: Near
  • +
    + +
  • Transform Scale: 1x
  • +
    +
+
-// Hidden text at certain widths (e.g. mobile layouts) -export const HiddenTextAtWidth: Story = { args: { widthToHideText: 900 } } + + + + +
    + +
  • Background: Color Value + White Overlay @ 10% Opacity
  • +
    + +
  • Shadow: Mid
  • +
    + +
  • Transform Scale: 1.04x
  • +
    +
+
+ + + + + +
    + +
  • Background: Color Value + Black Overlay @ 20% Opacity
  • +
    + +
  • Shadow: None
  • +
    + +
  • Transform Scale: 0.98x
  • +
    +
+
+ + + + +
    + +
  • Background: n-150
  • +
    + +
  • Shadow: None
  • +
    + +
  • Transform Scale: 1x
  • +
    +
+
+
+ ) +} export const Link: Story = { args: { asChild: true }, render: (props: ButtonProps) => { diff --git a/packages/harmony/src/components/button/Button/Button.tsx b/packages/harmony/src/components/button/Button/Button.tsx index 742bedd8668..10731ca3283 100644 --- a/packages/harmony/src/components/button/Button/Button.tsx +++ b/packages/harmony/src/components/button/Button/Button.tsx @@ -54,7 +54,8 @@ export const Button = forwardRef( disabled, ...baseProps } = props - const isDisabled = disabled || baseProps.isLoading + const { _isHovered, _isPressed, isLoading } = baseProps + const isDisabled = disabled || isLoading const style: CSSCustomProperties = { '--base-color': @@ -76,7 +77,11 @@ export const Button = forwardRef( button: cn( styles.button, TYPE_STYLE_MAP[variant], - { [styles.disabled]: isDisabled }, + { + [styles.disabled]: isDisabled, + [styles.hover]: _isHovered, + [styles.active]: _isPressed + }, buttonSizeClass, textSizeClass ), diff --git a/packages/harmony/src/components/button/types.ts b/packages/harmony/src/components/button/types.ts index 83ad4e730d0..6fb7c568fd0 100644 --- a/packages/harmony/src/components/button/types.ts +++ b/packages/harmony/src/components/button/types.ts @@ -25,6 +25,21 @@ type BaseButtonStyles = { export type HTMLButtonProps = ComponentPropsWithoutRef<'button'> +/** + * These props should only be used for dev purposes, whether in debug mode, + * or to show various states in storybook. + * */ +type InternalProps = { + /** + * @ignore: This prop is for internal use only + */ + _isHovered?: boolean + /** + * @ignore: This prop is for internal use only + */ + _isPressed?: boolean +} + export type BaseButtonProps = { /** * Optional icon element to include on the left side of the button @@ -68,7 +83,8 @@ export type BaseButtonProps = { * merging their props and behavior. */ asChild?: boolean -} & HTMLButtonProps +} & HTMLButtonProps & + InternalProps export type ButtonProps = { /** diff --git a/packages/harmony/src/components/layout/Box/Box.tsx b/packages/harmony/src/components/layout/Box/Box.tsx index 0c842afcb9c..f5ff56d2c4f 100644 --- a/packages/harmony/src/components/layout/Box/Box.tsx +++ b/packages/harmony/src/components/layout/Box/Box.tsx @@ -24,7 +24,8 @@ export const Box = styled.div( border, borderRadius, shadow, - flex + flex, + alignSelf }: BoxProps) => { const padT = pt ?? pv ?? p const padB = pb ?? pv ?? p @@ -53,7 +54,8 @@ export const Box = styled.div( border: border && `1px solid var(--harmony-border-${border})`, borderRadius: borderRadius && `var(--harmony-border-radius-${borderRadius})`, - flex + flex, + alignSelf } } ) diff --git a/packages/harmony/src/components/layout/Box/types.ts b/packages/harmony/src/components/layout/Box/types.ts index 1486c6ecf70..3f52c0044f1 100644 --- a/packages/harmony/src/components/layout/Box/types.ts +++ b/packages/harmony/src/components/layout/Box/types.ts @@ -50,4 +50,5 @@ export type BoxProps = { shadow?: ShadowOptions flex?: CSSProperties['flex'] + alignSelf?: CSSProperties['alignSelf'] } diff --git a/packages/harmony/tsconfig.json b/packages/harmony/tsconfig.json index af1504d40b0..a0e7ff474a9 100644 --- a/packages/harmony/tsconfig.json +++ b/packages/harmony/tsconfig.json @@ -8,6 +8,7 @@ "plugins": [{ "name": "typescript-plugin-css-modules" }], "allowJs": false, "jsx": "react-jsx", + "jsxImportSource": "@emotion/react", "resolveJsonModule": true, "moduleResolution": "node", "exactOptionalPropertyTypes": false,