vite-plugin-specter 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/client.js +247 -18
- package/dist/extension-chrome/content.js +247 -18
- package/dist/extension-chrome/manifest.json +2 -2
- package/dist/extension-firefox/content.js +247 -18
- package/dist/extension-firefox/manifest.json +2 -8
- package/dist/index.cjs +247 -18
- package/dist/index.js +247 -18
- package/extension/content.js +247 -18
- package/extension/icons/specter.png +0 -0
- package/extension/manifest.firefox.json +3 -9
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ function getClientScript(options) {
|
|
|
40
40
|
var LABEL = '#8B8D94';
|
|
41
41
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
42
42
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
43
|
+
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
43
44
|
var ACTIVATE = ${JSON.stringify(activateShortcut)};
|
|
44
45
|
|
|
45
46
|
// \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -59,6 +60,9 @@ function getClientScript(options) {
|
|
|
59
60
|
var lastMouse = { x: 0, y: 0 };
|
|
60
61
|
var selectedEls = [];
|
|
61
62
|
var selectedBadges = [];
|
|
63
|
+
var noteMap = new Map();
|
|
64
|
+
var noteInputEl = null;
|
|
65
|
+
var noteTargetEl = null;
|
|
62
66
|
|
|
63
67
|
// \u2500\u2500\u2500 Tooltip \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
64
68
|
var tooltip = document.createElement('div');
|
|
@@ -218,11 +222,11 @@ function getClientScript(options) {
|
|
|
218
222
|
pillExpanded = true;
|
|
219
223
|
if (text) { pillText.textContent = text; return; }
|
|
220
224
|
if (selectedEls.length > 0) {
|
|
221
|
-
pillText.textContent = selectedEls.length + ' selected \xB7 Cmd+C copy all \xB7 Esc clear';
|
|
225
|
+
pillText.textContent = selectedEls.length + ' selected \xB7 N annotate \xB7 Cmd+C copy all \xB7 Esc clear';
|
|
222
226
|
} else if (measureMode) {
|
|
223
227
|
pillText.textContent = 'Measure \xB7 hover distances \xB7 M pin \xB7 Cmd+C copy \xB7 Option toggle';
|
|
224
228
|
} else {
|
|
225
|
-
pillText.textContent = 'Properties \xB7 hover
|
|
229
|
+
pillText.textContent = 'Properties \xB7 hover \xB7 P pick \xB7 N annotate \xB7 Cmd+C copy \xB7 Option measure';
|
|
226
230
|
}
|
|
227
231
|
}
|
|
228
232
|
|
|
@@ -342,6 +346,55 @@ function getClientScript(options) {
|
|
|
342
346
|
return null;
|
|
343
347
|
}
|
|
344
348
|
|
|
349
|
+
// Collapse a rule's declarations to their shortest lossless form: drop
|
|
350
|
+
// 'initial' (= default, no signal) and always-'normal' noise, and fold
|
|
351
|
+
// side/corner longhands back into shorthands (margin/padding/radius/gap/transition).
|
|
352
|
+
function cleanDecls(style) {
|
|
353
|
+
var m = {}, order = [];
|
|
354
|
+
for (var i = 0; i < style.length; i++) {
|
|
355
|
+
var p = style[i];
|
|
356
|
+
var v = style.getPropertyValue(p);
|
|
357
|
+
if (!v) continue;
|
|
358
|
+
if (v === 'initial') continue;
|
|
359
|
+
if (p === 'transition-behavior') continue;
|
|
360
|
+
if (!(p in m)) order.push(p);
|
|
361
|
+
m[p] = v;
|
|
362
|
+
}
|
|
363
|
+
var used = {}, collapses = {};
|
|
364
|
+
function four(name, t, r, b, l) {
|
|
365
|
+
if (m[t] === undefined || m[r] === undefined || m[b] === undefined || m[l] === undefined) return;
|
|
366
|
+
used[t] = used[r] = used[b] = used[l] = 1;
|
|
367
|
+
var a = m[t], c = m[r], d = m[b], e = m[l], sh;
|
|
368
|
+
if (a === c && c === d && d === e) sh = a;
|
|
369
|
+
else if (a === d && c === e) sh = a + ' ' + c;
|
|
370
|
+
else if (c === e) sh = a + ' ' + c + ' ' + d;
|
|
371
|
+
else sh = a + ' ' + c + ' ' + d + ' ' + e;
|
|
372
|
+
collapses[t] = name + ': ' + sh;
|
|
373
|
+
}
|
|
374
|
+
four('margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left');
|
|
375
|
+
four('padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left');
|
|
376
|
+
four('border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius');
|
|
377
|
+
if (m['row-gap'] !== undefined && m['column-gap'] !== undefined) {
|
|
378
|
+
var g = m['row-gap'] === m['column-gap'] ? m['row-gap'] : m['row-gap'] + ' ' + m['column-gap'];
|
|
379
|
+
collapses['row-gap'] = 'gap: ' + g; used['row-gap'] = used['column-gap'] = 1;
|
|
380
|
+
}
|
|
381
|
+
if (m['transition-property'] !== undefined) {
|
|
382
|
+
var tr = 'transition: ' + m['transition-property'];
|
|
383
|
+
if (m['transition-duration'] !== undefined) tr += ' ' + m['transition-duration'];
|
|
384
|
+
if (m['transition-timing-function'] !== undefined) tr += ' ' + m['transition-timing-function'];
|
|
385
|
+
if (m['transition-delay'] !== undefined && m['transition-delay'] !== '0s') tr += ' ' + m['transition-delay'];
|
|
386
|
+
collapses['transition-property'] = tr;
|
|
387
|
+
used['transition-property'] = used['transition-duration'] = used['transition-timing-function'] = used['transition-delay'] = 1;
|
|
388
|
+
}
|
|
389
|
+
var out = [];
|
|
390
|
+
order.forEach(function (p) {
|
|
391
|
+
if (collapses[p]) { out.push(' ' + collapses[p] + ';'); return; }
|
|
392
|
+
if (used[p]) return;
|
|
393
|
+
out.push(' ' + p + ': ' + m[p] + ';');
|
|
394
|
+
});
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
|
|
345
398
|
function getMatchingRules(el) {
|
|
346
399
|
var results = [];
|
|
347
400
|
try {
|
|
@@ -358,12 +411,7 @@ function getClientScript(options) {
|
|
|
358
411
|
if (/^[*,]|^:root|^html|^body$|^::before|^::after/.test(sel.trim())) continue;
|
|
359
412
|
try {
|
|
360
413
|
if (el.matches(sel)) {
|
|
361
|
-
var props =
|
|
362
|
-
for (var i = 0; i < rule.style.length; i++) {
|
|
363
|
-
var prop = rule.style[i];
|
|
364
|
-
var val = rule.style.getPropertyValue(prop);
|
|
365
|
-
if (val) props.push(' ' + prop + ': ' + val + ';');
|
|
366
|
-
}
|
|
414
|
+
var props = cleanDecls(rule.style);
|
|
367
415
|
if (props.length) results.push(sel + ' {\\n' + props.join('\\n') + '\\n}');
|
|
368
416
|
}
|
|
369
417
|
} catch (e) {}
|
|
@@ -483,9 +531,13 @@ function getClientScript(options) {
|
|
|
483
531
|
}
|
|
484
532
|
|
|
485
533
|
function buildMultiSelectCopyText() {
|
|
534
|
+
var n = selectedEls.length;
|
|
486
535
|
return selectedEls.map(function (el, i) {
|
|
487
536
|
var body = buildLLMClipboard(buildInfo(el));
|
|
488
|
-
|
|
537
|
+
var note = noteMap.get(el);
|
|
538
|
+
var header = n > 1 ? '[Specter ' + (i + 1) + '/' + n + ']' : '[Specter]';
|
|
539
|
+
if (note) header += '\\n\u270F\uFE0F CHANGE: ' + note;
|
|
540
|
+
return body.replace('[Specter]', header);
|
|
489
541
|
}).join('\\n\\n' + Array(41).join('\u2500') + '\\n\\n');
|
|
490
542
|
}
|
|
491
543
|
|
|
@@ -536,16 +588,25 @@ function getClientScript(options) {
|
|
|
536
588
|
}
|
|
537
589
|
|
|
538
590
|
// \u2500\u2500\u2500 Multi-select \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
539
|
-
function makeBadge(el, index) {
|
|
591
|
+
function makeBadge(el, index, note) {
|
|
540
592
|
var rect = el.getBoundingClientRect();
|
|
541
|
-
var
|
|
542
|
-
|
|
543
|
-
Object.assign(badge.style, {
|
|
593
|
+
var wrap = document.createElement('div');
|
|
594
|
+
Object.assign(wrap.style, {
|
|
544
595
|
position: 'fixed',
|
|
545
596
|
left: (rect.left - 4) + 'px',
|
|
546
597
|
top: (rect.top - 4) + 'px',
|
|
598
|
+
zIndex: '2147483644',
|
|
599
|
+
pointerEvents: 'none',
|
|
600
|
+
display: 'flex',
|
|
601
|
+
alignItems: 'flex-start',
|
|
602
|
+
gap: '4px',
|
|
603
|
+
});
|
|
604
|
+
var badge = document.createElement('div');
|
|
605
|
+
badge.textContent = String(index + 1);
|
|
606
|
+
Object.assign(badge.style, {
|
|
547
607
|
width: '20px',
|
|
548
608
|
height: '20px',
|
|
609
|
+
flexShrink: '0',
|
|
549
610
|
background: PURPLE,
|
|
550
611
|
color: '#fff',
|
|
551
612
|
fontSize: '11px',
|
|
@@ -555,19 +616,38 @@ function getClientScript(options) {
|
|
|
555
616
|
display: 'flex',
|
|
556
617
|
alignItems: 'center',
|
|
557
618
|
justifyContent: 'center',
|
|
558
|
-
zIndex: '2147483644',
|
|
559
|
-
pointerEvents: 'none',
|
|
560
619
|
boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
|
|
561
620
|
});
|
|
562
|
-
|
|
563
|
-
|
|
621
|
+
wrap.appendChild(badge);
|
|
622
|
+
if (note) {
|
|
623
|
+
var chip = document.createElement('div');
|
|
624
|
+
chip.textContent = '\u270F\uFE0F ' + (note.length > 32 ? note.slice(0, 32) + '\u2026' : note);
|
|
625
|
+
Object.assign(chip.style, {
|
|
626
|
+
maxWidth: '240px',
|
|
627
|
+
background: TIP_BG,
|
|
628
|
+
color: '#fff',
|
|
629
|
+
fontSize: '10px',
|
|
630
|
+
lineHeight: '16px',
|
|
631
|
+
fontFamily: MONO,
|
|
632
|
+
padding: '2px 6px',
|
|
633
|
+
borderRadius: '4px',
|
|
634
|
+
whiteSpace: 'nowrap',
|
|
635
|
+
overflow: 'hidden',
|
|
636
|
+
textOverflow: 'ellipsis',
|
|
637
|
+
border: '1px solid ' + PURPLE,
|
|
638
|
+
boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
|
|
639
|
+
});
|
|
640
|
+
wrap.appendChild(chip);
|
|
641
|
+
}
|
|
642
|
+
document.body.appendChild(wrap);
|
|
643
|
+
return wrap;
|
|
564
644
|
}
|
|
565
645
|
|
|
566
646
|
function rebuildBadges() {
|
|
567
647
|
selectedBadges.forEach(function (b) { b.remove(); });
|
|
568
648
|
selectedBadges.length = 0;
|
|
569
649
|
selectedEls.forEach(function (el, i) {
|
|
570
|
-
selectedBadges.push(makeBadge(el, i));
|
|
650
|
+
selectedBadges.push(makeBadge(el, i, noteMap.get(el)));
|
|
571
651
|
});
|
|
572
652
|
}
|
|
573
653
|
|
|
@@ -576,6 +656,7 @@ function getClientScript(options) {
|
|
|
576
656
|
if (idx >= 0) {
|
|
577
657
|
selectedEls.splice(idx, 1);
|
|
578
658
|
el.style.outline = '';
|
|
659
|
+
noteMap.delete(el);
|
|
579
660
|
} else {
|
|
580
661
|
selectedEls.push(el);
|
|
581
662
|
el.style.outline = '2px solid ' + PURPLE;
|
|
@@ -586,10 +667,12 @@ function getClientScript(options) {
|
|
|
586
667
|
}
|
|
587
668
|
|
|
588
669
|
function clearSelection() {
|
|
670
|
+
closeNoteInput();
|
|
589
671
|
selectedEls.forEach(function (el) { el.style.outline = ''; el.style.outlineOffset = ''; });
|
|
590
672
|
selectedEls.length = 0;
|
|
591
673
|
selectedBadges.forEach(function (b) { b.remove(); });
|
|
592
674
|
selectedBadges.length = 0;
|
|
675
|
+
noteMap.clear();
|
|
593
676
|
}
|
|
594
677
|
|
|
595
678
|
function updatePillForSelection() {
|
|
@@ -597,6 +680,142 @@ function getClientScript(options) {
|
|
|
597
680
|
else if (!pillWrap.matches(':hover')) collapsePill();
|
|
598
681
|
}
|
|
599
682
|
|
|
683
|
+
// \u2500\u2500\u2500 Annotations (inline change notes) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
684
|
+
function openNoteInput(el) {
|
|
685
|
+
closeNoteInput();
|
|
686
|
+
if (selectedEls.indexOf(el) < 0) {
|
|
687
|
+
clearHoverOutline();
|
|
688
|
+
hideTooltip();
|
|
689
|
+
selectedEls.push(el);
|
|
690
|
+
el.style.outline = '2px solid ' + PURPLE;
|
|
691
|
+
el.style.outlineOffset = '-1px';
|
|
692
|
+
}
|
|
693
|
+
noteTargetEl = el;
|
|
694
|
+
var rect = el.getBoundingClientRect();
|
|
695
|
+
|
|
696
|
+
var box = document.createElement('div');
|
|
697
|
+
Object.assign(box.style, {
|
|
698
|
+
position: 'fixed',
|
|
699
|
+
zIndex: '2147483647',
|
|
700
|
+
display: 'inline-flex',
|
|
701
|
+
alignItems: 'flex-start',
|
|
702
|
+
gap: '8px',
|
|
703
|
+
boxSizing: 'border-box',
|
|
704
|
+
background: TIP_BG,
|
|
705
|
+
border: '1px solid ' + PURPLE,
|
|
706
|
+
borderRadius: '8px',
|
|
707
|
+
padding: '11px 12px',
|
|
708
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.35)',
|
|
709
|
+
fontFamily: MONO,
|
|
710
|
+
});
|
|
711
|
+
var pen = document.createElement('span');
|
|
712
|
+
pen.innerHTML = PENCIL;
|
|
713
|
+
Object.assign(pen.style, {
|
|
714
|
+
display: 'flex',
|
|
715
|
+
alignItems: 'center',
|
|
716
|
+
flexShrink: '0',
|
|
717
|
+
marginTop: '2px',
|
|
718
|
+
color: '#E0A3F5',
|
|
719
|
+
});
|
|
720
|
+
var input = document.createElement('textarea');
|
|
721
|
+
input.rows = 1;
|
|
722
|
+
input.placeholder = 'Describe the change\u2026 (Enter to save)';
|
|
723
|
+
input.value = noteMap.get(el) || '';
|
|
724
|
+
Object.assign(input.style, {
|
|
725
|
+
flexShrink: '0',
|
|
726
|
+
background: 'transparent',
|
|
727
|
+
border: 'none',
|
|
728
|
+
outline: 'none',
|
|
729
|
+
resize: 'none',
|
|
730
|
+
overflow: 'hidden',
|
|
731
|
+
color: '#fff',
|
|
732
|
+
fontFamily: MONO,
|
|
733
|
+
fontSize: '12px',
|
|
734
|
+
lineHeight: '18px',
|
|
735
|
+
padding: '0',
|
|
736
|
+
margin: '0',
|
|
737
|
+
whiteSpace: 'pre-wrap',
|
|
738
|
+
overflowWrap: 'anywhere',
|
|
739
|
+
});
|
|
740
|
+
// Hidden mirror to measure single-line text width so the field grows as you type.
|
|
741
|
+
var meas = document.createElement('span');
|
|
742
|
+
Object.assign(meas.style, {
|
|
743
|
+
position: 'absolute',
|
|
744
|
+
visibility: 'hidden',
|
|
745
|
+
whiteSpace: 'pre',
|
|
746
|
+
pointerEvents: 'none',
|
|
747
|
+
fontFamily: MONO,
|
|
748
|
+
fontSize: '12px',
|
|
749
|
+
left: '-9999px',
|
|
750
|
+
top: '0',
|
|
751
|
+
});
|
|
752
|
+
box.appendChild(pen);
|
|
753
|
+
box.appendChild(input);
|
|
754
|
+
box.appendChild(meas);
|
|
755
|
+
document.body.appendChild(box);
|
|
756
|
+
noteInputEl = box;
|
|
757
|
+
|
|
758
|
+
var margin = 8;
|
|
759
|
+
function textW(t) { meas.textContent = t; return meas.offsetWidth; }
|
|
760
|
+
|
|
761
|
+
// Anchor to the element; the box is repositioned around this as it grows.
|
|
762
|
+
var anchorL = rect.left, anchorT = rect.top, anchorB = rect.bottom;
|
|
763
|
+
|
|
764
|
+
function sizeAndPosition() {
|
|
765
|
+
var vw = window.innerWidth, vh = window.innerHeight;
|
|
766
|
+
var maxBoxW = Math.min(560, vw - margin * 2);
|
|
767
|
+
var maxTextW = Math.max(120, maxBoxW - 55); // room for icon + gaps + padding
|
|
768
|
+
var placeholderW = textW(input.placeholder);
|
|
769
|
+
var minTextW = Math.min(placeholderW, maxTextW);
|
|
770
|
+
var maxTaH = Math.min(14 * 18, Math.max(18, (vh - margin * 2) - 24)); // cap ~14 lines, never past viewport
|
|
771
|
+
|
|
772
|
+
// Width: grow with content up to the max, then wrapping takes over.
|
|
773
|
+
var single = textW(input.value || input.placeholder) + 3;
|
|
774
|
+
input.style.width = Math.min(Math.max(single, minTextW), maxTextW) + 'px';
|
|
775
|
+
// Height: fit wrapped content, scroll only in the extreme case.
|
|
776
|
+
input.style.height = 'auto';
|
|
777
|
+
var h = input.scrollHeight;
|
|
778
|
+
if (h > maxTaH) { input.style.height = maxTaH + 'px'; input.style.overflowY = 'auto'; }
|
|
779
|
+
else { input.style.height = h + 'px'; input.style.overflowY = 'hidden'; }
|
|
780
|
+
|
|
781
|
+
// Keep the whole box on screen.
|
|
782
|
+
var bw = box.offsetWidth, bh = box.offsetHeight;
|
|
783
|
+
var left = Math.min(Math.max(anchorL, margin), Math.max(margin, vw - bw - margin));
|
|
784
|
+
var top = anchorT - bh - 8; // prefer sitting above the element
|
|
785
|
+
if (top < margin) top = anchorB + 8; // otherwise below it
|
|
786
|
+
if (top + bh > vh - margin) top = Math.max(margin, vh - bh - margin);
|
|
787
|
+
box.style.left = left + 'px';
|
|
788
|
+
box.style.top = top + 'px';
|
|
789
|
+
}
|
|
790
|
+
sizeAndPosition();
|
|
791
|
+
|
|
792
|
+
input.addEventListener('input', sizeAndPosition);
|
|
793
|
+
input.addEventListener('keydown', function (ev) {
|
|
794
|
+
ev.stopPropagation();
|
|
795
|
+
if (ev.key === 'Enter' && !ev.shiftKey) { ev.preventDefault(); commitNote(input.value); }
|
|
796
|
+
else if (ev.key === 'Escape') { ev.preventDefault(); closeNoteInput(); }
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
rebuildBadges();
|
|
800
|
+
updatePillForSelection();
|
|
801
|
+
setTimeout(function () { input.focus(); }, 0);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
function commitNote(val) {
|
|
805
|
+
val = (val || '').trim();
|
|
806
|
+
if (noteTargetEl) {
|
|
807
|
+
if (val) noteMap.set(noteTargetEl, val);
|
|
808
|
+
else noteMap.delete(noteTargetEl);
|
|
809
|
+
}
|
|
810
|
+
closeNoteInput();
|
|
811
|
+
rebuildBadges();
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function closeNoteInput() {
|
|
815
|
+
if (noteInputEl) { noteInputEl.remove(); noteInputEl = null; }
|
|
816
|
+
noteTargetEl = null;
|
|
817
|
+
}
|
|
818
|
+
|
|
600
819
|
// \u2500\u2500\u2500 Pin (measure) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
601
820
|
function setPin(el) {
|
|
602
821
|
pinEl = el;
|
|
@@ -893,6 +1112,7 @@ function getClientScript(options) {
|
|
|
893
1112
|
var target = e.target;
|
|
894
1113
|
if (!target || target === pillWrap || pillWrap.contains(target)) return;
|
|
895
1114
|
if (target === tooltip || tooltip.contains(target)) return;
|
|
1115
|
+
if (noteInputEl && (target === noteInputEl || noteInputEl.contains(target))) return;
|
|
896
1116
|
|
|
897
1117
|
lastHovered = target;
|
|
898
1118
|
|
|
@@ -927,6 +1147,9 @@ function getClientScript(options) {
|
|
|
927
1147
|
|
|
928
1148
|
if (!fiActive) return;
|
|
929
1149
|
|
|
1150
|
+
// Note editor open: let the field handle its own keys (Enter/Esc) and native copy/paste.
|
|
1151
|
+
if (noteInputEl) return;
|
|
1152
|
+
|
|
930
1153
|
if (e.key === 'Alt' && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
|
|
931
1154
|
optionHeld = true;
|
|
932
1155
|
return;
|
|
@@ -957,6 +1180,12 @@ function getClientScript(options) {
|
|
|
957
1180
|
return;
|
|
958
1181
|
}
|
|
959
1182
|
|
|
1183
|
+
if (e.key === 'n' || e.key === 'N') {
|
|
1184
|
+
if (!lastHovered) return;
|
|
1185
|
+
openNoteInput(lastHovered);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
960
1189
|
if (e.key === 'm' || e.key === 'M') {
|
|
961
1190
|
if (!measureMode || !lastHovered) return;
|
|
962
1191
|
if (pinEl) {
|