ascii-tabs 0.10.6 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -4
- package/ascii-tabs.js +72 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,12 +62,12 @@ Design notes: [spec](docs/spec-v0.1.md), [glossary](GLOSSARY.md), [ADRs](docs/ad
|
|
|
62
62
|
## Usage
|
|
63
63
|
|
|
64
64
|
```html
|
|
65
|
-
<script type="module" src="https://cdn.jsdelivr.net/gh/libasoles/ascii-tabs@0.
|
|
65
|
+
<script type="module" src="https://cdn.jsdelivr.net/gh/libasoles/ascii-tabs@0.11.3/ascii-tabs.js"></script>
|
|
66
66
|
|
|
67
67
|
<ascii-tabs></ascii-tabs>
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
A bare `<ascii-tabs>` is editable: a hint, one Sheet per Tab with copy and delete buttons, and an add button. Click a string and type the fret number (0–24); move with the arrow keys, Enter and Tab. Press Cmd+Right Arrow or Alt+Right Arrow to copy all six strings of the current column into the next column, replacing its contents, and move the cursor there. Press Cmd+0 or Alt+0 to fill only the empty cells of the current column with zeros, keeping existing frets and the cursor in place.
|
|
70
|
+
A bare `<ascii-tabs>` is editable: a hint, one Sheet per Tab with copy and delete buttons, and an add button. Click a string and type the fret number (0–24, or up to `max-fret`); move with the arrow keys, Enter and Tab. Press Cmd+Right Arrow or Alt+Right Arrow to copy all six strings of the current column into the next column, replacing its contents, and move the cursor there. Press Shift+Up Arrow or Shift+Down Arrow to re-finger the current note (or the whole selection) on the next String up or down that keeps its pitch, for example a 7 on String 5 becomes a 2 on String 4; nothing happens when no such position exists. Press Cmd+0 or Alt+0 to fill only the empty cells of the current column with zeros, keeping existing frets and the cursor in place.
|
|
71
71
|
|
|
72
72
|
Drag from an empty cell or a blank area of a Sheet to select notes inside a rectangle. Drag any selected note to move the group, keeping its relative columns and strings; occupied destination cells are replaced. Cmd+Right Arrow or Alt+Right Arrow duplicates the selected group immediately after its last column and selects the duplicate. Cmd/Ctrl+C or the Sheet's copy button copies the selection as ASCII; Cmd/Ctrl+V pastes ASCII at the current column, preserving string positions. Delete or Backspace removes the selected notes, and Escape clears the selection.
|
|
73
73
|
|
|
@@ -409,7 +409,7 @@ E|-----3-|</pre>
|
|
|
409
409
|
The copy button copies the same plain ASCII. `parse` and `format` are exported as pure functions:
|
|
410
410
|
|
|
411
411
|
```js
|
|
412
|
-
import { parse, format } from 'https://cdn.jsdelivr.net/gh/libasoles/ascii-tabs@0.
|
|
412
|
+
import { parse, format } from 'https://cdn.jsdelivr.net/gh/libasoles/ascii-tabs@0.11.3/ascii-tabs.js';
|
|
413
413
|
|
|
414
414
|
const tab = parse('1 -3--5-\n2 ------\n3 ------\n4 ------\n5 ------\n6 ------'); // one Tab: Column[]
|
|
415
415
|
format(tab, { spacing: 2 }); // "1 -3--5-\n2 ------\n..."
|
|
@@ -573,14 +573,33 @@ Changing or removing the attribute updates the view immediately.
|
|
|
573
573
|
|
|
574
574
|
## String labels
|
|
575
575
|
|
|
576
|
+
`max-fret` (property `maxFret`) sets the highest Fret the editor accepts when typing or re-fingering with Shift+Up/Down Arrow. It defaults to `24`; use `max-fret="19"` for a classical guitar. Values outside 1–24 fall back to 24. It does not rewrite notes already in `value`.
|
|
577
|
+
|
|
578
|
+
```html
|
|
579
|
+
<ascii-tabs max-fret="19"></ascii-tabs>
|
|
580
|
+
```
|
|
581
|
+
|
|
576
582
|
Strings are labelled `1`–`6` by default, on screen and in copied text. `labels="notes"` names them using `tuning` (standard tuning by default: `e B G D A E`, String 1 to 6). `labels="none"` hides the labels and uses their space for Columns. This also applies to copied text. The `labels` property accepts `"numbers"`, `"notes"`, or `"none"`; other values fall back to numbers. Parsing accepts all three styles whatever the attribute says.
|
|
577
583
|
|
|
578
584
|
```html
|
|
579
585
|
<ascii-tabs></ascii-tabs> <!-- 1 -3--5- -->
|
|
580
|
-
<ascii-tabs labels="notes"></ascii-tabs> <!-- e
|
|
586
|
+
<ascii-tabs labels="notes"></ascii-tabs> <!-- e -3--5- -->
|
|
581
587
|
<ascii-tabs labels="none"></ascii-tabs> <!-- -3--5- -->
|
|
582
588
|
```
|
|
583
589
|
|
|
590
|
+
String labels have no bars by default. Add the boolean `string-bars` attribute
|
|
591
|
+
(or set `element.stringBars = true`) to draw a `|` at the start of each String,
|
|
592
|
+
independently of the labels. The bars also appear in copied ASCII. Remove the
|
|
593
|
+
attribute or set the property to `false` to hide them. With labels, the bar
|
|
594
|
+
replaces the separating space, so `e|` and `1|` occupy two characters.
|
|
595
|
+
|
|
596
|
+
```html
|
|
597
|
+
<ascii-tabs labels="notes" string-bars></ascii-tabs> <!-- e|-3--5- -->
|
|
598
|
+
<ascii-tabs labels="none" string-bars></ascii-tabs> <!-- |-3--5- -->
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
The standalone formatter accepts the same option: `format(tab, { stringBars: true })`.
|
|
602
|
+
|
|
584
603
|
## Tool position
|
|
585
604
|
|
|
586
605
|
A Sheet's tools (copy, delete) stand in a column to the right of the Staves by default, and the Staves leave room for them. `tools="top"` lines them up in a row above the first String instead. Also available as the `tools` property.
|
package/ascii-tabs.js
CHANGED
|
@@ -23,14 +23,16 @@ const normalizeTuning = value => {
|
|
|
23
23
|
: [...STANDARD_TUNING];
|
|
24
24
|
};
|
|
25
25
|
const labelStyle = value => (value === 'notes' || value === 'none' ? value : 'numbers');
|
|
26
|
-
const stringLabels = (labels, tuning) => {
|
|
26
|
+
const stringLabels = (labels, tuning, stringBars = false) => {
|
|
27
27
|
if (labelStyle(labels) === 'none') return Array(STRING_COUNT).fill('');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const names = labelStyle(labels) === 'numbers'
|
|
29
|
+
? ['1', '2', '3', '4', '5', '6']
|
|
30
|
+
: tuning.map((name, s) => s === 0 ? name.toLowerCase() : name);
|
|
31
|
+
const width = Math.max(...names.map(name => name.length)) + (stringBars ? 0 : 1);
|
|
31
32
|
return names.map(name => name.padEnd(width, ' '));
|
|
32
33
|
};
|
|
33
|
-
const labelWidth = (labels, tuning) => stringLabels(labels, tuning)[0].length;
|
|
34
|
+
const labelWidth = (labels, tuning, stringBars = false) => stringLabels(labels, tuning, stringBars)[0].length;
|
|
35
|
+
const prefixWidth = (labels, tuning, stringBars) => labelWidth(labels, tuning, stringBars) + (stringBars ? 1 : 0);
|
|
34
36
|
const notationStyle = value => (value === 'letters' || value === 'solfege' ? value : 'frets');
|
|
35
37
|
const NOTE_NAMES = {
|
|
36
38
|
letters: ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'],
|
|
@@ -176,22 +178,22 @@ function layout(tab, spacing, capacity, notation, tuning, sizes = []) {
|
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
// One Tab as plain ASCII, every Staff cut right after its last Column
|
|
179
|
-
function format(tab, { spacing = DEFAULT_SPACING, labels = 'numbers', notation = 'frets', tuning = STANDARD_TUNING, width = Infinity, annotations = [], annotationFit = 'overflow' } = {}) {
|
|
181
|
+
function format(tab, { spacing = DEFAULT_SPACING, labels = 'numbers', stringBars = false, notation = 'frets', tuning = STANDARD_TUNING, width = Infinity, annotations = [], annotationFit = 'overflow' } = {}) {
|
|
180
182
|
tuning = normalizeTuning(tuning);
|
|
181
183
|
annotations = normalizeAnnotations([annotations], [tab])[0] ?? [];
|
|
182
|
-
const names = stringLabels(labels, tuning);
|
|
184
|
+
const names = stringLabels(labels, tuning, stringBars);
|
|
183
185
|
const columns = tab.slice(0, lastContent(tab, annotations) + 1);
|
|
184
186
|
if (!columns.length) return '';
|
|
185
187
|
const lead = '-'.repeat(leadingDashes(spacing));
|
|
186
188
|
const trail = '-'.repeat(spacing - lead.length);
|
|
187
|
-
const capacity = width -
|
|
189
|
+
const capacity = width - prefixWidth(labels, tuning, stringBars);
|
|
188
190
|
const sizes = annotationSizes(columns, annotations, normalizeAnnotationFit(annotationFit), { spacing, notation, tuning, capacity });
|
|
189
191
|
return layout(columns, spacing, capacity, notation, tuning, sizes)
|
|
190
192
|
.map(([start, end]) => {
|
|
191
193
|
const offsets = columnOffsets(columns, start, end, spacing, notation, tuning, sizes);
|
|
192
|
-
const lines = annotationLines(annotations, start, end, offsets,
|
|
194
|
+
const lines = annotationLines(annotations, start, end, offsets, prefixWidth(labels, tuning, stringBars));
|
|
193
195
|
for (let s = 0; s < STRING_COUNT; s++) {
|
|
194
|
-
let line = names[s];
|
|
196
|
+
let line = names[s] + (stringBars ? '|' : '');
|
|
195
197
|
for (let c = start; c < end; c++) {
|
|
196
198
|
const digits = sizes[c] ?? columnDigits(columns[c], notation, tuning);
|
|
197
199
|
const fret = fretText(columns[c][s], s, notation, tuning);
|
|
@@ -229,7 +231,7 @@ function parse(ascii) {
|
|
|
229
231
|
continue;
|
|
230
232
|
}
|
|
231
233
|
const label = LABEL_PATTERN.exec(line);
|
|
232
|
-
if (!label && !/^\s
|
|
234
|
+
if (!label && !/^\s*[-|]/.test(line)) return fail(`unexpected line "${line.trim()}"`);
|
|
233
235
|
const body = label ? line.slice(label[0].length) : line;
|
|
234
236
|
if (!/^[-|\d\s]*$/.test(body.replace(/\(\d*\)/g, ''))) return fail(`unexpected characters in "${line.trim()}"`);
|
|
235
237
|
group.push(body);
|
|
@@ -453,6 +455,7 @@ ascii-tabs .ascii-tabs-text-editor:focus { border-bottom-color: var(--ascii-tabs
|
|
|
453
455
|
|
|
454
456
|
ascii-tabs .ascii-tabs-line { display: block; height: 1.5em; line-height: 1.5em; }
|
|
455
457
|
ascii-tabs .ascii-tabs-label { color: var(--ascii-tabs-dash); }
|
|
458
|
+
ascii-tabs .ascii-tabs-bar { display: inline-block; flex: 0 0 1ch; }
|
|
456
459
|
ascii-tabs .ascii-tabs-string { color: var(--ascii-tabs-string); }
|
|
457
460
|
ascii-tabs .ascii-tabs-cell {
|
|
458
461
|
display: inline-block; height: 1.5em;
|
|
@@ -785,7 +788,7 @@ class AsciiTabs extends Base {
|
|
|
785
788
|
}
|
|
786
789
|
}
|
|
787
790
|
|
|
788
|
-
static observedAttributes = ['readonly', 'spacing', 'labels', 'notation', 'tuning', 'lang', 'tools', 'annotations-editable', 'titles-editable', 'annotation-fit'];
|
|
791
|
+
static observedAttributes = ['readonly', 'spacing', 'labels', 'string-bars', 'notation', 'tuning', 'lang', 'tools', 'annotations-editable', 'titles-editable', 'annotation-fit', 'max-fret'];
|
|
789
792
|
|
|
790
793
|
// Strings: the `lang` preset (English by default) with `messages` merged over it
|
|
791
794
|
get #text() {
|
|
@@ -830,6 +833,14 @@ class AsciiTabs extends Base {
|
|
|
830
833
|
this.setAttribute('labels', labelStyle(value));
|
|
831
834
|
}
|
|
832
835
|
|
|
836
|
+
get stringBars() {
|
|
837
|
+
return this.hasAttribute('string-bars');
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
set stringBars(on) {
|
|
841
|
+
this.toggleAttribute('string-bars', Boolean(on));
|
|
842
|
+
}
|
|
843
|
+
|
|
833
844
|
get notation() {
|
|
834
845
|
return notationStyle(this.getAttribute('notation'));
|
|
835
846
|
}
|
|
@@ -846,6 +857,16 @@ class AsciiTabs extends Base {
|
|
|
846
857
|
this.setAttribute('tuning', normalizeTuning(value).join(' '));
|
|
847
858
|
}
|
|
848
859
|
|
|
860
|
+
// Highest Fret the editor accepts: 24 by default, lower for instruments with fewer frets
|
|
861
|
+
get maxFret() {
|
|
862
|
+
const n = Math.floor(Number(this.getAttribute('max-fret')));
|
|
863
|
+
return Number.isFinite(n) && n >= 1 && n <= MAX_FRET ? n : MAX_FRET;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
set maxFret(value) {
|
|
867
|
+
this.setAttribute('max-fret', value);
|
|
868
|
+
}
|
|
869
|
+
|
|
849
870
|
get tools() {
|
|
850
871
|
return toolsPosition(this.getAttribute('tools'));
|
|
851
872
|
}
|
|
@@ -881,7 +902,7 @@ class AsciiTabs extends Base {
|
|
|
881
902
|
|
|
882
903
|
attributeChangedCallback(name) {
|
|
883
904
|
if (name === 'spacing') return this.#applySpacing();
|
|
884
|
-
if (name === 'labels' || name === 'tuning') {
|
|
905
|
+
if (name === 'labels' || name === 'string-bars' || name === 'tuning') {
|
|
885
906
|
this.#measure();
|
|
886
907
|
return this.#render();
|
|
887
908
|
}
|
|
@@ -911,7 +932,7 @@ class AsciiTabs extends Base {
|
|
|
911
932
|
return;
|
|
912
933
|
}
|
|
913
934
|
// Properties set before the element was upgraded shadow the accessors
|
|
914
|
-
for (const name of ['value', 'columnLayout', 'annotations', 'tabTitles', 'annotationsEditable', 'titlesEditable', 'annotationFit', 'readonly', 'spacing', 'labels', 'notation', 'tuning', 'tools', 'variant', 'theme', 'messages']) {
|
|
935
|
+
for (const name of ['value', 'columnLayout', 'annotations', 'tabTitles', 'annotationsEditable', 'titlesEditable', 'annotationFit', 'readonly', 'spacing', 'labels', 'stringBars', 'notation', 'tuning', 'maxFret', 'tools', 'variant', 'theme', 'messages']) {
|
|
915
936
|
if (Object.hasOwn(this, name)) {
|
|
916
937
|
const own = this[name];
|
|
917
938
|
delete this[name];
|
|
@@ -1110,7 +1131,7 @@ class AsciiTabs extends Base {
|
|
|
1110
1131
|
if (!charWidth) return;
|
|
1111
1132
|
this.#scheduleOverflow();
|
|
1112
1133
|
const chars = Math.floor(width / charWidth);
|
|
1113
|
-
const capacity = Math.max(chars -
|
|
1134
|
+
const capacity = Math.max(chars - prefixWidth(this.labels, this.tuning, this.stringBars), 4 * (this.#spacing + 1));
|
|
1114
1135
|
const signature = `${width}:${charWidth}`;
|
|
1115
1136
|
const annotationResized = this.#annotationMeasure !== signature;
|
|
1116
1137
|
this.#annotationMeasure = signature;
|
|
@@ -1163,8 +1184,8 @@ class AsciiTabs extends Base {
|
|
|
1163
1184
|
this.#annotationResizeObserver?.disconnect();
|
|
1164
1185
|
const annotationPositions = [];
|
|
1165
1186
|
const labels = this.labels, notation = this.notation, tuning = this.tuning;
|
|
1166
|
-
const gutter = labelWidth(labels, tuning);
|
|
1167
|
-
const names = stringLabels(labels, tuning);
|
|
1187
|
+
const gutter = labelWidth(labels, tuning, this.stringBars);
|
|
1188
|
+
const names = stringLabels(labels, tuning, this.stringBars);
|
|
1168
1189
|
this.#titleEls.forEach((title, t) => {
|
|
1169
1190
|
title.textContent = this.#tabTitles[t] ?? '';
|
|
1170
1191
|
title.hidden = !title.textContent && !(this.titlesEditable && !this.readonly);
|
|
@@ -1188,6 +1209,7 @@ class AsciiTabs extends Base {
|
|
|
1188
1209
|
for (let s = 0; s < STRING_COUNT; s++) {
|
|
1189
1210
|
html += '<span class="ascii-tabs-line">';
|
|
1190
1211
|
if (labels !== 'none') html += `<span class="ascii-tabs-label" style="flex-basis:${gutter}ch">${names[s]}</span>`;
|
|
1212
|
+
if (this.stringBars) html += '<span class="ascii-tabs-bar ascii-tabs-string" aria-hidden="true">|</span>';
|
|
1191
1213
|
if (geometry) html += `<span class="ascii-tabs-area" data-t="${t}" data-s="${s}" style="width:${geometry.width}px">`;
|
|
1192
1214
|
for (let c = start; c < end; c++) {
|
|
1193
1215
|
const isCur = this.#cur && this.#cur.t === t && this.#cur.c === c && this.#cur.s === s;
|
|
@@ -1239,7 +1261,7 @@ class AsciiTabs extends Base {
|
|
|
1239
1261
|
const annotations = entries.filter(a => a.column >= start && a.column < end && (a.html ?? a.text));
|
|
1240
1262
|
if (!annotations.length && !(this.annotationsEditable && !this.readonly)) return;
|
|
1241
1263
|
const band = this.#el('div', 'ascii-tabs-annotations');
|
|
1242
|
-
if (geometry) band.style.width = `calc(${geometry.width}px + ${
|
|
1264
|
+
if (geometry) band.style.width = `calc(${geometry.width}px + ${prefixWidth(this.labels, this.tuning, this.stringBars)}ch)`;
|
|
1243
1265
|
staff.prepend(band);
|
|
1244
1266
|
const shown = shownAnnotations(entries);
|
|
1245
1267
|
for (const entry of annotations) {
|
|
@@ -1653,6 +1675,33 @@ class AsciiTabs extends Base {
|
|
|
1653
1675
|
this.#goTo(t, c, s + d);
|
|
1654
1676
|
}
|
|
1655
1677
|
|
|
1678
|
+
// Shift+Up/Down: re-finger the focused or selected notes on the nearest String that keeps their
|
|
1679
|
+
// pitch and puts every one of them within 0..maxFret. Strings are assumed to descend in pitch.
|
|
1680
|
+
#refinger(d) {
|
|
1681
|
+
const notes = (this.#selection.length ? this.#selection : [this.#cur]).filter(p => this.#tabs[p.t][p.c]?.[p.s] != null);
|
|
1682
|
+
if (!notes.length) return;
|
|
1683
|
+
const tuning = this.tuning;
|
|
1684
|
+
const depth = [0];
|
|
1685
|
+
for (let s = 1; s < STRING_COUNT; s++) depth[s] = depth[s - 1] + ((tuningPitch(tuning[s - 1]) - tuningPitch(tuning[s]) + 11) % 12 + 1);
|
|
1686
|
+
for (let step = 1; step < STRING_COUNT; step++) {
|
|
1687
|
+
const moved = notes.map(p => {
|
|
1688
|
+
const to = p.s + d * step;
|
|
1689
|
+
const note = this.#tabs[p.t][p.c][p.s];
|
|
1690
|
+
return { ...p, to, fret: fretValue(note) + depth[to] - depth[p.s], note };
|
|
1691
|
+
});
|
|
1692
|
+
if (moved.some(m => m.to < 0 || m.to >= STRING_COUNT || !isFret(m.fret) || m.fret > this.maxFret)) {
|
|
1693
|
+
if (moved.some(m => m.to < 0 || m.to >= STRING_COUNT)) return;
|
|
1694
|
+
continue;
|
|
1695
|
+
}
|
|
1696
|
+
for (const m of moved) this.#setFret(m.t, m.c, m.s, null);
|
|
1697
|
+
for (const m of moved) this.#setFret(m.t, m.c, m.to, typeof m.note === 'object' ? { ...m.note, fret: m.fret } : m.fret);
|
|
1698
|
+
const { t, c, s } = this.#cur;
|
|
1699
|
+
if (this.#selection.length) this.#selection = moved.map(m => ({ t: m.t, c: m.c, s: m.to }));
|
|
1700
|
+
this.#goTo(t, c, s + d * step, this.#selection.length > 0);
|
|
1701
|
+
return this.#emitChange(this.#selection.length ? null : this.#cur);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1656
1705
|
// Typing writes to the value straight away, so `change` follows every keystroke
|
|
1657
1706
|
#edit(draft, keepParentheses = true) {
|
|
1658
1707
|
this.#selection = [];
|
|
@@ -1670,7 +1719,7 @@ class AsciiTabs extends Base {
|
|
|
1670
1719
|
#typeDigit(d) {
|
|
1671
1720
|
if (this.#draft === null || this.#draft === '') return this.#edit(d);
|
|
1672
1721
|
const next = this.#draft + d;
|
|
1673
|
-
if (/^(0|[1-9][0-9]?)$/.test(next) && Number(next) <=
|
|
1722
|
+
if (/^(0|[1-9][0-9]?)$/.test(next) && Number(next) <= this.maxFret) this.#edit(next);
|
|
1674
1723
|
}
|
|
1675
1724
|
|
|
1676
1725
|
#parenthesize() {
|
|
@@ -1751,10 +1800,10 @@ class AsciiTabs extends Base {
|
|
|
1751
1800
|
return this.#moveHorizontal(-1);
|
|
1752
1801
|
case 'ArrowUp':
|
|
1753
1802
|
e.preventDefault();
|
|
1754
|
-
return this.#moveVertical(-1);
|
|
1803
|
+
return e.shiftKey ? this.#refinger(-1) : this.#moveVertical(-1);
|
|
1755
1804
|
case 'ArrowDown':
|
|
1756
1805
|
e.preventDefault();
|
|
1757
|
-
return this.#moveVertical(1);
|
|
1806
|
+
return e.shiftKey ? this.#refinger(1) : this.#moveVertical(1);
|
|
1758
1807
|
case 'Backspace': {
|
|
1759
1808
|
e.preventDefault();
|
|
1760
1809
|
const { t, c, s } = this.#cur;
|
|
@@ -1786,7 +1835,7 @@ class AsciiTabs extends Base {
|
|
|
1786
1835
|
const last = Math.max(...this.#selection.map(p => p.c));
|
|
1787
1836
|
const columns = Array.from({ length: last - first + 1 }, emptyColumn);
|
|
1788
1837
|
for (const { t, c, s } of this.#selection) columns[c - first][s] = this.#tabs[t][c][s];
|
|
1789
|
-
return format(columns, { spacing: this.#spacing, labels: this.labels, notation: this.notation, tuning: this.tuning });
|
|
1838
|
+
return format(columns, { spacing: this.#spacing, labels: this.labels, stringBars: this.stringBars, notation: this.notation, tuning: this.tuning });
|
|
1790
1839
|
}
|
|
1791
1840
|
|
|
1792
1841
|
#onCopy = e => {
|
|
@@ -1975,7 +2024,7 @@ class AsciiTabs extends Base {
|
|
|
1975
2024
|
async copy(index = 0) {
|
|
1976
2025
|
const tab = this.#tabs[index];
|
|
1977
2026
|
if (!tab) return;
|
|
1978
|
-
await copyText(this.#selection.length && this.#selection[0].t === index ? this.#selectionText() : format(tab, { spacing: this.#spacing, labels: this.labels, notation: this.notation, tuning: this.tuning, width: this.#capacity +
|
|
2027
|
+
await copyText(this.#selection.length && this.#selection[0].t === index ? this.#selectionText() : format(tab, { spacing: this.#spacing, labels: this.labels, stringBars: this.stringBars, notation: this.notation, tuning: this.tuning, width: this.#capacity + prefixWidth(this.labels, this.tuning, this.stringBars), annotations: this.#annotations[index], annotationFit: this.#annotationFit() }));
|
|
1979
2028
|
const button = this.#sheetEls[index]?.querySelector('.ascii-tabs-copy');
|
|
1980
2029
|
if (!button) return;
|
|
1981
2030
|
this.#flashCopied(button);
|