@arraypress/waveform-player-react 0.2.0 → 0.3.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/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ function buildLibraryOptions(props) {
42
42
  if (props.buttonAlign !== void 0) opts.buttonAlign = props.buttonAlign;
43
43
  if (props.layout !== void 0) opts.layout = props.layout;
44
44
  if (props.buttonStyle !== void 0) opts.buttonStyle = props.buttonStyle;
45
+ if (props.buttonSize !== void 0) opts.buttonSize = props.buttonSize;
45
46
  if (props.accessibleSeek !== void 0) opts.accessibleSeek = props.accessibleSeek;
46
47
  if (props.seekLabel !== void 0) opts.seekLabel = props.seekLabel;
47
48
  if (props.errorText !== void 0) opts.errorText = props.errorText;
@@ -149,6 +150,7 @@ var WaveformPlayer = react.forwardRef(
149
150
  props.showHoverTime,
150
151
  props.showBPM,
151
152
  props.buttonAlign,
153
+ props.buttonSize,
152
154
  props.accessibleSeek,
153
155
  props.seekLabel,
154
156
  props.errorText,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/WaveformPlayer.tsx"],"names":["forwardRef","WaveformPlayer","useRef","useLayoutEffect","useEffect","useImperativeHandle","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * WaveformPlayer.tsx\n * ------------------\n *\n * React wrapper around `@arraypress/waveform-player`. Mounts a player\n * instance into a `<div>` on first render, tears it down on unmount,\n * and re-mounts when any \"identity\" prop changes (the props whose\n * change requires the library to start over from scratch — `url`,\n * `audioMode`).\n *\n * For non-identity props, this component currently re-creates the\n * instance as well, which is simpler than diffing every option and\n * calling the right granular updater. The trade-off is acceptable\n * because:\n *\n * - The library re-uses any cached waveform data keyed by URL, so\n * re-mounts on the same URL are cheap.\n * - Per-render churn on a player widget is rare in practice.\n *\n * If you need finer control — imperative `loadTrack()`, `seekTo()`,\n * `setVolume()`, etc. — grab the instance through a `ref`:\n *\n * ```tsx\n * import { useRef, useEffect } from 'react';\n * import { WaveformPlayer, type WaveformPlayerHandle } from '@arraypress/waveform-player-react';\n *\n * function MyPlayer() {\n * const ref = useRef<WaveformPlayerHandle>(null);\n * return (\n * <>\n * <WaveformPlayer ref={ref} url=\"/audio/track.mp3\" />\n * <button onClick={() => ref.current?.seekTo(60)}>Jump to 1:00</button>\n * </>\n * );\n * }\n * ```\n *\n * ## Library setup\n *\n * This component does **not** load the core library's CSS for you.\n * Import it once at your app entry:\n *\n * ```ts\n * import '@arraypress/waveform-player/dist/waveform-player.css';\n * ```\n *\n * The library's JS is imported dynamically inside `useEffect` so it\n * only loads on the client (SSR-safe).\n *\n * @module WaveformPlayer\n */\nimport {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseRef,\n\ttype ForwardedRef,\n} from 'react';\n// Aliased to avoid colliding with this file's own `WaveformPlayer`\n// component export. This is the core library's player class type.\nimport type { WaveformPlayer as WaveformPlayerInstance } from '@arraypress/waveform-player';\nimport type { WaveformPlayerHandle, WaveformPlayerProps } from './types';\n\n/**\n * Convert a `WaveformPlayerProps` object into the option shape the\n * core library accepts. Most fields pass straight through; this\n * helper exists so the option-building logic is testable on its own\n * and the component body stays focused on lifecycle.\n *\n * @param props - The component's resolved props.\n * @returns An options object to pass into `new WaveformPlayer(el, …)`.\n */\nfunction buildLibraryOptions(props: WaveformPlayerProps): Record<string, unknown> {\n\tconst opts: Record<string, unknown> = {};\n\n\t/* Audio source — `src` is the core's shorthand alias for `url`. */\n\tif (props.url !== undefined) opts.url = props.url;\n\telse if (props.src !== undefined) opts.url = props.src;\n\tif (props.audioMode !== undefined) opts.audioMode = props.audioMode;\n\tif (props.preload !== undefined) opts.preload = props.preload;\n\n\t/* Waveform visualisation */\n\tif (props.waveformStyle !== undefined) opts.waveformStyle = props.waveformStyle;\n\tif (props.height !== undefined) opts.height = props.height;\n\tif (props.samples !== undefined) opts.samples = props.samples;\n\tif (props.barWidth !== undefined) opts.barWidth = props.barWidth;\n\tif (props.barSpacing !== undefined) opts.barSpacing = props.barSpacing;\n\tif (props.barRadius !== undefined) opts.barRadius = props.barRadius;\n\tif (props.waveform !== undefined && props.waveform !== null) {\n\t\topts.waveform = props.waveform;\n\t}\n\n\t/* Colours */\n\tif (props.colorPreset !== undefined) opts.colorPreset = props.colorPreset;\n\tif (props.waveformColor !== undefined) opts.waveformColor = props.waveformColor;\n\tif (props.progressColor !== undefined) opts.progressColor = props.progressColor;\n\tif (props.buttonColor !== undefined) opts.buttonColor = props.buttonColor;\n\tif (props.buttonHoverColor !== undefined) opts.buttonHoverColor = props.buttonHoverColor;\n\tif (props.textColor !== undefined) opts.textColor = props.textColor;\n\tif (props.textSecondaryColor !== undefined) opts.textSecondaryColor = props.textSecondaryColor;\n\tif (props.backgroundColor !== undefined) opts.backgroundColor = props.backgroundColor;\n\tif (props.borderColor !== undefined) opts.borderColor = props.borderColor;\n\n\t/* Playback controls */\n\tif (props.playbackRate !== undefined) opts.playbackRate = props.playbackRate;\n\tif (props.showPlaybackSpeed !== undefined) opts.showPlaybackSpeed = props.showPlaybackSpeed;\n\tif (props.playbackRates !== undefined) opts.playbackRates = props.playbackRates;\n\n\t/* UI toggles */\n\tif (props.showControls !== undefined) opts.showControls = props.showControls;\n\tif (props.showInfo !== undefined) opts.showInfo = props.showInfo;\n\tif (props.showTime !== undefined) opts.showTime = props.showTime;\n\tif (props.showHoverTime !== undefined) opts.showHoverTime = props.showHoverTime;\n\tif (props.showBPM !== undefined) opts.showBPM = props.showBPM;\n\tif (props.bpm !== undefined) opts.bpm = props.bpm;\n\tif (props.buttonAlign !== undefined) opts.buttonAlign = props.buttonAlign;\n\tif (props.layout !== undefined) opts.layout = props.layout;\n\tif (props.buttonStyle !== undefined) opts.buttonStyle = props.buttonStyle;\n\n\t/* Accessibility */\n\tif (props.accessibleSeek !== undefined) opts.accessibleSeek = props.accessibleSeek;\n\tif (props.seekLabel !== undefined) opts.seekLabel = props.seekLabel;\n\n\t/* Error UI */\n\tif (props.errorText !== undefined) opts.errorText = props.errorText;\n\n\t/* Markers */\n\tif (props.markers !== undefined) opts.markers = props.markers;\n\tif (props.showMarkers !== undefined) opts.showMarkers = props.showMarkers;\n\n\t/* Content metadata */\n\tif (props.title !== undefined) opts.title = props.title;\n\tif (props.subtitle !== undefined) opts.subtitle = props.subtitle;\n\tif (props.artwork !== undefined) opts.artwork = props.artwork;\n\tif (props.album !== undefined) opts.album = props.album;\n\n\t/* Behaviour */\n\tif (props.autoplay !== undefined) opts.autoplay = props.autoplay;\n\tif (props.singlePlay !== undefined) opts.singlePlay = props.singlePlay;\n\tif (props.playOnSeek !== undefined) opts.playOnSeek = props.playOnSeek;\n\tif (props.enableMediaSession !== undefined) opts.enableMediaSession = props.enableMediaSession;\n\n\t/* Icons */\n\tif (props.playIcon !== undefined) opts.playIcon = props.playIcon;\n\tif (props.pauseIcon !== undefined) opts.pauseIcon = props.pauseIcon;\n\n\t/* Callbacks are intentionally NOT mapped here. They are wired in\n\t * the mount effect as *stable* wrapper functions that read the\n\t * latest handlers from `callbacksRef` at call time. That way a\n\t * parent re-render passing fresh inline callbacks is always seen\n\t * by the core without re-creating the player — and the callbacks\n\t * never capture stale first-mount state (stale-closure bug). */\n\n\treturn opts;\n}\n\n/**\n * `WaveformPlayer` — React component wrapping\n * `@arraypress/waveform-player`.\n *\n * Render at the spot you want a waveform-driven audio player to\n * appear. The container `<div>` is rendered immediately for layout;\n * the actual player UI hydrates in once the library loads\n * client-side.\n *\n * @example Basic\n * <WaveformPlayer url=\"/audio/track.mp3\" title=\"My Track\" />\n *\n * @example With ref for imperative control\n * const ref = useRef<WaveformPlayerHandle>(null);\n * <WaveformPlayer ref={ref} url={url} />\n * <button onClick={() => ref.current?.togglePlay()}>Play/Pause</button>\n */\nexport const WaveformPlayer = forwardRef<WaveformPlayerHandle, WaveformPlayerProps>(\n\tfunction WaveformPlayer(props, ref: ForwardedRef<WaveformPlayerHandle>) {\n\t\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\t\tconst instanceRef = useRef<unknown>(null);\n\n\t\t/**\n\t\t * Latest user callbacks, kept in a ref so the wrappers handed to\n\t\t * the core (built once at mount, below) always invoke the most\n\t\t * recent handler instead of the ones captured on first mount.\n\t\t *\n\t\t * Initialised from this render's props and refreshed every render\n\t\t * by the layout effect underneath — never listed in the mount\n\t\t * effect's deps, so updating a callback does NOT tear the player\n\t\t * down.\n\t\t */\n\t\tconst callbacksRef = useRef<\n\t\t\tPick<\n\t\t\t\tWaveformPlayerProps,\n\t\t\t\t'onLoad' | 'onPlay' | 'onPause' | 'onEnd' | 'onTimeUpdate' | 'onError'\n\t\t\t>\n\t\t>({\n\t\t\tonLoad: props.onLoad,\n\t\t\tonPlay: props.onPlay,\n\t\t\tonPause: props.onPause,\n\t\t\tonEnd: props.onEnd,\n\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\tonError: props.onError,\n\t\t});\n\n\t\t/* Refresh the ref on every render (before paint) so the stable\n\t\t * wrappers below always read the latest handlers. */\n\t\tuseLayoutEffect(() => {\n\t\t\tcallbacksRef.current = {\n\t\t\t\tonLoad: props.onLoad,\n\t\t\t\tonPlay: props.onPlay,\n\t\t\t\tonPause: props.onPause,\n\t\t\t\tonEnd: props.onEnd,\n\t\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\t\tonError: props.onError,\n\t\t\t};\n\t\t});\n\n\t\t/**\n\t\t * Mount / re-mount lifecycle.\n\t\t *\n\t\t * The dep array intentionally contains EVERY prop the library\n\t\t * uses at construction time. When any of them change, this\n\t\t * effect tears down the old instance and creates a new one\n\t\t * with the updated options. That's simpler and more correct\n\t\t * than trying to partial-update the live instance, and the\n\t\t * library has built-in caches (waveform peaks keyed by URL)\n\t\t * that make same-URL re-mounts cheap.\n\t\t */\n\t\tuseEffect(() => {\n\t\t\tlet cancelled = false;\n\t\t\tlet localInstance: { destroy?: () => void } | null = null;\n\n\t\t\t/* The library is browser-only. Defer the import until we're\n\t\t\t * actually mounting client-side so SSR / RSC don't try to\n\t\t\t * evaluate the audio + canvas + fetch surface on the server.\n\t\t\t */\n\t\t\tvoid import('@arraypress/waveform-player')\n\t\t\t\t.then((mod) => {\n\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tif (!container) return;\n\n\t\t\t\t\tconst WaveformPlayerClass = (mod.default ?? (mod as { WaveformPlayer?: unknown }).WaveformPlayer) as {\n\t\t\t\t\t\tnew (el: HTMLElement, opts: Record<string, unknown>): { destroy?: () => void };\n\t\t\t\t\t};\n\n\t\t\t\t\tif (typeof WaveformPlayerClass !== 'function') {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'[WaveformPlayerReact] Failed to resolve WaveformPlayer constructor from module.'\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst opts = buildLibraryOptions(props);\n\n\t\t\t\t\t/* Stable callback wrappers. Created once per player\n\t\t\t\t\t * instance and never change identity, so the core holds a\n\t\t\t\t\t * fixed reference, yet each call reads the *current*\n\t\t\t\t\t * handler from `callbacksRef` — fixing the stale-closure\n\t\t\t\t\t * bug without re-mounting on callback changes. Signatures\n\t\t\t\t\t * mirror the core's option callbacks exactly. */\n\t\t\t\t\topts.onLoad = (instance: WaveformPlayerInstance) => callbacksRef.current.onLoad?.(instance);\n\t\t\t\t\topts.onPlay = (instance: WaveformPlayerInstance) => callbacksRef.current.onPlay?.(instance);\n\t\t\t\t\topts.onPause = (instance: WaveformPlayerInstance) => callbacksRef.current.onPause?.(instance);\n\t\t\t\t\topts.onEnd = (instance: WaveformPlayerInstance) => callbacksRef.current.onEnd?.(instance);\n\t\t\t\t\topts.onTimeUpdate = (currentTime: number, duration: number, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onTimeUpdate?.(currentTime, duration, instance);\n\t\t\t\t\topts.onError = (error: Error, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onError?.(error, instance);\n\n\t\t\t\t\tlocalInstance = new WaveformPlayerClass(container, opts);\n\t\t\t\t\tinstanceRef.current = localInstance;\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error('[WaveformPlayerReact] Failed to load library:', err);\n\t\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t\tconst current = localInstance ?? (instanceRef.current as { destroy?: () => void } | null);\n\t\t\t\tif (current && typeof current.destroy === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcurrent.destroy();\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.warn('[WaveformPlayerReact] destroy() threw:', err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinstanceRef.current = null;\n\t\t\t};\n\t\t\t/* Re-mount on any prop change. Listed exhaustively rather\n\t\t\t * than spread to make the intent explicit and to keep the\n\t\t\t * lint rule happy. Callbacks intentionally NOT in deps:\n\t\t\t * a parent re-rendering with a fresh inline function\n\t\t\t * shouldn't tear the player down. */\n\t\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t}, [\n\t\t\tprops.url,\n\t\t\tprops.src,\n\t\t\tprops.audioMode,\n\t\t\tprops.preload,\n\t\t\tprops.waveformStyle,\n\t\t\tprops.height,\n\t\t\tprops.samples,\n\t\t\tprops.barWidth,\n\t\t\tprops.barSpacing,\n\t\t\tprops.barRadius,\n\t\t\tprops.waveform,\n\t\t\tprops.colorPreset,\n\t\t\tprops.waveformColor,\n\t\t\tprops.progressColor,\n\t\t\tprops.buttonColor,\n\t\t\tprops.buttonHoverColor,\n\t\t\tprops.textColor,\n\t\t\tprops.textSecondaryColor,\n\t\t\tprops.backgroundColor,\n\t\t\tprops.borderColor,\n\t\t\tprops.playbackRate,\n\t\t\tprops.showPlaybackSpeed,\n\t\t\tprops.playbackRates,\n\t\t\tprops.showControls,\n\t\t\tprops.showInfo,\n\t\t\tprops.showTime,\n\t\t\tprops.showHoverTime,\n\t\t\tprops.showBPM,\n\t\t\tprops.buttonAlign,\n\t\t\tprops.accessibleSeek,\n\t\t\tprops.seekLabel,\n\t\t\tprops.errorText,\n\t\t\tprops.markers,\n\t\t\tprops.showMarkers,\n\t\t\tprops.title,\n\t\t\tprops.subtitle,\n\t\t\tprops.artwork,\n\t\t\tprops.album,\n\t\t\tprops.autoplay,\n\t\t\tprops.singlePlay,\n\t\t\tprops.playOnSeek,\n\t\t\tprops.enableMediaSession,\n\t\t\tprops.playIcon,\n\t\t\tprops.pauseIcon,\n\t\t]);\n\n\t\t/**\n\t\t * Expose an imperative handle on the forwarded ref. Each\n\t\t * method is a thin pass-through to the live instance — if the\n\t\t * instance hasn't mounted yet (still loading async), calls are\n\t\t * no-ops (`pause`, `seekTo`, etc. return `undefined`).\n\t\t */\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tplay() {\n\t\t\t\t\tconst inst = instanceRef.current as { play?: () => Promise<void> | undefined } | null;\n\t\t\t\t\treturn inst?.play?.();\n\t\t\t\t},\n\t\t\t\tpause() {\n\t\t\t\t\tconst inst = instanceRef.current as { pause?: () => void } | null;\n\t\t\t\t\tinst?.pause?.();\n\t\t\t\t},\n\t\t\t\ttogglePlay() {\n\t\t\t\t\tconst inst = instanceRef.current as { togglePlay?: () => void } | null;\n\t\t\t\t\tinst?.togglePlay?.();\n\t\t\t\t},\n\t\t\t\tseekTo(seconds) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekTo?: (s: number) => void } | null;\n\t\t\t\t\tinst?.seekTo?.(seconds);\n\t\t\t\t},\n\t\t\t\tseekToPercent(percent) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekToPercent?: (p: number) => void } | null;\n\t\t\t\t\tinst?.seekToPercent?.(percent);\n\t\t\t\t},\n\t\t\t\tsetVolume(volume) {\n\t\t\t\t\tconst inst = instanceRef.current as { setVolume?: (v: number) => void } | null;\n\t\t\t\t\tinst?.setVolume?.(volume);\n\t\t\t\t},\n\t\t\t\tsetPlaybackRate(rate) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlaybackRate?: (r: number) => void } | null;\n\t\t\t\t\tinst?.setPlaybackRate?.(rate);\n\t\t\t\t},\n\t\t\t\tsetPlayingState(playing) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlayingState?: (p: boolean) => void } | null;\n\t\t\t\t\tinst?.setPlayingState?.(playing);\n\t\t\t\t},\n\t\t\t\tsetProgress(currentTime, duration) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tsetProgress?: (c: number, d: number) => void;\n\t\t\t\t\t} | null;\n\t\t\t\t\tinst?.setProgress?.(currentTime, duration);\n\t\t\t\t},\n\t\t\t\tasync loadTrack(url, title, subtitle, options) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tloadTrack?: (\n\t\t\t\t\t\t\tu: string,\n\t\t\t\t\t\t\tt?: string,\n\t\t\t\t\t\t\ts?: string,\n\t\t\t\t\t\t\to?: Record<string, unknown>\n\t\t\t\t\t\t) => Promise<void>;\n\t\t\t\t\t} | null;\n\t\t\t\t\tif (!inst?.loadTrack) return;\n\t\t\t\t\tawait inst.loadTrack(url, title, subtitle, options);\n\t\t\t\t},\n\t\t\t\tget instance() {\n\t\t\t\t\treturn instanceRef.current as WaveformPlayerInstance;\n\t\t\t\t},\n\t\t\t}),\n\t\t\t[]\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tid={props.id}\n\t\t\t\tclassName={['wfp-host', props.className].filter(Boolean).join(' ')}\n\t\t\t\tstyle={props.style}\n\t\t\t/>\n\t\t);\n\t}\n);\n"]}
