@exode-team/react-recorder
v1.1.9
Published
Accessible audio recorder UI kit for React applications
Maintainers
Readme
@exode-team/react-recorder
Готовый компонент записи и отправки голосовых сообщений для React-приложений. Компонент инкапсулирует работу с
MediaRecorder, визуализацию волны и UX-паттерн «нажал — запись началась», оставляя вам полный контроль над загрузкой
файла и локализацией.
Возможности
- поддержка простого сценария «нажал — запись началась» без удержания и свайпов;
- встроенная визуализация уровней сигнала и предпросмотр записанного фрагмента;
- управление воспроизведением, паузой и повторным набором;
- адаптация текстов/aria-лейблов через проп
messages; - строгая типизация и SDK-подобный API (
uploader, callbacks жизненного цикла); - хук
useVoiceRecorderдля создания кастомного UI; - компонент
VoiceMessagePlayerс waveform-визуализацией и поддержкой последовательного воспроизведения; VoiceBlobCacheдля мгновенного воспроизведения только что отправленных сообщений;VoicePlaybackChain— автоматическое воспроизведение следующего голосового (как в Telegram).
Установка
yarn add @exode-team/react-recorder styled-components
# или
npm install @exode-team/react-recorder styled-componentsКомпонент требует React 17+ и styled-components в качестве peer dependency.
Быстрый старт
import React from 'react';
import { AudioRecorder, StorageSpaceEnum } from '@exode-team/react-recorder';
const Example = () => {
const uploader = async (file: File) => {
const body = new FormData();
body.append('file', file);
const response = await fetch('/api/upload', { method: 'POST', body });
return response.json();
};
return (
<AudioRecorder uploader={uploader}
space={StorageSpaceEnum.User}
onUploaded={(file) => console.log('Uploaded', file)}
onUploadError={(error) => console.error(error)}/>
);
};API
<AudioRecorder />
| Проп | Тип | Обязателен | По умолчанию | Описание |
|------------------------|----------------------------|------------|-------------------------|------------------------------------------------------------------------------|
| uploader | UploadStrategy<T> | ✅ | — | Функция, которая принимает File и возвращает результат (DTO, URL и т. д.). |
| onUploaded | (file: T) => void | — | — | Колбэк после успешной загрузки. |
| onUploadError | (error: unknown) => void | — | — | Обработчик ошибок загрузки. |
| space | StorageSpace | — | StorageSpaceEnum.User | Пространство хранения при загрузке. |
| uploadId | string | — | crypto.randomUUID() | Идентификатор загрузки. |
| messages | RecorderMessagesInput | — | встроенные тексты | Локализация кнопок и aria-лейблов. |
| fileName | string | — | record.webm | Имя файла при сохранении. |
| mimeType | string | — | audio/webm | MIME-тип создаваемого файла. |
| autoResetAfterUpload | boolean | — | true | Сбрасывать UI после onUploaded. |
| className | string | — | — | Пользовательский класс контейнера. |
| onRecordingStart | () => void | — | — | Колбэк старта записи. |
| onRecordingStop | (blob: Blob) => void | — | — | Колбэк остановки записи. |
| onRecordingDelete | () => void | — | — | Колбэк удаления записанного файла. |
| onRecordingError | (error: unknown) => void | — | — | Ошибка при записи. |
| onPermissionDenied | (error: unknown) => void | — | — | Отказ в доступе к микрофону. |
useVoiceRecorder
Хук для создания собственного интерфейса записи, если стандартный AudioRecorder не подходит.
import { useVoiceRecorder } from '@exode-team/react-recorder';
const MyCustomRecorder = () => {
const {
isRecording,
startRecording,
stopRecording,
audioURL
} = useVoiceRecorder({
onRecordingStop: (blob) => console.log('Recorded blob:', blob),
});
return (
<div>
<button onClick={isRecording ? stopRecording : startRecording}>
{isRecording ? 'Stop' : 'Record'}
</button>
{audioURL && <audio src={audioURL} controls/>}
</div>
);
};Параметры хука (UseVoiceRecorderOptions):
space,uploadId,uploader,onUploadedfileName,mimeTypeautoResetAfterUploadonRecordingStart,onRecordingStop,onRecordingDelete,onRecordingError,onPermissionDenied
Возвращаемое значение (UseVoiceRecorderResult):
- Состояния:
isRecording,isPaused,isPlaying,hasRecording - Данные:
audioURL,recordingTime,playbackTime,playbackDuration,audioLevels,previewLevels - Методы:
startRecording,stopRecording,cancelRecording,deleteRecording,toggleRecordingPause,togglePlayback,stopPlayback,sendRecording - Утилиты:
formatTime
<VoiceMessagePlayer />
Компонент воспроизведения голосовых сообщений с визуализацией waveform, поддержкой программного запуска через ref
и последовательного воспроизведения (chained playback).
import { useRef } from 'react';
import { VoiceMessagePlayer, VoiceMessagePlayerRef } from '@exode-team/react-recorder';
const Messages = () => {
const ref = useRef<VoiceMessagePlayerRef>(null);
return (
<VoiceMessagePlayer ref={ref}
src="/audio/message.webm"
chainId={42}
duration={12.5}
onEnded={() => console.log('Playback ended')}/>
);
};| Проп | Тип | Обязателен | По умолчанию | Описание |
|-----------------|--------------------------------|------------|--------------|---------------------------------------------------------------------------------------------|
| src | string | ✅ | — | URL аудиофайла. |
| chainId | number | — | — | ID для последовательного воспроизведения. При окончании автоматически запускает следующий. |
| duration | number | — | — | Длительность в секундах (отображается до загрузки аудио). |
| autoPreload | boolean | — | true | Автозагрузка аудио при попадании в viewport (IntersectionObserver). |
| waveformData | number[] | — | — | Предварительно вычисленные уровни waveform. |
| preloadedBlob | Blob \| null | — | — | Blob для мгновенного воспроизведения без сетевого запроса. |
| onEnded | () => void | — | — | Колбэк окончания воспроизведения. |
| className | string | — | — | CSS-класс контейнера. |
| onClick | (e: React.MouseEvent) => void| — | — | Обработчик клика по контейнеру. |
Ref API (VoiceMessagePlayerRef):
play()— программный запуск воспроизведения.prefetch()— загрузка аудио без воспроизведения (fetch + decode waveform).
VoicePlaybackChain
Singleton-реестр для последовательного воспроизведения голосовых сообщений (как в Telegram).
Автоматически используется внутри VoiceMessagePlayer при передаче chainId, но доступен и напрямую.
import { VoicePlaybackChain } from '@exode-team/react-recorder';
// Регистрация плеера (возвращает cleanup для useEffect)
const cleanup = VoicePlaybackChain.register(42, () => play());
// Запуск следующего после текущего
VoicePlaybackChain.playNext(42);
// Удаление из цепочки
VoicePlaybackChain.unregister(42);VoiceBlobCache
Кеш Blob-объектов голосовых сообщений для мгновенного воспроизведения только что отправленных записей (до получения URL с сервера).
import { VoiceBlobCache } from '@exode-team/react-recorder';
// Сохранить blob при отправке
VoiceBlobCache.set(messageId, blob);
// Получить для воспроизведения
const blob = VoiceBlobCache.get(messageId);
// Перенести при получении серверного ID
VoiceBlobCache.transfer(optimisticId, serverId);
// Удалить при ошибке
VoiceBlobCache.delete(messageId);Типы
StorageSpaceEnum
export const StorageSpaceEnum = {
User: 'user',
Shared: 'shared',
System: 'system',
} as const;Сборка
Команда yarn build (или npm run build) запускает Rollup, который собирает ESModule, CommonJS и декларации
TypeScript. .npmignore настроен так, чтобы в пакет попадали только dist, README и LICENSE.
Лицензия
MIT © Exode.
