From b7fd15b2ffa1a32eb40d6159d87ee99b83a9b80b Mon Sep 17 00:00:00 2001 From: Alexandra Goff Date: Wed, 29 Nov 2023 15:07:34 -0700 Subject: [PATCH] [C] improvements to slideout and share buttons --- packages/epo-react-lib/CHANGELOG.md | 8 +++ packages/epo-react-lib/package.json | 2 +- .../atomic/Share/BaseButton/BaseButton.tsx | 17 +++--- .../src/atomic/Share/BaseButton/styles.ts | 20 ++----- .../atomic/Share/CopyUrlButton.stories.tsx | 15 ++++-- .../src/atomic/Share/CopyUrlButton.tsx | 11 ++-- .../src/atomic/Share/EmailButton.stories.tsx | 15 ++++-- .../src/atomic/Share/EmailButton.tsx | 19 ++++--- .../atomic/Share/FacebookButton.stories.tsx | 15 ++++-- .../src/atomic/Share/FacebookButton.tsx | 14 ++--- .../atomic/Share/TwitterButton.stories.tsx | 15 ++++-- .../src/atomic/Share/TwitterButton.tsx | 20 ++++--- .../epo-react-lib/src/atomic/Share/styles.ts | 38 +++++++++++++- packages/epo-react-lib/src/contexts/Menu.ts | 9 ++-- .../layout/SlideoutMenu/MenuItem/MenuItem.tsx | 49 +++++++++++------ .../layout/SlideoutMenu/MenuItem/styles.ts | 17 +++--- .../SlideoutMenu/SlideoutMenu.stories.tsx | 8 ++- .../src/svg/icons/InfoCircle.tsx | 52 +++++++++++++++++++ .../src/svg/icons/defaultProps.ts | 1 + packages/epo-react-lib/src/svg/icons/index.ts | 2 + .../epo-react-lib/src/types/share-button.ts | 12 +++++ 21 files changed, 264 insertions(+), 95 deletions(-) create mode 100644 packages/epo-react-lib/src/svg/icons/InfoCircle.tsx diff --git a/packages/epo-react-lib/CHANGELOG.md b/packages/epo-react-lib/CHANGELOG.md index 507f82ac..af325d56 100644 --- a/packages/epo-react-lib/CHANGELOG.md +++ b/packages/epo-react-lib/CHANGELOG.md @@ -52,3 +52,11 @@ - add signature overloads to `token` - export `ImageShape`, `Option`, and `ListBoxOption` from their modules + +## 2.0.10 + +- add `showText` to share buttons to optionally display labels +- add links as a valid `menuitem` in Slideout +- add `InfoCircle` icon +- reset all icons to stroke-width: 0 +- minor refactor to use CSS variables for backgrounds and hovers. diff --git a/packages/epo-react-lib/package.json b/packages/epo-react-lib/package.json index 47f45be0..3a9ccb73 100644 --- a/packages/epo-react-lib/package.json +++ b/packages/epo-react-lib/package.json @@ -1,7 +1,7 @@ { "name": "@rubin-epo/epo-react-lib", "description": "Rubin Observatory Education & Public Outreach team React UI library.", - "version": "2.0.9", + "version": "2.0.10", "author": "Rubin EPO", "license": "MIT", "homepage": "https://lsst-epo.github.io/epo-react-lib", diff --git a/packages/epo-react-lib/src/atomic/Share/BaseButton/BaseButton.tsx b/packages/epo-react-lib/src/atomic/Share/BaseButton/BaseButton.tsx index 3c7c509a..5ee206a1 100644 --- a/packages/epo-react-lib/src/atomic/Share/BaseButton/BaseButton.tsx +++ b/packages/epo-react-lib/src/atomic/Share/BaseButton/BaseButton.tsx @@ -6,22 +6,23 @@ interface BaseButtonProps { label: string; icon: string; iconSize?: number; - bgColor?: string; - bgHoverColor?: string; + showText?: boolean; } const BaseButton: FunctionComponent = ({ label, icon, iconSize, - bgColor = "#000", - bgHoverColor = "#000", + showText = false, }) => { return ( - - - {label} - + <> + {showText && label} + + + {!showText && {label}} + + ); }; diff --git a/packages/epo-react-lib/src/atomic/Share/BaseButton/styles.ts b/packages/epo-react-lib/src/atomic/Share/BaseButton/styles.ts index ae1c8769..ddd458ab 100644 --- a/packages/epo-react-lib/src/atomic/Share/BaseButton/styles.ts +++ b/packages/epo-react-lib/src/atomic/Share/BaseButton/styles.ts @@ -1,29 +1,17 @@ import { ScreenreaderText } from "@/styles/utils"; import styled from "styled-components"; -interface WrapperProps { - $bgColor: string; - $bgHoverColor: string; -} - -export const Wrapper = styled.div` +export const Wrapper = styled.div` + background-color: var(--share-background-color, #000); display: flex; align-items: center; justify-content: center; - width: 40px; - height: 40px; + width: var(--share-size, 40px); + height: var(--share-size, 40px); border: transparent solid 2px; border-radius: 50%; color: var(--white); transition: background-color 0.2s, border-color 0.2s; - - ${({ $bgColor, $bgHoverColor }) => ` - background-color: ${$bgColor}; - - &:hover { - background-color: ${$bgHoverColor}; - } - `} `; export const SrText = ScreenreaderText; diff --git a/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.stories.tsx b/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.stories.tsx index bfca5622..769a2eeb 100644 --- a/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.stories.tsx +++ b/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.stories.tsx @@ -1,8 +1,8 @@ -import { ComponentMeta, ComponentStoryObj } from "@storybook/react"; +import { Meta, StoryObj } from "@storybook/react"; import CopyUrlButton from "./CopyUrlButton"; -const meta: ComponentMeta = { +const meta: Meta = { component: CopyUrlButton, argTypes: { url: { @@ -18,11 +18,20 @@ const meta: ComponentMeta = { }, }, }, + showText: { + description: "Shows the share button's label", + control: "boolean", + table: { + type: { + summary: "boolean", + }, + }, + }, }, }; export default meta; -export const Primary: ComponentStoryObj = { +export const Primary: StoryObj = { args: { url: "https://rubinobservatory.org/", }, diff --git a/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.tsx b/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.tsx index 5a199e76..910605a8 100644 --- a/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.tsx +++ b/packages/epo-react-lib/src/atomic/Share/CopyUrlButton.tsx @@ -4,9 +4,9 @@ import { useTranslation } from "react-i18next"; import * as Styled from "./styles"; import BaseButton from "./BaseButton/BaseButton"; -const CopyUrlButton: FunctionComponent> = ({ - url, -}) => { +const CopyUrlButton: FunctionComponent< + Pick +> = ({ url, className, showText }) => { const { t } = useTranslation(); function onClick() { @@ -16,13 +16,12 @@ const CopyUrlButton: FunctionComponent> = ({ } return ( - + ); diff --git a/packages/epo-react-lib/src/atomic/Share/EmailButton.stories.tsx b/packages/epo-react-lib/src/atomic/Share/EmailButton.stories.tsx index 28e1b8d2..f7cbe6c5 100644 --- a/packages/epo-react-lib/src/atomic/Share/EmailButton.stories.tsx +++ b/packages/epo-react-lib/src/atomic/Share/EmailButton.stories.tsx @@ -1,8 +1,8 @@ -import { ComponentMeta, ComponentStoryObj } from "@storybook/react"; +import { Meta, StoryObj } from "@storybook/react"; import EmailButton from "./EmailButton"; -const meta: ComponentMeta = { +const meta: Meta = { component: EmailButton, argTypes: { url: { @@ -30,11 +30,20 @@ const meta: ComponentMeta = { }, }, }, + showText: { + description: "Shows the share button's label", + control: "boolean", + table: { + type: { + summary: "boolean", + }, + }, + }, }, }; export default meta; -export const Primary: ComponentStoryObj = { +export const Primary: StoryObj = { args: { url: "https://rubinobservatory.org/", title: "New image gallery posts!", diff --git a/packages/epo-react-lib/src/atomic/Share/EmailButton.tsx b/packages/epo-react-lib/src/atomic/Share/EmailButton.tsx index aca79c81..ccb408ce 100644 --- a/packages/epo-react-lib/src/atomic/Share/EmailButton.tsx +++ b/packages/epo-react-lib/src/atomic/Share/EmailButton.tsx @@ -1,28 +1,33 @@ -import { EmailShareButton } from "react-share"; import { useTranslation } from "react-i18next"; import BaseButton from "./BaseButton/BaseButton"; import { FunctionComponent } from "react"; import { ShareButtonProps } from "@/types/share-button"; +import * as Styled from "./styles"; -const EmailButton: FunctionComponent = ({ title, url }) => { +const EmailButton: FunctionComponent = ({ + title, + url, + className, + showText, + ...shareProps +}) => { const { t } = useTranslation(); return ( - - + ); }; diff --git a/packages/epo-react-lib/src/atomic/Share/FacebookButton.stories.tsx b/packages/epo-react-lib/src/atomic/Share/FacebookButton.stories.tsx index bf99e52f..c77d8fd9 100644 --- a/packages/epo-react-lib/src/atomic/Share/FacebookButton.stories.tsx +++ b/packages/epo-react-lib/src/atomic/Share/FacebookButton.stories.tsx @@ -1,8 +1,8 @@ -import { ComponentMeta, ComponentStoryObj } from "@storybook/react"; +import { Meta, StoryObj } from "@storybook/react"; import FacebookButton from "./FacebookButton"; -const meta: ComponentMeta = { +const meta: Meta = { component: FacebookButton, argTypes: { url: { @@ -30,11 +30,20 @@ const meta: ComponentMeta = { }, }, }, + showText: { + description: "Shows the share button's label", + control: "boolean", + table: { + type: { + summary: "boolean", + }, + }, + }, }, }; export default meta; -export const Primary: ComponentStoryObj = { +export const Primary: StoryObj = { args: { url: "https://rubinobservatory.org/", title: "New image gallery posts!", diff --git a/packages/epo-react-lib/src/atomic/Share/FacebookButton.tsx b/packages/epo-react-lib/src/atomic/Share/FacebookButton.tsx index b1effe60..aca5f721 100644 --- a/packages/epo-react-lib/src/atomic/Share/FacebookButton.tsx +++ b/packages/epo-react-lib/src/atomic/Share/FacebookButton.tsx @@ -1,29 +1,31 @@ -import { FacebookShareButton } from "react-share"; import { useTranslation } from "react-i18next"; import BaseButton from "./BaseButton/BaseButton"; import { FunctionComponent } from "react"; import { ShareButtonProps } from "@/types/share-button"; +import * as Styled from "./styles"; const FacebookButton: FunctionComponent = ({ url, title, + className, + showText, + ...shareProps }) => { const { t } = useTranslation(); return ( - - + ); }; diff --git a/packages/epo-react-lib/src/atomic/Share/TwitterButton.stories.tsx b/packages/epo-react-lib/src/atomic/Share/TwitterButton.stories.tsx index e280775b..77bdf4d1 100644 --- a/packages/epo-react-lib/src/atomic/Share/TwitterButton.stories.tsx +++ b/packages/epo-react-lib/src/atomic/Share/TwitterButton.stories.tsx @@ -1,8 +1,8 @@ -import { ComponentMeta, ComponentStoryObj } from "@storybook/react"; +import { Meta, StoryObj } from "@storybook/react"; import TwitterButton from "./TwitterButton"; -const meta: ComponentMeta = { +const meta: Meta = { component: TwitterButton, argTypes: { url: { @@ -30,11 +30,20 @@ const meta: ComponentMeta = { }, }, }, + showText: { + description: "Shows the share button's label", + control: "boolean", + table: { + type: { + summary: "boolean", + }, + }, + }, }, }; export default meta; -export const Primary: ComponentStoryObj = { +export const Primary: StoryObj = { args: { url: "https://rubinobservatory.org/", title: "New image gallery posts!", diff --git a/packages/epo-react-lib/src/atomic/Share/TwitterButton.tsx b/packages/epo-react-lib/src/atomic/Share/TwitterButton.tsx index c028e0f5..1a02f0d2 100644 --- a/packages/epo-react-lib/src/atomic/Share/TwitterButton.tsx +++ b/packages/epo-react-lib/src/atomic/Share/TwitterButton.tsx @@ -1,27 +1,31 @@ import { FunctionComponent } from "react"; import { ShareButtonProps } from "@/types/share-button"; - -import { TwitterShareButton } from "react-share"; import { useTranslation } from "react-i18next"; import BaseButton from "./BaseButton/BaseButton"; +import * as Styled from "./styles"; -const TwitterButton: FunctionComponent = ({ url, title }) => { +const TwitterButton: FunctionComponent = ({ + url, + title, + className, + showText, + ...shareProps +}) => { const { t } = useTranslation(); return ( - - + ); }; diff --git a/packages/epo-react-lib/src/atomic/Share/styles.ts b/packages/epo-react-lib/src/atomic/Share/styles.ts index 2fa30601..754be250 100644 --- a/packages/epo-react-lib/src/atomic/Share/styles.ts +++ b/packages/epo-react-lib/src/atomic/Share/styles.ts @@ -1,6 +1,40 @@ -import { protoButton } from "@/styles/mixins/appearance"; +import { + EmailShareButton as EmailBase, + FacebookShareButton as FacebookBase, + TwitterShareButton as TwitterBase, +} from "react-share"; import styled from "styled-components"; +import { protoButton } from "@/styles/mixins/appearance"; export const CopyUrlButton = styled.button` - ${protoButton()} + --share-background-color: var(--turquoise70); + ${protoButton()}; + + &:hover { + --share-background-color: #7ac1c2; + } +`; + +export const EmailShareButton = styled(EmailBase)` + --share-background-color: var(--turquoise85); + + &:hover { + --share-background-color: #7fb3b1; + } +`; + +export const FacebookShareButton = styled(FacebookBase)` + --share-background-color: #3d5a99; + + &:hover { + --share-background-color: #98a5cb; + } +`; + +export const TwitterShareButton = styled(TwitterBase)` + --share-background-color: #38a8e0; + + &:hover { + --share-background-color: #98d0f1; + } `; diff --git a/packages/epo-react-lib/src/contexts/Menu.ts b/packages/epo-react-lib/src/contexts/Menu.ts index 6215a8cc..9dd16146 100644 --- a/packages/epo-react-lib/src/contexts/Menu.ts +++ b/packages/epo-react-lib/src/contexts/Menu.ts @@ -1,9 +1,8 @@ import { createContext } from "react"; -const MenuContext = - createContext<{ - menuItems: Set; - currentIndex: number; - } | null>(null); +const MenuContext = createContext<{ + menuItems: Set; + currentIndex: number; +} | null>(null); export default MenuContext; diff --git a/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/MenuItem.tsx b/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/MenuItem.tsx index 1e37b3e5..a2c6affc 100644 --- a/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/MenuItem.tsx +++ b/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/MenuItem.tsx @@ -1,25 +1,39 @@ import { - FunctionComponent, PropsWithChildren, useContext, useRef, useEffect, + HTMLProps, + ReactElement, } from "react"; import MenuContext from "@/contexts/Menu"; -import { StyledMenuItem, StyledMenuItemWrapper } from "./styles"; -import { ButtonProps } from "@/atomic/Button"; +import * as Styled from "./styles"; +import { IconKey } from "@/svg/icons"; +import IconComposer from "@/svg/IconComposer"; -interface MenuItemProps extends ButtonProps { +interface MenuButtonProps { + type?: "button"; text: string; + icon: IconKey; } -const MenuItem: FunctionComponent> = ({ - text, +interface MenuLinkProps extends HTMLProps { + type?: "link"; + text: string; + icon: IconKey; +} + +function MenuItem(props: PropsWithChildren): ReactElement; +function MenuItem(props: PropsWithChildren): ReactElement; +function MenuItem({ children, - ...buttonProps -}) => { + icon, + text, + type = "button", + ...restProps +}: PropsWithChildren): ReactElement { const menuContext = useContext(MenuContext); - const menuItemRef = useRef(); + const menuItemRef = useRef(); if (!menuContext) { throw new Error("Menu item must be used within a Menu Context"); @@ -44,20 +58,21 @@ const MenuItem: FunctionComponent> = ({ [...menuItems].indexOf(menuItemRef.current) === currentIndex; return ( - - + + {text} - + {children} - + ); -}; +} MenuItem.displayName = "Layout.SlideoutMenu.MenuItem"; diff --git a/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/styles.ts b/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/styles.ts index 83047890..4142ac03 100644 --- a/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/styles.ts +++ b/packages/epo-react-lib/src/layout/SlideoutMenu/MenuItem/styles.ts @@ -1,7 +1,9 @@ import styled from "styled-components"; -import Button from "@/atomic/Button"; +import { aButton } from "@/styles/mixins/appearance"; +import { fluidScale } from "@/styles/utils"; -export const StyledMenuItemWrapper = styled.div` +export const MenuItemWrapper = styled.div` + display: flex; padding: 0; margin: 0; @@ -10,14 +12,17 @@ export const StyledMenuItemWrapper = styled.div` } `; -export const StyledMenuItem = styled(Button)` - --button-border-color: transparent; - --button-background-color: transparent; - --button-text-align: left; +export const MenuItem = styled.button` + ${aButton} + display: inline-flex; + align-items: center; + gap: 10px; + font-size: ${fluidScale("20px", "16px")}; border: none; stroke-width: 0.25px; width: 100%; + padding-inline-start: 15px; &:not(:disabled):not([aria-disabled="true"]):hover { text-decoration: underline; diff --git a/packages/epo-react-lib/src/layout/SlideoutMenu/SlideoutMenu.stories.tsx b/packages/epo-react-lib/src/layout/SlideoutMenu/SlideoutMenu.stories.tsx index 252f0861..f9a6277d 100644 --- a/packages/epo-react-lib/src/layout/SlideoutMenu/SlideoutMenu.stories.tsx +++ b/packages/epo-react-lib/src/layout/SlideoutMenu/SlideoutMenu.stories.tsx @@ -263,7 +263,13 @@ const Template: ComponentStory = ({ ...args }) => { onCloseCallback={() => setIsSubMenuOpen(false)} /> - + setIsSubMenuOpen(true)} onCloseCallback={() => setIsSubMenuOpen(false)} diff --git a/packages/epo-react-lib/src/svg/icons/InfoCircle.tsx b/packages/epo-react-lib/src/svg/icons/InfoCircle.tsx new file mode 100644 index 00000000..eadcdff0 --- /dev/null +++ b/packages/epo-react-lib/src/svg/icons/InfoCircle.tsx @@ -0,0 +1,52 @@ +import { FunctionComponent } from "react"; +import { SVGProps } from "@/types/svg"; +import defaultProps from "./defaultProps"; + +const InfoCircle: FunctionComponent = ({ + className, + size = 24, + fill = "currentColor", +}) => { + const uniqueProps = { + viewBox: "-1 -1 20 20", + width: size, + height: size, + fill, + className, + }; + + const mergedSvgProps = Object.assign(defaultProps, uniqueProps); + return ( + + Info icon + + + + + ); +}; + +InfoCircle.displayName = "SVG.InfoCircle"; + +export default InfoCircle; diff --git a/packages/epo-react-lib/src/svg/icons/defaultProps.ts b/packages/epo-react-lib/src/svg/icons/defaultProps.ts index 4776f5ba..9aa4394c 100644 --- a/packages/epo-react-lib/src/svg/icons/defaultProps.ts +++ b/packages/epo-react-lib/src/svg/icons/defaultProps.ts @@ -1,4 +1,5 @@ export default { xmlns: "http://www.w3.org/2000/svg", role: "presentation", + strokeWidth: 0, }; diff --git a/packages/epo-react-lib/src/svg/icons/index.ts b/packages/epo-react-lib/src/svg/icons/index.ts index 865d9064..5af59da6 100644 --- a/packages/epo-react-lib/src/svg/icons/index.ts +++ b/packages/epo-react-lib/src/svg/icons/index.ts @@ -28,6 +28,7 @@ import Globe from "./Globe"; import Google from "./Google"; import Hamburger from "./Hamburger"; import Info from "./Info"; +import InfoCircle from "./InfoCircle"; import Instagram from "./Instagram"; import Lightbulb from "./Lightbulb"; import LinkedIn from "./LinkedIn"; @@ -95,6 +96,7 @@ const Icons = { Google, Hamburger, Info, + InfoCircle, Instagram, Lightbulb, LinkedIn, diff --git a/packages/epo-react-lib/src/types/share-button.ts b/packages/epo-react-lib/src/types/share-button.ts index 013ae877..eaecf61a 100644 --- a/packages/epo-react-lib/src/types/share-button.ts +++ b/packages/epo-react-lib/src/types/share-button.ts @@ -1,6 +1,18 @@ +import { CSSProperties } from "react"; + interface ShareButtonProps { url: string; title?: string; + className?: string; + showText?: boolean; + disabled?: boolean; + disabledStyle?: CSSProperties; + windowWidth?: number; + windowHeight?: number; + beforeOnClick?: () => void | Promise; + openShareDialogOnClick?: boolean; + onShareWindowClose?: () => void; + resetButtonStyle?: boolean; } export type { ShareButtonProps };