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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@get-set/gs-cropper

v1.0.2

Published

Get-Set Cropper

Readme

GSCropper

A dependency-free, feature-rich image cropper available in two flavours from one codebase:

  • Native / vanilla JS — a window.GSCropper(selector | element, params) factory plus a window.GSCropperConfigue instance registry, a jQuery plugin ($.fn.GSCropper) and an HTMLElement.prototype adapter.
  • React — a <GSCropper src="…" /> component with a fully typed imperative ref handle (GSCropperHandle).

Both share the exact same engine (actions/, constants/, helpers/, types/), so behaviour is identical across the two. Drag/zoom/rotate/flip, resizable crop box, rule-of-thirds guides, circular avatar mode, wheel + pinch zoom, keyboard nudging, and canvas/blob/dataURL export are all built in.

Features

  • Enhance an <img> or a container — the native factory accepts a CSS selector or a real DOM element; if you point it at a wrapper it finds the <img> inside.
  • Aspect ratiofree, a raw number (w / h), or a preset string (1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, 5:4, 4:5, 21:9, 2:1, 1:2), changeable at runtime via setAspectRatio.
  • Zoom — mouse wheel + pinch (touch), with minZoom / maxZoom clamping and a tunable wheelZoomRatio.
  • Rotate + flip — rotate by any step (default 90°) and flip horizontally / vertically.
  • Draggable / resizable crop box — 8 resize handles, drag the whole box, or pan the image behind it (movable / pannable).
  • View / boundary modes (viewMode 0–3, Cropper.js parity) keep the crop box inside the canvas.
  • Guides / grid overlaythirds, golden, grid, center, or off, plus a center indicator cross.
  • Circular crop (avatar) — round crop box and a round export mask.
  • Min / max crop-box size constraints.
  • Backdrop layer catalogcheckerboard, grid, solid, blur, glass, gradient, aurora behind transparent images.
  • Overlay dimming styles — dim, darken, blur, none.
  • Responsive — rescales the image + crop proportionally on container resize (ResizeObserver).
  • Initial cropautoCrop fraction or an explicit initialCrop rectangle in natural pixels.
  • Theminglight / dark / auto (follows OS) plus a custom accentColor token, RTL, and a disabled state.
  • A11y — focusable crop box with arrow-key nudging (+/- zoom, [/] rotate), ARIA roles/labels, and prefers-reduced-motion support.
  • Smooth animations — micro-interactions on drag/zoom/rotate and crop-box transitions (disabled during active drag and under reduced motion).
  • ExportgetCroppedCanvas, getDataURL, getBlob (with fill color, output size, MIME/quality, and rounded masking).
  • CallbacksonReady, onCrop, onCropStart, onCropEnd, onZoom, onRotate, onFlip.
  • React-only gsx prop for per-instance scoped styles.

Installation

npm i @get-set/gs-cropper

Compatibility

| Target | Requirement | |---|---| | React (<GSCropper>) | React 16.8+ (Hooks), and 17 / 18 / 19. React is an optional peer dependency. | | Native / vanilla (window.GSCropper) | No framework. Any modern evergreen browser. | | TypeScript | First-class — type declarations (.d.ts) ship in the package. | | SSR / Next.js | Safe to import server-side. The cropper is browser-only, so render it inside a Client Component ('use client'). |

The peer range is ^16.8.0 || ^17.0 || ^18.0 || ^19.0, with react/react-dom marked optional so the native build has zero peer dependencies.

Package entry points

| Field | Value | |---|---| | name | @get-set/gs-cropper | | main | dist/components/GSCropper.js | | module | dist/components/GSCropper.js | | types | dist/components/GSCropper.d.ts | | exports['.'].import | ./dist/components/GSCropper.js (React/ESM) | | exports['.'].require | ./dist-js/bundle.js (native window bundle) | | files | dist, dist-js, styles, example.html |

Project layout

GSCropper.ts               # native entry  (webpack -> dist-js/bundle.js, window global)
components/GSCropper.tsx     # React component (tsc -> dist/, npm entry)
actions/                    # shared engine (init/render/events/api/refresh/destroy)
constants/                  # aspectRatios, viewModes, defaultParams
helpers/                    # geometry, interaction, layout, markup, uihelpers
types/                      # Params / Ref / Window augmentation
components/styles/           # SCSS + compiled CSS + CSS-as-TS (runtime injection for React)
styles/                     # SCSS + compiled CSS (for <link> use by the native build)

Build

npm install
npm run build          # builds both targets
npm run build:js       # native bundle -> dist-js/bundle.js
npm run build:react    # React + types  -> dist/

Tests

Unit tests use Vitest + jsdom:

npm test         # run once
npm run test:watch

