Forráskód Böngészése

feat: generic button export (#6092)

Co-authored-by: dwelle <luzar.david@gmail.com>
Barnabás Molnár 2 éve
szülő
commit
699897f71b

+ 8 - 0
src/components/Button.scss

@@ -0,0 +1,8 @@
+@import "../css/theme";
+
+.excalidraw {
+  .excalidraw-button {
+    @include outlineButtonStyles;
+    overflow: hidden;
+  }
+}

+ 35 - 0
src/components/Button.tsx

@@ -0,0 +1,35 @@
+import "./Button.scss";
+
+interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
+  type?: "button" | "submit" | "reset";
+  onSelect: () => any;
+  children: React.ReactNode;
+  className?: string;
+}
+
+/**
+ * A generic button component that follows Excalidraw's design system.
+ * Style can be customised using `className` or `style` prop.
+ * Accepts all props that a regular `button` element accepts.
+ */
+export const Button = ({
+  type = "button",
+  onSelect,
+  children,
+  className = "",
+  ...rest
+}: ButtonProps) => {
+  return (
+    <button
+      onClick={(event) => {
+        onSelect();
+        rest.onClick?.(event);
+      }}
+      type={type}
+      className={`excalidraw-button ${className}`}
+      {...rest}
+    >
+      {children}
+    </button>
+  );
+};

+ 12 - 19
src/components/CollabButton.scss

