UNPKG

@iboshkov/wavesurfer-react

Version:
393 lines (384 loc) 10.5 kB
import React2, { createContext, useContext, useRef, useEffect, useState, useMemo, Children } from 'react'; import WaveSurfer from 'wavesurfer.js'; // react-shim.js var useRegionEvent = (ref, eventName, callback) => { const callbackRef = useRef(null); useEffect(() => { if (!ref) { return; } if (callback) { callbackRef.current = (...args) => callback(ref, ...args); ref.on(eventName, callbackRef.current); } return () => { callbackRef.current && ref.un(eventName, callbackRef.current); callbackRef.current = null; }; }, [ref, eventName, callback]); }; var useRegionEvent_default = useRegionEvent; var WaveSurferContext = createContext(null); var WaveSurferContext_default = WaveSurferContext; function useWavesurferContext() { return useContext(WaveSurferContext_default); } // src/components/Region.tsx var Region = ({ onOver, onLeave, onClick, onDoubleClick, onIn, onOut, onRemove, onUpdate, onUpdateEnd, ...props }) => { const waveSurfer = useWavesurferContext(); const isRenderedCache = useRef(false); const [regionRef, setRegionRef] = useState(null); useEffect(() => { return () => { if (regionRef) { regionRef.remove(); } }; }, [regionRef]); useEffect( () => { if (regionRef) { const update = UpdatableRegionProps.reduce( (result, prop) => { if (regionRef[prop] !== props[prop]) { return { ...result, [prop]: props[prop] }; } return result; }, { id: props.id } ); regionRef.update(update); } }, UpdatableRegionProps.map((prop) => props[prop]) ); useEffect(() => { if (!isRenderedCache.current && waveSurfer) { isRenderedCache.current = true; let region; region = waveSurfer.regions.list[props.id]; if (!region) { region = waveSurfer.addRegion(props); } setRegionRef(region); } }, [waveSurfer]); useRegionEvent_default(regionRef, "click", onClick); useRegionEvent_default(regionRef, "mouseenter", onOver); useRegionEvent_default(regionRef, "mouseleave", onLeave); useRegionEvent_default(regionRef, "dblclick", onDoubleClick); useRegionEvent_default(regionRef, "in", onIn); useRegionEvent_default(regionRef, "out", onOut); useRegionEvent_default(regionRef, "remove", onRemove); useRegionEvent_default(regionRef, "update", onUpdate); useRegionEvent_default(regionRef, "update-end", onUpdateEnd); return null; }; var Region_default = Region; var UpdatableRegionProps = [ "start", "end", "loop", "color", "handleStyle", "resize", "drag", "drag", "end", "handleStyle", "id", "loop", "preventContextMenu", "resize", "start" ]; function Marker({ onClick, onDrop, onDrag, ...data }) { const ws = useWavesurferContext(); const ws$ = useRef(ws); useEffect(() => { ws$.current = ws; }, [ws]); const isRendered = useRef(false); const markerEl = useRef(null); useEffect(() => { if (!ws) return; if (!onClick) return; function handler(marker, event) { if (!markerEl.current) return; if (marker.el !== markerEl.current.el) return; onClick == null ? void 0 : onClick(marker, event); } ws.on("marker-click", handler); return () => { ws.un("marker-click", handler); }; }, [ws, onClick]); useEffect(() => { if (!ws) return; if (!onDrag) return; function handler(marker, event) { if (!markerEl.current) return; if (marker.el !== markerEl.current.el) return; onDrag == null ? void 0 : onDrag(marker, event); } ws.on("marker-drag", handler); return () => { ws.un("marker-drag", handler); }; }, [ws, onDrag]); useEffect(() => { if (!ws) return; if (!onDrop) return; function handler(marker, event) { if (!markerEl.current) return; if (marker.el !== markerEl.current.el) return; onDrop == null ? void 0 : onDrop(marker, event); } ws.on("marker-drop", handler); return () => { ws.un("marker-drop", handler); }; }, [ws, onDrop]); useEffect(() => { if (!ws) return; if (isRendered.current) return; isRendered.current = true; markerEl.current = ws.addMarker(data); }, [ws]); useEffect(() => { var _a; if (!ws || !markerEl.current || !isRendered.current) return; if (data.time === ((_a = markerEl.current) == null ? void 0 : _a.time)) return; const marker = ws.markers.markers.find((mark) => { var _a2; return mark.el === ((_a2 = markerEl.current) == null ? void 0 : _a2.el); }); if (!marker) return; marker.time = data.time; ws.markers._updateMarkerPosition({ ...markerEl.current, time: data.time }); }, [data == null ? void 0 : data.time]); useEffect(() => () => { if (!ws$.current || !markerEl.current) return; const index = ws$.current.markers.markers.findIndex((marker) => { var _a; return marker.el === ((_a = markerEl.current) == null ? void 0 : _a.el); }); ws$.current.markers.remove(index); }, []); return null; } var WaveForm = ({ id = "waveform", children }) => { return /* @__PURE__ */ React2.createElement("div", { id }, children); }; var WaveForm_default = WaveForm; // src/utils/getWaveFormOptionsFromProps.ts var waveFormPropsList = [ "audioRate", "audioContext", "audioScriptProcessor", "autoCenter", "backend", "backgroundColor", "barGap", "barHeight", "barMinHeight", "barRadius", "barWidth", "closeAudioContext", "cursorColor", "cursorWidth", "fillParent", "forceDecode", "height", "hideScrollbar", "interact", "loopSelection", "maxCanvasWidth", "mediaControls", "mediaType", "minPxPerSec", "normalize", "partialRender", "pixelRatio", "progressColor", "removeMediaElementOnDestroy", "renderer", "responsive", "scrollParent", "skipLength", "splitChannels", "waveColor", "autoCenterRate", "autoCenterImmediately", "drawingContextAttributes", "duration", "ignoreSilenceMode", "rtl", "splitChannelsOptions", "vertical", "xhr" ]; var getWaveFormOptionsFromProps = (props) => { if (!props) return {}; return waveFormPropsList.reduce((waveFormOptions, optionName) => { if (!Object.prototype.hasOwnProperty.call(props, optionName)) { return waveFormOptions; } return { ...waveFormOptions, [optionName]: props[optionName] }; }, {}); }; var getWaveFormOptionsFromProps_default = getWaveFormOptionsFromProps; function createWavesurfer(options) { return WaveSurfer.create(options); } // src/utils/createPlugin.ts function createPlugin(pluginObj) { const { plugin, options, creator = "create" } = pluginObj; const createMethod = plugin[creator]; if (!plugin) throw new Error(`Please pass a valid plugin in plugin list`); if (!creator) throw new Error(`Please pass the creator function name in 'creator' property.`); if (createMethod instanceof Function === false) { throw new Error(`"${creator}" is not callable on given plugin. Please pass a valid 'creator' in plugins list.`); } return createMethod(options); } // src/utils/getDifference.ts var getDifference = (arr1, arr2) => { let nextArr1 = [...arr1]; let nextArr2 = [...arr2]; const disabled = nextArr1.filter((item) => { return nextArr2.findIndex((nextItem) => nextItem.name === item.name) === -1; }); const enabled = nextArr2.filter((item) => { return nextArr1.findIndex((nextItem) => nextItem.name === item.name) === -1; }); return { disabled, enabled }; }; var getDifference_default = getDifference; // src/hooks/useWavesurfer.ts function useWavesurfer({ container, plugins = [], onMount, ...props }) { const usedPluginsListCache = useRef([]); const [wavesurfer, setWavesurfer] = useState(null); useEffect(() => { if (!container) return; let _plugins = []; if (plugins) { _plugins = plugins.map(createPlugin); } usedPluginsListCache.current = _plugins; const ws = createWavesurfer({ container, ...props, plugins: _plugins }); onMount == null ? void 0 : onMount(ws); setWavesurfer(ws); return () => { ws.destroy(); }; }, [container]); useEffect(() => { if (wavesurfer) { const nextPluginsMap = plugins.map(createPlugin); const { disabled, enabled } = getDifference_default( usedPluginsListCache.current, nextPluginsMap ); usedPluginsListCache.current = nextPluginsMap; disabled.forEach((plugin) => { if (!plugin.name) return; wavesurfer == null ? void 0 : wavesurfer.destroyPlugin(plugin.name); }); enabled.forEach((plugin) => { if (!plugin.name) return; wavesurfer == null ? void 0 : wavesurfer.addPlugin(plugin).initPlugin(plugin.name); }); } }, [plugins]); return wavesurfer; } // src/containers/WaveSurfer.tsx var WaveSurfer3 = ({ children, plugins = [], onMount, ...props }) => { const UNSTABLE_waveFormProps = useMemo(() => { let waveformProps = {}; Children.forEach(children, (element) => { if (typeof element !== "object" || element === null || ["string", "number"].includes(typeof element)) { return; } if (!("props" in element || "type" in element)) return; const props2 = element.props; const elType = element.type; if (elType === WaveForm_default) { const { id, ...rest } = props2; waveformProps = getWaveFormOptionsFromProps_default(rest); waveformProps = { ...waveformProps, container: "#" + id }; } }); return waveformProps; }, [children]); const wavesurfer = useWavesurfer({ plugins, onMount, ...props, ...UNSTABLE_waveFormProps }); return /* @__PURE__ */ React2.createElement(WaveSurferContext_default.Provider, { value: wavesurfer }, children); }; WaveSurfer3.defaultProps = { children: null, plugins: [] }; var WaveSurfer_default = WaveSurfer3; export { Marker, Region_default as Region, WaveForm_default as WaveForm, WaveSurfer_default as WaveSurfer, useWavesurfer, useWavesurferContext };