UNPKG

@wordpress/block-library

Version:
8 lines (7 loc) 28.4 kB
{ "version": 3, "sources": ["../../src/utils/waveform-utils.js"], "sourcesContent": ["/**\n * Shared utilities for waveform audio player functionality.\n * Used by both the WaveformPlayer component (editor) and view.js (frontend).\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;\nconst DEFAULT_SEEK_LABEL = 'Seek';\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\nfunction getTopLevelGradientParts( gradientValue ) {\n\tconst match = gradientValue?.trim().match( /^[\\w-]+-gradient\\((.*)\\)$/i );\n\tif ( ! match ) {\n\t\treturn [];\n\t}\n\n\tconst parts = [];\n\tlet depth = 0;\n\tlet current = '';\n\n\tfor ( const character of match[ 1 ] ) {\n\t\tif ( character === '(' ) {\n\t\t\t++depth;\n\t\t} else if ( character === ')' ) {\n\t\t\t--depth;\n\t\t}\n\n\t\tif ( character === ',' && depth === 0 ) {\n\t\t\tparts.push( current.trim() );\n\t\t\tcurrent = '';\n\t\t\tcontinue;\n\t\t}\n\n\t\tcurrent += character;\n\t}\n\n\tif ( current.trim() ) {\n\t\tparts.push( current.trim() );\n\t}\n\n\treturn parts;\n}\n\nfunction getLeadingColorFunction( value ) {\n\tconst match = value.match( /^([\\w-]+)\\(/ );\n\tif ( ! match ) {\n\t\treturn;\n\t}\n\n\tconst supportedFunctions = [\n\t\t'color',\n\t\t'color-mix',\n\t\t'hsl',\n\t\t'hsla',\n\t\t'hwb',\n\t\t'lab',\n\t\t'lch',\n\t\t'oklab',\n\t\t'oklch',\n\t\t'rgb',\n\t\t'rgba',\n\t\t'var',\n\t];\n\tif ( ! supportedFunctions.includes( match[ 1 ].toLowerCase() ) ) {\n\t\treturn;\n\t}\n\n\tlet depth = 0;\n\tlet foundOpeningParenthesis = false;\n\tfor ( let index = 0; index < value.length; index++ ) {\n\t\tconst character = value[ index ];\n\t\tif ( character === '(' ) {\n\t\t\tfoundOpeningParenthesis = true;\n\t\t\t++depth;\n\t\t} else if ( character === ')' ) {\n\t\t\t--depth;\n\t\t}\n\n\t\tif ( foundOpeningParenthesis && depth === 0 ) {\n\t\t\treturn value.slice( 0, index + 1 );\n\t\t}\n\t}\n}\n\nfunction getColorStopValue( gradientPart ) {\n\tconst colorFunction = getLeadingColorFunction( gradientPart );\n\tif ( colorFunction ) {\n\t\treturn colorFunction;\n\t}\n\n\tconst [ possibleColor ] = gradientPart.split( /\\s+/ );\n\tif ( colord( possibleColor ).isValid() ) {\n\t\treturn possibleColor;\n\t}\n}\n\nfunction getWaveformGradientDirection( gradientValue ) {\n\tconst parts = getTopLevelGradientParts( gradientValue );\n\tconst direction = parts[ 0 ];\n\tconst angleMatch = direction?.match( /^(-?\\d+(?:\\.\\d+)?)deg$/i );\n\tif ( angleMatch ) {\n\t\tconst angle = ( ( Number( angleMatch[ 1 ] ) % 360 ) + 360 ) % 360;\n\t\tif ( angle === 90 || angle === 270 ) {\n\t\t\treturn 'horizontal';\n\t\t}\n\t\tif ( angle === 0 || angle === 180 ) {\n\t\t\treturn 'vertical';\n\t\t}\n\t\treturn 'diagonal';\n\t}\n\n\tif ( ! direction?.startsWith( 'to ' ) ) {\n\t\treturn undefined;\n\t}\n\n\tconst sideOrCorner = direction.toLowerCase().replace( /^to\\s+/, '' );\n\tconst hasHorizontalSide =\n\t\tsideOrCorner.includes( 'left' ) || sideOrCorner.includes( 'right' );\n\tconst hasVerticalSide =\n\t\tsideOrCorner.includes( 'top' ) || sideOrCorner.includes( 'bottom' );\n\n\tif ( hasHorizontalSide && hasVerticalSide ) {\n\t\treturn 'diagonal';\n\t}\n\tif ( hasHorizontalSide ) {\n\t\treturn 'horizontal';\n\t}\n\tif ( hasVerticalSide ) {\n\t\treturn 'vertical';\n\t}\n}\n\nfunction resolveColorValue( element, colorValue ) {\n\tif ( ! colorValue || colord( colorValue ).isValid() ) {\n\t\treturn colorValue;\n\t}\n\n\tconst colorResolver = element.ownerDocument.createElement( 'span' );\n\tcolorResolver.style.color = colorValue;\n\tif ( ! colorResolver.style.color ) {\n\t\treturn colorValue;\n\t}\n\telement.appendChild( colorResolver );\n\n\tconst resolvedColor = getComputedStyle( colorResolver ).color;\n\tcolorResolver.remove();\n\n\treturn resolvedColor && colord( resolvedColor ).isValid()\n\t\t? resolvedColor\n\t\t: colorValue;\n}\n\nfunction getResolvedGradientStops( element, gradientValue ) {\n\tconst stops = getWaveformGradientStops( gradientValue )\n\t\t?.map( ( colorValue ) => resolveColorValue( element, colorValue ) )\n\t\t.filter( ( colorValue ) => colord( colorValue ).isValid() );\n\n\treturn stops?.length > 1 ? stops : undefined;\n}\n\nfunction applyAlpha( colorValue, alpha ) {\n\tif ( Array.isArray( colorValue ) ) {\n\t\treturn colorValue.map( ( color ) =>\n\t\t\tcolord( color ).alpha( alpha ).toRgbString()\n\t\t);\n\t}\n\treturn colord( colorValue ).alpha( alpha ).toRgbString();\n}\n\nfunction getRepresentativeColor( colorValue ) {\n\tif ( Array.isArray( colorValue ) ) {\n\t\treturn colorValue[ colorValue.length - 1 ];\n\t}\n\treturn colorValue;\n}\n\nexport function getWaveformGradientStops( gradientValue ) {\n\tconst stops = getTopLevelGradientParts( gradientValue )\n\t\t.map( getColorStopValue )\n\t\t.filter( Boolean );\n\n\treturn stops.length > 1 ? stops : undefined;\n}\n\nfunction serializeColorValue( colorValue ) {\n\treturn Array.isArray( colorValue )\n\t\t? JSON.stringify( colorValue )\n\t\t: colorValue;\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 * @param {string} waveformColorValue - The base waveform color value to use.\n * @param {string} textColorValue - The text color value to use.\n * @param {string} waveformGradientValue - The waveform gradient value to use.\n * @return {Object} Object containing textColor, waveformColor, progressColor.\n */\nexport function getWaveformColors(\n\telement,\n\twaveformColorValue,\n\ttextColorValue,\n\twaveformGradientValue\n) {\n\tconst textColor = textColorValue || getComputedStyle( element ).color;\n\tconst waveformGradientStops = getResolvedGradientStops(\n\t\telement,\n\t\twaveformGradientValue\n\t);\n\tconst waveformBaseColor =\n\t\twaveformGradientStops || waveformColorValue || textColor;\n\tconst waveformColor = applyAlpha( waveformBaseColor, 0.3 );\n\tconst progressColor = applyAlpha( waveformBaseColor, 0.6 );\n\tconst waveformGradient = waveformGradientStops\n\t\t? getWaveformGradientDirection( waveformGradientValue )\n\t\t: undefined;\n\n\treturn {\n\t\ttextColor,\n\t\twaveformColor,\n\t\tprogressColor,\n\t\t...( waveformGradient && { waveformGradient } ),\n\t};\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 track image URL.\n * @param {string} options.waveformColor - The waveform bar color.\n * @param {string} options.progressColor - The progress indicator color.\n * @param {string} options.waveformGradient - The waveform gradient direction.\n * @param {string} options.buttonColor - The play button color.\n * @param {string} options.seekLabel - Accessible label for the seek control.\n * @param {string} options.seekValueText - Accessible value-text template for the seek control (e.g. '%1$s of %2$s').\n * @param {number} options.height - The waveform height in pixels.\n * @param {string} options.waveformStyle - The visualization style (bars, mirror, line, blocks, dots, seekbar).\n * @return {Element} The configured container element.\n */\nexport function createWaveformContainer( {\n\turl,\n\ttitle,\n\tartist,\n\tartwork,\n\twaveformColor,\n\tprogressColor,\n\twaveformGradient,\n\tbuttonColor,\n\tseekLabel,\n\tseekValueText,\n\theight = DEFAULT_WAVEFORM_HEIGHT,\n\twaveformStyle = 'bars',\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', waveformStyle );\n\tcontainer.setAttribute(\n\t\t'data-waveform-color',\n\t\tserializeColorValue( waveformColor )\n\t);\n\tcontainer.setAttribute(\n\t\t'data-progress-color',\n\t\tserializeColorValue( progressColor )\n\t);\n\tif ( waveformGradient ) {\n\t\tcontainer.setAttribute( 'data-waveform-gradient', waveformGradient );\n\t}\n\tcontainer.setAttribute( 'data-button-color', buttonColor );\n\tcontainer.setAttribute(\n\t\t'data-seek-label',\n\t\tgetSeekControlLabel( seekLabel )\n\t);\n\t// The library formats the current time and duration and interpolates them\n\t// into this translated template for the seek slider's aria-valuetext.\n\tif ( seekValueText ) {\n\t\tcontainer.setAttribute( 'data-seek-value-text', seekValueText );\n\t}\n\tcontainer.setAttribute( 'data-text-color', buttonColor );\n\tcontainer.setAttribute( 'data-text-secondary-color', buttonColor );\n\n\tif ( title ) {\n\t\tcontainer.setAttribute( 'data-title', title );\n\t}\n\tif ( artist ) {\n\t\tcontainer.setAttribute( 'data-artist', artist );\n\t}\n\tif ( artwork ) {\n\t\tcontainer.setAttribute( 'data-artwork', artwork );\n\t}\n\treturn container;\n}\n\n/**\n * Apply custom styles to a generated waveform player.\n *\n * @param {Element} container - The generated player container.\n * @param {Object} styles - The player styles.\n * @param {string} styles.backgroundColor - The waveform area background color.\n * @param {string} styles.backgroundGradient - The waveform area background gradient.\n * @param {string} styles.textColor - The player text color.\n * @param {string} styles.playButtonColor - The play button color.\n * @param {string} styles.playButtonGradient - The play button gradient.\n */\nexport function applyWaveformPlayerStyles(\n\tcontainer,\n\t{\n\t\tbackgroundColor,\n\t\tbackgroundGradient,\n\t\ttextColor,\n\t\tplayButtonColor,\n\t\tplayButtonGradient,\n\t} = {}\n) {\n\tconst waveformContainer = container.querySelector( '.waveform-container' );\n\tconst playButton = container.querySelector( '.waveform-btn' );\n\tconst playButtonBaseColor = getRepresentativeColor(\n\t\tgetResolvedGradientStops( container, playButtonGradient ) ||\n\t\t\tplayButtonColor\n\t);\n\n\tif ( playButtonBaseColor ) {\n\t\tcontainer.style.setProperty(\n\t\t\t'--wfp-button-color',\n\t\t\tplayButtonBaseColor\n\t\t);\n\t} else {\n\t\tcontainer.style.removeProperty( '--wfp-button-color' );\n\t}\n\n\tif ( textColor ) {\n\t\tcontainer.style.setProperty( '--wfp-text-color', textColor );\n\t\tcontainer.style.setProperty( '--wfp-text-secondary-color', textColor );\n\t} else {\n\t\tcontainer.style.removeProperty( '--wfp-text-color' );\n\t\tcontainer.style.removeProperty( '--wfp-text-secondary-color' );\n\t}\n\n\tif ( playButton ) {\n\t\tif ( playButtonGradient ) {\n\t\t\tplayButton.style.background = playButtonGradient;\n\t\t} else {\n\t\t\tplayButton.style.removeProperty( 'background' );\n\t\t}\n\t}\n\n\tif ( waveformContainer ) {\n\t\tif ( backgroundGradient ) {\n\t\t\twaveformContainer.style.background = backgroundGradient;\n\t\t} else if ( backgroundColor ) {\n\t\t\twaveformContainer.style.removeProperty( 'background' );\n\t\t\twaveformContainer.style.backgroundColor = backgroundColor;\n\t\t} else {\n\t\t\twaveformContainer.style.removeProperty( 'background' );\n\t\t\twaveformContainer.style.removeProperty( 'background-color' );\n\t\t}\n\t}\n}\n\n/**\n * Apply contrasting color to SVG icon paths for visibility.\n * The icons should contrast with the button background.\n *\n * @param {Element} container - The waveform container element.\n * @param {string} buttonColor - The button background color.\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 * Get the accessible label for the waveform seek control.\n *\n * @param {string} label - Accessible label for the seek control.\n * @return {string} The provided label or translated fallback.\n */\nfunction getSeekControlLabel( label ) {\n\treturn label || DEFAULT_SEEK_LABEL;\n}\n\n/**\n * Update the waveform seek control label.\n *\n * @param {Object} instance - The WaveformPlayer instance.\n * @param {string} label - Accessible label for the seek control.\n */\nexport function updateSeekControlLabel( instance, label ) {\n\tconst seekLabel = getSeekControlLabel( label );\n\tinstance.options.seekLabel = seekLabel;\n\tinstance.applySeekLabel?.( seekLabel );\n\n\tconst seekControl = instance?.container?.querySelector(\n\t\t'.waveform-container'\n\t);\n\n\tif ( seekControl ) {\n\t\tseekControl.setAttribute( 'aria-label', seekLabel );\n\t}\n}\n\n/**\n * Show the current artwork as the play button background.\n *\n * @param {Element} container - The waveform player container element.\n * @param {string} artworkUrl - The track image URL.\n */\nexport function setupPlayButtonArtwork( container, artworkUrl ) {\n\tif ( ! artworkUrl ) {\n\t\tcontainer.classList.remove( 'has-play-button-artwork' );\n\t\tcontainer.style.removeProperty( '--wp--playlist--play-button-artwork' );\n\t\treturn;\n\t}\n\n\tcontainer.classList.add( 'has-play-button-artwork' );\n\tcontainer.style.setProperty(\n\t\t'--wp--playlist--play-button-artwork',\n\t\t`url(${ JSON.stringify( artworkUrl ) })`\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 track image URL.\n * @param {string} options.imageAlt - The track image alt text.\n * @param {string} options.waveformColor - The waveform color.\n * @param {string} options.waveformGradient - The waveform gradient.\n * @param {string} options.textColor - The player text color.\n * @param {string} options.backgroundColor - The player background color.\n * @param {string} options.backgroundGradient - The player background gradient.\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 * @param {string} options.waveformStyle - Waveform style (bars, mirror, line, blocks, dots, seekbar).\n * @param {boolean} options.showPlayButtonArtwork - Whether to show artwork on the play button.\n * @return {Object} Object with instance, container, and destroy function.\n */\nexport function initWaveformPlayer(\n\telement,\n\t{\n\t\tsrc,\n\t\ttitle,\n\t\tartist,\n\t\timage,\n\t\timageAlt,\n\t\twaveformColor: waveformColorValue,\n\t\twaveformGradient: waveformGradientValue,\n\t\ttextColor: textColorValue,\n\t\tbackgroundColor,\n\t\tbackgroundGradient,\n\t\tautoPlay,\n\t\tonEnded,\n\t\tlabels,\n\t\twaveformStyle,\n\t\tshowPlayButtonArtwork = false,\n\t}\n) {\n\tconst playerArtwork = showPlayButtonArtwork ? undefined : image;\n\n\t// Get colors from computed styles.\n\tconst { textColor, waveformColor, progressColor, waveformGradient } =\n\t\tgetWaveformColors(\n\t\t\telement,\n\t\t\twaveformColorValue,\n\t\t\ttextColorValue,\n\t\t\twaveformGradientValue\n\t\t);\n\tconst waveformGradientStops = getResolvedGradientStops(\n\t\telement,\n\t\twaveformGradientValue\n\t);\n\tconst waveformButtonColor = getRepresentativeColor(\n\t\twaveformGradientStops || waveformColorValue\n\t);\n\n\t// Create the waveform container.\n\tconst container = createWaveformContainer( {\n\t\turl: src,\n\t\ttitle,\n\t\tartist,\n\t\tartwork: playerArtwork,\n\t\twaveformColor,\n\t\tprogressColor,\n\t\twaveformGradient,\n\t\tbuttonColor: textColor,\n\t\tseekLabel: title || labels?.seek,\n\t\tseekValueText: labels?.seekValueText,\n\t\twaveformStyle,\n\t} );\n\telement.appendChild( container );\n\n\t// Initialize the WaveformPlayer library. The library reads the translated\n\t// seek label and value-text templates from the container's data attributes\n\t// and owns the seek slider's accessible label and value text.\n\tconst instance = new WaveformPlayerLib( container );\n\tif ( instance.artworkEl ) {\n\t\tinstance.artworkEl.alt = imageAlt || '';\n\t}\n\tapplyWaveformPlayerStyles( container, {\n\t\tbackgroundColor,\n\t\tbackgroundGradient,\n\t\ttextColor,\n\t\tplayButtonColor: showPlayButtonArtwork\n\t\t\t? undefined\n\t\t\t: waveformButtonColor,\n\t\tplayButtonGradient: showPlayButtonArtwork\n\t\t\t? undefined\n\t\t\t: waveformGradientValue,\n\t} );\n\n\t// Set up event handlers.\n\tlet cleanupPlayButtonAccessibility;\n\tconst handlers = {\n\t\tready: () => {\n\t\t\tstyleSvgIcons( container, waveformButtonColor || textColor );\n\t\t\tif ( showPlayButtonArtwork ) {\n\t\t\t\tsetupPlayButtonArtwork( container, image );\n\t\t\t}\n\t\t\tcleanupPlayButtonAccessibility = 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\tcleanupPlayButtonAccessibility?.();\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"], "mappings": "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", "names": ["WaveformPlayerLib"] }