1
+ {"version":3,"sources":["../src/WaveformPlayer.tsx"],"names":["forwardRef","WaveformPlayer","useRef","useLayoutEffect","useEffect","useImperativeHandle","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * WaveformPlayer.tsx\n * ------------------\n *\n * React wrapper around `@arraypress/waveform-player`. Mounts a player\n * instance into a `<div>` on first render, tears it down on unmount,\n * and re-mounts when any \"identity\" prop changes (the props whose\n * change requires the library to start over from scratch — `url`,\n * `audioMode`).\n *\n * For non-identity props, this component currently re-creates the\n * instance as well, which is simpler than diffing every option and\n * calling the right granular updater. The trade-off is acceptable\n * because:\n *\n * - The library re-uses any cached waveform data keyed by URL, so\n * re-mounts on the same URL are cheap.\n * - Per-render churn on a player widget is rare in practice.\n *\n * If you need finer control — imperative `loadTrack()`, `seekTo()`,\n * `setVolume()`, etc. — grab the instance through a `ref`:\n *\n * ```tsx\n * import { useRef, useEffect } from 'react';\n * import { WaveformPlayer, type WaveformPlayerHandle } from '@arraypress/waveform-player-react';\n *\n * function MyPlayer() {\n * const ref = useRef<WaveformPlayerHandle>(null);\n * return (\n * <>\n * <WaveformPlayer ref={ref} url=\"/audio/track.mp3\" />\n * <button onClick={() => ref.current?.seekTo(60)}>Jump to 1:00</button>\n * </>\n * );\n * }\n * ```\n *\n * ## Library setup\n *\n * This component does **not** load the core library's CSS for you.\n * Import it once at your app entry:\n *\n * ```ts\n * import '@arraypress/waveform-player/dist/waveform-player.css';\n * ```\n *\n * The library's JS is imported dynamically inside `useEffect` so it\n * only loads on the client (SSR-safe).\n *\n * @module WaveformPlayer\n */\nimport {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseRef,\n\ttype ForwardedRef,\n} from 'react';\n// Aliased to avoid colliding with this file's own `WaveformPlayer`\n// component export. This is the core library's player class type.\nimport type { WaveformPlayer as WaveformPlayerInstance } from '@arraypress/waveform-player';\nimport type { WaveformPlayerHandle, WaveformPlayerProps } from './types';\n\n/**\n * Convert a `WaveformPlayerProps` object into the option shape the\n * core library accepts. Most fields pass straight through; this\n * helper exists so the option-building logic is testable on its own\n * and the component body stays focused on lifecycle.\n *\n * @param props - The component's resolved props.\n * @returns An options object to pass into `new WaveformPlayer(el, …)`.\n */\nfunction buildLibraryOptions(props: WaveformPlayerProps): Record<string, unknown> {\n\tconst opts: Record<string, unknown> = {};\n\n\t/* Audio source — `src` is the core's shorthand alias for `url`. */\n\tif (props.url !== undefined) opts.url = props.url;\n\telse if (props.src !== undefined) opts.url = props.src;\n\tif (props.audioMode !== undefined) opts.audioMode = props.audioMode;\n\tif (props.preload !== undefined) opts.preload = props.preload;\n\n\t/* Waveform visualisation */\n\tif (props.waveformStyle !== undefined) opts.waveformStyle = props.waveformStyle;\n\tif (props.height !== undefined) opts.height = props.height;\n\tif (props.samples !== undefined) opts.samples = props.samples;\n\tif (props.barWidth !== undefined) opts.barWidth = props.barWidth;\n\tif (props.barSpacing !== undefined) opts.barSpacing = props.barSpacing;\n\tif (props.barRadius !== undefined) opts.barRadius = props.barRadius;\n\tif (props.waveform !== undefined && props.waveform !== null) {\n\t\topts.waveform = props.waveform;\n\t}\n\n\t/* Colours */\n\tif (props.colorPreset !== undefined) opts.colorPreset = props.colorPreset;\n\tif (props.waveformColor !== undefined) opts.waveformColor = props.waveformColor;\n\tif (props.progressColor !== undefined) opts.progressColor = props.progressColor;\n\tif (props.buttonColor !== undefined) opts.buttonColor = props.buttonColor;\n\tif (props.buttonHoverColor !== undefined) opts.buttonHoverColor = props.buttonHoverColor;\n\tif (props.textColor !== undefined) opts.textColor = props.textColor;\n\tif (props.textSecondaryColor !== undefined) opts.textSecondaryColor = props.textSecondaryColor;\n\tif (props.backgroundColor !== undefined) opts.backgroundColor = props.backgroundColor;\n\tif (props.borderColor !== undefined) opts.borderColor = props.borderColor;\n\n\t/* Playback controls */\n\tif (props.playbackRate !== undefined) opts.playbackRate = props.playbackRate;\n\tif (props.showPlaybackSpeed !== undefined) opts.showPlaybackSpeed = props.showPlaybackSpeed;\n\tif (props.playbackRates !== undefined) opts.playbackRates = props.playbackRates;\n\n\t/* UI toggles */\n\tif (props.showControls !== undefined) opts.showControls = props.showControls;\n\tif (props.showInfo !== undefined) opts.showInfo = props.showInfo;\n\tif (props.showTime !== undefined) opts.showTime = props.showTime;\n\tif (props.showHoverTime !== undefined) opts.showHoverTime = props.showHoverTime;\n\tif (props.showBPM !== undefined) opts.showBPM = props.showBPM;\n\tif (props.bpm !== undefined) opts.bpm = props.bpm;\n\tif (props.buttonAlign !== undefined) opts.buttonAlign = props.buttonAlign;\n\tif (props.layout !== undefined) opts.layout = props.layout;\n\tif (props.buttonStyle !== undefined) opts.buttonStyle = props.buttonStyle;\n\tif (props.buttonSize !== undefined) opts.buttonSize = props.buttonSize;\n\n\t/* Accessibility */\n\tif (props.accessibleSeek !== undefined) opts.accessibleSeek = props.accessibleSeek;\n\tif (props.seekLabel !== undefined) opts.seekLabel = props.seekLabel;\n\n\t/* Error UI */\n\tif (props.errorText !== undefined) opts.errorText = props.errorText;\n\n\t/* Markers */\n\tif (props.markers !== undefined) opts.markers = props.markers;\n\tif (props.showMarkers !== undefined) opts.showMarkers = props.showMarkers;\n\n\t/* Content metadata */\n\tif (props.title !== undefined) opts.title = props.title;\n\tif (props.subtitle !== undefined) opts.subtitle = props.subtitle;\n\tif (props.artwork !== undefined) opts.artwork = props.artwork;\n\tif (props.album !== undefined) opts.album = props.album;\n\n\t/* Behaviour */\n\tif (props.autoplay !== undefined) opts.autoplay = props.autoplay;\n\tif (props.singlePlay !== undefined) opts.singlePlay = props.singlePlay;\n\tif (props.playOnSeek !== undefined) opts.playOnSeek = props.playOnSeek;\n\tif (props.enableMediaSession !== undefined) opts.enableMediaSession = props.enableMediaSession;\n\n\t/* Icons */\n\tif (props.playIcon !== undefined) opts.playIcon = props.playIcon;\n\tif (props.pauseIcon !== undefined) opts.pauseIcon = props.pauseIcon;\n\n\t/* Callbacks are intentionally NOT mapped here. They are wired in\n\t * the mount effect as *stable* wrapper functions that read the\n\t * latest handlers from `callbacksRef` at call time. That way a\n\t * parent re-render passing fresh inline callbacks is always seen\n\t * by the core without re-creating the player — and the callbacks\n\t * never capture stale first-mount state (stale-closure bug). */\n\n\treturn opts;\n}\n\n/**\n * `WaveformPlayer` — React component wrapping\n * `@arraypress/waveform-player`.\n *\n * Render at the spot you want a waveform-driven audio player to\n * appear. The container `<div>` is rendered immediately for layout;\n * the actual player UI hydrates in once the library loads\n * client-side.\n *\n * @example Basic\n * <WaveformPlayer url=\"/audio/track.mp3\" title=\"My Track\" />\n *\n * @example With ref for imperative control\n * const ref = useRef<WaveformPlayerHandle>(null);\n * <WaveformPlayer ref={ref} url={url} />\n * <button onClick={() => ref.current?.togglePlay()}>Play/Pause</button>\n */\nexport const WaveformPlayer = forwardRef<WaveformPlayerHandle, WaveformPlayerProps>(\n\tfunction WaveformPlayer(props, ref: ForwardedRef<WaveformPlayerHandle>) {\n\t\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\t\tconst instanceRef = useRef<unknown>(null);\n\n\t\t/**\n\t\t * Latest user callbacks, kept in a ref so the wrappers handed to\n\t\t * the core (built once at mount, below) always invoke the most\n\t\t * recent handler instead of the ones captured on first mount.\n\t\t *\n\t\t * Initialised from this render's props and refreshed every render\n\t\t * by the layout effect underneath — never listed in the mount\n\t\t * effect's deps, so updating a callback does NOT tear the player\n\t\t * down.\n\t\t */\n\t\tconst callbacksRef = useRef<\n\t\t\tPick<\n\t\t\t\tWaveformPlayerProps,\n\t\t\t\t'onLoad' | 'onPlay' | 'onPause' | 'onEnd' | 'onTimeUpdate' | 'onError'\n\t\t\t>\n\t\t>({\n\t\t\tonLoad: props.onLoad,\n\t\t\tonPlay: props.onPlay,\n\t\t\tonPause: props.onPause,\n\t\t\tonEnd: props.onEnd,\n\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\tonError: props.onError,\n\t\t});\n\n\t\t/* Refresh the ref on every render (before paint) so the stable\n\t\t * wrappers below always read the latest handlers. */\n\t\tuseLayoutEffect(() => {\n\t\t\tcallbacksRef.current = {\n\t\t\t\tonLoad: props.onLoad,\n\t\t\t\tonPlay: props.onPlay,\n\t\t\t\tonPause: props.onPause,\n\t\t\t\tonEnd: props.onEnd,\n\t\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\t\tonError: props.onError,\n\t\t\t};\n\t\t});\n\n\t\t/**\n\t\t * Mount / re-mount lifecycle.\n\t\t *\n\t\t * The dep array intentionally contains EVERY prop the library\n\t\t * uses at construction time. When any of them change, this\n\t\t * effect tears down the old instance and creates a new one\n\t\t * with the updated options. That's simpler and more correct\n\t\t * than trying to partial-update the live instance, and the\n\t\t * library has built-in caches (waveform peaks keyed by URL)\n\t\t * that make same-URL re-mounts cheap.\n\t\t */\n\t\tuseEffect(() => {\n\t\t\tlet cancelled = false;\n\t\t\tlet localInstance: { destroy?: () => void } | null = null;\n\n\t\t\t/* The library is browser-only. Defer the import until we're\n\t\t\t * actually mounting client-side so SSR / RSC don't try to\n\t\t\t * evaluate the audio + canvas + fetch surface on the server.\n\t\t\t */\n\t\t\tvoid import('@arraypress/waveform-player')\n\t\t\t\t.then((mod) => {\n\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tif (!container) return;\n\n\t\t\t\t\tconst WaveformPlayerClass = (mod.default ?? (mod as { WaveformPlayer?: unknown }).WaveformPlayer) as {\n\t\t\t\t\t\tnew (el: HTMLElement, opts: Record<string, unknown>): { destroy?: () => void };\n\t\t\t\t\t};\n\n\t\t\t\t\tif (typeof WaveformPlayerClass !== 'function') {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'[WaveformPlayerReact] Failed to resolve WaveformPlayer constructor from module.'\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst opts = buildLibraryOptions(props);\n\n\t\t\t\t\t/* Stable callback wrappers. Created once per player\n\t\t\t\t\t * instance and never change identity, so the core holds a\n\t\t\t\t\t * fixed reference, yet each call reads the *current*\n\t\t\t\t\t * handler from `callbacksRef` — fixing the stale-closure\n\t\t\t\t\t * bug without re-mounting on callback changes. Signatures\n\t\t\t\t\t * mirror the core's option callbacks exactly. */\n\t\t\t\t\topts.onLoad = (instance: WaveformPlayerInstance) => callbacksRef.current.onLoad?.(instance);\n\t\t\t\t\topts.onPlay = (instance: WaveformPlayerInstance) => callbacksRef.current.onPlay?.(instance);\n\t\t\t\t\topts.onPause = (instance: WaveformPlayerInstance) => callbacksRef.current.onPause?.(instance);\n\t\t\t\t\topts.onEnd = (instance: WaveformPlayerInstance) => callbacksRef.current.onEnd?.(instance);\n\t\t\t\t\topts.onTimeUpdate = (currentTime: number, duration: number, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onTimeUpdate?.(currentTime, duration, instance);\n\t\t\t\t\topts.onError = (error: Error, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onError?.(error, instance);\n\n\t\t\t\t\tlocalInstance = new WaveformPlayerClass(container, opts);\n\t\t\t\t\tinstanceRef.current = localInstance;\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error('[WaveformPlayerReact] Failed to load library:', err);\n\t\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t\tconst current = localInstance ?? (instanceRef.current as { destroy?: () => void } | null);\n\t\t\t\tif (current && typeof current.destroy === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcurrent.destroy();\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.warn('[WaveformPlayerReact] destroy() threw:', err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinstanceRef.current = null;\n\t\t\t};\n\t\t\t/* Re-mount on any prop change. Listed exhaustively rather\n\t\t\t * than spread to make the intent explicit and to keep the\n\t\t\t * lint rule happy. Callbacks intentionally NOT in deps:\n\t\t\t * a parent re-rendering with a fresh inline function\n\t\t\t * shouldn't tear the player down. */\n\t\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t}, [\n\t\t\tprops.url,\n\t\t\tprops.src,\n\t\t\tprops.audioMode,\n\t\t\tprops.preload,\n\t\t\tprops.waveformStyle,\n\t\t\tprops.height,\n\t\t\tprops.samples,\n\t\t\tprops.barWidth,\n\t\t\tprops.barSpacing,\n\t\t\tprops.barRadius,\n\t\t\tprops.waveform,\n\t\t\tprops.colorPreset,\n\t\t\tprops.waveformColor,\n\t\t\tprops.progressColor,\n\t\t\tprops.buttonColor,\n\t\t\tprops.buttonHoverColor,\n\t\t\tprops.textColor,\n\t\t\tprops.textSecondaryColor,\n\t\t\tprops.backgroundColor,\n\t\t\tprops.borderColor,\n\t\t\tprops.playbackRate,\n\t\t\tprops.showPlaybackSpeed,\n\t\t\tprops.playbackRates,\n\t\t\tprops.showControls,\n\t\t\tprops.showInfo,\n\t\t\tprops.showTime,\n\t\t\tprops.showHoverTime,\n\t\t\tprops.showBPM,\n\t\t\tprops.buttonAlign,\n\t\t\tprops.buttonSize,\n\t\t\tprops.accessibleSeek,\n\t\t\tprops.seekLabel,\n\t\t\tprops.errorText,\n\t\t\tprops.markers,\n\t\t\tprops.showMarkers,\n\t\t\tprops.title,\n\t\t\tprops.subtitle,\n\t\t\tprops.artwork,\n\t\t\tprops.album,\n\t\t\tprops.autoplay,\n\t\t\tprops.singlePlay,\n\t\t\tprops.playOnSeek,\n\t\t\tprops.enableMediaSession,\n\t\t\tprops.playIcon,\n\t\t\tprops.pauseIcon,\n\t\t]);\n\n\t\t/**\n\t\t * Expose an imperative handle on the forwarded ref. Each\n\t\t * method is a thin pass-through to the live instance — if the\n\t\t * instance hasn't mounted yet (still loading async), calls are\n\t\t * no-ops (`pause`, `seekTo`, etc. return `undefined`).\n\t\t */\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tplay() {\n\t\t\t\t\tconst inst = instanceRef.current as { play?: () => Promise<void> | undefined } | null;\n\t\t\t\t\treturn inst?.play?.();\n\t\t\t\t},\n\t\t\t\tpause() {\n\t\t\t\t\tconst inst = instanceRef.current as { pause?: () => void } | null;\n\t\t\t\t\tinst?.pause?.();\n\t\t\t\t},\n\t\t\t\ttogglePlay() {\n\t\t\t\t\tconst inst = instanceRef.current as { togglePlay?: () => void } | null;\n\t\t\t\t\tinst?.togglePlay?.();\n\t\t\t\t},\n\t\t\t\tseekTo(seconds) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekTo?: (s: number) => void } | null;\n\t\t\t\t\tinst?.seekTo?.(seconds);\n\t\t\t\t},\n\t\t\t\tseekToPercent(percent) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekToPercent?: (p: number) => void } | null;\n\t\t\t\t\tinst?.seekToPercent?.(percent);\n\t\t\t\t},\n\t\t\t\tsetVolume(volume) {\n\t\t\t\t\tconst inst = instanceRef.current as { setVolume?: (v: number) => void } | null;\n\t\t\t\t\tinst?.setVolume?.(volume);\n\t\t\t\t},\n\t\t\t\tsetPlaybackRate(rate) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlaybackRate?: (r: number) => void } | null;\n\t\t\t\t\tinst?.setPlaybackRate?.(rate);\n\t\t\t\t},\n\t\t\t\tsetPlayingState(playing) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlayingState?: (p: boolean) => void } | null;\n\t\t\t\t\tinst?.setPlayingState?.(playing);\n\t\t\t\t},\n\t\t\t\tsetProgress(currentTime, duration) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tsetProgress?: (c: number, d: number) => void;\n\t\t\t\t\t} | null;\n\t\t\t\t\tinst?.setProgress?.(currentTime, duration);\n\t\t\t\t},\n\t\t\t\tasync loadTrack(url, title, subtitle, options) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tloadTrack?: (\n\t\t\t\t\t\t\tu: string,\n\t\t\t\t\t\t\tt?: string,\n\t\t\t\t\t\t\ts?: string,\n\t\t\t\t\t\t\to?: Record<string, unknown>\n\t\t\t\t\t\t) => Promise<void>;\n\t\t\t\t\t} | null;\n\t\t\t\t\tif (!inst?.loadTrack) return;\n\t\t\t\t\tawait inst.loadTrack(url, title, subtitle, options);\n\t\t\t\t},\n\t\t\t\tget instance() {\n\t\t\t\t\treturn instanceRef.current as WaveformPlayerInstance;\n\t\t\t\t},\n\t\t\t}),\n\t\t\t[]\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tid={props.id}\n\t\t\t\tclassName={['wfp-host', props.className].filter(Boolean).join(' ')}\n\t\t\t\tstyle={props.style}\n\t\t\t/>\n\t\t);\n\t}\n);\n"]}
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ function buildLibraryOptions(props) {
38
38
  if (props.buttonAlign !== void 0) opts.buttonAlign = props.buttonAlign;
39
39
  if (props.layout !== void 0) opts.layout = props.layout;
40
40
  if (props.buttonStyle !== void 0) opts.buttonStyle = props.buttonStyle;
41
+ if (props.buttonSize !== void 0) opts.buttonSize = props.buttonSize;
41
42
  if (props.accessibleSeek !== void 0) opts.accessibleSeek = props.accessibleSeek;
42
43
  if (props.seekLabel !== void 0) opts.seekLabel = props.seekLabel;
43
44
  if (props.errorText !== void 0) opts.errorText = props.errorText;
@@ -145,6 +146,7 @@ var WaveformPlayer = forwardRef(
145
146
  props.showHoverTime,
146
147
  props.showBPM,
147
148
  props.buttonAlign,
149
+ props.buttonSize,
148
150
  props.accessibleSeek,
149
151
  props.seekLabel,
150
152
  props.errorText,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/WaveformPlayer.tsx"],"names":["WaveformPlayer"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * WaveformPlayer.tsx\n * ------------------\n *\n * React wrapper around `@arraypress/waveform-player`. Mounts a player\n * instance into a `<div>` on first render, tears it down on unmount,\n * and re-mounts when any \"identity\" prop changes (the props whose\n * change requires the library to start over from scratch — `url`,\n * `audioMode`).\n *\n * For non-identity props, this component currently re-creates the\n * instance as well, which is simpler than diffing every option and\n * calling the right granular updater. The trade-off is acceptable\n * because:\n *\n * - The library re-uses any cached waveform data keyed by URL, so\n * re-mounts on the same URL are cheap.\n * - Per-render churn on a player widget is rare in practice.\n *\n * If you need finer control — imperative `loadTrack()`, `seekTo()`,\n * `setVolume()`, etc. — grab the instance through a `ref`:\n *\n * ```tsx\n * import { useRef, useEffect } from 'react';\n * import { WaveformPlayer, type WaveformPlayerHandle } from '@arraypress/waveform-player-react';\n *\n * function MyPlayer() {\n * const ref = useRef<WaveformPlayerHandle>(null);\n * return (\n * <>\n * <WaveformPlayer ref={ref} url=\"/audio/track.mp3\" />\n * <button onClick={() => ref.current?.seekTo(60)}>Jump to 1:00</button>\n * </>\n * );\n * }\n * ```\n *\n * ## Library setup\n *\n * This component does **not** load the core library's CSS for you.\n * Import it once at your app entry:\n *\n * ```ts\n * import '@arraypress/waveform-player/dist/waveform-player.css';\n * ```\n *\n * The library's JS is imported dynamically inside `useEffect` so it\n * only loads on the client (SSR-safe).\n *\n * @module WaveformPlayer\n */\nimport {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseRef,\n\ttype ForwardedRef,\n} from 'react';\n// Aliased to avoid colliding with this file's own `WaveformPlayer`\n// component export. This is the core library's player class type.\nimport type { WaveformPlayer as WaveformPlayerInstance } from '@arraypress/waveform-player';\nimport type { WaveformPlayerHandle, WaveformPlayerProps } from './types';\n\n/**\n * Convert a `WaveformPlayerProps` object into the option shape the\n * core library accepts. Most fields pass straight through; this\n * helper exists so the option-building logic is testable on its own\n * and the component body stays focused on lifecycle.\n *\n * @param props - The component's resolved props.\n * @returns An options object to pass into `new WaveformPlayer(el, …)`.\n */\nfunction buildLibraryOptions(props: WaveformPlayerProps): Record<string, unknown> {\n\tconst opts: Record<string, unknown> = {};\n\n\t/* Audio source — `src` is the core's shorthand alias for `url`. */\n\tif (props.url !== undefined) opts.url = props.url;\n\telse if (props.src !== undefined) opts.url = props.src;\n\tif (props.audioMode !== undefined) opts.audioMode = props.audioMode;\n\tif (props.preload !== undefined) opts.preload = props.preload;\n\n\t/* Waveform visualisation */\n\tif (props.waveformStyle !== undefined) opts.waveformStyle = props.waveformStyle;\n\tif (props.height !== undefined) opts.height = props.height;\n\tif (props.samples !== undefined) opts.samples = props.samples;\n\tif (props.barWidth !== undefined) opts.barWidth = props.barWidth;\n\tif (props.barSpacing !== undefined) opts.barSpacing = props.barSpacing;\n\tif (props.barRadius !== undefined) opts.barRadius = props.barRadius;\n\tif (props.waveform !== undefined && props.waveform !== null) {\n\t\topts.waveform = props.waveform;\n\t}\n\n\t/* Colours */\n\tif (props.colorPreset !== undefined) opts.colorPreset = props.colorPreset;\n\tif (props.waveformColor !== undefined) opts.waveformColor = props.waveformColor;\n\tif (props.progressColor !== undefined) opts.progressColor = props.progressColor;\n\tif (props.buttonColor !== undefined) opts.buttonColor = props.buttonColor;\n\tif (props.buttonHoverColor !== undefined) opts.buttonHoverColor = props.buttonHoverColor;\n\tif (props.textColor !== undefined) opts.textColor = props.textColor;\n\tif (props.textSecondaryColor !== undefined) opts.textSecondaryColor = props.textSecondaryColor;\n\tif (props.backgroundColor !== undefined) opts.backgroundColor = props.backgroundColor;\n\tif (props.borderColor !== undefined) opts.borderColor = props.borderColor;\n\n\t/* Playback controls */\n\tif (props.playbackRate !== undefined) opts.playbackRate = props.playbackRate;\n\tif (props.showPlaybackSpeed !== undefined) opts.showPlaybackSpeed = props.showPlaybackSpeed;\n\tif (props.playbackRates !== undefined) opts.playbackRates = props.playbackRates;\n\n\t/* UI toggles */\n\tif (props.showControls !== undefined) opts.showControls = props.showControls;\n\tif (props.showInfo !== undefined) opts.showInfo = props.showInfo;\n\tif (props.showTime !== undefined) opts.showTime = props.showTime;\n\tif (props.showHoverTime !== undefined) opts.showHoverTime = props.showHoverTime;\n\tif (props.showBPM !== undefined) opts.showBPM = props.showBPM;\n\tif (props.bpm !== undefined) opts.bpm = props.bpm;\n\tif (props.buttonAlign !== undefined) opts.buttonAlign = props.buttonAlign;\n\tif (props.layout !== undefined) opts.layout = props.layout;\n\tif (props.buttonStyle !== undefined) opts.buttonStyle = props.buttonStyle;\n\n\t/* Accessibility */\n\tif (props.accessibleSeek !== undefined) opts.accessibleSeek = props.accessibleSeek;\n\tif (props.seekLabel !== undefined) opts.seekLabel = props.seekLabel;\n\n\t/* Error UI */\n\tif (props.errorText !== undefined) opts.errorText = props.errorText;\n\n\t/* Markers */\n\tif (props.markers !== undefined) opts.markers = props.markers;\n\tif (props.showMarkers !== undefined) opts.showMarkers = props.showMarkers;\n\n\t/* Content metadata */\n\tif (props.title !== undefined) opts.title = props.title;\n\tif (props.subtitle !== undefined) opts.subtitle = props.subtitle;\n\tif (props.artwork !== undefined) opts.artwork = props.artwork;\n\tif (props.album !== undefined) opts.album = props.album;\n\n\t/* Behaviour */\n\tif (props.autoplay !== undefined) opts.autoplay = props.autoplay;\n\tif (props.singlePlay !== undefined) opts.singlePlay = props.singlePlay;\n\tif (props.playOnSeek !== undefined) opts.playOnSeek = props.playOnSeek;\n\tif (props.enableMediaSession !== undefined) opts.enableMediaSession = props.enableMediaSession;\n\n\t/* Icons */\n\tif (props.playIcon !== undefined) opts.playIcon = props.playIcon;\n\tif (props.pauseIcon !== undefined) opts.pauseIcon = props.pauseIcon;\n\n\t/* Callbacks are intentionally NOT mapped here. They are wired in\n\t * the mount effect as *stable* wrapper functions that read the\n\t * latest handlers from `callbacksRef` at call time. That way a\n\t * parent re-render passing fresh inline callbacks is always seen\n\t * by the core without re-creating the player — and the callbacks\n\t * never capture stale first-mount state (stale-closure bug). */\n\n\treturn opts;\n}\n\n/**\n * `WaveformPlayer` — React component wrapping\n * `@arraypress/waveform-player`.\n *\n * Render at the spot you want a waveform-driven audio player to\n * appear. The container `<div>` is rendered immediately for layout;\n * the actual player UI hydrates in once the library loads\n * client-side.\n *\n * @example Basic\n * <WaveformPlayer url=\"/audio/track.mp3\" title=\"My Track\" />\n *\n * @example With ref for imperative control\n * const ref = useRef<WaveformPlayerHandle>(null);\n * <WaveformPlayer ref={ref} url={url} />\n * <button onClick={() => ref.current?.togglePlay()}>Play/Pause</button>\n */\nexport const WaveformPlayer = forwardRef<WaveformPlayerHandle, WaveformPlayerProps>(\n\tfunction WaveformPlayer(props, ref: ForwardedRef<WaveformPlayerHandle>) {\n\t\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\t\tconst instanceRef = useRef<unknown>(null);\n\n\t\t/**\n\t\t * Latest user callbacks, kept in a ref so the wrappers handed to\n\t\t * the core (built once at mount, below) always invoke the most\n\t\t * recent handler instead of the ones captured on first mount.\n\t\t *\n\t\t * Initialised from this render's props and refreshed every render\n\t\t * by the layout effect underneath — never listed in the mount\n\t\t * effect's deps, so updating a callback does NOT tear the player\n\t\t * down.\n\t\t */\n\t\tconst callbacksRef = useRef<\n\t\t\tPick<\n\t\t\t\tWaveformPlayerProps,\n\t\t\t\t'onLoad' | 'onPlay' | 'onPause' | 'onEnd' | 'onTimeUpdate' | 'onError'\n\t\t\t>\n\t\t>({\n\t\t\tonLoad: props.onLoad,\n\t\t\tonPlay: props.onPlay,\n\t\t\tonPause: props.onPause,\n\t\t\tonEnd: props.onEnd,\n\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\tonError: props.onError,\n\t\t});\n\n\t\t/* Refresh the ref on every render (before paint) so the stable\n\t\t * wrappers below always read the latest handlers. */\n\t\tuseLayoutEffect(() => {\n\t\t\tcallbacksRef.current = {\n\t\t\t\tonLoad: props.onLoad,\n\t\t\t\tonPlay: props.onPlay,\n\t\t\t\tonPause: props.onPause,\n\t\t\t\tonEnd: props.onEnd,\n\t\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\t\tonError: props.onError,\n\t\t\t};\n\t\t});\n\n\t\t/**\n\t\t * Mount / re-mount lifecycle.\n\t\t *\n\t\t * The dep array intentionally contains EVERY prop the library\n\t\t * uses at construction time. When any of them change, this\n\t\t * effect tears down the old instance and creates a new one\n\t\t * with the updated options. That's simpler and more correct\n\t\t * than trying to partial-update the live instance, and the\n\t\t * library has built-in caches (waveform peaks keyed by URL)\n\t\t * that make same-URL re-mounts cheap.\n\t\t */\n\t\tuseEffect(() => {\n\t\t\tlet cancelled = false;\n\t\t\tlet localInstance: { destroy?: () => void } | null = null;\n\n\t\t\t/* The library is browser-only. Defer the import until we're\n\t\t\t * actually mounting client-side so SSR / RSC don't try to\n\t\t\t * evaluate the audio + canvas + fetch surface on the server.\n\t\t\t */\n\t\t\tvoid import('@arraypress/waveform-player')\n\t\t\t\t.then((mod) => {\n\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tif (!container) return;\n\n\t\t\t\t\tconst WaveformPlayerClass = (mod.default ?? (mod as { WaveformPlayer?: unknown }).WaveformPlayer) as {\n\t\t\t\t\t\tnew (el: HTMLElement, opts: Record<string, unknown>): { destroy?: () => void };\n\t\t\t\t\t};\n\n\t\t\t\t\tif (typeof WaveformPlayerClass !== 'function') {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'[WaveformPlayerReact] Failed to resolve WaveformPlayer constructor from module.'\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst opts = buildLibraryOptions(props);\n\n\t\t\t\t\t/* Stable callback wrappers. Created once per player\n\t\t\t\t\t * instance and never change identity, so the core holds a\n\t\t\t\t\t * fixed reference, yet each call reads the *current*\n\t\t\t\t\t * handler from `callbacksRef` — fixing the stale-closure\n\t\t\t\t\t * bug without re-mounting on callback changes. Signatures\n\t\t\t\t\t * mirror the core's option callbacks exactly. */\n\t\t\t\t\topts.onLoad = (instance: WaveformPlayerInstance) => callbacksRef.current.onLoad?.(instance);\n\t\t\t\t\topts.onPlay = (instance: WaveformPlayerInstance) => callbacksRef.current.onPlay?.(instance);\n\t\t\t\t\topts.onPause = (instance: WaveformPlayerInstance) => callbacksRef.current.onPause?.(instance);\n\t\t\t\t\topts.onEnd = (instance: WaveformPlayerInstance) => callbacksRef.current.onEnd?.(instance);\n\t\t\t\t\topts.onTimeUpdate = (currentTime: number, duration: number, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onTimeUpdate?.(currentTime, duration, instance);\n\t\t\t\t\topts.onError = (error: Error, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onError?.(error, instance);\n\n\t\t\t\t\tlocalInstance = new WaveformPlayerClass(container, opts);\n\t\t\t\t\tinstanceRef.current = localInstance;\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error('[WaveformPlayerReact] Failed to load library:', err);\n\t\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t\tconst current = localInstance ?? (instanceRef.current as { destroy?: () => void } | null);\n\t\t\t\tif (current && typeof current.destroy === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcurrent.destroy();\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.warn('[WaveformPlayerReact] destroy() threw:', err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinstanceRef.current = null;\n\t\t\t};\n\t\t\t/* Re-mount on any prop change. Listed exhaustively rather\n\t\t\t * than spread to make the intent explicit and to keep the\n\t\t\t * lint rule happy. Callbacks intentionally NOT in deps:\n\t\t\t * a parent re-rendering with a fresh inline function\n\t\t\t * shouldn't tear the player down. */\n\t\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t}, [\n\t\t\tprops.url,\n\t\t\tprops.src,\n\t\t\tprops.audioMode,\n\t\t\tprops.preload,\n\t\t\tprops.waveformStyle,\n\t\t\tprops.height,\n\t\t\tprops.samples,\n\t\t\tprops.barWidth,\n\t\t\tprops.barSpacing,\n\t\t\tprops.barRadius,\n\t\t\tprops.waveform,\n\t\t\tprops.colorPreset,\n\t\t\tprops.waveformColor,\n\t\t\tprops.progressColor,\n\t\t\tprops.buttonColor,\n\t\t\tprops.buttonHoverColor,\n\t\t\tprops.textColor,\n\t\t\tprops.textSecondaryColor,\n\t\t\tprops.backgroundColor,\n\t\t\tprops.borderColor,\n\t\t\tprops.playbackRate,\n\t\t\tprops.showPlaybackSpeed,\n\t\t\tprops.playbackRates,\n\t\t\tprops.showControls,\n\t\t\tprops.showInfo,\n\t\t\tprops.showTime,\n\t\t\tprops.showHoverTime,\n\t\t\tprops.showBPM,\n\t\t\tprops.buttonAlign,\n\t\t\tprops.accessibleSeek,\n\t\t\tprops.seekLabel,\n\t\t\tprops.errorText,\n\t\t\tprops.markers,\n\t\t\tprops.showMarkers,\n\t\t\tprops.title,\n\t\t\tprops.subtitle,\n\t\t\tprops.artwork,\n\t\t\tprops.album,\n\t\t\tprops.autoplay,\n\t\t\tprops.singlePlay,\n\t\t\tprops.playOnSeek,\n\t\t\tprops.enableMediaSession,\n\t\t\tprops.playIcon,\n\t\t\tprops.pauseIcon,\n\t\t]);\n\n\t\t/**\n\t\t * Expose an imperative handle on the forwarded ref. Each\n\t\t * method is a thin pass-through to the live instance — if the\n\t\t * instance hasn't mounted yet (still loading async), calls are\n\t\t * no-ops (`pause`, `seekTo`, etc. return `undefined`).\n\t\t */\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tplay() {\n\t\t\t\t\tconst inst = instanceRef.current as { play?: () => Promise<void> | undefined } | null;\n\t\t\t\t\treturn inst?.play?.();\n\t\t\t\t},\n\t\t\t\tpause() {\n\t\t\t\t\tconst inst = instanceRef.current as { pause?: () => void } | null;\n\t\t\t\t\tinst?.pause?.();\n\t\t\t\t},\n\t\t\t\ttogglePlay() {\n\t\t\t\t\tconst inst = instanceRef.current as { togglePlay?: () => void } | null;\n\t\t\t\t\tinst?.togglePlay?.();\n\t\t\t\t},\n\t\t\t\tseekTo(seconds) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekTo?: (s: number) => void } | null;\n\t\t\t\t\tinst?.seekTo?.(seconds);\n\t\t\t\t},\n\t\t\t\tseekToPercent(percent) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekToPercent?: (p: number) => void } | null;\n\t\t\t\t\tinst?.seekToPercent?.(percent);\n\t\t\t\t},\n\t\t\t\tsetVolume(volume) {\n\t\t\t\t\tconst inst = instanceRef.current as { setVolume?: (v: number) => void } | null;\n\t\t\t\t\tinst?.setVolume?.(volume);\n\t\t\t\t},\n\t\t\t\tsetPlaybackRate(rate) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlaybackRate?: (r: number) => void } | null;\n\t\t\t\t\tinst?.setPlaybackRate?.(rate);\n\t\t\t\t},\n\t\t\t\tsetPlayingState(playing) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlayingState?: (p: boolean) => void } | null;\n\t\t\t\t\tinst?.setPlayingState?.(playing);\n\t\t\t\t},\n\t\t\t\tsetProgress(currentTime, duration) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tsetProgress?: (c: number, d: number) => void;\n\t\t\t\t\t} | null;\n\t\t\t\t\tinst?.setProgress?.(currentTime, duration);\n\t\t\t\t},\n\t\t\t\tasync loadTrack(url, title, subtitle, options) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tloadTrack?: (\n\t\t\t\t\t\t\tu: string,\n\t\t\t\t\t\t\tt?: string,\n\t\t\t\t\t\t\ts?: string,\n\t\t\t\t\t\t\to?: Record<string, unknown>\n\t\t\t\t\t\t) => Promise<void>;\n\t\t\t\t\t} | null;\n\t\t\t\t\tif (!inst?.loadTrack) return;\n\t\t\t\t\tawait inst.loadTrack(url, title, subtitle, options);\n\t\t\t\t},\n\t\t\t\tget instance() {\n\t\t\t\t\treturn instanceRef.current as WaveformPlayerInstance;\n\t\t\t\t},\n\t\t\t}),\n\t\t\t[]\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tid={props.id}\n\t\t\t\tclassName={['wfp-host', props.className].filter(Boolean).join(' ')}\n\t\t\t\tstyle={props.style}\n\t\t\t/>\n\t\t);\n\t}\n);\n"]}
