@designfever/web-review-kit 0.3.0 → 0.4.1
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/LICENSE +201 -0
- package/README.md +18 -1
- package/dist/{chunk-I76WEDLA.js → chunk-6L2KJ7XL.js} +1115 -110
- package/dist/chunk-6L2KJ7XL.js.map +1 -0
- package/dist/index.cjs +1114 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/react-shell.cjs +3256 -855
- package/dist/react-shell.cjs.map +1 -1
- package/dist/react-shell.d.cts +11 -3
- package/dist/react-shell.d.ts +11 -3
- package/dist/react-shell.js +2089 -689
- package/dist/react-shell.js.map +1 -1
- package/dist/{types-Cf2x5ky6.d.cts → types-D_qYtwTs.d.cts} +4 -1
- package/dist/{types-Cf2x5ky6.d.ts → types-D_qYtwTs.d.ts} +4 -1
- package/docs/adaptor.sample.ts +2 -0
- package/docs/architecture.md +3 -0
- package/docs/installation.md +26 -1
- package/docs/release-notes-0.3.0.md +94 -0
- package/docs/release-notes-0.4.0.md +144 -0
- package/package.json +2 -2
- package/dist/chunk-I76WEDLA.js.map +0 -1
|
@@ -301,19 +301,6 @@ function getPopoverPosition(point, environment, options) {
|
|
|
301
301
|
)
|
|
302
302
|
};
|
|
303
303
|
}
|
|
304
|
-
function getAreaPopoverPosition(selection, environment) {
|
|
305
|
-
return getPopoverPosition(
|
|
306
|
-
{
|
|
307
|
-
x: selection.left + selection.width,
|
|
308
|
-
y: selection.top
|
|
309
|
-
},
|
|
310
|
-
environment,
|
|
311
|
-
{
|
|
312
|
-
width: 360,
|
|
313
|
-
estimatedHeight: 206
|
|
314
|
-
}
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
304
|
function getPopoverBounds(environment) {
|
|
318
305
|
if (!environment) {
|
|
319
306
|
return {
|
|
@@ -378,6 +365,21 @@ function roundPoint(point) {
|
|
|
378
365
|
}
|
|
379
366
|
|
|
380
367
|
// src/core/dom.anchor.ts
|
|
368
|
+
var COMMON_ANCHOR_ATTRIBUTES = [
|
|
369
|
+
"data-testid",
|
|
370
|
+
"data-test-id",
|
|
371
|
+
"data-cy",
|
|
372
|
+
"data-test",
|
|
373
|
+
"data-qa",
|
|
374
|
+
"data-section-id",
|
|
375
|
+
"data-component"
|
|
376
|
+
];
|
|
377
|
+
var SEMANTIC_ANCHOR_ATTRIBUTES = [
|
|
378
|
+
"aria-label",
|
|
379
|
+
"title",
|
|
380
|
+
"name",
|
|
381
|
+
"href"
|
|
382
|
+
];
|
|
381
383
|
function getDomAnchor(selection, configuredAttribute = "data-qa-id", environment) {
|
|
382
384
|
const x = selection.left + selection.width / 2;
|
|
383
385
|
const y = selection.top + selection.height / 2;
|
|
@@ -398,8 +400,8 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
|
|
|
398
400
|
source: getDomSourceHint(target)
|
|
399
401
|
};
|
|
400
402
|
}
|
|
401
|
-
function getElementViewportSelection(anchor, environment) {
|
|
402
|
-
const element = getAnchorElement(anchor, environment);
|
|
403
|
+
function getElementViewportSelection(anchor, environment, preferredSelection) {
|
|
404
|
+
const element = getAnchorElement(anchor, environment, preferredSelection);
|
|
403
405
|
if (!element) return void 0;
|
|
404
406
|
const rect = element.getBoundingClientRect();
|
|
405
407
|
if (rect.width <= 0 || rect.height <= 0) return void 0;
|
|
@@ -438,22 +440,35 @@ function getAnchorCandidates(anchor) {
|
|
|
438
440
|
...anchor.candidates ?? []
|
|
439
441
|
]);
|
|
440
442
|
}
|
|
441
|
-
function resolveAnchorElement(anchor, environment) {
|
|
443
|
+
function resolveAnchorElement(anchor, environment, preferredSelection) {
|
|
442
444
|
const matches = getAnchorCandidates(anchor).flatMap((candidate) => {
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
(
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
445
|
+
const textFingerprint = candidate.textFingerprint ?? anchor.textFingerprint;
|
|
446
|
+
if (!preferredSelection) {
|
|
447
|
+
const match = queryBestAnchorCandidate(
|
|
448
|
+
candidate,
|
|
449
|
+
textFingerprint,
|
|
450
|
+
environment
|
|
451
|
+
);
|
|
452
|
+
if (!match) return [];
|
|
453
|
+
const confidence = roundRatio(
|
|
454
|
+
(candidate.confidence ?? 0.5) * match.score
|
|
455
|
+
);
|
|
456
|
+
return [{
|
|
457
|
+
element: match.element,
|
|
458
|
+
candidate,
|
|
459
|
+
confidence
|
|
460
|
+
}];
|
|
461
|
+
}
|
|
462
|
+
return queryAnchorElements(candidate.selector, environment).map((element) => {
|
|
463
|
+
const confidence = roundRatio(
|
|
464
|
+
(candidate.confidence ?? 0.5) * getTextFingerprintScore(textFingerprint, getTextFingerprint(element)) * getSelectionMatchScore(element, preferredSelection)
|
|
465
|
+
);
|
|
466
|
+
return {
|
|
467
|
+
element,
|
|
468
|
+
candidate,
|
|
469
|
+
confidence
|
|
470
|
+
};
|
|
471
|
+
});
|
|
457
472
|
});
|
|
458
473
|
return matches.sort((a, b) => b.confidence - a.confidence)[0];
|
|
459
474
|
}
|
|
@@ -463,50 +478,70 @@ function cssEscape(value) {
|
|
|
463
478
|
}
|
|
464
479
|
return value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
465
480
|
}
|
|
466
|
-
function getAnchorElement(anchor, environment) {
|
|
467
|
-
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment)?.element;
|
|
481
|
+
function getAnchorElement(anchor, environment, preferredSelection) {
|
|
482
|
+
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment, preferredSelection)?.element;
|
|
468
483
|
}
|
|
469
484
|
function createAnchorCandidates(target, configuredAttribute) {
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
485
|
+
const targetCandidates = [];
|
|
486
|
+
const configuredAnchor = getExactAttributeAnchorCandidate(
|
|
487
|
+
target,
|
|
488
|
+
configuredAttribute,
|
|
489
|
+
0.98,
|
|
490
|
+
"configured-attribute"
|
|
491
|
+
);
|
|
492
|
+
if (configuredAnchor) targetCandidates.push(configuredAnchor);
|
|
493
|
+
const targetAttributeAnchor = getAttributeAnchorCandidate(
|
|
494
|
+
target,
|
|
495
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
496
|
+
0.9
|
|
497
|
+
);
|
|
498
|
+
if (targetAttributeAnchor) targetCandidates.push(targetAttributeAnchor);
|
|
483
499
|
if (isMeaningfulId(target.id)) {
|
|
484
|
-
|
|
500
|
+
targetCandidates.push({
|
|
485
501
|
selector: `#${cssEscape(target.id)}`,
|
|
486
502
|
strategy: "id",
|
|
487
503
|
confidence: 0.94,
|
|
488
504
|
textFingerprint: getTextFingerprint(target)
|
|
489
505
|
});
|
|
490
506
|
}
|
|
507
|
+
const semanticAnchor = getAttributeAnchorCandidate(
|
|
508
|
+
target,
|
|
509
|
+
SEMANTIC_ANCHOR_ATTRIBUTES,
|
|
510
|
+
0.84
|
|
511
|
+
);
|
|
512
|
+
if (semanticAnchor) targetCandidates.push(semanticAnchor);
|
|
491
513
|
const targetClassName = getMeaningfulClassName(target);
|
|
492
514
|
if (targetClassName) {
|
|
493
|
-
|
|
515
|
+
targetCandidates.push({
|
|
494
516
|
selector: `${target.tagName.toLowerCase()}.${cssEscape(targetClassName)}`,
|
|
495
517
|
strategy: "class",
|
|
496
518
|
confidence: 0.82,
|
|
497
519
|
textFingerprint: getTextFingerprint(target)
|
|
498
520
|
});
|
|
499
521
|
}
|
|
500
|
-
|
|
522
|
+
const scopedPath = getScopedDomPathCandidate(target, configuredAttribute);
|
|
523
|
+
if (scopedPath) targetCandidates.push(scopedPath);
|
|
524
|
+
const targetDomPath = {
|
|
501
525
|
selector: getDomPath(target),
|
|
502
526
|
strategy: "dom-path",
|
|
503
|
-
confidence: 0.
|
|
527
|
+
confidence: targetCandidates.length > 0 ? 0.8 : 0.5,
|
|
504
528
|
textFingerprint: getTextFingerprint(target)
|
|
505
|
-
}
|
|
529
|
+
};
|
|
530
|
+
const parentCandidates = [];
|
|
506
531
|
const parent = target.parentElement;
|
|
532
|
+
const parentConfiguredAnchor = parent ? findClosestAttributeAnchor(parent, [configuredAttribute], 0.72, {
|
|
533
|
+
strategy: "configured-attribute"
|
|
534
|
+
}) : void 0;
|
|
535
|
+
if (parentConfiguredAnchor) parentCandidates.push(parentConfiguredAnchor);
|
|
536
|
+
const anchoredByAttribute = parent ? findClosestAttributeAnchor(
|
|
537
|
+
parent,
|
|
538
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
539
|
+
0.7
|
|
540
|
+
) : void 0;
|
|
541
|
+
if (anchoredByAttribute) parentCandidates.push(anchoredByAttribute);
|
|
507
542
|
const anchoredById = parent ? findClosest(parent, (element) => isMeaningfulId(element.id)) : void 0;
|
|
508
543
|
if (anchoredById?.id) {
|
|
509
|
-
|
|
544
|
+
parentCandidates.push({
|
|
510
545
|
selector: `#${cssEscape(anchoredById.id)}`,
|
|
511
546
|
strategy: "id",
|
|
512
547
|
confidence: 0.72,
|
|
@@ -516,7 +551,7 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
516
551
|
const anchoredByClass = parent ? findClosest(parent, (element) => Boolean(getMeaningfulClassName(element))) : void 0;
|
|
517
552
|
const className = anchoredByClass ? getMeaningfulClassName(anchoredByClass) : void 0;
|
|
518
553
|
if (anchoredByClass && className) {
|
|
519
|
-
|
|
554
|
+
parentCandidates.push({
|
|
520
555
|
selector: `${anchoredByClass.tagName.toLowerCase()}.${cssEscape(
|
|
521
556
|
className
|
|
522
557
|
)}`,
|
|
@@ -525,8 +560,107 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
525
560
|
textFingerprint: getTextFingerprint(anchoredByClass)
|
|
526
561
|
});
|
|
527
562
|
}
|
|
563
|
+
const candidates = targetCandidates.length > 0 ? [...targetCandidates, targetDomPath, ...parentCandidates] : [...parentCandidates, targetDomPath];
|
|
528
564
|
return dedupeAnchorCandidates(candidates);
|
|
529
565
|
}
|
|
566
|
+
function findClosestAttributeAnchor(target, attributeNames, confidence, options) {
|
|
567
|
+
for (const attributeName of attributeNames) {
|
|
568
|
+
const selector = `[${attributeName}]`;
|
|
569
|
+
const element = safeClosest(target, selector);
|
|
570
|
+
if (!element) continue;
|
|
571
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
572
|
+
if (!value) continue;
|
|
573
|
+
return {
|
|
574
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
575
|
+
strategy: options?.strategy ?? "attribute",
|
|
576
|
+
confidence,
|
|
577
|
+
textFingerprint: getTextFingerprint(element)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
return void 0;
|
|
581
|
+
}
|
|
582
|
+
function getExactAttributeAnchorCandidate(element, attributeName, confidence, strategy) {
|
|
583
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
584
|
+
if (!value) return void 0;
|
|
585
|
+
return {
|
|
586
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
587
|
+
strategy,
|
|
588
|
+
confidence,
|
|
589
|
+
textFingerprint: getTextFingerprint(element)
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
function getAttributeAnchorCandidate(element, attributeNames, confidence) {
|
|
593
|
+
for (const attributeName of attributeNames) {
|
|
594
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
595
|
+
if (!value) continue;
|
|
596
|
+
return {
|
|
597
|
+
selector: `${element.tagName.toLowerCase()}[${attributeName}="${cssEscape(
|
|
598
|
+
value
|
|
599
|
+
)}"]`,
|
|
600
|
+
strategy: "attribute",
|
|
601
|
+
confidence,
|
|
602
|
+
textFingerprint: getTextFingerprint(element)
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
return void 0;
|
|
606
|
+
}
|
|
607
|
+
function getScopedDomPathCandidate(target, configuredAttribute) {
|
|
608
|
+
const parent = target.parentElement;
|
|
609
|
+
if (!parent) return void 0;
|
|
610
|
+
const anchor = findStableAncestorSelector(parent, configuredAttribute);
|
|
611
|
+
if (!anchor) return void 0;
|
|
612
|
+
const selector = getDomPathBetween(anchor.element, target, anchor.selector);
|
|
613
|
+
if (!selector) return void 0;
|
|
614
|
+
return {
|
|
615
|
+
selector,
|
|
616
|
+
strategy: "dom-path",
|
|
617
|
+
confidence: anchor.confidence,
|
|
618
|
+
textFingerprint: getTextFingerprint(target)
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
function findStableAncestorSelector(start, configuredAttribute) {
|
|
622
|
+
let element = start;
|
|
623
|
+
const root = start.ownerDocument.documentElement;
|
|
624
|
+
while (element && element !== root) {
|
|
625
|
+
const configuredValue = getStableAttributeValue(element, configuredAttribute);
|
|
626
|
+
if (configuredValue) {
|
|
627
|
+
return {
|
|
628
|
+
element,
|
|
629
|
+
selector: `[${configuredAttribute}="${cssEscape(configuredValue)}"]`,
|
|
630
|
+
confidence: 0.88
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
const attributeAnchor = getAttributeAnchorCandidate(
|
|
634
|
+
element,
|
|
635
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
636
|
+
0.84
|
|
637
|
+
);
|
|
638
|
+
if (attributeAnchor) {
|
|
639
|
+
return {
|
|
640
|
+
element,
|
|
641
|
+
selector: attributeAnchor.selector,
|
|
642
|
+
confidence: 0.84
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
if (isMeaningfulId(element.id)) {
|
|
646
|
+
return {
|
|
647
|
+
element,
|
|
648
|
+
selector: `#${cssEscape(element.id)}`,
|
|
649
|
+
confidence: 0.82
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
const className = getMeaningfulClassName(element);
|
|
653
|
+
if (className) {
|
|
654
|
+
return {
|
|
655
|
+
element,
|
|
656
|
+
selector: `${element.tagName.toLowerCase()}.${cssEscape(className)}`,
|
|
657
|
+
confidence: 0.76
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
element = element.parentElement;
|
|
661
|
+
}
|
|
662
|
+
return void 0;
|
|
663
|
+
}
|
|
530
664
|
function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
531
665
|
if (candidate.strategy === "configured-attribute") {
|
|
532
666
|
return target.closest(`[${configuredAttribute}]`);
|
|
@@ -538,6 +672,13 @@ function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
|
538
672
|
return target;
|
|
539
673
|
}
|
|
540
674
|
}
|
|
675
|
+
function safeClosest(element, selector) {
|
|
676
|
+
try {
|
|
677
|
+
return element.closest(selector);
|
|
678
|
+
} catch {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
541
682
|
function getElementHtmlSnippet(element, maxLength = 1e3) {
|
|
542
683
|
const html = decodeHtmlEntities(element.outerHTML.replace(/\s+/g, " ").trim());
|
|
543
684
|
if (html.length <= maxLength) return html;
|
|
@@ -659,10 +800,38 @@ function getDomPath(element) {
|
|
|
659
800
|
}
|
|
660
801
|
return `body > ${parts.join(" > ")}`;
|
|
661
802
|
}
|
|
803
|
+
function getDomPathBetween(ancestor, target, ancestorSelector) {
|
|
804
|
+
const parts = [];
|
|
805
|
+
let current = target;
|
|
806
|
+
while (current && current !== ancestor) {
|
|
807
|
+
parts.unshift(getDomPathPart(current));
|
|
808
|
+
current = current.parentElement;
|
|
809
|
+
}
|
|
810
|
+
if (current !== ancestor || parts.length === 0) return void 0;
|
|
811
|
+
return `${ancestorSelector} > ${parts.join(" > ")}`;
|
|
812
|
+
}
|
|
813
|
+
function getDomPathPart(element) {
|
|
814
|
+
const parent = element.parentElement;
|
|
815
|
+
const tag = element.tagName.toLowerCase();
|
|
816
|
+
if (!parent) return tag;
|
|
817
|
+
const currentTagName = element.tagName;
|
|
818
|
+
const siblings = Array.from(parent.children).filter(
|
|
819
|
+
(child) => child.tagName === currentTagName
|
|
820
|
+
);
|
|
821
|
+
const index = siblings.indexOf(element) + 1;
|
|
822
|
+
return `${tag}:nth-of-type(${index})`;
|
|
823
|
+
}
|
|
662
824
|
function getTextFingerprint(element) {
|
|
663
825
|
const text = element.textContent?.replace(/\s+/g, " ").trim();
|
|
664
826
|
return text ? text.slice(0, 120) : void 0;
|
|
665
827
|
}
|
|
828
|
+
function getStableAttributeValue(element, attributeName) {
|
|
829
|
+
const value = element.getAttribute(attributeName)?.trim();
|
|
830
|
+
if (!value || value.length > 160) return void 0;
|
|
831
|
+
if (/^(true|false)$/i.test(value)) return void 0;
|
|
832
|
+
if (/^\d+$/.test(value) && value.length < 3) return void 0;
|
|
833
|
+
return value;
|
|
834
|
+
}
|
|
666
835
|
function getTextFingerprintScore(expected, actual) {
|
|
667
836
|
if (!expected) return 1;
|
|
668
837
|
if (!actual) return 0.5;
|
|
@@ -674,6 +843,38 @@ function getTextFingerprintScore(expected, actual) {
|
|
|
674
843
|
const matches = expectedTokens.filter((token) => actualTokens.has(token));
|
|
675
844
|
return clamp(matches.length / expectedTokens.length, 0.25, 0.76);
|
|
676
845
|
}
|
|
846
|
+
function getSelectionMatchScore(element, selection) {
|
|
847
|
+
const rect = element.getBoundingClientRect();
|
|
848
|
+
if (rect.width <= 0 || rect.height <= 0) return 0.05;
|
|
849
|
+
const overlapLeft = Math.max(rect.left, selection.left);
|
|
850
|
+
const overlapTop = Math.max(rect.top, selection.top);
|
|
851
|
+
const overlapRight = Math.min(rect.right, selection.left + selection.width);
|
|
852
|
+
const overlapBottom = Math.min(rect.bottom, selection.top + selection.height);
|
|
853
|
+
const overlapWidth = Math.max(0, overlapRight - overlapLeft);
|
|
854
|
+
const overlapHeight = Math.max(0, overlapBottom - overlapTop);
|
|
855
|
+
const overlapArea = overlapWidth * overlapHeight;
|
|
856
|
+
if (overlapArea > 0) {
|
|
857
|
+
const selectionArea = Math.max(1, selection.width * selection.height);
|
|
858
|
+
const rectArea = Math.max(1, rect.width * rect.height);
|
|
859
|
+
return 1 + overlapArea / Math.min(selectionArea, rectArea);
|
|
860
|
+
}
|
|
861
|
+
const rectCenterX = rect.left + rect.width / 2;
|
|
862
|
+
const rectCenterY = rect.top + rect.height / 2;
|
|
863
|
+
const selectionCenterX = selection.left + selection.width / 2;
|
|
864
|
+
const selectionCenterY = selection.top + selection.height / 2;
|
|
865
|
+
const distance = Math.hypot(
|
|
866
|
+
rectCenterX - selectionCenterX,
|
|
867
|
+
rectCenterY - selectionCenterY
|
|
868
|
+
);
|
|
869
|
+
const basis = Math.max(
|
|
870
|
+
1,
|
|
871
|
+
rect.width,
|
|
872
|
+
rect.height,
|
|
873
|
+
selection.width,
|
|
874
|
+
selection.height
|
|
875
|
+
);
|
|
876
|
+
return clamp(1 / (1 + distance / basis), 0.05, 0.95);
|
|
877
|
+
}
|
|
677
878
|
function getFingerprintTokens(value) {
|
|
678
879
|
return value.toLowerCase().split(/[\s/|,.:;()[\]{}"'`~!?<>]+/).map((token) => token.trim()).filter((token) => token.length > 1);
|
|
679
880
|
}
|
|
@@ -1038,6 +1239,19 @@ function createStyleElement() {
|
|
|
1038
1239
|
display: block;
|
|
1039
1240
|
}
|
|
1040
1241
|
|
|
1242
|
+
.dfwr-shell.has-dismissible-draft {
|
|
1243
|
+
z-index: 900;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.dfwr-draft-cancel-layer {
|
|
1247
|
+
position: fixed;
|
|
1248
|
+
inset: 0;
|
|
1249
|
+
z-index: 2;
|
|
1250
|
+
pointer-events: auto;
|
|
1251
|
+
background: transparent;
|
|
1252
|
+
cursor: default;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1041
1255
|
.dfwr-panel {
|
|
1042
1256
|
position: fixed;
|
|
1043
1257
|
right: 16px;
|
|
@@ -1531,6 +1745,40 @@ function createStyleElement() {
|
|
|
1531
1745
|
box-shadow: var(--df-review-shadow-popover);
|
|
1532
1746
|
}
|
|
1533
1747
|
|
|
1748
|
+
.dfwr-note-popover.is-composer,
|
|
1749
|
+
.dfwr-area-draft.is-composer {
|
|
1750
|
+
max-height: min(360px, calc(100vh - 32px));
|
|
1751
|
+
overflow: auto;
|
|
1752
|
+
border-color: rgba(99, 215, 199, 0.56);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
.dfwr-note-popover.is-dragging,
|
|
1756
|
+
.dfwr-area-draft.is-dragging {
|
|
1757
|
+
user-select: none;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
.dfwr-draft-drag-handle {
|
|
1761
|
+
display: block;
|
|
1762
|
+
width: 42px;
|
|
1763
|
+
height: 6px;
|
|
1764
|
+
margin: 0 auto 10px;
|
|
1765
|
+
padding: 0;
|
|
1766
|
+
cursor: grab;
|
|
1767
|
+
pointer-events: auto;
|
|
1768
|
+
background: rgba(247, 247, 242, 0.28);
|
|
1769
|
+
border: 0;
|
|
1770
|
+
border-radius: 999px;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
.dfwr-draft-drag-handle:hover,
|
|
1774
|
+
.dfwr-draft-drag-handle:focus-visible {
|
|
1775
|
+
background: rgba(215, 255, 95, 0.62);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.dfwr-draft-drag-handle:active {
|
|
1779
|
+
cursor: grabbing;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1534
1782
|
.dfwr-area-draft {
|
|
1535
1783
|
position: fixed;
|
|
1536
1784
|
right: 16px;
|
|
@@ -1552,6 +1800,14 @@ function createStyleElement() {
|
|
|
1552
1800
|
padding: 0;
|
|
1553
1801
|
}
|
|
1554
1802
|
|
|
1803
|
+
.dfwr-note-actions {
|
|
1804
|
+
justify-content: flex-end;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
.dfwr-note-actions .dfwr-button:first-child {
|
|
1808
|
+
margin-right: auto;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1555
1811
|
.dfwr-area-draft .dfwr-actions {
|
|
1556
1812
|
padding: 0;
|
|
1557
1813
|
}
|
|
@@ -1580,6 +1836,79 @@ function createStyleElement() {
|
|
|
1580
1836
|
outline-offset: 1px;
|
|
1581
1837
|
}
|
|
1582
1838
|
|
|
1839
|
+
.dfwr-adjust-panel {
|
|
1840
|
+
display: grid;
|
|
1841
|
+
gap: 4px;
|
|
1842
|
+
padding: 8px 10px;
|
|
1843
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
1844
|
+
border-radius: var(--df-review-radius-sm);
|
|
1845
|
+
background: rgba(255, 255, 255, 0.04);
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
.dfwr-adjust-panel-header {
|
|
1849
|
+
display: flex;
|
|
1850
|
+
align-items: center;
|
|
1851
|
+
justify-content: space-between;
|
|
1852
|
+
gap: 10px;
|
|
1853
|
+
min-width: 0;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
.dfwr-adjust-panel-header .dfwr-adjust-help {
|
|
1857
|
+
flex: 1 1 auto;
|
|
1858
|
+
min-width: 0;
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
.dfwr-adjust-panel.is-active {
|
|
1862
|
+
border-color: rgba(215, 255, 95, 0.5);
|
|
1863
|
+
background: var(--df-review-color-accent-soft);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
.dfwr-adjust-help,
|
|
1867
|
+
.dfwr-adjust-status {
|
|
1868
|
+
margin: 0;
|
|
1869
|
+
color: var(--df-review-color-text-muted);
|
|
1870
|
+
font-size: var(--df-review-font-size-xs);
|
|
1871
|
+
line-height: 1.35;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
.dfwr-adjust-status {
|
|
1875
|
+
color: var(--df-review-color-text);
|
|
1876
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
.dfwr-adjust-toggle {
|
|
1880
|
+
flex: 0 0 auto;
|
|
1881
|
+
display: inline-flex;
|
|
1882
|
+
align-items: center;
|
|
1883
|
+
justify-content: center;
|
|
1884
|
+
width: 34px;
|
|
1885
|
+
height: 30px;
|
|
1886
|
+
padding: 0;
|
|
1887
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1888
|
+
border-radius: var(--df-review-radius-sm);
|
|
1889
|
+
background: rgba(255, 255, 255, 0.04);
|
|
1890
|
+
color: var(--df-review-color-text);
|
|
1891
|
+
cursor: pointer;
|
|
1892
|
+
font: inherit;
|
|
1893
|
+
font-size: 14px;
|
|
1894
|
+
font-weight: 800;
|
|
1895
|
+
line-height: 1;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
.dfwr-adjust-toggle:hover,
|
|
1899
|
+
.dfwr-adjust-toggle:focus-visible,
|
|
1900
|
+
.dfwr-adjust-toggle.is-active {
|
|
1901
|
+
border-color: rgba(215, 255, 95, 0.68);
|
|
1902
|
+
background: var(--df-review-color-accent-soft);
|
|
1903
|
+
outline: none;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
.dfwr-adjust-toggle svg {
|
|
1907
|
+
width: 18px;
|
|
1908
|
+
height: 18px;
|
|
1909
|
+
pointer-events: none;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1583
1912
|
.dfwr-empty,
|
|
1584
1913
|
.dfwr-error {
|
|
1585
1914
|
margin: 0;
|
|
@@ -1800,16 +2129,6 @@ function createStyleElement() {
|
|
|
1800
2129
|
}
|
|
1801
2130
|
|
|
1802
2131
|
// src/core/review/format.ts
|
|
1803
|
-
function formatAreaDraftMeta(draft) {
|
|
1804
|
-
const parts = [`viewport ${formatSize(draft.viewport)}`];
|
|
1805
|
-
if (draft.selection) {
|
|
1806
|
-
parts.push(`rect ${formatSelection(draft.selection.viewport)}`);
|
|
1807
|
-
}
|
|
1808
|
-
if (draft.marker) {
|
|
1809
|
-
parts.push(`point ${formatPoint(draft.marker.viewport)}`);
|
|
1810
|
-
}
|
|
1811
|
-
return parts.join(" / ");
|
|
1812
|
-
}
|
|
1813
2132
|
function formatNoteDraftMeta(draft) {
|
|
1814
2133
|
const parts = [
|
|
1815
2134
|
`viewport ${formatSize(draft.viewport)}`,
|
|
@@ -1875,17 +2194,29 @@ function formatAnchorMeta(anchor) {
|
|
|
1875
2194
|
}
|
|
1876
2195
|
|
|
1877
2196
|
// src/core/web.review.kit.view.ts
|
|
2197
|
+
var DEFAULT_ADJUSTMENT_LABEL = "Responsive CSS px adjustments";
|
|
1878
2198
|
var WebReviewKitView = class {
|
|
1879
2199
|
constructor(config) {
|
|
1880
2200
|
this.config = config;
|
|
1881
2201
|
}
|
|
2202
|
+
clearDraftPreview() {
|
|
2203
|
+
this.restoreDraftPreview();
|
|
2204
|
+
}
|
|
1882
2205
|
render(shadow, hiddenItemsStyle) {
|
|
1883
2206
|
const state = this.state;
|
|
2207
|
+
this.syncDraftPreview(
|
|
2208
|
+
state.isOpen && state.mode === "element" ? state.noteDraft : void 0
|
|
2209
|
+
);
|
|
1884
2210
|
shadow.replaceChildren();
|
|
1885
2211
|
shadow.append(createStyleElement());
|
|
1886
2212
|
shadow.append(hiddenItemsStyle);
|
|
2213
|
+
const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
|
|
1887
2214
|
const shell = document.createElement("div");
|
|
1888
|
-
shell.className =
|
|
2215
|
+
shell.className = [
|
|
2216
|
+
"dfwr-shell",
|
|
2217
|
+
state.isOpen ? "is-open" : "",
|
|
2218
|
+
hasDismissableDraft ? "has-dismissible-draft" : ""
|
|
2219
|
+
].filter(Boolean).join(" ");
|
|
1889
2220
|
shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
|
|
1890
2221
|
if (this.config.options.ui?.panel !== false) {
|
|
1891
2222
|
const panel = document.createElement("div");
|
|
@@ -1901,6 +2232,9 @@ var WebReviewKitView = class {
|
|
|
1901
2232
|
shell.append(panel);
|
|
1902
2233
|
}
|
|
1903
2234
|
shell.append(this.createMarkerLayer());
|
|
2235
|
+
if (state.isOpen && hasDismissableDraft) {
|
|
2236
|
+
shell.append(this.createDraftCancelLayer());
|
|
2237
|
+
}
|
|
1904
2238
|
if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
|
|
1905
2239
|
shell.append(
|
|
1906
2240
|
state.noteDraft ? this.createNotePopover(state.noteDraft) : state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
|
|
@@ -1920,6 +2254,332 @@ var WebReviewKitView = class {
|
|
|
1920
2254
|
get state() {
|
|
1921
2255
|
return this.config.getState();
|
|
1922
2256
|
}
|
|
2257
|
+
createDraftCancelLayer() {
|
|
2258
|
+
const layer = document.createElement("div");
|
|
2259
|
+
layer.className = "dfwr-draft-cancel-layer";
|
|
2260
|
+
layer.setAttribute("aria-hidden", "true");
|
|
2261
|
+
const cancel = (event) => {
|
|
2262
|
+
event.preventDefault();
|
|
2263
|
+
event.stopPropagation();
|
|
2264
|
+
event.stopImmediatePropagation();
|
|
2265
|
+
this.config.actions.setModeState("idle");
|
|
2266
|
+
this.config.actions.clearDrafts();
|
|
2267
|
+
this.config.actions.setSelectingArea(false);
|
|
2268
|
+
this.config.actions.render();
|
|
2269
|
+
};
|
|
2270
|
+
layer.addEventListener("pointerdown", (event) => {
|
|
2271
|
+
if (event.button !== 0) return;
|
|
2272
|
+
cancel(event);
|
|
2273
|
+
});
|
|
2274
|
+
return layer;
|
|
2275
|
+
}
|
|
2276
|
+
getDraftAdjustmentMetrics(draft) {
|
|
2277
|
+
const adjustment = draft.adjustment;
|
|
2278
|
+
const x = adjustment?.x ?? 0;
|
|
2279
|
+
const y = adjustment?.y ?? 0;
|
|
2280
|
+
const scale = adjustment?.scale ?? 0;
|
|
2281
|
+
const {
|
|
2282
|
+
scale: viewportScale,
|
|
2283
|
+
designWidth,
|
|
2284
|
+
presetLabel
|
|
2285
|
+
} = this.getDraftViewportScale(draft.viewport);
|
|
2286
|
+
const selection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2287
|
+
const scaleCssDelta = scale * viewportScale;
|
|
2288
|
+
const scaleFactor = selection && selection.width > 0 ? Math.max(
|
|
2289
|
+
1 / selection.width,
|
|
2290
|
+
(selection.width + scaleCssDelta) / selection.width
|
|
2291
|
+
) : 1;
|
|
2292
|
+
return {
|
|
2293
|
+
x,
|
|
2294
|
+
y,
|
|
2295
|
+
scale,
|
|
2296
|
+
cssX: x * viewportScale,
|
|
2297
|
+
cssY: y * viewportScale,
|
|
2298
|
+
scaleFactor,
|
|
2299
|
+
viewportScale,
|
|
2300
|
+
designWidth,
|
|
2301
|
+
presetLabel,
|
|
2302
|
+
viewportWidth: draft.viewport.width
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
hasDraftAdjustment(draft) {
|
|
2306
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2307
|
+
return metrics.x !== 0 || metrics.y !== 0 || metrics.scale !== 0;
|
|
2308
|
+
}
|
|
2309
|
+
getAdjustedDraftPoint(point, draft) {
|
|
2310
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2311
|
+
return {
|
|
2312
|
+
x: point.x + metrics.cssX,
|
|
2313
|
+
y: point.y + metrics.cssY
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
getAdjustedDraftSelection(selection, draft) {
|
|
2317
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2318
|
+
return {
|
|
2319
|
+
...selection,
|
|
2320
|
+
left: selection.left + metrics.cssX,
|
|
2321
|
+
top: selection.top + metrics.cssY,
|
|
2322
|
+
width: selection.width * metrics.scaleFactor,
|
|
2323
|
+
height: selection.height * metrics.scaleFactor
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2326
|
+
getDraftViewportScale(viewport) {
|
|
2327
|
+
const preset = findReviewViewportPreset(
|
|
2328
|
+
viewport,
|
|
2329
|
+
this.config.options.viewports?.presets
|
|
2330
|
+
);
|
|
2331
|
+
const designWidth = typeof preset.designWidth === "number" && preset.designWidth > 0 ? preset.designWidth : viewport.width;
|
|
2332
|
+
const scale = designWidth > 0 ? viewport.width / designWidth : 1;
|
|
2333
|
+
return { scale, designWidth, presetLabel: preset.label };
|
|
2334
|
+
}
|
|
2335
|
+
getDraftComposerWidth(environment) {
|
|
2336
|
+
const bounds = environment.overlayRect;
|
|
2337
|
+
const margin = 12;
|
|
2338
|
+
return Math.min(360, Math.max(240, bounds.width - margin * 2));
|
|
2339
|
+
}
|
|
2340
|
+
getClampedComposerPosition(position, environment, size, bounds = environment.overlayRect) {
|
|
2341
|
+
const margin = 12;
|
|
2342
|
+
const width = size?.width ?? this.getDraftComposerWidth(environment);
|
|
2343
|
+
const height = size?.height ?? 236;
|
|
2344
|
+
return {
|
|
2345
|
+
x: clamp(
|
|
2346
|
+
position.x,
|
|
2347
|
+
bounds.left + margin,
|
|
2348
|
+
bounds.left + bounds.width - width - margin
|
|
2349
|
+
),
|
|
2350
|
+
y: clamp(
|
|
2351
|
+
position.y,
|
|
2352
|
+
bounds.top + margin,
|
|
2353
|
+
bounds.top + bounds.height - height - margin
|
|
2354
|
+
)
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
getHostComposerBounds() {
|
|
2358
|
+
const root = document.documentElement;
|
|
2359
|
+
return {
|
|
2360
|
+
left: 0,
|
|
2361
|
+
top: 0,
|
|
2362
|
+
width: root.clientWidth || window.innerWidth,
|
|
2363
|
+
height: root.clientHeight || window.innerHeight
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
getInitialDraftComposerPosition(selection, environment, size) {
|
|
2367
|
+
const bounds = this.getHostComposerBounds();
|
|
2368
|
+
const margin = 12;
|
|
2369
|
+
const gap = 20;
|
|
2370
|
+
if (!selection) {
|
|
2371
|
+
return this.getClampedComposerPosition(
|
|
2372
|
+
{
|
|
2373
|
+
x: environment.overlayRect.left + margin,
|
|
2374
|
+
y: environment.overlayRect.top + margin
|
|
2375
|
+
},
|
|
2376
|
+
environment,
|
|
2377
|
+
size,
|
|
2378
|
+
bounds
|
|
2379
|
+
);
|
|
2380
|
+
}
|
|
2381
|
+
const preferredX = selection.left + selection.width + gap;
|
|
2382
|
+
const maxX = bounds.left + bounds.width - size.width - margin;
|
|
2383
|
+
const x = preferredX <= maxX ? preferredX : selection.left - size.width - gap;
|
|
2384
|
+
return this.getClampedComposerPosition(
|
|
2385
|
+
{
|
|
2386
|
+
x,
|
|
2387
|
+
y: selection.top
|
|
2388
|
+
},
|
|
2389
|
+
environment,
|
|
2390
|
+
size,
|
|
2391
|
+
bounds
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
getDraftComposerPosition({
|
|
2395
|
+
selection,
|
|
2396
|
+
environment,
|
|
2397
|
+
composerPosition,
|
|
2398
|
+
estimatedHeight
|
|
2399
|
+
}) {
|
|
2400
|
+
const width = this.getDraftComposerWidth(environment);
|
|
2401
|
+
if (composerPosition) {
|
|
2402
|
+
const clamped = this.getClampedComposerPosition(
|
|
2403
|
+
composerPosition,
|
|
2404
|
+
environment,
|
|
2405
|
+
{ width, height: estimatedHeight },
|
|
2406
|
+
this.getHostComposerBounds()
|
|
2407
|
+
);
|
|
2408
|
+
return { width, left: clamped.x, top: clamped.y };
|
|
2409
|
+
}
|
|
2410
|
+
const position = this.getInitialDraftComposerPosition(selection, environment, {
|
|
2411
|
+
width,
|
|
2412
|
+
height: estimatedHeight
|
|
2413
|
+
});
|
|
2414
|
+
return { width, left: position.x, top: position.y };
|
|
2415
|
+
}
|
|
2416
|
+
getSelectionMqMetrics(selection, viewport) {
|
|
2417
|
+
const { scale } = this.getDraftViewportScale(viewport);
|
|
2418
|
+
const ratio = scale > 0 ? 1 / scale : 1;
|
|
2419
|
+
return {
|
|
2420
|
+
x: selection.left * ratio,
|
|
2421
|
+
y: selection.top * ratio,
|
|
2422
|
+
width: selection.width * ratio,
|
|
2423
|
+
height: selection.height * ratio
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
formatSignedPx(value) {
|
|
2427
|
+
if (value === 0) return "+0px";
|
|
2428
|
+
return `${value > 0 ? "+" : ""}${value}px`;
|
|
2429
|
+
}
|
|
2430
|
+
formatRoundedPx(value) {
|
|
2431
|
+
return `${Math.round(value)}px`;
|
|
2432
|
+
}
|
|
2433
|
+
getAdjustmentLabel() {
|
|
2434
|
+
return this.config.options.adjustmentLabel?.trim() || DEFAULT_ADJUSTMENT_LABEL;
|
|
2435
|
+
}
|
|
2436
|
+
getSelectionMetricLines(selection, viewport) {
|
|
2437
|
+
if (!selection) return ["area", "x none / y none", "w none / h none"];
|
|
2438
|
+
const metrics = this.getSelectionMqMetrics(selection, viewport);
|
|
2439
|
+
return [
|
|
2440
|
+
"area",
|
|
2441
|
+
`x ${this.formatRoundedPx(metrics.x)} / y ${this.formatRoundedPx(
|
|
2442
|
+
metrics.y
|
|
2443
|
+
)}`,
|
|
2444
|
+
`w ${this.formatRoundedPx(metrics.width)} / h ${this.formatRoundedPx(
|
|
2445
|
+
metrics.height
|
|
2446
|
+
)}`
|
|
2447
|
+
];
|
|
2448
|
+
}
|
|
2449
|
+
getAreaDraftMetricSelection(draft) {
|
|
2450
|
+
if (!draft.selection) return void 0;
|
|
2451
|
+
return toViewportSelection(draft.selection.viewport);
|
|
2452
|
+
}
|
|
2453
|
+
getDraftAdjustmentMetricLines(draft) {
|
|
2454
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2455
|
+
return [
|
|
2456
|
+
`x ${this.formatSignedPx(metrics.x)} / y ${this.formatSignedPx(
|
|
2457
|
+
metrics.y
|
|
2458
|
+
)}`,
|
|
2459
|
+
`scale ${this.formatSignedPx(metrics.scale)}`
|
|
2460
|
+
];
|
|
2461
|
+
}
|
|
2462
|
+
withDraftAdjustmentComment(comment, draft) {
|
|
2463
|
+
if (!this.hasDraftAdjustment(draft)) return comment;
|
|
2464
|
+
const trimmedComment = comment.trim();
|
|
2465
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2466
|
+
const adjustment = [
|
|
2467
|
+
`${this.getAdjustmentLabel()}: x ${this.formatSignedPx(
|
|
2468
|
+
metrics.x
|
|
2469
|
+
)}, y ${this.formatSignedPx(metrics.y)}, scale ${this.formatSignedPx(
|
|
2470
|
+
metrics.scale
|
|
2471
|
+
)}`,
|
|
2472
|
+
`(${metrics.presetLabel} viewport, ${Math.round(
|
|
2473
|
+
metrics.viewportWidth
|
|
2474
|
+
)}/design ${Math.round(metrics.designWidth)})`
|
|
2475
|
+
].join(" ");
|
|
2476
|
+
return trimmedComment ? `${trimmedComment}
|
|
2477
|
+
${adjustment}` : adjustment;
|
|
2478
|
+
}
|
|
2479
|
+
getStyleableDraftElement(draft, environment) {
|
|
2480
|
+
if (draft.previewElement && draft.previewElement.ownerDocument === environment.document && "style" in draft.previewElement) {
|
|
2481
|
+
return draft.previewElement;
|
|
2482
|
+
}
|
|
2483
|
+
if (!draft.anchor) return void 0;
|
|
2484
|
+
const preferredSelection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2485
|
+
const element = resolveAnchorElement(
|
|
2486
|
+
draft.anchor,
|
|
2487
|
+
environment,
|
|
2488
|
+
preferredSelection
|
|
2489
|
+
)?.element;
|
|
2490
|
+
if (!element) return void 0;
|
|
2491
|
+
if ("style" in element) return element;
|
|
2492
|
+
return void 0;
|
|
2493
|
+
}
|
|
2494
|
+
syncDraftPreview(draft) {
|
|
2495
|
+
const environment = this.config.getEnvironment();
|
|
2496
|
+
if (!draft || !environment || !this.hasDraftAdjustment(draft)) {
|
|
2497
|
+
this.restoreDraftPreview();
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
const element = this.getStyleableDraftElement(draft, environment);
|
|
2501
|
+
if (!element) {
|
|
2502
|
+
this.restoreDraftPreview();
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
if (this.draftPreview?.element !== element) {
|
|
2506
|
+
this.restoreDraftPreview();
|
|
2507
|
+
}
|
|
2508
|
+
if (!this.draftPreview) {
|
|
2509
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2510
|
+
const clone = element.cloneNode(true);
|
|
2511
|
+
this.removeDuplicateIds(clone);
|
|
2512
|
+
this.copyComputedStyle(element, clone, environment);
|
|
2513
|
+
this.positionDraftPreviewClone(clone, element, computedStyle);
|
|
2514
|
+
environment.document.body?.appendChild(clone);
|
|
2515
|
+
this.draftPreview = {
|
|
2516
|
+
element,
|
|
2517
|
+
clone,
|
|
2518
|
+
visibility: element.style.visibility
|
|
2519
|
+
};
|
|
2520
|
+
element.style.visibility = "hidden";
|
|
2521
|
+
}
|
|
2522
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2523
|
+
const translate = `translate(${this.toCssNumber(metrics.cssX)}px, ${this.toCssNumber(
|
|
2524
|
+
metrics.cssY
|
|
2525
|
+
)}px)`;
|
|
2526
|
+
const scale = metrics.scaleFactor === 1 ? "" : `scale(${this.toCssNumber(metrics.scaleFactor)})`;
|
|
2527
|
+
this.draftPreview.clone.style.transform = [translate, scale].filter(Boolean).join(" ");
|
|
2528
|
+
}
|
|
2529
|
+
restoreDraftPreview() {
|
|
2530
|
+
if (!this.draftPreview) return;
|
|
2531
|
+
const { element, clone, visibility } = this.draftPreview;
|
|
2532
|
+
clone.remove();
|
|
2533
|
+
element.style.visibility = visibility;
|
|
2534
|
+
this.draftPreview = void 0;
|
|
2535
|
+
}
|
|
2536
|
+
positionDraftPreviewClone(clone, element, computedStyle) {
|
|
2537
|
+
const rect = element.getBoundingClientRect();
|
|
2538
|
+
clone.setAttribute("data-dfwr-adjust-preview", "true");
|
|
2539
|
+
clone.setAttribute("aria-hidden", "true");
|
|
2540
|
+
clone.style.position = "fixed";
|
|
2541
|
+
clone.style.left = `${this.toCssNumber(rect.left)}px`;
|
|
2542
|
+
clone.style.top = `${this.toCssNumber(rect.top)}px`;
|
|
2543
|
+
clone.style.right = "auto";
|
|
2544
|
+
clone.style.bottom = "auto";
|
|
2545
|
+
clone.style.width = `${this.toCssNumber(rect.width)}px`;
|
|
2546
|
+
clone.style.height = `${this.toCssNumber(rect.height)}px`;
|
|
2547
|
+
clone.style.maxWidth = "none";
|
|
2548
|
+
clone.style.maxHeight = "none";
|
|
2549
|
+
clone.style.margin = "0";
|
|
2550
|
+
clone.style.boxSizing = "border-box";
|
|
2551
|
+
clone.style.display = this.getDraftPreviewDisplay(computedStyle.display);
|
|
2552
|
+
clone.style.zIndex = "2147483646";
|
|
2553
|
+
clone.style.pointerEvents = "none";
|
|
2554
|
+
clone.style.transition = "none";
|
|
2555
|
+
clone.style.willChange = "transform";
|
|
2556
|
+
clone.style.transformOrigin = "top left";
|
|
2557
|
+
clone.style.transform = "none";
|
|
2558
|
+
}
|
|
2559
|
+
getDraftPreviewDisplay(display) {
|
|
2560
|
+
if (display === "inline" || display === "contents") return "inline-block";
|
|
2561
|
+
return display || "block";
|
|
2562
|
+
}
|
|
2563
|
+
copyComputedStyle(element, clone, environment) {
|
|
2564
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2565
|
+
for (let index = 0; index < computedStyle.length; index += 1) {
|
|
2566
|
+
const property = computedStyle.item(index);
|
|
2567
|
+
clone.style.setProperty(
|
|
2568
|
+
property,
|
|
2569
|
+
computedStyle.getPropertyValue(property),
|
|
2570
|
+
computedStyle.getPropertyPriority(property)
|
|
2571
|
+
);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
removeDuplicateIds(element) {
|
|
2575
|
+
element.removeAttribute("id");
|
|
2576
|
+
element.querySelectorAll("[id]").forEach((child) => {
|
|
2577
|
+
child.removeAttribute("id");
|
|
2578
|
+
});
|
|
2579
|
+
}
|
|
2580
|
+
toCssNumber(value) {
|
|
2581
|
+
return Math.round(value * 1e3) / 1e3;
|
|
2582
|
+
}
|
|
1923
2583
|
createHeader() {
|
|
1924
2584
|
const header = document.createElement("div");
|
|
1925
2585
|
header.className = "dfwr-header";
|
|
@@ -2011,15 +2671,20 @@ var WebReviewKitView = class {
|
|
|
2011
2671
|
const group = document.createElement("div");
|
|
2012
2672
|
group.className = "dfwr-note-draft";
|
|
2013
2673
|
if (!environment) return group;
|
|
2014
|
-
const
|
|
2674
|
+
const isElementDraft = this.state.mode === "element" && Boolean(draft.selection);
|
|
2675
|
+
const hostPoint = toHostPoint(
|
|
2676
|
+
isElementDraft ? this.getAdjustedDraftPoint(draft.marker.viewport, draft) : draft.marker.viewport,
|
|
2677
|
+
environment
|
|
2678
|
+
);
|
|
2679
|
+
let selectionHighlight;
|
|
2015
2680
|
if (draft.selection) {
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
)
|
|
2681
|
+
const selection = toViewportSelection(draft.selection.viewport);
|
|
2682
|
+
selectionHighlight = this.createSelectionHighlight(
|
|
2683
|
+
isElementDraft ? this.getAdjustedDraftSelection(selection, draft) : selection,
|
|
2684
|
+
environment,
|
|
2685
|
+
true
|
|
2022
2686
|
);
|
|
2687
|
+
group.append(selectionHighlight);
|
|
2023
2688
|
}
|
|
2024
2689
|
const pin = document.createElement("button");
|
|
2025
2690
|
pin.className = "dfwr-note-pin";
|
|
@@ -2029,14 +2694,35 @@ var WebReviewKitView = class {
|
|
|
2029
2694
|
pin.style.top = `${hostPoint.y}px`;
|
|
2030
2695
|
const popover = document.createElement("div");
|
|
2031
2696
|
const position = getPopoverPosition(hostPoint, environment);
|
|
2032
|
-
popover.className =
|
|
2033
|
-
|
|
2034
|
-
|
|
2697
|
+
popover.className = `dfwr-note-popover${isElementDraft ? " is-composer" : ""}`;
|
|
2698
|
+
if (isElementDraft) {
|
|
2699
|
+
const selection = draft.selection ? toHostSelection(
|
|
2700
|
+
this.getAdjustedDraftSelection(
|
|
2701
|
+
toViewportSelection(draft.selection.viewport),
|
|
2702
|
+
draft
|
|
2703
|
+
),
|
|
2704
|
+
environment
|
|
2705
|
+
) : void 0;
|
|
2706
|
+
const composer = this.getDraftComposerPosition({
|
|
2707
|
+
selection,
|
|
2708
|
+
environment,
|
|
2709
|
+
composerPosition: draft.composerPosition,
|
|
2710
|
+
estimatedHeight: 252
|
|
2711
|
+
});
|
|
2712
|
+
popover.style.left = `${composer.left}px`;
|
|
2713
|
+
popover.style.top = `${composer.top}px`;
|
|
2714
|
+
popover.style.width = `${composer.width}px`;
|
|
2715
|
+
} else {
|
|
2716
|
+
popover.style.left = `${position.left}px`;
|
|
2717
|
+
popover.style.top = `${position.top}px`;
|
|
2718
|
+
}
|
|
2035
2719
|
const form = document.createElement("form");
|
|
2036
2720
|
form.className = "dfwr-form";
|
|
2037
|
-
const meta = document.createElement("div");
|
|
2038
|
-
meta
|
|
2039
|
-
|
|
2721
|
+
const meta = isElementDraft ? void 0 : document.createElement("div");
|
|
2722
|
+
if (meta) {
|
|
2723
|
+
meta.className = "dfwr-item-date";
|
|
2724
|
+
meta.textContent = formatNoteDraftMeta(draft);
|
|
2725
|
+
}
|
|
2040
2726
|
const textarea = document.createElement("textarea");
|
|
2041
2727
|
textarea.className = "dfwr-textarea";
|
|
2042
2728
|
textarea.placeholder = "Review comment";
|
|
@@ -2050,25 +2736,273 @@ var WebReviewKitView = class {
|
|
|
2050
2736
|
comment: textarea.value
|
|
2051
2737
|
});
|
|
2052
2738
|
});
|
|
2053
|
-
const
|
|
2739
|
+
const saveDraft = () => {
|
|
2054
2740
|
const comment = textarea.value.trim();
|
|
2055
|
-
|
|
2741
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2742
|
+
if (!comment && !this.hasDraftAdjustment(currentDraft)) return;
|
|
2056
2743
|
void this.config.actions.createItem({
|
|
2057
2744
|
kind: "note",
|
|
2058
|
-
comment,
|
|
2059
|
-
viewport:
|
|
2060
|
-
anchor:
|
|
2061
|
-
marker:
|
|
2062
|
-
selection:
|
|
2745
|
+
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
2746
|
+
viewport: currentDraft.viewport,
|
|
2747
|
+
anchor: currentDraft.anchor,
|
|
2748
|
+
marker: currentDraft.marker,
|
|
2749
|
+
selection: currentDraft.selection
|
|
2063
2750
|
});
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2751
|
+
};
|
|
2752
|
+
const adjustmentControls = isElementDraft ? this.createAdjustmentControls({
|
|
2753
|
+
draft,
|
|
2754
|
+
pin,
|
|
2755
|
+
popover,
|
|
2756
|
+
selectionHighlight,
|
|
2757
|
+
textarea
|
|
2758
|
+
}) : void 0;
|
|
2759
|
+
const actions = this.createFormActions("Save note", saveDraft);
|
|
2760
|
+
form.append(
|
|
2761
|
+
...meta ? [meta] : [],
|
|
2762
|
+
...adjustmentControls ? [adjustmentControls.panel] : [],
|
|
2763
|
+
textarea,
|
|
2764
|
+
actions
|
|
2765
|
+
);
|
|
2766
|
+
const dragHandle = isElementDraft ? this.createDraftDragHandle("Move DOM composer") : void 0;
|
|
2767
|
+
popover.append(...dragHandle ? [dragHandle] : [], form);
|
|
2067
2768
|
group.append(pin, popover);
|
|
2068
|
-
|
|
2069
|
-
|
|
2769
|
+
if (dragHandle) {
|
|
2770
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
2771
|
+
const noteDraft = this.state.noteDraft ?? draft;
|
|
2772
|
+
this.config.actions.setNoteDraft({
|
|
2773
|
+
...noteDraft,
|
|
2774
|
+
composerPosition,
|
|
2775
|
+
comment: textarea.value
|
|
2776
|
+
});
|
|
2777
|
+
});
|
|
2778
|
+
}
|
|
2779
|
+
this.attachDraftPinDrag(
|
|
2780
|
+
pin,
|
|
2781
|
+
isElementDraft ? void 0 : popover,
|
|
2782
|
+
meta,
|
|
2783
|
+
textarea
|
|
2784
|
+
);
|
|
2785
|
+
window.setTimeout(() => {
|
|
2786
|
+
if (draft.adjustment?.isActive) {
|
|
2787
|
+
adjustmentControls?.focusTarget.focus();
|
|
2788
|
+
return;
|
|
2789
|
+
}
|
|
2790
|
+
textarea.focus();
|
|
2791
|
+
}, 0);
|
|
2070
2792
|
return group;
|
|
2071
2793
|
}
|
|
2794
|
+
createDraftDragHandle(label) {
|
|
2795
|
+
const handle = document.createElement("button");
|
|
2796
|
+
handle.className = "dfwr-draft-drag-handle";
|
|
2797
|
+
handle.type = "button";
|
|
2798
|
+
handle.setAttribute("aria-label", label);
|
|
2799
|
+
return handle;
|
|
2800
|
+
}
|
|
2801
|
+
createIcon(paths) {
|
|
2802
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
2803
|
+
svg.setAttribute("aria-hidden", "true");
|
|
2804
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
2805
|
+
svg.setAttribute("fill", "none");
|
|
2806
|
+
svg.setAttribute("stroke", "currentColor");
|
|
2807
|
+
svg.setAttribute("stroke-width", "2.4");
|
|
2808
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
2809
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
2810
|
+
paths.forEach((d) => {
|
|
2811
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2812
|
+
path.setAttribute("d", d);
|
|
2813
|
+
svg.append(path);
|
|
2814
|
+
});
|
|
2815
|
+
return svg;
|
|
2816
|
+
}
|
|
2817
|
+
setAdjustmentToggleIcon(button, isActive) {
|
|
2818
|
+
const paths = isActive ? ["M20 6 9 17l-5-5"] : [
|
|
2819
|
+
"M12 2v20",
|
|
2820
|
+
"M2 12h20",
|
|
2821
|
+
"m9 5 3-3 3 3",
|
|
2822
|
+
"m9 19 3 3 3-3",
|
|
2823
|
+
"m5 9-3 3 3 3",
|
|
2824
|
+
"m19 9 3 3-3 3"
|
|
2825
|
+
];
|
|
2826
|
+
button.replaceChildren(this.createIcon(paths));
|
|
2827
|
+
}
|
|
2828
|
+
attachDraftComposerDrag(popover, handle, onMove) {
|
|
2829
|
+
let isDragging = false;
|
|
2830
|
+
let offsetX = 0;
|
|
2831
|
+
let offsetY = 0;
|
|
2832
|
+
const movePopover = (event) => {
|
|
2833
|
+
const environment = this.config.getEnvironment();
|
|
2834
|
+
if (!environment) return;
|
|
2835
|
+
const position = this.getClampedComposerPosition(
|
|
2836
|
+
{
|
|
2837
|
+
x: event.clientX - offsetX,
|
|
2838
|
+
y: event.clientY - offsetY
|
|
2839
|
+
},
|
|
2840
|
+
environment,
|
|
2841
|
+
{
|
|
2842
|
+
width: popover.offsetWidth,
|
|
2843
|
+
height: popover.offsetHeight
|
|
2844
|
+
},
|
|
2845
|
+
this.getHostComposerBounds()
|
|
2846
|
+
);
|
|
2847
|
+
popover.style.left = `${position.x}px`;
|
|
2848
|
+
popover.style.top = `${position.y}px`;
|
|
2849
|
+
onMove(position);
|
|
2850
|
+
};
|
|
2851
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
2852
|
+
if (event.button !== 0) return;
|
|
2853
|
+
const rect = popover.getBoundingClientRect();
|
|
2854
|
+
offsetX = event.clientX - rect.left;
|
|
2855
|
+
offsetY = event.clientY - rect.top;
|
|
2856
|
+
isDragging = true;
|
|
2857
|
+
event.preventDefault();
|
|
2858
|
+
event.stopPropagation();
|
|
2859
|
+
handle.setPointerCapture(event.pointerId);
|
|
2860
|
+
popover.classList.add("is-dragging");
|
|
2861
|
+
});
|
|
2862
|
+
handle.addEventListener("pointermove", (event) => {
|
|
2863
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
2864
|
+
event.preventDefault();
|
|
2865
|
+
movePopover(event);
|
|
2866
|
+
});
|
|
2867
|
+
const stopDrag = (event) => {
|
|
2868
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
2869
|
+
event.preventDefault();
|
|
2870
|
+
event.stopPropagation();
|
|
2871
|
+
isDragging = false;
|
|
2872
|
+
handle.releasePointerCapture(event.pointerId);
|
|
2873
|
+
popover.classList.remove("is-dragging");
|
|
2874
|
+
movePopover(event);
|
|
2875
|
+
};
|
|
2876
|
+
handle.addEventListener("pointerup", stopDrag);
|
|
2877
|
+
handle.addEventListener("pointercancel", stopDrag);
|
|
2878
|
+
}
|
|
2879
|
+
createAdjustmentControls({
|
|
2880
|
+
draft,
|
|
2881
|
+
pin,
|
|
2882
|
+
popover,
|
|
2883
|
+
selectionHighlight,
|
|
2884
|
+
textarea
|
|
2885
|
+
}) {
|
|
2886
|
+
const panel = document.createElement("div");
|
|
2887
|
+
panel.className = "dfwr-adjust-panel is-dom-adjust-panel";
|
|
2888
|
+
const header = document.createElement("div");
|
|
2889
|
+
header.className = "dfwr-adjust-panel-header";
|
|
2890
|
+
const help = document.createElement("div");
|
|
2891
|
+
help.className = "dfwr-adjust-help";
|
|
2892
|
+
help.textContent = this.getAdjustmentLabel();
|
|
2893
|
+
const adjust = document.createElement("button");
|
|
2894
|
+
adjust.className = "dfwr-adjust-toggle";
|
|
2895
|
+
adjust.type = "button";
|
|
2896
|
+
adjust.title = "Adjust DOM element with keyboard arrows";
|
|
2897
|
+
adjust.setAttribute("aria-label", "Adjust DOM element with keyboard arrows");
|
|
2898
|
+
const xyStatus = document.createElement("div");
|
|
2899
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
2900
|
+
const scaleStatus = document.createElement("div");
|
|
2901
|
+
scaleStatus.className = "dfwr-adjust-status";
|
|
2902
|
+
const syncControls = (nextDraft) => {
|
|
2903
|
+
const isActive = nextDraft.adjustment?.isActive === true;
|
|
2904
|
+
panel.classList.toggle("is-active", isActive);
|
|
2905
|
+
adjust.classList.toggle("is-active", isActive);
|
|
2906
|
+
adjust.setAttribute("aria-pressed", isActive ? "true" : "false");
|
|
2907
|
+
this.setAdjustmentToggleIcon(adjust, isActive);
|
|
2908
|
+
adjust.title = isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows";
|
|
2909
|
+
adjust.setAttribute(
|
|
2910
|
+
"aria-label",
|
|
2911
|
+
isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows"
|
|
2912
|
+
);
|
|
2913
|
+
const [xyLine, scaleLine] = this.getDraftAdjustmentMetricLines(nextDraft);
|
|
2914
|
+
xyStatus.textContent = xyLine;
|
|
2915
|
+
scaleStatus.textContent = scaleLine;
|
|
2916
|
+
this.syncDraftAdjustmentUi({
|
|
2917
|
+
draft: nextDraft,
|
|
2918
|
+
pin,
|
|
2919
|
+
selectionHighlight
|
|
2920
|
+
});
|
|
2921
|
+
};
|
|
2922
|
+
const updateDraft = (updater) => {
|
|
2923
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2924
|
+
const nextDraft = updater(currentDraft);
|
|
2925
|
+
this.config.actions.setNoteDraft({
|
|
2926
|
+
...nextDraft,
|
|
2927
|
+
comment: textarea.value
|
|
2928
|
+
});
|
|
2929
|
+
syncControls(nextDraft);
|
|
2930
|
+
};
|
|
2931
|
+
adjust.addEventListener("click", () => {
|
|
2932
|
+
updateDraft((currentDraft) => ({
|
|
2933
|
+
...currentDraft,
|
|
2934
|
+
adjustment: {
|
|
2935
|
+
x: currentDraft.adjustment?.x ?? 0,
|
|
2936
|
+
y: currentDraft.adjustment?.y ?? 0,
|
|
2937
|
+
scale: currentDraft.adjustment?.scale ?? 0,
|
|
2938
|
+
isActive: currentDraft.adjustment?.isActive !== true
|
|
2939
|
+
}
|
|
2940
|
+
}));
|
|
2941
|
+
adjust.focus();
|
|
2942
|
+
});
|
|
2943
|
+
popover.addEventListener("keydown", (event) => {
|
|
2944
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2945
|
+
if (currentDraft.adjustment?.isActive !== true) return;
|
|
2946
|
+
const keyDelta = this.getAdjustmentKeyDelta(event);
|
|
2947
|
+
if (!keyDelta) return;
|
|
2948
|
+
event.preventDefault();
|
|
2949
|
+
event.stopPropagation();
|
|
2950
|
+
updateDraft((activeDraft) => ({
|
|
2951
|
+
...activeDraft,
|
|
2952
|
+
adjustment: {
|
|
2953
|
+
x: (activeDraft.adjustment?.x ?? 0) + keyDelta.x,
|
|
2954
|
+
y: (activeDraft.adjustment?.y ?? 0) + keyDelta.y,
|
|
2955
|
+
scale: (activeDraft.adjustment?.scale ?? 0) + keyDelta.scale,
|
|
2956
|
+
isActive: true
|
|
2957
|
+
}
|
|
2958
|
+
}));
|
|
2959
|
+
});
|
|
2960
|
+
header.append(help, adjust);
|
|
2961
|
+
panel.append(header, xyStatus, scaleStatus);
|
|
2962
|
+
syncControls(draft);
|
|
2963
|
+
return {
|
|
2964
|
+
panel,
|
|
2965
|
+
focusTarget: adjust
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
getAdjustmentKeyDelta(event) {
|
|
2969
|
+
const step = event.shiftKey ? 10 : 1;
|
|
2970
|
+
if (event.key === "ArrowLeft") return { x: -step, y: 0, scale: 0 };
|
|
2971
|
+
if (event.key === "ArrowRight") return { x: step, y: 0, scale: 0 };
|
|
2972
|
+
if (event.key === "ArrowUp") return { x: 0, y: -step, scale: 0 };
|
|
2973
|
+
if (event.key === "ArrowDown") return { x: 0, y: step, scale: 0 };
|
|
2974
|
+
if (event.key.toLowerCase() === "w") return { x: 0, y: 0, scale: step };
|
|
2975
|
+
if (event.key.toLowerCase() === "s") return { x: 0, y: 0, scale: -step };
|
|
2976
|
+
return void 0;
|
|
2977
|
+
}
|
|
2978
|
+
syncDraftAdjustmentUi({
|
|
2979
|
+
draft,
|
|
2980
|
+
pin,
|
|
2981
|
+
selectionHighlight
|
|
2982
|
+
}) {
|
|
2983
|
+
const environment = this.config.getEnvironment();
|
|
2984
|
+
if (!environment) return;
|
|
2985
|
+
const hostPoint = toHostPoint(
|
|
2986
|
+
this.getAdjustedDraftPoint(draft.marker.viewport, draft),
|
|
2987
|
+
environment
|
|
2988
|
+
);
|
|
2989
|
+
pin.style.left = `${hostPoint.x}px`;
|
|
2990
|
+
pin.style.top = `${hostPoint.y}px`;
|
|
2991
|
+
if (draft.selection && selectionHighlight) {
|
|
2992
|
+
const rect = toHostSelection(
|
|
2993
|
+
this.getAdjustedDraftSelection(
|
|
2994
|
+
toViewportSelection(draft.selection.viewport),
|
|
2995
|
+
draft
|
|
2996
|
+
),
|
|
2997
|
+
environment
|
|
2998
|
+
);
|
|
2999
|
+
selectionHighlight.style.left = `${rect.left}px`;
|
|
3000
|
+
selectionHighlight.style.top = `${rect.top}px`;
|
|
3001
|
+
selectionHighlight.style.width = `${rect.width}px`;
|
|
3002
|
+
selectionHighlight.style.height = `${rect.height}px`;
|
|
3003
|
+
}
|
|
3004
|
+
this.syncDraftPreview(draft);
|
|
3005
|
+
}
|
|
2072
3006
|
createAreaForm() {
|
|
2073
3007
|
const form = document.createElement("form");
|
|
2074
3008
|
form.className = "dfwr-form";
|
|
@@ -2080,14 +3014,20 @@ var WebReviewKitView = class {
|
|
|
2080
3014
|
form.append(empty);
|
|
2081
3015
|
return form;
|
|
2082
3016
|
}
|
|
2083
|
-
|
|
2084
|
-
meta.className = "dfwr-item-date";
|
|
2085
|
-
meta.textContent = formatAreaDraftMeta(areaDraft);
|
|
2086
|
-
form.append(meta);
|
|
3017
|
+
form.append(this.createAreaMetricsPanel(areaDraft));
|
|
2087
3018
|
const textarea = document.createElement("textarea");
|
|
2088
3019
|
textarea.className = "dfwr-textarea";
|
|
2089
3020
|
textarea.placeholder = "Area comment";
|
|
2090
3021
|
textarea.rows = 4;
|
|
3022
|
+
textarea.value = areaDraft.comment ?? "";
|
|
3023
|
+
textarea.addEventListener("input", () => {
|
|
3024
|
+
const draft = this.state.areaDraft;
|
|
3025
|
+
if (!draft) return;
|
|
3026
|
+
this.config.actions.setAreaDraft({
|
|
3027
|
+
...draft,
|
|
3028
|
+
comment: textarea.value
|
|
3029
|
+
});
|
|
3030
|
+
});
|
|
2091
3031
|
const actions = this.createFormActions("Save area", () => {
|
|
2092
3032
|
const comment = textarea.value.trim();
|
|
2093
3033
|
const draft = this.state.areaDraft;
|
|
@@ -2104,6 +3044,25 @@ var WebReviewKitView = class {
|
|
|
2104
3044
|
form.append(textarea, actions);
|
|
2105
3045
|
return form;
|
|
2106
3046
|
}
|
|
3047
|
+
createAreaMetricsPanel(draft) {
|
|
3048
|
+
const panel = document.createElement("div");
|
|
3049
|
+
panel.className = "dfwr-adjust-panel is-area-metrics-panel";
|
|
3050
|
+
const help = document.createElement("div");
|
|
3051
|
+
help.className = "dfwr-adjust-help";
|
|
3052
|
+
const [labelLine, xyLine, sizeLine] = this.getSelectionMetricLines(
|
|
3053
|
+
this.getAreaDraftMetricSelection(draft),
|
|
3054
|
+
draft.viewport
|
|
3055
|
+
);
|
|
3056
|
+
help.textContent = labelLine;
|
|
3057
|
+
const xyStatus = document.createElement("div");
|
|
3058
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
3059
|
+
xyStatus.textContent = xyLine;
|
|
3060
|
+
const sizeStatus = document.createElement("div");
|
|
3061
|
+
sizeStatus.className = "dfwr-adjust-status";
|
|
3062
|
+
sizeStatus.textContent = sizeLine;
|
|
3063
|
+
panel.append(help, xyStatus, sizeStatus);
|
|
3064
|
+
return panel;
|
|
3065
|
+
}
|
|
2107
3066
|
createAreaDraftOverlay(draft) {
|
|
2108
3067
|
const layer = document.createElement("div");
|
|
2109
3068
|
layer.className = "dfwr-area-preview-layer";
|
|
@@ -2132,37 +3091,61 @@ var WebReviewKitView = class {
|
|
|
2132
3091
|
createAreaDraftPopover(draft) {
|
|
2133
3092
|
const environment = this.config.getEnvironment();
|
|
2134
3093
|
const popover = document.createElement("div");
|
|
2135
|
-
popover.className = "dfwr-area-draft";
|
|
3094
|
+
popover.className = "dfwr-area-draft is-composer";
|
|
2136
3095
|
if (environment && draft.selection) {
|
|
2137
3096
|
const selection = toHostSelection(
|
|
2138
3097
|
toViewportSelection(draft.selection.viewport),
|
|
2139
3098
|
environment
|
|
2140
3099
|
);
|
|
2141
|
-
const
|
|
2142
|
-
|
|
2143
|
-
|
|
3100
|
+
const composer = this.getDraftComposerPosition({
|
|
3101
|
+
selection,
|
|
3102
|
+
environment,
|
|
3103
|
+
composerPosition: draft.composerPosition,
|
|
3104
|
+
estimatedHeight: 220
|
|
3105
|
+
});
|
|
3106
|
+
popover.style.left = `${composer.left}px`;
|
|
3107
|
+
popover.style.top = `${composer.top}px`;
|
|
3108
|
+
popover.style.width = `${composer.width}px`;
|
|
2144
3109
|
popover.style.right = "auto";
|
|
2145
3110
|
}
|
|
2146
|
-
|
|
3111
|
+
const dragHandle = this.createDraftDragHandle("Move area composer");
|
|
3112
|
+
popover.append(dragHandle, this.createAreaForm());
|
|
3113
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
3114
|
+
const areaDraft = this.state.areaDraft ?? draft;
|
|
3115
|
+
this.config.actions.setAreaDraft({
|
|
3116
|
+
...areaDraft,
|
|
3117
|
+
composerPosition
|
|
3118
|
+
});
|
|
3119
|
+
});
|
|
2147
3120
|
return popover;
|
|
2148
3121
|
}
|
|
2149
|
-
createFormActions(saveLabel, onSave) {
|
|
3122
|
+
createFormActions(saveLabel, onSave, options) {
|
|
2150
3123
|
const actions = document.createElement("div");
|
|
2151
|
-
actions.className = "dfwr-actions";
|
|
3124
|
+
actions.className = ["dfwr-actions", options?.className].filter(Boolean).join(" ");
|
|
2152
3125
|
const save = document.createElement("button");
|
|
2153
3126
|
save.className = "dfwr-button is-primary";
|
|
2154
3127
|
save.type = "button";
|
|
2155
3128
|
save.textContent = saveLabel;
|
|
2156
|
-
save.addEventListener("click",
|
|
3129
|
+
save.addEventListener("click", (event) => {
|
|
3130
|
+
event.preventDefault();
|
|
3131
|
+
event.stopPropagation();
|
|
3132
|
+
onSave();
|
|
3133
|
+
});
|
|
2157
3134
|
const cancel = document.createElement("button");
|
|
2158
3135
|
cancel.className = "dfwr-button";
|
|
2159
3136
|
cancel.type = "button";
|
|
2160
3137
|
cancel.textContent = "Cancel";
|
|
2161
|
-
cancel.addEventListener("click", () => {
|
|
3138
|
+
cancel.addEventListener("click", (event) => {
|
|
3139
|
+
event.preventDefault();
|
|
3140
|
+
event.stopPropagation();
|
|
2162
3141
|
this.config.actions.setModeState("idle");
|
|
2163
3142
|
this.config.actions.clearDrafts();
|
|
2164
3143
|
this.config.actions.render();
|
|
2165
3144
|
});
|
|
3145
|
+
if (options?.beforeSave?.length || options?.className) {
|
|
3146
|
+
actions.append(cancel, ...options.beforeSave ?? [], save);
|
|
3147
|
+
return actions;
|
|
3148
|
+
}
|
|
2166
3149
|
actions.append(save, cancel);
|
|
2167
3150
|
return actions;
|
|
2168
3151
|
}
|
|
@@ -2367,11 +3350,13 @@ ${formatItemMeta(item)}`;
|
|
|
2367
3350
|
if (!environment) return;
|
|
2368
3351
|
const nextPoint = clampPoint(toTargetPoint(hostPoint, environment), environment);
|
|
2369
3352
|
const nextHostPoint = toHostPoint(nextPoint, environment);
|
|
2370
|
-
const position = getPopoverPosition(nextHostPoint, environment);
|
|
2371
3353
|
pin.style.left = `${nextHostPoint.x}px`;
|
|
2372
3354
|
pin.style.top = `${nextHostPoint.y}px`;
|
|
2373
|
-
popover
|
|
2374
|
-
|
|
3355
|
+
if (popover) {
|
|
3356
|
+
const position = getPopoverPosition(nextHostPoint, environment);
|
|
3357
|
+
popover.style.left = `${position.left}px`;
|
|
3358
|
+
popover.style.top = `${position.top}px`;
|
|
3359
|
+
}
|
|
2375
3360
|
const noteDraft = this.state.noteDraft;
|
|
2376
3361
|
if (!noteDraft) return;
|
|
2377
3362
|
const nextDraft = {
|
|
@@ -2383,7 +3368,9 @@ ${formatItemMeta(item)}`;
|
|
|
2383
3368
|
comment: textarea.value
|
|
2384
3369
|
};
|
|
2385
3370
|
this.config.actions.setNoteDraft(nextDraft);
|
|
2386
|
-
|
|
3371
|
+
if (meta) {
|
|
3372
|
+
meta.textContent = formatNoteDraftMeta(nextDraft);
|
|
3373
|
+
}
|
|
2387
3374
|
};
|
|
2388
3375
|
pin.addEventListener("pointerdown", (event) => {
|
|
2389
3376
|
if (event.button !== 0) return;
|
|
@@ -2616,6 +3603,9 @@ var WebReviewKitApp = class {
|
|
|
2616
3603
|
setNoteDraft: (draft) => {
|
|
2617
3604
|
this.noteDraft = draft;
|
|
2618
3605
|
},
|
|
3606
|
+
setAreaDraft: (draft) => {
|
|
3607
|
+
this.areaDraft = draft;
|
|
3608
|
+
},
|
|
2619
3609
|
setSelectingArea: (isSelectingArea) => {
|
|
2620
3610
|
this.isSelectingArea = isSelectingArea;
|
|
2621
3611
|
},
|
|
@@ -2641,6 +3631,7 @@ var WebReviewKitApp = class {
|
|
|
2641
3631
|
this.render();
|
|
2642
3632
|
}
|
|
2643
3633
|
destroy() {
|
|
3634
|
+
this.view.clearDraftPreview();
|
|
2644
3635
|
document.removeEventListener("keydown", this.handleKeyDown, true);
|
|
2645
3636
|
window.removeEventListener("scroll", this.handleViewportChange, true);
|
|
2646
3637
|
window.removeEventListener("resize", this.handleViewportChange);
|
|
@@ -2844,14 +3835,27 @@ var WebReviewKitApp = class {
|
|
|
2844
3835
|
const viewport = getViewportSize(environment);
|
|
2845
3836
|
const nextPoint = clampPoint(point, environment);
|
|
2846
3837
|
const draft = await this.withOverlayHidden(() => {
|
|
3838
|
+
const pointSelection = getPointSelection(nextPoint);
|
|
3839
|
+
const targetElement = environment.document.elementFromPoint(
|
|
3840
|
+
nextPoint.x,
|
|
3841
|
+
nextPoint.y
|
|
3842
|
+
);
|
|
3843
|
+
const previewElement = targetElement && "style" in targetElement ? targetElement : void 0;
|
|
3844
|
+
const targetRect = targetElement?.getBoundingClientRect();
|
|
3845
|
+
const clickedSelection = targetRect && targetRect.width > 0 && targetRect.height > 0 ? {
|
|
3846
|
+
left: targetRect.left,
|
|
3847
|
+
top: targetRect.top,
|
|
3848
|
+
width: targetRect.width,
|
|
3849
|
+
height: targetRect.height
|
|
3850
|
+
} : void 0;
|
|
2847
3851
|
const anchor = getDomAnchorFromPoint(
|
|
2848
3852
|
nextPoint,
|
|
2849
3853
|
this.options.anchors?.attribute,
|
|
2850
3854
|
environment
|
|
2851
3855
|
);
|
|
2852
|
-
const elementSelection = anchor ? getElementViewportSelection(anchor, environment) : void 0;
|
|
2853
|
-
const selection = elementSelection ??
|
|
2854
|
-
const markerPoint = getSelectionCenter(selection);
|
|
3856
|
+
const elementSelection = anchor ? clickedSelection ?? getElementViewportSelection(anchor, environment, pointSelection) : void 0;
|
|
3857
|
+
const selection = elementSelection ?? pointSelection;
|
|
3858
|
+
const markerPoint = elementSelection ? { x: selection.left, y: selection.top } : getSelectionCenter(selection);
|
|
2855
3859
|
const reviewSelection = elementSelection ? {
|
|
2856
3860
|
viewport: toPublicSelection(elementSelection),
|
|
2857
3861
|
relative: getRelativeSelection(
|
|
@@ -2869,7 +3873,8 @@ var WebReviewKitApp = class {
|
|
|
2869
3873
|
anchor,
|
|
2870
3874
|
marker,
|
|
2871
3875
|
selection: reviewSelection,
|
|
2872
|
-
comment
|
|
3876
|
+
comment,
|
|
3877
|
+
previewElement
|
|
2873
3878
|
};
|
|
2874
3879
|
});
|
|
2875
3880
|
this.noteDraft = draft;
|
|
@@ -3009,4 +4014,4 @@ export {
|
|
|
3009
4014
|
getNumberedReviewItems,
|
|
3010
4015
|
createWebReviewKit
|
|
3011
4016
|
};
|
|
3012
|
-
//# sourceMappingURL=chunk-
|
|
4017
|
+
//# sourceMappingURL=chunk-6L2KJ7XL.js.map
|