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.js
CHANGED
|
@@ -13,6 +13,7 @@ function getClientScript(options) {
|
|
|
13
13
|
var LABEL = '#8B8D94';
|
|
14
14
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
15
15
|
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>';
|
|
16
|
+
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>';
|
|
16
17
|
var ACTIVATE = ${JSON.stringify(activateShortcut)};
|
|
17
18
|
|
|
18
19
|
// \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
|
|
@@ -32,6 +33,9 @@ function getClientScript(options) {
|
|
|
32
33
|
var lastMouse = { x: 0, y: 0 };
|
|
33
34
|
var selectedEls = [];
|
|
34
35
|
var selectedBadges = [];
|
|
36
|
+
var noteMap = new Map();
|
|
37
|
+
var noteInputEl = null;
|
|
38
|
+
var noteTargetEl = null;
|
|
35
39
|
|
|
36
40
|
// \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
|
|
37
41
|
var tooltip = document.createElement('div');
|
|
@@ -191,11 +195,11 @@ function getClientScript(options) {
|
|
|
191
195
|
pillExpanded = true;
|
|
192
196
|
if (text) { pillText.textContent = text; return; }
|
|
193
197
|
if (selectedEls.length > 0) {
|
|
194
|
-
pillText.textContent = selectedEls.length + ' selected \xB7 Cmd+C copy all \xB7 Esc clear';
|
|
198
|
+
pillText.textContent = selectedEls.length + ' selected \xB7 N annotate \xB7 Cmd+C copy all \xB7 Esc clear';
|
|
195
199
|
} else if (measureMode) {
|
|
196
200
|
pillText.textContent = 'Measure \xB7 hover distances \xB7 M pin \xB7 Cmd+C copy \xB7 Option toggle';
|
|
197
201
|
} else {
|
|
198
|
-
pillText.textContent = 'Properties \xB7 hover
|
|
202
|
+
pillText.textContent = 'Properties \xB7 hover \xB7 P pick \xB7 N annotate \xB7 Cmd+C copy \xB7 Option measure';
|
|
199
203
|
}
|
|
200
204
|
}
|
|
201
205
|
|
|
@@ -315,6 +319,55 @@ function getClientScript(options) {
|
|
|
315
319
|
return null;
|
|
316
320
|
}
|
|
317
321
|
|
|
322
|
+
// Collapse a rule's declarations to their shortest lossless form: drop
|
|
323
|
+
// 'initial' (= default, no signal) and always-'normal' noise, and fold
|
|
324
|
+
// side/corner longhands back into shorthands (margin/padding/radius/gap/transition).
|
|
325
|
+
function cleanDecls(style) {
|
|
326
|
+
var m = {}, order = [];
|
|
327
|
+
for (var i = 0; i < style.length; i++) {
|
|
328
|
+
var p = style[i];
|
|
329
|
+
var v = style.getPropertyValue(p);
|
|
330
|
+
if (!v) continue;
|
|
331
|
+
if (v === 'initial') continue;
|
|
332
|
+
if (p === 'transition-behavior') continue;
|
|
333
|
+
if (!(p in m)) order.push(p);
|
|
334
|
+
m[p] = v;
|
|
335
|
+
}
|
|
336
|
+
var used = {}, collapses = {};
|
|
337
|
+
function four(name, t, r, b, l) {
|
|
338
|
+
if (m[t] === undefined || m[r] === undefined || m[b] === undefined || m[l] === undefined) return;
|
|
339
|
+
used[t] = used[r] = used[b] = used[l] = 1;
|
|
340
|
+
var a = m[t], c = m[r], d = m[b], e = m[l], sh;
|
|
341
|
+
if (a === c && c === d && d === e) sh = a;
|
|
342
|
+
else if (a === d && c === e) sh = a + ' ' + c;
|
|
343
|
+
else if (c === e) sh = a + ' ' + c + ' ' + d;
|
|
344
|
+
else sh = a + ' ' + c + ' ' + d + ' ' + e;
|
|
345
|
+
collapses[t] = name + ': ' + sh;
|
|
346
|
+
}
|
|
347
|
+
four('margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left');
|
|
348
|
+
four('padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left');
|
|
349
|
+
four('border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius');
|
|
350
|
+
if (m['row-gap'] !== undefined && m['column-gap'] !== undefined) {
|
|
351
|
+
var g = m['row-gap'] === m['column-gap'] ? m['row-gap'] : m['row-gap'] + ' ' + m['column-gap'];
|
|
352
|
+
collapses['row-gap'] = 'gap: ' + g; used['row-gap'] = used['column-gap'] = 1;
|
|
353
|
+
}
|
|
354
|
+
if (m['transition-property'] !== undefined) {
|
|
355
|
+
var tr = 'transition: ' + m['transition-property'];
|
|
356
|
+
if (m['transition-duration'] !== undefined) tr += ' ' + m['transition-duration'];
|
|
357
|
+
if (m['transition-timing-function'] !== undefined) tr += ' ' + m['transition-timing-function'];
|
|
358
|
+
if (m['transition-delay'] !== undefined && m['transition-delay'] !== '0s') tr += ' ' + m['transition-delay'];
|
|
359
|
+
collapses['transition-property'] = tr;
|
|
360
|
+
used['transition-property'] = used['transition-duration'] = used['transition-timing-function'] = used['transition-delay'] = 1;
|
|
361
|
+
}
|
|
362
|
+
var out = [];
|
|
363
|
+
order.forEach(function (p) {
|
|
364
|
+
if (collapses[p]) { out.push(' ' + collapses[p] + ';'); return; }
|
|
365
|
+
if (used[p]) return;
|
|
366
|
+
out.push(' ' + p + ': ' + m[p] + ';');
|
|
367
|
+
});
|
|
368
|
+
return out;
|
|
369
|
+
}
|
|
370
|
+
|
|
318
371
|
function getMatchingRules(el) {
|
|
319
372
|
var results = [];
|
|
320
373
|
try {
|
|
@@ -331,12 +384,7 @@ function getClientScript(options) {
|
|
|
331
384
|
if (/^[*,]|^:root|^html|^body$|^::before|^::after/.test(sel.trim())) continue;
|
|
332
385
|
try {
|
|
333
386
|
if (el.matches(sel)) {
|
|
334
|
-
var props =
|
|
335
|
-
for (var i = 0; i < rule.style.length; i++) {
|
|
336
|
-
var prop = rule.style[i];
|
|
337
|
-
var val = rule.style.getPropertyValue(prop);
|
|
338
|
-
if (val) props.push(' ' + prop + ': ' + val + ';');
|
|
339
|
-
}
|
|
387
|
+
var props = cleanDecls(rule.style);
|
|
340
388
|
if (props.length) results.push(sel + ' {\\n' + props.join('\\n') + '\\n}');
|
|
341
389
|
}
|
|
342
390
|
} catch (e) {}
|
|
@@ -456,9 +504,13 @@ function getClientScript(options) {
|
|
|
456
504
|
}
|
|
457
505
|
|
|
458
506
|
function buildMultiSelectCopyText() {
|
|
507
|
+
var n = selectedEls.length;
|
|
459
508
|
return selectedEls.map(function (el, i) {
|
|
460
509
|
var body = buildLLMClipboard(buildInfo(el));
|
|
461
|
-
|
|
510
|
+
var note = noteMap.get(el);
|
|
511
|
+
var header = n > 1 ? '[Specter ' + (i + 1) + '/' + n + ']' : '[Specter]';
|
|
512
|
+
if (note) header += '\\n\u270F\uFE0F CHANGE: ' + note;
|
|
513
|
+
return body.replace('[Specter]', header);
|
|
462
514
|
}).join('\\n\\n' + Array(41).join('\u2500') + '\\n\\n');
|
|
463
515
|
}
|
|
464
516
|
|
|
@@ -509,16 +561,25 @@ function getClientScript(options) {
|
|
|
509
561
|
}
|
|
510
562
|
|
|
511
563
|
// \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
|
|
512
|
-
function makeBadge(el, index) {
|
|
564
|
+
function makeBadge(el, index, note) {
|
|
513
565
|
var rect = el.getBoundingClientRect();
|
|
514
|
-
var
|
|
515
|
-
|
|
516
|
-
Object.assign(badge.style, {
|
|
566
|
+
var wrap = document.createElement('div');
|
|
567
|
+
Object.assign(wrap.style, {
|
|
517
568
|
position: 'fixed',
|
|
518
569
|
left: (rect.left - 4) + 'px',
|
|
519
570
|
top: (rect.top - 4) + 'px',
|
|
571
|
+
zIndex: '2147483644',
|
|
572
|
+
pointerEvents: 'none',
|
|
573
|
+
display: 'flex',
|
|
574
|
+
alignItems: 'flex-start',
|
|
575
|
+
gap: '4px',
|
|
576
|
+
});
|
|
577
|
+
var badge = document.createElement('div');
|
|
578
|
+
badge.textContent = String(index + 1);
|
|
579
|
+
Object.assign(badge.style, {
|
|
520
580
|
width: '20px',
|
|
521
581
|
height: '20px',
|
|
582
|
+
flexShrink: '0',
|
|
522
583
|
background: PURPLE,
|
|
523
584
|
color: '#fff',
|
|
524
585
|
fontSize: '11px',
|
|
@@ -528,19 +589,38 @@ function getClientScript(options) {
|
|
|
528
589
|
display: 'flex',
|
|
529
590
|
alignItems: 'center',
|
|
530
591
|
justifyContent: 'center',
|
|
531
|
-
zIndex: '2147483644',
|
|
532
|
-
pointerEvents: 'none',
|
|
533
592
|
boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
|
|
534
593
|
});
|
|
535
|
-
|
|
536
|
-
|
|
594
|
+
wrap.appendChild(badge);
|
|
595
|
+
if (note) {
|
|
596
|
+
var chip = document.createElement('div');
|
|
597
|
+
chip.textContent = '\u270F\uFE0F ' + (note.length > 32 ? note.slice(0, 32) + '\u2026' : note);
|
|
598
|
+
Object.assign(chip.style, {
|
|
599
|
+
maxWidth: '240px',
|
|
600
|
+
background: TIP_BG,
|
|
601
|
+
color: '#fff',
|
|
602
|
+
fontSize: '10px',
|
|
603
|
+
lineHeight: '16px',
|
|
604
|
+
fontFamily: MONO,
|
|
605
|
+
padding: '2px 6px',
|
|
606
|
+
borderRadius: '4px',
|
|
607
|
+
whiteSpace: 'nowrap',
|
|
608
|
+
overflow: 'hidden',
|
|
609
|
+
textOverflow: 'ellipsis',
|
|
610
|
+
border: '1px solid ' + PURPLE,
|
|
611
|
+
boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
|
|
612
|
+
});
|
|
613
|
+
wrap.appendChild(chip);
|
|
614
|
+
}
|
|
615
|
+
document.body.appendChild(wrap);
|
|
616
|
+
return wrap;
|
|
537
617
|
}
|
|
538
618
|
|
|
539
619
|
function rebuildBadges() {
|
|
540
620
|
selectedBadges.forEach(function (b) { b.remove(); });
|
|
541
621
|
selectedBadges.length = 0;
|
|
542
622
|
selectedEls.forEach(function (el, i) {
|
|
543
|
-
selectedBadges.push(makeBadge(el, i));
|
|
623
|
+
selectedBadges.push(makeBadge(el, i, noteMap.get(el)));
|
|
544
624
|
});
|
|
545
625
|
}
|
|
546
626
|
|
|
@@ -549,6 +629,7 @@ function getClientScript(options) {
|
|
|
549
629
|
if (idx >= 0) {
|
|
550
630
|
selectedEls.splice(idx, 1);
|
|
551
631
|
el.style.outline = '';
|
|
632
|
+
noteMap.delete(el);
|
|
552
633
|
} else {
|
|
553
634
|
selectedEls.push(el);
|
|
554
635
|
el.style.outline = '2px solid ' + PURPLE;
|
|
@@ -559,10 +640,12 @@ function getClientScript(options) {
|
|
|
559
640
|
}
|
|
560
641
|
|
|
561
642
|
function clearSelection() {
|
|
643
|
+
closeNoteInput();
|
|
562
644
|
selectedEls.forEach(function (el) { el.style.outline = ''; el.style.outlineOffset = ''; });
|
|
563
645
|
selectedEls.length = 0;
|
|
564
646
|
selectedBadges.forEach(function (b) { b.remove(); });
|
|
565
647
|
selectedBadges.length = 0;
|
|
648
|
+
noteMap.clear();
|
|
566
649
|
}
|
|
567
650
|
|
|
568
651
|
function updatePillForSelection() {
|
|
@@ -570,6 +653,142 @@ function getClientScript(options) {
|
|
|
570
653
|
else if (!pillWrap.matches(':hover')) collapsePill();
|
|
571
654
|
}
|
|
572
655
|
|
|
656
|
+
// \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
|
|
657
|
+
function openNoteInput(el) {
|
|
658
|
+
closeNoteInput();
|
|
659
|
+
if (selectedEls.indexOf(el) < 0) {
|
|
660
|
+
clearHoverOutline();
|
|
661
|
+
hideTooltip();
|
|
662
|
+
selectedEls.push(el);
|
|
663
|
+
el.style.outline = '2px solid ' + PURPLE;
|
|
664
|
+
el.style.outlineOffset = '-1px';
|
|
665
|
+
}
|
|
666
|
+
noteTargetEl = el;
|
|
667
|
+
var rect = el.getBoundingClientRect();
|
|
668
|
+
|
|
669
|
+
var box = document.createElement('div');
|
|
670
|
+
Object.assign(box.style, {
|
|
671
|
+
position: 'fixed',
|
|
672
|
+
zIndex: '2147483647',
|
|
673
|
+
display: 'inline-flex',
|
|
674
|
+
alignItems: 'flex-start',
|
|
675
|
+
gap: '8px',
|
|
676
|
+
boxSizing: 'border-box',
|
|
677
|
+
background: TIP_BG,
|
|
678
|
+
border: '1px solid ' + PURPLE,
|
|
679
|
+
borderRadius: '8px',
|
|
680
|
+
padding: '11px 12px',
|
|
681
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.35)',
|
|
682
|
+
fontFamily: MONO,
|
|
683
|
+
});
|
|
684
|
+
var pen = document.createElement('span');
|
|
685
|
+
pen.innerHTML = PENCIL;
|
|
686
|
+
Object.assign(pen.style, {
|
|
687
|
+
display: 'flex',
|
|
688
|
+
alignItems: 'center',
|
|
689
|
+
flexShrink: '0',
|
|
690
|
+
marginTop: '2px',
|
|
691
|
+
color: '#E0A3F5',
|
|
692
|
+
});
|
|
693
|
+
var input = document.createElement('textarea');
|
|
694
|
+
input.rows = 1;
|
|
695
|
+
input.placeholder = 'Describe the change\u2026 (Enter to save)';
|
|
696
|
+
input.value = noteMap.get(el) || '';
|
|
697
|
+
Object.assign(input.style, {
|
|
698
|
+
flexShrink: '0',
|
|
699
|
+
background: 'transparent',
|
|
700
|
+
border: 'none',
|
|
701
|
+
outline: 'none',
|
|
702
|
+
resize: 'none',
|
|
703
|
+
overflow: 'hidden',
|
|
704
|
+
color: '#fff',
|
|
705
|
+
fontFamily: MONO,
|
|
706
|
+
fontSize: '12px',
|
|
707
|
+
lineHeight: '18px',
|
|
708
|
+
padding: '0',
|
|
709
|
+
margin: '0',
|
|
710
|
+
whiteSpace: 'pre-wrap',
|
|
711
|
+
overflowWrap: 'anywhere',
|
|
712
|
+
});
|
|
713
|
+
// Hidden mirror to measure single-line text width so the field grows as you type.
|
|
714
|
+
var meas = document.createElement('span');
|
|
715
|
+
Object.assign(meas.style, {
|
|
716
|
+
position: 'absolute',
|
|
717
|
+
visibility: 'hidden',
|
|
718
|
+
whiteSpace: 'pre',
|
|
719
|
+
pointerEvents: 'none',
|
|
720
|
+
fontFamily: MONO,
|
|
721
|
+
fontSize: '12px',
|
|
722
|
+
left: '-9999px',
|
|
723
|
+
top: '0',
|
|
724
|
+
});
|
|
725
|
+
box.appendChild(pen);
|
|
726
|
+
box.appendChild(input);
|
|
727
|
+
box.appendChild(meas);
|
|
728
|
+
document.body.appendChild(box);
|
|
729
|
+
noteInputEl = box;
|
|
730
|
+
|
|
731
|
+
var margin = 8;
|
|
732
|
+
function textW(t) { meas.textContent = t; return meas.offsetWidth; }
|
|
733
|
+
|
|
734
|
+
// Anchor to the element; the box is repositioned around this as it grows.
|
|
735
|
+
var anchorL = rect.left, anchorT = rect.top, anchorB = rect.bottom;
|
|
736
|
+
|
|
737
|
+
function sizeAndPosition() {
|
|
738
|
+
var vw = window.innerWidth, vh = window.innerHeight;
|
|
739
|
+
var maxBoxW = Math.min(560, vw - margin * 2);
|
|
740
|
+
var maxTextW = Math.max(120, maxBoxW - 55); // room for icon + gaps + padding
|
|
741
|
+
var placeholderW = textW(input.placeholder);
|
|
742
|
+
var minTextW = Math.min(placeholderW, maxTextW);
|
|
743
|
+
var maxTaH = Math.min(14 * 18, Math.max(18, (vh - margin * 2) - 24)); // cap ~14 lines, never past viewport
|
|
744
|
+
|
|
745
|
+
// Width: grow with content up to the max, then wrapping takes over.
|
|
746
|
+
var single = textW(input.value || input.placeholder) + 3;
|
|
747
|
+
input.style.width = Math.min(Math.max(single, minTextW), maxTextW) + 'px';
|
|
748
|
+
// Height: fit wrapped content, scroll only in the extreme case.
|
|
749
|
+
input.style.height = 'auto';
|
|
750
|
+
var h = input.scrollHeight;
|
|
751
|
+
if (h > maxTaH) { input.style.height = maxTaH + 'px'; input.style.overflowY = 'auto'; }
|
|
752
|
+
else { input.style.height = h + 'px'; input.style.overflowY = 'hidden'; }
|
|
753
|
+
|
|
754
|
+
// Keep the whole box on screen.
|
|
755
|
+
var bw = box.offsetWidth, bh = box.offsetHeight;
|
|
756
|
+
var left = Math.min(Math.max(anchorL, margin), Math.max(margin, vw - bw - margin));
|
|
757
|
+
var top = anchorT - bh - 8; // prefer sitting above the element
|
|
758
|
+
if (top < margin) top = anchorB + 8; // otherwise below it
|
|
759
|
+
if (top + bh > vh - margin) top = Math.max(margin, vh - bh - margin);
|
|
760
|
+
box.style.left = left + 'px';
|
|
761
|
+
box.style.top = top + 'px';
|
|
762
|
+
}
|
|
763
|
+
sizeAndPosition();
|
|
764
|
+
|
|
765
|
+
input.addEventListener('input', sizeAndPosition);
|
|
766
|
+
input.addEventListener('keydown', function (ev) {
|
|
767
|
+
ev.stopPropagation();
|
|
768
|
+
if (ev.key === 'Enter' && !ev.shiftKey) { ev.preventDefault(); commitNote(input.value); }
|
|
769
|
+
else if (ev.key === 'Escape') { ev.preventDefault(); closeNoteInput(); }
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
rebuildBadges();
|
|
773
|
+
updatePillForSelection();
|
|
774
|
+
setTimeout(function () { input.focus(); }, 0);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function commitNote(val) {
|
|
778
|
+
val = (val || '').trim();
|
|
779
|
+
if (noteTargetEl) {
|
|
780
|
+
if (val) noteMap.set(noteTargetEl, val);
|
|
781
|
+
else noteMap.delete(noteTargetEl);
|
|
782
|
+
}
|
|
783
|
+
closeNoteInput();
|
|
784
|
+
rebuildBadges();
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function closeNoteInput() {
|
|
788
|
+
if (noteInputEl) { noteInputEl.remove(); noteInputEl = null; }
|
|
789
|
+
noteTargetEl = null;
|
|
790
|
+
}
|
|
791
|
+
|
|
573
792
|
// \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
|
|
574
793
|
function setPin(el) {
|
|
575
794
|
pinEl = el;
|
|
@@ -866,6 +1085,7 @@ function getClientScript(options) {
|
|
|
866
1085
|
var target = e.target;
|
|
867
1086
|
if (!target || target === pillWrap || pillWrap.contains(target)) return;
|
|
868
1087
|
if (target === tooltip || tooltip.contains(target)) return;
|
|
1088
|
+
if (noteInputEl && (target === noteInputEl || noteInputEl.contains(target))) return;
|
|
869
1089
|
|
|
870
1090
|
lastHovered = target;
|
|
871
1091
|
|
|
@@ -900,6 +1120,9 @@ function getClientScript(options) {
|
|
|
900
1120
|
|
|
901
1121
|
if (!fiActive) return;
|
|
902
1122
|
|
|
1123
|
+
// Note editor open: let the field handle its own keys (Enter/Esc) and native copy/paste.
|
|
1124
|
+
if (noteInputEl) return;
|
|
1125
|
+
|
|
903
1126
|
if (e.key === 'Alt' && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
|
|
904
1127
|
optionHeld = true;
|
|
905
1128
|
return;
|
|
@@ -930,6 +1153,12 @@ function getClientScript(options) {
|
|
|
930
1153
|
return;
|
|
931
1154
|
}
|
|
932
1155
|
|
|
1156
|
+
if (e.key === 'n' || e.key === 'N') {
|
|
1157
|
+
if (!lastHovered) return;
|
|
1158
|
+
openNoteInput(lastHovered);
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
933
1162
|
if (e.key === 'm' || e.key === 'M') {
|
|
934
1163
|
if (!measureMode || !lastHovered) return;
|
|
935
1164
|
if (pinEl) {
|