1
+ {"version":3,"sources":["../src/WaveformPlayer.tsx"],"names":["WaveformPlayer"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * WaveformPlayer.tsx\n * ------------------\n *\n * React wrapper around `@arraypress/waveform-player`. Mounts a player\n * instance into a `<div>` on first render, tears it down on unmount,\n * and re-mounts when any \"identity\" prop changes (the props whose\n * change requires the library to start over from scratch — `url`,\n * `audioMode`).\n *\n * For non-identity props, this component currently re-creates the\n * instance as well, which is simpler than diffing every option and\n * calling the right granular updater. The trade-off is acceptable\n * because:\n *\n * - The library re-uses any cached waveform data keyed by URL, so\n * re-mounts on the same URL are cheap.\n * - Per-render churn on a player widget is rare in practice.\n *\n * If you need finer control — imperative `loadTrack()`, `seekTo()`,\n * `setVolume()`, etc. — grab the instance through a `ref`:\n *\n * ```tsx\n * import { useRef, useEffect } from 'react';\n * import { WaveformPlayer, type WaveformPlayerHandle } from '@arraypress/waveform-player-react';\n *\n * function MyPlayer() {\n * const ref = useRef<WaveformPlayerHandle>(null);\n * return (\n * <>\n * <WaveformPlayer ref={ref} url=\"/audio/track.mp3\" />\n * <button onClick={() => ref.current?.seekTo(60)}>Jump to 1:00</button>\n * </>\n * );\n * }\n * ```\n *\n * ## Library setup\n *\n * This component does **not** load the core library's CSS for you.\n * Import it once at your app entry:\n *\n * ```ts\n * import '@arraypress/waveform-player/dist/waveform-player.css';\n * ```\n *\n * The library's JS is imported dynamically inside `useEffect` so it\n * only loads on the client (SSR-safe).\n *\n * @module WaveformPlayer\n */\nimport {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseRef,\n\ttype ForwardedRef,\n} from 'react';\n// Aliased to avoid colliding with this file's own `WaveformPlayer`\n// component export. This is the core library's player class type.\nimport type { WaveformPlayer as WaveformPlayerInstance } from '@arraypress/waveform-player';\nimport type { WaveformPlayerHandle, WaveformPlayerProps } from './types';\n\n/**\n * Convert a `WaveformPlayerProps` object into the option shape the\n * core library accepts. Most fields pass straight through; this\n * helper exists so the option-building logic is testable on its own\n * and the component body stays focused on lifecycle.\n *\n * @param props - The component's resolved props.\n * @returns An options object to pass into `new WaveformPlayer(el, …)`.\n */\nfunction buildLibraryOptions(props: WaveformPlayerProps): Record<string, unknown> {\n\tconst opts: Record<string, unknown> = {};\n\n\t/* Audio source — `src` is the core's shorthand alias for `url`. */\n\tif (props.url !== undefined) opts.url = props.url;\n\telse if (props.src !== undefined) opts.url = props.src;\n\tif (props.audioMode !== undefined) opts.audioMode = props.audioMode;\n\tif (props.preload !== undefined) opts.preload = props.preload;\n\n\t/* Waveform visualisation */\n\tif (props.waveformStyle !== undefined) opts.waveformStyle = props.waveformStyle;\n\tif (props.height !== undefined) opts.height = props.height;\n\tif (props.samples !== undefined) opts.samples = props.samples;\n\tif (props.barWidth !== undefined) opts.barWidth = props.barWidth;\n\tif (props.barSpacing !== undefined) opts.barSpacing = props.barSpacing;\n\tif (props.barRadius !== undefined) opts.barRadius = props.barRadius;\n\tif (props.waveform !== undefined && props.waveform !== null) {\n\t\topts.waveform = props.waveform;\n\t}\n\n\t/* Colours */\n\tif (props.colorPreset !== undefined) opts.colorPreset = props.colorPreset;\n\tif (props.waveformColor !== undefined) opts.waveformColor = props.waveformColor;\n\tif (props.progressColor !== undefined) opts.progressColor = props.progressColor;\n\tif (props.buttonColor !== undefined) opts.buttonColor = props.buttonColor;\n\tif (props.buttonHoverColor !== undefined) opts.buttonHoverColor = props.buttonHoverColor;\n\tif (props.textColor !== undefined) opts.textColor = props.textColor;\n\tif (props.textSecondaryColor !== undefined) opts.textSecondaryColor = props.textSecondaryColor;\n\tif (props.backgroundColor !== undefined) opts.backgroundColor = props.backgroundColor;\n\tif (props.borderColor !== undefined) opts.borderColor = props.borderColor;\n\n\t/* Playback controls */\n\tif (props.playbackRate !== undefined) opts.playbackRate = props.playbackRate;\n\tif (props.showPlaybackSpeed !== undefined) opts.showPlaybackSpeed = props.showPlaybackSpeed;\n\tif (props.playbackRates !== undefined) opts.playbackRates = props.playbackRates;\n\n\t/* UI toggles */\n\tif (props.showControls !== undefined) opts.showControls = props.showControls;\n\tif (props.showInfo !== undefined) opts.showInfo = props.showInfo;\n\tif (props.showTime !== undefined) opts.showTime = props.showTime;\n\tif (props.showHoverTime !== undefined) opts.showHoverTime = props.showHoverTime;\n\tif (props.showBPM !== undefined) opts.showBPM = props.showBPM;\n\tif (props.bpm !== undefined) opts.bpm = props.bpm;\n\tif (props.buttonAlign !== undefined) opts.buttonAlign = props.buttonAlign;\n\tif (props.layout !== undefined) opts.layout = props.layout;\n\tif (props.buttonStyle !== undefined) opts.buttonStyle = props.buttonStyle;\n\tif (props.buttonSize !== undefined) opts.buttonSize = props.buttonSize;\n\n\t/* Accessibility */\n\tif (props.accessibleSeek !== undefined) opts.accessibleSeek = props.accessibleSeek;\n\tif (props.seekLabel !== undefined) opts.seekLabel = props.seekLabel;\n\n\t/* Error UI */\n\tif (props.errorText !== undefined) opts.errorText = props.errorText;\n\n\t/* Markers */\n\tif (props.markers !== undefined) opts.markers = props.markers;\n\tif (props.showMarkers !== undefined) opts.showMarkers = props.showMarkers;\n\n\t/* Content metadata */\n\tif (props.title !== undefined) opts.title = props.title;\n\tif (props.subtitle !== undefined) opts.subtitle = props.subtitle;\n\tif (props.artwork !== undefined) opts.artwork = props.artwork;\n\tif (props.album !== undefined) opts.album = props.album;\n\n\t/* Behaviour */\n\tif (props.autoplay !== undefined) opts.autoplay = props.autoplay;\n\tif (props.singlePlay !== undefined) opts.singlePlay = props.singlePlay;\n\tif (props.playOnSeek !== undefined) opts.playOnSeek = props.playOnSeek;\n\tif (props.enableMediaSession !== undefined) opts.enableMediaSession = props.enableMediaSession;\n\n\t/* Icons */\n\tif (props.playIcon !== undefined) opts.playIcon = props.playIcon;\n\tif (props.pauseIcon !== undefined) opts.pauseIcon = props.pauseIcon;\n\n\t/* Callbacks are intentionally NOT mapped here. They are wired in\n\t * the mount effect as *stable* wrapper functions that read the\n\t * latest handlers from `callbacksRef` at call time. That way a\n\t * parent re-render passing fresh inline callbacks is always seen\n\t * by the core without re-creating the player — and the callbacks\n\t * never capture stale first-mount state (stale-closure bug). */\n\n\treturn opts;\n}\n\n/**\n * `WaveformPlayer` — React component wrapping\n * `@arraypress/waveform-player`.\n *\n * Render at the spot you want a waveform-driven audio player to\n * appear. The container `<div>` is rendered immediately for layout;\n * the actual player UI hydrates in once the library loads\n * client-side.\n *\n * @example Basic\n * <WaveformPlayer url=\"/audio/track.mp3\" title=\"My Track\" />\n *\n * @example With ref for imperative control\n * const ref = useRef<WaveformPlayerHandle>(null);\n * <WaveformPlayer ref={ref} url={url} />\n * <button onClick={() => ref.current?.togglePlay()}>Play/Pause</button>\n */\nexport const WaveformPlayer = forwardRef<WaveformPlayerHandle, WaveformPlayerProps>(\n\tfunction WaveformPlayer(props, ref: ForwardedRef<WaveformPlayerHandle>) {\n\t\tconst containerRef = useRef<HTMLDivElement | null>(null);\n\t\tconst instanceRef = useRef<unknown>(null);\n\n\t\t/**\n\t\t * Latest user callbacks, kept in a ref so the wrappers handed to\n\t\t * the core (built once at mount, below) always invoke the most\n\t\t * recent handler instead of the ones captured on first mount.\n\t\t *\n\t\t * Initialised from this render's props and refreshed every render\n\t\t * by the layout effect underneath — never listed in the mount\n\t\t * effect's deps, so updating a callback does NOT tear the player\n\t\t * down.\n\t\t */\n\t\tconst callbacksRef = useRef<\n\t\t\tPick<\n\t\t\t\tWaveformPlayerProps,\n\t\t\t\t'onLoad' | 'onPlay' | 'onPause' | 'onEnd' | 'onTimeUpdate' | 'onError'\n\t\t\t>\n\t\t>({\n\t\t\tonLoad: props.onLoad,\n\t\t\tonPlay: props.onPlay,\n\t\t\tonPause: props.onPause,\n\t\t\tonEnd: props.onEnd,\n\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\tonError: props.onError,\n\t\t});\n\n\t\t/* Refresh the ref on every render (before paint) so the stable\n\t\t * wrappers below always read the latest handlers. */\n\t\tuseLayoutEffect(() => {\n\t\t\tcallbacksRef.current = {\n\t\t\t\tonLoad: props.onLoad,\n\t\t\t\tonPlay: props.onPlay,\n\t\t\t\tonPause: props.onPause,\n\t\t\t\tonEnd: props.onEnd,\n\t\t\t\tonTimeUpdate: props.onTimeUpdate,\n\t\t\t\tonError: props.onError,\n\t\t\t};\n\t\t});\n\n\t\t/**\n\t\t * Mount / re-mount lifecycle.\n\t\t *\n\t\t * The dep array intentionally contains EVERY prop the library\n\t\t * uses at construction time. When any of them change, this\n\t\t * effect tears down the old instance and creates a new one\n\t\t * with the updated options. That's simpler and more correct\n\t\t * than trying to partial-update the live instance, and the\n\t\t * library has built-in caches (waveform peaks keyed by URL)\n\t\t * that make same-URL re-mounts cheap.\n\t\t */\n\t\tuseEffect(() => {\n\t\t\tlet cancelled = false;\n\t\t\tlet localInstance: { destroy?: () => void } | null = null;\n\n\t\t\t/* The library is browser-only. Defer the import until we're\n\t\t\t * actually mounting client-side so SSR / RSC don't try to\n\t\t\t * evaluate the audio + canvas + fetch surface on the server.\n\t\t\t */\n\t\t\tvoid import('@arraypress/waveform-player')\n\t\t\t\t.then((mod) => {\n\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\tconst container = containerRef.current;\n\t\t\t\t\tif (!container) return;\n\n\t\t\t\t\tconst WaveformPlayerClass = (mod.default ?? (mod as { WaveformPlayer?: unknown }).WaveformPlayer) as {\n\t\t\t\t\t\tnew (el: HTMLElement, opts: Record<string, unknown>): { destroy?: () => void };\n\t\t\t\t\t};\n\n\t\t\t\t\tif (typeof WaveformPlayerClass !== 'function') {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'[WaveformPlayerReact] Failed to resolve WaveformPlayer constructor from module.'\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst opts = buildLibraryOptions(props);\n\n\t\t\t\t\t/* Stable callback wrappers. Created once per player\n\t\t\t\t\t * instance and never change identity, so the core holds a\n\t\t\t\t\t * fixed reference, yet each call reads the *current*\n\t\t\t\t\t * handler from `callbacksRef` — fixing the stale-closure\n\t\t\t\t\t * bug without re-mounting on callback changes. Signatures\n\t\t\t\t\t * mirror the core's option callbacks exactly. */\n\t\t\t\t\topts.onLoad = (instance: WaveformPlayerInstance) => callbacksRef.current.onLoad?.(instance);\n\t\t\t\t\topts.onPlay = (instance: WaveformPlayerInstance) => callbacksRef.current.onPlay?.(instance);\n\t\t\t\t\topts.onPause = (instance: WaveformPlayerInstance) => callbacksRef.current.onPause?.(instance);\n\t\t\t\t\topts.onEnd = (instance: WaveformPlayerInstance) => callbacksRef.current.onEnd?.(instance);\n\t\t\t\t\topts.onTimeUpdate = (currentTime: number, duration: number, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onTimeUpdate?.(currentTime, duration, instance);\n\t\t\t\t\topts.onError = (error: Error, instance: WaveformPlayerInstance) =>\n\t\t\t\t\t\tcallbacksRef.current.onError?.(error, instance);\n\n\t\t\t\t\tlocalInstance = new WaveformPlayerClass(container, opts);\n\t\t\t\t\tinstanceRef.current = localInstance;\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error('[WaveformPlayerReact] Failed to load library:', err);\n\t\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tcancelled = true;\n\t\t\t\tconst current = localInstance ?? (instanceRef.current as { destroy?: () => void } | null);\n\t\t\t\tif (current && typeof current.destroy === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcurrent.destroy();\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.warn('[WaveformPlayerReact] destroy() threw:', err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinstanceRef.current = null;\n\t\t\t};\n\t\t\t/* Re-mount on any prop change. Listed exhaustively rather\n\t\t\t * than spread to make the intent explicit and to keep the\n\t\t\t * lint rule happy. Callbacks intentionally NOT in deps:\n\t\t\t * a parent re-rendering with a fresh inline function\n\t\t\t * shouldn't tear the player down. */\n\t\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t}, [\n\t\t\tprops.url,\n\t\t\tprops.src,\n\t\t\tprops.audioMode,\n\t\t\tprops.preload,\n\t\t\tprops.waveformStyle,\n\t\t\tprops.height,\n\t\t\tprops.samples,\n\t\t\tprops.barWidth,\n\t\t\tprops.barSpacing,\n\t\t\tprops.barRadius,\n\t\t\tprops.waveform,\n\t\t\tprops.colorPreset,\n\t\t\tprops.waveformColor,\n\t\t\tprops.progressColor,\n\t\t\tprops.buttonColor,\n\t\t\tprops.buttonHoverColor,\n\t\t\tprops.textColor,\n\t\t\tprops.textSecondaryColor,\n\t\t\tprops.backgroundColor,\n\t\t\tprops.borderColor,\n\t\t\tprops.playbackRate,\n\t\t\tprops.showPlaybackSpeed,\n\t\t\tprops.playbackRates,\n\t\t\tprops.showControls,\n\t\t\tprops.showInfo,\n\t\t\tprops.showTime,\n\t\t\tprops.showHoverTime,\n\t\t\tprops.showBPM,\n\t\t\tprops.buttonAlign,\n\t\t\tprops.buttonSize,\n\t\t\tprops.accessibleSeek,\n\t\t\tprops.seekLabel,\n\t\t\tprops.errorText,\n\t\t\tprops.markers,\n\t\t\tprops.showMarkers,\n\t\t\tprops.title,\n\t\t\tprops.subtitle,\n\t\t\tprops.artwork,\n\t\t\tprops.album,\n\t\t\tprops.autoplay,\n\t\t\tprops.singlePlay,\n\t\t\tprops.playOnSeek,\n\t\t\tprops.enableMediaSession,\n\t\t\tprops.playIcon,\n\t\t\tprops.pauseIcon,\n\t\t]);\n\n\t\t/**\n\t\t * Expose an imperative handle on the forwarded ref. Each\n\t\t * method is a thin pass-through to the live instance — if the\n\t\t * instance hasn't mounted yet (still loading async), calls are\n\t\t * no-ops (`pause`, `seekTo`, etc. return `undefined`).\n\t\t */\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tplay() {\n\t\t\t\t\tconst inst = instanceRef.current as { play?: () => Promise<void> | undefined } | null;\n\t\t\t\t\treturn inst?.play?.();\n\t\t\t\t},\n\t\t\t\tpause() {\n\t\t\t\t\tconst inst = instanceRef.current as { pause?: () => void } | null;\n\t\t\t\t\tinst?.pause?.();\n\t\t\t\t},\n\t\t\t\ttogglePlay() {\n\t\t\t\t\tconst inst = instanceRef.current as { togglePlay?: () => void } | null;\n\t\t\t\t\tinst?.togglePlay?.();\n\t\t\t\t},\n\t\t\t\tseekTo(seconds) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekTo?: (s: number) => void } | null;\n\t\t\t\t\tinst?.seekTo?.(seconds);\n\t\t\t\t},\n\t\t\t\tseekToPercent(percent) {\n\t\t\t\t\tconst inst = instanceRef.current as { seekToPercent?: (p: number) => void } | null;\n\t\t\t\t\tinst?.seekToPercent?.(percent);\n\t\t\t\t},\n\t\t\t\tsetVolume(volume) {\n\t\t\t\t\tconst inst = instanceRef.current as { setVolume?: (v: number) => void } | null;\n\t\t\t\t\tinst?.setVolume?.(volume);\n\t\t\t\t},\n\t\t\t\tsetPlaybackRate(rate) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlaybackRate?: (r: number) => void } | null;\n\t\t\t\t\tinst?.setPlaybackRate?.(rate);\n\t\t\t\t},\n\t\t\t\tsetPlayingState(playing) {\n\t\t\t\t\tconst inst = instanceRef.current as { setPlayingState?: (p: boolean) => void } | null;\n\t\t\t\t\tinst?.setPlayingState?.(playing);\n\t\t\t\t},\n\t\t\t\tsetProgress(currentTime, duration) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tsetProgress?: (c: number, d: number) => void;\n\t\t\t\t\t} | null;\n\t\t\t\t\tinst?.setProgress?.(currentTime, duration);\n\t\t\t\t},\n\t\t\t\tasync loadTrack(url, title, subtitle, options) {\n\t\t\t\t\tconst inst = instanceRef.current as {\n\t\t\t\t\t\tloadTrack?: (\n\t\t\t\t\t\t\tu: string,\n\t\t\t\t\t\t\tt?: string,\n\t\t\t\t\t\t\ts?: string,\n\t\t\t\t\t\t\to?: Record<string, unknown>\n\t\t\t\t\t\t) => Promise<void>;\n\t\t\t\t\t} | null;\n\t\t\t\t\tif (!inst?.loadTrack) return;\n\t\t\t\t\tawait inst.loadTrack(url, title, subtitle, options);\n\t\t\t\t},\n\t\t\t\tget instance() {\n\t\t\t\t\treturn instanceRef.current as WaveformPlayerInstance;\n\t\t\t\t},\n\t\t\t}),\n\t\t\t[]\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tid={props.id}\n\t\t\t\tclassName={['wfp-host', props.className].filter(Boolean).join(' ')}\n\t\t\t\tstyle={props.style}\n\t\t\t/>\n\t\t);\n\t}\n);\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arraypress/waveform-player-react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "React component wrapper for @arraypress/waveform-player — forwardRef-friendly, useEffect lifecycle, typed props for every library option.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -71,7 +71,7 @@
71
71
  "prepublishOnly": "npm run build"
72
72
  },
73
73
  "devDependencies": {
74
- "@arraypress/waveform-player": "^1.12.0",
74
+ "@arraypress/waveform-player": "^1.14.0",
75
75
  "@testing-library/jest-dom": "^6.9.1",
76
76
  "@testing-library/react": "^16.3.2",
77
77
  "@types/react": "^19.2.17",