Toolbar UI

Toolbar is a UI components to change elements on the canvas, reorder and align them, apply undo/redo.

Basic usage:

import Toolbar from 'polotno/toolbar/toolbar';
import Workspace from 'polotno/canvas/workspace';

const App = ({ store }) => {
  return (
    <div
      style={{
        display: 'flex',
        height: '100%',
        margin: 'auto',
        flex: 1,
        flexDirection: 'column',
        position: 'relative',
      }}
    >
      <Toolbar store={store} />
      <Workspace store={store} />
    </div>
  );
};

Also Toolbar component has additional properties to hide some elements and overwrite inputs for some properties.

type ToolbarProps = {
  store: StoreType,
  downloadButtonEnabled?: Boolean,
  // see how to use it in the example below
  components?: any,
};

// example
<Toolbar store={store} downloadButtonEnabled />;


How to overwrite available inputs for an element type?

Toolbar supports special components property to add/change/remove most of its UI components.

In some application you may want to change available properties for selected element type. E.g. you may want to display a different color picker for text element. Just pass a component in format TypeName e.g. TextFill. You can use all built-element types as Text, Image, Svg. But also you can use Many prefix when several elements are selected. Also you can define your own new components for any element type. E.g. ImageAlertButton

There are several built-in components but also you can add your own.

text element:
  TextFontFamily
  TextFontSize
  TextFontVariant
  TextFilters
  TextFill
  TextSpacing
  TextAnimations
  TextAiWrite

image elements
  ImageFlip
  ImageFilters
  ImageFitToBackground
  ImageCrop
  ImageClip
  ImageRemoveBackground
  ImageAnimations

svg element:
  SvgFlip
  SvgFilters
  SvgColors
  SvgAnimations

line element:
  LineSettings
  LineColor
  LineHeads
  LineAnimations

figure element:
  FigureFill
  FigureStroke
  FigureSettings
  FigureFilters
  FigureAnimations

video element:
  VideoTrim
  VideoAnimations

many elements selected:
  ManyAnimations

page (no elements selected):
  PageDuration

common:
  History
  Group
  Position
  Opacity
  Lock
  Duplicate
  Remove
import Toolbar from 'polotno/toolbar/toolbar';
import Workspace from 'polotno/canvas/workspace';
import { observer } from 'mobx-react-lite';

const MyColorPicker = observer(({ store, element, elements }) => {
  // store - main polotno store object
  // elements - array of selected elements. The same as store.selectedElements
  // element - first selected element. The same as store.selectedElements[0]
  return (
    <div>
      <input
        type="color"
        value={element.fill}
        onChange={(e) => {
          element.set({
            fill: e.target.value,
          });
        }}
      />
    </div>
  );
});

// as example lets disable font size input for text element
// just return null from your component
const TextTextFontSize = () => null;

// also we can invent our own new component
const TextAlertButton = observer(({ store, element, elements }) => {
  return (
    <button
      onClick={() => {
        alert('Hello!');
      }}
    >
      Alert
    </button>
  );
});

// also we can disable default Undo/Redo buttons via History component
const History = () => null;

const App = ({ store }) => {
  return (
    <div
      style={{
        display: 'flex',
        height: '100%',
        margin: 'auto',
        flex: 1,
        flexDirection: 'column',
        position: 'relative',
      }}
    >
      <Toolbar
        store={store}
        components={{
          TextFill: MyColorPicker,
          TextTextFontSize,
          TextAlertButton,
          History,
        }}
      />
      <Workspace store={store} />
    </div>
  );
};


How to overwrite all inputs at once?

Following Custom Element Example, you can make your own React component for any available element.

Recommendation: leverage blueprintjs components to build your own UI and use <Navbar.Group> to group inputs. Also remember to wrap your component in observer from mobx-react-lite library to add automatic reactivity of your components.

Example:

import React from 'react';
import { observer } from 'mobx-react-lite';
import { NumericInput, Navbar, Alignment } from '@blueprintjs/core';

import ColorPicker from 'polotno/toolbar/color-picker';
import { unstable_registerToolbarComponent } from 'polotno/config';

const TextToolbar = observer(({ store }) => {
  const element = store.selectedElements[0];

  return (
    <Navbar.Group align={Alignment.LEFT}>
      <ColorPicker
        value={element.fill}
        onChange={(fill) =>
          element.set({
            fill,
          })
        }
        store={store}
      />
      <NumericInput
        onValueChange={(fontSize) => {
          element.set({ fontSize: fontSize });
        }}
        value={element.fontSize}
        style={{ width: '50px', marginLeft: '10px' }}
        min={1}
        max={40}
      />
    </Navbar.Group>
  );
});

unstable_registerToolbarComponent('text', TextToolbar);


How to overwrite 'Download; button

On the right side of the toolbar, Polotno has 'Action Controls' section. You can use components prop to overwrite this section.

Recommendation: keep 'Action Controls' as small as possible. <Toolbar /> component already has a lot of tools. So it is better give it as much available width as possible. You can put 'Action Controls" somewhere else in the UI of your application. For example, take a look into https://studio.polotno.com/. Download button is placed on the top of the app instead of the <Toolbar />.

import { Toolbar } from 'polotno/toolbar/toolbar';
import { Button } from '@blueprintjs/core';
import { DownloadButton } from 'polotno/toolbar/download-button';

// it is important to define component onside of `MyToolbar` render function
const ActionControls = ({ store }) => {
  return (
    <div>
      <DownloadButton store={store} />
      <Button
        intent="primary"
        onClick={() => {
          alert('Saving');
        }}
      >
        Save
      </Button>
    </div>
  );
};

const MyToolbar = ({ store }) => {
  return (
    <Toolbar
      store={store}
      components={{
        ActionControls,
      }}
    />
  );
};

News, updates and promos – be the first to get 'em

News, updates and promos – be the first to get 'em