diff --git a/react-common/components/controls/Button.tsx b/react-common/components/controls/Button.tsx index 19497d70c712..bbb799fb70d2 100644 --- a/react-common/components/controls/Button.tsx +++ b/react-common/components/controls/Button.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { classList, ContainerProps, fireClickOnEnter } from "../util"; export interface ButtonViewProps extends ContainerProps { - buttonRef?: (ref: HTMLButtonElement) => void; + buttonRef?: (ref: HTMLButtonElement | HTMLAnchorElement) => void; title: string; label?: string | JSX.Element; labelClassName?: string; @@ -14,6 +14,7 @@ export interface ButtonViewProps extends ContainerProps { target?: string; tabIndex?: number; style?: React.CSSProperties; + asAnchorElement?: boolean; /** Miscellaneous aria pass-through props */ ariaControls?: string; @@ -53,15 +54,11 @@ export const Button = (props: ButtonProps) => { onBlur, buttonRef, title, - label, - labelClassName, - leftIcon, - rightIcon, hardDisabled, href, target, tabIndex, - children + asAnchorElement } = props; let { @@ -78,44 +75,87 @@ export const Button = (props: ButtonProps) => { ); let clickHandler = (ev: React.MouseEvent) => { - if (onClick) onClick(); - if (href) window.open(href, target || "_blank", "noopener,noreferrer") ev.stopPropagation(); + + if (onClick) { + onClick(); + } + if (href) { + if (asAnchorElement) { + // handled using the href attribute, so don't prevent default + return; + } + window.open(href, target || "_blank", "noopener,noreferrer"); + } ev.preventDefault(); } + const elementProps = { + id: id, + className: classes, + style: style, + title: title, + ref: buttonRef, + onClick: !disabled ? clickHandler : undefined, + onKeyDown: onKeydown || fireClickOnEnter, + onBlur: onBlur, + role: role || (asAnchorElement ? undefined : "button"), + tabIndex: tabIndex || (disabled ? -1 : 0), + disabled: hardDisabled, + "aria-label": ariaLabel, + "aria-hidden": ariaHidden, + "aria-controls": ariaControls, + "aria-expanded": ariaExpanded, + "aria-haspopup": ariaHasPopup as any, + "aria-posinset": ariaPosInSet, + "aria-setsize": ariaSetSize, + "aria-describedby": ariaDescribedBy, + "aria-selected": ariaSelected, + "aria-pressed": ariaPressed, + } + + if (asAnchorElement) { + return ( + + + + ); + } + return ( ); +} + +const ButtonBody = (props: ButtonViewProps) => { + const { + label, + labelClassName, + leftIcon, + rightIcon, + children + } = props; + return ( + <> + {(leftIcon || rightIcon || label) && ( + + {leftIcon && } + + {label} + + {rightIcon && } + + )} + {children} + + ) } \ No newline at end of file diff --git a/react-common/components/share/SocialButton.tsx b/react-common/components/share/SocialButton.tsx index 1d5b51ac3ba7..6423b0b44d9e 100644 --- a/react-common/components/share/SocialButton.tsx +++ b/react-common/components/share/SocialButton.tsx @@ -14,71 +14,82 @@ export const SocialButton = (props: SocialButtonProps) => { const classes = classList(className, "social-button", "type") - const handleClick = () => { + const getSocialUrl = () => { const socialOptions = pxt.appTarget.appTheme.socialOptions; - let socialUrl = ''; - pxt.tickEvent(`share.social.${type}`); switch (type) { case "facebook": { - socialUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`; - break; + return `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`; } case "twitter": { let twitterText = lf("Check out what I made!"); if (socialOptions.twitterHandle && socialOptions.orgTwitterHandle) { twitterText = lf("Check out what I made with @{0} and @{1}!", socialOptions.twitterHandle, socialOptions.orgTwitterHandle); - } else if (socialOptions.twitterHandle) { + } + else if (socialOptions.twitterHandle) { twitterText = lf("Check out what I made with @{0}!", socialOptions.twitterHandle); - } else if (socialOptions.orgTwitterHandle) { + } + else if (socialOptions.orgTwitterHandle) { twitterText = lf("Check out what I made with @{0}!", socialOptions.orgTwitterHandle); } - socialUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}` + + return `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}` + `&text=${encodeURIComponent(twitterText)}` + (socialOptions.hashtags ? `&hashtags=${encodeURIComponent(socialOptions.hashtags)}` : '') + (socialOptions.related ? `&related=${encodeURIComponent(socialOptions.related)}` : ''); - break; } case "discourse": { // https://meta.discourse.org/t/compose-a-new-pre-filled-topic-via-url/28074 - socialUrl = `${socialOptions.discourse || "https://forum.makecode.com/"}new-topic?title=${encodeURIComponent(url)}`; - if (socialOptions.discourseCategory) - socialUrl += `&category=${encodeURIComponent(socialOptions.discourseCategory)}`; - break; + let socialUrl = `${socialOptions.discourse || "https://forum.makecode.com/"}new-topic?title=${encodeURIComponent(url)}`; + if (socialOptions.discourseCategory) { + socialUrl += `&category=${encodeURIComponent(socialOptions.discourseCategory)}`; + } + return socialUrl; } case "google-classroom": - socialUrl = `https://classroom.google.com/share?url=${encodeURIComponent(url)}`; - break; + return `https://classroom.google.com/share?url=${encodeURIComponent(url)}`; case "microsoft-teams": - socialUrl = `https://teams.microsoft.com/share?href=${encodeURIComponent(url)}`; - break; + return `https://teams.microsoft.com/share?href=${encodeURIComponent(url)}`; case "whatsapp": - socialUrl = `https://api.whatsapp.com/send?text=${encodeURIComponent(url)}`; - break; + return `https://api.whatsapp.com/send?text=${encodeURIComponent(url)}`; } - pxt.BrowserUtils.popupWindow(socialUrl, heading, 600, 600); } + const handleClick = () => { + pxt.tickEvent(`share.social.${type}`); + } + + const useLink = pxt.BrowserUtils.isInGame(); + switch (type) { // Icon buttons case "facebook": case "twitter": case "discourse": case "whatsapp": - return