Custom Stencil

The stencil is the draggable, resizable overlay that marks the crop area. You can write your own stencil component by following the stencil contract.

Stencil contract

A stencil component receives these props from the cropper engine:

PropTypeDescription
cropRectRectCurrent crop rect in viewport pixels: { x, y, width, height }.
onmove(dx: number, dy: number) => voidCall with pixel delta to move the stencil.
onresize(delta: ResizeDelta) => voidCall with a resize delta object to resize from a handle.
gridbooleanWhether to show the rule-of-thirds grid.
gridOnlyActivebooleanOnly show the grid during active interaction.

ResizeDelta

interface ResizeDelta {
  top?: number;
  right?: number;
  bottom?: number;
  left?: number;
}

Using DragHandle

The built-in DragHandle component handles pointer events and emits resize deltas. Use it for the corner and edge handles of your stencil:

<script lang="ts">
  import { DragHandle } from '@we-are-singular/svelte-chop-chop';
  import type { StencilProps } from '@we-are-singular/svelte-chop-chop';

  let { cropRect, onmove, onresize, grid, gridOnlyActive }: StencilProps = $props();
</script>

<!-- Position stencil over crop rect -->
<div
  class="my-stencil"
  style="left:{cropRect.x}px; top:{cropRect.y}px;
         width:{cropRect.width}px; height:{cropRect.height}px"
  role="region"
  aria-label="Crop area"
>
  <!-- Corner handles -->
  <DragHandle direction="nw" {onresize} />
  <DragHandle direction="ne" {onresize} />
  <DragHandle direction="sw" {onresize} />
  <DragHandle direction="se" {onresize} />

  <!-- Move area -->
  <div
    class="my-stencil-move"
    onpointerdown={(e) => {
      // implement drag to move
    }}
  />
</div>

Passing the custom stencil

<script lang="ts">
  import { Cropper } from '@we-are-singular/svelte-chop-chop';
  import MyStencil from './MyStencil.svelte';
</script>

<Cropper src="/photo.jpg" stencil={MyStencil} />

CropOverlay

Use the built-in CropOverlay component to render the dark semi-transparent overlay with a transparent cutout over the crop rect:

import { CropOverlay } from '@we-are-singular/svelte-chop-chop';

<CropOverlay {cropRect} containerRect={...} />

GridOverlay

GridOverlay draws rule-of-thirds lines, a full grid, or a golden ratio guide:

import { GridOverlay } from '@we-are-singular/svelte-chop-chop';

<GridOverlay
  {cropRect}
  type="rule-of-thirds"
  visible={grid && (!gridOnlyActive || isDragging)}
/>