@wordpress/block-editor 14.7.1-next.082ed6819.0 → 14.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-toolbar/index.js +11 -4
  3. package/build/components/block-toolbar/index.js.map +1 -1
  4. package/build/components/iframe/index.js +12 -216
  5. package/build/components/iframe/index.js.map +1 -1
  6. package/build/components/iframe/use-scale-canvas.js +377 -0
  7. package/build/components/iframe/use-scale-canvas.js.map +1 -0
  8. package/build/components/image-editor/use-save-image.js +22 -3
  9. package/build/components/image-editor/use-save-image.js.map +1 -1
  10. package/build-module/components/block-toolbar/index.js +11 -4
  11. package/build-module/components/block-toolbar/index.js.map +1 -1
  12. package/build-module/components/iframe/index.js +14 -218
  13. package/build-module/components/iframe/index.js.map +1 -1
  14. package/build-module/components/iframe/use-scale-canvas.js +371 -0
  15. package/build-module/components/iframe/use-scale-canvas.js.map +1 -0
  16. package/build-module/components/image-editor/use-save-image.js +22 -3
  17. package/build-module/components/image-editor/use-save-image.js.map +1 -1
  18. package/build-style/content-rtl.css +7 -22
  19. package/build-style/content.css +7 -22
  20. package/build-style/style-rtl.css +30 -0
  21. package/build-style/style.css +30 -0
  22. package/package.json +31 -31
  23. package/src/components/block-canvas/style.scss +2 -1
  24. package/src/components/block-toolbar/index.js +8 -0
  25. package/src/components/block-tools/style.scss +39 -0
  26. package/src/components/color-palette/test/__snapshots__/control.js.snap +2 -2
  27. package/src/components/iframe/content.scss +34 -41
  28. package/src/components/iframe/index.js +13 -313
  29. package/src/components/iframe/use-scale-canvas.js +468 -0
  30. package/src/components/image-editor/use-save-image.js +27 -2
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useScaleCanvas = useScaleCanvas;
7
+ var _element = require("@wordpress/element");
8
+ var _compose = require("@wordpress/compose");
9
+ /**
10
+ * WordPress dependencies
11
+ */
12
+
13
+ /**
14
+ * @typedef {Object} TransitionState
15
+ * @property {number} scaleValue Scale of the canvas.
16
+ * @property {number} frameSize Size of the frame/offset around the canvas.
17
+ * @property {number} clientHeight ClientHeight of the iframe.
18
+ * @property {number} scrollTop ScrollTop of the iframe.
19
+ * @property {number} scrollHeight ScrollHeight of the iframe.
20
+ */
21
+
22
+ /**
23
+ * Calculate the scale of the canvas.
24
+ *
25
+ * @param {Object} options Object of options
26
+ * @param {number} options.frameSize Size of the frame/offset around the canvas
27
+ * @param {number} options.containerWidth Actual width of the canvas container
28
+ * @param {number} options.maxContainerWidth Maximum width of the container to use for the scale calculation. This locks the canvas to a maximum width when zooming out.
29
+ * @param {number} options.scaleContainerWidth Width the of the container wrapping the canvas container
30
+ * @return {number} Scale value between 0 and/or equal to 1
31
+ */
32
+ function calculateScale({
33
+ frameSize,
34
+ containerWidth,
35
+ maxContainerWidth,
36
+ scaleContainerWidth
37
+ }) {
38
+ return (Math.min(containerWidth, maxContainerWidth) - frameSize * 2) / scaleContainerWidth;
39
+ }
40
+
41
+ /**
42
+ * Compute the next scrollTop position after scaling the iframe content.
43
+ *
44
+ * @param {TransitionState} transitionFrom Starting point of the transition
45
+ * @param {TransitionState} transitionTo Ending state of the transition
46
+ * @return {number} Next scrollTop position after scaling the iframe content.
47
+ */
48
+ function computeScrollTopNext(transitionFrom, transitionTo) {
49
+ const {
50
+ clientHeight: prevClientHeight,
51
+ frameSize: prevFrameSize,
52
+ scaleValue: prevScale,
53
+ scrollTop,
54
+ scrollHeight
55
+ } = transitionFrom;
56
+ const {
57
+ clientHeight,
58
+ frameSize,
59
+ scaleValue
60
+ } = transitionTo;
61
+ // Step 0: Start with the current scrollTop.
62
+ let scrollTopNext = scrollTop;
63
+ // Step 1: Undo the effects of the previous scale and frame around the
64
+ // midpoint of the visible area.
65
+ scrollTopNext = (scrollTopNext + prevClientHeight / 2 - prevFrameSize) / prevScale - prevClientHeight / 2;
66
+
67
+ // Step 2: Apply the new scale and frame around the midpoint of the
68
+ // visible area.
69
+ scrollTopNext = (scrollTopNext + clientHeight / 2) * scaleValue + frameSize - clientHeight / 2;
70
+
71
+ // Step 3: Handle an edge case so that you scroll to the top of the
72
+ // iframe if the top of the iframe content is visible in the container.
73
+ // The same edge case for the bottom is skipped because changing content
74
+ // makes calculating it impossible.
75
+ scrollTopNext = scrollTop <= prevFrameSize ? 0 : scrollTopNext;
76
+
77
+ // This is the scrollTop value if you are scrolled to the bottom of the
78
+ // iframe. We can't just let the browser handle it because we need to
79
+ // animate the scaling.
80
+ const maxScrollTop = scrollHeight * (scaleValue / prevScale) + frameSize * 2 - clientHeight;
81
+
82
+ // Step 4: Clamp the scrollTopNext between the minimum and maximum
83
+ // possible scrollTop positions. Round the value to avoid subpixel
84
+ // truncation by the browser which sometimes causes a 1px error.
85
+ return Math.round(Math.min(Math.max(0, scrollTopNext), Math.max(0, maxScrollTop)));
86
+ }
87
+
88
+ /**
89
+ * Generate the keyframes to use for the zoom out animation.
90
+ *
91
+ * @param {TransitionState} transitionFrom Starting transition state.
92
+ * @param {TransitionState} transitionTo Ending transition state.
93
+ * @return {Object[]} An array of keyframes to use for the animation.
94
+ */
95
+ function getAnimationKeyframes(transitionFrom, transitionTo) {
96
+ const {
97
+ scaleValue: prevScale,
98
+ frameSize: prevFrameSize,
99
+ scrollTop
100
+ } = transitionFrom;
101
+ const {
102
+ scaleValue,
103
+ frameSize,
104
+ scrollTop: scrollTopNext
105
+ } = transitionTo;
106
+ return [{
107
+ translate: `0 0`,
108
+ scale: prevScale,
109
+ paddingTop: `${prevFrameSize / prevScale}px`,
110
+ paddingBottom: `${prevFrameSize / prevScale}px`
111
+ }, {
112
+ translate: `0 ${scrollTop - scrollTopNext}px`,
113
+ scale: scaleValue,
114
+ paddingTop: `${frameSize / scaleValue}px`,
115
+ paddingBottom: `${frameSize / scaleValue}px`
116
+ }];
117
+ }
118
+
119
+ /**
120
+ * @typedef {Object} ScaleCanvasResult
121
+ * @property {boolean} isZoomedOut A boolean indicating if the canvas is zoomed out.
122
+ * @property {number} scaleContainerWidth The width of the container used to calculate the scale.
123
+ * @property {Object} contentResizeListener A resize observer for the content.
124
+ * @property {Object} containerResizeListener A resize observer for the container.
125
+ */
126
+
127
+ /**
128
+ * Handles scaling the canvas for the zoom out mode and animating between
129
+ * the states.
130
+ *
131
+ * @param {Object} options Object of options.
132
+ * @param {number} options.frameSize Size of the frame around the content.
133
+ * @param {Document} options.iframeDocument Document of the iframe.
134
+ * @param {number} options.maxContainerWidth Max width of the canvas to use as the starting scale point. Defaults to 750.
135
+ * @param {number|string} options.scale Scale of the canvas. Can be an decimal between 0 and 1, 1, or 'auto-scaled'.
136
+ * @return {ScaleCanvasResult} Properties of the result.
137
+ */
138
+ function useScaleCanvas({
139
+ frameSize,
140
+ iframeDocument,
141
+ maxContainerWidth = 750,
142
+ scale
143
+ }) {
144
+ const [contentResizeListener, {
145
+ height: contentHeight
146
+ }] = (0, _compose.useResizeObserver)();
147
+ const [containerResizeListener, {
148
+ width: containerWidth
149
+ }] = (0, _compose.useResizeObserver)();
150
+ const initialContainerWidthRef = (0, _element.useRef)(0);
151
+ const isZoomedOut = scale !== 1;
152
+ const prefersReducedMotion = (0, _compose.useReducedMotion)();
153
+ const isAutoScaled = scale === 'auto-scaled';
154
+ // Track if the animation should start when the useEffect runs.
155
+ const startAnimationRef = (0, _element.useRef)(false);
156
+ // Track the animation so we know if we have an animation running,
157
+ // and can cancel it, reverse it, call a finish event, etc.
158
+ const animationRef = (0, _element.useRef)(null);
159
+ (0, _element.useEffect)(() => {
160
+ if (!isZoomedOut) {
161
+ initialContainerWidthRef.current = containerWidth;
162
+ }
163
+ }, [containerWidth, isZoomedOut]);
164
+ const scaleContainerWidth = Math.max(initialContainerWidthRef.current, containerWidth);
165
+ const scaleValue = isAutoScaled ? calculateScale({
166
+ frameSize,
167
+ containerWidth,
168
+ maxContainerWidth,
169
+ scaleContainerWidth
170
+ }) : scale;
171
+
172
+ /**
173
+ * The starting transition state for the zoom out animation.
174
+ * @type {import('react').RefObject<TransitionState>}
175
+ */
176
+ const transitionFromRef = (0, _element.useRef)({
177
+ scaleValue,
178
+ frameSize,
179
+ clientHeight: 0,
180
+ scrollTop: 0,
181
+ scrollHeight: 0
182
+ });
183
+
184
+ /**
185
+ * The ending transition state for the zoom out animation.
186
+ * @type {import('react').RefObject<TransitionState>}
187
+ */
188
+ const transitionToRef = (0, _element.useRef)({
189
+ scaleValue,
190
+ frameSize,
191
+ clientHeight: 0,
192
+ scrollTop: 0,
193
+ scrollHeight: 0
194
+ });
195
+
196
+ /**
197
+ * Start the zoom out animation. This sets the necessary CSS variables
198
+ * for animating the canvas and returns the Animation object.
199
+ *
200
+ * @return {Animation} The animation object for the zoom out animation.
201
+ */
202
+ const startZoomOutAnimation = (0, _element.useCallback)(() => {
203
+ const {
204
+ scrollTop
205
+ } = transitionFromRef.current;
206
+ const {
207
+ scrollTop: scrollTopNext
208
+ } = transitionToRef.current;
209
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scroll-top', `${scrollTop}px`);
210
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scroll-top-next', `${scrollTopNext}px`);
211
+ iframeDocument.documentElement.classList.add('zoom-out-animation');
212
+ return iframeDocument.documentElement.animate(getAnimationKeyframes(transitionFromRef.current, transitionToRef.current), {
213
+ easing: 'cubic-bezier(0.46, 0.03, 0.52, 0.96)',
214
+ duration: 400
215
+ });
216
+ }, [iframeDocument]);
217
+
218
+ /**
219
+ * Callback when the zoom out animation is finished.
220
+ * - Cleans up animations refs.
221
+ * - Adds final CSS vars for scale and frame size to preserve the state.
222
+ * - Removes the 'zoom-out-animation' class (which has the fixed positioning).
223
+ * - Sets the final scroll position after the canvas is no longer in fixed position.
224
+ * - Removes CSS vars related to the animation.
225
+ * - Sets the transitionFrom to the transitionTo state to be ready for the next animation.
226
+ */
227
+ const finishZoomOutAnimation = (0, _element.useCallback)(() => {
228
+ startAnimationRef.current = false;
229
+ animationRef.current = null;
230
+
231
+ // Add our final scale and frame size now that the animation is done.
232
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale', transitionToRef.current.scaleValue);
233
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-frame-size', `${transitionToRef.current.frameSize}px`);
234
+ iframeDocument.documentElement.classList.remove('zoom-out-animation');
235
+
236
+ // Set the final scroll position that was just animated to.
237
+ // Disable reason: Eslint isn't smart enough to know that this is a
238
+ // DOM element. https://github.com/facebook/react/issues/31483
239
+ // eslint-disable-next-line react-compiler/react-compiler
240
+ iframeDocument.documentElement.scrollTop = transitionToRef.current.scrollTop;
241
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scroll-top');
242
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scroll-top-next');
243
+
244
+ // Update previous values.
245
+ transitionFromRef.current = transitionToRef.current;
246
+ }, [iframeDocument]);
247
+
248
+ /**
249
+ * Runs when zoom out mode is toggled, and sets the startAnimation flag
250
+ * so the animation will start when the next useEffect runs. We _only_
251
+ * want to animate when the zoom out mode is toggled, not when the scale
252
+ * changes due to the container resizing.
253
+ */
254
+ (0, _element.useEffect)(() => {
255
+ if (!iframeDocument) {
256
+ return;
257
+ }
258
+ if (isZoomedOut) {
259
+ iframeDocument.documentElement.classList.add('is-zoomed-out');
260
+ }
261
+ startAnimationRef.current = true;
262
+ return () => {
263
+ iframeDocument.documentElement.classList.remove('is-zoomed-out');
264
+ };
265
+ }, [iframeDocument, isZoomedOut]);
266
+
267
+ /**
268
+ * This handles:
269
+ * 1. Setting the correct scale and vars of the canvas when zoomed out
270
+ * 2. If zoom out mode has been toggled, runs the animation of zooming in/out
271
+ */
272
+ (0, _element.useEffect)(() => {
273
+ if (!iframeDocument) {
274
+ return;
275
+ }
276
+
277
+ // We need to update the appropriate scale to exit from. If sidebars have been opened since setting the
278
+ // original scale, we will snap to a much smaller scale due to the scale container immediately changing sizes when exiting.
279
+ if (isAutoScaled && transitionFromRef.current.scaleValue !== 1) {
280
+ // We use containerWidth as the divisor, as scaleContainerWidth will always match the containerWidth when
281
+ // exiting.
282
+ transitionFromRef.current.scaleValue = calculateScale({
283
+ frameSize: transitionFromRef.current.frameSize,
284
+ containerWidth,
285
+ maxContainerWidth,
286
+ scaleContainerWidth: containerWidth
287
+ });
288
+ }
289
+
290
+ // If we are not going to animate the transition, set the scale and frame size directly.
291
+ // If we are animating, these values will be set when the animation is finished.
292
+ // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to
293
+ // animate the transition.
294
+ if (!startAnimationRef.current) {
295
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale', scaleValue);
296
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-frame-size', `${frameSize}px`);
297
+ }
298
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-content-height', `${contentHeight}px`);
299
+ const clientHeight = iframeDocument.documentElement.clientHeight;
300
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-inner-height', `${clientHeight}px`);
301
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-container-width', `${containerWidth}px`);
302
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale-container-width', `${scaleContainerWidth}px`);
303
+
304
+ /**
305
+ * Handle the zoom out animation:
306
+ *
307
+ * - Get the current scrollTop position.
308
+ * - Calculate where the same scroll position is after scaling.
309
+ * - Apply fixed positioning to the canvas with a transform offset
310
+ * to keep the canvas centered.
311
+ * - Animate the scale and padding to the new scale and frame size.
312
+ * - After the animation is complete, remove the fixed positioning
313
+ * and set the scroll position that keeps everything centered.
314
+ */
315
+ if (startAnimationRef.current) {
316
+ // Don't allow a new transition to start again unless it was started by the zoom out mode changing.
317
+ startAnimationRef.current = false;
318
+
319
+ /**
320
+ * If we already have an animation running, reverse it.
321
+ */
322
+ if (animationRef.current) {
323
+ animationRef.current.reverse();
324
+ // Swap the transition to/from refs so that we set the correct values when
325
+ // finishZoomOutAnimation runs.
326
+ const tempTransitionFrom = transitionFromRef.current;
327
+ const tempTransitionTo = transitionToRef.current;
328
+ transitionFromRef.current = tempTransitionTo;
329
+ transitionToRef.current = tempTransitionFrom;
330
+ } else {
331
+ var _transitionFromRef$cu;
332
+ /**
333
+ * Start a new zoom animation.
334
+ */
335
+
336
+ // We can't trust the set value from contentHeight, as it was measured
337
+ // before the zoom out mode was changed. After zoom out mode is changed,
338
+ // appenders may appear or disappear, so we need to get the height from
339
+ // the iframe at this point when we're about to animate the zoom out.
340
+ // The iframe scrollTop, scrollHeight, and clientHeight will all be
341
+ // the most accurate.
342
+ transitionFromRef.current.clientHeight = (_transitionFromRef$cu = transitionFromRef.current.clientHeight) !== null && _transitionFromRef$cu !== void 0 ? _transitionFromRef$cu : clientHeight;
343
+ transitionFromRef.current.scrollTop = iframeDocument.documentElement.scrollTop;
344
+ transitionFromRef.current.scrollHeight = iframeDocument.documentElement.scrollHeight;
345
+ transitionToRef.current = {
346
+ scaleValue,
347
+ frameSize,
348
+ clientHeight
349
+ };
350
+ transitionToRef.current.scrollTop = computeScrollTopNext(transitionFromRef.current, transitionToRef.current);
351
+ animationRef.current = startZoomOutAnimation();
352
+
353
+ // If the user prefers reduced motion, finish the animation immediately and set the final state.
354
+ if (prefersReducedMotion) {
355
+ finishZoomOutAnimation();
356
+ } else {
357
+ animationRef.current.onfinish = finishZoomOutAnimation;
358
+ }
359
+ }
360
+ }
361
+ return () => {
362
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scale');
363
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-frame-size');
364
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-content-height');
365
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-inner-height');
366
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-container-width');
367
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scale-container-width');
368
+ };
369
+ }, [startZoomOutAnimation, finishZoomOutAnimation, prefersReducedMotion, isAutoScaled, scaleValue, frameSize, iframeDocument, contentHeight, containerWidth, maxContainerWidth, scaleContainerWidth]);
370
+ return {
371
+ isZoomedOut,
372
+ scaleContainerWidth,
373
+ contentResizeListener,
374
+ containerResizeListener
375
+ };
376
+ }
377
+ //# sourceMappingURL=use-scale-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_element","require","_compose","calculateScale","frameSize","containerWidth","maxContainerWidth","scaleContainerWidth","Math","min","computeScrollTopNext","transitionFrom","transitionTo","clientHeight","prevClientHeight","prevFrameSize","scaleValue","prevScale","scrollTop","scrollHeight","scrollTopNext","maxScrollTop","round","max","getAnimationKeyframes","translate","scale","paddingTop","paddingBottom","useScaleCanvas","iframeDocument","contentResizeListener","height","contentHeight","useResizeObserver","containerResizeListener","width","initialContainerWidthRef","useRef","isZoomedOut","prefersReducedMotion","useReducedMotion","isAutoScaled","startAnimationRef","animationRef","useEffect","current","transitionFromRef","transitionToRef","startZoomOutAnimation","useCallback","documentElement","style","setProperty","classList","add","animate","easing","duration","finishZoomOutAnimation","remove","removeProperty","reverse","tempTransitionFrom","tempTransitionTo","_transitionFromRef$cu","onfinish"],"sources":["@wordpress/block-editor/src/components/iframe/use-scale-canvas.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useEffect, useRef, useCallback } from '@wordpress/element';\nimport { useReducedMotion, useResizeObserver } from '@wordpress/compose';\n\n/**\n * @typedef {Object} TransitionState\n * @property {number} scaleValue Scale of the canvas.\n * @property {number} frameSize Size of the frame/offset around the canvas.\n * @property {number} clientHeight ClientHeight of the iframe.\n * @property {number} scrollTop ScrollTop of the iframe.\n * @property {number} scrollHeight ScrollHeight of the iframe.\n */\n\n/**\n * Calculate the scale of the canvas.\n *\n * @param {Object} options Object of options\n * @param {number} options.frameSize Size of the frame/offset around the canvas\n * @param {number} options.containerWidth Actual width of the canvas container\n * @param {number} options.maxContainerWidth Maximum width of the container to use for the scale calculation. This locks the canvas to a maximum width when zooming out.\n * @param {number} options.scaleContainerWidth Width the of the container wrapping the canvas container\n * @return {number} Scale value between 0 and/or equal to 1\n */\nfunction calculateScale( {\n\tframeSize,\n\tcontainerWidth,\n\tmaxContainerWidth,\n\tscaleContainerWidth,\n} ) {\n\treturn (\n\t\t( Math.min( containerWidth, maxContainerWidth ) - frameSize * 2 ) /\n\t\tscaleContainerWidth\n\t);\n}\n\n/**\n * Compute the next scrollTop position after scaling the iframe content.\n *\n * @param {TransitionState} transitionFrom Starting point of the transition\n * @param {TransitionState} transitionTo Ending state of the transition\n * @return {number} Next scrollTop position after scaling the iframe content.\n */\nfunction computeScrollTopNext( transitionFrom, transitionTo ) {\n\tconst {\n\t\tclientHeight: prevClientHeight,\n\t\tframeSize: prevFrameSize,\n\t\tscaleValue: prevScale,\n\t\tscrollTop,\n\t\tscrollHeight,\n\t} = transitionFrom;\n\tconst { clientHeight, frameSize, scaleValue } = transitionTo;\n\t// Step 0: Start with the current scrollTop.\n\tlet scrollTopNext = scrollTop;\n\t// Step 1: Undo the effects of the previous scale and frame around the\n\t// midpoint of the visible area.\n\tscrollTopNext =\n\t\t( scrollTopNext + prevClientHeight / 2 - prevFrameSize ) / prevScale -\n\t\tprevClientHeight / 2;\n\n\t// Step 2: Apply the new scale and frame around the midpoint of the\n\t// visible area.\n\tscrollTopNext =\n\t\t( scrollTopNext + clientHeight / 2 ) * scaleValue +\n\t\tframeSize -\n\t\tclientHeight / 2;\n\n\t// Step 3: Handle an edge case so that you scroll to the top of the\n\t// iframe if the top of the iframe content is visible in the container.\n\t// The same edge case for the bottom is skipped because changing content\n\t// makes calculating it impossible.\n\tscrollTopNext = scrollTop <= prevFrameSize ? 0 : scrollTopNext;\n\n\t// This is the scrollTop value if you are scrolled to the bottom of the\n\t// iframe. We can't just let the browser handle it because we need to\n\t// animate the scaling.\n\tconst maxScrollTop =\n\t\tscrollHeight * ( scaleValue / prevScale ) +\n\t\tframeSize * 2 -\n\t\tclientHeight;\n\n\t// Step 4: Clamp the scrollTopNext between the minimum and maximum\n\t// possible scrollTop positions. Round the value to avoid subpixel\n\t// truncation by the browser which sometimes causes a 1px error.\n\treturn Math.round(\n\t\tMath.min( Math.max( 0, scrollTopNext ), Math.max( 0, maxScrollTop ) )\n\t);\n}\n\n/**\n * Generate the keyframes to use for the zoom out animation.\n *\n * @param {TransitionState} transitionFrom Starting transition state.\n * @param {TransitionState} transitionTo Ending transition state.\n * @return {Object[]} An array of keyframes to use for the animation.\n */\nfunction getAnimationKeyframes( transitionFrom, transitionTo ) {\n\tconst {\n\t\tscaleValue: prevScale,\n\t\tframeSize: prevFrameSize,\n\t\tscrollTop,\n\t} = transitionFrom;\n\tconst { scaleValue, frameSize, scrollTop: scrollTopNext } = transitionTo;\n\n\treturn [\n\t\t{\n\t\t\ttranslate: `0 0`,\n\t\t\tscale: prevScale,\n\t\t\tpaddingTop: `${ prevFrameSize / prevScale }px`,\n\t\t\tpaddingBottom: `${ prevFrameSize / prevScale }px`,\n\t\t},\n\t\t{\n\t\t\ttranslate: `0 ${ scrollTop - scrollTopNext }px`,\n\t\t\tscale: scaleValue,\n\t\t\tpaddingTop: `${ frameSize / scaleValue }px`,\n\t\t\tpaddingBottom: `${ frameSize / scaleValue }px`,\n\t\t},\n\t];\n}\n\n/**\n * @typedef {Object} ScaleCanvasResult\n * @property {boolean} isZoomedOut A boolean indicating if the canvas is zoomed out.\n * @property {number} scaleContainerWidth The width of the container used to calculate the scale.\n * @property {Object} contentResizeListener A resize observer for the content.\n * @property {Object} containerResizeListener A resize observer for the container.\n */\n\n/**\n * Handles scaling the canvas for the zoom out mode and animating between\n * the states.\n *\n * @param {Object} options Object of options.\n * @param {number} options.frameSize Size of the frame around the content.\n * @param {Document} options.iframeDocument Document of the iframe.\n * @param {number} options.maxContainerWidth Max width of the canvas to use as the starting scale point. Defaults to 750.\n * @param {number|string} options.scale Scale of the canvas. Can be an decimal between 0 and 1, 1, or 'auto-scaled'.\n * @return {ScaleCanvasResult} Properties of the result.\n */\nexport function useScaleCanvas( {\n\tframeSize,\n\tiframeDocument,\n\tmaxContainerWidth = 750,\n\tscale,\n} ) {\n\tconst [ contentResizeListener, { height: contentHeight } ] =\n\t\tuseResizeObserver();\n\tconst [ containerResizeListener, { width: containerWidth } ] =\n\t\tuseResizeObserver();\n\n\tconst initialContainerWidthRef = useRef( 0 );\n\tconst isZoomedOut = scale !== 1;\n\tconst prefersReducedMotion = useReducedMotion();\n\tconst isAutoScaled = scale === 'auto-scaled';\n\t// Track if the animation should start when the useEffect runs.\n\tconst startAnimationRef = useRef( false );\n\t// Track the animation so we know if we have an animation running,\n\t// and can cancel it, reverse it, call a finish event, etc.\n\tconst animationRef = useRef( null );\n\n\tuseEffect( () => {\n\t\tif ( ! isZoomedOut ) {\n\t\t\tinitialContainerWidthRef.current = containerWidth;\n\t\t}\n\t}, [ containerWidth, isZoomedOut ] );\n\n\tconst scaleContainerWidth = Math.max(\n\t\tinitialContainerWidthRef.current,\n\t\tcontainerWidth\n\t);\n\n\tconst scaleValue = isAutoScaled\n\t\t? calculateScale( {\n\t\t\t\tframeSize,\n\t\t\t\tcontainerWidth,\n\t\t\t\tmaxContainerWidth,\n\t\t\t\tscaleContainerWidth,\n\t\t } )\n\t\t: scale;\n\n\t/**\n\t * The starting transition state for the zoom out animation.\n\t * @type {import('react').RefObject<TransitionState>}\n\t */\n\tconst transitionFromRef = useRef( {\n\t\tscaleValue,\n\t\tframeSize,\n\t\tclientHeight: 0,\n\t\tscrollTop: 0,\n\t\tscrollHeight: 0,\n\t} );\n\n\t/**\n\t * The ending transition state for the zoom out animation.\n\t * @type {import('react').RefObject<TransitionState>}\n\t */\n\tconst transitionToRef = useRef( {\n\t\tscaleValue,\n\t\tframeSize,\n\t\tclientHeight: 0,\n\t\tscrollTop: 0,\n\t\tscrollHeight: 0,\n\t} );\n\n\t/**\n\t * Start the zoom out animation. This sets the necessary CSS variables\n\t * for animating the canvas and returns the Animation object.\n\t *\n\t * @return {Animation} The animation object for the zoom out animation.\n\t */\n\tconst startZoomOutAnimation = useCallback( () => {\n\t\tconst { scrollTop } = transitionFromRef.current;\n\t\tconst { scrollTop: scrollTopNext } = transitionToRef.current;\n\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scroll-top',\n\t\t\t`${ scrollTop }px`\n\t\t);\n\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scroll-top-next',\n\t\t\t`${ scrollTopNext }px`\n\t\t);\n\n\t\tiframeDocument.documentElement.classList.add( 'zoom-out-animation' );\n\n\t\treturn iframeDocument.documentElement.animate(\n\t\t\tgetAnimationKeyframes(\n\t\t\t\ttransitionFromRef.current,\n\t\t\t\ttransitionToRef.current\n\t\t\t),\n\t\t\t{\n\t\t\t\teasing: 'cubic-bezier(0.46, 0.03, 0.52, 0.96)',\n\t\t\t\tduration: 400,\n\t\t\t}\n\t\t);\n\t}, [ iframeDocument ] );\n\n\t/**\n\t * Callback when the zoom out animation is finished.\n\t * - Cleans up animations refs.\n\t * - Adds final CSS vars for scale and frame size to preserve the state.\n\t * - Removes the 'zoom-out-animation' class (which has the fixed positioning).\n\t * - Sets the final scroll position after the canvas is no longer in fixed position.\n\t * - Removes CSS vars related to the animation.\n\t * - Sets the transitionFrom to the transitionTo state to be ready for the next animation.\n\t */\n\tconst finishZoomOutAnimation = useCallback( () => {\n\t\tstartAnimationRef.current = false;\n\t\tanimationRef.current = null;\n\n\t\t// Add our final scale and frame size now that the animation is done.\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scale',\n\t\t\ttransitionToRef.current.scaleValue\n\t\t);\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-frame-size',\n\t\t\t`${ transitionToRef.current.frameSize }px`\n\t\t);\n\n\t\tiframeDocument.documentElement.classList.remove( 'zoom-out-animation' );\n\n\t\t// Set the final scroll position that was just animated to.\n\t\t// Disable reason: Eslint isn't smart enough to know that this is a\n\t\t// DOM element. https://github.com/facebook/react/issues/31483\n\t\t// eslint-disable-next-line react-compiler/react-compiler\n\t\tiframeDocument.documentElement.scrollTop =\n\t\t\ttransitionToRef.current.scrollTop;\n\n\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scroll-top'\n\t\t);\n\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scroll-top-next'\n\t\t);\n\n\t\t// Update previous values.\n\t\ttransitionFromRef.current = transitionToRef.current;\n\t}, [ iframeDocument ] );\n\n\t/**\n\t * Runs when zoom out mode is toggled, and sets the startAnimation flag\n\t * so the animation will start when the next useEffect runs. We _only_\n\t * want to animate when the zoom out mode is toggled, not when the scale\n\t * changes due to the container resizing.\n\t */\n\tuseEffect( () => {\n\t\tif ( ! iframeDocument ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isZoomedOut ) {\n\t\t\tiframeDocument.documentElement.classList.add( 'is-zoomed-out' );\n\t\t}\n\n\t\tstartAnimationRef.current = true;\n\n\t\treturn () => {\n\t\t\tiframeDocument.documentElement.classList.remove( 'is-zoomed-out' );\n\t\t};\n\t}, [ iframeDocument, isZoomedOut ] );\n\n\t/**\n\t * This handles:\n\t * 1. Setting the correct scale and vars of the canvas when zoomed out\n\t * 2. If zoom out mode has been toggled, runs the animation of zooming in/out\n\t */\n\tuseEffect( () => {\n\t\tif ( ! iframeDocument ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We need to update the appropriate scale to exit from. If sidebars have been opened since setting the\n\t\t// original scale, we will snap to a much smaller scale due to the scale container immediately changing sizes when exiting.\n\t\tif ( isAutoScaled && transitionFromRef.current.scaleValue !== 1 ) {\n\t\t\t// We use containerWidth as the divisor, as scaleContainerWidth will always match the containerWidth when\n\t\t\t// exiting.\n\t\t\ttransitionFromRef.current.scaleValue = calculateScale( {\n\t\t\t\tframeSize: transitionFromRef.current.frameSize,\n\t\t\t\tcontainerWidth,\n\t\t\t\tmaxContainerWidth,\n\t\t\t\tscaleContainerWidth: containerWidth,\n\t\t\t} );\n\t\t}\n\n\t\t// If we are not going to animate the transition, set the scale and frame size directly.\n\t\t// If we are animating, these values will be set when the animation is finished.\n\t\t// Example: Opening sidebars that reduce the scale of the canvas, but we don't want to\n\t\t// animate the transition.\n\t\tif ( ! startAnimationRef.current ) {\n\t\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-scale',\n\t\t\t\tscaleValue\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-frame-size',\n\t\t\t\t`${ frameSize }px`\n\t\t\t);\n\t\t}\n\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-content-height',\n\t\t\t`${ contentHeight }px`\n\t\t);\n\n\t\tconst clientHeight = iframeDocument.documentElement.clientHeight;\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-inner-height',\n\t\t\t`${ clientHeight }px`\n\t\t);\n\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-container-width',\n\t\t\t`${ containerWidth }px`\n\t\t);\n\t\tiframeDocument.documentElement.style.setProperty(\n\t\t\t'--wp-block-editor-iframe-zoom-out-scale-container-width',\n\t\t\t`${ scaleContainerWidth }px`\n\t\t);\n\n\t\t/**\n\t\t * Handle the zoom out animation:\n\t\t *\n\t\t * - Get the current scrollTop position.\n\t\t * - Calculate where the same scroll position is after scaling.\n\t\t * - Apply fixed positioning to the canvas with a transform offset\n\t\t * to keep the canvas centered.\n\t\t * - Animate the scale and padding to the new scale and frame size.\n\t\t * - After the animation is complete, remove the fixed positioning\n\t\t * and set the scroll position that keeps everything centered.\n\t\t */\n\t\tif ( startAnimationRef.current ) {\n\t\t\t// Don't allow a new transition to start again unless it was started by the zoom out mode changing.\n\t\t\tstartAnimationRef.current = false;\n\n\t\t\t/**\n\t\t\t * If we already have an animation running, reverse it.\n\t\t\t */\n\t\t\tif ( animationRef.current ) {\n\t\t\t\tanimationRef.current.reverse();\n\t\t\t\t// Swap the transition to/from refs so that we set the correct values when\n\t\t\t\t// finishZoomOutAnimation runs.\n\t\t\t\tconst tempTransitionFrom = transitionFromRef.current;\n\t\t\t\tconst tempTransitionTo = transitionToRef.current;\n\t\t\t\ttransitionFromRef.current = tempTransitionTo;\n\t\t\t\ttransitionToRef.current = tempTransitionFrom;\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Start a new zoom animation.\n\t\t\t\t */\n\n\t\t\t\t// We can't trust the set value from contentHeight, as it was measured\n\t\t\t\t// before the zoom out mode was changed. After zoom out mode is changed,\n\t\t\t\t// appenders may appear or disappear, so we need to get the height from\n\t\t\t\t// the iframe at this point when we're about to animate the zoom out.\n\t\t\t\t// The iframe scrollTop, scrollHeight, and clientHeight will all be\n\t\t\t\t// the most accurate.\n\t\t\t\ttransitionFromRef.current.clientHeight =\n\t\t\t\t\ttransitionFromRef.current.clientHeight ?? clientHeight;\n\t\t\t\ttransitionFromRef.current.scrollTop =\n\t\t\t\t\tiframeDocument.documentElement.scrollTop;\n\t\t\t\ttransitionFromRef.current.scrollHeight =\n\t\t\t\t\tiframeDocument.documentElement.scrollHeight;\n\n\t\t\t\ttransitionToRef.current = {\n\t\t\t\t\tscaleValue,\n\t\t\t\t\tframeSize,\n\t\t\t\t\tclientHeight,\n\t\t\t\t};\n\t\t\t\ttransitionToRef.current.scrollTop = computeScrollTopNext(\n\t\t\t\t\ttransitionFromRef.current,\n\t\t\t\t\ttransitionToRef.current\n\t\t\t\t);\n\n\t\t\t\tanimationRef.current = startZoomOutAnimation();\n\n\t\t\t\t// If the user prefers reduced motion, finish the animation immediately and set the final state.\n\t\t\t\tif ( prefersReducedMotion ) {\n\t\t\t\t\tfinishZoomOutAnimation();\n\t\t\t\t} else {\n\t\t\t\t\tanimationRef.current.onfinish = finishZoomOutAnimation;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn () => {\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-scale'\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-frame-size'\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-content-height'\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-inner-height'\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-container-width'\n\t\t\t);\n\t\t\tiframeDocument.documentElement.style.removeProperty(\n\t\t\t\t'--wp-block-editor-iframe-zoom-out-scale-container-width'\n\t\t\t);\n\t\t};\n\t}, [\n\t\tstartZoomOutAnimation,\n\t\tfinishZoomOutAnimation,\n\t\tprefersReducedMotion,\n\t\tisAutoScaled,\n\t\tscaleValue,\n\t\tframeSize,\n\t\tiframeDocument,\n\t\tcontentHeight,\n\t\tcontainerWidth,\n\t\tmaxContainerWidth,\n\t\tscaleContainerWidth,\n\t] );\n\n\treturn {\n\t\tisZoomedOut,\n\t\tscaleContainerWidth,\n\t\tcontentResizeListener,\n\t\tcontainerResizeListener,\n\t};\n}\n"],"mappings":"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","ignoreList":[]}
@@ -17,6 +17,11 @@ var _dom = require("@wordpress/dom");
17
17
  // Disable Reason: Needs to be refactored.
