Mixins / foldkit-mixins-ui

ImageCropperSlots

const · packages/mixins-ui/src/imageCropper.ts:49

const ImageCropperSlots: Slots.Contract<{ readonly root: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly [Attr.AttrToken<"role">], readonly Slot.RequirementName[], boolean>; readonly label: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly viewport: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly stage: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly pan: Slot.UnnamedSlot<Capability.Capability<"Draggable", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly image: Slot.UnnamedSlot<Capability.Capability<"Base", readonly []>, readonly Slot.EventName[], reado …;

An image cropper after Zag's: the image fitted in a viewport, a crop selection over it that a drag moves and eight handles resize, the rest of the image veiled, zoom (a Slider, the wheel, + and -), quarter turns, an aspect-ratio lock and a round crop. Export draws the crop on a canvas and answers with it as a data URL.

The crop is a small Model of this module's in the image's own pixels, of the image as turned: a 4000 by 3000 photo turned a quarter is 3000 wide, and a crop of its left half is { x: 0, y: 0, width: 1500, height: 4000 }. The view measures the viewport (Resize) and reads the image's natural size when it loads, and every drag reaches update as the Move Mount's distance from where the pointer went down, which update applies to the crop the drag began with, so a drag never drifts.

Zoom keeps the selection where it is on screen and magnifies the image under it, so zooming in crops less of the image. While zoomed in, a drag on the image outside the selection pans: the view and the crop move together over the image. The selection stays inside the image and inside what the viewport shows.

The selection is one focusable role="slider" (Zag's "2D slider"; the APG has no cropper) whose aria-valuetext says the crop: the arrows move it by a pixel of the screen (Shift by ten), Alt with the arrows resizes it from its far edges, and + and - zoom. The keys are physical, as the plane is, in either direction. The handles are for the pointer and hidden from assistive technology.

The viewport carries the geometry for the recipe as custom properties in pixels: --fk-cropper-x, -y, -w, -h (the selection), --fk-cropper-image-x, -y, -w, -h (the turned image's box), --fk-cropper-natural-w, -h (the image element before it is turned) and --fk-cropper-rotation.