riffscore 1.0.0-alpha.2

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.
@@ -0,0 +1,341 @@
1
+ import * as react from 'react';
2
+ import react__default, { ReactNode } from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ declare const THEMES: {
6
+ readonly DARK: {
7
+ accent: "#1DA59C";
8
+ background: "#1e293b";
9
+ panelBackground: "rgba(30, 41, 59, 0.8)";
10
+ text: "#e2e8f0";
11
+ secondaryText: "hsla(215, 20%, 65%, 1.00)";
12
+ border: "rgba(255, 255, 255, 0.1)";
13
+ buttonBackground: "rgba(30, 41, 59, 0.8)";
14
+ buttonHoverBackground: "hsla(218, 33%, 28%, 1.00)";
15
+ score: {
16
+ line: "hsla(215, 16%, 47%, 1.00)";
17
+ note: "#e2e8f0";
18
+ fill: "#e2e8f0";
19
+ };
20
+ };
21
+ readonly COOL: {
22
+ accent: "#22d3ee";
23
+ background: "#0f172a";
24
+ panelBackground: "rgba(15, 23, 42, 0.8)";
25
+ text: "#bfdbfe";
26
+ secondaryText: "#60a5fa";
27
+ border: "rgba(255, 255, 255, 0.1)";
28
+ buttonBackground: "rgba(15, 23, 42, 0.8)";
29
+ buttonHoverBackground: "#1e3a8a";
30
+ score: {
31
+ line: "#60a5fa";
32
+ note: "#bfdbfe";
33
+ fill: "#bfdbfe";
34
+ };
35
+ };
36
+ readonly WARM: {
37
+ accent: "#fb923c";
38
+ background: "#1c1917";
39
+ panelBackground: "rgba(28, 25, 23, 0.8)";
40
+ text: "#e7e5e4";
41
+ secondaryText: "#a8a29e";
42
+ border: "rgba(255, 255, 255, 0.1)";
43
+ buttonBackground: "rgba(28, 25, 23, 0.8)";
44
+ buttonHoverBackground: "#292524";
45
+ score: {
46
+ line: "#78716c";
47
+ note: "#e7e5e4";
48
+ fill: "#e7e5e4";
49
+ };
50
+ };
51
+ readonly LIGHT: {
52
+ accent: "#1DA59C";
53
+ background: string;
54
+ panelBackground: string;
55
+ text: "#1e293b";
56
+ secondaryText: "hsla(215, 16%, 47%, 1.00)";
57
+ border: string;
58
+ buttonBackground: string;
59
+ buttonHoverBackground: string;
60
+ score: {
61
+ line: "hsla(215, 20%, 65%, 1.00)";
62
+ note: string;
63
+ fill: string;
64
+ };
65
+ };
66
+ };
67
+ type ThemeName = keyof typeof THEMES;
68
+ interface Theme {
69
+ accent: string;
70
+ background: string;
71
+ panelBackground: string;
72
+ text: string;
73
+ secondaryText: string;
74
+ border: string;
75
+ buttonBackground: string;
76
+ buttonHoverBackground: string;
77
+ score: {
78
+ line: string;
79
+ note: string;
80
+ fill: string;
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Type definitions for the Sheet Music Editor
86
+ *
87
+ * This file defines the data model for scores, staves, measures, events, and notes.
88
+ * The model supports multiple staves for Grand Staff rendering.
89
+ */
90
+ interface Note {
91
+ id: string | number;
92
+ pitch: string | null;
93
+ accidental?: 'sharp' | 'flat' | 'natural' | null;
94
+ tied?: boolean;
95
+ isRest?: boolean;
96
+ }
97
+ interface ScoreEvent {
98
+ id: string | number;
99
+ duration: string;
100
+ dotted: boolean;
101
+ notes: Note[];
102
+ isRest?: boolean;
103
+ tuplet?: {
104
+ ratio: [number, number];
105
+ groupSize: number;
106
+ position: number;
107
+ baseDuration?: string;
108
+ id?: string;
109
+ };
110
+ }
111
+ interface Measure {
112
+ id: string | number;
113
+ events: ScoreEvent[];
114
+ isPickup?: boolean;
115
+ }
116
+ interface Staff {
117
+ id: string | number;
118
+ clef: 'treble' | 'bass' | 'grand';
119
+ keySignature: string;
120
+ measures: Measure[];
121
+ }
122
+ interface Score {
123
+ title: string;
124
+ timeSignature: string;
125
+ keySignature: string;
126
+ bpm: number;
127
+ staves: Staff[];
128
+ }
129
+ /**
130
+ * Represents the current selection state in the editor.
131
+ * Supports Grand Staff by tracking which staff is selected.
132
+ */
133
+ interface Selection {
134
+ staffIndex: number;
135
+ measureIndex: number | null;
136
+ eventId: string | number | null;
137
+ noteId: string | number | null;
138
+ selectedNotes: Array<{
139
+ staffIndex: number;
140
+ measureIndex: number;
141
+ eventId: string | number;
142
+ noteId: string | number | null;
143
+ }>;
144
+ anchor?: {
145
+ staffIndex: number;
146
+ measureIndex: number;
147
+ eventId: string | number;
148
+ noteId: string | number | null;
149
+ } | null;
150
+ }
151
+ /**
152
+ * Utility type for allowing partial nested objects
153
+ */
154
+ type DeepPartial<T> = {
155
+ [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
156
+ };
157
+ /**
158
+ * Staff template options for score generation
159
+ */
160
+ type StaffTemplate = 'grand' | 'treble' | 'bass';
161
+ /**
162
+ * Configuration interface for RiffScore component.
163
+ * Supports two modes:
164
+ * - Generator Mode: Pass `staff` + `measureCount` to create blank scores
165
+ * - Render Mode: Pass `staves` array to load existing compositions
166
+ */
167
+ /**
168
+ * Configuration interface for RiffScore component.
169
+ * Supports two modes:
170
+ * - Generator Mode: Pass `staff` + `measureCount` to create blank scores
171
+ * - Render Mode: Pass `staves` array to load existing compositions
172
+ */
173
+ interface RiffScoreConfig {
174
+ ui: {
175
+ showToolbar: boolean;
176
+ scale: number;
177
+ theme?: ThemeName;
178
+ };
179
+ interaction: {
180
+ isEnabled: boolean;
181
+ enableKeyboard: boolean;
182
+ enablePlayback: boolean;
183
+ };
184
+ score: {
185
+ title: string;
186
+ bpm: number;
187
+ timeSignature: string;
188
+ keySignature: string;
189
+ staff?: StaffTemplate;
190
+ measureCount?: number;
191
+ staves?: Staff[];
192
+ };
193
+ }
194
+
195
+ /**
196
+ * RiffScore Component
197
+ *
198
+ * Configurable React component for rendering and interacting with musical scores.
199
+ * Supports two modes:
200
+ * - Generator Mode: Create blank scores from templates (staff + measureCount)
201
+ * - Render Mode: Load compositions from staves array
202
+ */
203
+
204
+ interface RiffScoreProps {
205
+ config?: DeepPartial<RiffScoreConfig>;
206
+ }
207
+ /**
208
+ * RiffScore - Configurable Music Notation Editor
209
+ *
210
+ * @example
211
+ * // Generator Mode - Create blank grand staff with 4 measures
212
+ * <RiffScore config={{ score: { staff: 'grand', measureCount: 4 } }} />
213
+ *
214
+ * @example
215
+ * // Render Mode - Load existing composition
216
+ * <RiffScore config={{ score: { staves: myStaves } }} />
217
+ *
218
+ * @example
219
+ * // Disable all interaction (read-only display)
220
+ * <RiffScore config={{ interaction: { isEnabled: false } }} />
221
+ */
222
+ declare const RiffScore: react__default.FC<RiffScoreProps>;
223
+
224
+ interface ScoreEditorContentProps {
225
+ scale?: number;
226
+ label?: string;
227
+ showToolbar?: boolean;
228
+ enableKeyboard?: boolean;
229
+ enablePlayback?: boolean;
230
+ }
231
+ declare const ScoreEditorContent: ({ scale, label, showToolbar, enableKeyboard, enablePlayback, }: ScoreEditorContentProps) => react_jsx_runtime.JSX.Element;
232
+ declare const ScoreEditor: ({ scale, label, initialData, }: {
233
+ scale?: number;
234
+ label?: string;
235
+ initialData?: any;
236
+ }) => react_jsx_runtime.JSX.Element;
237
+
238
+ interface ThemeContextType {
239
+ theme: Theme;
240
+ themeName: ThemeName;
241
+ setTheme: (name: ThemeName) => void;
242
+ zoom: number;
243
+ setZoom: (zoom: number) => void;
244
+ }
245
+ declare const ThemeProvider: react__default.FC<{
246
+ children: react__default.ReactNode;
247
+ initialTheme?: ThemeName;
248
+ }>;
249
+ declare const useTheme: () => ThemeContextType;
250
+
251
+ /**
252
+ * Input mode for entry - determines whether canvas clicks create notes or rests.
253
+ */
254
+ type InputMode = 'NOTE' | 'REST';
255
+
256
+ interface Command {
257
+ type: string;
258
+ execute(score: Score): Score;
259
+ undo(score: Score): Score;
260
+ }
261
+
262
+ type EditorState = 'SELECTION_READY' | 'ENTRY_READY' | 'IDLE';
263
+
264
+ /**
265
+ * Main score logic orchestrator hook.
266
+ * Composes focused hooks for measure, note, modifier, and navigation actions.
267
+ */
268
+ declare const useScoreLogic: (initialScore: any) => {
269
+ score: Score;
270
+ selection: Selection;
271
+ editorState: EditorState;
272
+ selectedDurations: string[];
273
+ selectedDots: boolean[];
274
+ selectedTies: boolean[];
275
+ selectedAccidentals: string[];
276
+ setSelection: react.Dispatch<react.SetStateAction<Selection>>;
277
+ previewNote: any;
278
+ setPreviewNote: react.Dispatch<any>;
279
+ history: Command[];
280
+ redoStack: Command[];
281
+ undo: () => void;
282
+ redo: () => void;
283
+ dispatch: (command: Command) => void;
284
+ activeDuration: string;
285
+ setActiveDuration: react.Dispatch<react.SetStateAction<string>>;
286
+ isDotted: boolean;
287
+ setIsDotted: react.Dispatch<react.SetStateAction<boolean>>;
288
+ activeAccidental: "sharp" | "flat" | "natural" | null;
289
+ activeTie: boolean;
290
+ inputMode: InputMode;
291
+ setInputMode: react.Dispatch<react.SetStateAction<InputMode>>;
292
+ toggleInputMode: () => void;
293
+ handleTimeSignatureChange: (newSig: string) => void;
294
+ handleKeySignatureChange: (newKey: string) => void;
295
+ addMeasure: () => void;
296
+ removeMeasure: () => void;
297
+ togglePickup: () => void;
298
+ setGrandStaff: () => void;
299
+ handleMeasureHover: (measureIndex: number | null, hit: any, pitch: string, staffIndex?: number) => void;
300
+ addNoteToMeasure: (measureIndex: number, newNote: any, shouldAutoAdvance?: boolean, placementOverride?: any) => void;
301
+ addChordToMeasure: (measureIndex: number, notes: any[], duration: string, dotted: boolean) => void;
302
+ deleteSelected: () => void;
303
+ handleNoteSelection: (measureIndex: number, eventId: string | number, noteId: string | number | null, staffIndex?: number, isMulti?: boolean, selectAllInEvent?: boolean, isShift?: boolean) => void;
304
+ handleDurationChange: (newDuration: string) => void;
305
+ handleDotToggle: () => void;
306
+ handleAccidentalToggle: (type: "flat" | "natural" | "sharp" | null) => void;
307
+ handleTieToggle: () => void;
308
+ currentQuantsPerMeasure: number;
309
+ scoreRef: react.RefObject<Score>;
310
+ checkDurationValidity: (targetDuration: string) => boolean;
311
+ checkDotValidity: () => boolean;
312
+ updateNotePitch: (measureIndex: number, eventId: string | number, noteId: string | number, newPitch: string) => void;
313
+ applyTuplet: (ratio: [number, number], groupSize: number) => boolean;
314
+ removeTuplet: () => boolean;
315
+ canApplyTuplet: (groupSize: number) => boolean;
316
+ activeTupletRatio: [number, number] | null;
317
+ transposeSelection: (direction: string, isShift: boolean) => void;
318
+ moveSelection: (direction: string, isShift: boolean) => void;
319
+ switchStaff: (direction: "up" | "down") => void;
320
+ focusScore: () => void;
321
+ };
322
+
323
+ type ScoreContextType = ReturnType<typeof useScoreLogic> & {
324
+ pendingClefChange: {
325
+ targetClef: 'treble' | 'bass';
326
+ } | null;
327
+ setPendingClefChange: react__default.Dispatch<react__default.SetStateAction<{
328
+ targetClef: 'treble' | 'bass';
329
+ } | null>>;
330
+ handleClefChange: (val: string) => void;
331
+ };
332
+ declare const useScoreContext: () => ScoreContextType;
333
+ interface ScoreProviderProps {
334
+ children: ReactNode;
335
+ initialScore?: any;
336
+ }
337
+ declare const ScoreProvider: react__default.FC<ScoreProviderProps>;
338
+
339
+ declare const ConfigMenu: () => react_jsx_runtime.JSX.Element;
340
+
341
+ export { ConfigMenu, type Measure, type Note, RiffScore, type RiffScoreConfig, type Score, ScoreEditor, ScoreEditorContent, type ScoreEvent, ScoreProvider, type Selection, type Staff, ThemeProvider, useScoreContext, useTheme };