@joknoll/svelte-attach-sound 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# svelte-attach-sound
|
|
2
|
+
|
|
3
|
+
A Svelte attachment for binding sound playback to DOM events using the [Svelte 5 attachments API](https://svelte.dev/docs/svelte/attachments).
|
|
4
|
+
|
|
5
|
+
You can find CC-Zero licensed sounds at [freesound.org](https://freesound.org/)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install @joknoll/svelte-attach-sound
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```svelte
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import { sound, useSound } from "@joknoll/svelte-attach-sound";
|
|
18
|
+
import click_mp3 from "$lib/assets/click.mp3";
|
|
19
|
+
|
|
20
|
+
const click = useSound(click_mp3, ["pointerdown"]);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<!-- Inline -->
|
|
24
|
+
<button {@attach sound({ src: click_mp3, events: ["click"] })}>Click</button>
|
|
25
|
+
<button {@attach sound({ src: click_mp3, events: ["mouseenter"] })}>Enter</button>
|
|
26
|
+
|
|
27
|
+
<!-- Factory: reusable with shared defaults -->
|
|
28
|
+
<button {@attach click()}>Click</button>
|
|
29
|
+
<button {@attach click({ volume: 0.5 })}>Click (quieter)</button>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
[Demo](https://joknoll.github.io/svelte-attach-sound/) | [npm](https://www.npmjs.com/package/svelte-attach-sound)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Attachment } from "svelte/attachments";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
type SoundSource = string;
|
|
5
|
+
type SoundEvents = [keyof HTMLElementEventMap, (keyof HTMLElementEventMap)?];
|
|
6
|
+
type SoundOptions = {
|
|
7
|
+
/** Playback volume, 0.0 to 1.0. Default: 1. */volume?: number; /** Whether the sound loops. Default: false. */
|
|
8
|
+
loop?: boolean; /** Playback rate multiplier. Default: 1. */
|
|
9
|
+
rate?: number;
|
|
10
|
+
};
|
|
11
|
+
type Options = {
|
|
12
|
+
src: SoundSource;
|
|
13
|
+
events: SoundEvents;
|
|
14
|
+
} & SoundOptions;
|
|
15
|
+
declare class Sound {
|
|
16
|
+
private buffer;
|
|
17
|
+
private source;
|
|
18
|
+
private token;
|
|
19
|
+
private options;
|
|
20
|
+
constructor(src: SoundSource, options?: SoundOptions);
|
|
21
|
+
private load;
|
|
22
|
+
play(): void;
|
|
23
|
+
stop(): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a sound attachment that binds playback to DOM events on the element.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```svelte
|
|
30
|
+
* <button {@attach sound({ src: click_mp3, events: ["click"] })}>
|
|
31
|
+
* Click me
|
|
32
|
+
* </button>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare function sound(options: Options): Attachment<HTMLElement>;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a pre-configured sound attachment factory reusable across elements.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```svelte
|
|
41
|
+
* <script>
|
|
42
|
+
* import { useSound } from "svelte-attach-sound";
|
|
43
|
+
* import click_mp3 from "./assets/click.mp3";
|
|
44
|
+
*
|
|
45
|
+
* const click = useSound(click_mp3, ["click"]);
|
|
46
|
+
* </script>
|
|
47
|
+
*
|
|
48
|
+
* <button {@attach click()}>Click me</button>
|
|
49
|
+
* <button {@attach click({ volume: 0.5 })}>Quieter</button>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function useSound(src: SoundSource, events: SoundEvents, options?: SoundOptions): (overrideOptions?: SoundOptions) => Attachment<HTMLElement>;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Sound, sound, useSound };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{on as e}from"svelte/events";let t=null;function n(){return typeof AudioContext>`u`?null:t??=new AudioContext}var r=class{buffer;source=null;token=0;options;constructor(e,t={}){this.options=t,this.buffer=this.load(e)}async load(e){let t=n();if(!t)return null;try{let n=await(await fetch(e)).arrayBuffer();return await t.decodeAudioData(n)}catch(t){return console.warn(`[svelte-attach-sound] Failed to load sound:`,e,t),null}}play(){let e=this.token;this.buffer.then(t=>{if(!t||e!==this.token)return;let r=n();if(!r)return;r.resume();let i=r.createBufferSource();i.buffer=t,i.loop=this.options.loop??!1,i.playbackRate.value=this.options.rate??1;let a=r.createGain();a.gain.value=this.options.volume??1,i.connect(a).connect(r.destination),this.source=i,i.start()})}stop(){this.token+=1;try{this.source?.stop()}catch{}this.source=null}};function i(t){return n=>{let{src:i,events:a,...o}=t,[s,c]=a,l=new r(i,o),u=e(n,s,()=>l.play()),d=c?e(n,c,()=>l.stop()):null;return()=>{u(),d?.(),l.stop()}}}function a(e,t,n){return r=>i({src:e,events:t,...n,...r})}export{r as Sound,i as sound,a as useSound};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@joknoll/svelte-attach-sound",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Svelte attachment for binding sound playback to DOM events using the Web Audio API.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"attachment",
|
|
7
|
+
"sound",
|
|
8
|
+
"svelte",
|
|
9
|
+
"svelte5",
|
|
10
|
+
"web-audio"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/joknoll/svelte-attach/tree/main/packages/sound#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/joknoll/svelte-attach/issues"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "joknoll",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/joknoll/svelte-attach.git",
|
|
21
|
+
"directory": "packages/sound"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./dist/index.js",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^25.6.2",
|
|
37
|
+
"@typescript/native-preview": "7.0.0-dev.20260509.2",
|
|
38
|
+
"bumpp": "^11.1.0",
|
|
39
|
+
"jsdom": "^29.0.1",
|
|
40
|
+
"svelte": "^5.55.0",
|
|
41
|
+
"typescript": "^6.0.3",
|
|
42
|
+
"vite-plus": "latest"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"svelte": ">=5.55.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "vp pack",
|
|
49
|
+
"dev": "vp pack --watch",
|
|
50
|
+
"test": "vp test",
|
|
51
|
+
"check": "vp check"
|
|
52
|
+
}
|
|
53
|
+
}
|