18
18
  // eslint-disable-next-line no-restricted-imports
19
19
 
20
+ const messages = {
21
+ crop: (0, _i18n.__)('Image cropped.'),
22
+ rotate: (0, _i18n.__)('Image rotated.'),
23
+ cropAndRotate: (0, _i18n.__)('Image cropped and rotated.')
24
+ };
20
25
  function useSaveImage({
21
26
  crop,
22
27
  rotation,
@@ -26,7 +31,8 @@ function useSaveImage({
26
31
  onFinishEditing
27
32
  }) {
28
33
  const {
29
- createErrorNotice
34
+ createErrorNotice,
35
+ createSuccessNotice
30
36
  } = (0, _data.useDispatch)(_notices.store);
31
37
  const [isInProgress, setIsInProgress] = (0, _element.useState)(false);
32
38
  const cancel = (0, _element.useCallback)(() => {
@@ -64,6 +70,7 @@ function useSaveImage({
64
70
  onFinishEditing();
65
71
  return;
66
72
  }
73
+ const modifierType = modifiers.length === 1 ? modifiers[0].type : 'cropAndRotate';
67
74
  (0, _apiFetch.default)({
68
75
  path: `/wp/v2/media/${id}/edit`,
69
76
  method: 'POST',
@@ -76,8 +83,20 @@ function useSaveImage({
76
83
  id: response.id,
77
84
  url: response.source_url
78
85
  });
86
+ createSuccessNotice(messages[modifierType], {
87
+ type: 'snackbar',
88
+ actions: [{
89
+ label: (0, _i18n.__)('Undo'),
90
+ onClick: () => {
91
+ onSaveImage({
92
+ id,
93
+ url
94
+ });
95
+ }
96
+ }]
97
+ });
79
98
  }).catch(error => {
80
- createErrorNotice((0, _i18n.sprintf)(/* translators: 1. Error message */
99
+ createErrorNotice((0, _i18n.sprintf)(/* translators: %s: Error message. */
81
100
  (0, _i18n.__)('Could not edit image. %s'), (0, _dom.__unstableStripHTML)(error.message)), {
82
101
  id: 'image-editing-error',
83
102
  type: 'snackbar'
@@ -86,7 +105,7 @@ function useSaveImage({
86
105
  setIsInProgress(false);
87
106
  onFinishEditing();
88
107
  });
89
- }, [crop, rotation, id, url, onSaveImage, createErrorNotice, onFinishEditing]);
108
+ }, [crop, rotation, id, url, onSaveImage, createErrorNotice, createSuccessNotice, onFinishEditing]);
90
109
  return (0, _element.useMemo)(() => ({
91
110
  isInProgress,
92
111
  apply,
@@ -1 +1 @@
1
- {"version":3,"names":["_apiFetch","_interopRequireDefault","require","_data","_element","_i18n","_notices","_dom","useSaveImage","crop","rotation","url","id","onSaveImage","onFinishEditing","createErrorNotice","useDispatch","noticesStore","isInProgress","setIsInProgress","useState","cancel","useCallback","apply","modifiers","push","type","args","angle","width","height","left","x","top","y","length","apiFetch","path","method","data","src","then","response","source_url","catch","error","sprintf","__","stripHTML","message","finally","useMemo"],"sources":["@wordpress/block-editor/src/components/image-editor/use-save-image.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\n// Disable Reason: Needs to be refactored.\n// eslint-disable-next-line no-restricted-imports\nimport apiFetch from '@wordpress/api-fetch';\nimport { useDispatch } from '@wordpress/data';\nimport { useCallback, useMemo, useState } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { store as noticesStore } from '@wordpress/notices';\nimport { __unstableStripHTML as stripHTML } from '@wordpress/dom';\n\nexport default function useSaveImage( {\n\tcrop,\n\trotation,\n\turl,\n\tid,\n\tonSaveImage,\n\tonFinishEditing,\n} ) {\n\tconst { createErrorNotice } = useDispatch( noticesStore );\n\tconst [ isInProgress, setIsInProgress ] = useState( false );\n\n\tconst cancel = useCallback( () => {\n\t\tsetIsInProgress( false );\n\t\tonFinishEditing();\n\t}, [ onFinishEditing ] );\n\n\tconst apply = useCallback( () => {\n\t\tsetIsInProgress( true );\n\n\t\tconst modifiers = [];\n\n\t\tif ( rotation > 0 ) {\n\t\t\tmodifiers.push( {\n\t\t\t\ttype: 'rotate',\n\t\t\t\targs: {\n\t\t\t\t\tangle: rotation,\n\t\t\t\t},\n\t\t\t} );\n\t\t}\n\n\t\t// The crop script may return some very small, sub-pixel values when the image was not cropped.\n\t\t// Crop only when the new size has changed by more than 0.1%.\n\t\tif ( crop.width < 99.9 || crop.height < 99.9 ) {\n\t\t\tmodifiers.push( {\n\t\t\t\ttype: 'crop',\n\t\t\t\targs: {\n\t\t\t\t\tleft: crop.x,\n\t\t\t\t\ttop: crop.y,\n\t\t\t\t\twidth: crop.width,\n\t\t\t\t\theight: crop.height,\n\t\t\t\t},\n\t\t\t} );\n\t\t}\n\n\t\tif ( modifiers.length === 0 ) {\n\t\t\t// No changes to apply.\n\t\t\tsetIsInProgress( false );\n\t\t\tonFinishEditing();\n\t\t\treturn;\n\t\t}\n\n\t\tapiFetch( {\n\t\t\tpath: `/wp/v2/media/${ id }/edit`,\n\t\t\tmethod: 'POST',\n\t\t\tdata: { src: url, modifiers },\n\t\t} )\n\t\t\t.then( ( response ) => {\n\t\t\t\tonSaveImage( {\n\t\t\t\t\tid: response.id,\n\t\t\t\t\turl: response.source_url,\n\t\t\t\t} );\n\t\t\t} )\n\t\t\t.catch( ( error ) => {\n\t\t\t\tcreateErrorNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t/* translators: 1. Error message */\n\t\t\t\t\t\t__( 'Could not edit image. %s' ),\n\t\t\t\t\t\tstripHTML( error.message )\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\tid: 'image-editing-error',\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} )\n\t\t\t.finally( () => {\n\t\t\t\tsetIsInProgress( false );\n\t\t\t\tonFinishEditing();\n\t\t\t} );\n\t}, [\n\t\tcrop,\n\t\trotation,\n\t\tid,\n\t\turl,\n\t\tonSaveImage,\n\t\tcreateErrorNotice,\n\t\tonFinishEditing,\n\t] );\n\n\treturn useMemo(\n\t\t() => ( {\n\t\t\tisInProgress,\n\t\t\tapply,\n\t\t\tcancel,\n\t\t} ),\n\t\t[ isInProgress, apply, cancel ]\n\t);\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_apiFetch","_interopRequireDefault","require","_data","_element","_i18n","_notices","_dom","messages","crop","__","rotate","cropAndRotate","useSaveImage","rotation","url","id","onSaveImage","onFinishEditing","createErrorNotice","createSuccessNotice","useDispatch","noticesStore","isInProgress","setIsInProgress","useState","cancel","useCallback","apply","modifiers","push","type","args","angle","width","height","left","x","top","y","length","modifierType","apiFetch","path","method","data","src","then","response","source_url","actions","label","onClick","catch","error","sprintf","stripHTML","message","finally","useMemo"],"sources":["@wordpress/block-editor/src/components/image-editor/use-save-image.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\n// Disable Reason: Needs to be refactored.\n// eslint-disable-next-line no-restricted-imports\nimport apiFetch from '@wordpress/api-fetch';\nimport { useDispatch } from '@wordpress/data';\nimport { useCallback, useMemo, useState } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { store as noticesStore } from '@wordpress/notices';\nimport { __unstableStripHTML as stripHTML } from '@wordpress/dom';\n\nconst messages = {\n\tcrop: __( 'Image cropped.' ),\n\trotate: __( 'Image rotated.' ),\n\tcropAndRotate: __( 'Image cropped and rotated.' ),\n};\n\nexport default function useSaveImage( {\n\tcrop,\n\trotation,\n\turl,\n\tid,\n\tonSaveImage,\n\tonFinishEditing,\n} ) {\n\tconst { createErrorNotice, createSuccessNotice } =\n\t\tuseDispatch( noticesStore );\n\tconst [ isInProgress, setIsInProgress ] = useState( false );\n\n\tconst cancel = useCallback( () => {\n\t\tsetIsInProgress( false );\n\t\tonFinishEditing();\n\t}, [ onFinishEditing ] );\n\n\tconst apply = useCallback( () => {\n\t\tsetIsInProgress( true );\n\n\t\tconst modifiers = [];\n\n\t\tif ( rotation > 0 ) {\n\t\t\tmodifiers.push( {\n\t\t\t\ttype: 'rotate',\n\t\t\t\targs: {\n\t\t\t\t\tangle: rotation,\n\t\t\t\t},\n\t\t\t} );\n\t\t}\n\n\t\t// The crop script may return some very small, sub-pixel values when the image was not cropped.\n\t\t// Crop only when the new size has changed by more than 0.1%.\n\t\tif ( crop.width < 99.9 || crop.height < 99.9 ) {\n\t\t\tmodifiers.push( {\n\t\t\t\ttype: 'crop',\n\t\t\t\targs: {\n\t\t\t\t\tleft: crop.x,\n\t\t\t\t\ttop: crop.y,\n\t\t\t\t\twidth: crop.width,\n\t\t\t\t\theight: crop.height,\n\t\t\t\t},\n\t\t\t} );\n\t\t}\n\n\t\tif ( modifiers.length === 0 ) {\n\t\t\t// No changes to apply.\n\t\t\tsetIsInProgress( false );\n\t\t\tonFinishEditing();\n\t\t\treturn;\n\t\t}\n\n\t\tconst modifierType =\n\t\t\tmodifiers.length === 1 ? modifiers[ 0 ].type : 'cropAndRotate';\n\n\t\tapiFetch( {\n\t\t\tpath: `/wp/v2/media/${ id }/edit`,\n\t\t\tmethod: 'POST',\n\t\t\tdata: { src: url, modifiers },\n\t\t} )\n\t\t\t.then( ( response ) => {\n\t\t\t\tonSaveImage( {\n\t\t\t\t\tid: response.id,\n\t\t\t\t\turl: response.source_url,\n\t\t\t\t} );\n\t\t\t\tcreateSuccessNotice( messages[ modifierType ], {\n\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\tactions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: __( 'Undo' ),\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tonSaveImage( {\n\t\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t} );\n\t\t\t} )\n\t\t\t.catch( ( error ) => {\n\t\t\t\tcreateErrorNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t/* translators: %s: Error message. */\n\t\t\t\t\t\t__( 'Could not edit image. %s' ),\n\t\t\t\t\t\tstripHTML( error.message )\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\tid: 'image-editing-error',\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} )\n\t\t\t.finally( () => {\n\t\t\t\tsetIsInProgress( false );\n\t\t\t\tonFinishEditing();\n\t\t\t} );\n\t}, [\n\t\tcrop,\n\t\trotation,\n\t\tid,\n\t\turl,\n\t\tonSaveImage,\n\t\tcreateErrorNotice,\n\t\tcreateSuccessNotice,\n\t\tonFinishEditing,\n\t] );\n\n\treturn useMemo(\n\t\t() => ( {\n\t\t\tisInProgress,\n\t\t\tapply,\n\t\t\tcancel,\n\t\t} ),\n\t\t[ isInProgress, apply, cancel ]\n\t);\n}\n"],"mappings":"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","ignoreList":[]}
@@ -69,7 +69,9 @@ export function PrivateBlockToolbar({
69
69
  showSlots,
70
70
  showGroupButtons,
71
71
  showLockButtons,
72
- showSwitchSectionStyleButton
72
+ showSwitchSectionStyleButton,
73
+ hasFixedToolbar,
74
+ isNavigationMode
73
75
  } = useSelect(select => {
74
76
  const {
75
77
  getBlockName,
@@ -81,8 +83,10 @@ export function PrivateBlockToolbar({
81
83
  getBlockAttributes,
82
84
  getBlockParentsByBlockName,
83
85
  getTemplateLock,
86
+ getSettings,
84
87
  getParentSectionBlock,
85
- isZoomOut
88
+ isZoomOut,
89
+ isNavigationMode: _isNavigationMode
86
90
  } = unlock(select(blockEditorStore));
87
91
  const selectedBlockClientIds = getSelectedBlockClientIds();
88
92
  const selectedBlockClientId = selectedBlockClientIds[0];
@@ -116,7 +120,9 @@ export function PrivateBlockToolbar({
116
120
  showSlots: !isZoomOut(),
117
121
  showGroupButtons: !isZoomOut(),
118
122
  showLockButtons: !isZoomOut(),
119
- showSwitchSectionStyleButton: isZoomOut()
123
+ showSwitchSectionStyleButton: isZoomOut(),
124
+ hasFixedToolbar: getSettings().hasFixedToolbar,
125
+ isNavigationMode: _isNavigationMode()
120
126
  };
121
127
  }, []);
122
128
  const toolbarWrapperRef = useRef(null);
@@ -137,7 +143,8 @@ export function PrivateBlockToolbar({
137
143
 
138
144
  // Shifts the toolbar to make room for the parent block selector.
139
145
  const classes = clsx('block-editor-block-contextual-toolbar', {
140
- 'has-parent': showParentSelector
146
+ 'has-parent': showParentSelector,
147
+ 'is-inverted-toolbar': isNavigationMode && !hasFixedToolbar
141
148
  });
142
149
  const innerClasses = clsx('block-editor-block-toolbar', {
143
150
  'is-synced': isSynced,