@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 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)
@@ -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
+ }