From c3957a163f91374e78c78a69d01b94d9ba1ad76b Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Tue, 12 Nov 2024 08:36:06 -0300 Subject: [PATCH 1/6] added hook return cancelRecording --- README.md | 1 + src/components/AudioRecordingComponent.tsx | 10 ++++++++++ src/hooks/useAudioRecorder.ts | 15 ++++++++++++++- src/main.tsx | 19 +++++++++++++++---- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 95d69d21..435a8245 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ The hook returns the following: | :------------ |:---------------| | **`startRecording`** | Invoking this method starts the recording. Sets `isRecording` to `true` | | **`stopRecording`** | Invoking this method stops the recording in progress and the resulting audio is made available in `recordingBlob`. Sets `isRecording` to `false` | +| **`cancelRecording`** | Invoking this method cancels the recording in progress and discard audio. Sets `isRecording` to `false` | | **`togglePauseResume`** | Invoking this method would pause the recording if it is currently running or resume if it is paused. Toggles the value `isPaused` | | **`recordingBlob`** | This is the recording blob that is created after `stopRecording` has been called | | **`isRecording`** | A boolean value that represents whether a recording is currently in progress | diff --git a/src/components/AudioRecordingComponent.tsx b/src/components/AudioRecordingComponent.tsx index 8b376d38..5744d695 100644 --- a/src/components/AudioRecordingComponent.tsx +++ b/src/components/AudioRecordingComponent.tsx @@ -43,9 +43,11 @@ const AudioRecorder: (props: Props) => ReactElement = ({ startRecording, stopRecording, togglePauseResume, + cancelRecording, recordingBlob, isRecording, isPaused, + isCancelled, recordingTime, mediaRecorder, } = @@ -62,6 +64,9 @@ const AudioRecorder: (props: Props) => ReactElement = ({ const stopAudioRecorder: (save?: boolean) => void = ( save: boolean = true ) => { + if (!save) { + cancelRecording(); + } setShouldSave(save); stopRecording(); }; @@ -116,6 +121,7 @@ const AudioRecorder: (props: Props) => ReactElement = ({ useEffect(() => { if ( + !isCancelled && (shouldSave || recorderControls) && recordingBlob != null && onRecordingComplete != null @@ -127,6 +133,10 @@ const AudioRecorder: (props: Props) => ReactElement = ({ } }, [recordingBlob]); + useEffect(() => { + stopRecording(); + }, [isCancelled]); + return (
void; stopRecording: () => void; togglePauseResume: () => void; + cancelRecording: () => void; recordingBlob?: Blob; isRecording: boolean; isPaused: boolean; + isCancelled: boolean; recordingTime: number; mediaRecorder?: MediaRecorder; } @@ -49,6 +51,7 @@ const useAudioRecorder: ( ) => { const [isRecording, setIsRecording] = useState(false); const [isPaused, setIsPaused] = useState(false); + const [isCancelled, setIsCancelled] = useState(false); const [recordingTime, setRecordingTime] = useState(0); const [mediaRecorder, setMediaRecorder] = useState(); const [timerInterval, setTimerInterval] = useState(); @@ -71,7 +74,7 @@ const useAudioRecorder: ( */ const startRecording: () => void = useCallback(() => { if (timerInterval != null) return; - + setIsCancelled(false); navigator.mediaDevices .getUserMedia({ audio: audioTrackConstraints ?? true }) .then((stream) => { @@ -136,13 +139,23 @@ const useAudioRecorder: ( } }, [mediaRecorder, setIsPaused, _startTimer, _stopTimer]); + /** + * Calling this method would cancel the recording and discard + */ + const cancelRecording: () => void = useCallback(() => { + setIsCancelled(true); + setIsRecording(false); + }, []); + return { startRecording, stopRecording, togglePauseResume, + cancelRecording, recordingBlob, isRecording, isPaused, + isCancelled, recordingTime, mediaRecorder, }; diff --git a/src/main.tsx b/src/main.tsx index 35545fc2..ad2c8a06 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import AudioRecorder from "./components/AudioRecordingComponent"; +import useAudioRecorder from "./hooks/useAudioRecorder"; const addAudioElement = (blob: Blob) => { const url = URL.createObjectURL(blob); @@ -10,8 +11,10 @@ const addAudioElement = (blob: Blob) => { document.body.appendChild(audio); }; -ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - +function AudioRecorderComp() { + const { isRecording, stopRecording, cancelRecording, ...recordControls } = useAudioRecorder() + + return (<> addAudioElement(blob)} // audioTrackConstraints={{ @@ -20,8 +23,16 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( // }} onNotAllowedOrFound={(err) => console.table(err)} showVisualizer={true} - downloadOnSavePress - downloadFileExtension="mp3" + recorderControls={{ isRecording, stopRecording, cancelRecording, ...recordControls}} /> + + + + ) +} + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + ); From d7dba69697452ed4c3bf39767131c83631816e03 Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Fri, 28 Feb 2025 10:10:31 -0300 Subject: [PATCH 2/6] feat: added support to NextJS 15 --- README.md | 3 ++ package.json | 2 +- src/components/AudioRecordingComponent.tsx | 6 +-- .../ReactAudioVisualizerWrapper.tsx | 48 +++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 src/components/ReactAudioVisualizerWrapper.tsx diff --git a/README.md b/README.md index 435a8245..64599fa5 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ npm install react-audio-voice-recorder yarn add react-audio-voice-recorder ``` +## Version 2.3.0 +- Added support to NextJs 15 + ## Migrating from v1 → v2 ### Breaking changes - In v2 the `AudioRecorder` prop `downloadFileExtension` no longer supports `mp3` and `wav` without the website using this package being [cross-origin isolated](https://web.dev/cross-origin-isolation-guide/). This change was made in order to fix [issue #54](https://github.com/samhirtarif/react-audio-recorder/issues/54) in v1.2.1 diff --git a/package.json b/package.json index 122ad9e8..d594d676 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-audio-voice-recorder", "private": false, - "version": "2.2.0", + "version": "2.3.0", "type": "module", "license": "MIT", "author": "Samhir Tarif", diff --git a/src/components/AudioRecordingComponent.tsx b/src/components/AudioRecordingComponent.tsx index 5744d695..ea24a40d 100644 --- a/src/components/AudioRecordingComponent.tsx +++ b/src/components/AudioRecordingComponent.tsx @@ -8,11 +8,7 @@ import resumeSVG from "../icons/play.svg"; import saveSVG from "../icons/save.svg"; import discardSVG from "../icons/stop.svg"; import "../styles/audio-recorder.css"; - -const LiveAudioVisualizer = React.lazy(async () => { - const { LiveAudioVisualizer } = await import("react-audio-visualize"); - return { default: LiveAudioVisualizer }; -}); +import LiveAudioVisualizer from "./ReactAudioVisualizerWrapper"; /** * Usage: https://github.com/samhirtarif/react-audio-recorder#audiorecorder-component diff --git a/src/components/ReactAudioVisualizerWrapper.tsx b/src/components/ReactAudioVisualizerWrapper.tsx new file mode 100644 index 00000000..84e367fd --- /dev/null +++ b/src/components/ReactAudioVisualizerWrapper.tsx @@ -0,0 +1,48 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + +import React from "react"; + +// Função para carregar o componente dinamicamente +const loadVisualizer = async () => { + try { + // Tenta importar de forma segura + const module = await import("react-audio-visualize"); + return module.LiveAudioVisualizer; + } catch (error) { + console.error("Error loading LiveAudioVisualizer:", error); + // Retorna um componente vazio em caso de erro + return () => null; + } +}; + +// Componente wrapper que carrega o visualizador sob demanda +const DynamicLiveAudioVisualizer = (props) => { + const [Component, setComponent] = React.useState(null); + const [loading, setLoading] = React.useState(true); + + React.useEffect(() => { + let isMounted = true; + + const load = async () => { + const VisualizerComponent = await loadVisualizer(); + if (isMounted) { + setComponent(() => VisualizerComponent); + setLoading(false); + } + }; + + void load(); + + return () => { + isMounted = false; + }; + }, []); + + if (loading || !Component) { + return null; // ou um placeholder + } + + return ; +}; + +export default DynamicLiveAudioVisualizer; From 86d03586573909411ecae8c0ac3397df43a283f2 Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Fri, 28 Feb 2025 10:18:43 -0300 Subject: [PATCH 3/6] 0.0.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa411c42..f67fc9b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-audio-voice-recorder", - "version": "2.2.0", + "version": "0.0.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-audio-voice-recorder", - "version": "2.2.0", + "version": "0.0.5", "license": "MIT", "dependencies": { "@ffmpeg/ffmpeg": "^0.11.6", diff --git a/package.json b/package.json index d594d676..763beaf7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-audio-voice-recorder", "private": false, - "version": "2.3.0", + "version": "0.0.5", "type": "module", "license": "MIT", "author": "Samhir Tarif", From 080b8fe790a7ad9495d3b6cf6914ffd4a7cf8863 Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Fri, 28 Feb 2025 10:19:01 -0300 Subject: [PATCH 4/6] 0.1.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f67fc9b3..afa42aaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-audio-voice-recorder", - "version": "0.0.5", + "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-audio-voice-recorder", - "version": "0.0.5", + "version": "0.1.0", "license": "MIT", "dependencies": { "@ffmpeg/ffmpeg": "^0.11.6", diff --git a/package.json b/package.json index 763beaf7..fda384c9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-audio-voice-recorder", "private": false, - "version": "0.0.5", + "version": "0.1.0", "type": "module", "license": "MIT", "author": "Samhir Tarif", From fa1644814c4553a48620c7eca9635a2c93314bad Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Fri, 28 Feb 2025 10:19:48 -0300 Subject: [PATCH 5/6] 0.1.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index afa42aaa..4dff77db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-audio-voice-recorder", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-audio-voice-recorder", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "dependencies": { "@ffmpeg/ffmpeg": "^0.11.6", diff --git a/package.json b/package.json index fda384c9..3ea84f12 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-audio-voice-recorder", "private": false, - "version": "0.1.0", + "version": "0.1.1", "type": "module", "license": "MIT", "author": "Samhir Tarif", From b6e2381edb4eaf4d370d90e45d989852296f2dd3 Mon Sep 17 00:00:00 2001 From: Rafael Marreca Date: Fri, 28 Feb 2025 10:32:48 -0300 Subject: [PATCH 6/6] version 0.1.0 --- package-lock.json | 8 ++++---- package.json | 8 ++++---- src/components/ReactAudioVisualizerWrapper.tsx | 7 ++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4dff77db..3be83117 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "react-audio-voice-recorder", - "version": "0.1.1", + "name": "@rafaelmarreca/react-audio-voice-recorder", + "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "react-audio-voice-recorder", - "version": "0.1.1", + "name": "@rafaelmarreca/react-audio-voice-recorder", + "version": "0.1.0", "license": "MIT", "dependencies": { "@ffmpeg/ffmpeg": "^0.11.6", diff --git a/package.json b/package.json index 3ea84f12..7471d436 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "react-audio-voice-recorder", + "name": "@rafaelmarreca/react-audio-voice-recorder", "private": false, - "version": "0.1.1", + "version": "0.1.0", "type": "module", "license": "MIT", - "author": "Samhir Tarif", + "author": "Rafael Marreca", "repository": { "type": "git", - "url": "https://github.com/samhirtarif/react-audio-recorder.git" + "url": "https://github.com/rafael145a/react-audio-recorder.git" }, "keywords": [ "react", diff --git a/src/components/ReactAudioVisualizerWrapper.tsx b/src/components/ReactAudioVisualizerWrapper.tsx index 84e367fd..7e99b86f 100644 --- a/src/components/ReactAudioVisualizerWrapper.tsx +++ b/src/components/ReactAudioVisualizerWrapper.tsx @@ -16,7 +16,7 @@ const loadVisualizer = async () => { }; // Componente wrapper que carrega o visualizador sob demanda -const DynamicLiveAudioVisualizer = (props) => { +const DynamicLiveAudioVisualizer = (props: any) => { const [Component, setComponent] = React.useState(null); const [loading, setLoading] = React.useState(true); @@ -26,6 +26,7 @@ const DynamicLiveAudioVisualizer = (props) => { const load = async () => { const VisualizerComponent = await loadVisualizer(); if (isMounted) { + // @ts-expect-error setComponent(() => VisualizerComponent); setLoading(false); } @@ -39,9 +40,9 @@ const DynamicLiveAudioVisualizer = (props) => { }, []); if (loading || !Component) { - return null; // ou um placeholder + return null; } - + // @ts-expect-error return ; };