@solid-primitives/audio
Advanced tools
Comparing version 1.3.19 to 1.4.0
@@ -1,4 +0,3 @@ | ||
import { Accessor } from 'solid-js'; | ||
declare enum AudioState { | ||
import { Accessor } from "solid-js"; | ||
export declare enum AudioState { | ||
LOADING = "loading", | ||
@@ -12,4 +11,4 @@ PLAYING = "playing", | ||
} | ||
type AudioSource = string | undefined | HTMLAudioElement | MediaSource | (string & MediaSource); | ||
type AudioEventHandlers = { | ||
export type AudioSource = string | undefined | HTMLAudioElement | MediaSource | (string & MediaSource); | ||
export type AudioEventHandlers = { | ||
[K in keyof HTMLMediaElementEventMap]?: (event: HTMLMediaElementEventMap[K]) => void; | ||
@@ -24,3 +23,3 @@ }; | ||
*/ | ||
declare const makeAudio: (src: AudioSource, handlers?: AudioEventHandlers) => HTMLAudioElement; | ||
export declare const makeAudio: (src: AudioSource, handlers?: AudioEventHandlers) => HTMLAudioElement; | ||
/** | ||
@@ -43,3 +42,3 @@ * Generates a basic audio player with simple control mechanisms. | ||
*/ | ||
declare const makeAudioPlayer: (src: AudioSource, handlers?: AudioEventHandlers) => { | ||
export declare const makeAudioPlayer: (src: AudioSource, handlers?: AudioEventHandlers) => { | ||
play: () => Promise<void>; | ||
@@ -78,3 +77,3 @@ pause: VoidFunction; | ||
*/ | ||
declare const createAudio: (src: AudioSource | Accessor<AudioSource>, playing?: Accessor<boolean>, volume?: Accessor<number>) => [{ | ||
export declare const createAudio: (src: AudioSource | Accessor<AudioSource>, playing?: Accessor<boolean>, volume?: Accessor<number>) => [{ | ||
state: AudioState; | ||
@@ -91,3 +90,1 @@ currentTime: number; | ||
}]; | ||
export { type AudioEventHandlers, type AudioSource, AudioState, createAudio, makeAudio, makeAudioPlayer }; |
@@ -1,143 +0,191 @@ | ||
import { onMount, onCleanup, createEffect } from 'solid-js'; | ||
import { isServer } from 'solid-js/web'; | ||
import { noop, access } from '@solid-primitives/utils'; | ||
import { createStaticStore } from '@solid-primitives/static-store'; | ||
// src/index.ts | ||
var AudioState = /* @__PURE__ */ ((AudioState2) => { | ||
AudioState2["LOADING"] = "loading"; | ||
AudioState2["PLAYING"] = "playing"; | ||
AudioState2["PAUSED"] = "paused"; | ||
AudioState2["COMPLETE"] = "complete"; | ||
AudioState2["STOPPED"] = "stopped"; | ||
AudioState2["READY"] = "ready"; | ||
AudioState2["ERROR"] = "error"; | ||
return AudioState2; | ||
})(AudioState || {}); | ||
var unwrapSource = (src) => { | ||
if (src instanceof HTMLAudioElement) { | ||
return src; | ||
} | ||
const player = new Audio(); | ||
setAudioSrc(player, src); | ||
return player; | ||
import { onMount, onCleanup, createEffect } from "solid-js"; | ||
import { isServer } from "solid-js/web"; | ||
import { access, noop } from "@solid-primitives/utils"; | ||
import { createStaticStore } from "@solid-primitives/static-store"; | ||
// Set of control enums | ||
export var AudioState; | ||
(function (AudioState) { | ||
AudioState["LOADING"] = "loading"; | ||
AudioState["PLAYING"] = "playing"; | ||
AudioState["PAUSED"] = "paused"; | ||
AudioState["COMPLETE"] = "complete"; | ||
AudioState["STOPPED"] = "stopped"; | ||
AudioState["READY"] = "ready"; | ||
AudioState["ERROR"] = "error"; | ||
})(AudioState || (AudioState = {})); | ||
// Helper for producing the audio source | ||
const unwrapSource = (src) => { | ||
if (src instanceof HTMLAudioElement) { | ||
return src; | ||
} | ||
const player = new Audio(); | ||
setAudioSrc(player, src); | ||
return player; | ||
}; | ||
function setAudioSrc(el, src) { | ||
el[typeof src === "string" ? "src" : "srcObject"] = src; | ||
el[typeof src === "string" ? "src" : "srcObject"] = src; | ||
} | ||
var makeAudio = (src, handlers = {}) => { | ||
if (isServer) { | ||
return {}; | ||
} | ||
const player = unwrapSource(src); | ||
onMount(() => { | ||
for (const [name, handler] of Object.entries(handlers)) { | ||
player.addEventListener(name, handler); | ||
/** | ||
* Generates a basic audio instance with limited functionality. | ||
* | ||
* @param src Audio file path or MediaSource to be played | ||
* @param handlers An array of handlers to bind against the player | ||
* @return A basic audio player instance | ||
*/ | ||
export const makeAudio = (src, handlers = {}) => { | ||
if (isServer) { | ||
return {}; | ||
} | ||
}); | ||
onCleanup(() => { | ||
player.pause(); | ||
for (const [name, handler] of Object.entries(handlers)) { | ||
player.removeEventListener(name, handler); | ||
const player = unwrapSource(src); | ||
onMount(() => { | ||
for (const [name, handler] of Object.entries(handlers)) { | ||
player.addEventListener(name, handler); | ||
} | ||
}); | ||
onCleanup(() => { | ||
player.pause(); | ||
for (const [name, handler] of Object.entries(handlers)) { | ||
player.removeEventListener(name, handler); | ||
} | ||
}); | ||
return player; | ||
}; | ||
/** | ||
* Generates a basic audio player with simple control mechanisms. | ||
* | ||
* @param src Audio file path or MediaSource to be played | ||
* @return options - @type Object | ||
* @return options.start - Start playing | ||
* @return options.pause - Pause playing | ||
* @return options.seek - Seeks to a location in the playhead | ||
* @return options.setVolume - Sets the volume of the player | ||
* @return options.player - Raw player instance | ||
* @return Returns a location signal and one-off async query callback | ||
* | ||
* @example | ||
* ```ts | ||
* const { start, seek } = makeAudioPlayer('./example1.mp3'); | ||
* ``` | ||
*/ | ||
export const makeAudioPlayer = (src, handlers = {}) => { | ||
if (isServer) { | ||
return { | ||
pause: noop, | ||
play: async () => noop(), | ||
player: {}, | ||
seek: noop, | ||
setVolume: noop, | ||
}; | ||
} | ||
}); | ||
return player; | ||
}; | ||
var makeAudioPlayer = (src, handlers = {}) => { | ||
if (isServer) { | ||
const player = makeAudio(src, handlers); | ||
return { | ||
pause: noop, | ||
play: async () => noop(), | ||
player: {}, | ||
seek: noop, | ||
setVolume: noop | ||
player, | ||
play: () => player.play(), | ||
pause: () => player.pause(), | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
seek: player.fastSeek | ||
? (time) => player.fastSeek(time) | ||
: (time) => (player.currentTime = time), | ||
setVolume: (volume) => (player.volume = volume), | ||
}; | ||
} | ||
const player = makeAudio(src, handlers); | ||
return { | ||
player, | ||
play: () => player.play(), | ||
pause: () => player.pause(), | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
seek: player.fastSeek ? (time) => player.fastSeek(time) : (time) => player.currentTime = time, | ||
setVolume: (volume) => player.volume = volume | ||
}; | ||
}; | ||
var createAudio = (src, playing, volume) => { | ||
if (isServer) { | ||
return [ | ||
{ | ||
state: "loading" /* LOADING */, | ||
/** | ||
* A reactive audio primitive with basic control actions. | ||
* | ||
* @param src Audio source path or MediaSource to be played or an accessor | ||
* @param playing A signal for controlling the player | ||
* @param volume A signal for controlling the volume | ||
* @return [store] - @type Store | ||
* @return [store.state] - Current state of the player | ||
* @return [store.currentTime] - Current time of the playhead | ||
* @return [store.duration] - Duration of the loaded file | ||
* @return [store.volume] - Current volume of the audio player | ||
* @return [store.player] - Raw player instance | ||
* @return [controls] - Controls for the audio player @type Object | ||
* @return [controls.seek] - Seeks to a specified location | ||
* @return [controls.play] - Start playing | ||
* @return [controls.pause] - Pause playing | ||
* @return [controls.setVolume] - Sets the volume of the player, from 0 to 1 | ||
* | ||
* | ||
* @example | ||
* ```ts | ||
* const [playing, setPlaying] = createSignal(false); | ||
* const [volume, setVolume] = createSignal(1); | ||
* const [audio, controls] = createAudio('./example1.mp3', playing, volume); | ||
* console.log(audio.duration); | ||
* ``` | ||
*/ | ||
export const createAudio = (src, playing, volume) => { | ||
if (isServer) { | ||
return [ | ||
{ | ||
state: AudioState.LOADING, | ||
currentTime: 0, | ||
duration: 0, | ||
volume: 0, | ||
player: {}, | ||
}, | ||
{ | ||
seek: noop, | ||
setVolume: noop, | ||
play: async () => noop(), | ||
pause: noop, | ||
}, | ||
]; | ||
} | ||
const player = unwrapSource(access(src)); | ||
const [store, setStore] = createStaticStore({ | ||
state: AudioState.LOADING, | ||
player, | ||
currentTime: 0, | ||
duration: 0, | ||
volume: 0, | ||
player: {} | ||
}, | ||
{ | ||
seek: noop, | ||
setVolume: noop, | ||
play: async () => noop(), | ||
pause: noop | ||
} | ||
]; | ||
} | ||
const player = unwrapSource(access(src)); | ||
const [store, setStore] = createStaticStore({ | ||
state: "loading" /* LOADING */, | ||
player, | ||
currentTime: 0, | ||
duration: 0, | ||
volume: 0 | ||
}); | ||
const { | ||
play, | ||
pause, | ||
setVolume: _setVolume, | ||
seek | ||
} = makeAudioPlayer(store.player, { | ||
loadeddata: () => { | ||
setStore({ | ||
state: "ready" /* READY */, | ||
duration: player.duration | ||
}); | ||
if (playing && playing()) { | ||
play().catch((e) => { | ||
if (e.name === "NotAllowedError") { | ||
setStore("state", "error" /* ERROR */); | ||
} | ||
}); | ||
const { play, pause, setVolume: _setVolume, seek, } = makeAudioPlayer(store.player, { | ||
loadeddata: () => { | ||
setStore({ | ||
state: AudioState.READY, | ||
duration: player.duration, | ||
}); | ||
if (playing && playing()) { | ||
play().catch((e) => { | ||
if (e.name === "NotAllowedError") { | ||
setStore("state", AudioState.ERROR); | ||
} | ||
}); | ||
} | ||
}, | ||
timeupdate: () => setStore("currentTime", player.currentTime), | ||
loadstart: () => setStore("state", AudioState.LOADING), | ||
playing: () => setStore("state", AudioState.PLAYING), | ||
pause: () => setStore("state", AudioState.PAUSED), | ||
error: () => setStore("state", AudioState.ERROR), | ||
ended: () => setStore("state", AudioState.COMPLETE), | ||
}); | ||
const setVolume = (volume) => { | ||
setStore("volume", volume); | ||
_setVolume(volume); | ||
}; | ||
// Bind reactive properties as needed | ||
if (src instanceof Function) { | ||
createEffect(() => { | ||
const newSrc = src(); | ||
if (newSrc instanceof HTMLAudioElement) { | ||
setStore("player", newSrc); | ||
} | ||
else { | ||
setAudioSrc(store.player, newSrc); | ||
} | ||
seek(0); | ||
}); | ||
} | ||
}, | ||
timeupdate: () => setStore("currentTime", player.currentTime), | ||
loadstart: () => setStore("state", "loading" /* LOADING */), | ||
playing: () => setStore("state", "playing" /* PLAYING */), | ||
pause: () => setStore("state", "paused" /* PAUSED */), | ||
error: () => setStore("state", "error" /* ERROR */), | ||
ended: () => setStore("state", "complete" /* COMPLETE */) | ||
}); | ||
const setVolume = (volume2) => { | ||
setStore("volume", volume2); | ||
_setVolume(volume2); | ||
}; | ||
if (src instanceof Function) { | ||
createEffect(() => { | ||
const newSrc = src(); | ||
if (newSrc instanceof HTMLAudioElement) { | ||
setStore("player", newSrc); | ||
} else { | ||
setAudioSrc(store.player, newSrc); | ||
} | ||
seek(0); | ||
}); | ||
} | ||
if (playing) { | ||
createEffect(() => playing() ? play() : pause()); | ||
} | ||
if (volume) { | ||
createEffect(() => setVolume(volume())); | ||
setVolume(volume()); | ||
} | ||
return [store, { seek, play, pause, setVolume }]; | ||
} | ||
if (playing) { | ||
createEffect(() => (playing() ? play() : pause())); | ||
} | ||
if (volume) { | ||
createEffect(() => setVolume(volume())); | ||
setVolume(volume()); | ||
} | ||
return [store, { seek, play, pause, setVolume }]; | ||
}; | ||
export { AudioState, createAudio, makeAudio, makeAudioPlayer }; |
{ | ||
"name": "@solid-primitives/audio", | ||
"version": "1.3.19", | ||
"version": "1.4.0", | ||
"description": "Primitives to manage audio and single sounds.", | ||
@@ -28,3 +28,2 @@ "author": "David Di Biase <dave.dibiase@gmail.com>", | ||
"type": "module", | ||
"main": "./dist/index.cjs", | ||
"module": "./dist/index.js", | ||
@@ -38,6 +37,2 @@ "browser": {}, | ||
"default": "./dist/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/index.d.cts", | ||
"default": "./dist/index.cjs" | ||
} | ||
@@ -55,4 +50,4 @@ }, | ||
"dependencies": { | ||
"@solid-primitives/static-store": "^0.0.9", | ||
"@solid-primitives/utils": "^6.2.3" | ||
"@solid-primitives/static-store": "^0.1.0", | ||
"@solid-primitives/utils": "^6.3.0" | ||
}, | ||
@@ -59,0 +54,0 @@ "peerDependencies": { |
@@ -7,3 +7,2 @@ <p> | ||
[![turborepo](https://img.shields.io/badge/built%20with-turborepo-cc00ff.svg?style=for-the-badge&logo=turborepo)](https://turborepo.org/) | ||
[![size](https://img.shields.io/bundlephobia/minzip/@solid-primitives/audio?style=for-the-badge)](https://bundlephobia.com/package/@solid-primitives/audio) | ||
@@ -10,0 +9,0 @@ [![size](https://img.shields.io/npm/v/@solid-primitives/audio?style=for-the-badge)](https://www.npmjs.com/package/@solid-primitives/audio) |
16180
5
276
130
+ Added@solid-primitives/static-store@0.1.0(transitive)
- Removed@solid-primitives/static-store@0.0.9(transitive)