@wordpress/block-library 9.40.2-next.v.202602271551.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/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-link/shared/use-link-preview.cjs +2 -2
- package/build/navigation-link/shared/use-link-preview.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/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-link/shared/use-link-preview.mjs +2 -2
- package/build-module/navigation-link/shared/use-link-preview.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 +3 -3
- package/build-style/editor.css +3 -3
- 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/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/image/image.js +14 -15
- package/src/image/index.php +3 -1
- package/src/navigation-link/shared/test/use-link-preview.test.js +9 -0
- package/src/navigation-link/shared/use-link-preview.js +6 -9
- 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/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
|
@@ -22,7 +22,7 @@ import { createInterpolateElement } from "@wordpress/element";
|
|
|
22
22
|
import { useToolsPanelDropdownMenuProps } from "../utils/hooks.mjs";
|
|
23
23
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
24
24
|
function PostTitleEdit({
|
|
25
|
-
attributes: { level, levelOptions, isLink, rel, linkTarget },
|
|
25
|
+
attributes: { level, levelOptions, isLink, rel, linkTarget, placeholder },
|
|
26
26
|
setAttributes,
|
|
27
27
|
context: { postType, postId, queryId },
|
|
28
28
|
insertBlocksAfter
|
|
@@ -55,7 +55,7 @@ function PostTitleEdit({
|
|
|
55
55
|
const blockProps = useBlockProps();
|
|
56
56
|
const blockEditingMode = useBlockEditingMode();
|
|
57
57
|
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
|
|
58
|
-
let titleElement = /* @__PURE__ */ jsx(TagName, { ...blockProps, children: __("Title") });
|
|
58
|
+
let titleElement = /* @__PURE__ */ jsx(TagName, { ...blockProps, children: placeholder || __("Title") });
|
|
59
59
|
if (postType && postId) {
|
|
60
60
|
titleElement = userCanEdit ? /* @__PURE__ */ jsx(
|
|
61
61
|
PlainText,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/post-title/edit.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tBlockControls,\n\tInspectorControls,\n\tuseBlockProps,\n\tPlainText,\n\tHeadingLevelDropdown,\n\tuseBlockEditingMode,\n} from '@wordpress/block-editor';\nimport {\n\tToggleControl,\n\tTextControl,\n\tExternalLink,\n\t__experimentalToolsPanel as ToolsPanel,\n\t__experimentalToolsPanelItem as ToolsPanelItem,\n} from '@wordpress/components';\nimport { __ } from '@wordpress/i18n';\nimport { createBlock, getDefaultBlockName } from '@wordpress/blocks';\nimport { useEntityProp, store as coreStore } from '@wordpress/core-data';\nimport { useSelect } from '@wordpress/data';\nimport { createInterpolateElement } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useToolsPanelDropdownMenuProps } from '../utils/hooks';\n\nexport default function PostTitleEdit( {\n\tattributes: { level, levelOptions, isLink, rel, linkTarget },\n\tsetAttributes,\n\tcontext: { postType, postId, queryId },\n\tinsertBlocksAfter,\n} ) {\n\tconst TagName = level === 0 ? 'p' : `h${ level }`;\n\tconst isDescendentOfQueryLoop = Number.isFinite( queryId );\n\tconst userCanEdit = useSelect(\n\t\t( select ) => {\n\t\t\t/**\n\t\t\t * useCanEditEntity may trigger an OPTIONS request to the REST API\n\t\t\t * via the canUser resolver. However, when the Post Title is a\n\t\t\t * descendant of a Query Loop block, the title cannot be edited. In\n\t\t\t * order to avoid these unnecessary requests, we call the hook\n\t\t\t * without the proper data, resulting in returning early without\n\t\t\t * making them.\n\t\t\t */\n\t\t\tif ( isDescendentOfQueryLoop ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn select( coreStore ).canUser( 'update', {\n\t\t\t\tkind: 'postType',\n\t\t\t\tname: postType,\n\t\t\t\tid: postId,\n\t\t\t} );\n\t\t},\n\t\t[ isDescendentOfQueryLoop, postType, postId ]\n\t);\n\tconst [ rawTitle = '', setTitle, fullTitle ] = useEntityProp(\n\t\t'postType',\n\t\tpostType,\n\t\t'title',\n\t\tpostId\n\t);\n\tconst [ link ] = useEntityProp( 'postType', postType, 'link', postId );\n\tconst onSplitAtEnd = () => {\n\t\tinsertBlocksAfter( createBlock( getDefaultBlockName() ) );\n\t};\n\tconst blockProps = useBlockProps();\n\tconst blockEditingMode = useBlockEditingMode();\n\tconst dropdownMenuProps = useToolsPanelDropdownMenuProps();\n\n\tlet titleElement = <TagName { ...blockProps }>{ __( 'Title' ) }</TagName
|
|
5
|
-
"mappings": ";AAGA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA,4BAA4B;AAAA,EAC5B,gCAAgC;AAAA,OAC1B;AACP,SAAS,UAAU;AACnB,SAAS,aAAa,2BAA2B;AACjD,SAAS,eAAe,SAAS,iBAAiB;AAClD,SAAS,iBAAiB;AAC1B,SAAS,gCAAgC;AAKzC,SAAS,sCAAsC;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tBlockControls,\n\tInspectorControls,\n\tuseBlockProps,\n\tPlainText,\n\tHeadingLevelDropdown,\n\tuseBlockEditingMode,\n} from '@wordpress/block-editor';\nimport {\n\tToggleControl,\n\tTextControl,\n\tExternalLink,\n\t__experimentalToolsPanel as ToolsPanel,\n\t__experimentalToolsPanelItem as ToolsPanelItem,\n} from '@wordpress/components';\nimport { __ } from '@wordpress/i18n';\nimport { createBlock, getDefaultBlockName } from '@wordpress/blocks';\nimport { useEntityProp, store as coreStore } from '@wordpress/core-data';\nimport { useSelect } from '@wordpress/data';\nimport { createInterpolateElement } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useToolsPanelDropdownMenuProps } from '../utils/hooks';\n\nexport default function PostTitleEdit( {\n\tattributes: { level, levelOptions, isLink, rel, linkTarget, placeholder },\n\tsetAttributes,\n\tcontext: { postType, postId, queryId },\n\tinsertBlocksAfter,\n} ) {\n\tconst TagName = level === 0 ? 'p' : `h${ level }`;\n\tconst isDescendentOfQueryLoop = Number.isFinite( queryId );\n\tconst userCanEdit = useSelect(\n\t\t( select ) => {\n\t\t\t/**\n\t\t\t * useCanEditEntity may trigger an OPTIONS request to the REST API\n\t\t\t * via the canUser resolver. However, when the Post Title is a\n\t\t\t * descendant of a Query Loop block, the title cannot be edited. In\n\t\t\t * order to avoid these unnecessary requests, we call the hook\n\t\t\t * without the proper data, resulting in returning early without\n\t\t\t * making them.\n\t\t\t */\n\t\t\tif ( isDescendentOfQueryLoop ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn select( coreStore ).canUser( 'update', {\n\t\t\t\tkind: 'postType',\n\t\t\t\tname: postType,\n\t\t\t\tid: postId,\n\t\t\t} );\n\t\t},\n\t\t[ isDescendentOfQueryLoop, postType, postId ]\n\t);\n\tconst [ rawTitle = '', setTitle, fullTitle ] = useEntityProp(\n\t\t'postType',\n\t\tpostType,\n\t\t'title',\n\t\tpostId\n\t);\n\tconst [ link ] = useEntityProp( 'postType', postType, 'link', postId );\n\tconst onSplitAtEnd = () => {\n\t\tinsertBlocksAfter( createBlock( getDefaultBlockName() ) );\n\t};\n\tconst blockProps = useBlockProps();\n\tconst blockEditingMode = useBlockEditingMode();\n\tconst dropdownMenuProps = useToolsPanelDropdownMenuProps();\n\n\tlet titleElement = (\n\t\t<TagName { ...blockProps }>{ placeholder || __( 'Title' ) }</TagName>\n\t);\n\n\tif ( postType && postId ) {\n\t\ttitleElement = userCanEdit ? (\n\t\t\t<PlainText\n\t\t\t\ttagName={ TagName }\n\t\t\t\tplaceholder={ __( '(no title)' ) }\n\t\t\t\tvalue={ rawTitle }\n\t\t\t\tonChange={ setTitle }\n\t\t\t\t__experimentalVersion={ 2 }\n\t\t\t\t__unstableOnSplitAtEnd={ onSplitAtEnd }\n\t\t\t\t{ ...blockProps }\n\t\t\t/>\n\t\t) : (\n\t\t\t<TagName\n\t\t\t\t{ ...blockProps }\n\t\t\t\tdangerouslySetInnerHTML={ {\n\t\t\t\t\t__html: fullTitle?.rendered || __( '(no title)' ),\n\t\t\t\t} }\n\t\t\t/>\n\t\t);\n\t}\n\n\tif ( isLink && postType && postId ) {\n\t\ttitleElement = userCanEdit ? (\n\t\t\t<TagName { ...blockProps }>\n\t\t\t\t<PlainText\n\t\t\t\t\ttagName=\"a\"\n\t\t\t\t\thref={ link }\n\t\t\t\t\ttarget={ linkTarget }\n\t\t\t\t\trel={ rel }\n\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t! rawTitle.length ? __( '(no title)' ) : null\n\t\t\t\t\t}\n\t\t\t\t\tvalue={ rawTitle }\n\t\t\t\t\tonChange={ setTitle }\n\t\t\t\t\t__experimentalVersion={ 2 }\n\t\t\t\t\t__unstableOnSplitAtEnd={ onSplitAtEnd }\n\t\t\t\t/>\n\t\t\t</TagName>\n\t\t) : (\n\t\t\t<TagName { ...blockProps }>\n\t\t\t\t<a\n\t\t\t\t\thref={ link }\n\t\t\t\t\ttarget={ linkTarget }\n\t\t\t\t\trel={ rel }\n\t\t\t\t\tonClick={ ( event ) => event.preventDefault() }\n\t\t\t\t\tdangerouslySetInnerHTML={ {\n\t\t\t\t\t\t__html: fullTitle?.rendered || __( '(no title)' ),\n\t\t\t\t\t} }\n\t\t\t\t/>\n\t\t\t</TagName>\n\t\t);\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{ blockEditingMode === 'default' && (\n\t\t\t\t<>\n\t\t\t\t\t<BlockControls group=\"block\">\n\t\t\t\t\t\t<HeadingLevelDropdown\n\t\t\t\t\t\t\tvalue={ level }\n\t\t\t\t\t\t\toptions={ levelOptions }\n\t\t\t\t\t\t\tonChange={ ( newLevel ) =>\n\t\t\t\t\t\t\t\tsetAttributes( { level: newLevel } )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</BlockControls>\n\t\t\t\t\t<InspectorControls>\n\t\t\t\t\t\t<ToolsPanel\n\t\t\t\t\t\t\tlabel={ __( 'Settings' ) }\n\t\t\t\t\t\t\tresetAll={ () => {\n\t\t\t\t\t\t\t\tsetAttributes( {\n\t\t\t\t\t\t\t\t\trel: '',\n\t\t\t\t\t\t\t\t\tlinkTarget: '_self',\n\t\t\t\t\t\t\t\t\tisLink: false,\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\tdropdownMenuProps={ dropdownMenuProps }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<ToolsPanelItem\n\t\t\t\t\t\t\t\tlabel={ __( 'Make title a link' ) }\n\t\t\t\t\t\t\t\tisShownByDefault\n\t\t\t\t\t\t\t\thasValue={ () => isLink }\n\t\t\t\t\t\t\t\tonDeselect={ () =>\n\t\t\t\t\t\t\t\t\tsetAttributes( { isLink: false } )\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\t\t\t\tlabel={ __( 'Make title a link' ) }\n\t\t\t\t\t\t\t\t\tonChange={ () =>\n\t\t\t\t\t\t\t\t\t\tsetAttributes( { isLink: ! isLink } )\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tchecked={ isLink }\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</ToolsPanelItem>\n\t\t\t\t\t\t\t{ isLink && (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<ToolsPanelItem\n\t\t\t\t\t\t\t\t\t\tlabel={ __( 'Open in new tab' ) }\n\t\t\t\t\t\t\t\t\t\tisShownByDefault\n\t\t\t\t\t\t\t\t\t\thasValue={ () =>\n\t\t\t\t\t\t\t\t\t\t\tlinkTarget === '_blank'\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tonDeselect={ () =>\n\t\t\t\t\t\t\t\t\t\t\tsetAttributes( {\n\t\t\t\t\t\t\t\t\t\t\t\tlinkTarget: '_self',\n\t\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\t\t\t\t\t\tlabel={ __( 'Open in new tab' ) }\n\t\t\t\t\t\t\t\t\t\t\tonChange={ ( value ) =>\n\t\t\t\t\t\t\t\t\t\t\t\tsetAttributes( {\n\t\t\t\t\t\t\t\t\t\t\t\t\tlinkTarget: value\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? '_blank'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: '_self',\n\t\t\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tchecked={ linkTarget === '_blank' }\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</ToolsPanelItem>\n\t\t\t\t\t\t\t\t\t<ToolsPanelItem\n\t\t\t\t\t\t\t\t\t\tlabel={ __( 'Link relation' ) }\n\t\t\t\t\t\t\t\t\t\tisShownByDefault\n\t\t\t\t\t\t\t\t\t\thasValue={ () => !! rel }\n\t\t\t\t\t\t\t\t\t\tonDeselect={ () =>\n\t\t\t\t\t\t\t\t\t\t\tsetAttributes( { rel: '' } )\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<TextControl\n\t\t\t\t\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t\t\t\t\t\tlabel={ __( 'Link relation' ) }\n\t\t\t\t\t\t\t\t\t\t\thelp={ createInterpolateElement(\n\t\t\t\t\t\t\t\t\t\t\t\t__(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'The <a>Link Relation</a> attribute defines the relationship between a linked resource and the current document.'\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\ta: (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ExternalLink href=\"https://developer.mozilla.org/docs/Web/HTML/Attributes/rel\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t\t\t\tvalue={ rel }\n\t\t\t\t\t\t\t\t\t\t\tonChange={ ( newRel ) =>\n\t\t\t\t\t\t\t\t\t\t\t\tsetAttributes( { rel: newRel } )\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</ToolsPanelItem>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t</ToolsPanel>\n\t\t\t\t\t</InspectorControls>\n\t\t\t\t</>\n\t\t\t) }\n\t\t\t{ titleElement }\n\t\t</>\n\t);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// packages/block-library/src/utils/waveform-player.js
|
|
2
|
+
import { useRef } from "@wordpress/element";
|
|
3
|
+
import { useRefEffect } from "@wordpress/compose";
|
|
4
|
+
import { initWaveformPlayer } from "./waveform-utils.mjs";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
function WaveformPlayer({ src, title, artist, image, onEnded }) {
|
|
7
|
+
const onEndedRef = useRef(onEnded);
|
|
8
|
+
onEndedRef.current = onEnded;
|
|
9
|
+
const ref = useRefEffect(
|
|
10
|
+
(element) => {
|
|
11
|
+
if (!src) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let cancelled = false;
|
|
15
|
+
let playerDestroy;
|
|
16
|
+
function init() {
|
|
17
|
+
if (cancelled) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { destroy } = initWaveformPlayer(element, {
|
|
21
|
+
src,
|
|
22
|
+
title,
|
|
23
|
+
artist,
|
|
24
|
+
image,
|
|
25
|
+
onEnded: () => onEndedRef.current?.()
|
|
26
|
+
});
|
|
27
|
+
playerDestroy = destroy;
|
|
28
|
+
}
|
|
29
|
+
const timeoutId = setTimeout(init, 100);
|
|
30
|
+
return () => {
|
|
31
|
+
cancelled = true;
|
|
32
|
+
clearTimeout(timeoutId);
|
|
33
|
+
playerDestroy?.();
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
[src, title, artist, image]
|
|
37
|
+
);
|
|
38
|
+
return /* @__PURE__ */ jsx("div", { ref, className: "wp-block-playlist__waveform-player" });
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
WaveformPlayer
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=waveform-player.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/waveform-player.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useRef } from '@wordpress/element';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { initWaveformPlayer } from './waveform-utils';\n\n/**\n * A reusable WaveformPlayer component for the block editor.\n *\n * Renders an audio waveform visualization with play/pause controls.\n * Automatically inherits colors from the parent block's text color.\n *\n * @param {Object} props - Component props.\n * @param {string} props.src - The audio file URL.\n * @param {string} props.title - The track title.\n * @param {string} props.artist - The artist name.\n * @param {string} props.image - The artwork image URL.\n * @param {Function} props.onEnded - Callback when the track finishes playing.\n * @return {Element} The WaveformPlayer element.\n */\nexport function WaveformPlayer( { src, title, artist, image, onEnded } ) {\n\t// Store onEnded in a ref so it doesn't need to be a useRefEffect dependency.\n\t// The callback changes reference on every render (its dependency chain\n\t// includes an unstable array), which would cause useRefEffect to destroy\n\t// and recreate the entire player on every re-render, making it disappear\n\t// during editor resizes.\n\tconst onEndedRef = useRef( onEnded );\n\tonEndedRef.current = onEnded;\n\n\tconst ref = useRefEffect(\n\t\t( element ) => {\n\t\t\tif ( ! src ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet cancelled = false;\n\t\t\tlet playerDestroy;\n\n\t\t\tfunction init() {\n\t\t\t\tif ( cancelled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { destroy } = initWaveformPlayer( element, {\n\t\t\t\t\tsrc,\n\t\t\t\t\ttitle,\n\t\t\t\t\tartist,\n\t\t\t\t\timage,\n\t\t\t\t\tonEnded: () => onEndedRef.current?.(),\n\t\t\t\t} );\n\t\t\t\tplayerDestroy = destroy;\n\t\t\t}\n\n\t\t\t// Defer initialization so the element inherits the correct\n\t\t\t// text color, which is used to derive waveform colors. In the\n\t\t\t// editor iframe, theme styles (CSS custom properties) are\n\t\t\t// injected dynamically, so getComputedStyle may return the\n\t\t\t// default black on first render.\n\t\t\t// Using a requestAnimationFrame loop isn't sufficient to solve the issue.\n\t\t\t// TODO - find a better option than a setTimeout, so we're not relying on an arbitrary number.\n\t\t\tconst timeoutId = setTimeout( init, 100 );\n\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t\tclearTimeout( timeoutId );\n\t\t\t\tplayerDestroy?.();\n\t\t\t};\n\t\t},\n\t\t[ src, title, artist, image ]\n\t);\n\n\treturn <div ref={ ref } className=\"wp-block-playlist__waveform-player\" />;\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAK7B,SAAS,0BAA0B;AAkE3B;AAlDD,SAAS,eAAgB,EAAE,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAI;AAMxE,QAAM,aAAa,OAAQ,OAAQ;AACnC,aAAW,UAAU;AAErB,QAAM,MAAM;AAAA,IACX,CAAE,YAAa;AACd,UAAK,CAAE,KAAM;AACZ;AAAA,MACD;AAEA,UAAI,YAAY;AAChB,UAAI;AAEJ,eAAS,OAAO;AACf,YAAK,WAAY;AAChB;AAAA,QACD;AACA,cAAM,EAAE,QAAQ,IAAI,mBAAoB,SAAS;AAAA,UAChD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,SAAS,MAAM,WAAW,UAAU;AAAA,QACrC,CAAE;AACF,wBAAgB;AAAA,MACjB;AASA,YAAM,YAAY,WAAY,MAAM,GAAI;AAExC,aAAO,MAAM;AACZ,oBAAY;AACZ,qBAAc,SAAU;AACxB,wBAAgB;AAAA,MACjB;AAAA,IACD;AAAA,IACA,CAAE,KAAK,OAAO,QAAQ,KAAM;AAAA,EAC7B;AAEA,SAAO,oBAAC,SAAI,KAAY,WAAU,sCAAqC;AACxE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// packages/block-library/src/utils/waveform-utils.js
|
|
2
|
+
import { colord } from "colord";
|
|
3
|
+
import WaveformPlayerLib from "@arraypress/waveform-player";
|
|
4
|
+
var DEFAULT_WAVEFORM_HEIGHT = 100;
|
|
5
|
+
function getComputedStyle(element) {
|
|
6
|
+
return element.ownerDocument.defaultView.getComputedStyle(element);
|
|
7
|
+
}
|
|
8
|
+
function getWaveformColors(element) {
|
|
9
|
+
const textColor = getComputedStyle(element).color;
|
|
10
|
+
const waveformColor = colord(textColor).alpha(0.3).toRgbString();
|
|
11
|
+
const progressColor = colord(textColor).alpha(0.6).toRgbString();
|
|
12
|
+
return { textColor, waveformColor, progressColor };
|
|
13
|
+
}
|
|
14
|
+
function createWaveformContainer({
|
|
15
|
+
url,
|
|
16
|
+
title,
|
|
17
|
+
artist,
|
|
18
|
+
artwork,
|
|
19
|
+
waveformColor,
|
|
20
|
+
progressColor,
|
|
21
|
+
buttonColor,
|
|
22
|
+
height = DEFAULT_WAVEFORM_HEIGHT
|
|
23
|
+
}) {
|
|
24
|
+
const container = document.createElement("div");
|
|
25
|
+
container.setAttribute("data-waveform-player", "");
|
|
26
|
+
container.setAttribute("data-url", url);
|
|
27
|
+
container.setAttribute("data-height", String(height));
|
|
28
|
+
container.setAttribute("data-waveform-style", "bars");
|
|
29
|
+
container.setAttribute("data-waveform-color", waveformColor);
|
|
30
|
+
container.setAttribute("data-progress-color", progressColor);
|
|
31
|
+
container.setAttribute("data-button-color", buttonColor);
|
|
32
|
+
container.setAttribute("data-text-color", buttonColor);
|
|
33
|
+
container.setAttribute("data-text-secondary-color", buttonColor);
|
|
34
|
+
if (title) {
|
|
35
|
+
container.setAttribute("data-title", title);
|
|
36
|
+
}
|
|
37
|
+
if (artist) {
|
|
38
|
+
container.setAttribute("data-subtitle", artist);
|
|
39
|
+
}
|
|
40
|
+
if (artwork) {
|
|
41
|
+
container.setAttribute("data-artwork", artwork);
|
|
42
|
+
}
|
|
43
|
+
return container;
|
|
44
|
+
}
|
|
45
|
+
function styleSvgIcons(container, buttonColor) {
|
|
46
|
+
const isButtonDark = colord(buttonColor).isDark();
|
|
47
|
+
const iconColor = isButtonDark ? "#ffffff" : "#000000";
|
|
48
|
+
const svgPaths = container.querySelectorAll("svg path");
|
|
49
|
+
svgPaths.forEach((path) => {
|
|
50
|
+
path.style.fill = iconColor;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function setupPlayButtonAccessibility(container, { play: playLabel = "Play", pause: pauseLabel = "Pause" } = {}) {
|
|
54
|
+
const playBtn = container.querySelector(".waveform-btn");
|
|
55
|
+
if (!playBtn) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
playBtn.setAttribute("aria-label", playLabel);
|
|
59
|
+
const onPlay = () => playBtn.setAttribute("aria-label", pauseLabel);
|
|
60
|
+
const onPause = () => playBtn.setAttribute("aria-label", playLabel);
|
|
61
|
+
container.addEventListener("waveformplayer:play", onPlay);
|
|
62
|
+
container.addEventListener("waveformplayer:pause", onPause);
|
|
63
|
+
container.addEventListener("waveformplayer:ended", onPause);
|
|
64
|
+
return () => {
|
|
65
|
+
container.removeEventListener("waveformplayer:play", onPlay);
|
|
66
|
+
container.removeEventListener("waveformplayer:pause", onPause);
|
|
67
|
+
container.removeEventListener("waveformplayer:ended", onPause);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function logPlayError(error) {
|
|
71
|
+
if (error.name === "AbortError") {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.error("Playlist play error:", error);
|
|
75
|
+
}
|
|
76
|
+
function initWaveformPlayer(element, { src, title, artist, image, autoPlay, onEnded, labels }) {
|
|
77
|
+
const { textColor, waveformColor, progressColor } = getWaveformColors(element);
|
|
78
|
+
const container = createWaveformContainer({
|
|
79
|
+
url: src,
|
|
80
|
+
title,
|
|
81
|
+
artist,
|
|
82
|
+
artwork: image,
|
|
83
|
+
waveformColor,
|
|
84
|
+
progressColor,
|
|
85
|
+
buttonColor: textColor
|
|
86
|
+
});
|
|
87
|
+
element.appendChild(container);
|
|
88
|
+
const instance = new WaveformPlayerLib(container);
|
|
89
|
+
let cleanupAccessibility;
|
|
90
|
+
const handlers = {
|
|
91
|
+
ready: () => {
|
|
92
|
+
styleSvgIcons(container, textColor);
|
|
93
|
+
cleanupAccessibility = setupPlayButtonAccessibility(
|
|
94
|
+
container,
|
|
95
|
+
labels
|
|
96
|
+
);
|
|
97
|
+
if (autoPlay) {
|
|
98
|
+
instance.play()?.catch(logPlayError);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
ended: () => onEnded?.()
|
|
102
|
+
};
|
|
103
|
+
container.addEventListener("waveformplayer:ready", handlers.ready);
|
|
104
|
+
container.addEventListener("waveformplayer:ended", handlers.ended);
|
|
105
|
+
return {
|
|
106
|
+
instance,
|
|
107
|
+
container,
|
|
108
|
+
destroy: () => {
|
|
109
|
+
cleanupAccessibility?.();
|
|
110
|
+
container.removeEventListener(
|
|
111
|
+
"waveformplayer:ready",
|
|
112
|
+
handlers.ready
|
|
113
|
+
);
|
|
114
|
+
container.removeEventListener(
|
|
115
|
+
"waveformplayer:ended",
|
|
116
|
+
handlers.ended
|
|
117
|
+
);
|
|
118
|
+
instance.destroy();
|
|
119
|
+
container.remove();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
createWaveformContainer,
|
|
125
|
+
getWaveformColors,
|
|
126
|
+
initWaveformPlayer,
|
|
127
|
+
logPlayError,
|
|
128
|
+
setupPlayButtonAccessibility,
|
|
129
|
+
styleSvgIcons
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=waveform-utils.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/waveform-utils.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared utilities for waveform audio player functionality.\n * Used by both the WaveformPlayer component (editor) and view.js (frontend).\n */\n\n/**\n * External dependencies\n */\nimport { colord } from 'colord';\nimport WaveformPlayerLib from '@arraypress/waveform-player';\n\n/**\n * Configuration constants.\n * Note: DEFAULT_WAVEFORM_HEIGHT should match $waveform-player-height in style.scss.\n */\nconst DEFAULT_WAVEFORM_HEIGHT = 100;\n\n/**\n * Get computed style for an element, using ownerDocument for iframe compatibility.\n *\n * @param {Element} element - The element to get styles from.\n * @return {CSSStyleDeclaration} The computed style.\n */\nfunction getComputedStyle( element ) {\n\treturn element.ownerDocument.defaultView.getComputedStyle( element );\n}\n\n/**\n * Get all colors needed for the waveform player based on the element's styles.\n *\n * @param {Element} element - The element to derive colors from.\n * @return {Object} Object containing textColor, waveformColor, progressColor.\n */\nexport function getWaveformColors( element ) {\n\tconst textColor = getComputedStyle( element ).color;\n\tconst waveformColor = colord( textColor ).alpha( 0.3 ).toRgbString();\n\tconst progressColor = colord( textColor ).alpha( 0.6 ).toRgbString();\n\n\treturn { textColor, waveformColor, progressColor };\n}\n\n/**\n * Create a waveform container element with the specified attributes.\n *\n * @param {Object} options - The options for the container.\n * @param {string} options.url - The audio URL.\n * @param {string} options.title - The track title.\n * @param {string} options.artist - The track artist.\n * @param {string} options.artwork - The album artwork URL.\n * @param {string} options.waveformColor - The waveform bar color.\n * @param {string} options.progressColor - The progress indicator color.\n * @param {string} options.buttonColor - The play button color.\n * @param {number} options.height - The waveform height in pixels.\n * @return {Element} The configured container element.\n */\nexport function createWaveformContainer( {\n\turl,\n\ttitle,\n\tartist,\n\tartwork,\n\twaveformColor,\n\tprogressColor,\n\tbuttonColor,\n\theight = DEFAULT_WAVEFORM_HEIGHT,\n} ) {\n\tconst container = document.createElement( 'div' );\n\tcontainer.setAttribute( 'data-waveform-player', '' );\n\tcontainer.setAttribute( 'data-url', url );\n\tcontainer.setAttribute( 'data-height', String( height ) );\n\tcontainer.setAttribute( 'data-waveform-style', 'bars' );\n\tcontainer.setAttribute( 'data-waveform-color', waveformColor );\n\tcontainer.setAttribute( 'data-progress-color', progressColor );\n\tcontainer.setAttribute( 'data-button-color', buttonColor );\n\tcontainer.setAttribute( 'data-text-color', buttonColor );\n\tcontainer.setAttribute( 'data-text-secondary-color', buttonColor );\n\tif ( title ) {\n\t\tcontainer.setAttribute( 'data-title', title );\n\t}\n\tif ( artist ) {\n\t\tcontainer.setAttribute( 'data-subtitle', artist );\n\t}\n\tif ( artwork ) {\n\t\tcontainer.setAttribute( 'data-artwork', artwork );\n\t}\n\treturn container;\n}\n\n/**\n * Apply contrasting color to SVG icon paths for visibility.\n * The icons should contrast with the button background (which uses textColor).\n *\n * @param {Element} container - The waveform container element.\n * @param {string} buttonColor - The button background color (textColor).\n */\nexport function styleSvgIcons( container, buttonColor ) {\n\t// Compute a contrasting color for the icons based on button brightness.\n\tconst isButtonDark = colord( buttonColor ).isDark();\n\tconst iconColor = isButtonDark ? '#ffffff' : '#000000';\n\n\tconst svgPaths = container.querySelectorAll( 'svg path' );\n\tsvgPaths.forEach( ( path ) => {\n\t\tpath.style.fill = iconColor;\n\t} );\n}\n\n/**\n * Set up play button accessibility: aria-label that toggles on play/pause.\n *\n * @param {Element} container - The waveform container element.\n * @param {Object} labels - Button labels.\n * @param {string} labels.play - Label for the play state.\n * @param {string} labels.pause - Label for the pause state.\n */\nexport function setupPlayButtonAccessibility(\n\tcontainer,\n\t{ play: playLabel = 'Play', pause: pauseLabel = 'Pause' } = {}\n) {\n\tconst playBtn = container.querySelector( '.waveform-btn' );\n\tif ( ! playBtn ) {\n\t\treturn;\n\t}\n\n\tplayBtn.setAttribute( 'aria-label', playLabel );\n\n\tconst onPlay = () => playBtn.setAttribute( 'aria-label', pauseLabel );\n\tconst onPause = () => playBtn.setAttribute( 'aria-label', playLabel );\n\n\tcontainer.addEventListener( 'waveformplayer:play', onPlay );\n\tcontainer.addEventListener( 'waveformplayer:pause', onPause );\n\tcontainer.addEventListener( 'waveformplayer:ended', onPause );\n\n\treturn () => {\n\t\tcontainer.removeEventListener( 'waveformplayer:play', onPlay );\n\t\tcontainer.removeEventListener( 'waveformplayer:pause', onPause );\n\t\tcontainer.removeEventListener( 'waveformplayer:ended', onPause );\n\t};\n}\n\n/**\n * Log play errors, filtering out expected AbortError.\n *\n * @param {Error} error - The error from play().\n */\nexport function logPlayError( error ) {\n\t// The browser throws AbortError when a play() promise is interrupted\n\t// by a subsequent pause() or a new audio source load (track change).\n\t// This is normal during rapid user interaction and safe to ignore.\n\tif ( error.name === 'AbortError' ) {\n\t\treturn;\n\t}\n\t// eslint-disable-next-line no-console\n\tconsole.error( 'Playlist play error:', error );\n}\n\n/**\n * Initialize a WaveformPlayer instance on an element.\n *\n * This is the shared core logic used by both the React component (editor)\n * and the Interactivity API (frontend).\n *\n * @param {Element} element - The container element (must be in DOM).\n * @param {Object} options - Configuration options.\n * @param {string} options.src - The audio file URL.\n * @param {string} options.title - The track title.\n * @param {string} options.artist - The artist name.\n * @param {string} options.image - The artwork image URL.\n * @param {boolean} options.autoPlay - Whether to auto-play when ready.\n * @param {Function} options.onEnded - Callback when track ends.\n * @param {Object} options.labels - Translated button labels.\n * @return {Object} Object with instance, container, and destroy function.\n */\nexport function initWaveformPlayer(\n\telement,\n\t{ src, title, artist, image, autoPlay, onEnded, labels }\n) {\n\t// Get colors from computed styles.\n\tconst { textColor, waveformColor, progressColor } =\n\t\tgetWaveformColors( element );\n\n\t// Create the waveform container.\n\tconst container = createWaveformContainer( {\n\t\turl: src,\n\t\ttitle,\n\t\tartist,\n\t\tartwork: image,\n\t\twaveformColor,\n\t\tprogressColor,\n\t\tbuttonColor: textColor,\n\t} );\n\telement.appendChild( container );\n\n\t// Initialize the WaveformPlayer library.\n\tconst instance = new WaveformPlayerLib( container );\n\n\t// Set up event handlers.\n\tlet cleanupAccessibility;\n\tconst handlers = {\n\t\tready: () => {\n\t\t\tstyleSvgIcons( container, textColor );\n\t\t\tcleanupAccessibility = setupPlayButtonAccessibility(\n\t\t\t\tcontainer,\n\t\t\t\tlabels\n\t\t\t);\n\t\t\tif ( autoPlay ) {\n\t\t\t\tinstance.play()?.catch( logPlayError );\n\t\t\t}\n\t\t},\n\t\tended: () => onEnded?.(),\n\t};\n\n\tcontainer.addEventListener( 'waveformplayer:ready', handlers.ready );\n\tcontainer.addEventListener( 'waveformplayer:ended', handlers.ended );\n\n\t// Return instance, container, and cleanup function.\n\treturn {\n\t\tinstance,\n\t\tcontainer,\n\t\tdestroy: () => {\n\t\t\tcleanupAccessibility?.();\n\t\t\tcontainer.removeEventListener(\n\t\t\t\t'waveformplayer:ready',\n\t\t\t\thandlers.ready\n\t\t\t);\n\t\t\tcontainer.removeEventListener(\n\t\t\t\t'waveformplayer:ended',\n\t\t\t\thandlers.ended\n\t\t\t);\n\t\t\tinstance.destroy();\n\t\t\tcontainer.remove();\n\t\t},\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
.wp-block-buttons > .wp-block-button.has-custom-font-size .wp-block-button__link {
|
|
35
35
|
font-size: inherit;
|
|
36
36
|
}
|
|
37
|
+
.wp-block-buttons > .wp-block-button[class*=wp-block-button__width] {
|
|
38
|
+
width: calc(var(--wp--block-button--width) * 1% - var(--wp--style--block-gap, 0.5em) * (1 - var(--wp--block-button--width) / 100));
|
|
39
|
+
}
|
|
37
40
|
.wp-block-buttons > .wp-block-button.wp-block-button__width-25 {
|
|
38
41
|
width: calc(25% - var(--wp--style--block-gap, 0.5em) * 0.75);
|
|
39
42
|
}
|
|
@@ -48,6 +51,9 @@
|
|
|
48
51
|
flex-basis: 100%;
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
.wp-block-buttons.is-vertical > .wp-block-button[class*=wp-block-button__width] {
|
|
55
|
+
width: calc(var(--wp--block-button--width) * 1%);
|
|
56
|
+
}
|
|
51
57
|
.wp-block-buttons.is-vertical > .wp-block-button.wp-block-button__width-25 {
|
|
52
58
|
width: 25%;
|
|
53
59
|
}
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
.wp-block-buttons > .wp-block-button.has-custom-font-size .wp-block-button__link {
|
|
36
36
|
font-size: inherit;
|
|
37
37
|
}
|
|
38
|
+
.wp-block-buttons > .wp-block-button[class*=wp-block-button__width] {
|
|
39
|
+
width: calc(var(--wp--block-button--width) * 1% - var(--wp--style--block-gap, 0.5em) * (1 - var(--wp--block-button--width) / 100));
|
|
40
|
+
}
|
|
38
41
|
.wp-block-buttons > .wp-block-button.wp-block-button__width-25 {
|
|
39
42
|
width: calc(25% - var(--wp--style--block-gap, 0.5em) * 0.75);
|
|
40
43
|
}
|
|
@@ -49,6 +52,9 @@
|
|
|
49
52
|
flex-basis: 100%;
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
.wp-block-buttons.is-vertical > .wp-block-button[class*=wp-block-button__width] {
|
|
56
|
+
width: calc(var(--wp--block-button--width) * 1%);
|
|
57
|
+
}
|
|
52
58
|
.wp-block-buttons.is-vertical > .wp-block-button.wp-block-button__width-25 {
|
|
53
59
|
width: 25%;
|
|
54
60
|
}
|
|
@@ -1963,9 +1963,9 @@ html[dir=rtl] .has-drop-cap:not(:focus)::first-letter {
|
|
|
1963
1963
|
padding: 16px;
|
|
1964
1964
|
}
|
|
1965
1965
|
|
|
1966
|
-
.wp-block-playlist.
|
|
1967
|
-
|
|
1968
|
-
|
|
1966
|
+
.wp-block-playlist li.block-list-appender.block-list-appender {
|
|
1967
|
+
position: initial;
|
|
1968
|
+
margin-top: var(--wp--preset--spacing--30, 1em);
|
|
1969
1969
|
}
|
|
1970
1970
|
|
|
1971
1971
|
.wp-block-post-excerpt .wp-block-post-excerpt__excerpt.is-inline {
|
package/build-style/editor.css
CHANGED
|
@@ -1967,9 +1967,9 @@ html[dir=rtl] .has-drop-cap:not(:focus)::first-letter {
|
|
|
1967
1967
|
padding: 16px;
|
|
1968
1968
|
}
|
|
1969
1969
|
|
|
1970
|
-
.wp-block-playlist.
|
|
1971
|
-
|
|
1972
|
-
|
|
1970
|
+
.wp-block-playlist li.block-list-appender.block-list-appender {
|
|
1971
|
+
position: initial;
|
|
1972
|
+
margin-top: var(--wp--preset--spacing--30, 1em);
|
|
1973
1973
|
}
|
|
1974
1974
|
|
|
1975
1975
|
.wp-block-post-excerpt .wp-block-post-excerpt__excerpt.is-inline {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.wp-block-playlist.
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
.wp-block-playlist li.block-list-appender.block-list-appender {
|
|
2
|
+
position: initial;
|
|
3
|
+
margin-top: var(--wp--preset--spacing--30, 1em);
|
|
4
4
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.wp-block-playlist.
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
.wp-block-playlist li.block-list-appender.block-list-appender {
|
|
2
|
+
position: initial;
|
|
3
|
+
margin-top: var(--wp--preset--spacing--30, 1em);
|
|
4
4
|
}
|