@wordpress/block-library 9.40.2-next.v.202602241322.0 → 9.41.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/accordion/view.cjs +0 -34
- package/build/accordion/view.cjs.map +2 -2
- package/build/button/block.json +11 -3
- package/build/button/deprecated.cjs +246 -13
- package/build/button/deprecated.cjs.map +2 -2
- package/build/button/edit.cjs +45 -58
- package/build/button/edit.cjs.map +3 -3
- package/build/button/save.cjs +3 -7
- package/build/button/save.cjs.map +2 -2
- package/build/button/utils.cjs +59 -0
- package/build/button/utils.cjs.map +7 -0
- package/build/image/image.cjs +1 -1
- package/build/image/image.cjs.map +2 -2
- package/build/navigation/edit/index.cjs +4 -2
- package/build/navigation/edit/index.cjs.map +3 -3
- package/build/navigation/edit/leaf-more-menu.cjs +68 -6
- package/build/navigation/edit/leaf-more-menu.cjs.map +3 -3
- package/build/navigation/edit/menu-inspector-controls.cjs +20 -91
- package/build/navigation/edit/menu-inspector-controls.cjs.map +3 -3
- package/build/navigation/edit/navigation-link-ui.cjs +97 -0
- package/build/navigation/edit/navigation-link-ui.cjs.map +7 -0
- package/build/navigation/edit/navigation-list-view-header.cjs +86 -0
- package/build/navigation/edit/navigation-list-view-header.cjs.map +7 -0
- package/build/navigation/edit/navigation-menu-selector.cjs +4 -2
- package/build/navigation/edit/navigation-menu-selector.cjs.map +3 -3
- package/build/navigation/edit/placeholder/index.cjs +2 -2
- package/build/navigation/edit/placeholder/index.cjs.map +3 -3
- package/build/navigation-link/shared/controls.cjs +29 -52
- package/build/navigation-link/shared/controls.cjs.map +3 -3
- package/build/navigation-link/shared/use-link-preview.cjs +8 -9
- package/build/navigation-link/shared/use-link-preview.cjs.map +2 -2
- package/build/page-list-item/edit.cjs +6 -3
- package/build/page-list-item/edit.cjs.map +2 -2
- package/build/playlist/edit.cjs +43 -136
- package/build/playlist/edit.cjs.map +3 -3
- package/build/playlist/view.cjs +56 -38
- package/build/playlist/view.cjs.map +2 -2
- package/build/playlist-track/edit.cjs +0 -1
- package/build/playlist-track/edit.cjs.map +2 -2
- package/build/post-title/block.json +3 -0
- package/build/post-title/edit.cjs +2 -2
- package/build/post-title/edit.cjs.map +2 -2
- package/build/utils/waveform-player.cjs +68 -0
- package/build/utils/waveform-player.cjs.map +7 -0
- package/build/utils/waveform-utils.cjs +171 -0
- package/build/utils/waveform-utils.cjs.map +7 -0
- package/build-module/accordion/view.mjs +1 -35
- package/build-module/accordion/view.mjs.map +2 -2
- package/build-module/button/block.json +11 -3
- package/build-module/button/deprecated.mjs +246 -13
- package/build-module/button/deprecated.mjs.map +2 -2
- package/build-module/button/edit.mjs +47 -63
- package/build-module/button/edit.mjs.map +2 -2
- package/build-module/button/save.mjs +3 -7
- package/build-module/button/save.mjs.map +2 -2
- package/build-module/button/utils.mjs +33 -0
- package/build-module/button/utils.mjs.map +7 -0
- package/build-module/image/image.mjs +1 -1
- package/build-module/image/image.mjs.map +2 -2
- package/build-module/navigation/edit/index.mjs +4 -2
- package/build-module/navigation/edit/index.mjs.map +2 -2
- package/build-module/navigation/edit/leaf-more-menu.mjs +73 -7
- package/build-module/navigation/edit/leaf-more-menu.mjs.map +2 -2
- package/build-module/navigation/edit/menu-inspector-controls.mjs +21 -101
- package/build-module/navigation/edit/menu-inspector-controls.mjs.map +2 -2
- package/build-module/navigation/edit/navigation-link-ui.mjs +76 -0
- package/build-module/navigation/edit/navigation-link-ui.mjs.map +7 -0
- package/build-module/navigation/edit/navigation-list-view-header.mjs +58 -0
- package/build-module/navigation/edit/navigation-list-view-header.mjs.map +7 -0
- package/build-module/navigation/edit/navigation-menu-selector.mjs +5 -3
- package/build-module/navigation/edit/navigation-menu-selector.mjs.map +2 -2
- package/build-module/navigation/edit/placeholder/index.mjs +2 -2
- package/build-module/navigation/edit/placeholder/index.mjs.map +2 -2
- package/build-module/navigation-link/shared/controls.mjs +29 -53
- package/build-module/navigation-link/shared/controls.mjs.map +2 -2
- package/build-module/navigation-link/shared/use-link-preview.mjs +8 -9
- package/build-module/navigation-link/shared/use-link-preview.mjs.map +2 -2
- package/build-module/page-list-item/edit.mjs +6 -3
- package/build-module/page-list-item/edit.mjs.map +2 -2
- package/build-module/playlist/edit.mjs +41 -139
- package/build-module/playlist/edit.mjs.map +2 -2
- package/build-module/playlist/view.mjs +56 -38
- package/build-module/playlist/view.mjs.map +2 -2
- package/build-module/playlist-track/edit.mjs +0 -1
- package/build-module/playlist-track/edit.mjs.map +2 -2
- package/build-module/post-title/block.json +3 -0
- package/build-module/post-title/edit.mjs +2 -2
- package/build-module/post-title/edit.mjs.map +2 -2
- package/build-module/utils/waveform-player.mjs +43 -0
- package/build-module/utils/waveform-player.mjs.map +7 -0
- package/build-module/utils/waveform-utils.mjs +131 -0
- package/build-module/utils/waveform-utils.mjs.map +7 -0
- package/build-style/button/style-rtl.css +6 -0
- package/build-style/button/style.css +6 -0
- package/build-style/editor-rtl.css +13 -3
- package/build-style/editor.css +13 -3
- package/build-style/navigation-link/editor-rtl.css +10 -0
- package/build-style/navigation-link/editor.css +10 -0
- package/build-style/playlist/editor-rtl.css +3 -3
- package/build-style/playlist/editor.css +3 -3
- package/build-style/playlist/style-rtl.css +351 -17
- package/build-style/playlist/style.css +351 -17
- package/build-style/style-rtl.css +357 -17
- package/build-style/style.css +357 -17
- package/package.json +39 -38
- package/src/accordion/view.js +1 -44
- package/src/accordion-item/index.php +0 -1
- package/src/button/block.json +11 -3
- package/src/button/deprecated.js +254 -16
- package/src/button/edit.js +50 -61
- package/src/button/index.php +68 -0
- package/src/button/save.js +2 -8
- package/src/button/style.scss +49 -7
- package/src/button/test/utils.js +84 -0
- package/src/button/utils.js +42 -0
- package/src/cover/index.php +4 -4
- package/src/image/image.js +14 -15
- package/src/image/index.php +3 -1
- package/src/navigation/edit/index.js +4 -2
- package/src/navigation/edit/leaf-more-menu.js +86 -11
- package/src/navigation/edit/menu-inspector-controls.js +23 -142
- package/src/navigation/edit/navigation-link-ui.js +115 -0
- package/src/navigation/edit/navigation-list-view-header.js +62 -0
- package/src/navigation/edit/navigation-menu-selector.js +5 -3
- package/src/navigation/edit/placeholder/index.js +3 -2
- package/src/navigation/edit/test/navigation-menu-selector.js +23 -20
- package/src/navigation-link/editor.scss +18 -0
- package/src/navigation-link/shared/controls.js +35 -62
- package/src/navigation-link/shared/test/controls.js +5 -5
- package/src/navigation-link/shared/test/use-link-preview.test.js +19 -1
- package/src/navigation-link/shared/use-link-preview.js +14 -15
- package/src/page-list/index.php +1 -1
- package/src/page-list-item/edit.js +8 -7
- package/src/playlist/edit.js +60 -154
- package/src/playlist/editor.scss +3 -3
- package/src/playlist/index.php +15 -40
- package/src/playlist/style.scss +34 -27
- package/src/playlist/test/edit.js +137 -0
- package/src/playlist/view.js +97 -40
- package/src/playlist-track/edit.js +0 -1
- package/src/post-title/block.json +3 -0
- package/src/post-title/edit.js +4 -2
- package/src/query-title/index.php +1 -1
- package/src/search/index.php +1 -1
- package/src/utils/test/waveform-utils.js +328 -0
- package/src/utils/waveform-player.js +77 -0
- package/src/utils/waveform-utils.js +232 -0
- package/build/navigation/use-navigation-entities.cjs +0 -67
- package/build/navigation/use-navigation-entities.cjs.map +0 -7
- package/build-module/navigation/use-navigation-entities.mjs +0 -46
- package/build-module/navigation/use-navigation-entities.mjs.map +0 -7
- package/src/navigation/use-navigation-entities.js +0 -72
package/src/playlist/edit.js
CHANGED
|
@@ -7,7 +7,7 @@ import { v4 as uuid } from 'uuid';
|
|
|
7
7
|
/**
|
|
8
8
|
* WordPress dependencies
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { useCallback, useEffect } from '@wordpress/element';
|
|
11
11
|
import {
|
|
12
12
|
store as blockEditorStore,
|
|
13
13
|
MediaPlaceholder,
|
|
@@ -23,15 +23,13 @@ import {
|
|
|
23
23
|
ToggleControl,
|
|
24
24
|
Disabled,
|
|
25
25
|
SelectControl,
|
|
26
|
-
Spinner,
|
|
27
26
|
__experimentalToolsPanel as ToolsPanel,
|
|
28
27
|
__experimentalToolsPanelItem as ToolsPanelItem,
|
|
29
28
|
} from '@wordpress/components';
|
|
30
29
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
31
30
|
import { store as noticesStore } from '@wordpress/notices';
|
|
32
|
-
import { __
|
|
31
|
+
import { __ } from '@wordpress/i18n';
|
|
33
32
|
import { audio as icon } from '@wordpress/icons';
|
|
34
|
-
import { safeHTML, __unstableStripHTML as stripHTML } from '@wordpress/dom';
|
|
35
33
|
import { createBlock } from '@wordpress/blocks';
|
|
36
34
|
|
|
37
35
|
/**
|
|
@@ -39,99 +37,42 @@ import { createBlock } from '@wordpress/blocks';
|
|
|
39
37
|
*/
|
|
40
38
|
import { Caption } from '../utils/caption';
|
|
41
39
|
import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
|
|
40
|
+
import { WaveformPlayer } from '../utils/waveform-player';
|
|
42
41
|
|
|
43
42
|
const ALLOWED_MEDIA_TYPES = [ 'audio' ];
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
),
|
|
67
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Transform media library data into track block attributes.
|
|
46
|
+
*
|
|
47
|
+
* @param {Object} media - Media object from the media library.
|
|
48
|
+
* @return {Object} Track attributes for the playlist-track block.
|
|
49
|
+
*/
|
|
50
|
+
function getTrackAttributes( media ) {
|
|
51
|
+
return {
|
|
52
|
+
id: media.id || media.url, // Attachment ID or URL.
|
|
53
|
+
uniqueId: uuid(), // Unique ID for the track.
|
|
54
|
+
src: media.url,
|
|
55
|
+
title: media.title,
|
|
56
|
+
artist:
|
|
57
|
+
media.artist ||
|
|
58
|
+
media?.meta?.artist ||
|
|
59
|
+
media?.media_details?.artist ||
|
|
60
|
+
__( 'Unknown artist' ),
|
|
61
|
+
album:
|
|
62
|
+
media.album ||
|
|
63
|
+
media?.meta?.album ||
|
|
64
|
+
media?.media_details?.album ||
|
|
65
|
+
__( 'Unknown album' ),
|
|
66
|
+
length: media?.fileLength || media?.media_details?.length_formatted,
|
|
67
|
+
// Prevent using the default media attachment icon as the track image.
|
|
68
|
+
// Note: Image is not available when a new track is uploaded.
|
|
69
|
+
image:
|
|
70
|
+
media?.image?.src &&
|
|
71
|
+
media?.image?.src.endsWith( '/images/media/audio.svg' )
|
|
72
|
+
? ''
|
|
73
|
+
: media?.image?.src,
|
|
68
74
|
};
|
|
69
|
-
|
|
70
|
-
let ariaLabel;
|
|
71
|
-
if ( track?.title && track?.artist && track?.album ) {
|
|
72
|
-
ariaLabel = stripHTML(
|
|
73
|
-
sprintf(
|
|
74
|
-
/* translators: %1$s: track title, %2$s artist name, %3$s: album name. */
|
|
75
|
-
_x(
|
|
76
|
-
'%1$s by %2$s from the album %3$s',
|
|
77
|
-
'track title, artist name, album name'
|
|
78
|
-
),
|
|
79
|
-
track?.title,
|
|
80
|
-
track?.artist,
|
|
81
|
-
track?.album
|
|
82
|
-
)
|
|
83
|
-
);
|
|
84
|
-
} else if ( track?.title ) {
|
|
85
|
-
ariaLabel = stripHTML( track.title );
|
|
86
|
-
} else {
|
|
87
|
-
ariaLabel = stripHTML( __( 'Untitled' ) );
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<>
|
|
92
|
-
<div className="wp-block-playlist__current-item">
|
|
93
|
-
{ showImages && track?.image && (
|
|
94
|
-
<img
|
|
95
|
-
className="wp-block-playlist__item-image"
|
|
96
|
-
src={ track.image }
|
|
97
|
-
alt=""
|
|
98
|
-
width="70px"
|
|
99
|
-
height="70px"
|
|
100
|
-
/>
|
|
101
|
-
) }
|
|
102
|
-
<div>
|
|
103
|
-
{ ! track?.title ? (
|
|
104
|
-
<span className="wp-block-playlist__item-title">
|
|
105
|
-
<Spinner />
|
|
106
|
-
</span>
|
|
107
|
-
) : (
|
|
108
|
-
<span
|
|
109
|
-
className="wp-block-playlist__item-title"
|
|
110
|
-
{ ...trackTitle }
|
|
111
|
-
/>
|
|
112
|
-
) }
|
|
113
|
-
<div className="wp-block-playlist__current-item-artist-album">
|
|
114
|
-
<span
|
|
115
|
-
className="wp-block-playlist__item-artist"
|
|
116
|
-
{ ...trackArtist }
|
|
117
|
-
/>
|
|
118
|
-
<span
|
|
119
|
-
className="wp-block-playlist__item-album"
|
|
120
|
-
{ ...trackAlbum }
|
|
121
|
-
/>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
<audio
|
|
126
|
-
controls="controls"
|
|
127
|
-
src={ track?.url ? track.url : '' }
|
|
128
|
-
onEnded={ onTrackEnd }
|
|
129
|
-
aria-label={ ariaLabel }
|
|
130
|
-
tabIndex={ 0 }
|
|
131
|
-
/>
|
|
132
|
-
</>
|
|
133
|
-
);
|
|
134
|
-
};
|
|
75
|
+
}
|
|
135
76
|
|
|
136
77
|
const PlaylistEdit = ( {
|
|
137
78
|
attributes,
|
|
@@ -148,7 +89,6 @@ const PlaylistEdit = ( {
|
|
|
148
89
|
showArtists,
|
|
149
90
|
currentTrack,
|
|
150
91
|
} = attributes;
|
|
151
|
-
const [ trackListIndex, setTrackListIndex ] = useState( 0 );
|
|
152
92
|
const blockProps = useBlockProps();
|
|
153
93
|
const { replaceInnerBlocks, __unstableMarkNextChangeAsNotPersistent } =
|
|
154
94
|
useDispatch( blockEditorStore );
|
|
@@ -235,33 +175,7 @@ const PlaylistEdit = ( {
|
|
|
235
175
|
media = [ media ];
|
|
236
176
|
}
|
|
237
177
|
|
|
238
|
-
const
|
|
239
|
-
id: track.id || track.url, // Attachment ID or URL.
|
|
240
|
-
uniqueId: uuid(), // Unique ID for the track.
|
|
241
|
-
src: track.url,
|
|
242
|
-
title: track.title,
|
|
243
|
-
artist:
|
|
244
|
-
track.artist ||
|
|
245
|
-
track?.meta?.artist ||
|
|
246
|
-
track?.media_details?.artist ||
|
|
247
|
-
__( 'Unknown artist' ),
|
|
248
|
-
album:
|
|
249
|
-
track.album ||
|
|
250
|
-
track?.meta?.album ||
|
|
251
|
-
track?.media_details?.album ||
|
|
252
|
-
__( 'Unknown album' ),
|
|
253
|
-
length:
|
|
254
|
-
track?.fileLength || track?.media_details?.length_formatted,
|
|
255
|
-
// Prevent using the default media attachment icon as the track image.
|
|
256
|
-
// Note: Image is not available when a new track is uploaded.
|
|
257
|
-
image:
|
|
258
|
-
track?.image?.src &&
|
|
259
|
-
track?.image?.src.endsWith( '/images/media/audio.svg' )
|
|
260
|
-
? ''
|
|
261
|
-
: track?.image?.src,
|
|
262
|
-
} );
|
|
263
|
-
|
|
264
|
-
const trackList = media.map( trackAttributes );
|
|
178
|
+
const trackList = media.map( getTrackAttributes );
|
|
265
179
|
__unstableMarkNextChangeAsNotPersistent();
|
|
266
180
|
setAttributes( {
|
|
267
181
|
currentTrack:
|
|
@@ -282,29 +196,21 @@ const PlaylistEdit = ( {
|
|
|
282
196
|
]
|
|
283
197
|
);
|
|
284
198
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
} else if ( tracks.length > 0 ) {
|
|
299
|
-
const validTrack = tracks.find(
|
|
300
|
-
( track ) => track.uniqueId !== undefined
|
|
301
|
-
);
|
|
302
|
-
if ( validTrack ) {
|
|
303
|
-
setAttributes( { currentTrack: validTrack.uniqueId } );
|
|
304
|
-
}
|
|
305
|
-
}
|
|
199
|
+
// Get current track data by finding the track with matching uniqueId.
|
|
200
|
+
const currentTrackData = tracks.find(
|
|
201
|
+
( track ) => track.uniqueId === currentTrack
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// Handle track end - advance to next track or loop to first.
|
|
205
|
+
const onTrackEnded = useCallback( () => {
|
|
206
|
+
const currentIndex = tracks.findIndex(
|
|
207
|
+
( track ) => track.uniqueId === currentTrack
|
|
208
|
+
);
|
|
209
|
+
const nextTrack = tracks[ currentIndex + 1 ] || tracks[ 0 ];
|
|
210
|
+
if ( nextTrack?.uniqueId ) {
|
|
211
|
+
setAttributes( { currentTrack: nextTrack.uniqueId } );
|
|
306
212
|
}
|
|
307
|
-
}, [
|
|
213
|
+
}, [ currentTrack, tracks, setAttributes ] );
|
|
308
214
|
|
|
309
215
|
const onChangeOrder = useCallback(
|
|
310
216
|
( trackOrder ) => {
|
|
@@ -317,16 +223,13 @@ const PlaylistEdit = ( {
|
|
|
317
223
|
}
|
|
318
224
|
return titleB.localeCompare( titleA );
|
|
319
225
|
} );
|
|
320
|
-
const
|
|
321
|
-
( block ) => block.attributes
|
|
322
|
-
);
|
|
226
|
+
const firstUniqueId = sortedBlocks[ 0 ]?.attributes?.uniqueId;
|
|
323
227
|
replaceInnerBlocks( clientId, sortedBlocks );
|
|
324
228
|
setAttributes( {
|
|
325
229
|
order: trackOrder,
|
|
326
230
|
currentTrack:
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
? sortedTracks[ 0 ].uniqueId
|
|
231
|
+
firstUniqueId && firstUniqueId !== currentTrack
|
|
232
|
+
? firstUniqueId
|
|
330
233
|
: currentTrack,
|
|
331
234
|
} );
|
|
332
235
|
},
|
|
@@ -358,7 +261,7 @@ const PlaylistEdit = ( {
|
|
|
358
261
|
renderAppender: hasAnySelected && InnerBlocks.ButtonBlockAppender,
|
|
359
262
|
} );
|
|
360
263
|
|
|
361
|
-
if (
|
|
264
|
+
if ( tracks.length === 0 ) {
|
|
362
265
|
return (
|
|
363
266
|
<div
|
|
364
267
|
{ ...blockProps }
|
|
@@ -498,10 +401,12 @@ const PlaylistEdit = ( {
|
|
|
498
401
|
</InspectorControls>
|
|
499
402
|
<figure { ...blockProps }>
|
|
500
403
|
<Disabled isDisabled={ ! isSelected }>
|
|
501
|
-
<
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
404
|
+
<WaveformPlayer
|
|
405
|
+
src={ currentTrackData?.src }
|
|
406
|
+
title={ currentTrackData?.title }
|
|
407
|
+
artist={ currentTrackData?.artist }
|
|
408
|
+
image={ currentTrackData?.image }
|
|
409
|
+
onEnded={ onTrackEnded }
|
|
505
410
|
/>
|
|
506
411
|
</Disabled>
|
|
507
412
|
{ showTracklist && (
|
|
@@ -529,3 +434,4 @@ const PlaylistEdit = ( {
|
|
|
529
434
|
};
|
|
530
435
|
|
|
531
436
|
export default PlaylistEdit;
|
|
437
|
+
export { getTrackAttributes };
|
package/src/playlist/editor.scss
CHANGED
package/src/playlist/index.php
CHANGED
|
@@ -58,13 +58,16 @@ function render_block_core_playlist( $attributes, $content, $block ) {
|
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// Data is passed to wp_interactivity_state() which JSON-encodes it,
|
|
62
|
+
// so we use wp_strip_all_tags() instead of esc_html() to prevent
|
|
63
|
+
// HTML injection without double-encoding. URLs still use esc_url().
|
|
61
64
|
$tracks_data[ $unique_id ] = array(
|
|
62
65
|
'url' => esc_url( $url ),
|
|
63
|
-
'title' =>
|
|
64
|
-
'artist' =>
|
|
65
|
-
'album' =>
|
|
66
|
+
'title' => wp_strip_all_tags( $title ),
|
|
67
|
+
'artist' => wp_strip_all_tags( $artist ),
|
|
68
|
+
'album' => wp_strip_all_tags( $album ),
|
|
66
69
|
'image' => esc_url( $image ),
|
|
67
|
-
'ariaLabel' =>
|
|
70
|
+
'ariaLabel' => wp_strip_all_tags( $aria_label ),
|
|
68
71
|
);
|
|
69
72
|
|
|
70
73
|
if ( $unique_id === $current_media_id ) {
|
|
@@ -96,41 +99,14 @@ function render_block_core_playlist( $attributes, $content, $block ) {
|
|
|
96
99
|
)
|
|
97
100
|
);
|
|
98
101
|
|
|
99
|
-
//
|
|
100
|
-
$
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
$
|
|
105
|
-
'
|
|
106
|
-
|
|
107
|
-
alt=""
|
|
108
|
-
width="70px"
|
|
109
|
-
height="70px"
|
|
110
|
-
data-wp-bind--src="state.currentTrack.image"
|
|
111
|
-
data-wp-bind--hidden="!state.currentTrack.image"
|
|
112
|
-
/>';
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
$html .= '
|
|
116
|
-
<div>
|
|
117
|
-
<span class="wp-block-playlist__item-title" data-wp-text="state.currentTrack.title"></span>
|
|
118
|
-
<div class="wp-block-playlist__current-item-artist-album">
|
|
119
|
-
<span class="wp-block-playlist__item-artist" data-wp-text="state.currentTrack.artist"></span>
|
|
120
|
-
<span class="wp-block-playlist__item-album" data-wp-text="state.currentTrack.album"></span>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
<audio
|
|
125
|
-
controls="controls"
|
|
126
|
-
data-wp-on--ended="actions.nextSong"
|
|
127
|
-
data-wp-on--play="actions.isPlaying"
|
|
128
|
-
data-wp-on--pause="actions.isPaused"
|
|
129
|
-
data-wp-bind--src="state.currentTrack.url"
|
|
130
|
-
data-wp-bind--aria-label="state.currentTrack.ariaLabel"
|
|
131
|
-
data-wp-watch="callbacks.autoPlay"
|
|
132
|
-
></audio>
|
|
133
|
-
';
|
|
102
|
+
// Add waveform player container with translated button labels.
|
|
103
|
+
$label_play = esc_attr__( 'Play' );
|
|
104
|
+
$label_pause = esc_attr__( 'Pause' );
|
|
105
|
+
$html = '<div class="wp-block-playlist__waveform-player"
|
|
106
|
+
data-wp-watch="callbacks.initWaveformPlayer"
|
|
107
|
+
data-label-play="' . $label_play . '"
|
|
108
|
+
data-label-pause="' . $label_pause . '"
|
|
109
|
+
></div>';
|
|
134
110
|
|
|
135
111
|
// Add the HTML for the current track inside the figure.
|
|
136
112
|
$figure = null;
|
|
@@ -149,7 +125,6 @@ function render_block_core_playlist( $attributes, $content, $block ) {
|
|
|
149
125
|
'playlistId' => $playlist_id,
|
|
150
126
|
'currentId' => $current_unique_id,
|
|
151
127
|
'tracks' => $playlist_tracks,
|
|
152
|
-
'isPlaying' => false,
|
|
153
128
|
)
|
|
154
129
|
)
|
|
155
130
|
);
|
package/src/playlist/style.scss
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
|
+
@use "@arraypress/waveform-player/dist/waveform-player";
|
|
2
|
+
|
|
3
|
+
// Waveform player dimensions.
|
|
4
|
+
$waveform-player-height: 100px;
|
|
5
|
+
|
|
1
6
|
.wp-block-playlist {
|
|
2
|
-
.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
margin-bottom: var(--wp--preset--spacing--30, 1em);
|
|
9
|
-
|
|
10
|
-
div {
|
|
11
|
-
display: flex;
|
|
12
|
-
flex-direction: column;
|
|
13
|
-
align-items: flex-start;
|
|
14
|
-
gap: var(--wp--preset--spacing--20, 0.5em);
|
|
15
|
-
}
|
|
7
|
+
// Main waveform player container.
|
|
8
|
+
.wp-block-playlist__waveform-player {
|
|
9
|
+
width: 100%;
|
|
10
|
+
margin: var(--wp--preset--spacing--20, 0.625em) 0;
|
|
11
|
+
position: relative;
|
|
12
|
+
}
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
// Set the waveform track height and remove gap between button and waveform.
|
|
15
|
+
.waveform-track {
|
|
16
|
+
height: $waveform-player-height;
|
|
17
|
+
gap: 0;
|
|
18
|
+
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// WaveformPlayer button styling.
|
|
21
|
+
.waveform-btn {
|
|
22
|
+
border-radius: 0;
|
|
23
|
+
border-end-start-radius: 0.125rem;
|
|
24
|
+
border-start-start-radius: 0.125rem;
|
|
25
|
+
width: $waveform-player-height;
|
|
26
|
+
height: $waveform-player-height;
|
|
27
|
+
min-width: $waveform-player-height;
|
|
28
|
+
background: currentColor;
|
|
29
|
+
margin: 0;
|
|
30
|
+
|
|
31
|
+
&:hover:not(:disabled) {
|
|
32
|
+
transform: none;
|
|
23
33
|
}
|
|
34
|
+
}
|
|
24
35
|
|
|
36
|
+
.waveform-track.waveform-align-bottom .waveform-btn {
|
|
37
|
+
margin-bottom: 0;
|
|
25
38
|
}
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
margin-top: var(--wp--preset--spacing--20, 0.625em);
|
|
40
|
+
.waveform-subtitle {
|
|
41
|
+
opacity: 0.7;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
.wp-block-playlist__tracklist {
|
|
@@ -49,9 +61,4 @@
|
|
|
49
61
|
counter-reset: playlist-track;
|
|
50
62
|
}
|
|
51
63
|
}
|
|
52
|
-
|
|
53
|
-
li.block-list-appender.block-list-appender {
|
|
54
|
-
position: initial;
|
|
55
|
-
margin-top: var(--wp--preset--spacing--30, 1em);
|
|
56
|
-
}
|
|
57
64
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Internal dependencies
|
|
7
|
+
*/
|
|
8
|
+
import { getTrackAttributes } from '../edit';
|
|
9
|
+
|
|
10
|
+
// Mock uuid to return predictable values.
|
|
11
|
+
jest.mock( 'uuid', () => ( {
|
|
12
|
+
v4: jest.fn( () => 'mock-uuid-1234' ),
|
|
13
|
+
} ) );
|
|
14
|
+
|
|
15
|
+
describe( 'Playlist block edit utilities', () => {
|
|
16
|
+
describe( 'getTrackAttributes', () => {
|
|
17
|
+
it( 'should transform media object to track attributes', () => {
|
|
18
|
+
const media = {
|
|
19
|
+
id: 123,
|
|
20
|
+
url: 'https://example.com/song.mp3',
|
|
21
|
+
title: 'My Song',
|
|
22
|
+
artist: 'The Artist',
|
|
23
|
+
album: 'Great Album',
|
|
24
|
+
fileLength: '3:45',
|
|
25
|
+
image: { src: 'https://example.com/cover.jpg' },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const result = getTrackAttributes( media );
|
|
29
|
+
|
|
30
|
+
expect( result ).toEqual( {
|
|
31
|
+
id: 123,
|
|
32
|
+
uniqueId: 'mock-uuid-1234',
|
|
33
|
+
src: 'https://example.com/song.mp3',
|
|
34
|
+
title: 'My Song',
|
|
35
|
+
artist: 'The Artist',
|
|
36
|
+
album: 'Great Album',
|
|
37
|
+
length: '3:45',
|
|
38
|
+
image: 'https://example.com/cover.jpg',
|
|
39
|
+
} );
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
it( 'should use URL as id when attachment id is not available', () => {
|
|
43
|
+
const media = {
|
|
44
|
+
url: 'https://example.com/song.mp3',
|
|
45
|
+
title: 'My Song',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const result = getTrackAttributes( media );
|
|
49
|
+
|
|
50
|
+
expect( result.id ).toBe( 'https://example.com/song.mp3' );
|
|
51
|
+
} );
|
|
52
|
+
|
|
53
|
+
it( 'should fall back to meta.artist when artist is not available', () => {
|
|
54
|
+
const media = {
|
|
55
|
+
url: 'https://example.com/song.mp3',
|
|
56
|
+
title: 'My Song',
|
|
57
|
+
meta: { artist: 'Meta Artist' },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const result = getTrackAttributes( media );
|
|
61
|
+
|
|
62
|
+
expect( result.artist ).toBe( 'Meta Artist' );
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
it( 'should fall back to media_details.artist when artist and meta.artist are not available', () => {
|
|
66
|
+
const media = {
|
|
67
|
+
url: 'https://example.com/song.mp3',
|
|
68
|
+
title: 'My Song',
|
|
69
|
+
media_details: { artist: 'Media Details Artist' },
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const result = getTrackAttributes( media );
|
|
73
|
+
|
|
74
|
+
expect( result.artist ).toBe( 'Media Details Artist' );
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
it( 'should use "Unknown artist" when no artist is available', () => {
|
|
78
|
+
const media = {
|
|
79
|
+
url: 'https://example.com/song.mp3',
|
|
80
|
+
title: 'My Song',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const result = getTrackAttributes( media );
|
|
84
|
+
|
|
85
|
+
expect( result.artist ).toBe( 'Unknown artist' );
|
|
86
|
+
} );
|
|
87
|
+
|
|
88
|
+
it( 'should use "Unknown album" when no album is available', () => {
|
|
89
|
+
const media = {
|
|
90
|
+
url: 'https://example.com/song.mp3',
|
|
91
|
+
title: 'My Song',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const result = getTrackAttributes( media );
|
|
95
|
+
|
|
96
|
+
expect( result.album ).toBe( 'Unknown album' );
|
|
97
|
+
} );
|
|
98
|
+
|
|
99
|
+
it( 'should use media_details.length_formatted when fileLength is not available', () => {
|
|
100
|
+
const media = {
|
|
101
|
+
url: 'https://example.com/song.mp3',
|
|
102
|
+
title: 'My Song',
|
|
103
|
+
media_details: { length_formatted: '4:30' },
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const result = getTrackAttributes( media );
|
|
107
|
+
|
|
108
|
+
expect( result.length ).toBe( '4:30' );
|
|
109
|
+
} );
|
|
110
|
+
|
|
111
|
+
it( 'should exclude default audio icon from image', () => {
|
|
112
|
+
const media = {
|
|
113
|
+
url: 'https://example.com/song.mp3',
|
|
114
|
+
title: 'My Song',
|
|
115
|
+
image: {
|
|
116
|
+
src: 'https://example.com/wp-includes/images/media/audio.svg',
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const result = getTrackAttributes( media );
|
|
121
|
+
|
|
122
|
+
expect( result.image ).toBe( '' );
|
|
123
|
+
} );
|
|
124
|
+
|
|
125
|
+
it( 'should include image URLs', () => {
|
|
126
|
+
const media = {
|
|
127
|
+
url: 'https://example.com/song.mp3',
|
|
128
|
+
title: 'My Song',
|
|
129
|
+
image: { src: 'https://example.com/cover.jpg' },
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const result = getTrackAttributes( media );
|
|
133
|
+
|
|
134
|
+
expect( result.image ).toBe( 'https://example.com/cover.jpg' );
|
|
135
|
+
} );
|
|
136
|
+
} );
|
|
137
|
+
} );
|