astro-abcjs 1.0.0 → 2.0.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 +45 -5
- package/package.json +1 -1
- package/src/components/AbcjsPlayer.astro +77 -50
package/README.md
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
1
|
+
|
|
1
2
|
# astro-abcjs
|
|
2
3
|
|
|
3
4
|
An abcjs component for Astro projects.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
### In .astro files
|
|
9
|
+
|
|
10
|
+
Import the component and use it in your Astro page or component:
|
|
11
|
+
|
|
12
|
+
```astro
|
|
13
|
+
---
|
|
14
|
+
import AbcjsPlayer from 'astro-abcjs/AbcjsPlayer.astro';
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<AbcjsPlayer
|
|
18
|
+
notation={`X:1\nT:Scale\nM:4/4\nK:C\nC D E F | G A B c |`}
|
|
19
|
+
showControls={true}
|
|
20
|
+
responsive={true}
|
|
21
|
+
abcjsVersion="6.6.0"
|
|
22
|
+
/>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### In MDX files
|
|
6
26
|
|
|
7
|
-
|
|
27
|
+
First, make sure your project supports MDX and components in MDX.
|
|
28
|
+
|
|
29
|
+
Import the component at the top of your MDX file:
|
|
30
|
+
|
|
31
|
+
```mdx
|
|
32
|
+
import AbcjsPlayer from 'astro-abcjs/AbcjsPlayer.astro';
|
|
33
|
+
|
|
34
|
+
<AbcjsPlayer
|
|
35
|
+
notation={`X:1\nT:Scale\nM:4/4\nK:C\nC D E F | G A B c |`}
|
|
36
|
+
showControls={true}
|
|
37
|
+
responsive={true}
|
|
38
|
+
abcjsVersion="6.6.0"
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Props
|
|
43
|
+
|
|
44
|
+
- `notation` (string, required): The ABC notation string to render.
|
|
45
|
+
- `showControls` (boolean, default: true): Show audio playback controls.
|
|
46
|
+
- `responsive` (boolean, default: true): Make the notation responsive to container size.
|
|
47
|
+
- `abcjsVersion` (string, optional, default: "6.6.0"): The abcjs version to load from CDN. Override to pin or upgrade/downgrade.
|
|
48
|
+
|
|
49
|
+
## Credits & Inspiration
|
|
8
50
|
|
|
9
|
-
|
|
10
|
-
by [Pavlin Gunov](https://www.pavlinbg.com/)
|
|
11
|
-
<https://www.pavlinbg.com/posts/building-a-reusable-music-component-in-astro-using-abcjs>
|
|
51
|
+
This component was inspired by the article [Building a Reusable Music Component in Astro using ABCjs](https://www.pavlinbg.com/posts/building-a-reusable-music-component-in-astro-using-abcjs) by [Pavlin Gunov](https://www.pavlinbg.com/).
|
package/package.json
CHANGED
|
@@ -1,74 +1,101 @@
|
|
|
1
1
|
---
|
|
2
2
|
// AbcjsPlayer.astro
|
|
3
3
|
// Reusable Astro component for rendering ABCjs music notation and audio playback
|
|
4
|
+
|
|
4
5
|
import "abcjs/abcjs-audio.css";
|
|
5
6
|
|
|
7
|
+
// Use official abcjs types
|
|
8
|
+
import type { AbcVisualParams } from "abcjs";
|
|
9
|
+
|
|
10
|
+
// Props interface using official abcjs types
|
|
6
11
|
interface Props {
|
|
7
12
|
notation: string;
|
|
13
|
+
/**
|
|
14
|
+
* Options for abcjs.renderAbc (see AbcVisualParams in abcjs types)
|
|
15
|
+
* Note: Function callbacks (e.g., clickListener) are not supported as options
|
|
16
|
+
* are serialized to JSON for client-side use. For advanced interactivity, use
|
|
17
|
+
* custom events or request a callback/event API.
|
|
18
|
+
*/
|
|
19
|
+
options?: AbcVisualParams;
|
|
20
|
+
/**
|
|
21
|
+
* Show audio playback controls (default: true)
|
|
22
|
+
*/
|
|
8
23
|
showControls?: boolean;
|
|
9
|
-
|
|
24
|
+
/**
|
|
25
|
+
* abcjs version to load from CDN (default: "6.6.0")
|
|
26
|
+
*/
|
|
27
|
+
abcjsVersion?: string;
|
|
10
28
|
}
|
|
11
29
|
|
|
12
|
-
const {
|
|
30
|
+
const {
|
|
31
|
+
notation,
|
|
32
|
+
options = {},
|
|
33
|
+
showControls = true,
|
|
34
|
+
abcjsVersion = "6.6.0",
|
|
35
|
+
} = Astro.props;
|
|
13
36
|
---
|
|
14
37
|
|
|
15
38
|
<div
|
|
16
39
|
class="abcjs-container"
|
|
17
40
|
data-notation={notation}
|
|
18
|
-
data-
|
|
41
|
+
data-options={JSON.stringify(options)}
|
|
19
42
|
>
|
|
20
|
-
<div
|
|
21
|
-
{showControls && <div
|
|
43
|
+
<div class="abcjs-paper"></div>
|
|
44
|
+
{showControls && <div class="abcjs-audio" />}
|
|
22
45
|
</div>
|
|
23
46
|
|
|
24
|
-
<script>
|
|
47
|
+
<script define:vars={{ abcjsVersion, options }}>
|
|
25
48
|
if (typeof window !== "undefined") {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
// Load abcjs browser build from CDN if not already loaded
|
|
50
|
+
if (!window.ABCJS) {
|
|
51
|
+
const script = document.createElement("script");
|
|
52
|
+
script.src = `https://cdn.jsdelivr.net/npm/abcjs@${abcjsVersion}/dist/abcjs-basic.js`;
|
|
53
|
+
script.onload = initializeAbcjs;
|
|
54
|
+
document.head.appendChild(script);
|
|
55
|
+
} else {
|
|
56
|
+
initializeAbcjs();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function initializeAbcjs() {
|
|
60
|
+
const abcjs = window.ABCJS;
|
|
61
|
+
if (!abcjs) return;
|
|
62
|
+
const containers = document.querySelectorAll(".abcjs-container");
|
|
63
|
+
containers.forEach((container) => {
|
|
64
|
+
if (container.dataset.abcjsInitialized === "true") return;
|
|
65
|
+
const notation = container.getAttribute("data-notation");
|
|
66
|
+
if (!notation) return;
|
|
67
|
+
const paperDiv = container.querySelector(".abcjs-paper");
|
|
68
|
+
const audioDiv = container.querySelector(".abcjs-audio");
|
|
69
|
+
// Render music notation using options prop (passed via define:vars)
|
|
70
|
+
// Render music notation using per-container options
|
|
71
|
+
const containerOptions = JSON.parse(
|
|
72
|
+
container.getAttribute("data-options") || "{}",
|
|
73
|
+
);
|
|
74
|
+
const visualObj = abcjs.renderAbc(paperDiv, notation, containerOptions);
|
|
75
|
+
// Audio playback controls
|
|
76
|
+
if (audioDiv && abcjs.synth) {
|
|
77
|
+
const synthControl = new abcjs.synth.SynthController();
|
|
78
|
+
synthControl.load(audioDiv, null, {
|
|
79
|
+
displayLoop: true,
|
|
80
|
+
displayRestart: true,
|
|
81
|
+
displayPlay: true,
|
|
82
|
+
displayProgress: true,
|
|
83
|
+
displayWarp: true,
|
|
45
84
|
});
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
displayWarp: true,
|
|
85
|
+
const createSynth = new abcjs.synth.CreateSynth();
|
|
86
|
+
createSynth
|
|
87
|
+
.init({ visualObj: visualObj[0] })
|
|
88
|
+
.then(() => {
|
|
89
|
+
synthControl.setTune(visualObj[0], false);
|
|
90
|
+
})
|
|
91
|
+
.catch((error) => {
|
|
92
|
+
console.warn("Audio synthesis initialization failed:", error);
|
|
55
93
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
})
|
|
62
|
-
.catch((error) => {
|
|
63
|
-
console.warn("Audio synthesis initialization failed:", error);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
container.dataset.abcjsInitialized = "true";
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
initializeAbcjs();
|
|
70
|
-
document.addEventListener("astro:page-load", initializeAbcjs);
|
|
71
|
-
});
|
|
94
|
+
}
|
|
95
|
+
container.dataset.abcjsInitialized = "true";
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
document.addEventListener("astro:page-load", initializeAbcjs);
|
|
72
99
|
}
|
|
73
100
|
</script>
|
|
74
101
|
|