notations 1.0.6 → 1.0.7

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.
Files changed (43) hide show
  1. package/dist/NotationView.css +15 -0
  2. package/dist/NotationView.css.map +1 -1
  3. package/dist/NotationView.min.css +1 -1
  4. package/dist/NotationView.min.css.map +1 -1
  5. package/dist/notations.umd.js +142 -26
  6. package/dist/notations.umd.min.js +2 -2
  7. package/dist/notations.umd.min.js.map +1 -1
  8. package/lib/cjs/beats.js +1 -1
  9. package/lib/cjs/beats.js.map +1 -1
  10. package/lib/cjs/carnatic/NotationView.d.ts +1 -0
  11. package/lib/cjs/carnatic/NotationView.js +10 -0
  12. package/lib/cjs/carnatic/NotationView.js.map +1 -1
  13. package/lib/cjs/carnatic/atomviews.d.ts +4 -1
  14. package/lib/cjs/carnatic/atomviews.js +18 -2
  15. package/lib/cjs/carnatic/atomviews.js.map +1 -1
  16. package/lib/cjs/carnatic/embelishments.d.ts +18 -1
  17. package/lib/cjs/carnatic/embelishments.js +87 -1
  18. package/lib/cjs/carnatic/embelishments.js.map +1 -1
  19. package/lib/cjs/core.d.ts +3 -3
  20. package/lib/cjs/core.js +17 -17
  21. package/lib/cjs/core.js.map +1 -1
  22. package/lib/cjs/shapes.d.ts +2 -1
  23. package/lib/cjs/shapes.js +11 -6
  24. package/lib/cjs/shapes.js.map +1 -1
  25. package/lib/esm/beats.js +1 -1
  26. package/lib/esm/beats.js.map +1 -1
  27. package/lib/esm/carnatic/NotationView.d.ts +1 -0
  28. package/lib/esm/carnatic/NotationView.js +10 -0
  29. package/lib/esm/carnatic/NotationView.js.map +1 -1
  30. package/lib/esm/carnatic/atomviews.d.ts +4 -1
  31. package/lib/esm/carnatic/atomviews.js +19 -3
  32. package/lib/esm/carnatic/atomviews.js.map +1 -1
  33. package/lib/esm/carnatic/embelishments.d.ts +18 -1
  34. package/lib/esm/carnatic/embelishments.js +85 -0
  35. package/lib/esm/carnatic/embelishments.js.map +1 -1
  36. package/lib/esm/core.d.ts +3 -3
  37. package/lib/esm/core.js +17 -17
  38. package/lib/esm/core.js.map +1 -1
  39. package/lib/esm/shapes.d.ts +2 -1
  40. package/lib/esm/shapes.js +11 -6
  41. package/lib/esm/shapes.js.map +1 -1
  42. package/package.json +1 -1
  43. package/styles/NotationView.scss +15 -0
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { Entity, TimedEntity } from \"./entity\";\nimport { LayoutParams } from \"./layouts\";\nimport { AtomChangeType, GroupObserver, RoleObserver, LineObserver } from \"./events\";\n\n/**\n * Alias to TSU.Num.Fraction in tsutils.\n */\ntype Fraction = TSU.Num.Fraction;\nexport const ZERO = TSU.Num.Fraction.ZERO;\nexport const ONE = TSU.Num.Fraction.ONE;\n\n/**\n * AtomType enums are used to denote specific Atoms\n * Each type represents a specific musical or notational element.\n * @enum\n */\nexport enum AtomType {\n NOTE = \"Note\",\n LITERAL = \"Literal\",\n SYLLABLE = \"Syllable\",\n SPACE = \"Space\",\n GROUP = \"Group\",\n LABEL = \"Label\",\n REST = \"Rest\",\n MARKER = \"Marker\",\n}\n\n/**\n * Atoms are the base class for all timed entities that can appear in a Notation.\n * An Atom represents the fundamental building block of the notation system.\n */\nexport abstract class Atom extends TimedEntity {\n readonly TYPE: string = \"Atom\";\n\n protected _duration: Fraction;\n /** Markers to be displayed before this atom */\n markersBefore: Marker[];\n /** Markers to be displayed after this atom */\n markersAfter: Marker[];\n /** Next atom in the sequence */\n nextSibling: TSU.Nullable<Atom> = null;\n /** Previous atom in the sequence */\n prevSibling: TSU.Nullable<Atom> = null;\n /** The Group this Atom belongs to, if any */\n parentGroup: TSU.Nullable<Group> = null;\n\n /** Indicates if this Atom is a continuation from a previous atom */\n isContinuation = false;\n\n /**\n * Creates a new Atom with the specified duration.\n * @param duration The duration of the atom, defaults to ONE (1/1)\n */\n constructor(duration = ONE) {\n super();\n this._duration = duration || ONE;\n }\n\n /**\n * Splits this atom at the specified duration.\n * @param requiredDuration The duration at which to split the atom\n * @returns A new atom representing the portion beyond the split point, or null if no split is needed\n */\n abstract splitAt(requiredDuration: Fraction): TSU.Nullable<Atom>;\n\n /**\n * Returns a debug-friendly representation of this Atom.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = super.debugValue();\n if (!this.duration.isOne) {\n out.duration = this.duration.factorized.toString();\n }\n if (this.isContinuation) {\n out.isContinuation = true;\n }\n if ((this.markersBefore || []).length > 0) {\n out.mbef = this.markersBefore.map((m) => m.debugValue());\n }\n if ((this.markersAfter || []).length > 0) {\n out.maft = this.markersAfter.map((m) => m.debugValue());\n }\n return out;\n }\n\n /**\n * Copies the properties of this atom to another atom.\n * @param another The target atom to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another._duration = new TSU.Num.Fraction(this.duration.num, this.duration.den);\n }\n\n /**\n * Gets the duration of this atom.\n */\n get duration(): Fraction {\n return this._duration;\n }\n\n /**\n * Sets the duration of this atom.\n */\n set duration(d: Fraction) {\n this._duration = d;\n }\n}\n\n/**\n * Base class for atoms that cannot contain other atoms.\n * LeafAtom represents atomic elements that can't be further subdivided.\n */\nexport abstract class LeafAtom extends Atom {\n readonly TYPE: string = \"LeafAtom\";\n\n /** Indicates if this atom is followed by a rest */\n beforeRest = false;\n\n /**\n * Splits this atom at a certain duration.\n * If this atom's duration is longer than the given duration, it's truncated\n * to the given duration and a continuation space is returned.\n *\n * @param duration The duration at which to split the atom\n * @returns A new Space atom representing the spillover if needed, otherwise null\n */\n splitAt(duration: Fraction): TSU.Nullable<Atom> {\n if (this.duration.cmp(duration) > 0) {\n const spillOver = this.createSpilloverSpace(this.duration.minus(duration));\n spillOver.isContinuation = true;\n this.duration = duration;\n // TODO - Here we need to move the markersAfter to the spill-over as it doesnt belong to this any more\n return spillOver;\n }\n return null;\n }\n\n /**\n * Creates a Space atom to represent spillover duration when splitting.\n * @param duration The duration of the spillover\n * @returns A new Space atom\n */\n protected createSpilloverSpace(duration: Fraction): Space {\n return new Space(duration);\n }\n\n /**\n * Returns a debug-friendly representation of this LeafAtom.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return this.beforeRest ? { ...super.debugValue(), beforeRest: true } : super.debugValue();\n }\n}\n\n/**\n * Represents a marker or annotation in the notation.\n * Markers can be placed before or after atoms to provide additional context.\n */\nexport class Marker extends Entity {\n readonly TYPE = \"Marker\";\n\n /**\n * Creates a new Marker with the specified text.\n * @param text The text content of the marker\n * @param isBefore Whether the marker should appear before (true) or after (false) its associated atom\n */\n constructor(\n public text: string,\n public isBefore = true,\n ) {\n super();\n }\n\n /**\n * Returns a debug-friendly representation of this Marker.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), text: this.text, before: this.isBefore };\n }\n\n /**\n * Returns a string representation of this Marker.\n * @returns A string representation\n */\n toString(): string {\n return `Marker(${this.text}-${this.isBefore})`;\n }\n}\n\n/**\n * Represents a rest (silence) in the notation.\n * Rests are zero-length atoms that indicate a pause.\n */\nexport class Rest extends LeafAtom {\n readonly TYPE = \"Rest\";\n\n /**\n * Creates a new Rest.\n * Rests are zero length by default.\n */\n constructor() {\n super(ZERO);\n }\n}\n\n/**\n * Represents a space or silence in the notation.\n * Spaces can be used to denote either silence or continuations of previous notes.\n */\nexport class Space extends LeafAtom {\n readonly TYPE = \"Space\";\n\n /**\n * Indicates whether this is a silent space or a continuation of the previous note.\n */\n isSilent = false;\n\n /**\n * Creates a new Space with the specified duration and silence property.\n * @param duration The duration of the space, defaults to ONE (1/1)\n * @param isSilent Whether the space represents silence (true) or a continuation (false)\n */\n constructor(duration = ONE, isSilent = false) {\n super(duration);\n this.isSilent = isSilent;\n }\n\n /**\n * Returns a debug-friendly representation of this Space.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), isSilent: this.isSilent };\n }\n\n /**\n * Returns a string representation of this Space.\n * @returns A string representation\n */\n toString(): string {\n return `Space(${this.duration}-${this.isSilent})`;\n }\n\n /**\n * Copies the properties of this Space to another Space.\n * @param another The target Space to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.isSilent = this.isSilent;\n }\n\n /**\n * Checks if this Space is equal to another Space.\n * @param another The Space to compare with\n * @returns True if the Spaces are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.isSilent == another.isSilent;\n }\n\n /**\n * Creates a Space atom to represent spillover duration when splitting.\n * @param duration The duration of the spillover\n * @returns A new Space atom with the same silence property as this Space\n */\n protected createSpilloverSpace(duration: Fraction): Space {\n const out = super.createSpilloverSpace(duration);\n out.isSilent = this.isSilent;\n return out;\n }\n}\n\n/**\n * Represents a literal value in the notation.\n * Literals are the basic building blocks for notes and syllables.\n */\nexport class Literal extends LeafAtom {\n readonly TYPE: string = \"Literal\";\n\n /**\n * The embellishments applied to this Literal.\n */\n embelishments: any[] = [];\n\n /**\n * Creates a new Literal with the specified value and duration.\n * @param value The string value of the literal\n * @param duration The duration of the literal, defaults to ONE (1/1)\n */\n constructor(\n public value: string,\n duration = ONE,\n ) {\n super(duration);\n }\n\n /**\n * Returns a debug-friendly representation of this Literal.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue(), value: this.value };\n if (this.embelishments.length > 0) {\n out.embs = this.embelishments.map((e) => (\"debugValue\" in e ? e.debugValue() : e));\n }\n return out;\n }\n\n /**\n * Returns a string representation of this Literal.\n * @returns A string representation\n */\n toString(): string {\n return `Lit(${this.duration}-${this.value})`;\n }\n\n /**\n * Checks if this Literal is equal to another Literal.\n * @param another The Literal to compare with\n * @returns True if the Literals are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.value == another.value;\n }\n\n /**\n * Copies the properties of this Literal to another Literal.\n * @param another The target Literal to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.value = this.value;\n }\n}\n\n/**\n * Represents a syllable in lyrics or text to be sung.\n * Extends Literal to provide specialized handling for sung text.\n */\nexport class Syllable extends Literal {\n readonly TYPE = \"Syllable\";\n\n /**\n * Creates a Syllable from a Literal.\n * @param lit The Literal to convert to a Syllable\n * @returns A new Syllable with the properties of the Literal\n */\n static fromLit(lit: Literal): Syllable {\n if (lit.TYPE == AtomType.SYLLABLE) return lit as Syllable;\n const out = new Syllable(lit.value, lit.duration);\n out.embelishments = lit.embelishments;\n out.beforeRest = lit.beforeRest;\n return out;\n }\n\n /**\n * Returns a string representation of this Syllable.\n * @returns A string representation\n */\n toString(): string {\n return `Syll(${this.duration}-${this.value})`;\n }\n}\n\n/**\n * Represents a musical note in the notation.\n * Extends Literal to add properties specific to musical notes.\n */\nexport class Note extends Literal {\n readonly TYPE = \"Note\";\n\n /**\n * Which octave the note is in. Can be positive or negative to indicate higher or lower octaves.\n */\n octave = 0;\n\n /**\n * How the note is shifted - i.e., shifted towards major or minor by # of semi-tones.\n */\n shift: number | boolean = 0;\n\n /**\n * Creates a new Note with the specified properties.\n * @param value The string value of the note\n * @param duration The duration of the note, defaults to ONE (1/1)\n * @param octave The octave of the note, defaults to 0\n * @param shift The shift of the note, defaults to 0\n */\n constructor(value: string, duration = ONE, octave = 0, shift = 0) {\n super(value, duration);\n this.octave = octave;\n this.shift = shift;\n }\n\n /**\n * Creates a Note from a Literal.\n * @param lit The Literal to convert to a Note\n * @returns A new Note with the properties of the Literal\n */\n static fromLit(lit: Literal): Note {\n if (lit.TYPE == AtomType.NOTE) return lit as Note;\n const out = new Note(lit.value, lit.duration);\n out.embelishments = lit.embelishments;\n out.beforeRest = lit.beforeRest;\n return out;\n }\n\n /**\n * Returns a debug-friendly representation of this Note.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue() };\n if (this.octave != 0) out.octave = this.octave;\n if (this.shift != 0) out.shift = this.shift;\n return out;\n }\n\n /**\n * Returns a string representation of this Note.\n * @returns A string representation\n */\n toString(): string {\n return `Note(${this.duration}-${this.value}-${this.octave})`;\n }\n\n /**\n * Checks if this Note is equal to another Note.\n * @param another The Note to compare with\n * @returns True if the Notes are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.octave == another.octave && this.shift == another.shift;\n }\n\n /**\n * Copies the properties of this Note to another Note.\n * @param another The target Note to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.octave = this.octave;\n another.shift = this.shift;\n }\n}\n\n/**\n * Represents a group of atoms that are treated as a single unit.\n * Groups can contain any number of atoms, including other groups.\n */\nexport class Group extends Atom {\n readonly TYPE = \"Group\";\n\n /**\n * Indicates whether the duration is static or linear to the number of atoms in this group.\n * When true, the duration is used as a multiplier for the total child duration.\n * When false, the duration is absolute.\n */\n durationIsMultiplier = false;\n\n /**\n * The list of atoms in this group.\n */\n readonly atoms = new TSU.Lists.ValueList<Atom>();\n\n /**\n * Observers that receive notifications when atoms change.\n */\n private _observers: GroupObserver<Atom, Group>[] = [];\n\n /**\n * Creates a new Group containing the specified atoms.\n * @param atoms The atoms to include in this group\n */\n constructor(...atoms: Atom[]) {\n super(atoms.length == 0 ? ZERO : ONE);\n this.addAtoms(false, ...atoms);\n }\n\n /**\n * Adds an observer to receive atom change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: GroupObserver<Atom, Group>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: GroupObserver<Atom, Group>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Notifies observers of atom changes.\n */\n private notifyObservers(type: AtomChangeType, atoms: Atom[], index: number): void {\n if (!this._eventsEnabled) return;\n for (const observer of this._observers) {\n switch (type) {\n case AtomChangeType.ADD:\n observer.onAtomsAdded?.(this, atoms, index);\n break;\n case AtomChangeType.INSERT:\n observer.onAtomsInserted?.(this, atoms, index);\n break;\n case AtomChangeType.REMOVE:\n observer.onAtomsRemoved?.(this, atoms);\n break;\n }\n }\n }\n\n /**\n * Checks if this Group is equal to another Group.\n * @param another The Group to compare with\n * @param expect Optional parameter\n * @returns True if the Groups are equal, false otherwise\n */\n equals(another: this, expect = false): boolean {\n if (!super.equals(another)) return false;\n return this.atoms.equals(another.atoms, (a1, a2) => a1.equals(a2));\n }\n\n /**\n * Copies the properties of this Group to another Group.\n * @param another The target Group to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.durationIsMultiplier = this.durationIsMultiplier;\n for (const atom of this.atoms.values()) {\n another.atoms.add(atom.clone());\n }\n }\n\n /**\n * Gets the duration of this group.\n * If durationIsMultiplier is true, returns the total child duration divided by the multiplier.\n * Otherwise, returns the absolute duration.\n */\n get duration(): Fraction {\n if (this.durationIsMultiplier) {\n return this.totalChildDuration.divby(this._duration);\n } else {\n return this._duration;\n }\n }\n\n /**\n * Sets this group to use a multiplier for duration calculations.\n * @param asMultiplier Whether to use the duration as a multiplier\n * @returns This Group instance for method chaining\n */\n setDurationAsMultiplier(asMultiplier = true): this {\n this.durationIsMultiplier = asMultiplier;\n return this;\n }\n\n /**\n * Sets the duration of this group.\n * @param d The new duration\n * @param asMultiplier Whether to use the duration as a multiplier\n * @returns This Group instance for method chaining\n */\n setDuration(d: Fraction, asMultiplier = false): this {\n this._duration = d;\n this.durationIsMultiplier = asMultiplier;\n return this;\n }\n\n /**\n * Returns a debug-friendly representation of this Group.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue(), atoms: Array.from(this.atoms.values(), (a) => a.debugValue()) };\n if (this.durationIsMultiplier) out.durationIsMultiplier = true;\n return out;\n }\n\n /**\n * Splits this group into two parts.\n * The first part (this group) fits within the given duration and everything else\n * longer than the given duration is returned as a new Group.\n *\n * @param requiredDuration The duration at which to split the group\n * @returns A new Group containing the atoms beyond the split point, or null if no split is needed\n */\n splitAt(requiredDuration: Fraction): TSU.Nullable<Group> {\n if (this.duration.isLTE(requiredDuration) || requiredDuration.isLTE(ZERO)) {\n return null;\n }\n const targetGroup = new Group();\n if (this.durationIsMultiplier) {\n targetGroup.durationIsMultiplier = true;\n targetGroup._duration = this._duration;\n }\n\n let remainingDur = this.duration;\n const totalChildDuration = this.totalChildDuration;\n const durationFactor = this.durationIsMultiplier\n ? ONE.divby(this._duration)\n : this._duration.divby(totalChildDuration, true);\n while (remainingDur.isGT(requiredDuration) && this.atoms.last) {\n const lastChild = this.atoms.last;\n // Child's duration is absolute in its own \"system\"\n // Its duration within the parent (this) group's frame of reference depends\n // on whether the parent's duration is absolute or as a multiplier\n //\n // realChildDuration = case (group.durationIsMultiper) {\n // | true => child.duration / this._duration\n // | false => child.duration * this._duration / total child duration\n // }\n const childDuration = lastChild.duration.times(durationFactor);\n const newDuration = remainingDur.minus(childDuration);\n if (newDuration.isGTE(requiredDuration)) {\n // remove ourselves and add to target\n // in both cases duration will be adjusted if need be\n this.removeAtoms(true, lastChild);\n targetGroup.insertAtomsAt(targetGroup.atoms.first, true, lastChild);\n if (newDuration.equals(requiredDuration)) {\n // we have reached the end so return\n return targetGroup;\n }\n } else {\n // our scenario is now this:\n //\n // totalParentDuration = 10\n // required = 8\n // lastChildDuration (relative to parent) is 5\n //\n // durWithoutLast = 10 - 5\n // newRequired = requiredDur - durWithoutLast = 3\n //\n // However 3 is a duration in the parent's frame of reference\n // this has to be converted back to the child's FoR\n const newRequiredDur = requiredDuration.minus(newDuration, true).divby(durationFactor, true);\n // console.log( \"newRequiredDur: \", newRequiredDur, \"requiedDur: \", requiredDuration, \"remainingDur: \", remainingDur,);\n // then the last item needs to be split, and by how much?\n const spillOver = lastChild.splitAt(newRequiredDur);\n if (spillOver == null) {\n throw new Error(\"Spill over cannot be null here\");\n }\n if (!this.durationIsMultiplier) {\n // Our own duration has also now changed\n this._duration = requiredDuration;\n } else {\n if (this._duration.isZero) throw new Error(\"How can this be?\");\n }\n spillOver.isContinuation = true;\n // Add spill over to the target\n targetGroup.insertAtomsAt(targetGroup.atoms.first, true, spillOver);\n return targetGroup;\n }\n remainingDur = newDuration;\n }\n return targetGroup;\n }\n\n /**\n * Gets the total duration of all child atoms.\n * @returns The sum of durations of all atoms in this group\n */\n get totalChildDuration(): Fraction {\n let out = ZERO;\n for (const atom of this.atoms.values()) {\n out = out.plus(atom.duration);\n }\n return out;\n }\n\n /**\n * Inserts atoms before a given cursor atom.\n * If the cursor atom is null, the atoms are appended at the end.\n *\n * @param beforeAtom The atom before which to insert the new atoms, or null to append\n * @param adjustDuration Whether to adjust this group's duration based on the new atoms\n * @param atoms The atoms to insert\n * @returns This Group instance for method chaining\n */\n insertAtomsAt(beforeAtom: TSU.Nullable<Atom>, adjustDuration = false, ...atoms: Atom[]): this {\n adjustDuration = adjustDuration && !this.durationIsMultiplier;\n const oldChildDuration = adjustDuration ? this.totalChildDuration : ONE;\n\n // Calculate insertion index for event notification\n let insertIndex: number;\n if (beforeAtom) {\n // Find index of beforeAtom using for loop\n insertIndex = 0;\n for (const a of this.atoms.values()) {\n if (a === beforeAtom) break;\n insertIndex++;\n }\n } else {\n // Appending to end - use size property\n insertIndex = this.atoms.size;\n }\n\n // Track which atoms were actually added (excluding REST atoms)\n const addedAtoms: Atom[] = [];\n\n // First form a chain of the given atoms\n for (const atom of atoms) {\n if (atom.parentGroup != null) {\n if (atom.parentGroup != this) {\n throw new Error(\"Atom belongs to another parent. Remove it first\");\n }\n atom.parentGroup.removeAtoms(false, atom);\n }\n if (atom.TYPE == AtomType.REST) {\n const last = this.atoms.last;\n if (last && last.TYPE != AtomType.GROUP && last.TYPE != AtomType.LABEL) {\n (last as LeafAtom).beforeRest = true;\n }\n } else {\n atom.parentGroup = this;\n this.atoms.add(atom, beforeAtom);\n addedAtoms.push(atom);\n }\n }\n if (adjustDuration) {\n if (this._duration.isZero) {\n if (this.durationIsMultiplier) throw new Error(\"How can this be?\");\n this._duration = this.totalChildDuration;\n } else {\n const scaleFactor = this.totalChildDuration.divby(oldChildDuration);\n this._duration = this._duration.times(scaleFactor, true);\n }\n }\n\n // Notify observers if atoms were added\n if (addedAtoms.length > 0) {\n const type = beforeAtom ? AtomChangeType.INSERT : AtomChangeType.ADD;\n this.notifyObservers(type, addedAtoms, insertIndex);\n }\n\n return this;\n }\n\n /**\n * Adds atoms to the end of this group's atom list.\n *\n * @param adjustDuration Whether to adjust this group's duration based on the new atoms\n * @param atoms The atoms to add\n * @returns This Group instance for method chaining\n */\n addAtoms(adjustDuration = false, ...atoms: Atom[]): this {\n return this.insertAtomsAt(null, adjustDuration, ...atoms);\n }\n\n /**\n * Removes atoms from this group's child list.\n *\n * @param adjustDuration Whether to adjust this group's duration after removing atoms\n * @param atoms The atoms to remove\n * @returns This Group instance for method chaining\n */\n removeAtoms(adjustDuration = false, ...atoms: Atom[]): this {\n adjustDuration = adjustDuration && !this.durationIsMultiplier;\n const oldChildDuration = adjustDuration ? this.totalChildDuration : ONE;\n\n // Track which atoms were actually removed\n const removedAtoms: Atom[] = [];\n\n for (const atom of atoms) {\n if (atom.parentGroup == this) {\n this.atoms.remove(atom);\n atom.parentGroup = null;\n removedAtoms.push(atom);\n } else if (atom.parentGroup != null) {\n throw new Error(\"Atom cannot be removed as it does not belong to this group\");\n }\n }\n if (adjustDuration) {\n if (this._duration.isZero) {\n if (this.durationIsMultiplier) throw new Error(\"How can this be?\");\n this._duration = this.totalChildDuration;\n } else {\n const scaleFactor = this.totalChildDuration.divby(oldChildDuration);\n this._duration = this._duration.times(scaleFactor, true);\n }\n }\n\n // Notify observers if atoms were removed\n if (removedAtoms.length > 0) {\n this.notifyObservers(AtomChangeType.REMOVE, removedAtoms, -1);\n }\n\n return this;\n }\n}\n\n/**\n * Represents a line of notation containing multiple roles.\n * A line can have atoms starting before or after the cycle.\n */\nexport class Line extends Entity {\n readonly TYPE: string = \"Line\";\n\n /**\n * Offset tells how many notes before or after the cycle this line's atoms start at.\n */\n offset: Fraction = ZERO;\n\n /**\n * The roles contained in this line.\n */\n roles: Role[] = [];\n\n /**\n * Text to be displayed in the margin of the line.\n * This is a hacky solution to doing left side pre-margin text typically\n * found in notations - e.g., line X of a pallavi has this. This makes vertical\n * space less wasteful.\n *\n * A better solution is inter-beat annotation but it is very complex for now.\n */\n marginText = \"\";\n\n /**\n * The LayoutParams associated with this line.\n */\n layoutParams: LayoutParams;\n\n /**\n * Observers that receive notifications when roles change.\n */\n private _observers: LineObserver<Role, Line>[] = [];\n\n /**\n * Adds an observer to receive role change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: LineObserver<Role, Line>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: LineObserver<Role, Line>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Finds the index of a role with the given name.\n * @param name The name of the role to find\n * @returns The index of the role, or -1 if not found\n */\n indexOfRole(name: string): number {\n for (let i = 0; i < this.roles.length; i++) {\n if (this.roles[i].name == name) return i;\n }\n return -1;\n }\n\n /**\n * Checks if this line is empty (has no content in any role).\n */\n get isEmpty(): boolean {\n for (const r of this.roles) if (!r.isEmpty) return false;\n return true;\n }\n\n /**\n * Returns a debug-friendly representation of this Line.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = {\n ...super.debugValue(),\n roles: this.roles.map((r) => r.debugValue()),\n };\n if (!this.offset.isZero) {\n out.offset = this.offset.toString();\n }\n return out;\n }\n\n /**\n * Copies the properties of this Line to another Line.\n * @param another The target Line to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.roles = this.roles.map((r) => r.clone());\n }\n\n /**\n * Adds atoms to a role in this line.\n * @param roleName The name of the role to add atoms to\n * @param defaultToNotes Whether to default to notes for this role\n * @param atoms The atoms to add\n * @returns This Line instance for method chaining\n */\n addAtoms(roleName: string, defaultToNotes: boolean, ...atoms: Atom[]): this {\n const role = this.ensureRole(roleName, defaultToNotes);\n role.addAtoms(...atoms);\n return this;\n }\n\n /**\n * Ensures a role with the given name exists in this line, creating it if needed.\n * @param roleName The name of the role to ensure\n * @param defaultToNotes Whether to default to notes for this role\n * @returns The role with the specified name\n */\n ensureRole(roleName: string, defaultToNotes: boolean): Role {\n // Ensure we have this many roles\n let ri = this.roles.findIndex((r) => r.name == roleName);\n if (ri < 0) {\n ri = this.roles.length;\n const role = new Role(this, roleName);\n role.defaultToNotes = defaultToNotes;\n this.roles.push(role);\n\n // Notify observers of new role\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onRoleAdded?.(this, roleName, role);\n }\n }\n }\n return this.roles[ri];\n }\n\n /**\n * Removes a role from this line.\n * @param roleName The name of the role to remove\n * @returns True if the role was removed, false if not found\n */\n removeRole(roleName: string): boolean {\n const ri = this.roles.findIndex((r) => r.name == roleName);\n if (ri >= 0) {\n this.roles.splice(ri, 1);\n\n // Notify observers of removed role\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onRoleRemoved?.(this, roleName);\n }\n }\n return true;\n }\n return false;\n }\n\n /**\n * Gets the maximum duration across all roles in this line.\n */\n get duration(): Fraction {\n let max = ZERO;\n for (const role of this.roles) {\n max = TSU.Num.Fraction.max(role.duration, max);\n }\n return max;\n }\n}\n\n/**\n * Represents a specific role or voice in a line of notation.\n * Each role contains a sequence of atoms.\n */\nexport class Role extends Entity {\n readonly TYPE = \"Role\";\n\n /**\n * Whether this role represents notes by default.\n */\n defaultToNotes = true;\n\n /**\n * The atoms in this role.\n */\n atoms: Atom[] = [];\n\n /**\n * Observers that receive notifications when atoms change.\n */\n private _observers: RoleObserver<Atom, Role>[] = [];\n\n /**\n * Creates a new Role with the specified line and name.\n * @param line The line this role belongs to\n * @param name The name of the role\n */\n constructor(\n public readonly line: Line,\n public readonly name: string,\n ) {\n super();\n }\n\n /**\n * Adds an observer to receive atom change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: RoleObserver<Atom, Role>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: RoleObserver<Atom, Role>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Notifies observers of atom changes.\n */\n private notifyObservers(type: AtomChangeType, atoms: Atom[], index: number): void {\n if (!this._eventsEnabled) return;\n for (const observer of this._observers) {\n switch (type) {\n case AtomChangeType.ADD:\n observer.onAtomsAdded?.(this, atoms, index);\n break;\n case AtomChangeType.INSERT:\n observer.onAtomsInserted?.(this, atoms, index);\n break;\n case AtomChangeType.REMOVE:\n observer.onAtomsRemoved?.(this, atoms);\n break;\n }\n }\n }\n\n /**\n * Checks if this role is empty (has no atoms).\n */\n get isEmpty(): boolean {\n return this.atoms.length == 0;\n }\n\n /**\n * Returns a debug-friendly representation of this Role.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { name: this.name, atoms: this.atoms.map((a) => a.debugValue()) };\n }\n\n /**\n * Adds atoms to the end of this role.\n * @param atoms The atoms to add\n */\n addAtoms(...atoms: Atom[]): void {\n this.insertAtomsAt(this.atoms.length, ...atoms);\n }\n\n /**\n * Inserts atoms at a specific index in this role.\n * @param index The index at which to insert\n * @param atoms The atoms to insert\n */\n insertAtomsAt(index: number, ...atoms: Atom[]): void {\n // Track which atoms were actually added (excluding REST atoms)\n const addedAtoms: Atom[] = [];\n let last: null | Atom = index > 0 ? this.atoms[index - 1] : null;\n\n for (const atom of atoms) {\n if (atom.TYPE == AtomType.REST) {\n if (last && last.TYPE != AtomType.GROUP && last.TYPE != AtomType.LABEL) {\n (last as LeafAtom).beforeRest = true;\n }\n } else {\n this.atoms.splice(index + addedAtoms.length, 0, atom);\n addedAtoms.push(atom);\n }\n last = atom;\n }\n\n // Notify observers if atoms were added\n if (addedAtoms.length > 0) {\n const isAppend = index >= this.atoms.length - addedAtoms.length;\n const type = isAppend ? AtomChangeType.ADD : AtomChangeType.INSERT;\n this.notifyObservers(type, addedAtoms, index);\n }\n }\n\n /**\n * Removes atoms from this role.\n * @param atoms The atoms to remove\n */\n removeAtoms(...atoms: Atom[]): void {\n const removedAtoms: Atom[] = [];\n\n for (const atom of atoms) {\n const idx = this.atoms.indexOf(atom);\n if (idx >= 0) {\n this.atoms.splice(idx, 1);\n removedAtoms.push(atom);\n }\n }\n\n // Notify observers if atoms were removed\n if (removedAtoms.length > 0) {\n this.notifyObservers(AtomChangeType.REMOVE, removedAtoms, -1);\n }\n }\n\n /**\n * Copies the properties of this Role to another Role.\n * @param another The target Role to copy properties to\n */\n copyTo(another: Role): void {\n another.addAtoms(...this.atoms);\n }\n\n /**\n * Gets the total duration of all atoms in this role.\n */\n get duration(): Fraction {\n return this.atoms.reduce((a, b) => a.plus(b.duration), ZERO);\n }\n}\n"]}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { Entity, TimedEntity } from \"./entity\";\nimport { LayoutParams } from \"./layouts\";\nimport { AtomChangeType, GroupObserver, RoleObserver, LineObserver } from \"./events\";\n\n/**\n * Alias to TSU.Num.Fraction in tsutils.\n */\ntype Fraction = TSU.Num.Fraction;\nexport const ZERO = TSU.Num.Fraction.ZERO;\nexport const ONE = TSU.Num.Fraction.ONE;\n\n/**\n * AtomType enums are used to denote specific Atoms\n * Each type represents a specific musical or notational element.\n * @enum\n */\nexport enum AtomType {\n NOTE = \"Note\",\n LITERAL = \"Literal\",\n SYLLABLE = \"Syllable\",\n SPACE = \"Space\",\n GROUP = \"Group\",\n LABEL = \"Label\",\n REST = \"Rest\",\n MARKER = \"Marker\",\n}\n\n/**\n * Atoms are the base class for all timed entities that can appear in a Notation.\n * An Atom represents the fundamental building block of the notation system.\n */\nexport abstract class Atom extends TimedEntity {\n readonly TYPE: string = \"Atom\";\n\n protected _duration: Fraction;\n /** Markers to be displayed before this atom */\n markersBefore: Marker[];\n /** Markers to be displayed after this atom */\n markersAfter: Marker[];\n /** Next atom in the sequence */\n nextSibling: TSU.Nullable<Atom> = null;\n /** Previous atom in the sequence */\n prevSibling: TSU.Nullable<Atom> = null;\n /** The Group this Atom belongs to, if any */\n parentGroup: TSU.Nullable<Group> = null;\n\n /** Indicates if this Atom is a continuation from a previous atom */\n isContinuation = false;\n\n /**\n * Creates a new Atom with the specified duration.\n * @param duration The duration of the atom, defaults to ONE (1/1)\n */\n constructor(duration = ONE) {\n super();\n this._duration = duration || ONE;\n }\n\n /**\n * Splits this atom at the specified duration.\n * @param requiredDuration The duration at which to split the atom\n * @returns A new atom representing the portion beyond the split point, or null if no split is needed\n */\n abstract splitAt(requiredDuration: Fraction): TSU.Nullable<Atom>;\n\n /**\n * Returns a debug-friendly representation of this Atom.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = super.debugValue();\n if (!this.duration.isOne) {\n out.duration = this.duration.factorized.toString();\n }\n if (this.isContinuation) {\n out.isContinuation = true;\n }\n if ((this.markersBefore || []).length > 0) {\n out.mbef = this.markersBefore.map((m) => m.debugValue());\n }\n if ((this.markersAfter || []).length > 0) {\n out.maft = this.markersAfter.map((m) => m.debugValue());\n }\n return out;\n }\n\n /**\n * Copies the properties of this atom to another atom.\n * @param another The target atom to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another._duration = new TSU.Num.Fraction(this.duration.num, this.duration.den);\n }\n\n /**\n * Gets the duration of this atom.\n */\n get duration(): Fraction {\n return this._duration;\n }\n\n /**\n * Sets the duration of this atom.\n */\n set duration(d: Fraction) {\n this._duration = d;\n }\n}\n\n/**\n * Base class for atoms that cannot contain other atoms.\n * LeafAtom represents atomic elements that can't be further subdivided.\n */\nexport abstract class LeafAtom extends Atom {\n readonly TYPE: string = \"LeafAtom\";\n\n /** Indicates if this atom is followed by a rest */\n beforeRest = false;\n\n /**\n * Splits this atom at a certain duration.\n * If this atom's duration is longer than the given duration, it's truncated\n * to the given duration and a continuation space is returned.\n *\n * @param duration The duration at which to split the atom\n * @returns A new Space atom representing the spillover if needed, otherwise null\n */\n splitAt(duration: Fraction): TSU.Nullable<Atom> {\n if (this.duration.cmp(duration) > 0) {\n const spillOver = this.createSpilloverSpace(this.duration.minus(duration));\n spillOver.isContinuation = true;\n this.duration = duration;\n // TODO - Here we need to move the markersAfter to the spill-over as it doesnt belong to this any more\n return spillOver;\n }\n return null;\n }\n\n /**\n * Creates a Space atom to represent spillover duration when splitting.\n * @param duration The duration of the spillover\n * @returns A new Space atom\n */\n protected createSpilloverSpace(duration: Fraction): Space {\n return new Space(duration);\n }\n\n /**\n * Returns a debug-friendly representation of this LeafAtom.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return this.beforeRest ? { ...super.debugValue(), beforeRest: true } : super.debugValue();\n }\n}\n\n/**\n * Represents a marker or annotation in the notation.\n * Markers can be placed before or after atoms to provide additional context.\n */\nexport class Marker extends Entity {\n readonly TYPE = \"Marker\";\n\n /**\n * Creates a new Marker with the specified text.\n * @param text The text content of the marker\n * @param isBefore Whether the marker should appear before (true) or after (false) its associated atom\n */\n constructor(\n public text: string,\n public isBefore = true,\n ) {\n super();\n }\n\n /**\n * Returns a debug-friendly representation of this Marker.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), text: this.text, before: this.isBefore };\n }\n\n /**\n * Returns a string representation of this Marker.\n * @returns A string representation\n */\n toString(): string {\n return `Marker(${this.text}-${this.isBefore})`;\n }\n}\n\n/**\n * Represents a rest (silence) in the notation.\n * Rests are zero-length atoms that indicate a pause.\n */\nexport class Rest extends LeafAtom {\n readonly TYPE = \"Rest\";\n\n /**\n * Creates a new Rest.\n * Rests are zero length by default.\n */\n constructor() {\n super(ZERO);\n }\n}\n\n/**\n * Represents a space or silence in the notation.\n * Spaces can be used to denote either silence or continuations of previous notes.\n */\nexport class Space extends LeafAtom {\n readonly TYPE = \"Space\";\n\n /**\n * Indicates whether this is a silent space or a continuation of the previous note.\n */\n isSilent = false;\n\n /**\n * Creates a new Space with the specified duration and silence property.\n * @param duration The duration of the space, defaults to ONE (1/1)\n * @param isSilent Whether the space represents silence (true) or a continuation (false)\n */\n constructor(duration = ONE, isSilent = false) {\n super(duration);\n this.isSilent = isSilent;\n }\n\n /**\n * Returns a debug-friendly representation of this Space.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), isSilent: this.isSilent };\n }\n\n /**\n * Returns a string representation of this Space.\n * @returns A string representation\n */\n toString(): string {\n return `Space(${this.duration}-${this.isSilent})`;\n }\n\n /**\n * Copies the properties of this Space to another Space.\n * @param another The target Space to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.isSilent = this.isSilent;\n }\n\n /**\n * Checks if this Space is equal to another Space.\n * @param another The Space to compare with\n * @returns True if the Spaces are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.isSilent == another.isSilent;\n }\n\n /**\n * Creates a Space atom to represent spillover duration when splitting.\n * @param duration The duration of the spillover\n * @returns A new Space atom with the same silence property as this Space\n */\n protected createSpilloverSpace(duration: Fraction): Space {\n const out = super.createSpilloverSpace(duration);\n out.isSilent = this.isSilent;\n return out;\n }\n}\n\n/**\n * Represents a literal value in the notation.\n * Literals are the basic building blocks for notes and syllables.\n */\nexport class Literal extends LeafAtom {\n readonly TYPE: string = \"Literal\";\n\n /**\n * The embellishments applied to this Literal.\n */\n embelishments: any[] = [];\n\n /**\n * Creates a new Literal with the specified value and duration.\n * @param value The string value of the literal\n * @param duration The duration of the literal, defaults to ONE (1/1)\n */\n constructor(\n public value: string,\n duration = ONE,\n ) {\n super(duration);\n }\n\n /**\n * Returns a debug-friendly representation of this Literal.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue(), value: this.value };\n if (this.embelishments.length > 0) {\n out.embs = this.embelishments.map((e) => (\"debugValue\" in e ? e.debugValue() : e));\n }\n return out;\n }\n\n /**\n * Returns a string representation of this Literal.\n * @returns A string representation\n */\n toString(): string {\n return `Lit(${this.duration}-${this.value})`;\n }\n\n /**\n * Checks if this Literal is equal to another Literal.\n * @param another The Literal to compare with\n * @returns True if the Literals are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.value == another.value;\n }\n\n /**\n * Copies the properties of this Literal to another Literal.\n * @param another The target Literal to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.value = this.value;\n }\n}\n\n/**\n * Represents a syllable in lyrics or text to be sung.\n * Extends Literal to provide specialized handling for sung text.\n */\nexport class Syllable extends Literal {\n readonly TYPE = \"Syllable\";\n\n /**\n * Creates a Syllable from a Literal.\n * @param lit The Literal to convert to a Syllable\n * @returns A new Syllable with the properties of the Literal\n */\n static fromLit(lit: Literal): Syllable {\n if (lit.TYPE == AtomType.SYLLABLE) return lit as Syllable;\n const out = new Syllable(lit.value, lit.duration);\n out.embelishments = lit.embelishments;\n out.beforeRest = lit.beforeRest;\n return out;\n }\n\n /**\n * Returns a string representation of this Syllable.\n * @returns A string representation\n */\n toString(): string {\n return `Syll(${this.duration}-${this.value})`;\n }\n}\n\n/**\n * Represents a musical note in the notation.\n * Extends Literal to add properties specific to musical notes.\n */\nexport class Note extends Literal {\n readonly TYPE = \"Note\";\n\n /**\n * Which octave the note is in. Can be positive or negative to indicate higher or lower octaves.\n */\n octave = 0;\n\n /**\n * How the note is shifted - i.e., shifted towards major or minor by # of semi-tones.\n */\n shift: number | boolean = 0;\n\n /**\n * Creates a new Note with the specified properties.\n * @param value The string value of the note\n * @param duration The duration of the note, defaults to ONE (1/1)\n * @param octave The octave of the note, defaults to 0\n * @param shift The shift of the note, defaults to 0\n */\n constructor(value: string, duration = ONE, octave = 0, shift = 0) {\n super(value, duration);\n this.octave = octave;\n this.shift = shift;\n }\n\n /**\n * Creates a Note from a Literal.\n * @param lit The Literal to convert to a Note\n * @returns A new Note with the properties of the Literal\n */\n static fromLit(lit: Literal): Note {\n if (lit.TYPE == AtomType.NOTE) return lit as Note;\n const out = new Note(lit.value, lit.duration);\n out.embelishments = lit.embelishments;\n out.beforeRest = lit.beforeRest;\n return out;\n }\n\n /**\n * Returns a debug-friendly representation of this Note.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue() };\n if (this.octave != 0) out.octave = this.octave;\n if (this.shift != 0) out.shift = this.shift;\n return out;\n }\n\n /**\n * Returns a string representation of this Note.\n * @returns A string representation\n */\n toString(): string {\n return `Note(${this.duration}-${this.value}-${this.octave})`;\n }\n\n /**\n * Checks if this Note is equal to another Note.\n * @param another The Note to compare with\n * @returns True if the Notes are equal, false otherwise\n */\n equals(another: this): boolean {\n return super.equals(another) && this.octave == another.octave && this.shift == another.shift;\n }\n\n /**\n * Copies the properties of this Note to another Note.\n * @param another The target Note to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.octave = this.octave;\n another.shift = this.shift;\n }\n}\n\n/**\n * Represents a group of atoms that are treated as a single unit.\n * Groups can contain any number of atoms, including other groups.\n */\nexport class Group extends Atom {\n readonly TYPE = \"Group\";\n\n /**\n * Indicates whether the duration is static or linear to the number of atoms in this group.\n * When true, the duration is used as a multiplier for the total child duration.\n * When false, the duration is absolute.\n */\n durationIsSpeedMultiplier = false;\n\n /**\n * The list of atoms in this group.\n */\n readonly atoms = new TSU.Lists.ValueList<Atom>();\n\n /**\n * Observers that receive notifications when atoms change.\n */\n private _observers: GroupObserver<Atom, Group>[] = [];\n\n /**\n * Creates a new Group containing the specified atoms.\n * @param atoms The atoms to include in this group\n */\n constructor(...atoms: Atom[]) {\n super(atoms.length == 0 ? ZERO : ONE);\n this.addAtoms(false, ...atoms);\n }\n\n /**\n * Adds an observer to receive atom change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: GroupObserver<Atom, Group>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: GroupObserver<Atom, Group>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Notifies observers of atom changes.\n */\n private notifyObservers(type: AtomChangeType, atoms: Atom[], index: number): void {\n if (!this._eventsEnabled) return;\n for (const observer of this._observers) {\n switch (type) {\n case AtomChangeType.ADD:\n observer.onAtomsAdded?.(this, atoms, index);\n break;\n case AtomChangeType.INSERT:\n observer.onAtomsInserted?.(this, atoms, index);\n break;\n case AtomChangeType.REMOVE:\n observer.onAtomsRemoved?.(this, atoms);\n break;\n }\n }\n }\n\n /**\n * Checks if this Group is equal to another Group.\n * @param another The Group to compare with\n * @param expect Optional parameter\n * @returns True if the Groups are equal, false otherwise\n */\n equals(another: this, expect = false): boolean {\n if (!super.equals(another)) return false;\n return this.atoms.equals(another.atoms, (a1, a2) => a1.equals(a2));\n }\n\n /**\n * Copies the properties of this Group to another Group.\n * @param another The target Group to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.durationIsSpeedMultiplier = this.durationIsSpeedMultiplier;\n for (const atom of this.atoms.values()) {\n another.atoms.add(atom.clone());\n }\n }\n\n /**\n * Gets the duration of this group.\n * If durationIsSpeedMultiplier is true, returns the total child duration divided by the multiplier.\n * Otherwise, returns the absolute duration.\n */\n get duration(): Fraction {\n if (this.durationIsSpeedMultiplier) {\n return this.totalChildDuration.divby(this._duration);\n } else {\n return this._duration;\n }\n }\n\n /**\n * Sets this group to use a multiplier for duration calculations.\n * @param asSpeedMultiplier Whether to use the duration as a speed multiplier. Eg If our duration was 2 and this was\n * set then since the speed is doubled - then the actual duration is halved.\n * @returns This Group instance for method chaining\n */\n setDurationAsMultiplier(asSpeedMultiplier = true): this {\n this.durationIsSpeedMultiplier = asSpeedMultiplier;\n return this;\n }\n\n /**\n * Sets the duration of this group.\n * @param d The new duration\n * @param asSpeedMultiplier Whether to use the duration as a speed multiplier. Eg If our duration was 2 and this was\n * set then since the speed is doubled - then the actual duration is halved.\n * @returns This Group instance for method chaining\n */\n setDuration(d: Fraction, asSpeedMultiplier = false): this {\n this._duration = d;\n this.durationIsSpeedMultiplier = asSpeedMultiplier;\n return this;\n }\n\n /**\n * Returns a debug-friendly representation of this Group.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = { ...super.debugValue(), atoms: Array.from(this.atoms.values(), (a) => a.debugValue()) };\n if (this.durationIsSpeedMultiplier) out.durationIsSpeedMultiplier = true;\n return out;\n }\n\n /**\n * Splits this group into two parts.\n * The first part (this group) fits within the given duration and everything else\n * longer than the given duration is returned as a new Group.\n *\n * @param requiredDuration The duration at which to split the group\n * @returns A new Group containing the atoms beyond the split point, or null if no split is needed\n */\n splitAt(requiredDuration: Fraction): TSU.Nullable<Group> {\n if (this.duration.isLTE(requiredDuration) || requiredDuration.isLTE(ZERO)) {\n return null;\n }\n const targetGroup = new Group();\n if (this.durationIsSpeedMultiplier) {\n targetGroup.durationIsSpeedMultiplier = true;\n targetGroup._duration = this._duration;\n }\n\n let remainingDur = this.duration;\n const totalChildDuration = this.totalChildDuration;\n const durationFactor = this.durationIsSpeedMultiplier\n ? ONE.divby(this._duration)\n : this._duration.divby(totalChildDuration, true);\n while (remainingDur.isGT(requiredDuration) && this.atoms.last) {\n const lastChild = this.atoms.last;\n // Child's duration is absolute in its own \"system\"\n // Its duration within the parent (this) group's frame of reference depends\n // on whether the parent's duration is absolute or as a multiplier\n //\n // realChildDuration = case (group.durationIsMultiper) {\n // | true => child.duration / this._duration\n // | false => child.duration * this._duration / total child duration\n // }\n const childDuration = lastChild.duration.times(durationFactor);\n const newDuration = remainingDur.minus(childDuration);\n if (newDuration.isGTE(requiredDuration)) {\n // remove ourselves and add to target\n // in both cases duration will be adjusted if need be\n this.removeAtoms(true, lastChild);\n targetGroup.insertAtomsAt(targetGroup.atoms.first, true, lastChild);\n if (newDuration.equals(requiredDuration)) {\n // we have reached the end so return\n return targetGroup;\n }\n } else {\n // our scenario is now this:\n //\n // totalParentDuration = 10\n // required = 8\n // lastChildDuration (relative to parent) is 5\n //\n // durWithoutLast = 10 - 5\n // newRequired = requiredDur - durWithoutLast = 3\n //\n // However 3 is a duration in the parent's frame of reference\n // this has to be converted back to the child's FoR\n const newRequiredDur = requiredDuration.minus(newDuration, true).divby(durationFactor, true);\n // console.log( \"newRequiredDur: \", newRequiredDur, \"requiedDur: \", requiredDuration, \"remainingDur: \", remainingDur,);\n // then the last item needs to be split, and by how much?\n const spillOver = lastChild.splitAt(newRequiredDur);\n if (spillOver == null) {\n throw new Error(\"Spill over cannot be null here\");\n }\n if (!this.durationIsSpeedMultiplier) {\n // Our own duration has also now changed\n this._duration = requiredDuration;\n } else {\n if (this._duration.isZero) throw new Error(\"How can this be?\");\n }\n spillOver.isContinuation = true;\n // Add spill over to the target\n targetGroup.insertAtomsAt(targetGroup.atoms.first, true, spillOver);\n return targetGroup;\n }\n remainingDur = newDuration;\n }\n return targetGroup;\n }\n\n /**\n * Gets the total duration of all child atoms.\n * @returns The sum of durations of all atoms in this group\n */\n get totalChildDuration(): Fraction {\n let out = ZERO;\n for (const atom of this.atoms.values()) {\n out = out.plus(atom.duration);\n }\n return out;\n }\n\n /**\n * Inserts atoms before a given cursor atom.\n * If the cursor atom is null, the atoms are appended at the end.\n *\n * @param beforeAtom The atom before which to insert the new atoms, or null to append\n * @param adjustDuration Whether to adjust this group's duration based on the new atoms\n * @param atoms The atoms to insert\n * @returns This Group instance for method chaining\n */\n insertAtomsAt(beforeAtom: TSU.Nullable<Atom>, adjustDuration = false, ...atoms: Atom[]): this {\n adjustDuration = adjustDuration && !this.durationIsSpeedMultiplier;\n const oldChildDuration = adjustDuration ? this.totalChildDuration : ONE;\n\n // Calculate insertion index for event notification\n let insertIndex: number;\n if (beforeAtom) {\n // Find index of beforeAtom using for loop\n insertIndex = 0;\n for (const a of this.atoms.values()) {\n if (a === beforeAtom) break;\n insertIndex++;\n }\n } else {\n // Appending to end - use size property\n insertIndex = this.atoms.size;\n }\n\n // Track which atoms were actually added (excluding REST atoms)\n const addedAtoms: Atom[] = [];\n\n // First form a chain of the given atoms\n for (const atom of atoms) {\n if (atom.parentGroup != null) {\n if (atom.parentGroup != this) {\n throw new Error(\"Atom belongs to another parent. Remove it first\");\n }\n atom.parentGroup.removeAtoms(false, atom);\n }\n if (atom.TYPE == AtomType.REST) {\n const last = this.atoms.last;\n if (last && last.TYPE != AtomType.GROUP && last.TYPE != AtomType.LABEL) {\n (last as LeafAtom).beforeRest = true;\n }\n } else {\n atom.parentGroup = this;\n this.atoms.add(atom, beforeAtom);\n addedAtoms.push(atom);\n }\n }\n if (adjustDuration) {\n if (this._duration.isZero) {\n if (this.durationIsSpeedMultiplier) throw new Error(\"How can this be?\");\n this._duration = this.totalChildDuration;\n } else {\n const scaleFactor = this.totalChildDuration.divby(oldChildDuration);\n this._duration = this._duration.times(scaleFactor, true);\n }\n }\n\n // Notify observers if atoms were added\n if (addedAtoms.length > 0) {\n const type = beforeAtom ? AtomChangeType.INSERT : AtomChangeType.ADD;\n this.notifyObservers(type, addedAtoms, insertIndex);\n }\n\n return this;\n }\n\n /**\n * Adds atoms to the end of this group's atom list.\n *\n * @param adjustDuration Whether to adjust this group's duration based on the new atoms\n * @param atoms The atoms to add\n * @returns This Group instance for method chaining\n */\n addAtoms(adjustDuration = false, ...atoms: Atom[]): this {\n return this.insertAtomsAt(null, adjustDuration, ...atoms);\n }\n\n /**\n * Removes atoms from this group's child list.\n *\n * @param adjustDuration Whether to adjust this group's duration after removing atoms\n * @param atoms The atoms to remove\n * @returns This Group instance for method chaining\n */\n removeAtoms(adjustDuration = false, ...atoms: Atom[]): this {\n adjustDuration = adjustDuration && !this.durationIsSpeedMultiplier;\n const oldChildDuration = adjustDuration ? this.totalChildDuration : ONE;\n\n // Track which atoms were actually removed\n const removedAtoms: Atom[] = [];\n\n for (const atom of atoms) {\n if (atom.parentGroup == this) {\n this.atoms.remove(atom);\n atom.parentGroup = null;\n removedAtoms.push(atom);\n } else if (atom.parentGroup != null) {\n throw new Error(\"Atom cannot be removed as it does not belong to this group\");\n }\n }\n if (adjustDuration) {\n if (this._duration.isZero) {\n if (this.durationIsSpeedMultiplier) throw new Error(\"How can this be?\");\n this._duration = this.totalChildDuration;\n } else {\n const scaleFactor = this.totalChildDuration.divby(oldChildDuration);\n this._duration = this._duration.times(scaleFactor, true);\n }\n }\n\n // Notify observers if atoms were removed\n if (removedAtoms.length > 0) {\n this.notifyObservers(AtomChangeType.REMOVE, removedAtoms, -1);\n }\n\n return this;\n }\n}\n\n/**\n * Represents a line of notation containing multiple roles.\n * A line can have atoms starting before or after the cycle.\n */\nexport class Line extends Entity {\n readonly TYPE: string = \"Line\";\n\n /**\n * Offset tells how many notes before or after the cycle this line's atoms start at.\n */\n offset: Fraction = ZERO;\n\n /**\n * The roles contained in this line.\n */\n roles: Role[] = [];\n\n /**\n * Text to be displayed in the margin of the line.\n * This is a hacky solution to doing left side pre-margin text typically\n * found in notations - e.g., line X of a pallavi has this. This makes vertical\n * space less wasteful.\n *\n * A better solution is inter-beat annotation but it is very complex for now.\n */\n marginText = \"\";\n\n /**\n * The LayoutParams associated with this line.\n */\n layoutParams: LayoutParams;\n\n /**\n * Observers that receive notifications when roles change.\n */\n private _observers: LineObserver<Role, Line>[] = [];\n\n /**\n * Adds an observer to receive role change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: LineObserver<Role, Line>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: LineObserver<Role, Line>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Finds the index of a role with the given name.\n * @param name The name of the role to find\n * @returns The index of the role, or -1 if not found\n */\n indexOfRole(name: string): number {\n for (let i = 0; i < this.roles.length; i++) {\n if (this.roles[i].name == name) return i;\n }\n return -1;\n }\n\n /**\n * Checks if this line is empty (has no content in any role).\n */\n get isEmpty(): boolean {\n for (const r of this.roles) if (!r.isEmpty) return false;\n return true;\n }\n\n /**\n * Returns a debug-friendly representation of this Line.\n * @returns An object containing debug information\n */\n debugValue(): any {\n const out = {\n ...super.debugValue(),\n roles: this.roles.map((r) => r.debugValue()),\n };\n if (!this.offset.isZero) {\n out.offset = this.offset.toString();\n }\n return out;\n }\n\n /**\n * Copies the properties of this Line to another Line.\n * @param another The target Line to copy properties to\n */\n copyTo(another: this): void {\n super.copyTo(another);\n another.roles = this.roles.map((r) => r.clone());\n }\n\n /**\n * Adds atoms to a role in this line.\n * @param roleName The name of the role to add atoms to\n * @param defaultToNotes Whether to default to notes for this role\n * @param atoms The atoms to add\n * @returns This Line instance for method chaining\n */\n addAtoms(roleName: string, defaultToNotes: boolean, ...atoms: Atom[]): this {\n const role = this.ensureRole(roleName, defaultToNotes);\n role.addAtoms(...atoms);\n return this;\n }\n\n /**\n * Ensures a role with the given name exists in this line, creating it if needed.\n * @param roleName The name of the role to ensure\n * @param defaultToNotes Whether to default to notes for this role\n * @returns The role with the specified name\n */\n ensureRole(roleName: string, defaultToNotes: boolean): Role {\n // Ensure we have this many roles\n let ri = this.roles.findIndex((r) => r.name == roleName);\n if (ri < 0) {\n ri = this.roles.length;\n const role = new Role(this, roleName);\n role.defaultToNotes = defaultToNotes;\n this.roles.push(role);\n\n // Notify observers of new role\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onRoleAdded?.(this, roleName, role);\n }\n }\n }\n return this.roles[ri];\n }\n\n /**\n * Removes a role from this line.\n * @param roleName The name of the role to remove\n * @returns True if the role was removed, false if not found\n */\n removeRole(roleName: string): boolean {\n const ri = this.roles.findIndex((r) => r.name == roleName);\n if (ri >= 0) {\n this.roles.splice(ri, 1);\n\n // Notify observers of removed role\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onRoleRemoved?.(this, roleName);\n }\n }\n return true;\n }\n return false;\n }\n\n /**\n * Gets the maximum duration across all roles in this line.\n */\n get duration(): Fraction {\n let max = ZERO;\n for (const role of this.roles) {\n max = TSU.Num.Fraction.max(role.duration, max);\n }\n return max;\n }\n}\n\n/**\n * Represents a specific role or voice in a line of notation.\n * Each role contains a sequence of atoms.\n */\nexport class Role extends Entity {\n readonly TYPE = \"Role\";\n\n /**\n * Whether this role represents notes by default.\n */\n defaultToNotes = true;\n\n /**\n * The atoms in this role.\n */\n atoms: Atom[] = [];\n\n /**\n * Observers that receive notifications when atoms change.\n */\n private _observers: RoleObserver<Atom, Role>[] = [];\n\n /**\n * Creates a new Role with the specified line and name.\n * @param line The line this role belongs to\n * @param name The name of the role\n */\n constructor(\n public readonly line: Line,\n public readonly name: string,\n ) {\n super();\n }\n\n /**\n * Adds an observer to receive atom change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: RoleObserver<Atom, Role>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: RoleObserver<Atom, Role>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Notifies observers of atom changes.\n */\n private notifyObservers(type: AtomChangeType, atoms: Atom[], index: number): void {\n if (!this._eventsEnabled) return;\n for (const observer of this._observers) {\n switch (type) {\n case AtomChangeType.ADD:\n observer.onAtomsAdded?.(this, atoms, index);\n break;\n case AtomChangeType.INSERT:\n observer.onAtomsInserted?.(this, atoms, index);\n break;\n case AtomChangeType.REMOVE:\n observer.onAtomsRemoved?.(this, atoms);\n break;\n }\n }\n }\n\n /**\n * Checks if this role is empty (has no atoms).\n */\n get isEmpty(): boolean {\n return this.atoms.length == 0;\n }\n\n /**\n * Returns a debug-friendly representation of this Role.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { name: this.name, atoms: this.atoms.map((a) => a.debugValue()) };\n }\n\n /**\n * Adds atoms to the end of this role.\n * @param atoms The atoms to add\n */\n addAtoms(...atoms: Atom[]): void {\n this.insertAtomsAt(this.atoms.length, ...atoms);\n }\n\n /**\n * Inserts atoms at a specific index in this role.\n * @param index The index at which to insert\n * @param atoms The atoms to insert\n */\n insertAtomsAt(index: number, ...atoms: Atom[]): void {\n // Track which atoms were actually added (excluding REST atoms)\n const addedAtoms: Atom[] = [];\n let last: null | Atom = index > 0 ? this.atoms[index - 1] : null;\n\n for (const atom of atoms) {\n if (atom.TYPE == AtomType.REST) {\n if (last && last.TYPE != AtomType.GROUP && last.TYPE != AtomType.LABEL) {\n (last as LeafAtom).beforeRest = true;\n }\n } else {\n this.atoms.splice(index + addedAtoms.length, 0, atom);\n addedAtoms.push(atom);\n }\n last = atom;\n }\n\n // Notify observers if atoms were added\n if (addedAtoms.length > 0) {\n const isAppend = index >= this.atoms.length - addedAtoms.length;\n const type = isAppend ? AtomChangeType.ADD : AtomChangeType.INSERT;\n this.notifyObservers(type, addedAtoms, index);\n }\n }\n\n /**\n * Removes atoms from this role.\n * @param atoms The atoms to remove\n */\n removeAtoms(...atoms: Atom[]): void {\n const removedAtoms: Atom[] = [];\n\n for (const atom of atoms) {\n const idx = this.atoms.indexOf(atom);\n if (idx >= 0) {\n this.atoms.splice(idx, 1);\n removedAtoms.push(atom);\n }\n }\n\n // Notify observers if atoms were removed\n if (removedAtoms.length > 0) {\n this.notifyObservers(AtomChangeType.REMOVE, removedAtoms, -1);\n }\n }\n\n /**\n * Copies the properties of this Role to another Role.\n * @param another The target Role to copy properties to\n */\n copyTo(another: Role): void {\n another.addAtoms(...this.atoms);\n }\n\n /**\n * Gets the total duration of all atoms in this role.\n */\n get duration(): Fraction {\n return this.atoms.reduce((a, b) => a.plus(b.duration), ZERO);\n }\n}\n"]}
@@ -76,7 +76,7 @@ export declare abstract class LeafAtomView extends AtomView {
76
76
  export declare abstract class GroupView extends AtomView {
77
77
  group: Group;
78
78
  protected atomSpacing: number;
79
- protected groupElement: SVGGElement;
79
+ groupElement: SVGGElement;
80
80
  protected atomViews: AtomView[];
81
81
  private _embelishments;
82
82
  defaultToNotes: boolean;
@@ -84,6 +84,7 @@ export declare abstract class GroupView extends AtomView {
84
84
  scaleFactor: number;
85
85
  showContinuationMarkers: boolean;
86
86
  protected continuationMarkerElements: SVGTextElement[];
87
+ contentWidth: number;
87
88
  constructor(group: Group, config?: any);
88
89
  get totalDuration(): TSU.Num.Fraction;
89
90
  createElements(parent: SVGGraphicsElement): void;
package/lib/esm/shapes.js CHANGED
@@ -215,13 +215,14 @@ export class GroupView extends AtomView {
215
215
  this.defaultToNotes = true;
216
216
  this.needsLayout = true;
217
217
  this.scaleFactor = 1.0;
218
- this.showContinuationMarkers = true;
218
+ this.showContinuationMarkers = false;
219
219
  this.continuationMarkerElements = [];
220
- this.atomSpacing = 5;
220
+ this.contentWidth = 0;
221
+ this.atomSpacing = 2;
221
222
  this.setStyles(config || {});
222
223
  }
223
224
  get totalDuration() {
224
- return this.group.totalChildDuration;
225
+ return this.group.duration;
225
226
  }
226
227
  createElements(parent) {
227
228
  this.groupElement = TSU.DOM.createSVGNode("g", {
@@ -258,7 +259,7 @@ export class GroupView extends AtomView {
258
259
  });
259
260
  const totalDuration = this.group.totalChildDuration;
260
261
  const totalDurValue = totalDuration.num / totalDuration.den;
261
- const totalWidth = minWidthPerDuration * totalDurValue;
262
+ const totalWidth = Math.max(0, minWidthPerDuration * totalDurValue - this.atomSpacing);
262
263
  return new TSU.Geom.Size(totalWidth * this.scaleFactor, maxHeight * this.scaleFactor);
263
264
  }
264
265
  updateBounds(x, y, w, h) {
@@ -270,7 +271,9 @@ export class GroupView extends AtomView {
270
271
  transform += " scale(" + this.scaleFactor + ")";
271
272
  }
272
273
  this.groupElement.setAttribute("transform", transform);
273
- const currY = 0;
274
+ const unscaledContentHeight = this.minSize.height / this.scaleFactor;
275
+ const unscaledAllocatedHeight = this.hasHeight ? this.height / this.scaleFactor : unscaledContentHeight;
276
+ const currY = unscaledAllocatedHeight - unscaledContentHeight;
274
277
  const totalDur = this.group.totalChildDuration;
275
278
  const unscaledMinWidth = this.minSize.width / this.scaleFactor;
276
279
  const groupWidth = this.hasWidth ? this.width / this.scaleFactor : unscaledMinWidth;
@@ -284,7 +287,8 @@ export class GroupView extends AtomView {
284
287
  realX = prevNoteEndX;
285
288
  }
286
289
  av.setBounds(realX, currY, null, null, true);
287
- prevNoteEndX = realX + av.minSize.width;
290
+ const avWidth = av.contentWidth || av.bbox.width;
291
+ prevNoteEndX = realX + avWidth;
288
292
  if (this.showContinuationMarkers && !totalDur.isZero) {
289
293
  const atomDur = av.totalDuration;
290
294
  const durValue = atomDur.num / atomDur.den;
@@ -299,6 +303,7 @@ export class GroupView extends AtomView {
299
303
  }
300
304
  currTime = currTime.plus(av.totalDuration);
301
305
  });
306
+ this.contentWidth = prevNoteEndX;
302
307
  this.invalidateBounds();
303
308
  for (const e of this.embelishments)
304
309
  e.refreshLayout();
@@ -1 +1 @@
1
- {"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../src/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { ZERO, Atom, LeafAtom, Group } from \"./core\";\n\n/**\n * Represents an item to be positioned in collision-based layout.\n */\nexport interface CollisionLayoutItem {\n /** Time offset as a fraction (numerator/denominator) */\n timeOffset: TSU.Num.Fraction;\n /** Duration of this item */\n duration: TSU.Num.Fraction;\n /** Width of pre-embellishments (extends left from glyph position) */\n glyphOffset: number;\n /** Minimum width of the item (includes all embellishments and glyph) */\n minWidth: number;\n}\n\n/**\n * Result of collision-based layout for a single item.\n */\nexport interface CollisionLayoutResult {\n /** The calculated x position for the item */\n x: number;\n /** Whether the item was pushed right due to collision */\n wasCollision: boolean;\n}\n\n/**\n * Computes collision-based positions for a sequence of items within a container.\n *\n * ## Algorithm\n *\n * 1. Calculate ideal glyph position: `glyphX = (timeOffset / totalDuration) * containerWidth`\n * 2. Pre-embellishments extend left: `realX = glyphX - glyphOffset`\n * 3. Collision check: if `realX < prevItemEndX`, then `realX = prevItemEndX`\n * 4. Track: `prevItemEndX = realX + minWidth`\n *\n * @param items Items to position (must be in time order)\n * @param totalDuration Total duration of all items\n * @param containerWidth Width of the container to position items within\n * @returns Array of positions for each item\n */\nexport function computeCollisionLayout(\n items: CollisionLayoutItem[],\n totalDuration: TSU.Num.Fraction,\n containerWidth: number,\n): CollisionLayoutResult[] {\n const results: CollisionLayoutResult[] = [];\n let prevItemEndX = 0;\n let currTime = ZERO;\n\n for (const item of items) {\n // 1. Calculate ideal glyph position based on time offset\n const glyphX = totalDuration.isZero ? 0 : currTime.timesNum(containerWidth).divby(totalDuration).floor;\n\n // 2. Pre-embellishments extend left from glyph position\n let realX = glyphX - item.glyphOffset;\n\n // 3. Collision check: push right if overlapping previous item\n const wasCollision = realX < prevItemEndX;\n if (wasCollision) {\n realX = prevItemEndX;\n }\n\n results.push({ x: realX, wasCollision });\n\n // 4. Track end position for next collision check\n prevItemEndX = realX + item.minWidth;\n\n currTime = currTime.plus(item.duration);\n }\n\n return results;\n}\n\n/**\n * Base class for all renderable objects.\n *\n * Shape caches properties like bounding boxes to improve performance,\n * since bounding box calculations can be expensive. This also allows\n * testing layouts and positioning without worrying about implementation details.\n */\nexport abstract class Shape {\n private static idCounter = 0;\n readonly shapeId: number = Shape.idCounter++;\n\n /**\n * Note that x and y coordinates are not always the x and y coordinates\n * of the bounding box.\n * E.g., a circle's x and y coordinates are its center point and not the\n * top left corner.\n * These \"main\" coordinates are referred to as control coordinates.\n */\n protected _x: number | null = null;\n protected _y: number | null = null;\n protected _width: number | null = null;\n protected _height: number | null = null;\n protected _bbox: TSU.Geom.Rect;\n protected _minSize: TSU.Geom.Size;\n protected parentShape: Shape | null = null;\n /** Child shapes contained within this shape */\n children: Shape[] = [];\n\n /**\n * Gets the bounding box of this shape.\n * Calculates it if it hasn't been calculated yet.\n */\n get bbox(): TSU.Geom.Rect {\n if (!this._bbox) {\n this._bbox = this.refreshBBox();\n }\n return this._bbox;\n }\n\n /**\n * Gets the minimum size of this shape.\n * This is usually the size of the bounding box.\n */\n get minSize(): TSU.Geom.Size {\n if (!this._minSize) {\n this._minSize = this.refreshMinSize();\n }\n return this._minSize;\n }\n\n /**\n * Refreshes the bounding box of this shape.\n * Called when the shape knows the bbox it is tracking cannot be trusted\n * and has to be refreshed by calling native methods.\n * @returns The refreshed bounding box\n */\n protected abstract refreshBBox(): TSU.Geom.Rect;\n\n /**\n * Refreshes the minimum size of this shape.\n * @returns The refreshed minimum size\n */\n protected abstract refreshMinSize(): TSU.Geom.Size;\n\n /**\n * Updates the bounds of this shape.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected abstract updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null];\n\n /**\n * Invalidates the cached bounds of this shape.\n * Forces recalculation of bounding box and minimum size.\n */\n invalidateBounds(): void {\n this._minSize = null as unknown as TSU.Geom.Size;\n this._bbox = null as unknown as TSU.Geom.Rect;\n }\n\n /**\n * Sets the bounds of this shape.\n *\n * Note that null and NaN are valid values and mean the following:\n * - null: Don't change the value\n * - NaN: Set the value to null (use the bounding box's value)\n *\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @param applyLayout Whether to apply layout immediately\n * @returns The updated bounds values\n */\n setBounds(\n x: number | null,\n y: number | null,\n w: number | null,\n h: number | null,\n applyLayout = false,\n ): [number | null, number | null, number | null, number | null] {\n if (x != null) {\n if (isNaN(x)) {\n this._x = null;\n } else {\n this._x = x;\n }\n }\n if (y != null) {\n if (isNaN(y)) {\n this._y = null;\n } else {\n this._y = y;\n }\n }\n if (w != null) {\n if (isNaN(w)) {\n this._width = null;\n } else {\n this._width = w;\n }\n }\n if (h != null) {\n if (isNaN(h)) {\n this._height = null;\n } else {\n this._height = h;\n }\n }\n const [nx, ny, nw, nh] = this.updateBounds(x, y, w, h);\n if (nx != null) {\n if (isNaN(nx)) {\n this._x = null;\n } else {\n this._x = nx;\n }\n }\n if (ny != null) {\n if (isNaN(ny)) {\n this._y = null;\n } else {\n this._y = ny;\n }\n }\n if (nw != null) {\n if (isNaN(nw)) {\n this._width = null;\n } else {\n this._width = nw;\n }\n }\n if (nh != null) {\n if (isNaN(nh)) {\n this._height = null;\n } else {\n this._height = nh;\n }\n }\n if (applyLayout) this.refreshLayout();\n // this.resetBBox();\n return [nx, ny, nw, nh];\n }\n\n /**\n * Checks if this shape has an explicit x coordinate.\n */\n get hasX(): boolean {\n return this._x != null && !isNaN(this._x);\n }\n\n /**\n * Checks if this shape has an explicit y coordinate.\n */\n get hasY(): boolean {\n return this._y != null && !isNaN(this._y);\n }\n\n /**\n * Checks if this shape has an explicit width.\n */\n get hasWidth(): boolean {\n return this._width != null && !isNaN(this._width);\n }\n\n /**\n * Checks if this shape has an explicit height.\n */\n get hasHeight(): boolean {\n return this._height != null && !isNaN(this._height);\n }\n\n /**\n * Gets the x coordinate within the parent's coordinate system.\n */\n get x(): number {\n return this._x || 0;\n }\n\n /**\n * Sets the x coordinate within the parent's coordinate system.\n */\n set x(x: number | null) {\n // Here a manual x is being set - how does this interfere with the bounding box?\n // We should _x to the new value to indicate a manual value was set.\n // and reset bbox so that based on this x a new bbox may need to be calculated\n this.setBounds(x == null ? NaN : x, null, null, null);\n }\n\n /**\n * Gets the y coordinate within the parent's coordinate system.\n */\n get y(): number {\n if (this._y != null) return this._y;\n return 0; // this.bbox.y;\n }\n\n /**\n * Sets the y coordinate within the parent's coordinate system.\n */\n set y(y: number | null) {\n this.setBounds(null, y == null ? NaN : y, null, null);\n }\n\n /**\n * Gets the width of this shape.\n */\n get width(): number {\n if (this._width != null) return this._width;\n return 0; // this.bbox.width;\n }\n\n /**\n * Sets the width of this shape.\n */\n set width(w: number | null) {\n this.setBounds(null, null, w == null ? NaN : w, null);\n }\n\n /**\n * Gets the height of this shape.\n */\n get height(): number {\n if (this._height != null) return this._height;\n return 0; // this.bbox.height;\n }\n\n /**\n * Sets the height of this shape.\n */\n set height(h: number | null) {\n this.setBounds(null, null, null, h == null ? NaN : h);\n }\n\n /**\n * Refreshes the layout of this shape.\n * Called when bounds or other properties have changed to give the shape an\n * opportunity to layout its children. For shapes with no children this is a no-op.\n */\n refreshLayout(): void {\n // throw new Error(\"Implement this\");\n }\n}\n\n/**\n * Represents an embellishment applied to a musical element.\n */\nexport abstract class Embelishment extends Shape {}\n\n/**\n * A shape that wraps an SVG element.\n * ElementShape provides the base class for all shapes that are rendered as SVG elements.\n */\nexport class ElementShape<T extends SVGGraphicsElement = SVGGraphicsElement> extends Shape {\n /**\n * Creates a new ElementShape.\n * @param element The SVG element this shape wraps\n */\n constructor(public readonly element: T) {\n super();\n }\n\n /**\n * Refreshes the bounding box of this element.\n * @returns The refreshed bounding box\n */\n protected refreshBBox(): TSU.Geom.Rect {\n return TSU.DOM.svgBBox(this.element);\n }\n\n /**\n * Refreshes the minimum size of this element.\n * @returns The refreshed minimum size\n */\n protected refreshMinSize(): TSU.Geom.Size {\n return TSU.DOM.svgBBox(this.element);\n }\n\n /**\n * Updates the bounds of this element.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null] {\n return [x, y, w, h];\n }\n\n /**\n * Refreshes the layout of this element.\n * Updates the element's attributes based on the shape's properties.\n */\n refreshLayout(): void {\n if (this.hasX) this.element.setAttribute(\"x\", \"\" + this._x);\n if (this.hasY) this.element.setAttribute(\"y\", \"\" + this._y);\n }\n}\n\n/**\n * Base class for views that represent atoms in the notation.\n * AtomView provides the visual representation of an atom.\n */\nexport abstract class AtomView extends Shape {\n /** Nesting depth of this atom in the structure */\n depth = 0;\n /** Index of the role containing this atom */\n roleIndex = 0;\n\n // LayoutMetrics for the AtomView so all atomviews laid out on the\n // same baseline will show up aligned vertically\n /** Baseline position for vertical alignment */\n baseline: number;\n /** Ascent (space above baseline) */\n ascent: number;\n /** Descent (space below baseline) */\n descent: number;\n /** Height of capital letters */\n capHeight: number;\n /** Space between lines */\n leading: number;\n\n /**\n * Checks if this atom view represents a leaf atom.\n */\n abstract isLeaf(): boolean;\n\n abstract get totalDuration(): TSU.Num.Fraction;\n\n /**\n * Returns the horizontal offset from the atom's origin to where the note glyph starts.\n * This accounts for left embellishments that appear before the note.\n * Used by GroupView to align note glyphs at their correct time positions.\n *\n * Default is 0 (glyph starts at origin). Subclasses with left embellishments\n * should override to return the width of left-side decorations.\n */\n get glyphOffset(): number {\n return 0;\n }\n\n /**\n * Creates the SVG elements needed for this atom view.\n * @param parent The parent SVG element to attach to\n */\n abstract createElements(parent: SVGGraphicsElement): void;\n}\n\n/**\n * A view for leaf atoms (those that cannot contain other atoms).\n */\nexport abstract class LeafAtomView extends AtomView {\n /**\n * Creates a new LeafAtomView.\n * @param leafAtom The leaf atom this view represents\n */\n constructor(public leafAtom: LeafAtom) {\n super();\n }\n\n /**\n * Leaf atom views always return true for isLeaf().\n */\n isLeaf(): boolean {\n return true;\n }\n\n /**\n * Gets a unique identifier for this view based on the atom's UUID.\n */\n get viewId(): number {\n return this.leafAtom.uuid;\n }\n\n /**\n * Returns the total duration of the atom rendered by this view.\n */\n get totalDuration(): TSU.Num.Fraction {\n return this.leafAtom.duration;\n }\n}\n\n/**\n * A view for group atoms that contain multiple child atoms.\n */\nexport abstract class GroupView extends AtomView {\n /** Space between atoms in this group */\n protected atomSpacing: number;\n /** The SVG group element for this view */\n protected groupElement: SVGGElement;\n /** Views for the atoms in this group */\n protected atomViews: AtomView[] = [];\n private _embelishments: Embelishment[];\n /** Whether this group represents notes by default */\n defaultToNotes = true;\n /** Whether this view needs layout */\n needsLayout = true;\n /** Scale factor for this group */\n scaleFactor = 1.0;\n /**\n * When true, shows continuation markers (\",\") for atoms with duration > 1\n * instead of just leaving empty space.\n */\n showContinuationMarkers = true;\n /** SVG elements for continuation markers */\n protected continuationMarkerElements: SVGTextElement[] = [];\n\n /**\n * Creates a new GroupView.\n * @param group The group atom this view represents\n * @param config Optional configuration object\n */\n constructor(\n public group: Group,\n config?: any,\n ) {\n super();\n this.atomSpacing = 5;\n this.setStyles(config || {});\n }\n\n /**\n * Returns the total duration of the group rendered by this view.\n */\n get totalDuration(): TSU.Num.Fraction {\n return this.group.totalChildDuration;\n }\n\n /**\n * Creates the SVG elements needed for this group view.\n * @param parent The parent SVG element to attach to\n */\n createElements(parent: SVGGraphicsElement): void {\n this.groupElement = TSU.DOM.createSVGNode(\"g\", {\n parent: parent,\n attrs: {\n class: \"groupViewRoot\",\n id: \"groupViewRoot\" + this.group.uuid,\n },\n });\n\n // now create child atom views for each atom in this Group\n for (const atom of this.group.atoms.values()) {\n const atomView = this.createAtomView(atom);\n this.atomViews.push(atomView);\n }\n this.invalidateBounds();\n }\n\n /**\n * Group views always return false for isLeaf().\n */\n isLeaf(): boolean {\n return false;\n }\n\n /**\n * Refreshes the bounding box of this group.\n * @returns The refreshed bounding box\n */\n protected refreshBBox(): TSU.Geom.Rect {\n return TSU.DOM.svgBBox(this.groupElement);\n }\n\n /**\n * Refreshes the minimum size of this group using duration-based width calculation.\n *\n * ## Duration-Based Width Algorithm\n *\n * This algorithm ensures atoms with extended durations receive proportionally\n * more horizontal space. For example, with `\\beatDuration(4)` and input `S 2 R G M`:\n * - S has duration 1, R has duration 2, G has duration 1\n * - R should visually occupy twice the horizontal space of S or G\n *\n * ### Algorithm Steps:\n *\n * 1. **Calculate width per duration unit**: For each atom, compute the visual width\n * needed per unit of duration: `(visualWidth + spacing) / duration`\n *\n * 2. **Find maximum**: Take the maximum width-per-duration across all atoms.\n * This ensures every atom has enough space for its visual content.\n *\n * 3. **Scale by total duration**: Multiply the max width-per-duration by the\n * group's total duration to get the final group width.\n *\n * ### Example:\n * ```\n * Atoms: S(dur=1, width=10px), R(dur=2, width=10px), G(dur=1, width=10px)\n * Spacing: 5px\n *\n * Width per duration:\n * S: (10 + 5) / 1 = 15 px/unit\n * R: (10 + 5) / 2 = 7.5 px/unit\n * G: (10 + 5) / 1 = 15 px/unit\n *\n * Max width per duration: 15 px/unit\n * Total duration: 1 + 2 + 1 = 4 units\n * Group width: 15 * 4 = 60px\n *\n * Positioning:\n * S at x=0 (time 0/4 * 60 = 0)\n * R at x=15 (time 1/4 * 60 = 15)\n * G at x=45 (time 3/4 * 60 = 45)\n * ```\n *\n * @returns The refreshed minimum size\n */\n protected refreshMinSize(): TSU.Geom.Size {\n let maxHeight = 0;\n\n // Step 1: Calculate width per duration unit for each atom\n let minWidthPerDuration = 0;\n this.atomViews.forEach((av) => {\n const ms = av.minSize;\n const dur = av.totalDuration;\n if (!dur.isZero) {\n const durValue = dur.num / dur.den;\n const widthPerDur = (ms.width + this.atomSpacing) / durValue;\n // Step 2: Track maximum width per duration\n minWidthPerDuration = Math.max(minWidthPerDuration, widthPerDur);\n }\n maxHeight = Math.max(maxHeight, ms.height);\n });\n\n // Step 3: Scale by total duration\n const totalDuration = this.group.totalChildDuration;\n const totalDurValue = totalDuration.num / totalDuration.den;\n const totalWidth = minWidthPerDuration * totalDurValue;\n\n return new TSU.Geom.Size(totalWidth * this.scaleFactor, maxHeight * this.scaleFactor);\n }\n\n /**\n * Creates an atom view for a specific atom.\n * @param atom The atom to create a view for\n * @returns The created atom view\n */\n abstract createAtomView(atom: Atom): AtomView;\n\n /**\n * Updates the bounds of this group.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null] {\n return [x, y, w, h];\n }\n\n /**\n * Refreshes the layout of this group using collision-based positioning.\n *\n * ## Collision-Based Layout Algorithm\n *\n * Atoms are positioned using time-based positioning with collision avoidance.\n * Each atom starts at its ideal time-based position, but is pushed right if\n * it would overlap with the previous atom (including embellishments).\n *\n * ### Algorithm:\n * ```\n * 1. Calculate ideal glyph position: glyphX = (time / totalDuration) * groupWidth\n * 2. Pre-embellishments extend left: realX = glyphX - preEmbellishmentWidth\n * 3. Collision check: if (realX < prevNoteEndX) realX = prevNoteEndX\n * 4. Position the atom at realX\n * 5. Track: prevNoteEndX = realX + atom.minSize.width\n * ```\n *\n * ### Width Source Priority:\n *\n * 1. **Column width** (preferred): If width was set via `setBounds()` from the\n * grid layout system (ColAlign), use that width. This enables global alignment\n * across all beats in the same column.\n *\n * 2. **Minimum size**: Fall back to `minSize.width` calculated by `refreshMinSize()`.\n *\n * ### Continuation Markers:\n *\n * When `showContinuationMarkers` is true (default), atoms with duration > 1\n * will have \",\" markers rendered at each additional time slot. For example,\n * an atom with duration 2 will show \"R ,\" instead of \"R \".\n *\n * ### Example (no collisions):\n * ```\n * Input: S R G M (equal duration, no embellishments)\n * Group width: 60px, Total duration: 4 units\n *\n * Positioning:\n * S at x=0 (time 0/4 * 60 = 0)\n * R at x=15 (time 1/4 * 60 = 15)\n * G at x=30 (time 2/4 * 60 = 30)\n * M at x=45 (time 3/4 * 60 = 45)\n * ```\n *\n * ### Example (with collision):\n * ```\n * Input: [Jaaru+S] R (S has 10px pre-embellishment, each atom 15px wide)\n * Group width: 60px, Total duration: 2 units\n *\n * Without collision avoidance:\n * S.glyphX = 0, S.realX = 0 - 10 = -10 (clamped to 0)\n * R.glyphX = 30, R overlaps with S\n *\n * With collision avoidance:\n * S at x=0 (prevNoteEndX becomes 15)\n * R.glyphX = 30, R.realX = 30 - 0 = 30\n * 30 >= 15, no collision, R at x=30\n * ```\n */\n refreshLayout(): void {\n let transform = \"translate(\" + this.x + \",\" + this.y + \")\";\n if (this.scaleFactor < 1) {\n transform += \" scale(\" + this.scaleFactor + \")\";\n }\n this.groupElement.setAttribute(\"transform\", transform);\n\n const currY = 0;\n const totalDur = this.group.totalChildDuration;\n\n // Width source priority: column width (for global alignment) > minSize\n const unscaledMinWidth = this.minSize.width / this.scaleFactor;\n const groupWidth = this.hasWidth ? this.width / this.scaleFactor : unscaledMinWidth;\n\n // Clear existing continuation markers before re-rendering\n this.clearContinuationMarkers();\n\n // Position each atom using collision-based layout\n // Atoms start at their time-based position, but are pushed right if they would\n // overlap with the previous atom (including embellishments)\n let currTime = ZERO;\n let prevNoteEndX = 0;\n this.atomViews.forEach((av, index) => {\n // 1. Calculate ideal glyph position based on time offset\n const glyphX = totalDur.isZero ? 0 : currTime.timesNum(groupWidth).divby(totalDur).floor;\n\n // 2. Pre-embellishments extend left from glyph position\n // realX is where the atom origin should be placed\n let realX = glyphX - av.glyphOffset;\n\n // 3. Collision check: push right if overlapping previous atom\n if (realX < prevNoteEndX) {\n realX = prevNoteEndX;\n }\n\n // 4. Position the atom\n av.setBounds(realX, currY, null, null, true);\n\n // 5. Track end position for next collision check\n prevNoteEndX = realX + av.minSize.width;\n\n // Render continuation markers for atoms with duration > 1\n if (this.showContinuationMarkers && !totalDur.isZero) {\n const atomDur = av.totalDuration;\n const durValue = atomDur.num / atomDur.den;\n if (durValue > 1) {\n // Render one marker at each additional time slot within the atom's duration\n const numMarkers = Math.floor(durValue) - 1;\n for (let i = 1; i <= numMarkers; i++) {\n // Marker time = currTime + (atomDuration * i / floor(duration))\n const markerTime = currTime.plus(atomDur.timesNum(i).divbyNum(Math.floor(durValue)));\n const markerX = markerTime.timesNum(groupWidth).divby(totalDur).floor;\n this.renderContinuationMarker(markerX, currY);\n }\n }\n }\n\n currTime = currTime.plus(av.totalDuration);\n });\n\n this.invalidateBounds();\n for (const e of this.embelishments) e.refreshLayout();\n this.invalidateBounds();\n }\n\n /**\n * Clears all continuation marker elements.\n */\n protected clearContinuationMarkers(): void {\n for (const el of this.continuationMarkerElements) {\n el.remove();\n }\n this.continuationMarkerElements = [];\n }\n\n /**\n * Renders a continuation marker (\",\") at the specified position.\n * @param x X position for the marker\n * @param y Y position for the marker\n */\n protected renderContinuationMarker(x: number, y: number): void {\n const marker = TSU.DOM.createSVGNode(\"text\", {\n parent: this.groupElement,\n attrs: {\n class: \"continuationMarker\",\n x: x.toString(),\n y: y.toString(),\n },\n text: \",\",\n }) as SVGTextElement;\n this.continuationMarkerElements.push(marker);\n }\n\n /**\n * Gets the embellishments for this group.\n */\n get embelishments(): Embelishment[] {\n if (!this._embelishments) {\n this._embelishments = this.createEmbelishments();\n }\n return this._embelishments;\n }\n\n /**\n * Creates the embellishments for this group.\n * @returns An array of embellishments\n */\n protected createEmbelishments(): Embelishment[] {\n return [];\n }\n\n /**\n * Sets the styles for this group.\n * @param config Style configuration object\n */\n setStyles(config: any): void {\n if (\"atomSpacing\" in config) this.atomSpacing = config.atomSpacing;\n if (\"showContinuationMarkers\" in config) this.showContinuationMarkers = config.showContinuationMarkers;\n this.needsLayout = true;\n }\n}\n"]}
1
+ {"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../src/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { ZERO, Atom, LeafAtom, Group } from \"./core\";\n\n/**\n * Represents an item to be positioned in collision-based layout.\n */\nexport interface CollisionLayoutItem {\n /** Time offset as a fraction (numerator/denominator) */\n timeOffset: TSU.Num.Fraction;\n /** Duration of this item */\n duration: TSU.Num.Fraction;\n /** Width of pre-embellishments (extends left from glyph position) */\n glyphOffset: number;\n /** Minimum width of the item (includes all embellishments and glyph) */\n minWidth: number;\n}\n\n/**\n * Result of collision-based layout for a single item.\n */\nexport interface CollisionLayoutResult {\n /** The calculated x position for the item */\n x: number;\n /** Whether the item was pushed right due to collision */\n wasCollision: boolean;\n}\n\n/**\n * Computes collision-based positions for a sequence of items within a container.\n *\n * ## Algorithm\n *\n * 1. Calculate ideal glyph position: `glyphX = (timeOffset / totalDuration) * containerWidth`\n * 2. Pre-embellishments extend left: `realX = glyphX - glyphOffset`\n * 3. Collision check: if `realX < prevItemEndX`, then `realX = prevItemEndX`\n * 4. Track: `prevItemEndX = realX + minWidth`\n *\n * @param items Items to position (must be in time order)\n * @param totalDuration Total duration of all items\n * @param containerWidth Width of the container to position items within\n * @returns Array of positions for each item\n */\nexport function computeCollisionLayout(\n items: CollisionLayoutItem[],\n totalDuration: TSU.Num.Fraction,\n containerWidth: number,\n): CollisionLayoutResult[] {\n const results: CollisionLayoutResult[] = [];\n let prevItemEndX = 0;\n let currTime = ZERO;\n\n for (const item of items) {\n // 1. Calculate ideal glyph position based on time offset\n const glyphX = totalDuration.isZero ? 0 : currTime.timesNum(containerWidth).divby(totalDuration).floor;\n\n // 2. Pre-embellishments extend left from glyph position\n let realX = glyphX - item.glyphOffset;\n\n // 3. Collision check: push right if overlapping previous item\n const wasCollision = realX < prevItemEndX;\n if (wasCollision) {\n realX = prevItemEndX;\n }\n\n results.push({ x: realX, wasCollision });\n\n // 4. Track end position for next collision check\n prevItemEndX = realX + item.minWidth;\n\n currTime = currTime.plus(item.duration);\n }\n\n return results;\n}\n\n/**\n * Base class for all renderable objects.\n *\n * Shape caches properties like bounding boxes to improve performance,\n * since bounding box calculations can be expensive. This also allows\n * testing layouts and positioning without worrying about implementation details.\n */\nexport abstract class Shape {\n private static idCounter = 0;\n readonly shapeId: number = Shape.idCounter++;\n\n /**\n * Note that x and y coordinates are not always the x and y coordinates\n * of the bounding box.\n * E.g., a circle's x and y coordinates are its center point and not the\n * top left corner.\n * These \"main\" coordinates are referred to as control coordinates.\n */\n protected _x: number | null = null;\n protected _y: number | null = null;\n protected _width: number | null = null;\n protected _height: number | null = null;\n protected _bbox: TSU.Geom.Rect;\n protected _minSize: TSU.Geom.Size;\n protected parentShape: Shape | null = null;\n /** Child shapes contained within this shape */\n children: Shape[] = [];\n\n /**\n * Gets the bounding box of this shape.\n * Calculates it if it hasn't been calculated yet.\n */\n get bbox(): TSU.Geom.Rect {\n if (!this._bbox) {\n this._bbox = this.refreshBBox();\n }\n return this._bbox;\n }\n\n /**\n * Gets the minimum size of this shape.\n * This is usually the size of the bounding box.\n */\n get minSize(): TSU.Geom.Size {\n if (!this._minSize) {\n this._minSize = this.refreshMinSize();\n }\n return this._minSize;\n }\n\n /**\n * Refreshes the bounding box of this shape.\n * Called when the shape knows the bbox it is tracking cannot be trusted\n * and has to be refreshed by calling native methods.\n * @returns The refreshed bounding box\n */\n protected abstract refreshBBox(): TSU.Geom.Rect;\n\n /**\n * Refreshes the minimum size of this shape.\n * @returns The refreshed minimum size\n */\n protected abstract refreshMinSize(): TSU.Geom.Size;\n\n /**\n * Updates the bounds of this shape.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected abstract updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null];\n\n /**\n * Invalidates the cached bounds of this shape.\n * Forces recalculation of bounding box and minimum size.\n */\n invalidateBounds(): void {\n this._minSize = null as unknown as TSU.Geom.Size;\n this._bbox = null as unknown as TSU.Geom.Rect;\n }\n\n /**\n * Sets the bounds of this shape.\n *\n * Note that null and NaN are valid values and mean the following:\n * - null: Don't change the value\n * - NaN: Set the value to null (use the bounding box's value)\n *\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @param applyLayout Whether to apply layout immediately\n * @returns The updated bounds values\n */\n setBounds(\n x: number | null,\n y: number | null,\n w: number | null,\n h: number | null,\n applyLayout = false,\n ): [number | null, number | null, number | null, number | null] {\n if (x != null) {\n if (isNaN(x)) {\n this._x = null;\n } else {\n this._x = x;\n }\n }\n if (y != null) {\n if (isNaN(y)) {\n this._y = null;\n } else {\n this._y = y;\n }\n }\n if (w != null) {\n if (isNaN(w)) {\n this._width = null;\n } else {\n this._width = w;\n }\n }\n if (h != null) {\n if (isNaN(h)) {\n this._height = null;\n } else {\n this._height = h;\n }\n }\n const [nx, ny, nw, nh] = this.updateBounds(x, y, w, h);\n if (nx != null) {\n if (isNaN(nx)) {\n this._x = null;\n } else {\n this._x = nx;\n }\n }\n if (ny != null) {\n if (isNaN(ny)) {\n this._y = null;\n } else {\n this._y = ny;\n }\n }\n if (nw != null) {\n if (isNaN(nw)) {\n this._width = null;\n } else {\n this._width = nw;\n }\n }\n if (nh != null) {\n if (isNaN(nh)) {\n this._height = null;\n } else {\n this._height = nh;\n }\n }\n if (applyLayout) this.refreshLayout();\n // this.resetBBox();\n return [nx, ny, nw, nh];\n }\n\n /**\n * Checks if this shape has an explicit x coordinate.\n */\n get hasX(): boolean {\n return this._x != null && !isNaN(this._x);\n }\n\n /**\n * Checks if this shape has an explicit y coordinate.\n */\n get hasY(): boolean {\n return this._y != null && !isNaN(this._y);\n }\n\n /**\n * Checks if this shape has an explicit width.\n */\n get hasWidth(): boolean {\n return this._width != null && !isNaN(this._width);\n }\n\n /**\n * Checks if this shape has an explicit height.\n */\n get hasHeight(): boolean {\n return this._height != null && !isNaN(this._height);\n }\n\n /**\n * Gets the x coordinate within the parent's coordinate system.\n */\n get x(): number {\n return this._x || 0;\n }\n\n /**\n * Sets the x coordinate within the parent's coordinate system.\n */\n set x(x: number | null) {\n // Here a manual x is being set - how does this interfere with the bounding box?\n // We should _x to the new value to indicate a manual value was set.\n // and reset bbox so that based on this x a new bbox may need to be calculated\n this.setBounds(x == null ? NaN : x, null, null, null);\n }\n\n /**\n * Gets the y coordinate within the parent's coordinate system.\n */\n get y(): number {\n if (this._y != null) return this._y;\n return 0; // this.bbox.y;\n }\n\n /**\n * Sets the y coordinate within the parent's coordinate system.\n */\n set y(y: number | null) {\n this.setBounds(null, y == null ? NaN : y, null, null);\n }\n\n /**\n * Gets the width of this shape.\n */\n get width(): number {\n if (this._width != null) return this._width;\n return 0; // this.bbox.width;\n }\n\n /**\n * Sets the width of this shape.\n */\n set width(w: number | null) {\n this.setBounds(null, null, w == null ? NaN : w, null);\n }\n\n /**\n * Gets the height of this shape.\n */\n get height(): number {\n if (this._height != null) return this._height;\n return 0; // this.bbox.height;\n }\n\n /**\n * Sets the height of this shape.\n */\n set height(h: number | null) {\n this.setBounds(null, null, null, h == null ? NaN : h);\n }\n\n /**\n * Refreshes the layout of this shape.\n * Called when bounds or other properties have changed to give the shape an\n * opportunity to layout its children. For shapes with no children this is a no-op.\n */\n refreshLayout(): void {\n // throw new Error(\"Implement this\");\n }\n}\n\n/**\n * Represents an embellishment applied to a musical element.\n */\nexport abstract class Embelishment extends Shape {}\n\n/**\n * A shape that wraps an SVG element.\n * ElementShape provides the base class for all shapes that are rendered as SVG elements.\n */\nexport class ElementShape<T extends SVGGraphicsElement = SVGGraphicsElement> extends Shape {\n /**\n * Creates a new ElementShape.\n * @param element The SVG element this shape wraps\n */\n constructor(public readonly element: T) {\n super();\n }\n\n /**\n * Refreshes the bounding box of this element.\n * @returns The refreshed bounding box\n */\n protected refreshBBox(): TSU.Geom.Rect {\n return TSU.DOM.svgBBox(this.element);\n }\n\n /**\n * Refreshes the minimum size of this element.\n * @returns The refreshed minimum size\n */\n protected refreshMinSize(): TSU.Geom.Size {\n return TSU.DOM.svgBBox(this.element);\n }\n\n /**\n * Updates the bounds of this element.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null] {\n return [x, y, w, h];\n }\n\n /**\n * Refreshes the layout of this element.\n * Updates the element's attributes based on the shape's properties.\n */\n refreshLayout(): void {\n if (this.hasX) this.element.setAttribute(\"x\", \"\" + this._x);\n if (this.hasY) this.element.setAttribute(\"y\", \"\" + this._y);\n }\n}\n\n/**\n * Base class for views that represent atoms in the notation.\n * AtomView provides the visual representation of an atom.\n */\nexport abstract class AtomView extends Shape {\n /** Nesting depth of this atom in the structure */\n depth = 0;\n /** Index of the role containing this atom */\n roleIndex = 0;\n\n // LayoutMetrics for the AtomView so all atomviews laid out on the\n // same baseline will show up aligned vertically\n /** Baseline position for vertical alignment */\n baseline: number;\n /** Ascent (space above baseline) */\n ascent: number;\n /** Descent (space below baseline) */\n descent: number;\n /** Height of capital letters */\n capHeight: number;\n /** Space between lines */\n leading: number;\n\n /**\n * Checks if this atom view represents a leaf atom.\n */\n abstract isLeaf(): boolean;\n\n abstract get totalDuration(): TSU.Num.Fraction;\n\n /**\n * Returns the horizontal offset from the atom's origin to where the note glyph starts.\n * This accounts for left embellishments that appear before the note.\n * Used by GroupView to align note glyphs at their correct time positions.\n *\n * Default is 0 (glyph starts at origin). Subclasses with left embellishments\n * should override to return the width of left-side decorations.\n */\n get glyphOffset(): number {\n return 0;\n }\n\n /**\n * Creates the SVG elements needed for this atom view.\n * @param parent The parent SVG element to attach to\n */\n abstract createElements(parent: SVGGraphicsElement): void;\n}\n\n/**\n * A view for leaf atoms (those that cannot contain other atoms).\n */\nexport abstract class LeafAtomView extends AtomView {\n /**\n * Creates a new LeafAtomView.\n * @param leafAtom The leaf atom this view represents\n */\n constructor(public leafAtom: LeafAtom) {\n super();\n }\n\n /**\n * Leaf atom views always return true for isLeaf().\n */\n isLeaf(): boolean {\n return true;\n }\n\n /**\n * Gets a unique identifier for this view based on the atom's UUID.\n */\n get viewId(): number {\n return this.leafAtom.uuid;\n }\n\n /**\n * Returns the total duration of the atom rendered by this view.\n */\n get totalDuration(): TSU.Num.Fraction {\n return this.leafAtom.duration;\n }\n}\n\n/**\n * A view for group atoms that contain multiple child atoms.\n */\nexport abstract class GroupView extends AtomView {\n /** Space between atoms in this group */\n protected atomSpacing: number;\n /** The SVG group element for this view */\n groupElement: SVGGElement;\n /** Views for the atoms in this group */\n protected atomViews: AtomView[] = [];\n private _embelishments: Embelishment[];\n /** Whether this group represents notes by default */\n defaultToNotes = true;\n /** Whether this view needs layout */\n needsLayout = true;\n /** Scale factor for this group */\n scaleFactor = 1.0;\n /**\n * When true, shows continuation markers (\",\") for atoms with duration > 1\n * instead of just leaving empty space.\n * Disabled by default as group bracket lines provide clearer visual boundaries.\n */\n showContinuationMarkers = false;\n /** SVG elements for continuation markers */\n protected continuationMarkerElements: SVGTextElement[] = [];\n /** Actual content width after layout (position of last atom + its width) */\n contentWidth = 0;\n\n /**\n * Creates a new GroupView.\n * @param group The group atom this view represents\n * @param config Optional configuration object\n */\n constructor(\n public group: Group,\n config?: any,\n ) {\n super();\n this.atomSpacing = 2;\n this.setStyles(config || {});\n }\n\n /**\n * Returns the total duration of the group rendered by this view.\n * This returns the group's actual duration (accounting for scaling),\n * not the raw sum of child durations.\n */\n get totalDuration(): TSU.Num.Fraction {\n return this.group.duration;\n }\n\n /**\n * Creates the SVG elements needed for this group view.\n * @param parent The parent SVG element to attach to\n */\n createElements(parent: SVGGraphicsElement): void {\n this.groupElement = TSU.DOM.createSVGNode(\"g\", {\n parent: parent,\n attrs: {\n class: \"groupViewRoot\",\n id: \"groupViewRoot\" + this.group.uuid,\n },\n });\n\n // now create child atom views for each atom in this Group\n for (const atom of this.group.atoms.values()) {\n const atomView = this.createAtomView(atom);\n this.atomViews.push(atomView);\n }\n this.invalidateBounds();\n }\n\n /**\n * Group views always return false for isLeaf().\n */\n isLeaf(): boolean {\n return false;\n }\n\n /**\n * Refreshes the bounding box of this group.\n * @returns The refreshed bounding box\n */\n protected refreshBBox(): TSU.Geom.Rect {\n return TSU.DOM.svgBBox(this.groupElement);\n }\n\n /**\n * Refreshes the minimum size of this group using duration-based width calculation.\n *\n * ## Duration-Based Width Algorithm\n *\n * This algorithm ensures atoms with extended durations receive proportionally\n * more horizontal space. For example, with `\\beatDuration(4)` and input `S 2 R G M`:\n * - S has duration 1, R has duration 2, G has duration 1\n * - R should visually occupy twice the horizontal space of S or G\n *\n * ### Algorithm Steps:\n *\n * 1. **Calculate width per duration unit**: For each atom, compute the visual width\n * needed per unit of duration: `(visualWidth + spacing) / duration`\n *\n * 2. **Find maximum**: Take the maximum width-per-duration across all atoms.\n * This ensures every atom has enough space for its visual content.\n *\n * 3. **Scale by total duration**: Multiply the max width-per-duration by the\n * group's total duration to get the final group width.\n *\n * ### Example:\n * ```\n * Atoms: S(dur=1, width=10px), R(dur=2, width=10px), G(dur=1, width=10px)\n * Spacing: 5px\n *\n * Width per duration:\n * S: (10 + 5) / 1 = 15 px/unit\n * R: (10 + 5) / 2 = 7.5 px/unit\n * G: (10 + 5) / 1 = 15 px/unit\n *\n * Max width per duration: 15 px/unit\n * Total duration: 1 + 2 + 1 = 4 units\n * Group width: 15 * 4 = 60px\n *\n * Positioning:\n * S at x=0 (time 0/4 * 60 = 0)\n * R at x=15 (time 1/4 * 60 = 15)\n * G at x=45 (time 3/4 * 60 = 45)\n * ```\n *\n * @returns The refreshed minimum size\n */\n protected refreshMinSize(): TSU.Geom.Size {\n let maxHeight = 0;\n\n // Step 1: Calculate width per duration unit for each atom\n let minWidthPerDuration = 0;\n this.atomViews.forEach((av) => {\n const ms = av.minSize;\n const dur = av.totalDuration;\n if (!dur.isZero) {\n const durValue = dur.num / dur.den;\n const widthPerDur = (ms.width + this.atomSpacing) / durValue;\n // Step 2: Track maximum width per duration\n minWidthPerDuration = Math.max(minWidthPerDuration, widthPerDur);\n }\n maxHeight = Math.max(maxHeight, ms.height);\n });\n\n // Step 3: Scale by total duration\n const totalDuration = this.group.totalChildDuration;\n const totalDurValue = totalDuration.num / totalDuration.den;\n // Subtract one atomSpacing since we don't need spacing after the last atom\n const totalWidth = Math.max(0, minWidthPerDuration * totalDurValue - this.atomSpacing);\n\n return new TSU.Geom.Size(totalWidth * this.scaleFactor, maxHeight * this.scaleFactor);\n }\n\n /**\n * Creates an atom view for a specific atom.\n * @param atom The atom to create a view for\n * @returns The created atom view\n */\n abstract createAtomView(atom: Atom): AtomView;\n\n /**\n * Updates the bounds of this group.\n * @param x New x coordinate, or null to keep current value\n * @param y New y coordinate, or null to keep current value\n * @param w New width, or null to keep current value\n * @param h New height, or null to keep current value\n * @returns The updated bounds values\n */\n protected updateBounds(\n x: null | number,\n y: null | number,\n w: null | number,\n h: null | number,\n ): [number | null, number | null, number | null, number | null] {\n return [x, y, w, h];\n }\n\n /**\n * Refreshes the layout of this group using collision-based positioning.\n *\n * ## Collision-Based Layout Algorithm\n *\n * Atoms are positioned using time-based positioning with collision avoidance.\n * Each atom starts at its ideal time-based position, but is pushed right if\n * it would overlap with the previous atom (including embellishments).\n *\n * ### Algorithm:\n * ```\n * 1. Calculate ideal glyph position: glyphX = (time / totalDuration) * groupWidth\n * 2. Pre-embellishments extend left: realX = glyphX - preEmbellishmentWidth\n * 3. Collision check: if (realX < prevNoteEndX) realX = prevNoteEndX\n * 4. Position the atom at realX\n * 5. Track: prevNoteEndX = realX + atom.minSize.width\n * ```\n *\n * ### Width Source Priority:\n *\n * 1. **Column width** (preferred): If width was set via `setBounds()` from the\n * grid layout system (ColAlign), use that width. This enables global alignment\n * across all beats in the same column.\n *\n * 2. **Minimum size**: Fall back to `minSize.width` calculated by `refreshMinSize()`.\n *\n * ### Continuation Markers:\n *\n * When `showContinuationMarkers` is true (default), atoms with duration > 1\n * will have \",\" markers rendered at each additional time slot. For example,\n * an atom with duration 2 will show \"R ,\" instead of \"R \".\n *\n * ### Example (no collisions):\n * ```\n * Input: S R G M (equal duration, no embellishments)\n * Group width: 60px, Total duration: 4 units\n *\n * Positioning:\n * S at x=0 (time 0/4 * 60 = 0)\n * R at x=15 (time 1/4 * 60 = 15)\n * G at x=30 (time 2/4 * 60 = 30)\n * M at x=45 (time 3/4 * 60 = 45)\n * ```\n *\n * ### Example (with collision):\n * ```\n * Input: [Jaaru+S] R (S has 10px pre-embellishment, each atom 15px wide)\n * Group width: 60px, Total duration: 2 units\n *\n * Without collision avoidance:\n * S.glyphX = 0, S.realX = 0 - 10 = -10 (clamped to 0)\n * R.glyphX = 30, R overlaps with S\n *\n * With collision avoidance:\n * S at x=0 (prevNoteEndX becomes 15)\n * R.glyphX = 30, R.realX = 30 - 0 = 30\n * 30 >= 15, no collision, R at x=30\n * ```\n */\n refreshLayout(): void {\n let transform = \"translate(\" + this.x + \",\" + this.y + \")\";\n if (this.scaleFactor < 1) {\n transform += \" scale(\" + this.scaleFactor + \")\";\n }\n this.groupElement.setAttribute(\"transform\", transform);\n\n // BASELINE ALIGNMENT: Position atoms at bottom of allocated height.\n // This ensures atoms align across beats with different bracket heights.\n // When beats in the same row have different content heights (e.g., due to\n // nested group brackets), all beats get the same allocated height from the\n // grid. By positioning content at the bottom, atom baselines align.\n const unscaledContentHeight = this.minSize.height / this.scaleFactor;\n const unscaledAllocatedHeight = this.hasHeight ? this.height / this.scaleFactor : unscaledContentHeight;\n const currY = unscaledAllocatedHeight - unscaledContentHeight;\n\n const totalDur = this.group.totalChildDuration;\n\n // Width source priority: column width (for global alignment) > minSize\n const unscaledMinWidth = this.minSize.width / this.scaleFactor;\n const groupWidth = this.hasWidth ? this.width / this.scaleFactor : unscaledMinWidth;\n\n // Clear existing continuation markers before re-rendering\n this.clearContinuationMarkers();\n\n // Position each atom using collision-based layout\n // Atoms start at their time-based position, but are pushed right if they would\n // overlap with the previous atom (including embellishments)\n let currTime = ZERO;\n let prevNoteEndX = 0;\n this.atomViews.forEach((av, index) => {\n // 1. Calculate ideal glyph position based on time offset\n const glyphX = totalDur.isZero ? 0 : currTime.timesNum(groupWidth).divby(totalDur).floor;\n\n // 2. Pre-embellishments extend left from glyph position\n // realX is where the atom origin should be placed\n let realX = glyphX - av.glyphOffset;\n\n // 3. Collision check: push right if overlapping previous atom\n if (realX < prevNoteEndX) {\n realX = prevNoteEndX;\n }\n\n // 4. Position the atom\n av.setBounds(realX, currY, null, null, true);\n\n // 5. Track end position for next collision check\n // For groups, use contentWidth (actual content) instead of bbox.width (which may include extra space).\n // For leaf atoms, use bbox.width.\n const avWidth = (av as any).contentWidth || av.bbox.width;\n prevNoteEndX = realX + avWidth;\n\n // Render continuation markers for atoms with duration > 1\n if (this.showContinuationMarkers && !totalDur.isZero) {\n const atomDur = av.totalDuration;\n const durValue = atomDur.num / atomDur.den;\n if (durValue > 1) {\n // Render one marker at each additional time slot within the atom's duration\n const numMarkers = Math.floor(durValue) - 1;\n for (let i = 1; i <= numMarkers; i++) {\n // Marker time = currTime + (atomDuration * i / floor(duration))\n const markerTime = currTime.plus(atomDur.timesNum(i).divbyNum(Math.floor(durValue)));\n const markerX = markerTime.timesNum(groupWidth).divby(totalDur).floor;\n this.renderContinuationMarker(markerX, currY);\n }\n }\n }\n\n currTime = currTime.plus(av.totalDuration);\n });\n\n // Track actual content width for bracket sizing\n this.contentWidth = prevNoteEndX;\n\n this.invalidateBounds();\n for (const e of this.embelishments) e.refreshLayout();\n this.invalidateBounds();\n }\n\n /**\n * Clears all continuation marker elements.\n */\n protected clearContinuationMarkers(): void {\n for (const el of this.continuationMarkerElements) {\n el.remove();\n }\n this.continuationMarkerElements = [];\n }\n\n /**\n * Renders a continuation marker (\",\") at the specified position.\n * @param x X position for the marker\n * @param y Y position for the marker\n */\n protected renderContinuationMarker(x: number, y: number): void {\n const marker = TSU.DOM.createSVGNode(\"text\", {\n parent: this.groupElement,\n attrs: {\n class: \"continuationMarker\",\n x: x.toString(),\n y: y.toString(),\n },\n text: \",\",\n }) as SVGTextElement;\n this.continuationMarkerElements.push(marker);\n }\n\n /**\n * Gets the embellishments for this group.\n */\n get embelishments(): Embelishment[] {\n if (!this._embelishments) {\n this._embelishments = this.createEmbelishments();\n }\n return this._embelishments;\n }\n\n /**\n * Creates the embellishments for this group.\n * @returns An array of embellishments\n */\n protected createEmbelishments(): Embelishment[] {\n return [];\n }\n\n /**\n * Sets the styles for this group.\n * @param config Style configuration object\n */\n setStyles(config: any): void {\n if (\"atomSpacing\" in config) this.atomSpacing = config.atomSpacing;\n if (\"showContinuationMarkers\" in config) this.showContinuationMarkers = config.showContinuationMarkers;\n this.needsLayout = true;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notations",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "author": "Sriram Panyam",
5
5
  "description": "A package for modelling, parsing, laying out carnatic musical notation",
6
6
  "homepage": "https://github.com/panyam/notations#readme",
@@ -60,6 +60,21 @@
60
60
  fill: var(--notation-fill-color);
61
61
  }
62
62
 
63
+ /* Group bracket lines - top border of nested group containers */
64
+ .group-bracket-line {
65
+ stroke: var(--notation-stroke-color);
66
+ stroke-width: 1;
67
+ }
68
+
69
+ .group-bracket-circle {
70
+ fill: var(--notation-stroke-color);
71
+ stroke: none;
72
+ }
73
+
74
+ .group-bracket {
75
+ opacity: 0.8;
76
+ }
77
+
63
78
  /* Text elements - target all SVG text within notation */
64
79
  .notationsContentRootTable text,
65
80
  .atomViewTextRoot,