@@ -2,29 +2,22 @@
 
 .excalidraw {
   .collab-button {
-    @include outlineButtonStyles;
-    width: var(--lg-button-size);
-    height: var(--lg-button-size);
+    --button-bg: var(--color-primary);
+    --button-color: white;
+    --button-border: var(--color-primary);
 
-    svg {
-      width: var(--lg-icon-size);
-      height: var(--lg-icon-size);
-    }
-    background-color: var(--color-primary);
-    border-color: var(--color-primary);
-    color: white;
-    flex-shrink: 0;
+    --button-width: var(--lg-button-size);
+    --button-height: var(--lg-button-size);
 
-    &:hover {
-      background-color: var(--color-primary-darker);
-      border-color: var(--color-primary-darker);
-    }
+    --button-hover-bg: var(--color-primary-darker);
+    --button-hover-border: var(--color-primary-darker);
 
-    &:active {
-      background-color: var(--color-primary-darker);
-    }
+    --button-active-bg: var(--color-primary-darker);
+
+    flex-shrink: 0;
 
-    &.active {
+    // double .active to force specificity
+    &.active.active {
       background-color: #0fb884;
       border-color: #0fb884;
 

+ 4 - 3
src/components/CollabButton.tsx

@@ -3,6 +3,7 @@ import { UsersIcon } from "./icons";
 
 import "./CollabButton.scss";
 import clsx from "clsx";
+import { Button } from "./Button";
 
 const CollabButton = ({
   isCollaborating,
@@ -14,10 +15,10 @@ const CollabButton = ({
   onClick: () => void;
 }) => {
   return (
-    <button
+    <Button
       className={clsx("collab-button", { active: isCollaborating })}
       type="button"
-      onClick={onClick}
+      onSelect={onClick}
       style={{ position: "relative" }}
       title={t("labels.liveCollaboration")}
     >
@@ -25,7 +26,7 @@ const CollabButton = ({
       {collaboratorCount > 0 && (
         <div className="CollabButton-collaborators">{collaboratorCount}</div>
       )}
-    </button>
+    </Button>
   );
 };
 

+ 1 - 1
src/components/dropdownMenu/DropdownMenu.scss

@@ -73,7 +73,7 @@
       }
 
       &:hover {
-        background-color: var(--button-hover);
+        background-color: var(--button-hover-bg);
         text-decoration: none;
       }
 

+ 1 - 1
src/css/styles.scss

@@ -408,7 +408,7 @@
     pointer-events: all;
 
     &:hover {
-      background-color: var(--button-hover);
+      background-color: var(--button-hover-bg);
     }
 
     &:active {

+ 2 - 2
src/css/theme.scss

@@ -35,7 +35,7 @@
   --shadow-island: 0px 7px 14px rgba(0, 0, 0, 0.05),
     0px 0px 3.12708px rgba(0, 0, 0, 0.0798),
     0px 0px 0.931014px rgba(0, 0, 0, 0.1702);
-  --button-hover: var(--color-gray-10);
+  --button-hover-bg: var(--color-gray-10);
   --default-border-color: var(--color-gray-30);
 
   --default-button-size: 2rem;
@@ -135,7 +135,7 @@
     --popup-text-inverted-color: #2c2c2c;
     --select-highlight-color: #{$oc-blue-4};
     --text-primary-color: var(--color-gray-40);
-    --button-hover: var(--color-gray-80);
+    --button-hover-bg: var(--color-gray-80);
     --default-border-color: var(--color-gray-80);
     --shadow-island: 0px 13px 33px rgba(0, 0, 0, 0.07),
       0px 4.13px 9.94853px rgba(0, 0, 0, 0.0456112),

+ 15 - 11
src/css/variables.module.scss

@@ -39,11 +39,11 @@
 
   .ToolIcon__icon {
     &:hover {
-      background: var(--button-hover);
+      background: var(--button-hover-bg);
     }
 
     &:active {
-      background: var(--button-hover);
+      background: var(--button-hover-bg);
       border: 1px solid var(--color-primary-darkest);
     }
   }
@@ -54,24 +54,25 @@
   justify-content: center;
   align-items: center;
   padding: 0.625rem;
-  width: var(--default-button-size);
-  height: var(--default-button-size);
+  width: var(--button-width, var(--default-button-size));
+  height: var(--button-height, var(--default-button-size));
   box-sizing: border-box;
   border-width: 1px;
   border-style: solid;
-  border-color: var(--default-border-color);
+  border-color: var(--button-border, var(--default-border-color));
   border-radius: var(--border-radius-lg);
   cursor: pointer;
-  background-color: transparent;
-  color: var(--text-primary-color);
+  background-color: var(--button-bg, var(--island-bg-color));
+  color: var(--button-color, var(--text-primary-color));
 
   &:hover {
-    background-color: var(--button-hover);
+    background-color: var(--button-hover-bg);
+    border-color: var(--button-hover-border, var(--default-border-color));
   }
 
   &:active {
-    background-color: var(--button-hover);
-    border-color: var(--color-primary-darkest);
+    background-color: var(--button-active-bg);
+    border-color: var(--button-active-border, var(--color-primary-darkest));
   }
 
   &.active {
@@ -83,7 +84,10 @@
     }
 
     svg {
-      color: var(--color-primary-darker);
+      color: var(--button-color, var(--color-primary-darker));
+
+      width: var(--button-width, var(--lg-icon-size));
+      height: var(--button-height, var(--lg-icon-size));
     }
   }
 }

+ 10 - 0
src/packages/excalidraw/example/CustomFooter.tsx

@@ -1,5 +1,7 @@
 import { ExcalidrawImperativeAPI } from "../../../types";
 import { MIME_TYPES } from "../entry";
+import { Button } from "../../../components/Button";
+
 const COMMENT_SVG = (
   <svg
     xmlns="http://www.w3.org/2000/svg"
@@ -23,6 +25,14 @@ const CustomFooter = ({
 }) => {
   return (
     <>
+      <Button
+        onSelect={() => alert("General Kenobi!")}
+        className="you are a bold one"
+        style={{ marginLeft: "1rem" }}
+        title="Hello there!"
+      >
+        {COMMENT_SVG}
+      </Button>
       <button
         className="custom-element"
         onClick={() => {

+ 1 - 0
src/packages/excalidraw/index.tsx

@@ -239,6 +239,7 @@ export {
 } from "../../utils";
 
 export { Sidebar } from "../../components/Sidebar/Sidebar";
+export { Button } from "../../components/Button";
 export { Footer };
 export { MainMenu };
 export { useDevice } from "../../components/App";