Coverage spans the pure logic (aspect resolution, geometry, interaction math, param merge, layout/markup helpers), native DOM behaviour (registry, structure, the full imperative API, drag/resize/wheel/keyboard/toolbar wiring, destroy/refresh), the jQuery + prototype adapters (which prove the factory accepts an element), and the React component (structure, imperative handle, gsx, prop-stripping, registry parity). jsdom has no layout engine, so pixel-exact positioning is validated in-browser; the units mock element boxes + canvas.

Usage — Native JS

Point the factory at an <img> (or a container holding one):

<link rel="stylesheet" href="styles/GSCropper.css" />

<img id="avatar" src="portrait.jpg" alt="Portrait" />

<script src="dist-js/bundle.js"></script>
<script>
  const cropper = window.GSCropper('#avatar', {
    aspectRatio: '1:1',
    circular: true,
    zoomable: true,
    guides: 'thirds',
    toolbar: true,
    onCrop: (data) => console.log(data)
  });
</script>

GSCropper is exposed as a global factory. Call it with a CSS selector string or a real element — this is essential, because the jQuery / prototype adapters pass an element:

window.GSCropper('#avatar', { aspectRatio: '1:1' });
window.GSCropper(document.querySelector('#avatar'), { aspectRatio: '1:1' });

jQuery plugin

// when jQuery is present on the page
$('#avatar').GSCropper({ aspectRatio: '16:9', guides: 'golden' });

HTMLElement.prototype

document.querySelector('#avatar').GSCropper({ circular: true });

Both adapters create the cropper exactly like the factory and register it in window.GSCropperConfigue.

The instance registry — window.GSCropperConfigue

Every cropper registers itself under its reference key. Look up a live instance and drive it:

window.GSCropper('#avatar', { reference: 'main', aspectRatio: '1:1' });

const inst = window.GSCropperConfigue.instance('main');
inst.zoom(0.2);                       // zoom in
inst.rotate(90);                      // rotate 90°
inst.flipX();                         // mirror horizontally
inst.setAspectRatio('16:9');          // change ratio at runtime
const url = inst.getDataURL();        // export as data URL
inst.reset();                         // back to the initial crop
inst.destroy();                       // tear down + restore the <img>

window.GSCropperConfigue shape:

| Member | Type | Description | |---|---|---| | references | Array<{ key: string; ref: Ref }> | All registered instances. | | instance(key) | (key: string) => Ref \| undefined | Look up an instance's runtime Ref by its reference key. |

Native instance methods (Ref)

The object returned by window.GSCropper(...) (and stored in the registry) exposes:

| Method | Signature | Description | |---|---|---| | getCroppedCanvas | (options?) => HTMLCanvasElement \| null | Render the crop to a canvas at natural resolution. | | getData | () => GSCropData | Crop rectangle in natural image pixels (+ rotate/scale). | | setData | (data: Partial<GSCropData>) => void | Set the crop rect / rotation / flip. | | getBlob | (options?) => Promise<Blob \| null> | Export the crop as a Blob. | | getDataURL | (options?) => string \| null | Export the crop as a data URL. | | zoom | (delta: number) => void | Zoom by a relative amount (+ in, − out). | | zoomTo | (scale: number) => void | Zoom to an absolute scale. | | rotate | (deg: number) => void | Rotate by a relative angle. | | rotateTo | (deg: number) => void | Rotate to an absolute angle. | | flipX / flipY | () => void | Flip horizontally / vertically. | | flip | (axis: 'horizontal' \| 'vertical') => void | Flip on an axis. | | move | (x: number, y: number) => void | Nudge the crop box by canvas px. | | setAspectRatio | (aspect: number \| string \| 'free') => void | Change the crop-box ratio at runtime. | | reset | () => void | Restore the initial image + auto crop. | | clear | () => void | Empty the crop box. | | enable / disable | () => void | Toggle interaction. | | refresh | () => void | Rebuild from (updated) params. | | destroy | () => void | Tear down + restore the original element. |

Usage — React

'use client';
import { useRef } from 'react';
import GSCropper, { GSCropperHandle } from '@get-set/gs-cropper';

export default function AvatarEditor() {
  const ref = useRef<GSCropperHandle>(null);

  const save = async () => {
    const blob = await ref.current!.getBlob({ width: 256, height: 256 });
    // upload blob…
  };

  return (
    <>
      <GSCropper
        ref={ref}
        src="/portrait.jpg"
        alt="Portrait"
        aspectRatio="1:1"
        circular
        guides="thirds"
        toolbar
        theme="auto"
        accentColor="#2563eb"
        onCrop={(data) => console.log(data)}
        onReady={() => console.log('ready')}
      />
      <button onClick={() => ref.current!.rotate(90)}>Rotate</button>
      <button onClick={() => ref.current!.flip('horizontal')}>Flip</button>
      <button onClick={save}>Save</button>
    </>
  );
}

The imperative handle — GSCropperHandle

