Docs
API Docs

Components

One of the main features of PhotoEditorSDK is the capability to customize the colors and fonts and different components of the UI.

Please refer to the nomenclature for a better understanding of the naming convention.

The following components can be customised and replaced in the configuration:

  • AdvancedUICategoryCard
  • AdvancedUIItemCard
  • AdvancedUIToolbarItem
  • ColorItem
  • Checkbox
  • Loader
  • Buttons
    • MainCanvasActionUndo
    • MainCanvasActionRedo
    • MainCanvasActionExport
    • MainCanvasActionClose
    • CanvasActionEdit
    • CanvasActionBringToFront
    • CanvasActionDuplicate
    • CanvasActionDelete
    • CanvasActionInvert
    • CanvasActionFlip
    • TransformActionFlipHorizontal
    • TransformActionFlipVertical
    • TransformActionRotateClockwise
    • TransformActionRotateAntiClockwise
    • TextAlignment
    • ToolControlBarPrimaryButton
    • ToolControlBarSecondaryButton

Styling

The custom components are also part of the styled-components theme context and can use the values which are defined in the theme.

import { Buttons } from "photoeditorsdk";
import styled from "styled-components";

const ExportButton = styled(Buttons.ContainedPrimaryButton)`
  color: ${({ theme }) => theme.button.containedPrimaryForeground}
  background: ${({ theme }) => theme.button.containedPrimaryBackground}
`;

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      buttons: {
        mainCanvasActionExport: ExportButton,
      },
    },
  },
});

It is also possible to style the default components through the className or style props.

Replacing Components

The components in the the configuration can be replaced by any React component and will receive the same props as the default components.

The photoeditorsdk package exports all default components which makes it quite easy to modify the behaviour of certain parts of the app.

e.g.:

import { AdvancedUIItemCard } from "photoeditorsdk";

const ItemCard = ({ onClick, tool, ...props }) => {
  const handleClick = () => {
    if (tool === "sticker") {
      // add your custom click handeling here
    }
    onClick();
  };

  return <ItemCard {...props} onClick={handleClick} tool={tool} />;
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      advancedUIItemCard: ItemCard,
    },
  },
});

The following components are available in the photoeditorsdk package:

AdvancedUICategoryCard,
AdvancedUIItemCard,
AdvancedUICardLabel,
AdvancedUIToolbarItem,
Loader,
CanvasBarTextSecondaryButton,
ContainedPrimaryButton,
OutlinedPrimaryButton,
OutlinedSecondaryButton,
SpriteActionButton,
IconButton,
ColorItem,
ColorItemActiveOverlay,
ColorItemBase,
ColorItemBackground,
ColorItemTiledBackground,
Checkbox,
CheckboxCheckMark,
CheckboxBase,
CheckboxInput,
Label,

Category Card in AdvancedUI

This will replace the category cards in the toolControlBar.

The React component will receive the following props:

{
  tool: Tool
  label: string
  image?: string
  isActive?: boolean
  type: CardType
  isDisabled?: boolean
  onClick: (e?: React.MouseEvent<HTMLButtonElement>) => void
  className?: string
  style?: { [key: string]: string }
  children?: React.ReactNode
}
import React from "react";
import styled from "styled-components";
import { CustomCardProps, AdvancedUICategoryCard } from "photoeditorsdk";

const Card = styled(AdvancedUICategoryCard)`
  height: 50px;
  width: 180px;
  border-radius: 16px;
  margin-bottom: 16px;
`;

const Label = styled.div<{ isActive: boolean | void }>`
  width: 180px;
  text-align: center;
  font-size: 12px;
  margin-bottom: 10px;
  color: ${(props) =>
    props.isActive ? props.theme.primary : props.theme.card.labelForeground};
`;

const CategoryCard: React.FC<CustomCardProps> = ({
  label,
  isActive,
  children,
  ...props
}) => (
  <div>
    <Label isActive={isActive}>{label}</Label>
    <Card {...props} isActive={isActive} />
  </div>
);

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      advancedUICategoryCard: CategoryCard,
    },
  },
});

Item Card in AdvancedUI

This will replace the item cards in the toolControlBar.

The React component will receive the following props:

{
  tool: Tool
  label?: string
  image?: string
  isActive?: boolean
  type: CardType
  isDisabled?: boolean
  onClick: (e?: React.MouseEvent<HTMLButtonElement>) => void
  className?: string
  style?: { [key: string]: string }
  children?: React.ReactNode
}
import React from "react";
import styled from "styled-components";
import { CustomCardProps, AdvancedUIItemCard, Tool } from "photoeditorsdk";

const Container = styled.div`
  margin-bottom: 10px;
  &:nth-child(2n + 1) {
    margin-right: ${(props) =>
      props.theme.measurements.advancedSpacer}px !important;
  }
`;

