@wordpress/editor 14.42.0 → 14.43.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.
- package/CHANGELOG.md +2 -0
- package/build/components/collaborators-overlay/cursor-registry.cjs +86 -0
- package/build/components/collaborators-overlay/cursor-registry.cjs.map +7 -0
- package/build/components/collaborators-overlay/index.cjs +7 -2
- package/build/components/collaborators-overlay/index.cjs.map +2 -2
- package/build/components/collaborators-overlay/overlay-iframe-styles.cjs +1 -1
- package/build/components/collaborators-overlay/overlay-iframe-styles.cjs.map +2 -2
- package/build/components/collaborators-overlay/overlay.cjs +31 -1
- package/build/components/collaborators-overlay/overlay.cjs.map +2 -2
- package/build/components/collaborators-presence/index.cjs +14 -4
- package/build/components/collaborators-presence/index.cjs.map +2 -2
- package/build/components/collaborators-presence/list.cjs +20 -4
- package/build/components/collaborators-presence/list.cjs.map +2 -2
- package/build/components/post-card-panel/index.cjs +4 -15
- package/build/components/post-card-panel/index.cjs.map +2 -2
- package/build/components/post-content-information/index.cjs +10 -13
- package/build/components/post-content-information/index.cjs.map +2 -2
- package/build/components/post-revisions-panel/index.cjs +164 -0
- package/build/components/post-revisions-panel/index.cjs.map +7 -0
- package/build/components/post-revisions-preview/revisions-slider.cjs +24 -5
- package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
- package/build/components/post-template/create-new-template-modal.cjs +39 -46
- package/build/components/post-template/create-new-template-modal.cjs.map +2 -2
- package/build/components/post-template/hooks.cjs +52 -6
- package/build/components/post-template/hooks.cjs.map +2 -2
- package/build/components/post-template/swap-template-button.cjs +31 -20
- package/build/components/post-template/swap-template-button.cjs.map +2 -2
- package/build/components/preferences-modal/index.cjs +35 -27
- package/build/components/preferences-modal/index.cjs.map +2 -2
- package/build/components/revision-block-diff/index.cjs +9 -32
- package/build/components/revision-block-diff/index.cjs.map +3 -3
- package/build/components/revision-diff-panel/index.cjs +68 -0
- package/build/components/revision-diff-panel/index.cjs.map +7 -0
- package/build/components/revision-fields-diff/index.cjs +96 -0
- package/build/components/revision-fields-diff/index.cjs.map +7 -0
- package/build/components/sidebar/dataform-post-summary.cjs +8 -53
- package/build/components/sidebar/dataform-post-summary.cjs.map +2 -2
- package/build/components/sidebar/index.cjs +25 -22
- package/build/components/sidebar/index.cjs.map +3 -3
- package/build/components/sidebar/post-revision-summary.cjs +74 -0
- package/build/components/sidebar/post-revision-summary.cjs.map +7 -0
- package/build/components/sidebar/post-summary.cjs +35 -42
- package/build/components/sidebar/post-summary.cjs.map +3 -3
- package/build/components/style-book/index.cjs +4 -3
- package/build/components/style-book/index.cjs.map +2 -2
- package/build/components/sync-connection-error-modal/index.cjs +2 -2
- package/build/components/sync-connection-error-modal/index.cjs.map +1 -1
- package/build/components/template-actions-panel/block-theme-content.cjs +188 -0
- package/build/components/template-actions-panel/block-theme-content.cjs.map +7 -0
- package/build/components/template-actions-panel/classic-theme-content.cjs +159 -0
- package/build/components/template-actions-panel/classic-theme-content.cjs.map +7 -0
- package/build/components/template-actions-panel/index.cjs +59 -0
- package/build/components/template-actions-panel/index.cjs.map +7 -0
- package/build/dataviews/store/private-actions.cjs +2 -0
- package/build/dataviews/store/private-actions.cjs.map +2 -2
- package/build/store/private-actions.cjs +21 -2
- package/build/store/private-actions.cjs.map +2 -2
- package/build/store/private-selectors.cjs +40 -15
- package/build/store/private-selectors.cjs.map +2 -2
- package/build-module/components/collaborators-overlay/cursor-registry.mjs +61 -0
- package/build-module/components/collaborators-overlay/cursor-registry.mjs.map +7 -0
- package/build-module/components/collaborators-overlay/index.mjs +7 -2
- package/build-module/components/collaborators-overlay/index.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs +1 -1
- package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs.map +2 -2
- package/build-module/components/collaborators-overlay/overlay.mjs +32 -2
- package/build-module/components/collaborators-overlay/overlay.mjs.map +2 -2
- package/build-module/components/collaborators-presence/index.mjs +14 -4
- package/build-module/components/collaborators-presence/index.mjs.map +2 -2
- package/build-module/components/collaborators-presence/list.mjs +20 -4
- package/build-module/components/collaborators-presence/list.mjs.map +2 -2
- package/build-module/components/post-card-panel/index.mjs +6 -17
- package/build-module/components/post-card-panel/index.mjs.map +2 -2
- package/build-module/components/post-content-information/index.mjs +6 -13
- package/build-module/components/post-content-information/index.mjs.map +2 -2
- package/build-module/components/post-revisions-panel/index.mjs +139 -0
- package/build-module/components/post-revisions-panel/index.mjs.map +7 -0
- package/build-module/components/post-revisions-preview/revisions-slider.mjs +24 -5
- package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
- package/build-module/components/post-template/create-new-template-modal.mjs +39 -46
- package/build-module/components/post-template/create-new-template-modal.mjs.map +2 -2
- package/build-module/components/post-template/hooks.mjs +53 -7
- package/build-module/components/post-template/hooks.mjs.map +2 -2
- package/build-module/components/post-template/swap-template-button.mjs +27 -20
- package/build-module/components/post-template/swap-template-button.mjs.map +2 -2
- package/build-module/components/preferences-modal/index.mjs +35 -27
- package/build-module/components/preferences-modal/index.mjs.map +2 -2
- package/build-module/components/revision-block-diff/index.mjs +9 -32
- package/build-module/components/revision-block-diff/index.mjs.map +2 -2
- package/build-module/components/revision-diff-panel/index.mjs +37 -0
- package/build-module/components/revision-diff-panel/index.mjs.map +7 -0
- package/build-module/components/revision-fields-diff/index.mjs +65 -0
- package/build-module/components/revision-fields-diff/index.mjs.map +7 -0
- package/build-module/components/sidebar/dataform-post-summary.mjs +8 -53
- package/build-module/components/sidebar/dataform-post-summary.mjs.map +2 -2
- package/build-module/components/sidebar/index.mjs +25 -22
- package/build-module/components/sidebar/index.mjs.map +2 -2
- package/build-module/components/sidebar/post-revision-summary.mjs +43 -0
- package/build-module/components/sidebar/post-revision-summary.mjs.map +7 -0
- package/build-module/components/sidebar/post-summary.mjs +31 -42
- package/build-module/components/sidebar/post-summary.mjs.map +2 -2
- package/build-module/components/style-book/index.mjs +4 -3
- package/build-module/components/style-book/index.mjs.map +2 -2
- package/build-module/components/sync-connection-error-modal/index.mjs +2 -2
- package/build-module/components/sync-connection-error-modal/index.mjs.map +1 -1
- package/build-module/components/template-actions-panel/block-theme-content.mjs +167 -0
- package/build-module/components/template-actions-panel/block-theme-content.mjs.map +7 -0
- package/build-module/components/template-actions-panel/classic-theme-content.mjs +138 -0
- package/build-module/components/template-actions-panel/classic-theme-content.mjs.map +7 -0
- package/build-module/components/template-actions-panel/index.mjs +28 -0
- package/build-module/components/template-actions-panel/index.mjs.map +7 -0
- package/build-module/dataviews/store/private-actions.mjs +5 -1
- package/build-module/dataviews/store/private-actions.mjs.map +2 -2
- package/build-module/store/private-actions.mjs +21 -2
- package/build-module/store/private-actions.mjs.map +2 -2
- package/build-module/store/private-selectors.mjs +40 -15
- package/build-module/store/private-selectors.mjs.map +2 -2
- package/build-style/style-rtl.css +111 -42
- package/build-style/style.css +111 -42
- package/build-types/components/collaborators-overlay/cursor-registry.d.ts +36 -0
- package/build-types/components/collaborators-overlay/cursor-registry.d.ts.map +1 -0
- package/build-types/components/collaborators-overlay/index.d.ts +7 -4
- package/build-types/components/collaborators-overlay/index.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts +1 -1
- package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts.map +1 -1
- package/build-types/components/collaborators-overlay/overlay.d.ts +4 -1
- package/build-types/components/collaborators-overlay/overlay.d.ts.map +1 -1
- package/build-types/components/collaborators-presence/index.d.ts.map +1 -1
- package/build-types/components/collaborators-presence/list.d.ts +4 -1
- package/build-types/components/collaborators-presence/list.d.ts.map +1 -1
- package/build-types/components/post-card-panel/index.d.ts.map +1 -1
- package/build-types/components/post-content-information/index.d.ts +4 -1
- package/build-types/components/post-content-information/index.d.ts.map +1 -1
- package/build-types/components/post-revisions-panel/index.d.ts +2 -0
- package/build-types/components/post-revisions-panel/index.d.ts.map +1 -0
- package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -1
- package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
- package/build-types/components/post-template/hooks.d.ts +1 -1
- package/build-types/components/post-template/hooks.d.ts.map +1 -1
- package/build-types/components/post-template/swap-template-button.d.ts +4 -0
- package/build-types/components/post-template/swap-template-button.d.ts.map +1 -1
- package/build-types/components/revision-block-diff/index.d.ts.map +1 -1
- package/build-types/components/revision-diff-panel/index.d.ts +14 -0
- package/build-types/components/revision-diff-panel/index.d.ts.map +1 -0
- package/build-types/components/revision-fields-diff/index.d.ts +6 -0
- package/build-types/components/revision-fields-diff/index.d.ts.map +1 -0
- package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -1
- package/build-types/components/sidebar/index.d.ts.map +1 -1
- package/build-types/components/sidebar/post-revision-summary.d.ts +2 -0
- package/build-types/components/sidebar/post-revision-summary.d.ts.map +1 -0
- package/build-types/components/sidebar/post-summary.d.ts +3 -0
- package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
- package/build-types/components/style-book/index.d.ts +2 -1
- package/build-types/components/style-book/index.d.ts.map +1 -1
- package/build-types/components/template-actions-panel/block-theme-content.d.ts +2 -0
- package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -0
- package/build-types/components/template-actions-panel/classic-theme-content.d.ts +2 -0
- package/build-types/components/template-actions-panel/classic-theme-content.d.ts.map +1 -0
- package/build-types/components/template-actions-panel/index.d.ts +2 -0
- package/build-types/components/template-actions-panel/index.d.ts.map +1 -0
- package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
- package/build-types/store/private-actions.d.ts.map +1 -1
- package/build-types/store/private-selectors.d.ts.map +1 -1
- package/package.json +45 -44
- package/src/components/collaborators-overlay/cursor-registry.ts +96 -0
- package/src/components/collaborators-overlay/index.tsx +12 -4
- package/src/components/collaborators-overlay/overlay-iframe-styles.ts +1 -1
- package/src/components/collaborators-overlay/overlay.tsx +45 -1
- package/src/components/collaborators-presence/index.tsx +9 -1
- package/src/components/collaborators-presence/list.tsx +25 -1
- package/src/components/post-card-panel/index.js +7 -21
- package/src/components/post-content-information/index.js +5 -16
- package/src/components/post-revisions-panel/index.js +151 -0
- package/src/components/post-revisions-panel/style.scss +16 -0
- package/src/components/post-revisions-preview/revisions-slider.js +29 -7
- package/src/components/post-template/create-new-template-modal.js +1 -4
- package/src/components/post-template/hooks.js +65 -9
- package/src/components/post-template/style.scss +0 -6
- package/src/components/post-template/swap-template-button.js +30 -21
- package/src/components/preferences-modal/index.js +37 -25
- package/src/components/revision-block-diff/index.js +8 -43
- package/src/components/revision-diff-panel/index.js +59 -0
- package/src/components/revision-fields-diff/index.js +91 -0
- package/src/components/sidebar/dataform-post-summary.js +8 -55
- package/src/components/sidebar/index.js +33 -22
- package/src/components/sidebar/post-revision-summary.js +50 -0
- package/src/components/sidebar/post-summary.js +22 -40
- package/src/components/sidebar/style.scss +7 -0
- package/src/components/style-book/index.js +4 -2
- package/src/components/sync-connection-error-modal/index.tsx +2 -2
- package/src/components/template-actions-panel/block-theme-content.js +196 -0
- package/src/components/template-actions-panel/classic-theme-content.js +170 -0
- package/src/components/template-actions-panel/index.js +32 -0
- package/src/components/template-actions-panel/style.scss +39 -0
- package/src/dataviews/store/private-actions.ts +6 -0
- package/src/store/private-actions.js +24 -3
- package/src/store/private-selectors.js +46 -16
- package/src/style.scss +3 -1
- /package/src/components/{revision-block-diff → revision-diff-panel}/style.scss +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useResizeObserver, useMergeRefs } from '@wordpress/compose';
|
|
2
|
-
import { useCallback, useEffect, useState } from '@wordpress/element';
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
5
|
import Avatar from '../collaborators-presence/avatar';
|
|
@@ -8,6 +8,7 @@ import { OVERLAY_IFRAME_STYLES } from './overlay-iframe-styles';
|
|
|
8
8
|
import { setDelayedInterval } from './timing-utils';
|
|
9
9
|
import { useBlockHighlighting } from './use-block-highlighting';
|
|
10
10
|
import { useRenderCursors } from './use-render-cursors';
|
|
11
|
+
import { type CursorRegistry } from './cursor-registry';
|
|
11
12
|
|
|
12
13
|
// Milliseconds to wait after a change before recomputing cursor positions.
|
|
13
14
|
const RERENDER_DELAY_MS = 500;
|
|
@@ -22,6 +23,7 @@ interface OverlayProps {
|
|
|
22
23
|
blockEditorDocument?: Document;
|
|
23
24
|
postId: number | null;
|
|
24
25
|
postType: string | null;
|
|
26
|
+
cursorRegistry?: CursorRegistry;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -31,12 +33,14 @@ interface OverlayProps {
|
|
|
31
33
|
* @param props.blockEditorDocument - The block editor document.
|
|
32
34
|
* @param props.postId - The ID of the post.
|
|
33
35
|
* @param props.postType - The type of the post.
|
|
36
|
+
* @param props.cursorRegistry - The shared cursor registry.
|
|
34
37
|
* @return The Overlay component.
|
|
35
38
|
*/
|
|
36
39
|
export function Overlay( {
|
|
37
40
|
blockEditorDocument,
|
|
38
41
|
postId,
|
|
39
42
|
postType,
|
|
43
|
+
cursorRegistry,
|
|
40
44
|
}: OverlayProps ) {
|
|
41
45
|
// Use state for the overlay element so that the hook re-runs once the ref is attached.
|
|
42
46
|
const [ overlayElement, setOverlayElement ] =
|
|
@@ -93,6 +97,45 @@ export function Overlay( {
|
|
|
93
97
|
resizeObserverRef,
|
|
94
98
|
] );
|
|
95
99
|
|
|
100
|
+
// Track cursor element refs for registry registration.
|
|
101
|
+
const cursorRefsMap = useRef< Map< number, HTMLElement > >( new Map() );
|
|
102
|
+
|
|
103
|
+
// Keep the registry in sync whenever the rendered cursors change.
|
|
104
|
+
useEffect( () => {
|
|
105
|
+
if ( ! cursorRegistry ) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const refs = cursorRefsMap.current;
|
|
109
|
+
const currentIds = new Set( cursors.map( ( c ) => c.clientId ) );
|
|
110
|
+
|
|
111
|
+
// Unregister cursors that are no longer rendered.
|
|
112
|
+
for ( const id of refs.keys() ) {
|
|
113
|
+
if ( ! currentIds.has( id ) ) {
|
|
114
|
+
cursorRegistry.unregisterCursor( id );
|
|
115
|
+
refs.delete( id );
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Register or update cursors that are currently rendered.
|
|
120
|
+
for ( const [ id, el ] of refs.entries() ) {
|
|
121
|
+
cursorRegistry.registerCursor( id, el );
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return () => cursorRegistry.removeAll();
|
|
125
|
+
}, [ cursors, cursorRegistry ] );
|
|
126
|
+
|
|
127
|
+
// Callback ref factory to capture each cursor's DOM element.
|
|
128
|
+
const setCursorRef = useCallback(
|
|
129
|
+
( clientId: number ) => ( el: HTMLDivElement | null ) => {
|
|
130
|
+
if ( el ) {
|
|
131
|
+
cursorRefsMap.current.set( clientId, el );
|
|
132
|
+
} else {
|
|
133
|
+
cursorRefsMap.current.delete( clientId );
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
[]
|
|
137
|
+
);
|
|
138
|
+
|
|
96
139
|
// This is a full overlay that covers the entire iframe document. Good for
|
|
97
140
|
// scrollable elements like cursor indicators.
|
|
98
141
|
return (
|
|
@@ -115,6 +158,7 @@ export function Overlay( {
|
|
|
115
158
|
/>
|
|
116
159
|
) ) }
|
|
117
160
|
<div
|
|
161
|
+
ref={ setCursorRef( cursor.clientId ) }
|
|
118
162
|
className="collaborators-overlay-user"
|
|
119
163
|
style={ {
|
|
120
164
|
left: `${ cursor.x }px`,
|
|
@@ -12,6 +12,7 @@ import { CollaboratorsList } from './list';
|
|
|
12
12
|
import { unlock } from '../../lock-unlock';
|
|
13
13
|
import { getAvatarUrl } from '../collaborators-overlay/get-avatar-url';
|
|
14
14
|
import { getAvatarBorderColor } from '../collab-sidebar/utils';
|
|
15
|
+
import { createCursorRegistry } from '../collaborators-overlay/cursor-registry';
|
|
15
16
|
|
|
16
17
|
import './styles/collaborators-presence.scss';
|
|
17
18
|
import { CollaboratorsOverlay } from '../collaborators-overlay';
|
|
@@ -57,6 +58,8 @@ export function CollaboratorsPresence( {
|
|
|
57
58
|
} );
|
|
58
59
|
}, [ activeCollaborators ] );
|
|
59
60
|
|
|
61
|
+
const [ cursorRegistry ] = useState( createCursorRegistry );
|
|
62
|
+
|
|
60
63
|
const [ isPopoverVisible, setIsPopoverVisible ] = useState( false );
|
|
61
64
|
const [ popoverAnchor, setPopoverAnchor ] = useState< HTMLElement | null >(
|
|
62
65
|
null
|
|
@@ -123,10 +126,15 @@ export function CollaboratorsPresence( {
|
|
|
123
126
|
activeCollaborators={ collaboratorsForList }
|
|
124
127
|
popoverAnchor={ popoverAnchor }
|
|
125
128
|
setIsPopoverVisible={ setIsPopoverVisible }
|
|
129
|
+
cursorRegistry={ cursorRegistry }
|
|
126
130
|
/>
|
|
127
131
|
) }
|
|
128
132
|
</div>
|
|
129
|
-
<CollaboratorsOverlay
|
|
133
|
+
<CollaboratorsOverlay
|
|
134
|
+
postId={ postId }
|
|
135
|
+
postType={ postType }
|
|
136
|
+
cursorRegistry={ cursorRegistry }
|
|
137
|
+
/>
|
|
130
138
|
</>
|
|
131
139
|
);
|
|
132
140
|
}
|
|
@@ -2,10 +2,12 @@ import { __ } from '@wordpress/i18n';
|
|
|
2
2
|
import { Popover, Button } from '@wordpress/components';
|
|
3
3
|
import { closeSmall } from '@wordpress/icons';
|
|
4
4
|
import { type PostEditorAwarenessState } from '@wordpress/core-data';
|
|
5
|
+
import { speak } from '@wordpress/a11y';
|
|
5
6
|
|
|
6
7
|
import Avatar from './avatar';
|
|
7
8
|
import { getAvatarUrl } from '../collaborators-overlay/get-avatar-url';
|
|
8
9
|
import { getAvatarBorderColor } from '../collab-sidebar/utils';
|
|
10
|
+
import { type CursorRegistry } from '../collaborators-overlay/cursor-registry';
|
|
9
11
|
|
|
10
12
|
import './styles/collaborators-list.scss';
|
|
11
13
|
|
|
@@ -13,6 +15,7 @@ interface CollaboratorsListProps {
|
|
|
13
15
|
activeCollaborators: PostEditorAwarenessState[];
|
|
14
16
|
popoverAnchor?: HTMLElement | null;
|
|
15
17
|
setIsPopoverVisible: ( isVisible: boolean ) => void;
|
|
18
|
+
cursorRegistry: CursorRegistry;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
/**
|
|
@@ -23,12 +26,28 @@ interface CollaboratorsListProps {
|
|
|
23
26
|
* @param props.activeCollaborators List of active collaborators
|
|
24
27
|
* @param props.popoverAnchor Anchor element for the popover
|
|
25
28
|
* @param props.setIsPopoverVisible Callback to set the visibility of the popover
|
|
29
|
+
* @param props.cursorRegistry Shared registry for scroll-to-cursor support
|
|
26
30
|
*/
|
|
27
31
|
export function CollaboratorsList( {
|
|
28
32
|
activeCollaborators,
|
|
29
33
|
popoverAnchor,
|
|
30
34
|
setIsPopoverVisible,
|
|
35
|
+
cursorRegistry,
|
|
31
36
|
}: CollaboratorsListProps ) {
|
|
37
|
+
const handleCollaboratorClick = ( clientId: number ) => {
|
|
38
|
+
const success = cursorRegistry.scrollToCursor( clientId, {
|
|
39
|
+
behavior: 'smooth',
|
|
40
|
+
block: 'center',
|
|
41
|
+
highlightDuration: 2000,
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
if ( success ) {
|
|
45
|
+
speak( __( 'Scrolled to cursor' ), 'polite' );
|
|
46
|
+
|
|
47
|
+
setIsPopoverVisible( false );
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
32
51
|
return (
|
|
33
52
|
<Popover
|
|
34
53
|
anchor={ popoverAnchor }
|
|
@@ -60,7 +79,12 @@ export function CollaboratorsList( {
|
|
|
60
79
|
<button
|
|
61
80
|
key={ collaboratorState.clientId }
|
|
62
81
|
className="editor-collaborators-presence__list-item"
|
|
63
|
-
disabled
|
|
82
|
+
disabled={ isCurrentUser }
|
|
83
|
+
onClick={ () =>
|
|
84
|
+
handleCollaboratorClick(
|
|
85
|
+
collaboratorState.clientId
|
|
86
|
+
)
|
|
87
|
+
}
|
|
64
88
|
>
|
|
65
89
|
<Avatar
|
|
66
90
|
src={ getAvatarUrl(
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
__experimentalText as Text,
|
|
10
10
|
privateApis as componentsPrivateApis,
|
|
11
11
|
} from '@wordpress/components';
|
|
12
|
-
import {
|
|
12
|
+
import { close } from '@wordpress/icons';
|
|
13
13
|
import { store as coreStore } from '@wordpress/core-data';
|
|
14
14
|
import { useSelect } from '@wordpress/data';
|
|
15
15
|
import { useMemo } from '@wordpress/element';
|
|
@@ -52,7 +52,7 @@ export default function PostCardPanel( {
|
|
|
52
52
|
() => ( Array.isArray( postId ) ? postId : [ postId ] ),
|
|
53
53
|
[ postId ]
|
|
54
54
|
);
|
|
55
|
-
const { postTitle, icon, labels
|
|
55
|
+
const { postTitle, icon, labels } = useSelect(
|
|
56
56
|
( select ) => {
|
|
57
57
|
const { getEditedEntityRecord, getCurrentTheme, getPostType } =
|
|
58
58
|
select( coreStore );
|
|
@@ -75,7 +75,6 @@ export default function PostCardPanel( {
|
|
|
75
75
|
area: _record?.area,
|
|
76
76
|
} ),
|
|
77
77
|
labels: getPostType( parentPostType )?.labels,
|
|
78
|
-
isRevision: true,
|
|
79
78
|
};
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -146,24 +145,11 @@ export default function PostCardPanel( {
|
|
|
146
145
|
) }
|
|
147
146
|
</Text>
|
|
148
147
|
{ ! hideActions && postIds.length === 1 && (
|
|
149
|
-
|
|
150
|
-
{
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
label={ __( 'Actions' ) }
|
|
155
|
-
disabled
|
|
156
|
-
accessibleWhenDisabled
|
|
157
|
-
className="editor-all-actions-button"
|
|
158
|
-
/>
|
|
159
|
-
) : (
|
|
160
|
-
<PostActions
|
|
161
|
-
postType={ postType }
|
|
162
|
-
postId={ postIds[ 0 ] }
|
|
163
|
-
onActionPerformed={ onActionPerformed }
|
|
164
|
-
/>
|
|
165
|
-
) }
|
|
166
|
-
</>
|
|
148
|
+
<PostActions
|
|
149
|
+
postType={ postType }
|
|
150
|
+
postId={ postIds[ 0 ] }
|
|
151
|
+
onActionPerformed={ onActionPerformed }
|
|
152
|
+
/>
|
|
167
153
|
) }
|
|
168
154
|
{ onClose && (
|
|
169
155
|
<Button
|
|
@@ -12,7 +12,6 @@ import { store as coreStore } from '@wordpress/core-data';
|
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
14
|
import { store as editorStore } from '../../store';
|
|
15
|
-
import { unlock } from '../../lock-unlock';
|
|
16
15
|
import {
|
|
17
16
|
TEMPLATE_POST_TYPE,
|
|
18
17
|
TEMPLATE_PART_POST_TYPE,
|
|
@@ -23,19 +22,9 @@ const AVERAGE_READING_RATE = 189;
|
|
|
23
22
|
|
|
24
23
|
// This component renders the wordcount and reading time for the post.
|
|
25
24
|
export default function PostContentInformation() {
|
|
26
|
-
const
|
|
25
|
+
const postContent = useSelect( ( select ) => {
|
|
27
26
|
const { getEditedPostAttribute, getCurrentPostType, getCurrentPostId } =
|
|
28
27
|
select( editorStore );
|
|
29
|
-
const { getCurrentRevision, isRevisionsMode } = unlock(
|
|
30
|
-
select( editorStore )
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
if ( isRevisionsMode() ) {
|
|
34
|
-
return {
|
|
35
|
-
postContent: getCurrentRevision()?.content?.raw,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
28
|
const { canUser } = select( coreStore );
|
|
40
29
|
const { getEntityRecord } = select( coreStore );
|
|
41
30
|
const siteSettings = canUser( 'read', {
|
|
@@ -52,12 +41,12 @@ export default function PostContentInformation() {
|
|
|
52
41
|
! [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes(
|
|
53
42
|
postType
|
|
54
43
|
);
|
|
55
|
-
return
|
|
56
|
-
postContent:
|
|
57
|
-
showPostContentInfo && getEditedPostAttribute( 'content' ),
|
|
58
|
-
};
|
|
44
|
+
return showPostContentInfo && getEditedPostAttribute( 'content' );
|
|
59
45
|
}, [] );
|
|
46
|
+
return <PostContentInformationUI postContent={ postContent } />;
|
|
47
|
+
}
|
|
60
48
|
|
|
49
|
+
export function PostContentInformationUI( { postContent } ) {
|
|
61
50
|
/*
|
|
62
51
|
* translators: If your word count is based on single characters (e.g. East Asian characters),
|
|
63
52
|
* enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
PanelBody,
|
|
6
|
+
Button,
|
|
7
|
+
__experimentalHStack as HStack,
|
|
8
|
+
__experimentalVStack as VStack,
|
|
9
|
+
privateApis as componentsPrivateApis,
|
|
10
|
+
} from '@wordpress/components';
|
|
11
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
12
|
+
import { DataViews } from '@wordpress/dataviews';
|
|
13
|
+
import { dateI18n, getDate, humanTimeDiff, getSettings } from '@wordpress/date';
|
|
14
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
15
|
+
import { __ } from '@wordpress/i18n';
|
|
16
|
+
import { authorField } from '@wordpress/fields';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Internal dependencies
|
|
20
|
+
*/
|
|
21
|
+
import PostLastRevisionCheck from '../post-last-revision/check';
|
|
22
|
+
import { store as editorStore } from '../../store';
|
|
23
|
+
import { unlock } from '../../lock-unlock';
|
|
24
|
+
|
|
25
|
+
const { Badge } = unlock( componentsPrivateApis );
|
|
26
|
+
const DAY_IN_MILLISECONDS = 86400000;
|
|
27
|
+
const EMPTY_ARRAY = [];
|
|
28
|
+
|
|
29
|
+
const REVISIONS_QUERY = {
|
|
30
|
+
per_page: 3,
|
|
31
|
+
orderby: 'date',
|
|
32
|
+
order: 'desc',
|
|
33
|
+
context: 'embed',
|
|
34
|
+
_fields: 'id,date,author',
|
|
35
|
+
};
|
|
36
|
+
const defaultLayouts = { activity: {} };
|
|
37
|
+
const view = {
|
|
38
|
+
type: 'activity',
|
|
39
|
+
titleField: 'date',
|
|
40
|
+
fields: [ 'author' ],
|
|
41
|
+
layout: {
|
|
42
|
+
density: 'compact',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const fields = [
|
|
46
|
+
{
|
|
47
|
+
id: 'date',
|
|
48
|
+
label: __( 'Date' ),
|
|
49
|
+
render: ( { item } ) => {
|
|
50
|
+
const dateNowInMs = getDate( null ).getTime();
|
|
51
|
+
const date = getDate( item.date ?? null );
|
|
52
|
+
const displayDate =
|
|
53
|
+
dateNowInMs - date.getTime() > DAY_IN_MILLISECONDS
|
|
54
|
+
? dateI18n(
|
|
55
|
+
getSettings().formats.datetimeAbbreviated,
|
|
56
|
+
date
|
|
57
|
+
)
|
|
58
|
+
: humanTimeDiff( date );
|
|
59
|
+
return (
|
|
60
|
+
<time
|
|
61
|
+
className="editor-post-revisions-panel__revision-date"
|
|
62
|
+
dateTime={ item.date }
|
|
63
|
+
>
|
|
64
|
+
{ displayDate }
|
|
65
|
+
</time>
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
enableSorting: false,
|
|
69
|
+
enableHiding: false,
|
|
70
|
+
},
|
|
71
|
+
authorField,
|
|
72
|
+
];
|
|
73
|
+
const noop = () => {};
|
|
74
|
+
const paginationInfo = {};
|
|
75
|
+
|
|
76
|
+
function PostRevisionsPanelContent() {
|
|
77
|
+
const { setCurrentRevisionId } = unlock( useDispatch( editorStore ) );
|
|
78
|
+
const { revisionsCount, revisions, isLoading, lastRevisionId } = useSelect(
|
|
79
|
+
( select ) => {
|
|
80
|
+
const { getCurrentPostId, getCurrentPostType } =
|
|
81
|
+
select( editorStore );
|
|
82
|
+
const {
|
|
83
|
+
getCurrentPostRevisionsCount,
|
|
84
|
+
getCurrentPostLastRevisionId,
|
|
85
|
+
} = select( editorStore );
|
|
86
|
+
const { getRevisions, isResolving } = select( coreStore );
|
|
87
|
+
const query = [
|
|
88
|
+
'postType',
|
|
89
|
+
getCurrentPostType(),
|
|
90
|
+
getCurrentPostId(),
|
|
91
|
+
REVISIONS_QUERY,
|
|
92
|
+
];
|
|
93
|
+
const _revisions = getRevisions( ...query );
|
|
94
|
+
return {
|
|
95
|
+
revisionsCount: getCurrentPostRevisionsCount(),
|
|
96
|
+
lastRevisionId: getCurrentPostLastRevisionId(),
|
|
97
|
+
revisions: _revisions,
|
|
98
|
+
isLoading: isResolving( 'getRevisions', query ),
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
[]
|
|
102
|
+
);
|
|
103
|
+
return (
|
|
104
|
+
<PanelBody
|
|
105
|
+
title={
|
|
106
|
+
<HStack justify="space-between" align="center" as="span">
|
|
107
|
+
<span>{ __( 'Revisions' ) }</span>
|
|
108
|
+
<Badge className="editor-post-revisions-panel__revisions-count">
|
|
109
|
+
{ revisionsCount }
|
|
110
|
+
</Badge>
|
|
111
|
+
</HStack>
|
|
112
|
+
}
|
|
113
|
+
initialOpen={ false }
|
|
114
|
+
>
|
|
115
|
+
<VStack className="editor-post-revisions-panel">
|
|
116
|
+
<DataViews
|
|
117
|
+
view={ view }
|
|
118
|
+
onChangeView={ noop }
|
|
119
|
+
fields={ fields }
|
|
120
|
+
data={ revisions || EMPTY_ARRAY }
|
|
121
|
+
isLoading={ isLoading }
|
|
122
|
+
paginationInfo={ paginationInfo }
|
|
123
|
+
defaultLayouts={ defaultLayouts }
|
|
124
|
+
getItemId={ ( item ) => item.id }
|
|
125
|
+
isItemClickable={ () => true }
|
|
126
|
+
onClickItem={ ( item ) => {
|
|
127
|
+
setCurrentRevisionId( item.id );
|
|
128
|
+
} }
|
|
129
|
+
>
|
|
130
|
+
<DataViews.Layout />
|
|
131
|
+
</DataViews>
|
|
132
|
+
<Button
|
|
133
|
+
className="editor-post-revisions-panel__view-all"
|
|
134
|
+
__next40pxDefaultSize
|
|
135
|
+
variant="secondary"
|
|
136
|
+
onClick={ () => setCurrentRevisionId( lastRevisionId ) }
|
|
137
|
+
>
|
|
138
|
+
{ __( 'View all revisions' ) }
|
|
139
|
+
</Button>
|
|
140
|
+
</VStack>
|
|
141
|
+
</PanelBody>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default function PostRevisionsPanel() {
|
|
146
|
+
return (
|
|
147
|
+
<PostLastRevisionCheck>
|
|
148
|
+
<PostRevisionsPanelContent />
|
|
149
|
+
</PostLastRevisionCheck>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.editor-post-revisions-panel {
|
|
2
|
+
.editor-post-revisions-panel__view-all {
|
|
3
|
+
justify-content: center;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.editor-post-revisions-panel__revision-date {
|
|
7
|
+
text-transform: uppercase;
|
|
8
|
+
font-weight: 600;
|
|
9
|
+
font-size: 12px;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.editor-post-revisions-panel__revisions-count {
|
|
14
|
+
margin-top: -4.5px;
|
|
15
|
+
margin-bottom: -4.5px;
|
|
16
|
+
}
|
|
@@ -35,11 +35,23 @@ function RevisionsSlider() {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const entityConfig = getEntityConfig( 'postType', postType );
|
|
38
|
+
const _revisionKey = entityConfig?.revisionKey || 'id';
|
|
38
39
|
const query = {
|
|
39
40
|
per_page: -1,
|
|
40
41
|
context: 'edit',
|
|
41
|
-
_fields:
|
|
42
|
-
|
|
42
|
+
_fields: [
|
|
43
|
+
...new Set( [
|
|
44
|
+
'id',
|
|
45
|
+
'date',
|
|
46
|
+
'modified',
|
|
47
|
+
'author',
|
|
48
|
+
'meta',
|
|
49
|
+
'title.raw',
|
|
50
|
+
'excerpt.raw',
|
|
51
|
+
'content.raw',
|
|
52
|
+
_revisionKey,
|
|
53
|
+
] ),
|
|
54
|
+
].join(),
|
|
43
55
|
};
|
|
44
56
|
return {
|
|
45
57
|
revisions: getRevisions( 'postType', postType, postId, query ),
|
|
@@ -52,7 +64,7 @@ function RevisionsSlider() {
|
|
|
52
64
|
currentRevisionId: unlock(
|
|
53
65
|
select( editorStore )
|
|
54
66
|
).getCurrentRevisionId(),
|
|
55
|
-
revisionKey:
|
|
67
|
+
revisionKey: _revisionKey,
|
|
56
68
|
};
|
|
57
69
|
},
|
|
58
70
|
[]
|
|
@@ -60,14 +72,21 @@ function RevisionsSlider() {
|
|
|
60
72
|
|
|
61
73
|
const { setCurrentRevisionId } = unlock( useDispatch( editorStore ) );
|
|
62
74
|
|
|
75
|
+
// Template revisions use the template REST API format, which exposes
|
|
76
|
+
// 'modified' instead of 'date'.
|
|
77
|
+
const revisionDateField = revisionKey === 'wp_id' ? 'modified' : 'date';
|
|
78
|
+
|
|
63
79
|
const sortedRevisions = useMemo( () => {
|
|
64
80
|
return (
|
|
65
81
|
revisions
|
|
66
82
|
?.slice()
|
|
67
|
-
.sort(
|
|
68
|
-
|
|
83
|
+
.sort(
|
|
84
|
+
( a, b ) =>
|
|
85
|
+
new Date( a[ revisionDateField ] ) -
|
|
86
|
+
new Date( b[ revisionDateField ] )
|
|
87
|
+
) ?? []
|
|
69
88
|
);
|
|
70
|
-
}, [ revisions ] );
|
|
89
|
+
}, [ revisions, revisionDateField ] );
|
|
71
90
|
|
|
72
91
|
const selectedIndex = sortedRevisions.findIndex(
|
|
73
92
|
( r ) => r[ revisionKey ] === currentRevisionId
|
|
@@ -87,7 +106,10 @@ function RevisionsSlider() {
|
|
|
87
106
|
if ( ! revision ) {
|
|
88
107
|
return index;
|
|
89
108
|
}
|
|
90
|
-
return dateI18n(
|
|
109
|
+
return dateI18n(
|
|
110
|
+
dateSettings.formats.datetime,
|
|
111
|
+
revision[ revisionDateField ]
|
|
112
|
+
);
|
|
91
113
|
};
|
|
92
114
|
|
|
93
115
|
if ( isLoading ) {
|
|
@@ -118,10 +118,7 @@ export default function CreateNewTemplateModal( { onClose } ) {
|
|
|
118
118
|
size="small"
|
|
119
119
|
overlayClassName="editor-post-template__create-template-modal"
|
|
120
120
|
>
|
|
121
|
-
<form
|
|
122
|
-
className="editor-post-template__create-form"
|
|
123
|
-
onSubmit={ submit }
|
|
124
|
-
>
|
|
121
|
+
<form onSubmit={ submit }>
|
|
125
122
|
<VStack spacing="3">
|
|
126
123
|
<TextControl
|
|
127
124
|
__next40pxDefaultSize
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { useSelect } from '@wordpress/data';
|
|
5
5
|
import { useMemo } from '@wordpress/element';
|
|
6
|
-
import { store as coreStore } from '@wordpress/core-data';
|
|
6
|
+
import { useEntityProp, store as coreStore } from '@wordpress/core-data';
|
|
7
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Internal dependencies
|
|
@@ -64,20 +65,75 @@ function useTemplates( postType ) {
|
|
|
64
65
|
);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
export function useAvailableTemplates(
|
|
68
|
+
export function useAvailableTemplates() {
|
|
69
|
+
const { postType, postId } = useEditedPostContext();
|
|
70
|
+
const [ postSlug ] = useEntityProp( 'postType', postType, 'slug', postId );
|
|
68
71
|
const currentTemplateSlug = useCurrentTemplateSlug();
|
|
69
72
|
const allowSwitchingTemplate = useAllowSwitchingTemplates();
|
|
70
73
|
const templates = useTemplates( postType );
|
|
74
|
+
// Add the default template to the available ones. We don't care about
|
|
75
|
+
// possible assignment to postspage/homepage because it's guarded by
|
|
76
|
+
// `allowSwitchingTemplate` above.
|
|
77
|
+
const defaultTemplate = useSelect(
|
|
78
|
+
( select ) => {
|
|
79
|
+
// Only append the default template if the experiment is enabled.
|
|
80
|
+
if ( ! window?.__experimentalDataFormInspector ) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
// If the default template is already assigned, no need
|
|
84
|
+
// to add it to the available templates.
|
|
85
|
+
if ( ! currentTemplateSlug ) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const { getDefaultTemplateId, getEntityRecord } =
|
|
89
|
+
select( coreStore );
|
|
90
|
+
let slug;
|
|
91
|
+
if ( postSlug ) {
|
|
92
|
+
slug =
|
|
93
|
+
postType === 'page'
|
|
94
|
+
? `${ postType }-${ postSlug }`
|
|
95
|
+
: `single-${ postType }-${ postSlug }`;
|
|
96
|
+
} else {
|
|
97
|
+
slug = postType === 'page' ? 'page' : `single-${ postType }`;
|
|
98
|
+
}
|
|
99
|
+
const templateId = getDefaultTemplateId( { slug } );
|
|
100
|
+
if ( ! templateId ) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return getEntityRecord( 'postType', 'wp_template', templateId );
|
|
104
|
+
},
|
|
105
|
+
[ currentTemplateSlug, postSlug, postType ]
|
|
106
|
+
);
|
|
71
107
|
return useMemo(
|
|
72
108
|
() =>
|
|
73
109
|
allowSwitchingTemplate &&
|
|
74
|
-
|
|
75
|
-
(
|
|
76
|
-
template
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
[
|
|
111
|
+
...( templates || [] ).filter(
|
|
112
|
+
( template ) =>
|
|
113
|
+
template.is_custom &&
|
|
114
|
+
template.slug !== currentTemplateSlug &&
|
|
115
|
+
!! template.content.raw // Skip empty templates.
|
|
116
|
+
),
|
|
117
|
+
defaultTemplate && {
|
|
118
|
+
...defaultTemplate,
|
|
119
|
+
title: {
|
|
120
|
+
rendered: sprintf(
|
|
121
|
+
// translators: %s: Template name
|
|
122
|
+
__( '%s (default)' ),
|
|
123
|
+
defaultTemplate.title.rendered
|
|
124
|
+
),
|
|
125
|
+
},
|
|
126
|
+
// That's extra custom prop in order to update to an empty template
|
|
127
|
+
// when we select the default template.
|
|
128
|
+
isDefault: true,
|
|
129
|
+
},
|
|
130
|
+
].filter( Boolean ),
|
|
131
|
+
[
|
|
132
|
+
templates,
|
|
133
|
+
defaultTemplate,
|
|
134
|
+
currentTemplateSlug,
|
|
135
|
+
allowSwitchingTemplate,
|
|
136
|
+
]
|
|
81
137
|
);
|
|
82
138
|
}
|
|
83
139
|
|