@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
package/dist/index.cjs
CHANGED
|
@@ -459,19 +459,6 @@ function getPopoverPosition(point, environment, options) {
|
|
|
459
459
|
)
|
|
460
460
|
};
|
|
461
461
|
}
|
|
462
|
-
function getAreaPopoverPosition(selection, environment) {
|
|
463
|
-
return getPopoverPosition(
|
|
464
|
-
{
|
|
465
|
-
x: selection.left + selection.width,
|
|
466
|
-
y: selection.top
|
|
467
|
-
},
|
|
468
|
-
environment,
|
|
469
|
-
{
|
|
470
|
-
width: 360,
|
|
471
|
-
estimatedHeight: 206
|
|
472
|
-
}
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
462
|
function getPopoverBounds(environment) {
|
|
476
463
|
if (!environment) {
|
|
477
464
|
return {
|
|
@@ -536,6 +523,21 @@ function roundPoint(point) {
|
|
|
536
523
|
}
|
|
537
524
|
|
|
538
525
|
// src/core/dom.anchor.ts
|
|
526
|
+
var COMMON_ANCHOR_ATTRIBUTES = [
|
|
527
|
+
"data-testid",
|
|
528
|
+
"data-test-id",
|
|
529
|
+
"data-cy",
|
|
530
|
+
"data-test",
|
|
531
|
+
"data-qa",
|
|
532
|
+
"data-section-id",
|
|
533
|
+
"data-component"
|
|
534
|
+
];
|
|
535
|
+
var SEMANTIC_ANCHOR_ATTRIBUTES = [
|
|
536
|
+
"aria-label",
|
|
537
|
+
"title",
|
|
538
|
+
"name",
|
|
539
|
+
"href"
|
|
540
|
+
];
|
|
539
541
|
function getDomAnchor(selection, configuredAttribute = "data-qa-id", environment) {
|
|
540
542
|
const x = selection.left + selection.width / 2;
|
|
541
543
|
const y = selection.top + selection.height / 2;
|
|
@@ -556,8 +558,8 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
|
|
|
556
558
|
source: getDomSourceHint(target)
|
|
557
559
|
};
|
|
558
560
|
}
|
|
559
|
-
function getElementViewportSelection(anchor, environment) {
|
|
560
|
-
const element = getAnchorElement(anchor, environment);
|
|
561
|
+
function getElementViewportSelection(anchor, environment, preferredSelection) {
|
|
562
|
+
const element = getAnchorElement(anchor, environment, preferredSelection);
|
|
561
563
|
if (!element) return void 0;
|
|
562
564
|
const rect = element.getBoundingClientRect();
|
|
563
565
|
if (rect.width <= 0 || rect.height <= 0) return void 0;
|
|
@@ -596,22 +598,35 @@ function getAnchorCandidates(anchor) {
|
|
|
596
598
|
...anchor.candidates ?? []
|
|
597
599
|
]);
|
|
598
600
|
}
|
|
599
|
-
function resolveAnchorElement(anchor, environment) {
|
|
601
|
+
function resolveAnchorElement(anchor, environment, preferredSelection) {
|
|
600
602
|
const matches = getAnchorCandidates(anchor).flatMap((candidate) => {
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
(
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
603
|
+
const textFingerprint = candidate.textFingerprint ?? anchor.textFingerprint;
|
|
604
|
+
if (!preferredSelection) {
|
|
605
|
+
const match = queryBestAnchorCandidate(
|
|
606
|
+
candidate,
|
|
607
|
+
textFingerprint,
|
|
608
|
+
environment
|
|
609
|
+
);
|
|
610
|
+
if (!match) return [];
|
|
611
|
+
const confidence = roundRatio(
|
|
612
|
+
(candidate.confidence ?? 0.5) * match.score
|
|
613
|
+
);
|
|
614
|
+
return [{
|
|
615
|
+
element: match.element,
|
|
616
|
+
candidate,
|
|
617
|
+
confidence
|
|
618
|
+
}];
|
|
619
|
+
}
|
|
620
|
+
return queryAnchorElements(candidate.selector, environment).map((element) => {
|
|
621
|
+
const confidence = roundRatio(
|
|
622
|
+
(candidate.confidence ?? 0.5) * getTextFingerprintScore(textFingerprint, getTextFingerprint(element)) * getSelectionMatchScore(element, preferredSelection)
|
|
623
|
+
);
|
|
624
|
+
return {
|
|
625
|
+
element,
|
|
626
|
+
candidate,
|
|
627
|
+
confidence
|
|
628
|
+
};
|
|
629
|
+
});
|
|
615
630
|
});
|
|
616
631
|
return matches.sort((a, b) => b.confidence - a.confidence)[0];
|
|
617
632
|
}
|
|
@@ -621,50 +636,70 @@ function cssEscape(value) {
|
|
|
621
636
|
}
|
|
622
637
|
return value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
623
638
|
}
|
|
624
|
-
function getAnchorElement(anchor, environment) {
|
|
625
|
-
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment)?.element;
|
|
639
|
+
function getAnchorElement(anchor, environment, preferredSelection) {
|
|
640
|
+
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment, preferredSelection)?.element;
|
|
626
641
|
}
|
|
627
642
|
function createAnchorCandidates(target, configuredAttribute) {
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
643
|
+
const targetCandidates = [];
|
|
644
|
+
const configuredAnchor = getExactAttributeAnchorCandidate(
|
|
645
|
+
target,
|
|
646
|
+
configuredAttribute,
|
|
647
|
+
0.98,
|
|
648
|
+
"configured-attribute"
|
|
649
|
+
);
|
|
650
|
+
if (configuredAnchor) targetCandidates.push(configuredAnchor);
|
|
651
|
+
const targetAttributeAnchor = getAttributeAnchorCandidate(
|
|
652
|
+
target,
|
|
653
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
654
|
+
0.9
|
|
655
|
+
);
|
|
656
|
+
if (targetAttributeAnchor) targetCandidates.push(targetAttributeAnchor);
|
|
641
657
|
if (isMeaningfulId(target.id)) {
|
|
642
|
-
|
|
658
|
+
targetCandidates.push({
|
|
643
659
|
selector: `#${cssEscape(target.id)}`,
|
|
644
660
|
strategy: "id",
|
|
645
661
|
confidence: 0.94,
|
|
646
662
|
textFingerprint: getTextFingerprint(target)
|
|
647
663
|
});
|
|
648
664
|
}
|
|
665
|
+
const semanticAnchor = getAttributeAnchorCandidate(
|
|
666
|
+
target,
|
|
667
|
+
SEMANTIC_ANCHOR_ATTRIBUTES,
|
|
668
|
+
0.84
|
|
669
|
+
);
|
|
670
|
+
if (semanticAnchor) targetCandidates.push(semanticAnchor);
|
|
649
671
|
const targetClassName = getMeaningfulClassName(target);
|
|
650
672
|
if (targetClassName) {
|
|
651
|
-
|
|
673
|
+
targetCandidates.push({
|
|
652
674
|
selector: `${target.tagName.toLowerCase()}.${cssEscape(targetClassName)}`,
|
|
653
675
|
strategy: "class",
|
|
654
676
|
confidence: 0.82,
|
|
655
677
|
textFingerprint: getTextFingerprint(target)
|
|
656
678
|
});
|
|
657
679
|
}
|
|
658
|
-
|
|
680
|
+
const scopedPath = getScopedDomPathCandidate(target, configuredAttribute);
|
|
681
|
+
if (scopedPath) targetCandidates.push(scopedPath);
|
|
682
|
+
const targetDomPath = {
|
|
659
683
|
selector: getDomPath(target),
|
|
660
684
|
strategy: "dom-path",
|
|
661
|
-
confidence: 0.
|
|
685
|
+
confidence: targetCandidates.length > 0 ? 0.8 : 0.5,
|
|
662
686
|
textFingerprint: getTextFingerprint(target)
|
|
663
|
-
}
|
|
687
|
+
};
|
|
688
|
+
const parentCandidates = [];
|
|
664
689
|
const parent = target.parentElement;
|
|
690
|
+
const parentConfiguredAnchor = parent ? findClosestAttributeAnchor(parent, [configuredAttribute], 0.72, {
|
|
691
|
+
strategy: "configured-attribute"
|
|
692
|
+
}) : void 0;
|
|
693
|
+
if (parentConfiguredAnchor) parentCandidates.push(parentConfiguredAnchor);
|
|
694
|
+
const anchoredByAttribute = parent ? findClosestAttributeAnchor(
|
|
695
|
+
parent,
|
|
696
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
697
|
+
0.7
|
|
698
|
+
) : void 0;
|
|
699
|
+
if (anchoredByAttribute) parentCandidates.push(anchoredByAttribute);
|
|
665
700
|
const anchoredById = parent ? findClosest(parent, (element) => isMeaningfulId(element.id)) : void 0;
|
|
666
701
|
if (anchoredById?.id) {
|
|
667
|
-
|
|
702
|
+
parentCandidates.push({
|
|
668
703
|
selector: `#${cssEscape(anchoredById.id)}`,
|
|
669
704
|
strategy: "id",
|
|
670
705
|
confidence: 0.72,
|
|
@@ -674,7 +709,7 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
674
709
|
const anchoredByClass = parent ? findClosest(parent, (element) => Boolean(getMeaningfulClassName(element))) : void 0;
|
|
675
710
|
const className = anchoredByClass ? getMeaningfulClassName(anchoredByClass) : void 0;
|
|
676
711
|
if (anchoredByClass && className) {
|
|
677
|
-
|
|
712
|
+
parentCandidates.push({
|
|
678
713
|
selector: `${anchoredByClass.tagName.toLowerCase()}.${cssEscape(
|
|
679
714
|
className
|
|
680
715
|
)}`,
|
|
@@ -683,8 +718,107 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
683
718
|
textFingerprint: getTextFingerprint(anchoredByClass)
|
|
684
719
|
});
|
|
685
720
|
}
|
|
721
|
+
const candidates = targetCandidates.length > 0 ? [...targetCandidates, targetDomPath, ...parentCandidates] : [...parentCandidates, targetDomPath];
|
|
686
722
|
return dedupeAnchorCandidates(candidates);
|
|
687
723
|
}
|
|
724
|
+
function findClosestAttributeAnchor(target, attributeNames, confidence, options) {
|
|
725
|
+
for (const attributeName of attributeNames) {
|
|
726
|
+
const selector = `[${attributeName}]`;
|
|
727
|
+
const element = safeClosest(target, selector);
|
|
728
|
+
if (!element) continue;
|
|
729
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
730
|
+
if (!value) continue;
|
|
731
|
+
return {
|
|
732
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
733
|
+
strategy: options?.strategy ?? "attribute",
|
|
734
|
+
confidence,
|
|
735
|
+
textFingerprint: getTextFingerprint(element)
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
return void 0;
|
|
739
|
+
}
|
|
740
|
+
function getExactAttributeAnchorCandidate(element, attributeName, confidence, strategy) {
|
|
741
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
742
|
+
if (!value) return void 0;
|
|
743
|
+
return {
|
|
744
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
745
|
+
strategy,
|
|
746
|
+
confidence,
|
|
747
|
+
textFingerprint: getTextFingerprint(element)
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function getAttributeAnchorCandidate(element, attributeNames, confidence) {
|
|
751
|
+
for (const attributeName of attributeNames) {
|
|
752
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
753
|
+
if (!value) continue;
|
|
754
|
+
return {
|
|
755
|
+
selector: `${element.tagName.toLowerCase()}[${attributeName}="${cssEscape(
|
|
756
|
+
value
|
|
757
|
+
)}"]`,
|
|
758
|
+
strategy: "attribute",
|
|
759
|
+
confidence,
|
|
760
|
+
textFingerprint: getTextFingerprint(element)
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
return void 0;
|
|
764
|
+
}
|
|
765
|
+
function getScopedDomPathCandidate(target, configuredAttribute) {
|
|
766
|
+
const parent = target.parentElement;
|
|
767
|
+
if (!parent) return void 0;
|
|
768
|
+
const anchor = findStableAncestorSelector(parent, configuredAttribute);
|
|
769
|
+
if (!anchor) return void 0;
|
|
770
|
+
const selector = getDomPathBetween(anchor.element, target, anchor.selector);
|
|
771
|
+
if (!selector) return void 0;
|
|
772
|
+
return {
|
|
773
|
+
selector,
|
|
774
|
+
strategy: "dom-path",
|
|
775
|
+
confidence: anchor.confidence,
|
|
776
|
+
textFingerprint: getTextFingerprint(target)
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function findStableAncestorSelector(start, configuredAttribute) {
|
|
780
|
+
let element = start;
|
|
781
|
+
const root = start.ownerDocument.documentElement;
|
|
782
|
+
while (element && element !== root) {
|
|
783
|
+
const configuredValue = getStableAttributeValue(element, configuredAttribute);
|
|
784
|
+
if (configuredValue) {
|
|
785
|
+
return {
|
|
786
|
+
element,
|
|
787
|
+
selector: `[${configuredAttribute}="${cssEscape(configuredValue)}"]`,
|
|
788
|
+
confidence: 0.88
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
const attributeAnchor = getAttributeAnchorCandidate(
|
|
792
|
+
element,
|
|
793
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
794
|
+
0.84
|
|
795
|
+
);
|
|
796
|
+
if (attributeAnchor) {
|
|
797
|
+
return {
|
|
798
|
+
element,
|
|
799
|
+
selector: attributeAnchor.selector,
|
|
800
|
+
confidence: 0.84
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
if (isMeaningfulId(element.id)) {
|
|
804
|
+
return {
|
|
805
|
+
element,
|
|
806
|
+
selector: `#${cssEscape(element.id)}`,
|
|
807
|
+
confidence: 0.82
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
const className = getMeaningfulClassName(element);
|
|
811
|
+
if (className) {
|
|
812
|
+
return {
|
|
813
|
+
element,
|
|
814
|
+
selector: `${element.tagName.toLowerCase()}.${cssEscape(className)}`,
|
|
815
|
+
confidence: 0.76
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
element = element.parentElement;
|
|
819
|
+
}
|
|
820
|
+
return void 0;
|
|
821
|
+
}
|
|
688
822
|
function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
689
823
|
if (candidate.strategy === "configured-attribute") {
|
|
690
824
|
return target.closest(`[${configuredAttribute}]`);
|
|
@@ -696,6 +830,13 @@ function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
|
696
830
|
return target;
|
|
697
831
|
}
|
|
698
832
|
}
|
|
833
|
+
function safeClosest(element, selector) {
|
|
834
|
+
try {
|
|
835
|
+
return element.closest(selector);
|
|
836
|
+
} catch {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
699
840
|
function getElementHtmlSnippet(element, maxLength = 1e3) {
|
|
700
841
|
const html = decodeHtmlEntities(element.outerHTML.replace(/\s+/g, " ").trim());
|
|
701
842
|
if (html.length <= maxLength) return html;
|
|
@@ -817,10 +958,38 @@ function getDomPath(element) {
|
|
|
817
958
|
}
|
|
818
959
|
return `body > ${parts.join(" > ")}`;
|
|
819
960
|
}
|
|
961
|
+
function getDomPathBetween(ancestor, target, ancestorSelector) {
|
|
962
|
+
const parts = [];
|
|
963
|
+
let current = target;
|
|
964
|
+
while (current && current !== ancestor) {
|
|
965
|
+
parts.unshift(getDomPathPart(current));
|
|
966
|
+
current = current.parentElement;
|
|
967
|
+
}
|
|
968
|
+
if (current !== ancestor || parts.length === 0) return void 0;
|
|
969
|
+
return `${ancestorSelector} > ${parts.join(" > ")}`;
|
|
970
|
+
}
|
|
971
|
+
function getDomPathPart(element) {
|
|
972
|
+
const parent = element.parentElement;
|
|
973
|
+
const tag = element.tagName.toLowerCase();
|
|
974
|
+
if (!parent) return tag;
|
|
975
|
+
const currentTagName = element.tagName;
|
|
976
|
+
const siblings = Array.from(parent.children).filter(
|
|
977
|
+
(child) => child.tagName === currentTagName
|
|
978
|
+
);
|
|
979
|
+
const index = siblings.indexOf(element) + 1;
|
|
980
|
+
return `${tag}:nth-of-type(${index})`;
|
|
981
|
+
}
|
|
820
982
|
function getTextFingerprint(element) {
|
|
821
983
|
const text = element.textContent?.replace(/\s+/g, " ").trim();
|
|
822
984
|
return text ? text.slice(0, 120) : void 0;
|
|
823
985
|
}
|
|
986
|
+
function getStableAttributeValue(element, attributeName) {
|
|
987
|
+
const value = element.getAttribute(attributeName)?.trim();
|
|
988
|
+
if (!value || value.length > 160) return void 0;
|
|
989
|
+
if (/^(true|false)$/i.test(value)) return void 0;
|
|
990
|
+
if (/^\d+$/.test(value) && value.length < 3) return void 0;
|
|
991
|
+
return value;
|
|
992
|
+
}
|
|
824
993
|
function getTextFingerprintScore(expected, actual) {
|
|
825
994
|
if (!expected) return 1;
|
|
826
995
|
if (!actual) return 0.5;
|
|
@@ -832,6 +1001,38 @@ function getTextFingerprintScore(expected, actual) {
|
|
|
832
1001
|
const matches = expectedTokens.filter((token) => actualTokens.has(token));
|
|
833
1002
|
return clamp(matches.length / expectedTokens.length, 0.25, 0.76);
|
|
834
1003
|
}
|
|
1004
|
+
function getSelectionMatchScore(element, selection) {
|
|
1005
|
+
const rect = element.getBoundingClientRect();
|
|
1006
|
+
if (rect.width <= 0 || rect.height <= 0) return 0.05;
|
|
1007
|
+
const overlapLeft = Math.max(rect.left, selection.left);
|
|
1008
|
+
const overlapTop = Math.max(rect.top, selection.top);
|
|
1009
|
+
const overlapRight = Math.min(rect.right, selection.left + selection.width);
|
|
1010
|
+
const overlapBottom = Math.min(rect.bottom, selection.top + selection.height);
|
|
1011
|
+
const overlapWidth = Math.max(0, overlapRight - overlapLeft);
|
|
1012
|
+
const overlapHeight = Math.max(0, overlapBottom - overlapTop);
|
|
1013
|
+
const overlapArea = overlapWidth * overlapHeight;
|
|
1014
|
+
if (overlapArea > 0) {
|
|
1015
|
+
const selectionArea = Math.max(1, selection.width * selection.height);
|
|
1016
|
+
const rectArea = Math.max(1, rect.width * rect.height);
|
|
1017
|
+
return 1 + overlapArea / Math.min(selectionArea, rectArea);
|
|
1018
|
+
}
|
|
1019
|
+
const rectCenterX = rect.left + rect.width / 2;
|
|
1020
|
+
const rectCenterY = rect.top + rect.height / 2;
|
|
1021
|
+
const selectionCenterX = selection.left + selection.width / 2;
|
|
1022
|
+
const selectionCenterY = selection.top + selection.height / 2;
|
|
1023
|
+
const distance = Math.hypot(
|
|
1024
|
+
rectCenterX - selectionCenterX,
|
|
1025
|
+
rectCenterY - selectionCenterY
|
|
1026
|
+
);
|
|
1027
|
+
const basis = Math.max(
|
|
1028
|
+
1,
|
|
1029
|
+
rect.width,
|
|
1030
|
+
rect.height,
|
|
1031
|
+
selection.width,
|
|
1032
|
+
selection.height
|
|
1033
|
+
);
|
|
1034
|
+
return clamp(1 / (1 + distance / basis), 0.05, 0.95);
|
|
1035
|
+
}
|
|
835
1036
|
function getFingerprintTokens(value) {
|
|
836
1037
|
return value.toLowerCase().split(/[\s/|,.:;()[\]{}"'`~!?<>]+/).map((token) => token.trim()).filter((token) => token.length > 1);
|
|
837
1038
|
}
|
|
@@ -1292,6 +1493,19 @@ function createStyleElement() {
|
|
|
1292
1493
|
display: block;
|
|
1293
1494
|
}
|
|
1294
1495
|
|
|
1496
|
+
.dfwr-shell.has-dismissible-draft {
|
|
1497
|
+
z-index: 900;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
.dfwr-draft-cancel-layer {
|
|
1501
|
+
position: fixed;
|
|
1502
|
+
inset: 0;
|
|
1503
|
+
z-index: 2;
|
|
1504
|
+
pointer-events: auto;
|
|
1505
|
+
background: transparent;
|
|
1506
|
+
cursor: default;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1295
1509
|
.dfwr-panel {
|
|
1296
1510
|
position: fixed;
|
|
1297
1511
|
right: 16px;
|
|
@@ -1785,6 +1999,40 @@ function createStyleElement() {
|
|
|
1785
1999
|
box-shadow: var(--df-review-shadow-popover);
|
|
1786
2000
|
}
|
|
1787
2001
|
|
|
2002
|
+
.dfwr-note-popover.is-composer,
|
|
2003
|
+
.dfwr-area-draft.is-composer {
|
|
2004
|
+
max-height: min(360px, calc(100vh - 32px));
|
|
2005
|
+
overflow: auto;
|
|
2006
|
+
border-color: rgba(99, 215, 199, 0.56);
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
.dfwr-note-popover.is-dragging,
|
|
2010
|
+
.dfwr-area-draft.is-dragging {
|
|
2011
|
+
user-select: none;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
.dfwr-draft-drag-handle {
|
|
2015
|
+
display: block;
|
|
2016
|
+
width: 42px;
|
|
2017
|
+
height: 6px;
|
|
2018
|
+
margin: 0 auto 10px;
|
|
2019
|
+
padding: 0;
|
|
2020
|
+
cursor: grab;
|
|
2021
|
+
pointer-events: auto;
|
|
2022
|
+
background: rgba(247, 247, 242, 0.28);
|
|
2023
|
+
border: 0;
|
|
2024
|
+
border-radius: 999px;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
.dfwr-draft-drag-handle:hover,
|
|
2028
|
+
.dfwr-draft-drag-handle:focus-visible {
|
|
2029
|
+
background: rgba(215, 255, 95, 0.62);
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
.dfwr-draft-drag-handle:active {
|
|
2033
|
+
cursor: grabbing;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
1788
2036
|
.dfwr-area-draft {
|
|
1789
2037
|
position: fixed;
|
|
1790
2038
|
right: 16px;
|
|
@@ -1806,6 +2054,14 @@ function createStyleElement() {
|
|
|
1806
2054
|
padding: 0;
|
|
1807
2055
|
}
|
|
1808
2056
|
|
|
2057
|
+
.dfwr-note-actions {
|
|
2058
|
+
justify-content: flex-end;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
.dfwr-note-actions .dfwr-button:first-child {
|
|
2062
|
+
margin-right: auto;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
1809
2065
|
.dfwr-area-draft .dfwr-actions {
|
|
1810
2066
|
padding: 0;
|
|
1811
2067
|
}
|
|
@@ -1834,6 +2090,79 @@ function createStyleElement() {
|
|
|
1834
2090
|
outline-offset: 1px;
|
|
1835
2091
|
}
|
|
1836
2092
|
|
|
2093
|
+
.dfwr-adjust-panel {
|
|
2094
|
+
display: grid;
|
|
2095
|
+
gap: 4px;
|
|
2096
|
+
padding: 8px 10px;
|
|
2097
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2098
|
+
border-radius: var(--df-review-radius-sm);
|
|
2099
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
.dfwr-adjust-panel-header {
|
|
2103
|
+
display: flex;
|
|
2104
|
+
align-items: center;
|
|
2105
|
+
justify-content: space-between;
|
|
2106
|
+
gap: 10px;
|
|
2107
|
+
min-width: 0;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
.dfwr-adjust-panel-header .dfwr-adjust-help {
|
|
2111
|
+
flex: 1 1 auto;
|
|
2112
|
+
min-width: 0;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
.dfwr-adjust-panel.is-active {
|
|
2116
|
+
border-color: rgba(215, 255, 95, 0.5);
|
|
2117
|
+
background: var(--df-review-color-accent-soft);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
.dfwr-adjust-help,
|
|
2121
|
+
.dfwr-adjust-status {
|
|
2122
|
+
margin: 0;
|
|
2123
|
+
color: var(--df-review-color-text-muted);
|
|
2124
|
+
font-size: var(--df-review-font-size-xs);
|
|
2125
|
+
line-height: 1.35;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
.dfwr-adjust-status {
|
|
2129
|
+
color: var(--df-review-color-text);
|
|
2130
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
.dfwr-adjust-toggle {
|
|
2134
|
+
flex: 0 0 auto;
|
|
2135
|
+
display: inline-flex;
|
|
2136
|
+
align-items: center;
|
|
2137
|
+
justify-content: center;
|
|
2138
|
+
width: 34px;
|
|
2139
|
+
height: 30px;
|
|
2140
|
+
padding: 0;
|
|
2141
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
2142
|
+
border-radius: var(--df-review-radius-sm);
|
|
2143
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2144
|
+
color: var(--df-review-color-text);
|
|
2145
|
+
cursor: pointer;
|
|
2146
|
+
font: inherit;
|
|
2147
|
+
font-size: 14px;
|
|
2148
|
+
font-weight: 800;
|
|
2149
|
+
line-height: 1;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
.dfwr-adjust-toggle:hover,
|
|
2153
|
+
.dfwr-adjust-toggle:focus-visible,
|
|
2154
|
+
.dfwr-adjust-toggle.is-active {
|
|
2155
|
+
border-color: rgba(215, 255, 95, 0.68);
|
|
2156
|
+
background: var(--df-review-color-accent-soft);
|
|
2157
|
+
outline: none;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
.dfwr-adjust-toggle svg {
|
|
2161
|
+
width: 18px;
|
|
2162
|
+
height: 18px;
|
|
2163
|
+
pointer-events: none;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
1837
2166
|
.dfwr-empty,
|
|
1838
2167
|
.dfwr-error {
|
|
1839
2168
|
margin: 0;
|
|
@@ -2054,16 +2383,6 @@ function createStyleElement() {
|
|
|
2054
2383
|
}
|
|
2055
2384
|
|
|
2056
2385
|
// src/core/review/format.ts
|
|
2057
|
-
function formatAreaDraftMeta(draft) {
|
|
2058
|
-
const parts = [`viewport ${formatSize(draft.viewport)}`];
|
|
2059
|
-
if (draft.selection) {
|
|
2060
|
-
parts.push(`rect ${formatSelection(draft.selection.viewport)}`);
|
|
2061
|
-
}
|
|
2062
|
-
if (draft.marker) {
|
|
2063
|
-
parts.push(`point ${formatPoint(draft.marker.viewport)}`);
|
|
2064
|
-
}
|
|
2065
|
-
return parts.join(" / ");
|
|
2066
|
-
}
|
|
2067
2386
|
function formatNoteDraftMeta(draft) {
|
|
2068
2387
|
const parts = [
|
|
2069
2388
|
`viewport ${formatSize(draft.viewport)}`,
|
|
@@ -2129,17 +2448,29 @@ function formatAnchorMeta(anchor) {
|
|
|
2129
2448
|
}
|
|
2130
2449
|
|
|
2131
2450
|
// src/core/web.review.kit.view.ts
|
|
2451
|
+
var DEFAULT_ADJUSTMENT_LABEL = "Responsive CSS px adjustments";
|
|
2132
2452
|
var WebReviewKitView = class {
|
|
2133
2453
|
constructor(config) {
|
|
2134
2454
|
this.config = config;
|
|
2135
2455
|
}
|
|
2456
|
+
clearDraftPreview() {
|
|
2457
|
+
this.restoreDraftPreview();
|
|
2458
|
+
}
|
|
2136
2459
|
render(shadow, hiddenItemsStyle) {
|
|
2137
2460
|
const state = this.state;
|
|
2461
|
+
this.syncDraftPreview(
|
|
2462
|
+
state.isOpen && state.mode === "element" ? state.noteDraft : void 0
|
|
2463
|
+
);
|
|
2138
2464
|
shadow.replaceChildren();
|
|
2139
2465
|
shadow.append(createStyleElement());
|
|
2140
2466
|
shadow.append(hiddenItemsStyle);
|
|
2467
|
+
const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
|
|
2141
2468
|
const shell = document.createElement("div");
|
|
2142
|
-
shell.className =
|
|
2469
|
+
shell.className = [
|
|
2470
|
+
"dfwr-shell",
|
|
2471
|
+
state.isOpen ? "is-open" : "",
|
|
2472
|
+
hasDismissableDraft ? "has-dismissible-draft" : ""
|
|
2473
|
+
].filter(Boolean).join(" ");
|
|
2143
2474
|
shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
|
|
2144
2475
|
if (this.config.options.ui?.panel !== false) {
|
|
2145
2476
|
const panel = document.createElement("div");
|
|
@@ -2155,6 +2486,9 @@ var WebReviewKitView = class {
|
|
|
2155
2486
|
shell.append(panel);
|
|
2156
2487
|
}
|
|
2157
2488
|
shell.append(this.createMarkerLayer());
|
|
2489
|
+
if (state.isOpen && hasDismissableDraft) {
|
|
2490
|
+
shell.append(this.createDraftCancelLayer());
|
|
2491
|
+
}
|
|
2158
2492
|
if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
|
|
2159
2493
|
shell.append(
|
|
2160
2494
|
state.noteDraft ? this.createNotePopover(state.noteDraft) : state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
|
|
@@ -2174,6 +2508,332 @@ var WebReviewKitView = class {
|
|
|
2174
2508
|
get state() {
|
|
2175
2509
|
return this.config.getState();
|
|
2176
2510
|
}
|
|
2511
|
+
createDraftCancelLayer() {
|
|
2512
|
+
const layer = document.createElement("div");
|
|
2513
|
+
layer.className = "dfwr-draft-cancel-layer";
|
|
2514
|
+
layer.setAttribute("aria-hidden", "true");
|
|
2515
|
+
const cancel = (event) => {
|
|
2516
|
+
event.preventDefault();
|
|
2517
|
+
event.stopPropagation();
|
|
2518
|
+
event.stopImmediatePropagation();
|
|
2519
|
+
this.config.actions.setModeState("idle");
|
|
2520
|
+
this.config.actions.clearDrafts();
|
|
2521
|
+
this.config.actions.setSelectingArea(false);
|
|
2522
|
+
this.config.actions.render();
|
|
2523
|
+
};
|
|
2524
|
+
layer.addEventListener("pointerdown", (event) => {
|
|
2525
|
+
if (event.button !== 0) return;
|
|
2526
|
+
cancel(event);
|
|
2527
|
+
});
|
|
2528
|
+
return layer;
|
|
2529
|
+
}
|
|
2530
|
+
getDraftAdjustmentMetrics(draft) {
|
|
2531
|
+
const adjustment = draft.adjustment;
|
|
2532
|
+
const x = adjustment?.x ?? 0;
|
|
2533
|
+
const y = adjustment?.y ?? 0;
|
|
2534
|
+
const scale = adjustment?.scale ?? 0;
|
|
2535
|
+
const {
|
|
2536
|
+
scale: viewportScale,
|
|
2537
|
+
designWidth,
|
|
2538
|
+
presetLabel
|
|
2539
|
+
} = this.getDraftViewportScale(draft.viewport);
|
|
2540
|
+
const selection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2541
|
+
const scaleCssDelta = scale * viewportScale;
|
|
2542
|
+
const scaleFactor = selection && selection.width > 0 ? Math.max(
|
|
2543
|
+
1 / selection.width,
|
|
2544
|
+
(selection.width + scaleCssDelta) / selection.width
|
|
2545
|
+
) : 1;
|
|
2546
|
+
return {
|
|
2547
|
+
x,
|
|
2548
|
+
y,
|
|
2549
|
+
scale,
|
|
2550
|
+
cssX: x * viewportScale,
|
|
2551
|
+
cssY: y * viewportScale,
|
|
2552
|
+
scaleFactor,
|
|
2553
|
+
viewportScale,
|
|
2554
|
+
designWidth,
|
|
2555
|
+
presetLabel,
|
|
2556
|
+
viewportWidth: draft.viewport.width
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
hasDraftAdjustment(draft) {
|
|
2560
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2561
|
+
return metrics.x !== 0 || metrics.y !== 0 || metrics.scale !== 0;
|
|
2562
|
+
}
|
|
2563
|
+
getAdjustedDraftPoint(point, draft) {
|
|
2564
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2565
|
+
return {
|
|
2566
|
+
x: point.x + metrics.cssX,
|
|
2567
|
+
y: point.y + metrics.cssY
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
getAdjustedDraftSelection(selection, draft) {
|
|
2571
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2572
|
+
return {
|
|
2573
|
+
...selection,
|
|
2574
|
+
left: selection.left + metrics.cssX,
|
|
2575
|
+
top: selection.top + metrics.cssY,
|
|
2576
|
+
width: selection.width * metrics.scaleFactor,
|
|
2577
|
+
height: selection.height * metrics.scaleFactor
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
getDraftViewportScale(viewport) {
|
|
2581
|
+
const preset = findReviewViewportPreset(
|
|
2582
|
+
viewport,
|
|
2583
|
+
this.config.options.viewports?.presets
|
|
2584
|
+
);
|
|
2585
|
+
const designWidth = typeof preset.designWidth === "number" && preset.designWidth > 0 ? preset.designWidth : viewport.width;
|
|
2586
|
+
const scale = designWidth > 0 ? viewport.width / designWidth : 1;
|
|
2587
|
+
return { scale, designWidth, presetLabel: preset.label };
|
|
2588
|
+
}
|
|
2589
|
+
getDraftComposerWidth(environment) {
|
|
2590
|
+
const bounds = environment.overlayRect;
|
|
2591
|
+
const margin = 12;
|
|
2592
|
+
return Math.min(360, Math.max(240, bounds.width - margin * 2));
|
|
2593
|
+
}
|
|
2594
|
+
getClampedComposerPosition(position, environment, size, bounds = environment.overlayRect) {
|
|
2595
|
+
const margin = 12;
|
|
2596
|
+
const width = size?.width ?? this.getDraftComposerWidth(environment);
|
|
2597
|
+
const height = size?.height ?? 236;
|
|
2598
|
+
return {
|
|
2599
|
+
x: clamp(
|
|
2600
|
+
position.x,
|
|
2601
|
+
bounds.left + margin,
|
|
2602
|
+
bounds.left + bounds.width - width - margin
|
|
2603
|
+
),
|
|
2604
|
+
y: clamp(
|
|
2605
|
+
position.y,
|
|
2606
|
+
bounds.top + margin,
|
|
2607
|
+
bounds.top + bounds.height - height - margin
|
|
2608
|
+
)
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
getHostComposerBounds() {
|
|
2612
|
+
const root = document.documentElement;
|
|
2613
|
+
return {
|
|
2614
|
+
left: 0,
|
|
2615
|
+
top: 0,
|
|
2616
|
+
width: root.clientWidth || window.innerWidth,
|
|
2617
|
+
height: root.clientHeight || window.innerHeight
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
getInitialDraftComposerPosition(selection, environment, size) {
|
|
2621
|
+
const bounds = this.getHostComposerBounds();
|
|
2622
|
+
const margin = 12;
|
|
2623
|
+
const gap = 20;
|
|
2624
|
+
if (!selection) {
|
|
2625
|
+
return this.getClampedComposerPosition(
|
|
2626
|
+
{
|
|
2627
|
+
x: environment.overlayRect.left + margin,
|
|
2628
|
+
y: environment.overlayRect.top + margin
|
|
2629
|
+
},
|
|
2630
|
+
environment,
|
|
2631
|
+
size,
|
|
2632
|
+
bounds
|
|
2633
|
+
);
|
|
2634
|
+
}
|
|
2635
|
+
const preferredX = selection.left + selection.width + gap;
|
|
2636
|
+
const maxX = bounds.left + bounds.width - size.width - margin;
|
|
2637
|
+
const x = preferredX <= maxX ? preferredX : selection.left - size.width - gap;
|
|
2638
|
+
return this.getClampedComposerPosition(
|
|
2639
|
+
{
|
|
2640
|
+
x,
|
|
2641
|
+
y: selection.top
|
|
2642
|
+
},
|
|
2643
|
+
environment,
|
|
2644
|
+
size,
|
|
2645
|
+
bounds
|
|
2646
|
+
);
|
|
2647
|
+
}
|
|
2648
|
+
getDraftComposerPosition({
|
|
2649
|
+
selection,
|
|
2650
|
+
environment,
|
|
2651
|
+
composerPosition,
|
|
2652
|
+
estimatedHeight
|
|
2653
|
+
}) {
|
|
2654
|
+
const width = this.getDraftComposerWidth(environment);
|
|
2655
|
+
if (composerPosition) {
|
|
2656
|
+
const clamped = this.getClampedComposerPosition(
|
|
2657
|
+
composerPosition,
|
|
2658
|
+
environment,
|
|
2659
|
+
{ width, height: estimatedHeight },
|
|
2660
|
+
this.getHostComposerBounds()
|
|
2661
|
+
);
|
|
2662
|
+
return { width, left: clamped.x, top: clamped.y };
|
|
2663
|
+
}
|
|
2664
|
+
const position = this.getInitialDraftComposerPosition(selection, environment, {
|
|
2665
|
+
width,
|
|
2666
|
+
height: estimatedHeight
|
|
2667
|
+
});
|
|
2668
|
+
return { width, left: position.x, top: position.y };
|
|
2669
|
+
}
|
|
2670
|
+
getSelectionMqMetrics(selection, viewport) {
|
|
2671
|
+
const { scale } = this.getDraftViewportScale(viewport);
|
|
2672
|
+
const ratio = scale > 0 ? 1 / scale : 1;
|
|
2673
|
+
return {
|
|
2674
|
+
x: selection.left * ratio,
|
|
2675
|
+
y: selection.top * ratio,
|
|
2676
|
+
width: selection.width * ratio,
|
|
2677
|
+
height: selection.height * ratio
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2680
|
+
formatSignedPx(value) {
|
|
2681
|
+
if (value === 0) return "+0px";
|
|
2682
|
+
return `${value > 0 ? "+" : ""}${value}px`;
|
|
2683
|
+
}
|
|
2684
|
+
formatRoundedPx(value) {
|
|
2685
|
+
return `${Math.round(value)}px`;
|
|
2686
|
+
}
|
|
2687
|
+
getAdjustmentLabel() {
|
|
2688
|
+
return this.config.options.adjustmentLabel?.trim() || DEFAULT_ADJUSTMENT_LABEL;
|
|
2689
|
+
}
|
|
2690
|
+
getSelectionMetricLines(selection, viewport) {
|
|
2691
|
+
if (!selection) return ["area", "x none / y none", "w none / h none"];
|
|
2692
|
+
const metrics = this.getSelectionMqMetrics(selection, viewport);
|
|
2693
|
+
return [
|
|
2694
|
+
"area",
|
|
2695
|
+
`x ${this.formatRoundedPx(metrics.x)} / y ${this.formatRoundedPx(
|
|
2696
|
+
metrics.y
|
|
2697
|
+
)}`,
|
|
2698
|
+
`w ${this.formatRoundedPx(metrics.width)} / h ${this.formatRoundedPx(
|
|
2699
|
+
metrics.height
|
|
2700
|
+
)}`
|
|
2701
|
+
];
|
|
2702
|
+
}
|
|
2703
|
+
getAreaDraftMetricSelection(draft) {
|
|
2704
|
+
if (!draft.selection) return void 0;
|
|
2705
|
+
return toViewportSelection(draft.selection.viewport);
|
|
2706
|
+
}
|
|
2707
|
+
getDraftAdjustmentMetricLines(draft) {
|
|
2708
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2709
|
+
return [
|
|
2710
|
+
`x ${this.formatSignedPx(metrics.x)} / y ${this.formatSignedPx(
|
|
2711
|
+
metrics.y
|
|
2712
|
+
)}`,
|
|
2713
|
+
`scale ${this.formatSignedPx(metrics.scale)}`
|
|
2714
|
+
];
|
|
2715
|
+
}
|
|
2716
|
+
withDraftAdjustmentComment(comment, draft) {
|
|
2717
|
+
if (!this.hasDraftAdjustment(draft)) return comment;
|
|
2718
|
+
const trimmedComment = comment.trim();
|
|
2719
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2720
|
+
const adjustment = [
|
|
2721
|
+
`${this.getAdjustmentLabel()}: x ${this.formatSignedPx(
|
|
2722
|
+
metrics.x
|
|
2723
|
+
)}, y ${this.formatSignedPx(metrics.y)}, scale ${this.formatSignedPx(
|
|
2724
|
+
metrics.scale
|
|
2725
|
+
)}`,
|
|
2726
|
+
`(${metrics.presetLabel} viewport, ${Math.round(
|
|
2727
|
+
metrics.viewportWidth
|
|
2728
|
+
)}/design ${Math.round(metrics.designWidth)})`
|
|
2729
|
+
].join(" ");
|
|
2730
|
+
return trimmedComment ? `${trimmedComment}
|
|
2731
|
+
${adjustment}` : adjustment;
|
|
2732
|
+
}
|
|
2733
|
+
getStyleableDraftElement(draft, environment) {
|
|
2734
|
+
if (draft.previewElement && draft.previewElement.ownerDocument === environment.document && "style" in draft.previewElement) {
|
|
2735
|
+
return draft.previewElement;
|
|
2736
|
+
}
|
|
2737
|
+
if (!draft.anchor) return void 0;
|
|
2738
|
+
const preferredSelection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2739
|
+
const element = resolveAnchorElement(
|
|
2740
|
+
draft.anchor,
|
|
2741
|
+
environment,
|
|
2742
|
+
preferredSelection
|
|
2743
|
+
)?.element;
|
|
2744
|
+
if (!element) return void 0;
|
|
2745
|
+
if ("style" in element) return element;
|
|
2746
|
+
return void 0;
|
|
2747
|
+
}
|
|
2748
|
+
syncDraftPreview(draft) {
|
|
2749
|
+
const environment = this.config.getEnvironment();
|
|
2750
|
+
if (!draft || !environment || !this.hasDraftAdjustment(draft)) {
|
|
2751
|
+
this.restoreDraftPreview();
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const element = this.getStyleableDraftElement(draft, environment);
|
|
2755
|
+
if (!element) {
|
|
2756
|
+
this.restoreDraftPreview();
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
if (this.draftPreview?.element !== element) {
|
|
2760
|
+
this.restoreDraftPreview();
|
|
2761
|
+
}
|
|
2762
|
+
if (!this.draftPreview) {
|
|
2763
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2764
|
+
const clone = element.cloneNode(true);
|
|
2765
|
+
this.removeDuplicateIds(clone);
|
|
2766
|
+
this.copyComputedStyle(element, clone, environment);
|
|
2767
|
+
this.positionDraftPreviewClone(clone, element, computedStyle);
|
|
2768
|
+
environment.document.body?.appendChild(clone);
|
|
2769
|
+
this.draftPreview = {
|
|
2770
|
+
element,
|
|
2771
|
+
clone,
|
|
2772
|
+
visibility: element.style.visibility
|
|
2773
|
+
};
|
|
2774
|
+
element.style.visibility = "hidden";
|
|
2775
|
+
}
|
|
2776
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2777
|
+
const translate = `translate(${this.toCssNumber(metrics.cssX)}px, ${this.toCssNumber(
|
|
2778
|
+
metrics.cssY
|
|
2779
|
+
)}px)`;
|
|
2780
|
+
const scale = metrics.scaleFactor === 1 ? "" : `scale(${this.toCssNumber(metrics.scaleFactor)})`;
|
|
2781
|
+
this.draftPreview.clone.style.transform = [translate, scale].filter(Boolean).join(" ");
|
|
2782
|
+
}
|
|
2783
|
+
restoreDraftPreview() {
|
|
2784
|
+
if (!this.draftPreview) return;
|
|
2785
|
+
const { element, clone, visibility } = this.draftPreview;
|
|
2786
|
+
clone.remove();
|
|
2787
|
+
element.style.visibility = visibility;
|
|
2788
|
+
this.draftPreview = void 0;
|
|
2789
|
+
}
|
|
2790
|
+
positionDraftPreviewClone(clone, element, computedStyle) {
|
|
2791
|
+
const rect = element.getBoundingClientRect();
|
|
2792
|
+
clone.setAttribute("data-dfwr-adjust-preview", "true");
|
|
2793
|
+
clone.setAttribute("aria-hidden", "true");
|
|
2794
|
+
clone.style.position = "fixed";
|
|
2795
|
+
clone.style.left = `${this.toCssNumber(rect.left)}px`;
|
|
2796
|
+
clone.style.top = `${this.toCssNumber(rect.top)}px`;
|
|
2797
|
+
clone.style.right = "auto";
|
|
2798
|
+
clone.style.bottom = "auto";
|
|
2799
|
+
clone.style.width = `${this.toCssNumber(rect.width)}px`;
|
|
2800
|
+
clone.style.height = `${this.toCssNumber(rect.height)}px`;
|
|
2801
|
+
clone.style.maxWidth = "none";
|
|
2802
|
+
clone.style.maxHeight = "none";
|
|
2803
|
+
clone.style.margin = "0";
|
|
2804
|
+
clone.style.boxSizing = "border-box";
|
|
2805
|
+
clone.style.display = this.getDraftPreviewDisplay(computedStyle.display);
|
|
2806
|
+
clone.style.zIndex = "2147483646";
|
|
2807
|
+
clone.style.pointerEvents = "none";
|
|
2808
|
+
clone.style.transition = "none";
|
|
2809
|
+
clone.style.willChange = "transform";
|
|
2810
|
+
clone.style.transformOrigin = "top left";
|
|
2811
|
+
clone.style.transform = "none";
|
|
2812
|
+
}
|
|
2813
|
+
getDraftPreviewDisplay(display) {
|
|
2814
|
+
if (display === "inline" || display === "contents") return "inline-block";
|
|
2815
|
+
return display || "block";
|
|
2816
|
+
}
|
|
2817
|
+
copyComputedStyle(element, clone, environment) {
|
|
2818
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2819
|
+
for (let index = 0; index < computedStyle.length; index += 1) {
|
|
2820
|
+
const property = computedStyle.item(index);
|
|
2821
|
+
clone.style.setProperty(
|
|
2822
|
+
property,
|
|
2823
|
+
computedStyle.getPropertyValue(property),
|
|
2824
|
+
computedStyle.getPropertyPriority(property)
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
removeDuplicateIds(element) {
|
|
2829
|
+
element.removeAttribute("id");
|
|
2830
|
+
element.querySelectorAll("[id]").forEach((child) => {
|
|
2831
|
+
child.removeAttribute("id");
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2834
|
+
toCssNumber(value) {
|
|
2835
|
+
return Math.round(value * 1e3) / 1e3;
|
|
2836
|
+
}
|
|
2177
2837
|
createHeader() {
|
|
2178
2838
|
const header = document.createElement("div");
|
|
2179
2839
|
header.className = "dfwr-header";
|
|
@@ -2265,15 +2925,20 @@ var WebReviewKitView = class {
|
|
|
2265
2925
|
const group = document.createElement("div");
|
|
2266
2926
|
group.className = "dfwr-note-draft";
|
|
2267
2927
|
if (!environment) return group;
|
|
2268
|
-
const
|
|
2928
|
+
const isElementDraft = this.state.mode === "element" && Boolean(draft.selection);
|
|
2929
|
+
const hostPoint = toHostPoint(
|
|
2930
|
+
isElementDraft ? this.getAdjustedDraftPoint(draft.marker.viewport, draft) : draft.marker.viewport,
|
|
2931
|
+
environment
|
|
2932
|
+
);
|
|
2933
|
+
let selectionHighlight;
|
|
2269
2934
|
if (draft.selection) {
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
)
|
|
2935
|
+
const selection = toViewportSelection(draft.selection.viewport);
|
|
2936
|
+
selectionHighlight = this.createSelectionHighlight(
|
|
2937
|
+
isElementDraft ? this.getAdjustedDraftSelection(selection, draft) : selection,
|
|
2938
|
+
environment,
|
|
2939
|
+
true
|
|
2276
2940
|
);
|
|
2941
|
+
group.append(selectionHighlight);
|
|
2277
2942
|
}
|
|
2278
2943
|
const pin = document.createElement("button");
|
|
2279
2944
|
pin.className = "dfwr-note-pin";
|
|
@@ -2283,14 +2948,35 @@ var WebReviewKitView = class {
|
|
|
2283
2948
|
pin.style.top = `${hostPoint.y}px`;
|
|
2284
2949
|
const popover = document.createElement("div");
|
|
2285
2950
|
const position = getPopoverPosition(hostPoint, environment);
|
|
2286
|
-
popover.className =
|
|
2287
|
-
|
|
2288
|
-
|
|
2951
|
+
popover.className = `dfwr-note-popover${isElementDraft ? " is-composer" : ""}`;
|
|
2952
|
+
if (isElementDraft) {
|
|
2953
|
+
const selection = draft.selection ? toHostSelection(
|
|
2954
|
+
this.getAdjustedDraftSelection(
|
|
2955
|
+
toViewportSelection(draft.selection.viewport),
|
|
2956
|
+
draft
|
|
2957
|
+
),
|
|
2958
|
+
environment
|
|
2959
|
+
) : void 0;
|
|
2960
|
+
const composer = this.getDraftComposerPosition({
|
|
2961
|
+
selection,
|
|
2962
|
+
environment,
|
|
2963
|
+
composerPosition: draft.composerPosition,
|
|
2964
|
+
estimatedHeight: 252
|
|
2965
|
+
});
|
|
2966
|
+
popover.style.left = `${composer.left}px`;
|
|
2967
|
+
popover.style.top = `${composer.top}px`;
|
|
2968
|
+
popover.style.width = `${composer.width}px`;
|
|
2969
|
+
} else {
|
|
2970
|
+
popover.style.left = `${position.left}px`;
|
|
2971
|
+
popover.style.top = `${position.top}px`;
|
|
2972
|
+
}
|
|
2289
2973
|
const form = document.createElement("form");
|
|
2290
2974
|
form.className = "dfwr-form";
|
|
2291
|
-
const meta = document.createElement("div");
|
|
2292
|
-
meta
|
|
2293
|
-
|
|
2975
|
+
const meta = isElementDraft ? void 0 : document.createElement("div");
|
|
2976
|
+
if (meta) {
|
|
2977
|
+
meta.className = "dfwr-item-date";
|
|
2978
|
+
meta.textContent = formatNoteDraftMeta(draft);
|
|
2979
|
+
}
|
|
2294
2980
|
const textarea = document.createElement("textarea");
|
|
2295
2981
|
textarea.className = "dfwr-textarea";
|
|
2296
2982
|
textarea.placeholder = "Review comment";
|
|
@@ -2304,25 +2990,273 @@ var WebReviewKitView = class {
|
|
|
2304
2990
|
comment: textarea.value
|
|
2305
2991
|
});
|
|
2306
2992
|
});
|
|
2307
|
-
const
|
|
2993
|
+
const saveDraft = () => {
|
|
2308
2994
|
const comment = textarea.value.trim();
|
|
2309
|
-
|
|
2995
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2996
|
+
if (!comment && !this.hasDraftAdjustment(currentDraft)) return;
|
|
2310
2997
|
void this.config.actions.createItem({
|
|
2311
2998
|
kind: "note",
|
|
2312
|
-
comment,
|
|
2313
|
-
viewport:
|
|
2314
|
-
anchor:
|
|
2315
|
-
marker:
|
|
2316
|
-
selection:
|
|
2999
|
+
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
3000
|
+
viewport: currentDraft.viewport,
|
|
3001
|
+
anchor: currentDraft.anchor,
|
|
3002
|
+
marker: currentDraft.marker,
|
|
3003
|
+
selection: currentDraft.selection
|
|
2317
3004
|
});
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
|
|
3005
|
+
};
|
|
3006
|
+
const adjustmentControls = isElementDraft ? this.createAdjustmentControls({
|
|
3007
|
+
draft,
|
|
3008
|
+
pin,
|
|
3009
|
+
popover,
|
|
3010
|
+
selectionHighlight,
|
|
3011
|
+
textarea
|
|
3012
|
+
}) : void 0;
|
|
3013
|
+
const actions = this.createFormActions("Save note", saveDraft);
|
|
3014
|
+
form.append(
|
|
3015
|
+
...meta ? [meta] : [],
|
|
3016
|
+
...adjustmentControls ? [adjustmentControls.panel] : [],
|
|
3017
|
+
textarea,
|
|
3018
|
+
actions
|
|
3019
|
+
);
|
|
3020
|
+
const dragHandle = isElementDraft ? this.createDraftDragHandle("Move DOM composer") : void 0;
|
|
3021
|
+
popover.append(...dragHandle ? [dragHandle] : [], form);
|
|
2321
3022
|
group.append(pin, popover);
|
|
2322
|
-
|
|
2323
|
-
|
|
3023
|
+
if (dragHandle) {
|
|
3024
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
3025
|
+
const noteDraft = this.state.noteDraft ?? draft;
|
|
3026
|
+
this.config.actions.setNoteDraft({
|
|
3027
|
+
...noteDraft,
|
|
3028
|
+
composerPosition,
|
|
3029
|
+
comment: textarea.value
|
|
3030
|
+
});
|
|
3031
|
+
});
|
|
3032
|
+
}
|
|
3033
|
+
this.attachDraftPinDrag(
|
|
3034
|
+
pin,
|
|
3035
|
+
isElementDraft ? void 0 : popover,
|
|
3036
|
+
meta,
|
|
3037
|
+
textarea
|
|
3038
|
+
);
|
|
3039
|
+
window.setTimeout(() => {
|
|
3040
|
+
if (draft.adjustment?.isActive) {
|
|
3041
|
+
adjustmentControls?.focusTarget.focus();
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
textarea.focus();
|
|
3045
|
+
}, 0);
|
|
2324
3046
|
return group;
|
|
2325
3047
|
}
|
|
3048
|
+
createDraftDragHandle(label) {
|
|
3049
|
+
const handle = document.createElement("button");
|
|
3050
|
+
handle.className = "dfwr-draft-drag-handle";
|
|
3051
|
+
handle.type = "button";
|
|
3052
|
+
handle.setAttribute("aria-label", label);
|
|
3053
|
+
return handle;
|
|
3054
|
+
}
|
|
3055
|
+
createIcon(paths) {
|
|
3056
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3057
|
+
svg.setAttribute("aria-hidden", "true");
|
|
3058
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
3059
|
+
svg.setAttribute("fill", "none");
|
|
3060
|
+
svg.setAttribute("stroke", "currentColor");
|
|
3061
|
+
svg.setAttribute("stroke-width", "2.4");
|
|
3062
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
3063
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
3064
|
+
paths.forEach((d) => {
|
|
3065
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3066
|
+
path.setAttribute("d", d);
|
|
3067
|
+
svg.append(path);
|
|
3068
|
+
});
|
|
3069
|
+
return svg;
|
|
3070
|
+
}
|
|
3071
|
+
setAdjustmentToggleIcon(button, isActive) {
|
|
3072
|
+
const paths = isActive ? ["M20 6 9 17l-5-5"] : [
|
|
3073
|
+
"M12 2v20",
|
|
3074
|
+
"M2 12h20",
|
|
3075
|
+
"m9 5 3-3 3 3",
|
|
3076
|
+
"m9 19 3 3 3-3",
|
|
3077
|
+
"m5 9-3 3 3 3",
|
|
3078
|
+
"m19 9 3 3-3 3"
|
|
3079
|
+
];
|
|
3080
|
+
button.replaceChildren(this.createIcon(paths));
|
|
3081
|
+
}
|
|
3082
|
+
attachDraftComposerDrag(popover, handle, onMove) {
|
|
3083
|
+
let isDragging = false;
|
|
3084
|
+
let offsetX = 0;
|
|
3085
|
+
let offsetY = 0;
|
|
3086
|
+
const movePopover = (event) => {
|
|
3087
|
+
const environment = this.config.getEnvironment();
|
|
3088
|
+
if (!environment) return;
|
|
3089
|
+
const position = this.getClampedComposerPosition(
|
|
3090
|
+
{
|
|
3091
|
+
x: event.clientX - offsetX,
|
|
3092
|
+
y: event.clientY - offsetY
|
|
3093
|
+
},
|
|
3094
|
+
environment,
|
|
3095
|
+
{
|
|
3096
|
+
width: popover.offsetWidth,
|
|
3097
|
+
height: popover.offsetHeight
|
|
3098
|
+
},
|
|
3099
|
+
this.getHostComposerBounds()
|
|
3100
|
+
);
|
|
3101
|
+
popover.style.left = `${position.x}px`;
|
|
3102
|
+
popover.style.top = `${position.y}px`;
|
|
3103
|
+
onMove(position);
|
|
3104
|
+
};
|
|
3105
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
3106
|
+
if (event.button !== 0) return;
|
|
3107
|
+
const rect = popover.getBoundingClientRect();
|
|
3108
|
+
offsetX = event.clientX - rect.left;
|
|
3109
|
+
offsetY = event.clientY - rect.top;
|
|
3110
|
+
isDragging = true;
|
|
3111
|
+
event.preventDefault();
|
|
3112
|
+
event.stopPropagation();
|
|
3113
|
+
handle.setPointerCapture(event.pointerId);
|
|
3114
|
+
popover.classList.add("is-dragging");
|
|
3115
|
+
});
|
|
3116
|
+
handle.addEventListener("pointermove", (event) => {
|
|
3117
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
3118
|
+
event.preventDefault();
|
|
3119
|
+
movePopover(event);
|
|
3120
|
+
});
|
|
3121
|
+
const stopDrag = (event) => {
|
|
3122
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
3123
|
+
event.preventDefault();
|
|
3124
|
+
event.stopPropagation();
|
|
3125
|
+
isDragging = false;
|
|
3126
|
+
handle.releasePointerCapture(event.pointerId);
|
|
3127
|
+
popover.classList.remove("is-dragging");
|
|
3128
|
+
movePopover(event);
|
|
3129
|
+
};
|
|
3130
|
+
handle.addEventListener("pointerup", stopDrag);
|
|
3131
|
+
handle.addEventListener("pointercancel", stopDrag);
|
|
3132
|
+
}
|
|
3133
|
+
createAdjustmentControls({
|
|
3134
|
+
draft,
|
|
3135
|
+
pin,
|
|
3136
|
+
popover,
|
|
3137
|
+
selectionHighlight,
|
|
3138
|
+
textarea
|
|
3139
|
+
}) {
|
|
3140
|
+
const panel = document.createElement("div");
|
|
3141
|
+
panel.className = "dfwr-adjust-panel is-dom-adjust-panel";
|
|
3142
|
+
const header = document.createElement("div");
|
|
3143
|
+
header.className = "dfwr-adjust-panel-header";
|
|
3144
|
+
const help = document.createElement("div");
|
|
3145
|
+
help.className = "dfwr-adjust-help";
|
|
3146
|
+
help.textContent = this.getAdjustmentLabel();
|
|
3147
|
+
const adjust = document.createElement("button");
|
|
3148
|
+
adjust.className = "dfwr-adjust-toggle";
|
|
3149
|
+
adjust.type = "button";
|
|
3150
|
+
adjust.title = "Adjust DOM element with keyboard arrows";
|
|
3151
|
+
adjust.setAttribute("aria-label", "Adjust DOM element with keyboard arrows");
|
|
3152
|
+
const xyStatus = document.createElement("div");
|
|
3153
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
3154
|
+
const scaleStatus = document.createElement("div");
|
|
3155
|
+
scaleStatus.className = "dfwr-adjust-status";
|
|
3156
|
+
const syncControls = (nextDraft) => {
|
|
3157
|
+
const isActive = nextDraft.adjustment?.isActive === true;
|
|
3158
|
+
panel.classList.toggle("is-active", isActive);
|
|
3159
|
+
adjust.classList.toggle("is-active", isActive);
|
|
3160
|
+
adjust.setAttribute("aria-pressed", isActive ? "true" : "false");
|
|
3161
|
+
this.setAdjustmentToggleIcon(adjust, isActive);
|
|
3162
|
+
adjust.title = isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows";
|
|
3163
|
+
adjust.setAttribute(
|
|
3164
|
+
"aria-label",
|
|
3165
|
+
isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows"
|
|
3166
|
+
);
|
|
3167
|
+
const [xyLine, scaleLine] = this.getDraftAdjustmentMetricLines(nextDraft);
|
|
3168
|
+
xyStatus.textContent = xyLine;
|
|
3169
|
+
scaleStatus.textContent = scaleLine;
|
|
3170
|
+
this.syncDraftAdjustmentUi({
|
|
3171
|
+
draft: nextDraft,
|
|
3172
|
+
pin,
|
|
3173
|
+
selectionHighlight
|
|
3174
|
+
});
|
|
3175
|
+
};
|
|
3176
|
+
const updateDraft = (updater) => {
|
|
3177
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
3178
|
+
const nextDraft = updater(currentDraft);
|
|
3179
|
+
this.config.actions.setNoteDraft({
|
|
3180
|
+
...nextDraft,
|
|
3181
|
+
comment: textarea.value
|
|
3182
|
+
});
|
|
3183
|
+
syncControls(nextDraft);
|
|
3184
|
+
};
|
|
3185
|
+
adjust.addEventListener("click", () => {
|
|
3186
|
+
updateDraft((currentDraft) => ({
|
|
3187
|
+
...currentDraft,
|
|
3188
|
+
adjustment: {
|
|
3189
|
+
x: currentDraft.adjustment?.x ?? 0,
|
|
3190
|
+
y: currentDraft.adjustment?.y ?? 0,
|
|
3191
|
+
scale: currentDraft.adjustment?.scale ?? 0,
|
|
3192
|
+
isActive: currentDraft.adjustment?.isActive !== true
|
|
3193
|
+
}
|
|
3194
|
+
}));
|
|
3195
|
+
adjust.focus();
|
|
3196
|
+
});
|
|
3197
|
+
popover.addEventListener("keydown", (event) => {
|
|
3198
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
3199
|
+
if (currentDraft.adjustment?.isActive !== true) return;
|
|
3200
|
+
const keyDelta = this.getAdjustmentKeyDelta(event);
|
|
3201
|
+
if (!keyDelta) return;
|
|
3202
|
+
event.preventDefault();
|
|
3203
|
+
event.stopPropagation();
|
|
3204
|
+
updateDraft((activeDraft) => ({
|
|
3205
|
+
...activeDraft,
|
|
3206
|
+
adjustment: {
|
|
3207
|
+
x: (activeDraft.adjustment?.x ?? 0) + keyDelta.x,
|
|
3208
|
+
y: (activeDraft.adjustment?.y ?? 0) + keyDelta.y,
|
|
3209
|
+
scale: (activeDraft.adjustment?.scale ?? 0) + keyDelta.scale,
|
|
3210
|
+
isActive: true
|
|
3211
|
+
}
|
|
3212
|
+
}));
|
|
3213
|
+
});
|
|
3214
|
+
header.append(help, adjust);
|
|
3215
|
+
panel.append(header, xyStatus, scaleStatus);
|
|
3216
|
+
syncControls(draft);
|
|
3217
|
+
return {
|
|
3218
|
+
panel,
|
|
3219
|
+
focusTarget: adjust
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
getAdjustmentKeyDelta(event) {
|
|
3223
|
+
const step = event.shiftKey ? 10 : 1;
|
|
3224
|
+
if (event.key === "ArrowLeft") return { x: -step, y: 0, scale: 0 };
|
|
3225
|
+
if (event.key === "ArrowRight") return { x: step, y: 0, scale: 0 };
|
|
3226
|
+
if (event.key === "ArrowUp") return { x: 0, y: -step, scale: 0 };
|
|
3227
|
+
if (event.key === "ArrowDown") return { x: 0, y: step, scale: 0 };
|
|
3228
|
+
if (event.key.toLowerCase() === "w") return { x: 0, y: 0, scale: step };
|
|
3229
|
+
if (event.key.toLowerCase() === "s") return { x: 0, y: 0, scale: -step };
|
|
3230
|
+
return void 0;
|
|
3231
|
+
}
|
|
3232
|
+
syncDraftAdjustmentUi({
|
|
3233
|
+
draft,
|
|
3234
|
+
pin,
|
|
3235
|
+
selectionHighlight
|
|
3236
|
+
}) {
|
|
3237
|
+
const environment = this.config.getEnvironment();
|
|
3238
|
+
if (!environment) return;
|
|
3239
|
+
const hostPoint = toHostPoint(
|
|
3240
|
+
this.getAdjustedDraftPoint(draft.marker.viewport, draft),
|
|
3241
|
+
environment
|
|
3242
|
+
);
|
|
3243
|
+
pin.style.left = `${hostPoint.x}px`;
|
|
3244
|
+
pin.style.top = `${hostPoint.y}px`;
|
|
3245
|
+
if (draft.selection && selectionHighlight) {
|
|
3246
|
+
const rect = toHostSelection(
|
|
3247
|
+
this.getAdjustedDraftSelection(
|
|
3248
|
+
toViewportSelection(draft.selection.viewport),
|
|
3249
|
+
draft
|
|
3250
|
+
),
|
|
3251
|
+
environment
|
|
3252
|
+
);
|
|
3253
|
+
selectionHighlight.style.left = `${rect.left}px`;
|
|
3254
|
+
selectionHighlight.style.top = `${rect.top}px`;
|
|
3255
|
+
selectionHighlight.style.width = `${rect.width}px`;
|
|
3256
|
+
selectionHighlight.style.height = `${rect.height}px`;
|
|
3257
|
+
}
|
|
3258
|
+
this.syncDraftPreview(draft);
|
|
3259
|
+
}
|
|
2326
3260
|
createAreaForm() {
|
|
2327
3261
|
const form = document.createElement("form");
|
|
2328
3262
|
form.className = "dfwr-form";
|
|
@@ -2334,14 +3268,20 @@ var WebReviewKitView = class {
|
|
|
2334
3268
|
form.append(empty);
|
|
2335
3269
|
return form;
|
|
2336
3270
|
}
|
|
2337
|
-
|
|
2338
|
-
meta.className = "dfwr-item-date";
|
|
2339
|
-
meta.textContent = formatAreaDraftMeta(areaDraft);
|
|
2340
|
-
form.append(meta);
|
|
3271
|
+
form.append(this.createAreaMetricsPanel(areaDraft));
|
|
2341
3272
|
const textarea = document.createElement("textarea");
|
|
2342
3273
|
textarea.className = "dfwr-textarea";
|
|
2343
3274
|
textarea.placeholder = "Area comment";
|
|
2344
3275
|
textarea.rows = 4;
|
|
3276
|
+
textarea.value = areaDraft.comment ?? "";
|
|
3277
|
+
textarea.addEventListener("input", () => {
|
|
3278
|
+
const draft = this.state.areaDraft;
|
|
3279
|
+
if (!draft) return;
|
|
3280
|
+
this.config.actions.setAreaDraft({
|
|
3281
|
+
...draft,
|
|
3282
|
+
comment: textarea.value
|
|
3283
|
+
});
|
|
3284
|
+
});
|
|
2345
3285
|
const actions = this.createFormActions("Save area", () => {
|
|
2346
3286
|
const comment = textarea.value.trim();
|
|
2347
3287
|
const draft = this.state.areaDraft;
|
|
@@ -2358,6 +3298,25 @@ var WebReviewKitView = class {
|
|
|
2358
3298
|
form.append(textarea, actions);
|
|
2359
3299
|
return form;
|
|
2360
3300
|
}
|
|
3301
|
+
createAreaMetricsPanel(draft) {
|
|
3302
|
+
const panel = document.createElement("div");
|
|
3303
|
+
panel.className = "dfwr-adjust-panel is-area-metrics-panel";
|
|
3304
|
+
const help = document.createElement("div");
|
|
3305
|
+
help.className = "dfwr-adjust-help";
|
|
3306
|
+
const [labelLine, xyLine, sizeLine] = this.getSelectionMetricLines(
|
|
3307
|
+
this.getAreaDraftMetricSelection(draft),
|
|
3308
|
+
draft.viewport
|
|
3309
|
+
);
|
|
3310
|
+
help.textContent = labelLine;
|
|
3311
|
+
const xyStatus = document.createElement("div");
|
|
3312
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
3313
|
+
xyStatus.textContent = xyLine;
|
|
3314
|
+
const sizeStatus = document.createElement("div");
|
|
3315
|
+
sizeStatus.className = "dfwr-adjust-status";
|
|
3316
|
+
sizeStatus.textContent = sizeLine;
|
|
3317
|
+
panel.append(help, xyStatus, sizeStatus);
|
|
3318
|
+
return panel;
|
|
3319
|
+
}
|
|
2361
3320
|
createAreaDraftOverlay(draft) {
|
|
2362
3321
|
const layer = document.createElement("div");
|
|
2363
3322
|
layer.className = "dfwr-area-preview-layer";
|
|
@@ -2386,37 +3345,61 @@ var WebReviewKitView = class {
|
|
|
2386
3345
|
createAreaDraftPopover(draft) {
|
|
2387
3346
|
const environment = this.config.getEnvironment();
|
|
2388
3347
|
const popover = document.createElement("div");
|
|
2389
|
-
popover.className = "dfwr-area-draft";
|
|
3348
|
+
popover.className = "dfwr-area-draft is-composer";
|
|
2390
3349
|
if (environment && draft.selection) {
|
|
2391
3350
|
const selection = toHostSelection(
|
|
2392
3351
|
toViewportSelection(draft.selection.viewport),
|
|
2393
3352
|
environment
|
|
2394
3353
|
);
|
|
2395
|
-
const
|
|
2396
|
-
|
|
2397
|
-
|
|
3354
|
+
const composer = this.getDraftComposerPosition({
|
|
3355
|
+
selection,
|
|
3356
|
+
environment,
|
|
3357
|
+
composerPosition: draft.composerPosition,
|
|
3358
|
+
estimatedHeight: 220
|
|
3359
|
+
});
|
|
3360
|
+
popover.style.left = `${composer.left}px`;
|
|
3361
|
+
popover.style.top = `${composer.top}px`;
|
|
3362
|
+
popover.style.width = `${composer.width}px`;
|
|
2398
3363
|
popover.style.right = "auto";
|
|
2399
3364
|
}
|
|
2400
|
-
|
|
3365
|
+
const dragHandle = this.createDraftDragHandle("Move area composer");
|
|
3366
|
+
popover.append(dragHandle, this.createAreaForm());
|
|
3367
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
3368
|
+
const areaDraft = this.state.areaDraft ?? draft;
|
|
3369
|
+
this.config.actions.setAreaDraft({
|
|
3370
|
+
...areaDraft,
|
|
3371
|
+
composerPosition
|
|
3372
|
+
});
|
|
3373
|
+
});
|
|
2401
3374
|
return popover;
|
|
2402
3375
|
}
|
|
2403
|
-
createFormActions(saveLabel, onSave) {
|
|
3376
|
+
createFormActions(saveLabel, onSave, options) {
|
|
2404
3377
|
const actions = document.createElement("div");
|
|
2405
|
-
actions.className = "dfwr-actions";
|
|
3378
|
+
actions.className = ["dfwr-actions", options?.className].filter(Boolean).join(" ");
|
|
2406
3379
|
const save = document.createElement("button");
|
|
2407
3380
|
save.className = "dfwr-button is-primary";
|
|
2408
3381
|
save.type = "button";
|
|
2409
3382
|
save.textContent = saveLabel;
|
|
2410
|
-
save.addEventListener("click",
|
|
3383
|
+
save.addEventListener("click", (event) => {
|
|
3384
|
+
event.preventDefault();
|
|
3385
|
+
event.stopPropagation();
|
|
3386
|
+
onSave();
|
|
3387
|
+
});
|
|
2411
3388
|
const cancel = document.createElement("button");
|
|
2412
3389
|
cancel.className = "dfwr-button";
|
|
2413
3390
|
cancel.type = "button";
|
|
2414
3391
|
cancel.textContent = "Cancel";
|
|
2415
|
-
cancel.addEventListener("click", () => {
|
|
3392
|
+
cancel.addEventListener("click", (event) => {
|
|
3393
|
+
event.preventDefault();
|
|
3394
|
+
event.stopPropagation();
|
|
2416
3395
|
this.config.actions.setModeState("idle");
|
|
2417
3396
|
this.config.actions.clearDrafts();
|
|
2418
3397
|
this.config.actions.render();
|
|
2419
3398
|
});
|
|
3399
|
+
if (options?.beforeSave?.length || options?.className) {
|
|
3400
|
+
actions.append(cancel, ...options.beforeSave ?? [], save);
|
|
3401
|
+
return actions;
|
|
3402
|
+
}
|
|
2420
3403
|
actions.append(save, cancel);
|
|
2421
3404
|
return actions;
|
|
2422
3405
|
}
|
|
@@ -2621,11 +3604,13 @@ ${formatItemMeta(item)}`;
|
|
|
2621
3604
|
if (!environment) return;
|
|
2622
3605
|
const nextPoint = clampPoint(toTargetPoint(hostPoint, environment), environment);
|
|
2623
3606
|
const nextHostPoint = toHostPoint(nextPoint, environment);
|
|
2624
|
-
const position = getPopoverPosition(nextHostPoint, environment);
|
|
2625
3607
|
pin.style.left = `${nextHostPoint.x}px`;
|
|
2626
3608
|
pin.style.top = `${nextHostPoint.y}px`;
|
|
2627
|
-
popover
|
|
2628
|
-
|
|
3609
|
+
if (popover) {
|
|
3610
|
+
const position = getPopoverPosition(nextHostPoint, environment);
|
|
3611
|
+
popover.style.left = `${position.left}px`;
|
|
3612
|
+
popover.style.top = `${position.top}px`;
|
|
3613
|
+
}
|
|
2629
3614
|
const noteDraft = this.state.noteDraft;
|
|
2630
3615
|
if (!noteDraft) return;
|
|
2631
3616
|
const nextDraft = {
|
|
@@ -2637,7 +3622,9 @@ ${formatItemMeta(item)}`;
|
|
|
2637
3622
|
comment: textarea.value
|
|
2638
3623
|
};
|
|
2639
3624
|
this.config.actions.setNoteDraft(nextDraft);
|
|
2640
|
-
|
|
3625
|
+
if (meta) {
|
|
3626
|
+
meta.textContent = formatNoteDraftMeta(nextDraft);
|
|
3627
|
+
}
|
|
2641
3628
|
};
|
|
2642
3629
|
pin.addEventListener("pointerdown", (event) => {
|
|
2643
3630
|
if (event.button !== 0) return;
|
|
@@ -2870,6 +3857,9 @@ var WebReviewKitApp = class {
|
|
|
2870
3857
|
setNoteDraft: (draft) => {
|
|
2871
3858
|
this.noteDraft = draft;
|
|
2872
3859
|
},
|
|
3860
|
+
setAreaDraft: (draft) => {
|
|
3861
|
+
this.areaDraft = draft;
|
|
3862
|
+
},
|
|
2873
3863
|
setSelectingArea: (isSelectingArea) => {
|
|
2874
3864
|
this.isSelectingArea = isSelectingArea;
|
|
2875
3865
|
},
|
|
@@ -2895,6 +3885,7 @@ var WebReviewKitApp = class {
|
|
|
2895
3885
|
this.render();
|
|
2896
3886
|
}
|
|
2897
3887
|
destroy() {
|
|
3888
|
+
this.view.clearDraftPreview();
|
|
2898
3889
|
document.removeEventListener("keydown", this.handleKeyDown, true);
|
|
2899
3890
|
window.removeEventListener("scroll", this.handleViewportChange, true);
|
|
2900
3891
|
window.removeEventListener("resize", this.handleViewportChange);
|
|
@@ -3098,14 +4089,27 @@ var WebReviewKitApp = class {
|
|
|
3098
4089
|
const viewport = getViewportSize(environment);
|
|
3099
4090
|
const nextPoint = clampPoint(point, environment);
|
|
3100
4091
|
const draft = await this.withOverlayHidden(() => {
|
|
4092
|
+
const pointSelection = getPointSelection(nextPoint);
|
|
4093
|
+
const targetElement = environment.document.elementFromPoint(
|
|
4094
|
+
nextPoint.x,
|
|
4095
|
+
nextPoint.y
|
|
4096
|
+
);
|
|
4097
|
+
const previewElement = targetElement && "style" in targetElement ? targetElement : void 0;
|
|
4098
|
+
const targetRect = targetElement?.getBoundingClientRect();
|
|
4099
|
+
const clickedSelection = targetRect && targetRect.width > 0 && targetRect.height > 0 ? {
|
|
4100
|
+
left: targetRect.left,
|
|
4101
|
+
top: targetRect.top,
|
|
4102
|
+
width: targetRect.width,
|
|
4103
|
+
height: targetRect.height
|
|
4104
|
+
} : void 0;
|
|
3101
4105
|
const anchor = getDomAnchorFromPoint(
|
|
3102
4106
|
nextPoint,
|
|
3103
4107
|
this.options.anchors?.attribute,
|
|
3104
4108
|
environment
|
|
3105
4109
|
);
|
|
3106
|
-
const elementSelection = anchor ? getElementViewportSelection(anchor, environment) : void 0;
|
|
3107
|
-
const selection = elementSelection ??
|
|
3108
|
-
const markerPoint = getSelectionCenter(selection);
|
|
4110
|
+
const elementSelection = anchor ? clickedSelection ?? getElementViewportSelection(anchor, environment, pointSelection) : void 0;
|
|
4111
|
+
const selection = elementSelection ?? pointSelection;
|
|
4112
|
+
const markerPoint = elementSelection ? { x: selection.left, y: selection.top } : getSelectionCenter(selection);
|
|
3109
4113
|
const reviewSelection = elementSelection ? {
|
|
3110
4114
|
viewport: toPublicSelection(elementSelection),
|
|
3111
4115
|
relative: getRelativeSelection(
|
|
@@ -3123,7 +4127,8 @@ var WebReviewKitApp = class {
|
|
|
3123
4127
|
anchor,
|
|
3124
4128
|
marker,
|
|
3125
4129
|
selection: reviewSelection,
|
|
3126
|
-
comment
|
|
4130
|
+
comment,
|
|
4131
|
+
previewElement
|
|
3127
4132
|
};
|
|
3128
4133
|
});
|
|
3129
4134
|
this.noteDraft = draft;
|