const CardStyles = styled(AdvancedUIItemCard).attrs((props) => {
  const style: any = {};
  if (props.image) {
    style.backgroundImage = `url(${props.image})`;
  }
  if (props.isActive) {
    style.border = `2px solid ${props.theme.primary}`;
  }
  return { style };
})`
  height: 87px;
  width: 87px;
  padding: 5px;
  border-radius: 50%;
  margin-right: 0px !important;
  background-position: center center;
  background-repeat: no-repeat;
  background-clip: content-box;
`;

const Label = styled.div`
  max-width: 80px;
  text-align: center;
  font-size: 12px;
  margin-bottom: 10px;
`;

const ItemCard: React.FC<CustomCardProps> = ({
  label,
  children,
  tool,
  style,
  ...props
}) => {
  if (tool === Tool.FRAME && style) {
    style.backgroundSize = "55%";
  }

  return (
    <Container>
      <CardStyles {...props} tool={tool} style={style} />
      <Label>{label}</Label>
    </Container>
  );
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      advancedUIItemCard: ItemCard,
    },
  },
});

Toolbar Item in AdvancedUI

This will replace the icons in the toolbar. Available only in AdvancedUI.

The React component will receive the following props:

{
  tool: string
  label: string
  icon: React.ReactNode
  isActive: boolean
  isReverse: boolean
  style?: { [key: string]: string }
  onClick: (e?: React.MouseEvent<HTMLButtonElement>) => void
}

You can choose to use the default icons or replace them with your own icons.

import React from "react";
import styled, { css } from "styled-components";

import { CustomToolbarItemProps, AdvancedUIToolbarItem } from "photoeditorsdk";

const Item = styled(AdvancedUIToolbarItem)`
  height: 48px;
  width: 48px;
  margin: 4px;
  * button {
    border-radius: 50%;
    background: transparent;
    color: ${(props) => props.theme.foreground};
  }
  ${(props) => {
    if (props.isActive) {
      return css`
        * button {
          color: white !important;
          background: ${props.theme.primary};
        }
      `;
    }
    return "";
  }}
`;

const Container = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

const Label = styled.div`
  max-width: 48px;
  text-align: center;
  font-size: 12px;
  margin-bottom: 10px;
  margin: 4px;
`;

const ToolbarItem: React.FC<CustomToolbarItemProps> = ({
  label,
  isActive,
  ...props
}) => {
  return (
    <Container>
      <Item label={label} isActive={isActive} {...props} />
      <Label>{label}</Label>
    </Container>
  );
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    measurements: {
      advancedUIToolbar: {
        width: 80,
      },
    },
    components: {
      advancedUIToolbarItem: ToolbarItem,
    },
  },
});

ColorItem

This will replace the items which are used to select a color in the Text, Text Design, Sticker, Frame and Brush tool. Available in both AdvancedUI and BasicUI

The PhotoEditorSDK exports the default ColorItem and also all components which are used to build the ColorItem.

The React component will receive the following props:

{
  color: string
  label: string
  isActive: boolean
  isDisabled: boolean
  tiledBackgroundUrl: string
  onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
  className?: string
  style?: { [key: string]: string }
  children?: React.ReactNode
}

Modifying the default ColorItem

import React from "react";
import styled from "styled-components";
import { ColorItem, CustomColorItemProps } from "photoeditorsdk";

const CustomColorItem = styled(ColorItem)<CustomColorItemProps>`
  margin: 8px;
`;

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      colorItem: CustomColorItem,
    },
  },
});

Building your own ColorItem

This example will use the following child components of the ColorItem:

  • ColorItemBase: This is a container which will handle the onClick behaviour
  • ColorItemBackground: This component will display the current color
  • ColorItemTiledBackground: This component will display the tiled background for transparent colors
  • ColorItemActiveOverlay: This component will display the border around the ColorItem
import React from "react";
import styled from "styled-components";

import {
  CustomColorItemProps,
  CustomConfiguration,
  ColorItemActiveOverlay,
  ColorItemBase,
  ColorItemBackground,
  ColorItemTiledBackground,
} from "photoeditorsdk";

const ActiveOverlay = styled(ColorItemActiveOverlay)`
  box-sizing: content-box;
  padding: 2px;
  left: -4px;
  top: -4px;
`;

export const CustomColorItem: React.FC<CustomColorItemProps> = ({
  label,
  color,
  isActive,
  isDisabled,
  tiledBackgroundUrl,
  onClick,
}) => {
  return (
    <ColorItemBase onClick={onClick} disabled={isDisabled} aria-label={label}>
      <ColorItemBackground color={color} />
      <ColorItemTiledBackground url={tiledBackgroundUrl} />
      <ActiveOverlay isActive={isActive} />
    </ColorItemBase>
  );
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    measurements: {
      colorItem: {
        size: 28,
      },
    },
    themes: {
      dark: {
        colorItem: {
          borderRadius: "50%",
          margin: "6px",
        },
      },
    },
    components: {
      colorItem: CustomColorItem,
    },
  },
});

