@wordpress/editor 14.47.0 → 14.48.1
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.
- package/CHANGELOG.md +26 -0
- package/build/components/block-removal-warnings/index.cjs +0 -3
- package/build/components/block-removal-warnings/index.cjs.map +2 -2
- package/build/components/collab-sidebar/note-indicator-toolbar.cjs +49 -43
- package/build/components/collab-sidebar/note-indicator-toolbar.cjs.map +3 -3
- package/build/components/collaborators-overlay/use-block-highlighting.cjs +1 -8
- package/build/components/collaborators-overlay/use-block-highlighting.cjs.map +3 -3
- package/build/components/collaborators-overlay/use-render-cursors.cjs +1 -7
- package/build/components/collaborators-overlay/use-render-cursors.cjs.map +3 -3
- package/build/components/more-menu/view-more-menu-group.cjs +1 -2
- package/build/components/more-menu/view-more-menu-group.cjs.map +2 -2
- package/build/components/page-attributes/parent.cjs +1 -0
- package/build/components/page-attributes/parent.cjs.map +2 -2
- package/build/components/post-publish-button/index.cjs +114 -157
- package/build/components/post-publish-button/index.cjs.map +3 -3
- package/build/components/post-revisions-preview/block-diff.cjs +21 -9
- package/build/components/post-revisions-preview/block-diff.cjs.map +2 -2
- package/build/components/post-revisions-preview/preserve-client-ids.cjs +2 -2
- package/build/components/post-revisions-preview/preserve-client-ids.cjs.map +2 -2
- package/build/components/provider/index.cjs +2 -0
- package/build/components/provider/index.cjs.map +3 -3
- package/build/components/provider/use-block-editor-settings.cjs +1 -1
- package/build/components/provider/use-block-editor-settings.cjs.map +2 -2
- package/build/components/provider/use-network-reconnect.cjs +51 -0
- package/build/components/provider/use-network-reconnect.cjs.map +7 -0
- package/build/components/revision-fields-diff/index.cjs +2 -2
- package/build/components/revision-fields-diff/index.cjs.map +2 -2
- package/build/components/sidebar/index.cjs +1 -4
- package/build/components/sidebar/index.cjs.map +2 -2
- package/build/components/template-actions-panel/block-theme-content.cjs +7 -1
- package/build/components/template-actions-panel/block-theme-content.cjs.map +2 -2
- package/build/components/upload-progress-snackbar/index.cjs +161 -0
- package/build/components/upload-progress-snackbar/index.cjs.map +7 -0
- package/build/components/upload-progress-snackbar/tracker.cjs +90 -0
- package/build/components/upload-progress-snackbar/tracker.cjs.map +7 -0
- package/build/private-apis.cjs +2 -0
- package/build/private-apis.cjs.map +3 -3
- package/build/store/selectors.cjs +1 -2
- package/build/store/selectors.cjs.map +2 -2
- package/build/utils/media-upload/index.cjs +16 -0
- package/build/utils/media-upload/index.cjs.map +3 -3
- package/build-module/components/block-removal-warnings/index.mjs +0 -3
- package/build-module/components/block-removal-warnings/index.mjs.map +2 -2
- package/build-module/components/collab-sidebar/note-indicator-toolbar.mjs +53 -44
- package/build-module/components/collab-sidebar/note-indicator-toolbar.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/use-block-highlighting.mjs +1 -8
- package/build-module/components/collaborators-overlay/use-block-highlighting.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/use-render-cursors.mjs +1 -7
- package/build-module/components/collaborators-overlay/use-render-cursors.mjs.map +2 -2
- package/build-module/components/more-menu/view-more-menu-group.mjs +1 -2
- package/build-module/components/more-menu/view-more-menu-group.mjs.map +2 -2
- package/build-module/components/page-attributes/parent.mjs +1 -0
- package/build-module/components/page-attributes/parent.mjs.map +2 -2
- package/build-module/components/post-publish-button/index.mjs +116 -159
- package/build-module/components/post-publish-button/index.mjs.map +2 -2
- package/build-module/components/post-revisions-preview/block-diff.mjs +20 -8
- package/build-module/components/post-revisions-preview/block-diff.mjs.map +2 -2
- package/build-module/components/post-revisions-preview/preserve-client-ids.mjs +1 -1
- package/build-module/components/post-revisions-preview/preserve-client-ids.mjs.map +1 -1
- package/build-module/components/provider/index.mjs +2 -0
- package/build-module/components/provider/index.mjs.map +2 -2
- package/build-module/components/provider/use-block-editor-settings.mjs +1 -1
- package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
- package/build-module/components/provider/use-network-reconnect.mjs +30 -0
- package/build-module/components/provider/use-network-reconnect.mjs.map +7 -0
- package/build-module/components/revision-fields-diff/index.mjs +2 -2
- package/build-module/components/revision-fields-diff/index.mjs.map +2 -2
- package/build-module/components/sidebar/index.mjs +2 -11
- package/build-module/components/sidebar/index.mjs.map +2 -2
- package/build-module/components/template-actions-panel/block-theme-content.mjs +7 -1
- package/build-module/components/template-actions-panel/block-theme-content.mjs.map +2 -2
- package/build-module/components/upload-progress-snackbar/index.mjs +135 -0
- package/build-module/components/upload-progress-snackbar/index.mjs.map +7 -0
- package/build-module/components/upload-progress-snackbar/tracker.mjs +61 -0
- package/build-module/components/upload-progress-snackbar/tracker.mjs.map +7 -0
- package/build-module/private-apis.mjs +2 -0
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/store/selectors.mjs +1 -2
- package/build-module/store/selectors.mjs.map +2 -2
- package/build-module/utils/media-upload/index.mjs +19 -0
- package/build-module/utils/media-upload/index.mjs.map +2 -2
- package/build-style/style-rtl.css +479 -84
- package/build-style/style.css +479 -84
- package/build-types/components/block-removal-warnings/index.d.ts.map +1 -1
- package/build-types/components/collab-sidebar/add-comment.d.ts +6 -0
- package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-author-info.d.ts +8 -0
- package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-form.d.ts +9 -0
- package/build-types/components/collab-sidebar/comment-form.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts +6 -0
- package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comment-menu-item.d.ts +6 -0
- package/build-types/components/collab-sidebar/comment-menu-item.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/comments.d.ts +10 -0
- package/build-types/components/collab-sidebar/comments.d.ts.map +1 -0
- package/build-types/components/collab-sidebar/note-indicator-toolbar.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts +0 -3
- package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/use-render-cursors.d.ts.map +1 -1
- package/build-types/components/document-bar/index.d.ts +2 -2
- package/build-types/components/document-bar/index.d.ts.map +1 -1
- package/build-types/components/global-styles-provider/index.d.ts +16 -0
- package/build-types/components/global-styles-provider/index.d.ts.map +1 -0
- package/build-types/components/media/index.d.ts +3 -0
- package/build-types/components/media/index.d.ts.map +1 -0
- package/build-types/components/media/metadata-panel.d.ts +12 -0
- package/build-types/components/media/metadata-panel.d.ts.map +1 -0
- package/build-types/components/media/preview.d.ts +9 -0
- package/build-types/components/media/preview.d.ts.map +1 -0
- package/build-types/components/more-menu/view-more-menu-group.d.ts.map +1 -1
- package/build-types/components/page-attributes/parent.d.ts.map +1 -1
- package/build-types/components/post-locked-modal/index.d.ts +6 -1
- package/build-types/components/post-publish-button/index.d.ts +9 -9
- package/build-types/components/post-publish-button/index.d.ts.map +1 -1
- package/build-types/components/post-revisions-preview/block-diff.d.ts +3 -0
- package/build-types/components/post-revisions-preview/block-diff.d.ts.map +1 -1
- package/build-types/components/post-taxonomies/flat-term-selector.d.ts +6 -1
- package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts +6 -1
- package/build-types/components/post-text-editor/index.d.ts +1 -1
- package/build-types/components/post-text-editor/index.d.ts.map +1 -1
- package/build-types/components/post-text-editor/utils.d.ts +29 -0
- package/build-types/components/post-text-editor/utils.d.ts.map +1 -0
- package/build-types/components/provider/index.d.ts.map +1 -1
- package/build-types/components/provider/use-network-reconnect.d.ts +8 -0
- package/build-types/components/provider/use-network-reconnect.d.ts.map +1 -0
- package/build-types/components/revision-fields-diff/index.d.ts +3 -0
- package/build-types/components/revision-fields-diff/index.d.ts.map +1 -1
- package/build-types/components/sidebar/index.d.ts.map +1 -1
- package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -1
- package/build-types/components/upload-progress-snackbar/index.d.ts +19 -0
- package/build-types/components/upload-progress-snackbar/index.d.ts.map +1 -0
- package/build-types/components/upload-progress-snackbar/stories/index.story.d.ts +28 -0
- package/build-types/components/upload-progress-snackbar/stories/index.story.d.ts.map +1 -0
- package/build-types/components/upload-progress-snackbar/tracker.d.ts +41 -0
- package/build-types/components/upload-progress-snackbar/tracker.d.ts.map +1 -0
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/store/selectors.d.ts.map +1 -1
- package/build-types/utils/get-template-part-icon.d.ts.map +1 -1
- package/build-types/utils/media-upload/index.d.ts.map +1 -1
- package/package.json +55 -52
- package/src/components/README.md +1 -1
- package/src/components/block-removal-warnings/index.js +0 -7
- package/src/components/collab-sidebar/note-indicator-toolbar.js +73 -60
- package/src/components/collaborators-overlay/use-block-highlighting.ts +0 -9
- package/src/components/collaborators-overlay/use-render-cursors.ts +0 -8
- package/src/components/collaborators-presence/avatar/test/index.tsx +8 -3
- package/src/components/more-menu/view-more-menu-group.js +1 -2
- package/src/components/page-attributes/parent.js +1 -0
- package/src/components/post-publish-button/index.js +143 -192
- package/src/components/post-publish-button/test/index.js +137 -114
- package/src/components/post-revisions-preview/block-diff.js +63 -19
- package/src/components/post-revisions-preview/preserve-client-ids.js +1 -1
- package/src/components/post-revisions-preview/test/block-diff.js +109 -6
- package/src/components/provider/index.js +4 -0
- package/src/components/provider/test/use-network-reconnect.js +137 -0
- package/src/components/provider/use-block-editor-settings.js +2 -2
- package/src/components/provider/use-network-reconnect.js +44 -0
- package/src/components/revision-fields-diff/index.js +7 -2
- package/src/components/sidebar/index.js +2 -11
- package/src/components/template-actions-panel/block-theme-content.js +10 -1
- package/src/components/upload-progress-snackbar/README.md +26 -0
- package/src/components/upload-progress-snackbar/index.js +216 -0
- package/src/components/upload-progress-snackbar/stories/index.story.tsx +85 -0
- package/src/components/upload-progress-snackbar/style.scss +30 -0
- package/src/components/upload-progress-snackbar/test/index.js +199 -0
- package/src/components/upload-progress-snackbar/tracker.js +105 -0
- package/src/private-apis.js +2 -0
- package/src/store/selectors.js +1 -3
- package/src/style.scss +1 -0
- package/src/utils/media-upload/index.js +27 -0
- package/src/components/commands/index.native.js +0 -2
- package/src/components/deprecated.native.js +0 -47
- package/src/components/editor-help/add-blocks.native.js +0 -40
- package/src/components/editor-help/customize-blocks.native.js +0 -40
- package/src/components/editor-help/help-detail-navigation-screen.native.js +0 -67
- package/src/components/editor-help/help-get-support-button.native.js +0 -38
- package/src/components/editor-help/help-section-title.native.js +0 -29
- package/src/components/editor-help/help-topic-row.native.js +0 -33
- package/src/components/editor-help/icon-move-blocks.native.js +0 -10
- package/src/components/editor-help/index.native.js +0 -208
- package/src/components/editor-help/intro-to-blocks.native.js +0 -91
- package/src/components/editor-help/move-blocks.native.js +0 -55
- package/src/components/editor-help/remove-blocks.native.js +0 -35
- package/src/components/editor-help/style.android.scss +0 -6
- package/src/components/editor-help/style.ios.scss +0 -6
- package/src/components/editor-help/test/index.native.js +0 -81
- package/src/components/editor-help/view-sections.native.js +0 -79
- package/src/components/error-boundary/index.native.js +0 -192
- package/src/components/error-boundary/style.native.scss +0 -116
- package/src/components/index.native.js +0 -15
- package/src/components/offline-status/index.native.js +0 -99
- package/src/components/offline-status/style.native.scss +0 -28
- package/src/components/offline-status/test/index.native.js +0 -108
- package/src/components/post-title/index.native.js +0 -282
- package/src/components/post-title/style.native.scss +0 -13
- package/src/components/post-title/test/__snapshots__/index.native.js.snap +0 -25
- package/src/components/post-title/test/index.native.js +0 -78
- package/src/components/provider/index.native.js +0 -497
- package/src/components/provider/use-block-editor-settings.native.js +0 -48
- package/src/components/template-part-menu-items/index.native.js +0 -3
- package/src/hooks/index.native.js +0 -0
- package/src/index.native.js +0 -16
- package/src/private-apis.native.js +0 -33
- package/src/store/actions.native.js +0 -27
- package/src/store/reducer.native.js +0 -94
- package/src/store/selectors.native.js +0 -57
- package/src/store/test/actions.native.js +0 -16
- package/src/store/test/reducer.native.js +0 -36
- package/src/store/test/selectors.native.js +0 -28
- package/src/utils/index.native.js +0 -6
- package/src/utils/media-sideload/index.native.js +0 -1
- package/src/utils/media-upload/index.native.js +0 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, act } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useSelect } from '@wordpress/data';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import UploadProgressSnackbar from '../';
|
|
15
|
+
import { addFiles, advance, reset } from '../tracker';
|
|
16
|
+
|
|
17
|
+
jest.mock( '@wordpress/data/src/components/use-select', () => {
|
|
18
|
+
const mock = jest.fn();
|
|
19
|
+
return mock;
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
const mockCreateNotice = jest.fn();
|
|
23
|
+
const mockRemoveNotice = jest.fn();
|
|
24
|
+
|
|
25
|
+
jest.mock( '@wordpress/data/src/components/use-dispatch', () => {
|
|
26
|
+
return {
|
|
27
|
+
useDispatch: jest.fn( () => ( {
|
|
28
|
+
createNotice: mockCreateNotice,
|
|
29
|
+
removeNotice: mockRemoveNotice,
|
|
30
|
+
} ) ),
|
|
31
|
+
useDispatchWithMap: jest.fn(),
|
|
32
|
+
};
|
|
33
|
+
} );
|
|
34
|
+
|
|
35
|
+
jest.mock( '@wordpress/a11y', () => ( {
|
|
36
|
+
speak: jest.fn(),
|
|
37
|
+
} ) );
|
|
38
|
+
|
|
39
|
+
function mockQueue( items ) {
|
|
40
|
+
useSelect.mockImplementation( ( mapSelect ) =>
|
|
41
|
+
mapSelect( () => ( {
|
|
42
|
+
getItems: () => items,
|
|
43
|
+
isUploading: () => items.length > 0,
|
|
44
|
+
} ) )
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function makeItem( id, name, { parentId } = {} ) {
|
|
49
|
+
return {
|
|
50
|
+
id,
|
|
51
|
+
sourceFile: { name },
|
|
52
|
+
status: 'PROCESSING',
|
|
53
|
+
parentId,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe( 'UploadProgressSnackbar', () => {
|
|
58
|
+
beforeEach( () => {
|
|
59
|
+
jest.clearAllMocks();
|
|
60
|
+
reset();
|
|
61
|
+
} );
|
|
62
|
+
|
|
63
|
+
it( 'does not create a notice when both sources are empty', () => {
|
|
64
|
+
mockQueue( [] );
|
|
65
|
+
render( <UploadProgressSnackbar /> );
|
|
66
|
+
expect( mockCreateNotice ).not.toHaveBeenCalled();
|
|
67
|
+
} );
|
|
68
|
+
|
|
69
|
+
it( 'creates a notice with the filename when a single CSM upload is in progress', () => {
|
|
70
|
+
mockQueue( [ makeItem( '1', 'photo.jpg' ) ] );
|
|
71
|
+
render( <UploadProgressSnackbar /> );
|
|
72
|
+
expect( mockCreateNotice ).toHaveBeenCalledWith(
|
|
73
|
+
'info',
|
|
74
|
+
expect.stringContaining( 'photo.jpg' ),
|
|
75
|
+
expect.objectContaining( {
|
|
76
|
+
id: 'upload-progress',
|
|
77
|
+
type: 'snackbar',
|
|
78
|
+
} )
|
|
79
|
+
);
|
|
80
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toBe(
|
|
81
|
+
'Uploading — photo.jpg'
|
|
82
|
+
);
|
|
83
|
+
} );
|
|
84
|
+
|
|
85
|
+
it( 'shows batch count for CSM uploads', () => {
|
|
86
|
+
mockQueue( [
|
|
87
|
+
makeItem( '1', 'a.jpg' ),
|
|
88
|
+
makeItem( '2', 'b.jpg' ),
|
|
89
|
+
makeItem( '3', 'c.jpg' ),
|
|
90
|
+
] );
|
|
91
|
+
render( <UploadProgressSnackbar /> );
|
|
92
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toMatch( /1 of 3/ );
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
it( 'excludes subsizes from the CSM count', () => {
|
|
96
|
+
mockQueue( [
|
|
97
|
+
makeItem( '1', 'photo.jpg' ),
|
|
98
|
+
makeItem( '1-thumb', 'photo-150x150.jpg', { parentId: '1' } ),
|
|
99
|
+
makeItem( '1-medium', 'photo-300x300.jpg', { parentId: '1' } ),
|
|
100
|
+
] );
|
|
101
|
+
render( <UploadProgressSnackbar /> );
|
|
102
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toBe(
|
|
103
|
+
'Uploading — photo.jpg'
|
|
104
|
+
);
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
it( 'shows non-CSM uploads tracked by the editor mediaUpload wrapper', () => {
|
|
108
|
+
mockQueue( [] );
|
|
109
|
+
act( () => {
|
|
110
|
+
addFiles( [ 'traditional.jpg' ] );
|
|
111
|
+
} );
|
|
112
|
+
render( <UploadProgressSnackbar /> );
|
|
113
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toBe(
|
|
114
|
+
'Uploading — traditional.jpg'
|
|
115
|
+
);
|
|
116
|
+
} );
|
|
117
|
+
|
|
118
|
+
it( 'shows batch count for non-CSM uploads', () => {
|
|
119
|
+
mockQueue( [] );
|
|
120
|
+
act( () => {
|
|
121
|
+
addFiles( [ 'a.jpg', 'b.jpg', 'c.jpg' ] );
|
|
122
|
+
} );
|
|
123
|
+
render( <UploadProgressSnackbar /> );
|
|
124
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toMatch( /1 of 3/ );
|
|
125
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toMatch( /a\.jpg/ );
|
|
126
|
+
} );
|
|
127
|
+
|
|
128
|
+
it( 'shows a completion notice and then removes it when uploads finish', () => {
|
|
129
|
+
jest.useFakeTimers();
|
|
130
|
+
try {
|
|
131
|
+
mockQueue( [] );
|
|
132
|
+
act( () => {
|
|
133
|
+
addFiles( [ 'a.jpg' ] );
|
|
134
|
+
} );
|
|
135
|
+
render( <UploadProgressSnackbar /> );
|
|
136
|
+
expect( mockCreateNotice ).toHaveBeenCalled();
|
|
137
|
+
mockCreateNotice.mockClear();
|
|
138
|
+
|
|
139
|
+
act( () => {
|
|
140
|
+
advance( 1 );
|
|
141
|
+
} );
|
|
142
|
+
|
|
143
|
+
// Completion notice replaces the progress notice (same ID).
|
|
144
|
+
expect( mockCreateNotice ).toHaveBeenCalledWith(
|
|
145
|
+
'info',
|
|
146
|
+
'Upload complete',
|
|
147
|
+
expect.objectContaining( {
|
|
148
|
+
id: 'upload-progress',
|
|
149
|
+
type: 'snackbar',
|
|
150
|
+
icon: expect.anything(),
|
|
151
|
+
} )
|
|
152
|
+
);
|
|
153
|
+
expect( mockRemoveNotice ).not.toHaveBeenCalled();
|
|
154
|
+
|
|
155
|
+
act( () => {
|
|
156
|
+
jest.runAllTimers();
|
|
157
|
+
} );
|
|
158
|
+
|
|
159
|
+
expect( mockRemoveNotice ).toHaveBeenCalledWith(
|
|
160
|
+
'upload-progress'
|
|
161
|
+
);
|
|
162
|
+
} finally {
|
|
163
|
+
jest.useRealTimers();
|
|
164
|
+
}
|
|
165
|
+
} );
|
|
166
|
+
|
|
167
|
+
it( 'middle-truncates a long filename while keeping the extension', () => {
|
|
168
|
+
const longName =
|
|
169
|
+
'a-really-long-uuid-like-filename-1234567890-abcdefghij.jpg';
|
|
170
|
+
mockQueue( [ makeItem( '1', longName ) ] );
|
|
171
|
+
render( <UploadProgressSnackbar /> );
|
|
172
|
+
const content = mockCreateNotice.mock.calls[ 0 ][ 1 ];
|
|
173
|
+
// Truncated: shorter than the original, marked with an ellipsis, and the
|
|
174
|
+
// extension is still visible.
|
|
175
|
+
expect( content ).toContain( '…' );
|
|
176
|
+
expect( content ).not.toContain( longName );
|
|
177
|
+
expect( content ).toMatch( /\.jpg$/ );
|
|
178
|
+
} );
|
|
179
|
+
|
|
180
|
+
it( 'does not truncate a short filename', () => {
|
|
181
|
+
mockQueue( [ makeItem( '1', 'photo.jpg' ) ] );
|
|
182
|
+
render( <UploadProgressSnackbar /> );
|
|
183
|
+
expect( mockCreateNotice.mock.calls[ 0 ][ 1 ] ).toBe(
|
|
184
|
+
'Uploading — photo.jpg'
|
|
185
|
+
);
|
|
186
|
+
} );
|
|
187
|
+
|
|
188
|
+
it( 'includes a spinner icon on the in-progress notice', () => {
|
|
189
|
+
mockQueue( [ makeItem( '1', 'photo.jpg' ) ] );
|
|
190
|
+
render( <UploadProgressSnackbar /> );
|
|
191
|
+
expect( mockCreateNotice ).toHaveBeenCalledWith(
|
|
192
|
+
'info',
|
|
193
|
+
expect.any( String ),
|
|
194
|
+
expect.objectContaining( {
|
|
195
|
+
icon: expect.anything(),
|
|
196
|
+
} )
|
|
197
|
+
);
|
|
198
|
+
} );
|
|
199
|
+
} );
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSyncExternalStore } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A minimal in-memory tracker for in-flight media uploads that happen outside
|
|
8
|
+
* the `@wordpress/upload-media` store (i.e. the traditional / non-CSM upload
|
|
9
|
+
* path). The editor's `mediaUpload` wrapper writes to it; the
|
|
10
|
+
* `UploadProgressSnackbar` reads from it.
|
|
11
|
+
*
|
|
12
|
+
* State shape: { total, completed, pending: string[] }
|
|
13
|
+
* - `total`: total files registered in the current session.
|
|
14
|
+
* - `completed`: files that have finished (succeeded OR errored).
|
|
15
|
+
* - `pending`: remaining filenames in submission order.
|
|
16
|
+
*
|
|
17
|
+
* The tracker holds at most one "session" at a time — if a new batch starts
|
|
18
|
+
* while one is in progress, its files are appended to the existing session.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
let state = null;
|
|
22
|
+
const listeners = new Set();
|
|
23
|
+
|
|
24
|
+
function notify() {
|
|
25
|
+
listeners.forEach( ( listener ) => listener() );
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Registers a new batch of files that have started uploading.
|
|
30
|
+
*
|
|
31
|
+
* @param {string[]} filenames Filenames in submission order.
|
|
32
|
+
*/
|
|
33
|
+
export function addFiles( filenames ) {
|
|
34
|
+
if ( ! filenames.length ) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if ( ! state ) {
|
|
38
|
+
state = { total: 0, completed: 0, pending: [] };
|
|
39
|
+
}
|
|
40
|
+
state = {
|
|
41
|
+
total: state.total + filenames.length,
|
|
42
|
+
completed: state.completed,
|
|
43
|
+
pending: [ ...state.pending, ...filenames ],
|
|
44
|
+
};
|
|
45
|
+
notify();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Advances the tracker by a number of finished files (success or error).
|
|
50
|
+
*
|
|
51
|
+
* @param {number} count Number of files that finished since the last call.
|
|
52
|
+
*/
|
|
53
|
+
export function advance( count ) {
|
|
54
|
+
if ( ! state || count <= 0 ) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const completed = Math.min( state.total, state.completed + count );
|
|
58
|
+
const pending = state.pending.slice( count );
|
|
59
|
+
if ( completed >= state.total ) {
|
|
60
|
+
state = null;
|
|
61
|
+
} else {
|
|
62
|
+
state = { total: state.total, completed, pending };
|
|
63
|
+
}
|
|
64
|
+
notify();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resets the tracker to its empty state.
|
|
69
|
+
*
|
|
70
|
+
* Test-only helper: `state` is a module-level singleton, so tests call this in
|
|
71
|
+
* `beforeEach` to isolate cases from one another. Not used in production -
|
|
72
|
+
* `advance` clears the state on its own once every file in a batch finishes.
|
|
73
|
+
*/
|
|
74
|
+
export function reset() {
|
|
75
|
+
if ( state === null ) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
state = null;
|
|
79
|
+
notify();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns the current tracker state, or `null` when idle.
|
|
84
|
+
*
|
|
85
|
+
* @return {?{total: number, completed: number, pending: string[]}} Tracker state.
|
|
86
|
+
*/
|
|
87
|
+
export function getState() {
|
|
88
|
+
return state;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function subscribe( listener ) {
|
|
92
|
+
listeners.add( listener );
|
|
93
|
+
return () => {
|
|
94
|
+
listeners.delete( listener );
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* React hook that subscribes to the tracker.
|
|
100
|
+
*
|
|
101
|
+
* @return {?{total: number, completed: number, pending: string[]}} Tracker state.
|
|
102
|
+
*/
|
|
103
|
+
export function useTracker() {
|
|
104
|
+
return useSyncExternalStore( subscribe, getState, getState );
|
|
105
|
+
}
|
package/src/private-apis.js
CHANGED
|
@@ -29,6 +29,7 @@ import GlobalStylesUIWrapper from './components/global-styles';
|
|
|
29
29
|
import { StyleBookPreview } from './components/style-book';
|
|
30
30
|
import { useGlobalStyles, useStyle } from './components/global-styles/hooks';
|
|
31
31
|
import { GlobalStylesActionMenu } from './components/global-styles/menu';
|
|
32
|
+
import UploadProgressSnackbar from './components/upload-progress-snackbar';
|
|
32
33
|
|
|
33
34
|
const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis;
|
|
34
35
|
|
|
@@ -48,6 +49,7 @@ lock( privateApis, {
|
|
|
48
49
|
ToolsMoreMenuGroup,
|
|
49
50
|
ViewMoreMenuGroup,
|
|
50
51
|
ResizableEditor,
|
|
52
|
+
UploadProgressSnackbar,
|
|
51
53
|
registerCoreBlockBindingsSources,
|
|
52
54
|
getTemplateInfo,
|
|
53
55
|
// Global Styles
|
package/src/store/selectors.js
CHANGED
|
@@ -11,7 +11,6 @@ import { isInTheFuture, getDate } from '@wordpress/date';
|
|
|
11
11
|
import { addQueryArgs, cleanForSlug } from '@wordpress/url';
|
|
12
12
|
import { createSelector, createRegistrySelector } from '@wordpress/data';
|
|
13
13
|
import deprecated from '@wordpress/deprecated';
|
|
14
|
-
import { Platform } from '@wordpress/element';
|
|
15
14
|
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
16
15
|
import { store as coreStore } from '@wordpress/core-data';
|
|
17
16
|
import { store as preferencesStore } from '@wordpress/preferences';
|
|
@@ -524,8 +523,7 @@ export function isEditedPostSaveable( state ) {
|
|
|
524
523
|
return (
|
|
525
524
|
!! getEditedPostAttribute( state, 'title' ) ||
|
|
526
525
|
!! getEditedPostAttribute( state, 'excerpt' ) ||
|
|
527
|
-
! isEditedPostEmpty( state )
|
|
528
|
-
Platform.OS === 'native'
|
|
526
|
+
! isEditedPostEmpty( state )
|
|
529
527
|
);
|
|
530
528
|
}
|
|
531
529
|
|
package/src/style.scss
CHANGED
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
@use "./components/styles-canvas/style.scss" as *;
|
|
69
69
|
@use "./components/table-of-contents/style.scss" as *;
|
|
70
70
|
@use "./components/text-editor/style.scss" as *;
|
|
71
|
+
@use "./components/upload-progress-snackbar/style.scss" as *;
|
|
71
72
|
@use "./components/visual-editor/style.scss" as *;
|
|
72
73
|
@use "./dataviews/fields/content-preview/style.scss" as *;
|
|
73
74
|
@use "./hooks/push-changes-to-global-styles/style.scss" as *;
|
|
@@ -15,6 +15,10 @@ import { isClientSideMediaSupported } from '@wordpress/upload-media';
|
|
|
15
15
|
* Internal dependencies
|
|
16
16
|
*/
|
|
17
17
|
import { store as editorStore } from '../../store';
|
|
18
|
+
import {
|
|
19
|
+
addFiles as trackStart,
|
|
20
|
+
advance as trackAdvance,
|
|
21
|
+
} from '../../components/upload-progress-snackbar/tracker';
|
|
18
22
|
|
|
19
23
|
const noop = () => {};
|
|
20
24
|
|
|
@@ -78,6 +82,18 @@ export default function mediaUpload( {
|
|
|
78
82
|
|
|
79
83
|
const postData = currentPostId ? { post: currentPostId } : {};
|
|
80
84
|
|
|
85
|
+
// Track this batch for the upload progress snackbar. Only applies to the
|
|
86
|
+
// non-CSM path — when CSM is enabled, the block-editor provider intercepts
|
|
87
|
+
// mediaUpload and dispatches to the upload-media store, so this wrapper is
|
|
88
|
+
// not called.
|
|
89
|
+
if ( ! isClientSideMediaActive ) {
|
|
90
|
+
const trackingFiles = Array.from( filesList ).map(
|
|
91
|
+
( f ) => f?.name || ''
|
|
92
|
+
);
|
|
93
|
+
trackStart( trackingFiles );
|
|
94
|
+
}
|
|
95
|
+
let lastCompletedCount = 0;
|
|
96
|
+
|
|
81
97
|
uploadMedia( {
|
|
82
98
|
allowedTypes,
|
|
83
99
|
filesList,
|
|
@@ -106,6 +122,15 @@ export default function mediaUpload( {
|
|
|
106
122
|
) {
|
|
107
123
|
clearSaveLock();
|
|
108
124
|
}
|
|
125
|
+
|
|
126
|
+
// Advance the snackbar tracker for newly-completed files.
|
|
127
|
+
if ( ! isClientSideMediaActive ) {
|
|
128
|
+
const completedCount = entityFiles.length;
|
|
129
|
+
if ( completedCount > lastCompletedCount ) {
|
|
130
|
+
trackAdvance( completedCount - lastCompletedCount );
|
|
131
|
+
lastCompletedCount = completedCount;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
109
134
|
},
|
|
110
135
|
onSuccess,
|
|
111
136
|
additionalData: {
|
|
@@ -116,6 +141,8 @@ export default function mediaUpload( {
|
|
|
116
141
|
onError: ( { message } ) => {
|
|
117
142
|
if ( ! isClientSideMediaActive ) {
|
|
118
143
|
clearSaveLock();
|
|
144
|
+
// Failed files still count as "done" for the snackbar.
|
|
145
|
+
trackAdvance( 1 );
|
|
119
146
|
}
|
|
120
147
|
onError( message );
|
|
121
148
|
},
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Block Creation Components.
|
|
2
|
-
/**
|
|
3
|
-
* WordPress dependencies
|
|
4
|
-
*/
|
|
5
|
-
import {
|
|
6
|
-
BlockControls,
|
|
7
|
-
BlockEdit,
|
|
8
|
-
BlockFormatControls,
|
|
9
|
-
DefaultBlockAppender,
|
|
10
|
-
createCustomColorsHOC,
|
|
11
|
-
getColorClassName,
|
|
12
|
-
getColorObjectByAttributeValues,
|
|
13
|
-
getColorObjectByColorValue,
|
|
14
|
-
InspectorControls,
|
|
15
|
-
PlainText,
|
|
16
|
-
RichText,
|
|
17
|
-
RichTextShortcut,
|
|
18
|
-
RichTextToolbarButton,
|
|
19
|
-
RichTextInserterItem,
|
|
20
|
-
__unstableRichTextInputEvent,
|
|
21
|
-
MediaPlaceholder,
|
|
22
|
-
URLInput,
|
|
23
|
-
withColors,
|
|
24
|
-
withFontSizes,
|
|
25
|
-
} from '@wordpress/block-editor';
|
|
26
|
-
|
|
27
|
-
export {
|
|
28
|
-
BlockControls,
|
|
29
|
-
BlockEdit,
|
|
30
|
-
BlockFormatControls,
|
|
31
|
-
DefaultBlockAppender,
|
|
32
|
-
createCustomColorsHOC,
|
|
33
|
-
getColorClassName,
|
|
34
|
-
getColorObjectByAttributeValues,
|
|
35
|
-
getColorObjectByColorValue,
|
|
36
|
-
InspectorControls,
|
|
37
|
-
PlainText,
|
|
38
|
-
RichText,
|
|
39
|
-
RichTextShortcut,
|
|
40
|
-
RichTextToolbarButton,
|
|
41
|
-
RichTextInserterItem,
|
|
42
|
-
__unstableRichTextInputEvent,
|
|
43
|
-
MediaPlaceholder,
|
|
44
|
-
URLInput,
|
|
45
|
-
withColors,
|
|
46
|
-
withFontSizes,
|
|
47
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { View } from 'react-native';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* WordPress dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { __ } from '@wordpress/i18n';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Internal dependencies
|
|
13
|
-
*/
|
|
14
|
-
import styles from './style.scss';
|
|
15
|
-
import { HelpDetailBodyText, HelpDetailImage } from './view-sections';
|
|
16
|
-
|
|
17
|
-
const AddBlocks = () => {
|
|
18
|
-
return (
|
|
19
|
-
<>
|
|
20
|
-
<HelpDetailImage
|
|
21
|
-
source={ require( './images/add-light.png' ) }
|
|
22
|
-
sourceDarkMode={ require( './images/add-dark.png' ) }
|
|
23
|
-
/>
|
|
24
|
-
<View style={ styles.helpDetailContainer }>
|
|
25
|
-
<HelpDetailBodyText
|
|
26
|
-
text={ __(
|
|
27
|
-
'Add a new block at any time by tapping on the + icon in the toolbar on the bottom left.'
|
|
28
|
-
) }
|
|
29
|
-
/>
|
|
30
|
-
<HelpDetailBodyText
|
|
31
|
-
text={ __(
|
|
32
|
-
'Once you become familiar with the names of different blocks, you can add a block by typing a forward slash followed by the block name — for example, /image or /heading.'
|
|
33
|
-
) }
|
|
34
|
-
/>
|
|
35
|
-
</View>
|
|
36
|
-
</>
|
|
37
|
-
);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export default AddBlocks;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { View } from 'react-native';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* WordPress dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { __ } from '@wordpress/i18n';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Internal dependencies
|
|
13
|
-
*/
|
|
14
|
-
import styles from './style.scss';
|
|
15
|
-
import { HelpDetailBodyText, HelpDetailImage } from './view-sections';
|
|
16
|
-
|
|
17
|
-
const CustomizeBlocks = () => {
|
|
18
|
-
return (
|
|
19
|
-
<>
|
|
20
|
-
<HelpDetailImage
|
|
21
|
-
source={ require( './images/settings-light.png' ) }
|
|
22
|
-
sourceDarkMode={ require( './images/settings-dark.png' ) }
|
|
23
|
-
/>
|
|
24
|
-
<View style={ styles.helpDetailContainer }>
|
|
25
|
-
<HelpDetailBodyText
|
|
26
|
-
text={ __(
|
|
27
|
-
'Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen.'
|
|
28
|
-
) }
|
|
29
|
-
/>
|
|
30
|
-
<HelpDetailBodyText
|
|
31
|
-
text={ __(
|
|
32
|
-
'Some blocks have additional settings. Tap the settings icon on the bottom right of the block to view more options.'
|
|
33
|
-
) }
|
|
34
|
-
/>
|
|
35
|
-
</View>
|
|
36
|
-
</>
|
|
37
|
-
);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export default CustomizeBlocks;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import {
|
|
5
|
-
ScrollView,
|
|
6
|
-
StyleSheet,
|
|
7
|
-
TouchableWithoutFeedback,
|
|
8
|
-
View,
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { useNavigation } from '@react-navigation/native';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* WordPress dependencies
|
|
14
|
-
*/
|
|
15
|
-
import { BottomSheet, BottomSheetContext } from '@wordpress/components';
|
|
16
|
-
import { useContext } from '@wordpress/element';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Internal dependencies
|
|
20
|
-
*/
|
|
21
|
-
import styles from './style.scss';
|
|
22
|
-
|
|
23
|
-
const HelpDetailNavigationScreen = ( { content, label } ) => {
|
|
24
|
-
const navigation = useNavigation();
|
|
25
|
-
|
|
26
|
-
const { listProps } = useContext( BottomSheetContext );
|
|
27
|
-
const contentContainerStyle = StyleSheet.flatten(
|
|
28
|
-
listProps.contentContainerStyle
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<BottomSheet.NavigationScreen isScrollable fullScreen>
|
|
33
|
-
<View style={ styles.container }>
|
|
34
|
-
<BottomSheet.NavBar>
|
|
35
|
-
<BottomSheet.NavBar.BackButton
|
|
36
|
-
onPress={ navigation.goBack }
|
|
37
|
-
/>
|
|
38
|
-
<BottomSheet.NavBar.Heading>
|
|
39
|
-
{ label }
|
|
40
|
-
</BottomSheet.NavBar.Heading>
|
|
41
|
-
</BottomSheet.NavBar>
|
|
42
|
-
<ScrollView
|
|
43
|
-
{ ...listProps }
|
|
44
|
-
contentContainerStyle={ {
|
|
45
|
-
...contentContainerStyle,
|
|
46
|
-
paddingBottom: Math.max(
|
|
47
|
-
listProps.safeAreaBottomInset,
|
|
48
|
-
contentContainerStyle.paddingBottom
|
|
49
|
-
),
|
|
50
|
-
/**
|
|
51
|
-
* Remove margin set via `hideHeader`. Combining a header
|
|
52
|
-
* and navigation in this bottom sheet is at odds with the
|
|
53
|
-
* current `BottomSheet` implementation.
|
|
54
|
-
*/
|
|
55
|
-
marginTop: 0,
|
|
56
|
-
} }
|
|
57
|
-
>
|
|
58
|
-
<TouchableWithoutFeedback accessible={ false }>
|
|
59
|
-
<View>{ content }</View>
|
|
60
|
-
</TouchableWithoutFeedback>
|
|
61
|
-
</ScrollView>
|
|
62
|
-
</View>
|
|
63
|
-
</BottomSheet.NavigationScreen>
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export default HelpDetailNavigationScreen;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { Pressable, Text } from 'react-native';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* WordPress dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Internal dependencies
|
|
13
|
-
*/
|
|
14
|
-
import styles from './style.scss';
|
|
15
|
-
|
|
16
|
-
const HelpGetSupportButton = ( { onPress, title } ) => {
|
|
17
|
-
const buttonStyle = usePreferredColorSchemeStyle(
|
|
18
|
-
styles.button,
|
|
19
|
-
styles.buttonDark
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const textStyle = usePreferredColorSchemeStyle(
|
|
23
|
-
styles.buttonText,
|
|
24
|
-
styles.buttonTextDark
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<Pressable
|
|
29
|
-
style={ buttonStyle }
|
|
30
|
-
onPress={ onPress }
|
|
31
|
-
accessibilityRole="button"
|
|
32
|
-
>
|
|
33
|
-
<Text style={ textStyle }>{ title }</Text>
|
|
34
|
-
</Pressable>
|
|
35
|
-
);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default HelpGetSupportButton;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { Text, View } from 'react-native';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* WordPress dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Internal dependencies
|
|
13
|
-
*/
|
|
14
|
-
import styles from './style.scss';
|
|
15
|
-
|
|
16
|
-
const HelpSectionTitle = ( { children } ) => {
|
|
17
|
-
const helpSectionTitle = usePreferredColorSchemeStyle(
|
|
18
|
-
styles.helpSectionTitle,
|
|
19
|
-
styles.helpSectionTitleDark
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<View style={ styles.helpSectionTitleContainer }>
|
|
24
|
-
<Text style={ helpSectionTitle }>{ children }</Text>
|
|
25
|
-
</View>
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default HelpSectionTitle;
|