useImperativeHandle exposes full parity with the native Ref:

| Method | Signature | |---|---| | getCroppedCanvas | (options?: GSCropperOutputOptions) => HTMLCanvasElement \| null | | getData | () => GSCropData | | setData | (data: Partial<GSCropData>) => void | | getBlob | (options?) => Promise<Blob \| null> | | getDataURL | (options?) => string \| null | | zoom | (delta: number) => void | | zoomTo | (scale: number) => void | | rotate | (deg: number) => void | | rotateTo | (deg: number) => void | | flipX | () => void | | flipY | () => void | | flip | (axis: 'horizontal' \| 'vertical') => void | | move | (x: number, y: number) => void | | reset | () => void | | clear | () => void | | setAspectRatio | (aspect: number \| string \| 'free') => void | | enable | () => void | | disable | () => void | | destroy | () => void |

React components also register in window.GSCropperConfigue, so window.GSCropperConfigue.instance('your-reference') returns the same imperative API from anywhere.

The gsx prop (React only)

Scoped, per-instance styles injected into <head> and removed on unmount. Keys are nested selectors relative to this instance ([data-key='…']):

<GSCropper
  src="/pic.jpg"
  gsx={{
    '.gs-cropper-crop-box': { outlineColor: '#f43f5e' },
    '.gs-cropper-handle': { background: '#f43f5e' }
  }}
/>

Options

Every option (native params and React props are identical):

| Option | Type | Default | Description | |---|---|---|---| | reference | string | auto GUID | Registry key. | | src | string | host <img src> | Image source URL. | | alt | string | '' | Image alt text. | | crossOrigin | '' \| 'anonymous' \| 'use-credentials' | — | For taint-free canvas export of remote images. | | aspectRatio | 'free' \| number \| preset | 'free' | Crop-box ratio (1:1, 16:9, … or w/h). | | initialAspectRatio | 'free' \| number \| preset | — | Ratio applied only to the initial auto crop. | | circular | boolean | false | Round (avatar) crop box + round export mask. | | viewMode | 0 \| 1 \| 2 \| 3 | 1 | Boundary mode (Cropper.js parity). | | background | boolean | true | Show the checkerboard/grid behind transparency. | | responsive | boolean | true | Rescale on container resize. | | restore | boolean | true | Restore the crop on resize. | | containerAspectRatio | number | — | Fixed canvas aspect ratio (w/h). | | autoCrop | number \| false | 0.8 | Initial crop area as a fraction of the canvas; false = none. | | initialCrop | Partial<GSCropData> | — | Explicit initial crop in natural pixels (overrides autoCrop). | | zoomable | boolean | true | Enable zoom (wheel + pinch). | | zoomOnWheel | boolean | true | Enable wheel zoom. | | zoomOnPinch | boolean | true | Enable pinch zoom. | | wheelZoomRatio | number | 0.1 | Wheel/keyboard zoom step. | | minZoom | number | 0.1 | Minimum zoom (× fit). | | maxZoom | number | 10 | Maximum zoom (× fit). | | rotatable | boolean | true | Enable rotation. | | flippable | boolean | true | Enable flipping. | | rotateStep | number | 90 | Rotate step (deg) for keyboard/toolbar. | | draggable | boolean | true | Drag the whole crop box. | | movable | boolean | true | Allow moving the image. | | pannable | boolean | true | Pan the image with a drag on the canvas. | | resizable | boolean | true | Resize the crop box via handles. | | handles | boolean | true | Render the resize handles. | | nudgeStep | number | 1 | Arrow-key nudge amount (px). | | minCropWidth | number | 20 | Minimum crop-box width. | | minCropHeight | number | 20 | Minimum crop-box height. | | maxCropWidth | number | — | Maximum crop-box width. | | maxCropHeight | number | — | Maximum crop-box height. | | overlay | 'dim' \| 'blur' \| 'darken' \| 'none' | 'dim' | Outside-the-box dimming style. | | guides | boolean \| 'thirds' \| 'golden' \| 'grid' \| 'center' | true | Grid / guide lines. | | center | boolean | true | Center indicator cross. | | backdropType | 'none' \| 'solid' \| 'blur' \| 'glass' \| 'gradient' \| 'checkerboard' \| 'grid' \| 'aurora' | 'checkerboard' | Canvas backdrop layer. | | toolbar | boolean | false | Built-in zoom/rotate/flip/reset toolbar. | | theme | 'light' \| 'dark' \| 'auto' | 'auto' | Visual theme. | | accentColor | string | #2563eb | Accent (--gsc-accent) for handles/focus. | | rtl | boolean | false | Right-to-left layout. | | disabled | boolean | false | Disable all interaction. | | reducedMotion | 'auto' \| boolean | 'auto' | Honor prefers-reduced-motion. | | customClass | GSCropperCustomClass | — | Per-part class overrides. | | className | string | — | Extra class on the container. | | output | GSCropperOutputOptions | — | Default export options. | | gsx | NestedCSS | — | React only — scoped inline styles. | | onReady | () => void | — | Image loaded + cropper laid out. | | onCrop | (data: GSCropData) => void | — | Crop rectangle changed. | | onCropStart | (action: string) => void | — | Drag/resize interaction started. | | onCropEnd | (action: string) => void | — | Drag/resize interaction ended. | | onZoom | (scale: number) => void | — | Zoom level changed. | | onRotate | (angle: number) => void | — | Image rotated. | | onFlip | (flip: { scaleX; scaleY }) => void | — | Image flipped. |