Checkbox

This will replace all checkboxes which are used in the PhotoeditorSDK. Available in both AdvancedUI and BasicUI

The PhotoEditorSDK exports the default Checkbox and also all components which are used to build the Checkbox.

The React component will receive the following props:

{
  label: string
  value: boolean
  isDisabled?: boolean
  checkMarkPosition?: 'left' | 'right'
  onClick: (e?: React.SyntheticEvent) => void
  className?: string
  style?: { [key: string]: string }
  children?: React.ReactNode
}

Modifying the default Checkbox

import React from "react";
import styled from "styled-components";
import { Checkbox, CustomCheckboxProps } from "photoeditorsdk";

const CustomCheckbox = styled(Checkbox)<CustomCheckboxProps>`
  margin: 8px;
`;

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      checkbox: CustomCheckbox,
    },
  },
});

Building your own Checkbox

This example will use the following child components of the ColorItem:

  • CheckboxBase: This is a container around the child components
  • CheckboxCheckMark: This component will display the checkmark
  • CheckboxInput: This component is used for accessibility
  • Label: This component will display the label next to the checkmark and is also clickable
import React from "react";
import styled from "styled-components";
import {
  CustomCheckbox,
  CheckboxCheckMark,
  CheckboxBase,
  CheckboxInput,
  Label,
} from "photoeditorsdk";

const Base = styled(CheckboxBase)`
  justify-content: unset;
`;

const CheckMark = styled(CheckboxCheckMark)`
  margin-right: 8px;
`;

const Checkbox: CustomCheckbox = ({
  label,
  value,
  isDisabled,
  onClick,
  ...props
}) => {
  const id = `photoeditorsdk-${label.replace(" ", "-")}`;

  const onChange = () => {
    onClick();
  };

  return (
    <Base {...props}>
      <CheckMark isDisabled={isDisabled} isChecked={value} onClick={onClick} />
      <Label isDisabled={isDisabled} label={label} htmlFor={id} />
      <CheckboxInput
        id={id}
        disabled={isDisabled}
        checked={value}
        onChange={onChange}
      />
    </Base>
  );
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      checkbox: Checkbox,
    },
  },
});

Loader

This will replace the initial loading screen. Available in both AdvancedUI and BasicUI.

The React component will receive the following props:

{
  show: boolean
  heading: string
  body: string
  position?: { x: number; y: number }
  className?: string
}
import React from "react";
import styled from "styled-components";

import { CustomLoaderProps } from "photoeditorsdk";

const Backdrop = styled.div<{ show: boolean }>`
  height: 100%;
  width: 100%;
  background: rgba(0, 0, 0, 0.6);
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  opacity: ${({ show }) => (show ? 1 : 0)};
`;

const LoaderStyles = styled.div`
  background: white;
  position: absolute;
  z-index: 5;
  top: 50%;
  left: 50%;
  border-radius: 4px;
  transform: translate(-50%, -50%);
  color: ${(props) => props.theme.primary};
  padding: 20px;
`;

const Loader: React.FC<CustomLoaderProps> = ({ show, body }) => {
  return (
    <Backdrop show={show}>
      <LoaderStyles>{body}</LoaderStyles>
    </Backdrop>
  );
};

const editor = await PhotoEditorSDKUI.init({
  custom: {
    components: {
      loader: Loader,
    },
  },
});
custom: {
  components: {
    advancedUICategoryCard: AdvancedUICategoryCard,
    advancedUIItemCard: AdvancedUIItemCard,
    advancedUIToolbarItem: AdvancedUIToolbarItem,
    loader: Loader,
    colorItem: ColorItem,
    buttons: {
      mainCanvasActionUndo: CanvasBarTextSecondaryButton,
      mainCanvasActionRedo: CanvasBarTextSecondaryButton,
      mainCanvasActionExport: ContainedPrimaryButton,
      mainCanvasActionClose: OutlinedSecondaryButton,
      canvasActionEdit: SpriteActionButton,
      canvasActionBringToFront: SpriteActionButton,
      canvasActionDuplicate: SpriteActionButton,
      canvasActionDelete: SpriteActionButton,
      canvasActionInvert: SpriteActionButton,
      canvasActionFlip: SpriteActionButton,
      transformActionFlipHorizontal: IconButton,
      transformActionFlipVertical: IconButton,
      transformActionRotateClockwise: IconButton,
      transformActionRotateAntiClockwise: IconButton,
      textAlignment: IconButton,
      toolControlBarPrimaryButton: OutlinedPrimaryButton,
      toolControlBarSecondaryButton: OutlinedSecondaryButton,
    },
  }
}