@parent-tobias/chord-component 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tobias Padilla
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,359 @@
1
+ # chord-component
2
+
3
+ Lit-based web components for displaying musical chord diagrams and chord lists across various string instruments.
4
+
5
+ ## Features
6
+
7
+ - 🎸 Support for multiple instruments (Ukulele, Guitar, Mandolin)
8
+ - 🎵 Comprehensive chord library with major, minor, 7th, and extended chords
9
+ - ✏️ **Interactive chord editor** for creating custom fingerings
10
+ - 💾 **Persistent storage** with IndexedDB for user-defined chords
11
+ - 🎯 **High-position chord support** with automatic position markers
12
+ - 📱 Responsive design with container queries
13
+ - 🎨 Dark theme optimized
14
+ - ⚡ Built with Lit for fast, efficient rendering
15
+ - 🔧 TypeScript support with full type definitions
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install chord-component
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### Import and use in HTML
26
+
27
+ ```html
28
+ <!DOCTYPE html>
29
+ <html>
30
+ <head>
31
+ <script type="module">
32
+ import 'chord-component';
33
+ </script>
34
+ </head>
35
+ <body>
36
+ <!-- Single chord diagram -->
37
+ <chord-diagram chord="C" instrument="Standard Ukulele"></chord-diagram>
38
+
39
+ <!-- Chord list -->
40
+ <chord-list
41
+ instrument="Standard Ukulele"
42
+ chords='["C", "F", "G", "Am"]'>
43
+ </chord-list>
44
+ </body>
45
+ </html>
46
+ ```
47
+
48
+ ### Import specific components
49
+
50
+ ```javascript
51
+ import 'chord-component/chord-diagram';
52
+ import 'chord-component/chord-list';
53
+ import 'chord-component/chord-editor';
54
+ ```
55
+
56
+ ### Import utilities and services
57
+
58
+ ```javascript
59
+ import {
60
+ instruments,
61
+ chordToNotes,
62
+ systemDefaultChords,
63
+ chordDataService, // Data management service
64
+ indexedDBService // IndexedDB wrapper
65
+ } from 'chord-component';
66
+ ```
67
+
68
+ ## Components
69
+
70
+ ### `<chord-diagram>`
71
+
72
+ Displays a single chord diagram with fretboard visualization.
73
+
74
+ #### Attributes
75
+
76
+ - **`chord`** (string, required): The chord name (e.g., "C", "Am7", "F#dim")
77
+ - **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
78
+
79
+ #### Examples
80
+
81
+ ```html
82
+ <!-- Basic usage -->
83
+ <chord-diagram chord="C"></chord-diagram>
84
+
85
+ <!-- Guitar chord -->
86
+ <chord-diagram chord="Em" instrument="Standard Guitar"></chord-diagram>
87
+
88
+ <!-- Complex chord -->
89
+ <chord-diagram chord="Cmaj7" instrument="Standard Ukulele"></chord-diagram>
90
+ ```
91
+
92
+ ### `<chord-list>`
93
+
94
+ Displays multiple chord diagrams in a responsive grid layout.
95
+
96
+ #### Attributes
97
+
98
+ - **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
99
+ - **`chords`** (string|array, required): JSON string or array of chord names
100
+
101
+ #### Examples
102
+
103
+ ```html
104
+ <!-- Array of chords -->
105
+ <chord-list
106
+ instrument="Standard Ukulele"
107
+ chords='["C", "F", "G", "Am"]'>
108
+ </chord-list>
109
+
110
+ <!-- More complex chord progression -->
111
+ <chord-list
112
+ instrument="Standard Guitar"
113
+ chords='["Cmaj7", "Dm7", "G7", "Em7", "Am7"]'>
114
+ </chord-list>
115
+ ```
116
+
117
+ ### `<chord-editor>` ✨ NEW
118
+
119
+ **Interactive editor for creating and customizing chord diagrams.**
120
+
121
+ Create custom chord fingerings with visual and text-based editing. All custom chords are automatically saved to IndexedDB and persist across sessions.
122
+
123
+ #### Attributes
124
+
125
+ - **`chord`** (string, required): The chord name to edit
126
+ - **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
127
+
128
+ #### Events
129
+
130
+ - **`chord-saved`**: Fired when user saves a custom chord
131
+ - **`chord-reset`**: Fired when user resets to default
132
+
133
+ #### Examples
134
+
135
+ ```html
136
+ <!-- Basic editor -->
137
+ <chord-editor chord="C" instrument="Standard Ukulele"></chord-editor>
138
+
139
+ <!-- Listen for save events -->
140
+ <script type="module">
141
+ const editor = document.querySelector('chord-editor');
142
+
143
+ editor.addEventListener('chord-saved', (e) => {
144
+ console.log('Saved:', e.detail.chord, e.detail.data);
145
+ });
146
+ </script>
147
+ ```
148
+
149
+ #### Features
150
+
151
+ - **Visual editing**: Click on diagram to add/remove finger positions
152
+ - **Text-based editing**: Edit finger and barre positions with input fields
153
+ - **Add buttons**: Quickly add new fingers or barres
154
+ - **View position control**: Adjust display window for high-position chords
155
+ - **Auto-save to IndexedDB**: Custom chords persist across sessions
156
+ - **Reset to default**: Revert to system defaults anytime
157
+
158
+ See [CHORD_EDITOR.md](./CHORD_EDITOR.md) for complete documentation.
159
+
160
+ #### Creating Custom Chords
161
+
162
+ ```javascript
163
+ import { chordDataService } from 'chord-component';
164
+
165
+ // Programmatically save a custom chord
166
+ await chordDataService.saveUserChord('Standard Ukulele', 'C', {
167
+ fingers: [[4, 0], [3, 0], [2, 0], [1, 3]],
168
+ barres: []
169
+ });
170
+
171
+ // Get all user-defined chords
172
+ const userChords = await chordDataService.getAllUserChords();
173
+
174
+ // Delete a custom chord (revert to default)
175
+ await chordDataService.deleteUserChord('Standard Ukulele', 'C');
176
+ ```
177
+
178
+ ## Supported Instruments
179
+
180
+ - **Standard Ukulele** (G-C-E-A tuning)
181
+ - **Baritone Ukulele** (D-G-B-E tuning)
182
+ - **5ths tuned Ukulele** (C-G-D-A tuning)
183
+ - **Standard Guitar** (E-A-D-G-B-E tuning)
184
+ - **Drop-D Guitar** (D-A-D-G-B-E tuning)
185
+ - **Standard Mandolin** (G-D-A-E tuning)
186
+
187
+ ## Supported Chord Types
188
+
189
+ - **Major**: C, D, E, F, G, A, B
190
+ - **Minor**: Cm, Dm, Em, etc.
191
+ - **Dominant 7th**: C7, D7, G7, etc.
192
+ - **Major 7th**: Cmaj7, Fmaj7, etc.
193
+ - **Minor 7th**: Cm7, Am7, etc.
194
+ - **Diminished**: Cdim, F#dim, etc.
195
+ - **Augmented**: Caug, etc.
196
+ - **Suspended**: Csus2, Csus4, etc.
197
+ - **Extended**: C9, C11, C13, etc.
198
+ - **Add chords**: Cadd9, etc.
199
+
200
+ ## Development
201
+
202
+ ### Setup
203
+
204
+ ```bash
205
+ git clone <repository-url>
206
+ cd chord-components
207
+ npm install
208
+ ```
209
+
210
+ ### Development Server
211
+
212
+ ```bash
213
+ npm run dev
214
+ ```
215
+
216
+ This starts a development server with the demo page at `http://localhost:5173/demo/`
217
+
218
+ ### Build
219
+
220
+ ```bash
221
+ npm run build
222
+ ```
223
+
224
+ ### Lint
225
+
226
+ ```bash
227
+ npm run lint
228
+ ```
229
+
230
+ ## Customization
231
+
232
+ ### Custom Chord Definitions
233
+
234
+ #### Using the Chord Editor (Recommended)
235
+
236
+ The easiest way to create custom chords is using the interactive `<chord-editor>` component:
237
+
238
+ ```html
239
+ <chord-editor chord="Csus2" instrument="Standard Ukulele"></chord-editor>
240
+ ```
241
+
242
+ Custom chords are automatically saved to IndexedDB and will be used by all `<chord-diagram>` components.
243
+
244
+ See the [interactive demo](./demo/editor.html) for hands-on examples.
245
+
246
+ #### Programmatic API
247
+
248
+ ```javascript
249
+ import { chordDataService } from 'chord-component';
250
+
251
+ // Save a custom chord
252
+ await chordDataService.saveUserChord('Standard Ukulele', 'Csus2', {
253
+ barres: [],
254
+ fingers: [[4, 0], [3, 2], [2, 3], [1, 0]]
255
+ });
256
+
257
+ // Get chord data (user override if exists, otherwise system default)
258
+ const chord = await chordDataService.getChord('Standard Ukulele', 'C');
259
+ ```
260
+
261
+ #### Modifying System Defaults
262
+
263
+ You can also extend the system defaults (not recommended for user preferences):
264
+
265
+ ```javascript
266
+ import { systemDefaultChords } from 'chord-component';
267
+
268
+ // Add to system defaults
269
+ systemDefaultChords["Standard Ukulele"]["Csus2"] = {
270
+ barres: [],
271
+ fingers: [[4, 0], [3, 2], [2, 3], [1, 0]]
272
+ };
273
+ ```
274
+
275
+ ### Styling
276
+
277
+ The components use CSS custom properties for theming. You can override the default dark theme:
278
+
279
+ ```css
280
+ chord-diagram {
281
+ --chord-bg-color: #ffffff;
282
+ --chord-text-color: #000000;
283
+ --chord-border-color: #cccccc;
284
+ }
285
+ ```
286
+
287
+ ## API Reference
288
+
289
+ ### Music Utilities
290
+
291
+ The package exports several utility functions for working with music theory:
292
+
293
+ ```javascript
294
+ import {
295
+ instruments, // Array of supported instruments
296
+ chordToNotes, // Convert chord name to note array
297
+ parseChords, // Parse chords from ChordPro notation
298
+ scaleTones, // Get notes in a scale
299
+ findBase // Find note index in chromatic scale
300
+ } from 'chord-component';
301
+
302
+ // Example usage
303
+ const chordData = chordToNotes("Cmaj7");
304
+ console.log(chordData); // { name: "Cmaj7", notes: ["C", "E", "G", "B"] }
305
+ ```
306
+
307
+ ### Data Management Services
308
+
309
+ The package includes services for managing chord data:
310
+
311
+ ```javascript
312
+ import { chordDataService, indexedDBService } from 'chord-component';
313
+
314
+ // Chord Data Service
315
+ await chordDataService.getChordData('Standard Ukulele');
316
+ await chordDataService.saveUserChord(instrument, chord, data);
317
+ await chordDataService.getAllUserChords();
318
+ await chordDataService.clearCache();
319
+
320
+ // IndexedDB Service (low-level)
321
+ await indexedDBService.saveUserChord(instrument, chord, data);
322
+ await indexedDBService.getUserChord(instrument, chord);
323
+ ```
324
+
325
+ See [DATA_SERVICE.md](./DATA_SERVICE.md) for complete API documentation.
326
+
327
+ ## Documentation
328
+
329
+ Comprehensive guides for advanced features:
330
+
331
+ - **[CHORD_EDITOR.md](./CHORD_EDITOR.md)** - Complete chord editor documentation
332
+ - **[INTERACTIVE_EDITING.md](./INTERACTIVE_EDITING.md)** - Visual and text-based editing workflows
333
+ - **[VIEW_POSITION.md](./VIEW_POSITION.md)** - Understanding the display window system
334
+ - **[DATA_SERVICE.md](./DATA_SERVICE.md)** - Data caching and API integration
335
+ - **[POSITION_SUPPORT.md](./POSITION_SUPPORT.md)** - High-position chords and neck positions
336
+
337
+ ## Demo
338
+
339
+ Run the demo locally:
340
+
341
+ ```bash
342
+ npm run dev
343
+ ```
344
+
345
+ Then visit:
346
+ - `http://localhost:5173/demo/` - Chord diagram and list examples
347
+ - `http://localhost:5173/demo/editor.html` - Interactive chord editor
348
+
349
+ ## License
350
+
351
+ MIT
352
+
353
+ ## Contributing
354
+
355
+ Contributions are welcome! Please feel free to submit issues and pull requests.
356
+
357
+ ## Support
358
+
359
+ For questions and support, please open an issue on the GitHub repository.
@@ -0,0 +1,190 @@
1
+ import { indexedDBService as t } from "./indexed-db-service.js";
2
+ import { systemDefaultChords as c } from "./default-chords.js";
3
+ class i {
4
+ constructor() {
5
+ this.useRemoteAPI = !1, this.apiEndpoint = "";
6
+ }
7
+ /**
8
+ * Configure the service to use a remote API endpoint
9
+ */
10
+ configureAPI(a) {
11
+ this.apiEndpoint = a, this.useRemoteAPI = !0;
12
+ }
13
+ /**
14
+ * Disable remote API and use local data
15
+ */
16
+ disableAPI() {
17
+ this.useRemoteAPI = !1;
18
+ }
19
+ /**
20
+ * Get chord data for a specific instrument
21
+ * This method implements the fallback chain: IndexedDB -> API -> Local
22
+ */
23
+ async getChordData(a) {
24
+ try {
25
+ const e = await t.getChordData(a);
26
+ if (e && e.chords)
27
+ return console.log(`[ChordDataService] Loaded ${a} from IndexedDB cache`), {
28
+ data: e.chords,
29
+ source: { type: "indexeddb", timestamp: e.timestamp }
30
+ };
31
+ } catch (e) {
32
+ console.warn("[ChordDataService] IndexedDB error, falling back:", e);
33
+ }
34
+ if (this.useRemoteAPI && this.apiEndpoint)
35
+ try {
36
+ const e = await this.fetchFromAPI(a);
37
+ if (e)
38
+ return console.log(`[ChordDataService] Loaded ${a} from remote API`), await this.cacheChordData(a, e), {
39
+ data: e,
40
+ source: { type: "api", timestamp: Date.now() }
41
+ };
42
+ } catch (e) {
43
+ console.warn("[ChordDataService] API fetch error, falling back to local:", e);
44
+ }
45
+ console.log(`[ChordDataService] Loaded ${a} from local defaults`);
46
+ const r = c[a] || {};
47
+ return await this.cacheChordData(a, r), {
48
+ data: r,
49
+ source: { type: "local", timestamp: Date.now() }
50
+ };
51
+ }
52
+ /**
53
+ * Fetch chord data from remote API
54
+ * This is a placeholder that can be implemented when API is ready
55
+ */
56
+ async fetchFromAPI(a) {
57
+ if (!this.apiEndpoint)
58
+ return null;
59
+ try {
60
+ const r = `${this.apiEndpoint}?instrument=${encodeURIComponent(a)}`, e = await fetch(r);
61
+ if (!e.ok)
62
+ throw new Error(`API request failed: ${e.status} ${e.statusText}`);
63
+ const s = await e.json();
64
+ return s.chords || s;
65
+ } catch (r) {
66
+ return console.error("[ChordDataService] API fetch error:", r), null;
67
+ }
68
+ }
69
+ /**
70
+ * Cache chord data in IndexedDB
71
+ */
72
+ async cacheChordData(a, r) {
73
+ try {
74
+ await t.setChordData(a, r), console.log(`[ChordDataService] Cached ${a} in IndexedDB`);
75
+ } catch (e) {
76
+ console.warn("[ChordDataService] Failed to cache in IndexedDB:", e);
77
+ }
78
+ }
79
+ /**
80
+ * Get all available instruments from local defaults
81
+ * In the future, this could also query the API
82
+ */
83
+ getAvailableInstruments() {
84
+ return Object.keys(c);
85
+ }
86
+ /**
87
+ * Clear all cached data from IndexedDB
88
+ */
89
+ async clearCache() {
90
+ await t.clearAll(), console.log("[ChordDataService] Cache cleared");
91
+ }
92
+ /**
93
+ * Force refresh data from source (API or local) and update cache
94
+ */
95
+ async refreshData(a) {
96
+ if (this.useRemoteAPI && this.apiEndpoint)
97
+ try {
98
+ const e = await this.fetchFromAPI(a);
99
+ if (e)
100
+ return await this.cacheChordData(a, e), {
101
+ data: e,
102
+ source: { type: "api", timestamp: Date.now() }
103
+ };
104
+ } catch (e) {
105
+ console.warn("[ChordDataService] Refresh from API failed:", e);
106
+ }
107
+ const r = c[a] || {};
108
+ return await this.cacheChordData(a, r), {
109
+ data: r,
110
+ source: { type: "local", timestamp: Date.now() }
111
+ };
112
+ }
113
+ /**
114
+ * Check if a specific chord exists for an instrument
115
+ */
116
+ async hasChord(a, r) {
117
+ const e = await this.getChordData(a);
118
+ return r in e.data;
119
+ }
120
+ /**
121
+ * Get data for a specific chord
122
+ * @param instrument - The instrument name
123
+ * @param chordName - The chord name
124
+ * @param preferUser - If true, returns user override if it exists; if false, returns system default only
125
+ */
126
+ async getChord(a, r, e = !0) {
127
+ if (e)
128
+ try {
129
+ const o = await t.getUserChord(a, r);
130
+ if (o)
131
+ return {
132
+ fingers: o.fingers,
133
+ barres: o.barres,
134
+ position: o.position
135
+ };
136
+ } catch (o) {
137
+ console.warn("[ChordDataService] Failed to get user chord:", o);
138
+ }
139
+ return (await this.getChordData(a)).data[r] || null;
140
+ }
141
+ /**
142
+ * Save a user-defined chord override
143
+ */
144
+ async saveUserChord(a, r, e) {
145
+ await t.saveUserChord(a, r, e), console.log(`[ChordDataService] Saved user chord: ${a} - ${r}`);
146
+ }
147
+ /**
148
+ * Delete a user-defined chord override (revert to system default)
149
+ */
150
+ async deleteUserChord(a, r) {
151
+ await t.deleteUserChord(a, r), console.log(`[ChordDataService] Deleted user chord: ${a} - ${r}`);
152
+ }
153
+ /**
154
+ * Get all user-defined chords for an instrument
155
+ */
156
+ async getUserChordsByInstrument(a) {
157
+ return (await t.getUserChordsByInstrument(a)).map((e) => ({
158
+ chordName: e.chordName,
159
+ data: {
160
+ fingers: e.fingers,
161
+ barres: e.barres,
162
+ position: e.position
163
+ }
164
+ }));
165
+ }
166
+ /**
167
+ * Get all user-defined chords across all instruments
168
+ */
169
+ async getAllUserChords() {
170
+ return (await t.getAllUserChords()).map((r) => ({
171
+ instrument: r.instrument,
172
+ chordName: r.chordName,
173
+ data: {
174
+ fingers: r.fingers,
175
+ barres: r.barres,
176
+ position: r.position
177
+ }
178
+ }));
179
+ }
180
+ /**
181
+ * Clear all user-defined chord overrides
182
+ */
183
+ async clearUserChords() {
184
+ await t.clearUserChords(), console.log("[ChordDataService] Cleared all user chords");
185
+ }
186
+ }
187
+ const l = new i();
188
+ export {
189
+ l as chordDataService
190
+ };