npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dwelle/excalidraw-oss

v0.7.1

Published

Excalidraw as a React component

Downloads

3

Readme

Excalidraw

Excalidraw exported as a component to directly embed in your projects.

Installation

You can use npm

npm install react react-dom @excalidraw/excalidraw

or via yarn

yarn add react react-dom @excalidraw/excalidraw

After installation you will see a folder excalidraw-assets and excalidraw-assets-dev in dist directory which contains the assets needed for this app in prod and dev mode respectively.

Move the folder excalidraw-assets and excalidraw-assets-dev to the path where your assets are served.

By default it will try to load the files from https://unpkg.com/@excalidraw/excalidraw/{currentVersion}/dist/

If you want to load assets from a different path you can set a variable window.EXCALIDRAW_ASSET_PATH depending on environment (for example if you have different URL's for dev and prod) to the url from where you want to load the assets.

Demo

Try here.

Usage

Using Web Bundler

If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module as shown below

import React, { useEffect, useState, useRef } from "react";
import Excalidraw from "@excalidraw/excalidraw";
import InitialData from "./initialData";

import "./styles.scss";

export default function App() {
  const excalidrawRef = useRef(null);

  const [viewModeEnabled, setViewModeEnabled] = useState(false);
  const [zenModeEnabled, setZenModeEnabled] = useState(false);
  const [gridModeEnabled, setGridModeEnabled] = useState(false);

  const updateScene = () => {
    const sceneData = {
      elements: [
        {
          type: "rectangle",
          version: 141,
          versionNonce: 361174001,
          isDeleted: false,
          id: "oDVXy8D6rom3H1-LLH2-f",
          fillStyle: "hachure",
          strokeWidth: 1,
          strokeStyle: "solid",
          roughness: 1,
          opacity: 100,
          angle: 0,
          x: 100.50390625,
          y: 93.67578125,
          strokeColor: "#c92a2a",
          backgroundColor: "transparent",
          width: 186.47265625,
          height: 141.9765625,
          seed: 1968410350,
          groupIds: [],
        },
      ],
      appState: {
        viewBackgroundColor: "#edf2ff",
      },
    };
    excalidrawRef.current.updateScene(sceneData);
  };

  return (
    <div className="App">
      <h1> Excalidraw Example</h1>
      <div className="button-wrapper">
        <button className="update-scene" onClick={updateScene}>
          Update Scene
        </button>
        <button
          className="reset-scene"
          onClick={() => {
            excalidrawRef.current.resetScene();
          }}
        >
          Reset Scene
        </button>
        <label>
          <input
            type="checkbox"
            checked={viewModeEnabled}
            onChange={() => setViewModeEnabled(!viewModeEnabled)}
          />
          View mode
        </label>
        <label>
          <input
            type="checkbox"
            checked={zenModeEnabled}
            onChange={() => setZenModeEnabled(!zenModeEnabled)}
          />
          Zen mode
        </label>
        <label>
          <input
            type="checkbox"
            checked={gridModeEnabled}
            onChange={() => setGridModeEnabled(!gridModeEnabled)}
          />
          Grid mode
        </label>
      </div>
      <div className="excalidraw-wrapper">
        <Excalidraw
          ref={excalidrawRef}
          initialData={InitialData}
          onChange={(elements, state) =>
            console.log("Elements :", elements, "State : ", state)
          }
          onPointerUpdate={(payload) => console.log(payload)}
          onCollabButtonClick={() =>
            window.alert("You clicked on collab button")
          }
          viewModeEnabled={viewModeEnabled}
          zenModeEnabled={zenModeEnabled}
          gridModeEnabled={gridModeEnabled}
        />
      </div>
    </div>
  );
}

To view the full example visit :point_down:

Edit excalidraw

Since Excalidraw doesn't support server side rendering yet so you will have to make sure the component is rendered once host is mounted.

import { useState, useEffect } from "react";
export default function IndexPage() {
  const [Comp, setComp] = useState(null);
  useEffect(() => {
    import("@excalidraw/excalidraw").then((comp) => setComp(comp.default));
  });
  return <>{Comp && <Comp />}</>;
}

The types are available at @excalidraw/excalidraw/types, you can view example for typescript

In Browser

To use it in a browser directly:

For development use :point_down:

<script
  type="text/javascript"
  src="https://unpkg.com/@excalidraw/[email protected]/dist/excalidraw.development.js"
></script>

For production use :point_down:

<script
  type="text/javascript"
  src="https://unpkg.com/@excalidraw/[email protected]/dist/excalidraw.production.min.js"
></script>

You will need to make sure react, react-dom is available as shown in the below example. For prod please use the production versions of react, react-dom.

<!DOCTYPE html>
<html>
  <head>
    <title>Excalidraw in browser</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

    <script
      type="text/javascript"
      src="https://unpkg.com/@excalidraw/[email protected]/dist/excalidraw.development.js"
    ></script>
  </head>

  <body>
    <div class="container">
      <h1>Excalidraw Embed Example</h1>
      <div id="app"></div>
    </div>
    <script type="text/javascript" src="src/index.js"></script>
  </body>
</html>
/*eslint-disable */
import "./styles.css";
import InitialData from "./initialData";

const App = () => {
  const excalidrawRef = React.useRef(null);

  const [viewModeEnabled, setViewModeEnabled] = React.useState(false);
  const [zenModeEnabled, setZenModeEnabled] = React.useState(false);
  const [gridModeEnabled, setGridModeEnabled] = React.useState(false);

  const updateScene = () => {
    const sceneData = {
      elements: [
        {
          type: "rectangle",
          version: 141,
          versionNonce: 361174001,
          isDeleted: false,
          id: "oDVXy8D6rom3H1-LLH2-f",
          fillStyle: "hachure",
          strokeWidth: 1,
          strokeStyle: "solid",
          roughness: 1,
          opacity: 100,
          angle: 0,
          x: 100.50390625,
          y: 93.67578125,
          strokeColor: "#c92a2a",
          backgroundColor: "transparent",
          width: 186.47265625,
          height: 141.9765625,
          seed: 1968410350,
          groupIds: [],
        },
      ],
      appState: {
        viewBackgroundColor: "#edf2ff",
      },
    };
    excalidrawRef.current.updateScene(sceneData);
  };

  return React.createElement(
    React.Fragment,
    null,
    React.createElement(
      "div",
      { className: "button-wrapper" },
      React.createElement(
        "button",
        {
          className: "update-scene",
          onClick: updateScene,
        },
        "Update Scene",
      ),
      React.createElement(
        "button",
        {
          className: "reset-scene",
          onClick: () => excalidrawRef.current.resetScene(),
        },
        "Reset Scene",
      ),
      React.createElement(
        "label",
        null,
        React.createElement("input", {
          type: "checkbox",
          checked: viewModeEnabled,
          onChange: () => setViewModeEnabled(!viewModeEnabled),
        }),
        "View mode",
      ),
      React.createElement(
        "label",
        null,
        React.createElement("input", {
          type: "checkbox",
          checked: zenModeEnabled,
          onChange: () => setZenModeEnabled(!zenModeEnabled),
        }),
        "Zen mode",
      ),
      React.createElement(
        "label",
        null,
        React.createElement("input", {
          type: "checkbox",
          checked: gridModeEnabled,
          onChange: () => setGridModeEnabled(!gridModeEnabled),
        }),
        "Grid mode",
      ),
    ),
    React.createElement(
      "div",
      {
        className: "excalidraw-wrapper",
        ref: excalidrawWrapperRef,
      },
      React.createElement(Excalidraw.default, {
        initialData: InitialData,
        onChange: (elements, state) =>
          console.log("Elements :", elements, "State : ", state),
        onPointerUpdate: (payload) => console.log(payload),
        onCollabButtonClick: () => window.alert("You clicked on collab button"),
        viewModeEnabled: viewModeEnabled,
        zenModeEnabled: zenModeEnabled,
        gridModeEnabled: gridModeEnabled,
      }),
    ),
  );
};

const excalidrawWrapper = document.getElementById("app");

ReactDOM.render(React.createElement(App), excalidrawWrapper);

To view the full example visit :point_down:

Edit excalidraw-in-browser

Props

| Name | Type | Default | Description | | --- | --- | --- | --- | | onChange | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. | | initialData | {elements?: ExcalidrawElement[], appState?: AppState } | null | The initial data with which app loads. | | ref | createRef or callbackRef or { current: { readyPromise: resolvablePromise } } | | Ref to be passed to Excalidraw | | onCollabButtonClick | Function | | Callback to be triggered when the collab button is clicked | | isCollaborating | boolean | | This implies if the app is in collaboration mode | | onPointerUpdate | Function | | Callback triggered when mouse pointer is updated. | | onExportToBackend | Function | | Callback triggered when link button is clicked on export dialog | | langCode | string | en | Language code string | | renderFooter | Function | | Function that renders custom UI footer | | renderCustomStats | Function | | Function that can be used to render custom stats on the stats dialog. | | viewModeEnabled | boolean | | This implies if the app is in view mode. | | zenModeEnabled | boolean | | This implies if the zen mode is enabled | | gridModeEnabled | boolean | | This implies if the grid mode is enabled | | libraryReturnUrl | string | | What URL should libraries.excalidraw.com be installed to | | theme | light or dark | | The theme of the Excalidraw component | | name | string | | Name of the drawing | | UIOptions | { canvasActions: CanvasActions } | DEFAULT UI OPTIONS | To customise UI options. Currently we support customising canvas actions | | onPaste | (data: ClipboardData, event: ClipboardEvent | null) => boolean | | Callback to be triggered if passed when the something is pasted in to the scene | | detectScroll | boolean | true | Indicates whether to update the offsets when nearest ancestor is scrolled. | | handleKeyboardGlobally | boolean | false | Indicates whether to bind the keyboard events to document. | | onLibraryChange | (items: LibraryItems) => void | Promise<any> | | The callback if supplied is triggered when the library is updated and receives the library items. |

Dimensions of Excalidraw

Excalidraw takes 100% of width and height of the containing block so make sure the container in which you render Excalidraw has non zero dimensions.

onChange

Every time component updates, this callback if passed will get triggered and has the below signature.

(excalidrawElements, appState) => void;

1.excalidrawElements: Array of excalidrawElements in the scene.

2.appState: AppState of the scene

Here you can try saving the data to your backend or local storage for example.

initialData

This helps to load Excalidraw with initialData. It must be an object or a promise which resolves to an object containing the below optional fields.

| Name | Type | Descrption | | --- | --- | --- | | elements | ExcalidrawElement[] | The elements with which Excalidraw should be mounted. | | appState | AppState | The App state with which Excalidraw should be mounted. | | scrollToContent | boolean | This attribute implies whether to scroll to the nearest element to center once Excalidraw is mounted. By default, it will not scroll the nearest element to the center. Make sure you pass initialData.appState.scrollX and initialData.appState.scrollY when scrollToContent is false so that scroll positions are retained | | libraryItems | LibraryItems | This library items with which Excalidraw should be mounted. |

{
  "elements": [
    {
      "type": "rectangle",
      "version": 141,
      "versionNonce": 361174001,
      "isDeleted": false,
      "id": "oDVXy8D6rom3H1-LLH2-f",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 100.50390625,
      "y": 93.67578125,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 186.47265625,
      "height": 141.9765625,
      "seed": 1968410350,
      "groupIds": []
    }
  ],
  "appState": { "zenModeEnabled": true, "viewBackgroundColor": "#AFEEEE" }
}

You might want to use this when you want to load excalidraw with some initial elements and app state.

ref

You can pass a ref when you want to access some excalidraw APIs. We expose the below APIs:

| API | signature | Usage | | --- | --- | --- | | ready | boolean | This is set to true once Excalidraw is rendered | | readyPromise | resolvablePromise | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown here | | updateScene | (sceneData)) => void | updates the scene with the sceneData | | resetScene | ({ resetLoadingState: boolean }) => void | Resets the scene. If resetLoadingState is passed as true then it will also force set the loading state to false. | | getSceneElementsIncludingDeleted | () => ExcalidrawElement[] | Returns all the elements including the deleted in the scene | | getSceneElements | () => ExcalidrawElement[] | Returns all the elements excluding the deleted in the scene | | getAppState | () => AppState | Returns current appState | | history | { clear: () => void } | This is the history API. history.clear() will clear the history | | scrollToContent | (target?: ExcalidrawElement | ExcalidrawElement[]) => void | Scroll the nearest element out of the elements supplied to the center. Defaults to the elements on the scene. | | refresh | () => void | Updates the offsets for the Excalidraw component so that the coordinates are computed correctly (for example the cursor position). You don't have to call this when the position is changed on page scroll or when the excalidraw container resizes (we handle that ourselves). For any other cases if the position of excalidraw is updated (example due to scroll on parent container and not page scroll) you should call this API. | | importLibrary | (url: string, token?: string) => void | Imports library from given URL | | setToastMessage | (message: string) => void | This API can be used to show the toast with custom message. | | id | string | Unique ID for the excalidraw component. |

