-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Expand file tree
/
Copy pathindex.tsx
More file actions
157 lines (150 loc) · 4.35 KB
/
index.tsx
File metadata and controls
157 lines (150 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* WordPress dependencies
*/
import {
RangeControl,
SelectControl,
ToggleControl,
} from '@wordpress/components';
import { Stack } from '@wordpress/ui';
import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { useCropper } from '../../image-editor';
import {
DEFAULT_ASPECT_RATIOS,
MAX_ZOOM,
MIN_ZOOM,
ORIGINAL_ASPECT_RATIO,
} from '../../image-editor/core/constants';
import type { AspectRatioPreset } from '../../image-editor/core/constants';
import CropAdvancedPanel from './crop-advanced-panel';
export interface MediaEditorCropPanelProps {
/**
* Selected aspect-ratio preset value as a string (so it round-trips
* through `<SelectControl>`). `'0'` = free, `'-1'` = original, any
* positive number = fixed ratio.
*/
aspectRatioValue: string;
/** Setter for the aspect-ratio preset value. */
onAspectRatioChange: ( value: string ) => void;
/** Whether the cropper is in freeform (resize-handle) mode. */
freeformCrop: boolean;
/** Setter for freeform mode. */
onFreeformChange: ( value: boolean ) => void;
/** Signal that a placement-oriented control is being adjusted. */
onPlacementControlInteraction?: () => void;
/**
* Fixed aspect-ratio presets to display after Free and Original. When
* omitted, the media editor's default fixed-ratio presets are used.
*/
aspectRatioPresets?: AspectRatioPreset[];
}
/**
* Resolve an aspect-ratio preset value into a number suitable for
* `<Cropper aspectRatio=...>`. Returns `undefined` for Free (no lock).
*
* @param value Preset value as a string.
* @param imageAspectRatio Image's natural width / height — used for
* the Original preset.
*/
export function resolveAspectRatio(
value: string,
imageAspectRatio: number | null
): number | undefined {
const num = parseFloat( value );
if ( num === 0 ) {
return undefined;
}
if ( num === ORIGINAL_ASPECT_RATIO && imageAspectRatio ) {
return imageAspectRatio;
}
if ( num > 0 ) {
return num;
}
return undefined;
}
/**
* Sidebar panel for crop-shape controls — aspect-ratio presets and
* freeform toggle. The tactile verbs (rotate, flip) live in the
* bottom toolbar instead.
* @param props
* @param props.aspectRatioValue
* @param props.onAspectRatioChange
* @param props.freeformCrop
* @param props.onFreeformChange
* @param props.onPlacementControlInteraction
* @param props.aspectRatioPresets
*/
export default function MediaEditorCropPanel( {
aspectRatioValue,
onAspectRatioChange,
freeformCrop,
onFreeformChange,
onPlacementControlInteraction,
aspectRatioPresets,
}: MediaEditorCropPanelProps ) {
const { state, setZoom } = useCropper();
const imageAspectRatio = state.image
? state.image.naturalWidth / state.image.naturalHeight
: null;
const resolvedAspectRatio = resolveAspectRatio(
aspectRatioValue,
imageAspectRatio
);
const aspectRatioOptions = [
...DEFAULT_ASPECT_RATIOS.filter( ( preset ) => preset.value <= 0 ),
...( aspectRatioPresets ??
DEFAULT_ASPECT_RATIOS.filter( ( preset ) => preset.value > 0 ) ),
];
return (
<Stack direction="column" gap="md">
<RangeControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'Zoom' ) }
min={ MIN_ZOOM }
max={ MAX_ZOOM }
step={ 0.1 }
value={ state.zoom }
onChange={ ( value ) => {
onPlacementControlInteraction?.();
setZoom( typeof value === 'number' ? value : MIN_ZOOM );
} }
renderTooltipContent={ ( value ) => {
const zoom = typeof value === 'number' ? value : MIN_ZOOM;
return sprintf(
/* translators: %d: zoom level as a percentage. */
__( '%d%%' ),
Math.round( zoom * 100 )
);
} }
/>
<SelectControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'Aspect ratio' ) }
value={ aspectRatioValue }
onChange={ onAspectRatioChange }
options={ aspectRatioOptions.map( ( preset ) => ( {
label: preset.label,
value: preset.value.toString(),
} ) ) }
/>
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Freeform crop' ) }
help={ __(
'Drag the crop edges to resize freely. When off, the crop is fixed to the selected ratio.'
) }
checked={ freeformCrop }
onChange={ onFreeformChange }
/>
<CropAdvancedPanel
aspectRatio={ resolvedAspectRatio }
onPlacementControlInteraction={ onPlacementControlInteraction }
/>
</Stack>
);
}