GSCropData

interface GSCropData {
  x: number;       // crop left in natural image pixels
  y: number;       // crop top in natural image pixels
  width: number;   // crop width in natural pixels
  height: number;  // crop height in natural pixels
  rotate: number;  // image rotation (deg)
  scaleX: number;  // horizontal flip (±1)
  scaleY: number;  // vertical flip (±1)
}

GSCropperOutputOptions

interface GSCropperOutputOptions {
  width?: number;                    // output width (default: crop width)
  height?: number;                   // output height (default: crop height)
  fillColor?: string;                // paint behind transparent/rotated corners
  imageSmoothingQuality?: 'low' | 'medium' | 'high';
  imageSmoothingEnabled?: boolean;
  mimeType?: string;                 // toDataURL / toBlob MIME (default image/png)
  quality?: number;                  // 0–1 for lossy MIME
  rounded?: boolean;                 // force a circular mask (defaults to `circular`)
}

Variant catalogs

aspectRatio presets

1:1 · 4:3 · 3:4 · 16:9 · 9:16 · 3:2 · 2:3 · 5:4 · 4:5 · 21:9 · 2:1 · 1:2 — or a raw number (1.7778) or 'free'.

viewMode

| Value | Behaviour | |---|---| | 0 | No restriction — the crop box may leave the canvas. | | 1 | Crop box is restricted to the canvas (default). | | 2 | The image covers and is restricted to the crop box. | | 3 | The image covers and is restricted to the container. |

guides

thirds (rule of thirds) · golden (golden ratio) · grid (4×4) · center (cross only) · true (= thirds) · false (off).

backdropType

checkerboard (default) · grid · solid · blur · glass · gradient · aurora (animated).

overlay

dim (default) · darken · blur · none.

Events / callbacks

window.GSCropper('#img', {
  onReady:     () => {},
  onCrop:      (data) => {},          // { x, y, width, height, rotate, scaleX, scaleY }
  onCropStart: (action) => {},        // 'move' | 'pan' | 'e' | 'se' | …
  onCropEnd:   (action) => {},
  onZoom:      (scale) => {},
  onRotate:    (deg) => {},
  onFlip:      ({ scaleX, scaleY }) => {}
});

Examples

Native — square avatar with circular mask, dark theme, toolbar

<img id="ava" src="face.jpg" alt="Avatar" />
<script src="dist-js/bundle.js"></script>
<script>
  const c = window.GSCropper('#ava', {
    reference: 'ava',
    aspectRatio: '1:1',
    circular: true,
    theme: 'dark',
    accentColor: '#22d3ee',
    guides: 'center',
    toolbar: true,
    minCropWidth: 64,
    minCropHeight: 64
  });

  document.querySelector('#save').addEventListener('click', async () => {
    const blob = await c.getBlob({ width: 256, height: 256, mimeType: 'image/png' });
    // upload blob…
  });
</script>

Native — free-form crop with golden guides + wheel zoom

window.GSCropper(document.querySelector('#photo'), {
  aspectRatio: 'free',
  guides: 'golden',
  overlay: 'darken',
  backdropType: 'grid',
  wheelZoomRatio: 0.15,
  maxZoom: 6
});

React — controlled 16:9 banner cropper

'use client';
import { useRef, useState } from 'react';
import GSCropper, { GSCropperHandle } from '@get-set/gs-cropper';

export default function BannerCropper() {
  const ref = useRef<GSCropperHandle>(null);
  const [preview, setPreview] = useState<string>('');

  return (
    <div>
      <GSCropper
        ref={ref}
        src="/banner.jpg"
        aspectRatio="16:9"
        guides="thirds"
        toolbar
        onCrop={() => setPreview(ref.current!.getDataURL() ?? '')}
      />
      {preview && <img src={preview} alt="Preview" />}
    </div>
  );
}

React — scoped styling with gsx

<GSCropper
  src="/pic.jpg"
  aspectRatio="4:3"
  gsx={{
    '.gs-cropper-crop-box': { outline: '2px solid #f43f5e' },
    '.gs-cropper-handle': { borderColor: '#f43f5e', background: '#fff' }
  }}
/>

License

ISC © Get-Set