readyPromise

onCollabButtonClick

This callback is triggered when clicked on the collab button in excalidraw. If not supplied, the collab dialog button is not rendered.

isCollaborating

This prop indicates if the app is in collaboration mode.

onPointerUpdate

This callback is triggered when mouse pointer is updated.

({ x, y }, button, pointersMap}) => void;

1.{x, y}: Pointer coordinates

2.button: The position of the button. This will be one of ["down", "up"]

3.pointersMap: pointers map of the scene

onExportToBackend

This callback is triggered when the shareable-link button is clicked in the export dialog. The link button will only be shown if this callback is passed.

(exportedElements, appState, canvas) => void
  1. exportedElements: An array of non deleted elements which needs to be exported.
  2. appState: AppState of the scene.
  3. canvas: The HTMLCanvasElement of the scene.

langCode

Determines the language of the UI. It should be one of the available language codes. Defaults to en (English). We also export default language and supported languages which you can import as shown below.

import { defaultLang, languages } from "@excalidraw/excalidraw";

| name | type | | --- | --- | | defaultLang | string | | languages | Language[] |

renderFooter

A function that renders (returns JSX) custom UI footer. For example, you can use this to render a language picker that was previously being rendered by Excalidraw itself (for now, you'll need to implement your own language picker).

renderCustomStats

A function that can be used to render custom stats (returns JSX) in the nerd stats dialog. For example you can use this prop to render the size of the elements in the storage.

viewModeEnabled

This prop indicates whether the app is in view mode. When supplied, the value takes precedence over intialData.appState.viewModeEnabled, the view mode will be fully controlled by the host app, and users won't be able to toggle it from within the app.

zenModeEnabled

This prop indicates whether the app is in zen mode. When supplied, the value takes precedence over intialData.appState.zenModeEnabled, the zen mode will be fully controlled by the host app, and users won't be able to toggle it from within the app.

gridModeEnabled

This prop indicates whether the shows the grid. When supplied, the value takes precedence over intialData.appState.gridModeEnabled, the grid will be fully controlled by the host app, and users won't be able to toggle it from within the app.

libraryReturnUrl

If supplied, this URL will be used when user tries to install a library from libraries.excalidraw.com. Defaults to window.location.origin + window.location.pathname. To install the libraries in the same tab from which it was opened, you need to set window.name (to any alphanumeric string) — if it's not set it will open in a new tab.

theme

This prop controls Excalidraw's theme. When supplied, the value takes precedence over intialData.appState.theme, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app.

name

This prop sets the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over intialData.appState.name, the name will be fully controlled by host app and the users won't be able to edit from within Excalidraw.

UIOptions

This prop can be used to customise UI of Excalidraw. Currently we support customising only canvasActions. It accepts the below parameters

canvasActions

| Attribute | Type | Default | Description | | --- | --- | --- | --- | | changeViewBackgroundColor | boolean | true | Implies whether to show Background color picker | | clearCanvas | boolean | true | Implies whether to show Clear canvas button | | export | boolean | true | Implies whether to show Export button | | loadScene | boolean | true | Implies whether to show Load button | | saveAsScene | boolean | true | Implies whether to show Save as button | | saveScene | boolean | true | Implies whether to show Save button | | theme | boolean | true | Implies whether to show Theme toggle |

onPaste

This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs.

This callback must return a boolean value or a promise which resolves to a boolean value.

In case you want to prevent the excalidraw paste action you must return true, it will stop the native excalidraw clipboard management flow (nothing will be pasted into the scene).

Does it support collaboration ?

No Excalidraw package doesn't come with collaboration, since this would have different implementations on the consumer so we expose the API's which you can use to communicate with Excalidraw as mentioned above. If you are interested in understanding how Excalidraw does it you can check it here.

importLibrary

Imports library from given URL. You should call this on hashchange, passing the addLibrary value if you detect it as shown below. Optionally pass a CSRF token to skip prompting during installation (retrievable via token key from the url coming from https://libraries.excalidraw.com).

useEffect(() => {
  const onHashChange = () => {
    const hash = new URLSearchParams(window.location.hash.slice(1));
    const libraryUrl = hash.get("addLibrary");
    if (libraryUrl) {
      excalidrawRef.current.importLibrary(libraryUrl, hash.get("token"));
    }
  };
  window.addEventListener("hashchange", onHashChange, false);
  return () => {
    window.removeEventListener("hashchange", onHashChange);
  };
}, []);

Try out the Demo to see it in action.

detectScroll

Indicates whether Excalidraw should listen for scroll event on the nearest scrollable container in the DOM tree and recompute the coordinates (e.g. to correctly handle the cursor) when the component's position changes. You can disable this when you either know this doesn't affect your app or you want to take care of it yourself (calling the refresh() method).

handleKeyboardGlobally

Indicates whether to bind keyboard events to document. Disabled by default, meaning the keyboard events are bound to the Excalidraw component. This allows for multiple Excalidraw components to live on the same page, and ensures that Excalidraw keyboard handling doesn't collide with your app's (or the browser) when the component isn't focused.

Enable this if you want Excalidraw to handle keyboard even if the component isn't focused (e.g. a user is interacting with the navbar, sidebar, or similar).

onLibraryChange

Ths callback if supplied will get triggered when the library is updated and has the below signature.

It is invoked with empty items when user clears the library. You can use this callback when you want to do something additional when library is updated for example persisting it to local storage.

id

The unique id of the excalidraw component. This can be used to identify the excalidraw component, for example importing the library items to the excalidraw component from where it was initiated when you have multiple excalidraw components rendered on the same page as shown in multiple excalidraw demo.

Extra API's

getSceneVersion

How to use

This function returns the current scene version.

isInvisiblySmallElement

Signature

How to use

import { isInvisiblySmallElement } from "@excalidraw/excalidraw";

Returns true if element is invisibly small (e.g. width & height are zero).

getElementMap

Signature

How to use

import { getElementsMap } from "@excalidraw/excalidraw";

This function returns an object where each element is mapped to its id.

Restore utilities

restoreAppState

Signature

How to use

import { restoreAppState } from "@excalidraw/excalidraw";

This function will make sure all the keys have appropriate values in appState and if any key is missing, it will be set to default value. If you pass localAppState, localAppState value will be preferred over the appState passed in params.

restoreElements

Signature

How to use

import { restoreElements } from "@excalidraw/excalidraw";

This function will make sure all properties of element is correctly set and if any attribute is missing, it will be set to default value.

restore

Signature

How to use

import { restore } from "@excalidraw/excalidraw";

This function makes sure elements and state is set to appropriate values and set to default value if not present. It is combination of restoreElements and restoreAppState

Export utilities

exportToCanvas

Signature

| Name | Type | Default | Description | | --- | --- | --- | --- | | elements | Excalidraw Element [] | | The elements to be exported to canvas | | appState | AppState | defaultAppState | The app state of the scene | | getDimensions | (width: number, height: number) => {width: number, height: number, scale: number) | (width, height) => ({ width, height, scale: 1 }) | A function which returns the width, height and scale with which canvas is to be exported. |

How to use

import { exportToCanvas } from "@excalidraw/excalidraw";

This function returns the canvas with the exported elements, appState and dimensions.

exportToBlob

Signature

| Name | Type | Default | Description | | --- | --- | --- | --- | | opts | | | This param is passed to exportToCanvas. You can refer to exportToCanvas | | mimeType | string | "image/png" | Indicates the image format | | quality | number | 0.92 | A value between 0 and 1 indicating the image quality. Applies only to image/jpeg/image/webp MIME types. |

How to use

import { exportToBlob } from "@excalidraw/excalidraw";

Returns a promise which resolves with a blob. It internally uses canvas.ToBlob.

exportToSvg

Signature

| Name | Type | Default | Description | | --- | --- | --- | --- | | elements | Excalidraw Element [] | | The elements to exported as svg | | appState | AppState | defaultAppState | The app state of the scene | | exportPadding | number | 10 | The padding to be added on canvas | | metadata | string | '' | The metadata to be embedded in svg |

This function returns a svg with the exported elements.

Additional attributes of appState for export\* APIs

| Name | Type | Default | Description | | --- | --- | --- | --- | | exportBackground | boolean | true | Indicates whether background should be exported | | viewBackgroundColor | string | #fff | The default background color | | shouldAddWatermark | boolean | false | Indicates whether watermark should be exported | | exportWithDarkMode | boolean | false | Indicates whether to export with dark mode |