(
props: ParentProps<{
onCropChange?: (bounds: CropBounds) => void;
onInteraction?: (interacting: boolean) => void;
onContextMenu?: (event: PointerEvent) => void;
ref?: CropperRef | ((ref: CropperRef) => void);
class?: string;
minSize?: Vec2;
maxSize?: Vec2;
targetSize?: Vec2;
initialCrop?: CropBounds | (() => CropBounds | undefined);
aspectRatio?: Ratio;
showBounds?: boolean;
snapToRatioEnabled?: boolean;
useBackdropFilter?: boolean;
allowLightMode?: boolean;
}>,
)
| 232 | }; |
| 233 | |
| 234 | export function Cropper( |
| 235 | props: ParentProps<{ |
| 236 | onCropChange?: (bounds: CropBounds) => void; |
| 237 | onInteraction?: (interacting: boolean) => void; |
| 238 | onContextMenu?: (event: PointerEvent) => void; |
| 239 | ref?: CropperRef | ((ref: CropperRef) => void); |
| 240 | class?: string; |
| 241 | minSize?: Vec2; |
| 242 | maxSize?: Vec2; |
| 243 | targetSize?: Vec2; |
| 244 | initialCrop?: CropBounds | (() => CropBounds | undefined); |
| 245 | aspectRatio?: Ratio; |
| 246 | showBounds?: boolean; |
| 247 | snapToRatioEnabled?: boolean; |
| 248 | useBackdropFilter?: boolean; |
| 249 | allowLightMode?: boolean; |
| 250 | }>, |
| 251 | ) { |
| 252 | let containerRef: HTMLDivElement | undefined; |
| 253 | let regionRef: HTMLDivElement | undefined; |
| 254 | let occTopRef: HTMLDivElement | undefined; |
| 255 | let occBottomRef: HTMLDivElement | undefined; |
| 256 | let occLeftRef: HTMLDivElement | undefined; |
| 257 | let occRightRef: HTMLDivElement | undefined; |
| 258 | |
| 259 | const resolvedChildren = children(() => props.children); |
| 260 | |
| 261 | // raw bounds are in "logical" coordinates (not scaled to targetSize) |
| 262 | const [rawBounds, setRawBounds] = createSignal<CropBounds>(CROP_ZERO); |
| 263 | const [displayRawBounds, setDisplayRawBounds] = |
| 264 | createSignal<CropBounds>(CROP_ZERO); |
| 265 | |
| 266 | const [isAnimating, setIsAnimating] = createSignal(false); |
| 267 | let animationFrameId: number | null = null; |
| 268 | const [isReady, setIsReady] = createSignal(false); |
| 269 | |
| 270 | function stopAnimation() { |
| 271 | if (animationFrameId !== null) cancelAnimationFrame(animationFrameId); |
| 272 | animationFrameId = null; |
| 273 | setIsAnimating(false); |
| 274 | setDisplayRawBounds(rawBounds()); |
| 275 | } |
| 276 | |
| 277 | const boundsTooSmall = createMemo( |
| 278 | () => displayRawBounds().width <= 30 || displayRawBounds().height <= 30, |
| 279 | ); |
| 280 | |
| 281 | const [mouseState, setMouseState] = createStore< |
| 282 | ( |
| 283 | | { drag: null | "region" | "overlay" } |
| 284 | | { drag: "handle"; cursor: string } |
| 285 | ) & { hoveringHandle: HandleSide | null } |
| 286 | >({ drag: null, hoveringHandle: null }); |
| 287 | |
| 288 | const resizing = () => |
| 289 | mouseState.drag === "handle" || mouseState.drag === "overlay"; |
| 290 | const cursorStyle = () => { |
| 291 | if (mouseState.drag === "region" || mouseState.drag === "overlay") |
nothing calls this directly
no test coverage detected