Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export interface MediaEditorCanvasProps {
onGestureStart?: () => void;
/** Fires when a canvas cropper gesture ends. */
onGestureEnd?: () => void;
/**
* Disable crop interaction on the canvas. Set while the edit is saving,
* so a drag cannot change the crop after the request was built.
*/
disabled?: boolean;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the thing can be disabled at a higher level, by consumers

}

/**
Expand All @@ -28,11 +33,13 @@ export interface MediaEditorCanvasProps {
* @param props.isPlacementActive
* @param props.onGestureStart
* @param props.onGestureEnd
* @param props.disabled
*/
export default function MediaEditorCanvas( {
isPlacementActive = false,
onGestureStart,
onGestureEnd,
disabled = false,
}: MediaEditorCanvasProps ) {
const { media } = useMediaEditorContext();
const controller = useMediaEditor();
Expand Down Expand Up @@ -159,6 +166,7 @@ export default function MediaEditorCanvas( {
isPlacementActive={ isPlacementActive }
onGestureStart={ handleGestureStart }
onGestureEnd={ handleGestureEnd }
disabled={ disabled }
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface MediaEditorCropPanelProps {
onAspectRatioChange: ( value: string ) => void;
/** Aspect-ratio presets to display in the selector. */
aspectRatioOptions: AspectRatioPreset[];
/** Disable every control in the panel while the edit is saving. */
disabled?: boolean;
}

/**
Expand All @@ -26,11 +28,13 @@ export interface MediaEditorCropPanelProps {
* @param props.aspectRatioValue
* @param props.onAspectRatioChange
* @param props.aspectRatioOptions
* @param props.disabled
*/
export default function MediaEditorCropPanel( {
aspectRatioValue,
onAspectRatioChange,
aspectRatioOptions,
disabled = false,
}: MediaEditorCropPanelProps ) {
return (
// Tag the whole panel as a crop-control region so the modal's
Expand All @@ -44,11 +48,12 @@ export default function MediaEditorCropPanel( {
<VisuallyHidden render={ <h2 /> }>
{ __( 'Crop options' ) }
</VisuallyHidden>
<MediaEditorImageControls withLabels />
<MediaEditorImageControls withLabels disabled={ disabled } />
<SelectControl
label={ __( 'Aspect ratio' ) }
value={ aspectRatioValue }
onChange={ onAspectRatioChange }
disabled={ disabled }
options={ aspectRatioOptions.map( ( preset ) => ( {
label: preset.label,
value: preset.value.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import RotationRuler from '../rotation-ruler';
export interface MediaEditorFineRotationProps {
/** Signal that a placement-oriented control is being adjusted. */
onPlacementControlInteraction?: () => void;
/**
* Disable the ruler. Set while the edit is saving; `RotationRuler`
* cancels an in-flight drag when this flips.
*/
disabled?: boolean;
}

/**
Expand All @@ -17,9 +22,11 @@ export interface MediaEditorFineRotationProps {
*
* @param props
* @param props.onPlacementControlInteraction
* @param props.disabled
*/
export default function MediaEditorFineRotation( {
onPlacementControlInteraction,
disabled = false,
}: MediaEditorFineRotationProps ) {
const { state, setRotation } = useMediaEditor();
// `commitOnKeyUp: false` lets rapid arrow-key adjustments coalesce
Expand Down Expand Up @@ -62,6 +69,7 @@ export default function MediaEditorFineRotation( {
max={ MAX_ROTATION_OFFSET }
value={ fineOffset }
onChange={ handleRotationSlider }
disabled={ disabled }
Comment thread
ramonjd marked this conversation as resolved.
Resolved
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export interface MediaEditorImageControlsProps {
* `DEFAULT_ZOOM_FACTOR` (1.2).
*/
zoomFactor?: number;
/**
* Disable every control. Set while the edit is saving, so the crop the
* request was built from cannot change under it.
*/
disabled?: boolean;
}

/**
Expand All @@ -67,12 +72,14 @@ export interface MediaEditorImageControlsProps {
* @param props.showAspectRatioControl
* @param props.aspectRatioPresets
* @param props.zoomFactor
* @param props.disabled
*/
export default function MediaEditorImageControls( {
withLabels = false,
showAspectRatioControl = false,
aspectRatioPresets,
zoomFactor = DEFAULT_ZOOM_FACTOR,
disabled = false,
}: MediaEditorImageControlsProps ) {
const { state, setFlip, snapRotate90, setZoom } = useMediaEditor();
const { aspectRatioValue, setAspectRatioValue, aspectRatioOptions } =
Expand All @@ -92,13 +99,17 @@ export default function MediaEditorImageControls( {
icon={ rotateLeft }
label={ __( 'Rotate 90° counter-clockwise' ) }
showTooltip
disabled={ disabled }
accessibleWhenDisabled
onClick={ () => snapRotate90( -1 ) }
/>
<Button
size="compact"
icon={ rotateRight }
label={ __( 'Rotate 90° clockwise' ) }
showTooltip
disabled={ disabled }
accessibleWhenDisabled
onClick={ () => snapRotate90( 1 ) }
/>
</>
Expand All @@ -112,6 +123,8 @@ export default function MediaEditorImageControls( {
label={ __( 'Flip horizontal' ) }
showTooltip
isPressed={ state.flip.horizontal }
disabled={ disabled }
accessibleWhenDisabled
onClick={ () =>
setFlip( {
horizontal: ! state.flip.horizontal,
Expand All @@ -125,6 +138,8 @@ export default function MediaEditorImageControls( {
label={ __( 'Flip vertical' ) }
showTooltip
isPressed={ state.flip.vertical }
disabled={ disabled }
accessibleWhenDisabled
onClick={ () =>
setFlip( {
horizontal: state.flip.horizontal,
Expand All @@ -142,7 +157,7 @@ export default function MediaEditorImageControls( {
icon={ plus }
label={ __( 'Zoom in' ) }
showTooltip
disabled={ state.zoom >= MAX_ZOOM }
disabled={ disabled || state.zoom >= MAX_ZOOM }
accessibleWhenDisabled
onClick={ () => zoomByFactor( zoomFactor ) }
/>
Expand All @@ -151,7 +166,7 @@ export default function MediaEditorImageControls( {
icon={ lineSolid }
label={ __( 'Zoom out' ) }
showTooltip
disabled={ state.zoom <= minZoom }
disabled={ disabled || state.zoom <= minZoom }
accessibleWhenDisabled
onClick={ () => zoomByFactor( 1 / zoomFactor ) }
/>
Expand All @@ -163,7 +178,7 @@ export default function MediaEditorImageControls( {
icon={ aspectRatioIcon }
label={ __( 'Aspect ratio' ) }
popoverProps={ { placement: 'top' } }
toggleProps={ { size: 'compact' } }
toggleProps={ { size: 'compact', disabled } }
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
>
{ ( { onClose } ) => (
<MenuGroup label={ __( 'Aspect ratio' ) }>
Expand Down
26 changes: 22 additions & 4 deletions packages/media-editor/src/components/media-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,15 @@ interface MediaEditorSidebarProps {
/** The open panel's id. Always one of `tabs`. */
activeTab: string;
onSelectTab: ( tab: string ) => void;
/** Freeze the open panel while the edit is saving. */
disabled?: boolean;
}

function MediaEditorSidebar( {
tabs,
activeTab,
onSelectTab,
disabled = false,
}: MediaEditorSidebarProps ) {
return (
<NavigableRegion
Expand All @@ -146,7 +149,11 @@ function MediaEditorSidebar( {
<div className="media-editor__tablist">
<Tabs.List variant="minimal">
{ tabs.map( ( tab ) => (
<Tabs.Tab key={ tab.id } value={ tab.id }>
<Tabs.Tab
key={ tab.id }
value={ tab.id }
disabled={ disabled }
>
{ tab.title }
</Tabs.Tab>
) ) }
Expand Down Expand Up @@ -320,6 +327,9 @@ function HistoryActions() {
redoCrop();
};
const handleReset = () => {
if ( isUndoRedoDisabled ) {
return;
}
beginGesture();
reset();
onReset();
Expand All @@ -334,7 +344,7 @@ function HistoryActions() {
<Button
size="compact"
variant="tertiary"
disabled={ ! isDirty }
disabled={ isUndoRedoDisabled || ! isDirty }
accessibleWhenDisabled
onClick={ handleReset }
>
Expand Down Expand Up @@ -634,7 +644,7 @@ function MediaEditorContent( {
! target.closest( `[${ CROP_CONTROL_ATTR }]` );
if ( ! isMetadataField ) {
event.preventDefault();
if ( isCropInteractionActive ) {
if ( isCropInteractionActive || isSaving ) {
return;
}
if ( isRedoShortcut ) {
Expand Down Expand Up @@ -677,6 +687,7 @@ function MediaEditorContent( {
<MediaEditorImageControls
showAspectRatioControl
aspectRatioPresets={ aspectRatioPresets }
disabled={ isSaving }
/>
) : null;

Expand All @@ -694,6 +705,7 @@ function MediaEditorContent( {
aspectRatioValue={ aspectRatioValue }
onAspectRatioChange={ setAspectRatioValue }
aspectRatioOptions={ aspectRatioOptions }
disabled={ isSaving }
/>
),
},
Expand All @@ -709,6 +721,7 @@ function MediaEditorContent( {
const ruler = isImage ? (
<MediaEditorFineRotation
onPlacementControlInteraction={ signalPlacementControlInteraction }
disabled={ isSaving }
/>
) : null;

Expand Down Expand Up @@ -745,6 +758,7 @@ function MediaEditorContent( {
handleCanvasGestureStart
}
onGestureEnd={ handleCanvasGestureEnd }
disabled={ isSaving }
/>
) : (
<MediaPreview />
Expand Down Expand Up @@ -773,6 +787,7 @@ function MediaEditorContent( {
: DETAILS_PANEL
}
onSelectTab={ selectPanel }
disabled={ isSaving }
/>
) }
</div>
Expand Down Expand Up @@ -805,7 +820,10 @@ function MediaEditorContent( {
isSaving,
hasMedia: !! media,
hasChanges,
isUndoRedoDisabled: isCropInteractionActive,
// Saving freezes the whole edit surface: `save()` reads the
// modifiers once and then awaits, so anything changed after that
// would be silently dropped when the save resolves.
isUndoRedoDisabled: isCropInteractionActive || isSaving,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
aspectRatioPresets,
isWide,
activePanel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ export interface CropperProps {
freeformCrop?: boolean;
/** Focus the crop area when the cropper mounts. */
focusOnMount?: boolean;
/**
* Ignore all crop interaction: pointer drags, wheel zoom, keyboard
* pan/zoom and the stencil's resize handles. Any gesture already in
* flight is cancelled. Used while the edit is being saved, so the
* modifiers sent to the server cannot change after the request starts.
*/
disabled?: boolean;
/** Callback fired when the image is loaded. */
onImageLoaded?: ( size: Size ) => void;
/**
Expand Down Expand Up @@ -136,6 +143,7 @@ export interface CropperProps {
* @param root0.aspectRatio Fixed aspect ratio (width/height).
* @param root0.freeformCrop Enable resize handles.
* @param root0.focusOnMount Focus the crop area on mount.
* @param root0.disabled Ignore all crop interaction.
* @param root0.onImageLoaded Image load callback.
* @param root0.onStateChange Every-frame state callback.
* @param root0.onGestureStart Gesture boundary start.
Expand All @@ -157,6 +165,7 @@ function CropperInner(
aspectRatio,
freeformCrop = false,
focusOnMount = false,
disabled = false,
onImageLoaded,
onStateChange,
onGestureStart,
Expand Down Expand Up @@ -585,6 +594,7 @@ function CropperInner(
maxZoom,
onGestureStart,
onGestureEnd,
disabled,
} );

// Compose focus-visibility tracking into the canvas event handlers.
Expand Down Expand Up @@ -632,6 +642,7 @@ function CropperInner(
},
onPointerDown: ( event: React.PointerEvent< HTMLDivElement > ) => {
if (
disabled ||
isResizingRef.current ||
isTouchPinchingRef.current ||
( event.pointerType === 'touch' && event.isPrimary === false )
Expand Down Expand Up @@ -1067,7 +1078,7 @@ function CropperInner(
onEscape={ handleEscape }
aspectRatio={ aspectRatio }
freeformCrop={ freeformCrop }
isResizeDisabled={ isTouchPinching }
isResizeDisabled={ isTouchPinching || disabled }
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
Comment thread
ramonjd marked this conversation as resolved.
Resolved
stencilTransition={ settleStencilTransition }
cropBounds={ cropBounds }
minCropSize={ minCropSize }
Expand Down
Loading
Loading