@solid-primitives/audio
Advanced tools
Comparing version
@@ -0,1 +1,3 @@ | ||
import { Accessor } from 'solid-js'; | ||
declare enum AudioState { | ||
@@ -7,19 +9,15 @@ LOADING = "loading", | ||
STOPPED = "stopped", | ||
READY = "ready" | ||
READY = "ready", | ||
ERROR = "error" | ||
} | ||
declare type AudioSource = string | MediaSource | (string & MediaSource) | (() => string | MediaSource | (string & MediaSource)); | ||
/** | ||
* Creates an extremely basic audio generator method. | ||
* 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 | ||
* @return A basic audio player instance | ||
*/ | ||
declare const createAudioPlayer: (src: AudioSource, handlers: Array<[string, EventListener]>) => { | ||
player: HTMLAudioElement; | ||
state: () => AudioState; | ||
setState: (state: AudioState) => void; | ||
}; | ||
declare const makeAudio: (src: AudioSource, handlers?: AudioEventHandlers) => HTMLAudioElement; | ||
/** | ||
* Creates a simple audio manager with basic pause and play. | ||
* Generates a basic audio player with simple control mechanisms. | ||
* | ||
@@ -29,4 +27,6 @@ * @param src Audio file path or MediaSource to be played | ||
* @return options.start - Start playing | ||
* @return options.stop - Stop playing | ||
* @return options.state - Current state of the player as a Symbol | ||
* @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 | ||
@@ -36,42 +36,45 @@ * | ||
* ```ts | ||
* const [start, pause] = createAudio('./example1.mp3); | ||
* const { start, seek } = makeAudioPlayer('./example1.mp3); | ||
* ``` | ||
*/ | ||
declare const createAudio: (src: AudioSource) => { | ||
play: () => void; | ||
pause: () => void; | ||
state: () => AudioState; | ||
declare const makeAudioPlayer: (src: AudioSource, handlers?: AudioEventHandlers) => { | ||
play: VoidFunction; | ||
pause: VoidFunction; | ||
seek: (time: number) => void; | ||
setVolume: (volume: number) => void; | ||
player: HTMLAudioElement; | ||
}; | ||
/** | ||
* Creates a simple audio manager with most control actions. | ||
* A reactive audio primitive with basic control actions. | ||
* | ||
* @param src Audio file path or MediaSource to be played | ||
* @param volume Volume setting for the audio file | ||
* @return options - @type Object | ||
* @return options.start - Start playing | ||
* @return options.stop - Stop playing | ||
* @return options.currentTime - Current time that the player is at | ||
* @return options.state - Current state of the player as a Symbol | ||
* @return options.duration - Duration of the audio clip | ||
* @return options.seek - A function to support seeking | ||
* @return options.setVolume - A function to change the volume setting | ||
* @return Returns a location signal and one-off async query callback | ||
* @param src Audio source path or MediaSource to be played or an accessor | ||
* @param playing A signal for controlling the player | ||
* @param playerhead A signal for controlling the playhead location | ||
* @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 - Duratio of the audio player | ||
* | ||
* @example | ||
* ```ts | ||
* const [start, pause, seek, currentTime, duration] = createAudioManager('./example1.mp3); | ||
* const [playing, setPlaying] = createSignal(false); | ||
* const [volume, setVolume] = createSignal(1); | ||
* const audio = createAudio('./example1.mp3', playing, volume); | ||
* console.log(audio.duration); | ||
* ``` | ||
*/ | ||
declare const createAudioManager: (src: AudioSource, volume?: number) => { | ||
play: () => void; | ||
pause: () => void; | ||
state: () => AudioState; | ||
currentTime: () => number; | ||
duration: () => number; | ||
declare const createAudio: (src: AudioSource | Accessor<AudioSource>, playing?: Accessor<boolean> | undefined, volume?: Accessor<number> | undefined) => [{ | ||
state: AudioState; | ||
currentTime: number; | ||
duration: number; | ||
volume: number; | ||
player: HTMLAudioElement; | ||
}, { | ||
seek: (time: number) => void; | ||
setVolume: (volume: number) => void; | ||
seek: (position: number) => void; | ||
player: HTMLAudioElement; | ||
}; | ||
play: VoidFunction; | ||
pause: VoidFunction; | ||
}]; | ||
export { AudioState, createAudio, createAudioManager, createAudioPlayer }; | ||
export { AudioState, createAudio, makeAudio, makeAudioPlayer }; |
@@ -1,68 +0,12 @@ | ||
// src/index.ts | ||
import { createSignal, batch, onMount, onCleanup, createEffect } from "solid-js"; | ||
var AudioState = /* @__PURE__ */ ((AudioState2) => { | ||
AudioState2["LOADING"] = "loading"; | ||
AudioState2["PLAYING"] = "playing"; | ||
AudioState2["PAUSED"] = "paused"; | ||
AudioState2["COMPLETE"] = "complete"; | ||
AudioState2["STOPPED"] = "stopped"; | ||
AudioState2["READY"] = "ready"; | ||
return AudioState2; | ||
})(AudioState || {}); | ||
var createAudioPlayer = (src, handlers) => { | ||
const [state, setState] = createSignal("stopped" /* STOPPED */); | ||
const player = new Audio(); | ||
if (src instanceof Function) { | ||
const srcKey = typeof src() === "string" ? "src" : "srcObject"; | ||
player[srcKey] = src(); | ||
createEffect(() => player[srcKey] = src()); | ||
} else { | ||
player[typeof src === "string" ? "src" : "srcObject"] = src; | ||
} | ||
onMount(() => handlers.forEach(([evt, handler]) => player.addEventListener(evt, handler))); | ||
onCleanup(() => handlers.forEach(([evt, handler]) => player.removeEventListener(evt, handler))); | ||
return { player, state, setState }; | ||
}; | ||
var createAudio = (src) => { | ||
const { player, state, setState } = createAudioPlayer(src, [ | ||
["loadeddata", () => setState("ready" /* READY */)], | ||
["loadstart", () => setState("loading" /* LOADING */)], | ||
["playing", () => setState("playing" /* PLAYING */)], | ||
["pause", () => setState("paused" /* PAUSED */)] | ||
]); | ||
const play = () => player.play(); | ||
const pause = () => player.pause(); | ||
return { play, pause, state, player }; | ||
}; | ||
var createAudioManager = (src, volume = 1) => { | ||
const [currentTime, setCurrentTime] = createSignal(0); | ||
const [duration, setDuration] = createSignal(0); | ||
const { player, state, setState } = createAudioPlayer(src, [ | ||
[ | ||
"loadeddata", | ||
() => batch(() => { | ||
setState("ready" /* READY */); | ||
setDuration(player.duration); | ||
}) | ||
], | ||
["loadstart", () => setState("loading" /* LOADING */)], | ||
["playing", () => setState("playing" /* PLAYING */)], | ||
["pause", () => setState("paused" /* PAUSED */)], | ||
["loadstart", () => setState("loading" /* LOADING */)], | ||
["playing", () => setState("playing" /* PLAYING */)], | ||
["pause", () => setState("paused" /* PAUSED */)], | ||
["timeupdate", () => setCurrentTime(player.currentTime)] | ||
]); | ||
const play = () => player.play(); | ||
const pause = () => player.pause(); | ||
const seek = (time) => player.fastSeek(time); | ||
const setVolume = (volume2) => player.volume = volume2; | ||
createEffect(() => player.volume = volume); | ||
return { play, pause, currentTime, state, duration, seek, setVolume, player }; | ||
}; | ||
import { | ||
AudioState, | ||
createAudio, | ||
makeAudio, | ||
makeAudioPlayer | ||
} from "./chunk-JBHTPEQN.js"; | ||
export { | ||
AudioState, | ||
createAudio, | ||
createAudioManager, | ||
createAudioPlayer | ||
makeAudio, | ||
makeAudioPlayer | ||
}; |
@@ -0,40 +1,36 @@ | ||
import { | ||
AudioState | ||
} from "./chunk-JBHTPEQN.js"; | ||
// src/server.ts | ||
var createAudioPlayer = (_src, _handlers) => { | ||
return { | ||
player: {}, | ||
state: () => AudioState.LOADING, | ||
setState: (_state) => { | ||
} | ||
}; | ||
}; | ||
var createAudio = (_src) => { | ||
return { | ||
play: () => { | ||
}, | ||
pause: () => { | ||
}, | ||
state: () => AudioState.LOADING, | ||
import { noop } from "@solid-primitives/utils"; | ||
var AudioState2 = AudioState; | ||
var makeAudio = () => ({}); | ||
var makeAudioPlayer = () => ({ | ||
pause: noop, | ||
play: noop, | ||
player: {}, | ||
seek: noop, | ||
setVolume: noop | ||
}); | ||
var createAudio = () => [ | ||
{ | ||
state: AudioState2.LOADING, | ||
currentTime: 0, | ||
duration: 0, | ||
volume: 0, | ||
player: {} | ||
}; | ||
}; | ||
var createAudioManager = (_src, _volume = 1) => { | ||
return { | ||
play: () => { | ||
}, | ||
pause: () => { | ||
}, | ||
currentTime: () => 0, | ||
state: () => AudioState.LOADING, | ||
duration: () => 0, | ||
seek: () => { | ||
}, | ||
setVolume: () => { | ||
}, | ||
player: {} | ||
}; | ||
}; | ||
}, | ||
{ | ||
seek: noop, | ||
setVolume: noop, | ||
play: noop, | ||
pause: noop | ||
} | ||
]; | ||
export { | ||
AudioState2 as AudioState, | ||
createAudio, | ||
createAudioManager, | ||
createAudioPlayer | ||
makeAudio, | ||
makeAudioPlayer | ||
}; |
{ | ||
"name": "@solid-primitives/audio", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Primitives to manage audio and single sounds.", | ||
@@ -16,5 +16,5 @@ "author": "David Di Biase <dave.dibiase@gmail.com>", | ||
"list": [ | ||
"createAudio", | ||
"createAudioPlayer", | ||
"createAudioManager" | ||
"makeAudio", | ||
"makeAudioPlayer", | ||
"createAudio" | ||
], | ||
@@ -41,5 +41,6 @@ "category": "Display & Media" | ||
"scripts": { | ||
"start": "vite -r ./dev/ -c ./dev/vite.config.ts", | ||
"start": "vite serve dev", | ||
"dev": "vite serve dev", | ||
"build": "tsup", | ||
"test": "echo disabled defunct jest test suite" | ||
"test": "uvu -b -r solid-register" | ||
}, | ||
@@ -51,40 +52,26 @@ "keywords": [ | ||
], | ||
"testEnvironment": "jsdom", | ||
"devDependencies": { | ||
"@babel/preset-env": "^7.15.8", | ||
"@types/jest": "^27.4.0", | ||
"babel-preset-solid": "^1.1.5", | ||
"jest": "^27.4.7", | ||
"@babel/preset-env": "^7.18.2", | ||
"babel-preset-solid": "^1.4.4", | ||
"jsdom": "^19.0.0", | ||
"prettier": "^2.0.5", | ||
"prettier": "^2.7.1", | ||
"solid-heroicons": "^2.0.3", | ||
"solid-register": "^0.2.5", | ||
"solid-testing-library": "^0.2.0", | ||
"ts-jest": "^27.0.5", | ||
"tslib": "^2.0.1", | ||
"tsup": "^5.10.0", | ||
"typescript": "^4.0.2" | ||
"tsup": "^6.1.2", | ||
"typescript": "^4.7.4", | ||
"unocss": "^0.39.1", | ||
"uvu": "^0.5.3", | ||
"vite": "^2.9.12", | ||
"vite-plugin-solid": "^2.2.6", | ||
"vitest": "^0.14.2" | ||
}, | ||
"jest": { | ||
"preset": "ts-jest", | ||
"globals": { | ||
"ts-jest": { | ||
"tsconfig": "tsconfig.json", | ||
"babelConfig": { | ||
"presets": [ | ||
"babel-preset-solid", | ||
"@babel/preset-env" | ||
] | ||
} | ||
} | ||
}, | ||
"setupFiles": [ | ||
"./test/setup.ts" | ||
], | ||
"testEnvironment": "jsdom", | ||
"moduleNameMapper": { | ||
"solid-js/web": "<rootDir>/../../node_modules/solid-js/web/dist/web.cjs", | ||
"solid-js": "<rootDir>/../../node_modules/solid-js/dist/solid.cjs" | ||
} | ||
"peerDependencies": { | ||
"solid-js": "^1.4.4" | ||
}, | ||
"peerDependencies": { | ||
"solid-js": "^1.3.1" | ||
"dependencies": { | ||
"@solid-primitives/utils": "^2.1.0" | ||
} | ||
} |
@@ -12,3 +12,3 @@ <p> | ||
Primitive to manage audio playback in the browser. The primitives are easily composable and extended. To create your own audio element, consider using createAudioPlayer which allows you to supply a player instance that matches the built-in standard Audio API. | ||
Primitive to manage audio playback in the browser. The primitives are easily composable and extended. To create your own audio element, consider using makeAudioPlayer which allows you to supply a player instance that matches the built-in standard Audio API. | ||
@@ -27,3 +27,3 @@ Each primitive also exposes the audio instance for further custom extensions. Within an SSR context this audio primitive performs noops but never interrupts the process. Time values and durations are zero'd and in LOADING state. | ||
### createAudioPlayer | ||
### makeAudio | ||
@@ -33,21 +33,88 @@ A foundational primitive with no player controls but exposes the raw player object. | ||
```ts | ||
const { player } = createAudioPlayer("example.wav"); | ||
const player = makeAudio("example.mp3"); | ||
``` | ||
### createAudio | ||
#### Definition | ||
```ts | ||
function makeAudio(src: AudioSource, handlers: AudioEventHandlers = {}): HTMLAudioElement; | ||
``` | ||
### makeAudioPlayer | ||
Provides a very basic interface for wrapping listeners to a supplied or default audio player. | ||
```ts | ||
const { play, pause } = createAudio("example.wav"); | ||
const { play, pause, seek } = makeAudioPlayer("example.mp3"); | ||
``` | ||
### createAudioManager | ||
#### Definition | ||
Creates a very basic audio/sound player. | ||
```ts | ||
function makeAudioPlayer( | ||
src: AudioSource, | ||
handlers: AudioEventHandlers = {} | ||
): { | ||
play: VoidFunction; | ||
pause: VoidFunction; | ||
seek: (time: number) => void; | ||
setVolume: (volume: number) => void; | ||
player: HTMLAudioElement; | ||
}; | ||
``` | ||
The seek function falls back to fastSeek when on [supporting browsers](https://caniuse.com/?search=fastseek). | ||
### createAudio | ||
Creates a very basic audio/sound player with reactive properties to control the audio. Be careful not to destructure the properties provided by the primitive as it will likely break reactivity. | ||
```ts | ||
const { play, pause, duration, currentTime, seek, setVolume } = createAudioManager("example.wav"); | ||
const [playing, setPlaying] = createSignal(false); | ||
const [volume, setVolume] = createSignal(false); | ||
const [playhead, setPlayhead] = createSignal(0); | ||
const audio = createAudio("sample.mp3", playing, playhead, volume); | ||
setPlaying(true); | ||
audio.seek(4000); | ||
``` | ||
The audio primitive exports an reactive properties that provides you access to state, duration and playhead location. | ||
_Note:_ Initializing the primitive with `playing` as true works, however note that the user has to interact with the page first (on a fresh page load). | ||
```ts | ||
function makeAudioPlayer( | ||
src: AudioSource | Accessor<AudioSource>, | ||
playing?: Accessor<boolean>, | ||
volume?: Accessor<number> | ||
): { | ||
seek: (time: number) => void; | ||
state: AudioState; | ||
currentTime: number; | ||
duration: number; | ||
player: HTMLAudioElement; | ||
}; | ||
``` | ||
#### Dynamic audio changes | ||
The source property can be a signal as well as a media source. Upon switching the source via a signal it will continue playing from the head. | ||
```ts | ||
const [src, setSrc] = createSignal("sample.mp3"); | ||
const audio = createAudio(src); | ||
setSrc("sample2.mp3"); | ||
``` | ||
### Audio Source | ||
`createAudio` as well as `makeAudio` and `makeAudioPlayer` all accept MediaSource as a property. | ||
```ts | ||
const media = new MediaSource(); | ||
const audio = createAudio(URL.createObjectURL(media)); | ||
``` | ||
This allows you to managed streamed or Blob supplied media. In essence the primitives in this package are very flexible and allow direct access to the base browser API. | ||
## Demo | ||
@@ -82,2 +149,10 @@ | ||
1.2.0 | ||
Major improvements to bring package in line with project standards. | ||
1.3.0 | ||
A major refactor of the `audio` package that includes new basic and reactive primitives. | ||
</details> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
20968
22.05%9
12.5%424
24.71%155
93.75%2
100%15
36.36%+ Added