@designfever/web-review-kit 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +18 -1
- package/dist/{chunk-I76WEDLA.js → chunk-QFNYQCTA.js} +1046 -85
- package/dist/chunk-QFNYQCTA.js.map +1 -0
- package/dist/index.cjs +1045 -84
- 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 +3058 -806
- 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 +1917 -622
- 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/architecture.md +3 -0
- package/docs/installation.md +7 -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;
|
|
@@ -625,46 +627,66 @@ function getAnchorElement(anchor, environment) {
|
|
|
625
627
|
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment)?.element;
|
|
626
628
|
}
|
|
627
629
|
function createAnchorCandidates(target, configuredAttribute) {
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
630
|
+
const targetCandidates = [];
|
|
631
|
+
const configuredAnchor = getExactAttributeAnchorCandidate(
|
|
632
|
+
target,
|
|
633
|
+
configuredAttribute,
|
|
634
|
+
0.98,
|
|
635
|
+
"configured-attribute"
|
|
636
|
+
);
|
|
637
|
+
if (configuredAnchor) targetCandidates.push(configuredAnchor);
|
|
638
|
+
const targetAttributeAnchor = getAttributeAnchorCandidate(
|
|
639
|
+
target,
|
|
640
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
641
|
+
0.9
|
|
642
|
+
);
|
|
643
|
+
if (targetAttributeAnchor) targetCandidates.push(targetAttributeAnchor);
|
|
641
644
|
if (isMeaningfulId(target.id)) {
|
|
642
|
-
|
|
645
|
+
targetCandidates.push({
|
|
643
646
|
selector: `#${cssEscape(target.id)}`,
|
|
644
647
|
strategy: "id",
|
|
645
648
|
confidence: 0.94,
|
|
646
649
|
textFingerprint: getTextFingerprint(target)
|
|
647
650
|
});
|
|
648
651
|
}
|
|
652
|
+
const semanticAnchor = getAttributeAnchorCandidate(
|
|
653
|
+
target,
|
|
654
|
+
SEMANTIC_ANCHOR_ATTRIBUTES,
|
|
655
|
+
0.84
|
|
656
|
+
);
|
|
657
|
+
if (semanticAnchor) targetCandidates.push(semanticAnchor);
|
|
649
658
|
const targetClassName = getMeaningfulClassName(target);
|
|
650
659
|
if (targetClassName) {
|
|
651
|
-
|
|
660
|
+
targetCandidates.push({
|
|
652
661
|
selector: `${target.tagName.toLowerCase()}.${cssEscape(targetClassName)}`,
|
|
653
662
|
strategy: "class",
|
|
654
663
|
confidence: 0.82,
|
|
655
664
|
textFingerprint: getTextFingerprint(target)
|
|
656
665
|
});
|
|
657
666
|
}
|
|
658
|
-
|
|
667
|
+
const scopedPath = getScopedDomPathCandidate(target, configuredAttribute);
|
|
668
|
+
if (scopedPath) targetCandidates.push(scopedPath);
|
|
669
|
+
const targetDomPath = {
|
|
659
670
|
selector: getDomPath(target),
|
|
660
671
|
strategy: "dom-path",
|
|
661
|
-
confidence: 0.
|
|
672
|
+
confidence: targetCandidates.length > 0 ? 0.8 : 0.5,
|
|
662
673
|
textFingerprint: getTextFingerprint(target)
|
|
663
|
-
}
|
|
674
|
+
};
|
|
675
|
+
const parentCandidates = [];
|
|
664
676
|
const parent = target.parentElement;
|
|
677
|
+
const parentConfiguredAnchor = parent ? findClosestAttributeAnchor(parent, [configuredAttribute], 0.72, {
|
|
678
|
+
strategy: "configured-attribute"
|
|
679
|
+
}) : void 0;
|
|
680
|
+
if (parentConfiguredAnchor) parentCandidates.push(parentConfiguredAnchor);
|
|
681
|
+
const anchoredByAttribute = parent ? findClosestAttributeAnchor(
|
|
682
|
+
parent,
|
|
683
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
684
|
+
0.7
|
|
685
|
+
) : void 0;
|
|
686
|
+
if (anchoredByAttribute) parentCandidates.push(anchoredByAttribute);
|
|
665
687
|
const anchoredById = parent ? findClosest(parent, (element) => isMeaningfulId(element.id)) : void 0;
|
|
666
688
|
if (anchoredById?.id) {
|
|
667
|
-
|
|
689
|
+
parentCandidates.push({
|
|
668
690
|
selector: `#${cssEscape(anchoredById.id)}`,
|
|
669
691
|
strategy: "id",
|
|
670
692
|
confidence: 0.72,
|
|
@@ -674,7 +696,7 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
674
696
|
const anchoredByClass = parent ? findClosest(parent, (element) => Boolean(getMeaningfulClassName(element))) : void 0;
|
|
675
697
|
const className = anchoredByClass ? getMeaningfulClassName(anchoredByClass) : void 0;
|
|
676
698
|
if (anchoredByClass && className) {
|
|
677
|
-
|
|
699
|
+
parentCandidates.push({
|
|
678
700
|
selector: `${anchoredByClass.tagName.toLowerCase()}.${cssEscape(
|
|
679
701
|
className
|
|
680
702
|
)}`,
|
|
@@ -683,8 +705,107 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
683
705
|
textFingerprint: getTextFingerprint(anchoredByClass)
|
|
684
706
|
});
|
|
685
707
|
}
|
|
708
|
+
const candidates = targetCandidates.length > 0 ? [...targetCandidates, targetDomPath, ...parentCandidates] : [...parentCandidates, targetDomPath];
|
|
686
709
|
return dedupeAnchorCandidates(candidates);
|
|
687
710
|
}
|
|
711
|
+
function findClosestAttributeAnchor(target, attributeNames, confidence, options) {
|
|
712
|
+
for (const attributeName of attributeNames) {
|
|
713
|
+
const selector = `[${attributeName}]`;
|
|
714
|
+
const element = safeClosest(target, selector);
|
|
715
|
+
if (!element) continue;
|
|
716
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
717
|
+
if (!value) continue;
|
|
718
|
+
return {
|
|
719
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
720
|
+
strategy: options?.strategy ?? "attribute",
|
|
721
|
+
confidence,
|
|
722
|
+
textFingerprint: getTextFingerprint(element)
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
return void 0;
|
|
726
|
+
}
|
|
727
|
+
function getExactAttributeAnchorCandidate(element, attributeName, confidence, strategy) {
|
|
728
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
729
|
+
if (!value) return void 0;
|
|
730
|
+
return {
|
|
731
|
+
selector: `[${attributeName}="${cssEscape(value)}"]`,
|
|
732
|
+
strategy,
|
|
733
|
+
confidence,
|
|
734
|
+
textFingerprint: getTextFingerprint(element)
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
function getAttributeAnchorCandidate(element, attributeNames, confidence) {
|
|
738
|
+
for (const attributeName of attributeNames) {
|
|
739
|
+
const value = getStableAttributeValue(element, attributeName);
|
|
740
|
+
if (!value) continue;
|
|
741
|
+
return {
|
|
742
|
+
selector: `${element.tagName.toLowerCase()}[${attributeName}="${cssEscape(
|
|
743
|
+
value
|
|
744
|
+
)}"]`,
|
|
745
|
+
strategy: "attribute",
|
|
746
|
+
confidence,
|
|
747
|
+
textFingerprint: getTextFingerprint(element)
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
return void 0;
|
|
751
|
+
}
|
|
752
|
+
function getScopedDomPathCandidate(target, configuredAttribute) {
|
|
753
|
+
const parent = target.parentElement;
|
|
754
|
+
if (!parent) return void 0;
|
|
755
|
+
const anchor = findStableAncestorSelector(parent, configuredAttribute);
|
|
756
|
+
if (!anchor) return void 0;
|
|
757
|
+
const selector = getDomPathBetween(anchor.element, target, anchor.selector);
|
|
758
|
+
if (!selector) return void 0;
|
|
759
|
+
return {
|
|
760
|
+
selector,
|
|
761
|
+
strategy: "dom-path",
|
|
762
|
+
confidence: anchor.confidence,
|
|
763
|
+
textFingerprint: getTextFingerprint(target)
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function findStableAncestorSelector(start, configuredAttribute) {
|
|
767
|
+
let element = start;
|
|
768
|
+
const root = start.ownerDocument.documentElement;
|
|
769
|
+
while (element && element !== root) {
|
|
770
|
+
const configuredValue = getStableAttributeValue(element, configuredAttribute);
|
|
771
|
+
if (configuredValue) {
|
|
772
|
+
return {
|
|
773
|
+
element,
|
|
774
|
+
selector: `[${configuredAttribute}="${cssEscape(configuredValue)}"]`,
|
|
775
|
+
confidence: 0.88
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
const attributeAnchor = getAttributeAnchorCandidate(
|
|
779
|
+
element,
|
|
780
|
+
COMMON_ANCHOR_ATTRIBUTES.filter((name) => name !== configuredAttribute),
|
|
781
|
+
0.84
|
|
782
|
+
);
|
|
783
|
+
if (attributeAnchor) {
|
|
784
|
+
return {
|
|
785
|
+
element,
|
|
786
|
+
selector: attributeAnchor.selector,
|
|
787
|
+
confidence: 0.84
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
if (isMeaningfulId(element.id)) {
|
|
791
|
+
return {
|
|
792
|
+
element,
|
|
793
|
+
selector: `#${cssEscape(element.id)}`,
|
|
794
|
+
confidence: 0.82
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
const className = getMeaningfulClassName(element);
|
|
798
|
+
if (className) {
|
|
799
|
+
return {
|
|
800
|
+
element,
|
|
801
|
+
selector: `${element.tagName.toLowerCase()}.${cssEscape(className)}`,
|
|
802
|
+
confidence: 0.76
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
element = element.parentElement;
|
|
806
|
+
}
|
|
807
|
+
return void 0;
|
|
808
|
+
}
|
|
688
809
|
function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
689
810
|
if (candidate.strategy === "configured-attribute") {
|
|
690
811
|
return target.closest(`[${configuredAttribute}]`);
|
|
@@ -696,6 +817,13 @@ function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
|
696
817
|
return target;
|
|
697
818
|
}
|
|
698
819
|
}
|
|
820
|
+
function safeClosest(element, selector) {
|
|
821
|
+
try {
|
|
822
|
+
return element.closest(selector);
|
|
823
|
+
} catch {
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
699
827
|
function getElementHtmlSnippet(element, maxLength = 1e3) {
|
|
700
828
|
const html = decodeHtmlEntities(element.outerHTML.replace(/\s+/g, " ").trim());
|
|
701
829
|
if (html.length <= maxLength) return html;
|
|
@@ -817,10 +945,38 @@ function getDomPath(element) {
|
|
|
817
945
|
}
|
|
818
946
|
return `body > ${parts.join(" > ")}`;
|
|
819
947
|
}
|
|
948
|
+
function getDomPathBetween(ancestor, target, ancestorSelector) {
|
|
949
|
+
const parts = [];
|
|
950
|
+
let current = target;
|
|
951
|
+
while (current && current !== ancestor) {
|
|
952
|
+
parts.unshift(getDomPathPart(current));
|
|
953
|
+
current = current.parentElement;
|
|
954
|
+
}
|
|
955
|
+
if (current !== ancestor || parts.length === 0) return void 0;
|
|
956
|
+
return `${ancestorSelector} > ${parts.join(" > ")}`;
|
|
957
|
+
}
|
|
958
|
+
function getDomPathPart(element) {
|
|
959
|
+
const parent = element.parentElement;
|
|
960
|
+
const tag = element.tagName.toLowerCase();
|
|
961
|
+
if (!parent) return tag;
|
|
962
|
+
const currentTagName = element.tagName;
|
|
963
|
+
const siblings = Array.from(parent.children).filter(
|
|
964
|
+
(child) => child.tagName === currentTagName
|
|
965
|
+
);
|
|
966
|
+
const index = siblings.indexOf(element) + 1;
|
|
967
|
+
return `${tag}:nth-of-type(${index})`;
|
|
968
|
+
}
|
|
820
969
|
function getTextFingerprint(element) {
|
|
821
970
|
const text = element.textContent?.replace(/\s+/g, " ").trim();
|
|
822
971
|
return text ? text.slice(0, 120) : void 0;
|
|
823
972
|
}
|
|
973
|
+
function getStableAttributeValue(element, attributeName) {
|
|
974
|
+
const value = element.getAttribute(attributeName)?.trim();
|
|
975
|
+
if (!value || value.length > 160) return void 0;
|
|
976
|
+
if (/^(true|false)$/i.test(value)) return void 0;
|
|
977
|
+
if (/^\d+$/.test(value) && value.length < 3) return void 0;
|
|
978
|
+
return value;
|
|
979
|
+
}
|
|
824
980
|
function getTextFingerprintScore(expected, actual) {
|
|
825
981
|
if (!expected) return 1;
|
|
826
982
|
if (!actual) return 0.5;
|
|
@@ -1292,6 +1448,19 @@ function createStyleElement() {
|
|
|
1292
1448
|
display: block;
|
|
1293
1449
|
}
|
|
1294
1450
|
|
|
1451
|
+
.dfwr-shell.has-dismissible-draft {
|
|
1452
|
+
z-index: 900;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
.dfwr-draft-cancel-layer {
|
|
1456
|
+
position: fixed;
|
|
1457
|
+
inset: 0;
|
|
1458
|
+
z-index: 2;
|
|
1459
|
+
pointer-events: auto;
|
|
1460
|
+
background: transparent;
|
|
1461
|
+
cursor: default;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1295
1464
|
.dfwr-panel {
|
|
1296
1465
|
position: fixed;
|
|
1297
1466
|
right: 16px;
|
|
@@ -1785,6 +1954,40 @@ function createStyleElement() {
|
|
|
1785
1954
|
box-shadow: var(--df-review-shadow-popover);
|
|
1786
1955
|
}
|
|
1787
1956
|
|
|
1957
|
+
.dfwr-note-popover.is-composer,
|
|
1958
|
+
.dfwr-area-draft.is-composer {
|
|
1959
|
+
max-height: min(360px, calc(100vh - 32px));
|
|
1960
|
+
overflow: auto;
|
|
1961
|
+
border-color: rgba(99, 215, 199, 0.56);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
.dfwr-note-popover.is-dragging,
|
|
1965
|
+
.dfwr-area-draft.is-dragging {
|
|
1966
|
+
user-select: none;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
.dfwr-draft-drag-handle {
|
|
1970
|
+
display: block;
|
|
1971
|
+
width: 42px;
|
|
1972
|
+
height: 6px;
|
|
1973
|
+
margin: 0 auto 10px;
|
|
1974
|
+
padding: 0;
|
|
1975
|
+
cursor: grab;
|
|
1976
|
+
pointer-events: auto;
|
|
1977
|
+
background: rgba(247, 247, 242, 0.28);
|
|
1978
|
+
border: 0;
|
|
1979
|
+
border-radius: 999px;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
.dfwr-draft-drag-handle:hover,
|
|
1983
|
+
.dfwr-draft-drag-handle:focus-visible {
|
|
1984
|
+
background: rgba(215, 255, 95, 0.62);
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
.dfwr-draft-drag-handle:active {
|
|
1988
|
+
cursor: grabbing;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1788
1991
|
.dfwr-area-draft {
|
|
1789
1992
|
position: fixed;
|
|
1790
1993
|
right: 16px;
|
|
@@ -1806,6 +2009,14 @@ function createStyleElement() {
|
|
|
1806
2009
|
padding: 0;
|
|
1807
2010
|
}
|
|
1808
2011
|
|
|
2012
|
+
.dfwr-note-actions {
|
|
2013
|
+
justify-content: flex-end;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
.dfwr-note-actions .dfwr-button:first-child {
|
|
2017
|
+
margin-right: auto;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1809
2020
|
.dfwr-area-draft .dfwr-actions {
|
|
1810
2021
|
padding: 0;
|
|
1811
2022
|
}
|
|
@@ -1834,6 +2045,105 @@ function createStyleElement() {
|
|
|
1834
2045
|
outline-offset: 1px;
|
|
1835
2046
|
}
|
|
1836
2047
|
|
|
2048
|
+
.dfwr-adjust-panel {
|
|
2049
|
+
display: grid;
|
|
2050
|
+
gap: 4px;
|
|
2051
|
+
padding: 8px 10px;
|
|
2052
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2053
|
+
border-radius: var(--df-review-radius-sm);
|
|
2054
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
.dfwr-adjust-panel-header {
|
|
2058
|
+
display: flex;
|
|
2059
|
+
align-items: center;
|
|
2060
|
+
justify-content: space-between;
|
|
2061
|
+
gap: 10px;
|
|
2062
|
+
min-width: 0;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
.dfwr-adjust-panel-header .dfwr-adjust-help {
|
|
2066
|
+
flex: 1 1 auto;
|
|
2067
|
+
min-width: 0;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
.dfwr-adjust-panel.is-active {
|
|
2071
|
+
border-color: rgba(215, 255, 95, 0.5);
|
|
2072
|
+
background: var(--df-review-color-accent-soft);
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
.dfwr-adjust-help,
|
|
2076
|
+
.dfwr-adjust-status {
|
|
2077
|
+
margin: 0;
|
|
2078
|
+
color: var(--df-review-color-text-muted);
|
|
2079
|
+
font-size: var(--df-review-font-size-xs);
|
|
2080
|
+
line-height: 1.35;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
.dfwr-adjust-status {
|
|
2084
|
+
color: var(--df-review-color-text);
|
|
2085
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
.dfwr-adjust-toggle {
|
|
2089
|
+
flex: 0 0 auto;
|
|
2090
|
+
display: inline-flex;
|
|
2091
|
+
align-items: center;
|
|
2092
|
+
justify-content: center;
|
|
2093
|
+
width: 34px;
|
|
2094
|
+
height: 30px;
|
|
2095
|
+
padding: 0;
|
|
2096
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
2097
|
+
border-radius: var(--df-review-radius-sm);
|
|
2098
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2099
|
+
color: var(--df-review-color-text);
|
|
2100
|
+
cursor: pointer;
|
|
2101
|
+
font: inherit;
|
|
2102
|
+
font-size: 14px;
|
|
2103
|
+
font-weight: 800;
|
|
2104
|
+
line-height: 1;
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
.dfwr-adjust-toggle:hover,
|
|
2108
|
+
.dfwr-adjust-toggle:focus-visible,
|
|
2109
|
+
.dfwr-adjust-toggle.is-active {
|
|
2110
|
+
border-color: rgba(215, 255, 95, 0.68);
|
|
2111
|
+
background: var(--df-review-color-accent-soft);
|
|
2112
|
+
outline: none;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
.dfwr-adjust-toggle svg {
|
|
2116
|
+
width: 18px;
|
|
2117
|
+
height: 18px;
|
|
2118
|
+
pointer-events: none;
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
.dfwr-adjust-hud {
|
|
2122
|
+
position: fixed;
|
|
2123
|
+
z-index: 5;
|
|
2124
|
+
display: inline-flex;
|
|
2125
|
+
align-items: center;
|
|
2126
|
+
min-height: 22px;
|
|
2127
|
+
padding: 0 8px;
|
|
2128
|
+
border: 1px solid rgba(99, 215, 199, 0.72);
|
|
2129
|
+
border-radius: var(--df-review-radius-sm);
|
|
2130
|
+
background: rgba(21, 25, 29, 0.92);
|
|
2131
|
+
box-shadow:
|
|
2132
|
+
0 0 0 3px rgba(99, 215, 199, 0.14),
|
|
2133
|
+
0 8px 18px rgba(0, 0, 0, 0.26);
|
|
2134
|
+
color: #63d7c7;
|
|
2135
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
2136
|
+
font-size: var(--df-review-font-size-2xs);
|
|
2137
|
+
font-weight: 800;
|
|
2138
|
+
line-height: 1;
|
|
2139
|
+
pointer-events: none;
|
|
2140
|
+
white-space: nowrap;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
.dfwr-adjust-hud[hidden] {
|
|
2144
|
+
display: none;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
1837
2147
|
.dfwr-empty,
|
|
1838
2148
|
.dfwr-error {
|
|
1839
2149
|
margin: 0;
|
|
@@ -2054,16 +2364,6 @@ function createStyleElement() {
|
|
|
2054
2364
|
}
|
|
2055
2365
|
|
|
2056
2366
|
// 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
2367
|
function formatNoteDraftMeta(draft) {
|
|
2068
2368
|
const parts = [
|
|
2069
2369
|
`viewport ${formatSize(draft.viewport)}`,
|
|
@@ -2129,17 +2429,29 @@ function formatAnchorMeta(anchor) {
|
|
|
2129
2429
|
}
|
|
2130
2430
|
|
|
2131
2431
|
// src/core/web.review.kit.view.ts
|
|
2432
|
+
var DEFAULT_ADJUSTMENT_LABEL = "Responsive CSS px adjustments";
|
|
2132
2433
|
var WebReviewKitView = class {
|
|
2133
2434
|
constructor(config) {
|
|
2134
2435
|
this.config = config;
|
|
2135
2436
|
}
|
|
2437
|
+
clearDraftPreview() {
|
|
2438
|
+
this.restoreDraftPreview();
|
|
2439
|
+
}
|
|
2136
2440
|
render(shadow, hiddenItemsStyle) {
|
|
2137
2441
|
const state = this.state;
|
|
2442
|
+
this.syncDraftPreview(
|
|
2443
|
+
state.isOpen && state.mode === "element" ? state.noteDraft : void 0
|
|
2444
|
+
);
|
|
2138
2445
|
shadow.replaceChildren();
|
|
2139
2446
|
shadow.append(createStyleElement());
|
|
2140
2447
|
shadow.append(hiddenItemsStyle);
|
|
2448
|
+
const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
|
|
2141
2449
|
const shell = document.createElement("div");
|
|
2142
|
-
shell.className =
|
|
2450
|
+
shell.className = [
|
|
2451
|
+
"dfwr-shell",
|
|
2452
|
+
state.isOpen ? "is-open" : "",
|
|
2453
|
+
hasDismissableDraft ? "has-dismissible-draft" : ""
|
|
2454
|
+
].filter(Boolean).join(" ");
|
|
2143
2455
|
shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
|
|
2144
2456
|
if (this.config.options.ui?.panel !== false) {
|
|
2145
2457
|
const panel = document.createElement("div");
|
|
@@ -2155,6 +2467,9 @@ var WebReviewKitView = class {
|
|
|
2155
2467
|
shell.append(panel);
|
|
2156
2468
|
}
|
|
2157
2469
|
shell.append(this.createMarkerLayer());
|
|
2470
|
+
if (state.isOpen && hasDismissableDraft) {
|
|
2471
|
+
shell.append(this.createDraftCancelLayer());
|
|
2472
|
+
}
|
|
2158
2473
|
if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
|
|
2159
2474
|
shell.append(
|
|
2160
2475
|
state.noteDraft ? this.createNotePopover(state.noteDraft) : state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
|
|
@@ -2174,6 +2489,294 @@ var WebReviewKitView = class {
|
|
|
2174
2489
|
get state() {
|
|
2175
2490
|
return this.config.getState();
|
|
2176
2491
|
}
|
|
2492
|
+
createDraftCancelLayer() {
|
|
2493
|
+
const layer = document.createElement("div");
|
|
2494
|
+
layer.className = "dfwr-draft-cancel-layer";
|
|
2495
|
+
layer.setAttribute("aria-hidden", "true");
|
|
2496
|
+
const cancel = (event) => {
|
|
2497
|
+
event.preventDefault();
|
|
2498
|
+
event.stopPropagation();
|
|
2499
|
+
event.stopImmediatePropagation();
|
|
2500
|
+
this.config.actions.setModeState("idle");
|
|
2501
|
+
this.config.actions.clearDrafts();
|
|
2502
|
+
this.config.actions.setSelectingArea(false);
|
|
2503
|
+
this.config.actions.render();
|
|
2504
|
+
};
|
|
2505
|
+
layer.addEventListener("pointerdown", (event) => {
|
|
2506
|
+
if (event.button !== 0) return;
|
|
2507
|
+
cancel(event);
|
|
2508
|
+
});
|
|
2509
|
+
layer.addEventListener("click", cancel);
|
|
2510
|
+
return layer;
|
|
2511
|
+
}
|
|
2512
|
+
getDraftAdjustmentMetrics(draft) {
|
|
2513
|
+
const adjustment = draft.adjustment;
|
|
2514
|
+
const x = adjustment?.x ?? 0;
|
|
2515
|
+
const y = adjustment?.y ?? 0;
|
|
2516
|
+
const scale = adjustment?.scale ?? 0;
|
|
2517
|
+
const {
|
|
2518
|
+
scale: viewportScale,
|
|
2519
|
+
designWidth,
|
|
2520
|
+
presetLabel
|
|
2521
|
+
} = this.getDraftViewportScale(draft.viewport);
|
|
2522
|
+
const selection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2523
|
+
const scaleCssDelta = scale * viewportScale;
|
|
2524
|
+
const scaleFactor = selection && selection.width > 0 ? Math.max(
|
|
2525
|
+
1 / selection.width,
|
|
2526
|
+
(selection.width + scaleCssDelta) / selection.width
|
|
2527
|
+
) : 1;
|
|
2528
|
+
return {
|
|
2529
|
+
x,
|
|
2530
|
+
y,
|
|
2531
|
+
scale,
|
|
2532
|
+
cssX: x * viewportScale,
|
|
2533
|
+
cssY: y * viewportScale,
|
|
2534
|
+
scaleFactor,
|
|
2535
|
+
viewportScale,
|
|
2536
|
+
designWidth,
|
|
2537
|
+
presetLabel,
|
|
2538
|
+
viewportWidth: draft.viewport.width
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
2541
|
+
hasDraftAdjustment(draft) {
|
|
2542
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2543
|
+
return metrics.x !== 0 || metrics.y !== 0 || metrics.scale !== 0;
|
|
2544
|
+
}
|
|
2545
|
+
getAdjustedDraftPoint(point, draft) {
|
|
2546
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2547
|
+
return {
|
|
2548
|
+
x: point.x + metrics.cssX,
|
|
2549
|
+
y: point.y + metrics.cssY
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
getAdjustedDraftSelection(selection, draft) {
|
|
2553
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2554
|
+
return {
|
|
2555
|
+
...selection,
|
|
2556
|
+
left: selection.left + metrics.cssX,
|
|
2557
|
+
top: selection.top + metrics.cssY,
|
|
2558
|
+
width: selection.width * metrics.scaleFactor,
|
|
2559
|
+
height: selection.height * metrics.scaleFactor
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
getDraftViewportScale(viewport) {
|
|
2563
|
+
const preset = findReviewViewportPreset(
|
|
2564
|
+
viewport,
|
|
2565
|
+
this.config.options.viewports?.presets
|
|
2566
|
+
);
|
|
2567
|
+
const designWidth = typeof preset.designWidth === "number" && preset.designWidth > 0 ? preset.designWidth : viewport.width;
|
|
2568
|
+
const scale = designWidth > 0 ? viewport.width / designWidth : 1;
|
|
2569
|
+
return { scale, designWidth, presetLabel: preset.label };
|
|
2570
|
+
}
|
|
2571
|
+
getDraftComposerWidth(environment) {
|
|
2572
|
+
const bounds = environment.overlayRect;
|
|
2573
|
+
const margin = 12;
|
|
2574
|
+
return Math.min(360, Math.max(240, bounds.width - margin * 2));
|
|
2575
|
+
}
|
|
2576
|
+
getClampedComposerPosition(position, environment, size, bounds = environment.overlayRect) {
|
|
2577
|
+
const margin = 12;
|
|
2578
|
+
const width = size?.width ?? this.getDraftComposerWidth(environment);
|
|
2579
|
+
const height = size?.height ?? 236;
|
|
2580
|
+
return {
|
|
2581
|
+
x: clamp(
|
|
2582
|
+
position.x,
|
|
2583
|
+
bounds.left + margin,
|
|
2584
|
+
bounds.left + bounds.width - width - margin
|
|
2585
|
+
),
|
|
2586
|
+
y: clamp(
|
|
2587
|
+
position.y,
|
|
2588
|
+
bounds.top + margin,
|
|
2589
|
+
bounds.top + bounds.height - height - margin
|
|
2590
|
+
)
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
getHostComposerBounds() {
|
|
2594
|
+
const root = document.documentElement;
|
|
2595
|
+
return {
|
|
2596
|
+
left: 0,
|
|
2597
|
+
top: 0,
|
|
2598
|
+
width: root.clientWidth || window.innerWidth,
|
|
2599
|
+
height: root.clientHeight || window.innerHeight
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
getInitialDraftComposerPosition(selection, environment, size) {
|
|
2603
|
+
const bounds = this.getHostComposerBounds();
|
|
2604
|
+
const margin = 12;
|
|
2605
|
+
const gap = 20;
|
|
2606
|
+
if (!selection) {
|
|
2607
|
+
return this.getClampedComposerPosition(
|
|
2608
|
+
{
|
|
2609
|
+
x: environment.overlayRect.left + margin,
|
|
2610
|
+
y: environment.overlayRect.top + margin
|
|
2611
|
+
},
|
|
2612
|
+
environment,
|
|
2613
|
+
size,
|
|
2614
|
+
bounds
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
const preferredX = selection.left + selection.width + gap;
|
|
2618
|
+
const maxX = bounds.left + bounds.width - size.width - margin;
|
|
2619
|
+
const x = preferredX <= maxX ? preferredX : selection.left - size.width - gap;
|
|
2620
|
+
return this.getClampedComposerPosition(
|
|
2621
|
+
{
|
|
2622
|
+
x,
|
|
2623
|
+
y: selection.top
|
|
2624
|
+
},
|
|
2625
|
+
environment,
|
|
2626
|
+
size,
|
|
2627
|
+
bounds
|
|
2628
|
+
);
|
|
2629
|
+
}
|
|
2630
|
+
getDraftComposerPosition({
|
|
2631
|
+
selection,
|
|
2632
|
+
environment,
|
|
2633
|
+
composerPosition,
|
|
2634
|
+
estimatedHeight
|
|
2635
|
+
}) {
|
|
2636
|
+
const width = this.getDraftComposerWidth(environment);
|
|
2637
|
+
if (composerPosition) {
|
|
2638
|
+
const clamped = this.getClampedComposerPosition(
|
|
2639
|
+
composerPosition,
|
|
2640
|
+
environment,
|
|
2641
|
+
{ width, height: estimatedHeight },
|
|
2642
|
+
this.getHostComposerBounds()
|
|
2643
|
+
);
|
|
2644
|
+
return { width, left: clamped.x, top: clamped.y };
|
|
2645
|
+
}
|
|
2646
|
+
const position = this.getInitialDraftComposerPosition(selection, environment, {
|
|
2647
|
+
width,
|
|
2648
|
+
height: estimatedHeight
|
|
2649
|
+
});
|
|
2650
|
+
return { width, left: position.x, top: position.y };
|
|
2651
|
+
}
|
|
2652
|
+
getSelectionMqMetrics(selection, viewport) {
|
|
2653
|
+
const { scale } = this.getDraftViewportScale(viewport);
|
|
2654
|
+
const ratio = scale > 0 ? 1 / scale : 1;
|
|
2655
|
+
return {
|
|
2656
|
+
x: selection.left * ratio,
|
|
2657
|
+
y: selection.top * ratio,
|
|
2658
|
+
width: selection.width * ratio,
|
|
2659
|
+
height: selection.height * ratio
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
formatSignedPx(value) {
|
|
2663
|
+
if (value === 0) return "+0px";
|
|
2664
|
+
return `${value > 0 ? "+" : ""}${value}px`;
|
|
2665
|
+
}
|
|
2666
|
+
formatRoundedPx(value) {
|
|
2667
|
+
return `${Math.round(value)}px`;
|
|
2668
|
+
}
|
|
2669
|
+
getAdjustmentLabel() {
|
|
2670
|
+
return this.config.options.adjustmentLabel?.trim() || DEFAULT_ADJUSTMENT_LABEL;
|
|
2671
|
+
}
|
|
2672
|
+
getSelectionMetricLines(selection, viewport) {
|
|
2673
|
+
if (!selection) return ["area", "x none / y none", "w none / h none"];
|
|
2674
|
+
const metrics = this.getSelectionMqMetrics(selection, viewport);
|
|
2675
|
+
return [
|
|
2676
|
+
"area",
|
|
2677
|
+
`x ${this.formatRoundedPx(metrics.x)} / y ${this.formatRoundedPx(
|
|
2678
|
+
metrics.y
|
|
2679
|
+
)}`,
|
|
2680
|
+
`w ${this.formatRoundedPx(metrics.width)} / h ${this.formatRoundedPx(
|
|
2681
|
+
metrics.height
|
|
2682
|
+
)}`
|
|
2683
|
+
];
|
|
2684
|
+
}
|
|
2685
|
+
getAreaDraftMetricSelection(draft) {
|
|
2686
|
+
if (!draft.selection) return void 0;
|
|
2687
|
+
return toViewportSelection(draft.selection.viewport);
|
|
2688
|
+
}
|
|
2689
|
+
formatDraftAdjustmentStatus(draft) {
|
|
2690
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2691
|
+
return [
|
|
2692
|
+
`x ${this.formatSignedPx(metrics.x)}`,
|
|
2693
|
+
`y ${this.formatSignedPx(metrics.y)}`,
|
|
2694
|
+
`scale ${this.formatSignedPx(metrics.scale)}`
|
|
2695
|
+
].join(" / ");
|
|
2696
|
+
}
|
|
2697
|
+
getDraftAdjustmentMetricLines(draft) {
|
|
2698
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2699
|
+
return [
|
|
2700
|
+
`x ${this.formatSignedPx(metrics.x)} / y ${this.formatSignedPx(
|
|
2701
|
+
metrics.y
|
|
2702
|
+
)}`,
|
|
2703
|
+
`scale ${this.formatSignedPx(metrics.scale)}`
|
|
2704
|
+
];
|
|
2705
|
+
}
|
|
2706
|
+
withDraftAdjustmentComment(comment, draft) {
|
|
2707
|
+
if (!this.hasDraftAdjustment(draft)) return comment;
|
|
2708
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2709
|
+
const adjustment = [
|
|
2710
|
+
`${this.getAdjustmentLabel()}: x ${this.formatSignedPx(
|
|
2711
|
+
metrics.x
|
|
2712
|
+
)}, y ${this.formatSignedPx(metrics.y)}, scale ${this.formatSignedPx(
|
|
2713
|
+
metrics.scale
|
|
2714
|
+
)}`,
|
|
2715
|
+
`(${metrics.presetLabel} viewport, ${Math.round(
|
|
2716
|
+
metrics.viewportWidth
|
|
2717
|
+
)}/design ${Math.round(metrics.designWidth)})`
|
|
2718
|
+
].join(" ");
|
|
2719
|
+
return `${comment.trim()}
|
|
2720
|
+
${adjustment}`;
|
|
2721
|
+
}
|
|
2722
|
+
getStyleableDraftElement(draft, environment) {
|
|
2723
|
+
if (!draft.anchor) return void 0;
|
|
2724
|
+
const element = resolveAnchorElement(draft.anchor, environment)?.element;
|
|
2725
|
+
if (!element) return void 0;
|
|
2726
|
+
if ("style" in element) return element;
|
|
2727
|
+
return void 0;
|
|
2728
|
+
}
|
|
2729
|
+
syncDraftPreview(draft) {
|
|
2730
|
+
const environment = this.config.getEnvironment();
|
|
2731
|
+
if (!draft || !environment || !this.hasDraftAdjustment(draft)) {
|
|
2732
|
+
this.restoreDraftPreview();
|
|
2733
|
+
return;
|
|
2734
|
+
}
|
|
2735
|
+
const element = this.getStyleableDraftElement(draft, environment);
|
|
2736
|
+
if (!element) {
|
|
2737
|
+
this.restoreDraftPreview();
|
|
2738
|
+
return;
|
|
2739
|
+
}
|
|
2740
|
+
if (this.draftPreview?.element !== element) {
|
|
2741
|
+
this.restoreDraftPreview();
|
|
2742
|
+
}
|
|
2743
|
+
if (!this.draftPreview) {
|
|
2744
|
+
const computedTransform = environment.window.getComputedStyle(element).transform;
|
|
2745
|
+
this.draftPreview = {
|
|
2746
|
+
element,
|
|
2747
|
+
transform: element.style.transform,
|
|
2748
|
+
transformOrigin: element.style.transformOrigin,
|
|
2749
|
+
transition: element.style.transition,
|
|
2750
|
+
willChange: element.style.willChange,
|
|
2751
|
+
baseTransform: element.style.transform || (computedTransform && computedTransform !== "none" ? computedTransform : "")
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2755
|
+
const translate = `translate(${this.toCssNumber(metrics.cssX)}px, ${this.toCssNumber(
|
|
2756
|
+
metrics.cssY
|
|
2757
|
+
)}px)`;
|
|
2758
|
+
const scale = metrics.scaleFactor === 1 ? "" : `scale(${this.toCssNumber(metrics.scaleFactor)})`;
|
|
2759
|
+
element.style.transition = "none";
|
|
2760
|
+
element.style.willChange = "transform";
|
|
2761
|
+
element.style.transformOrigin = "top left";
|
|
2762
|
+
element.style.transform = [
|
|
2763
|
+
this.draftPreview.baseTransform,
|
|
2764
|
+
translate,
|
|
2765
|
+
scale
|
|
2766
|
+
].filter(Boolean).join(" ");
|
|
2767
|
+
}
|
|
2768
|
+
restoreDraftPreview() {
|
|
2769
|
+
if (!this.draftPreview) return;
|
|
2770
|
+
const { element, transform, transformOrigin, transition, willChange } = this.draftPreview;
|
|
2771
|
+
element.style.transform = transform;
|
|
2772
|
+
element.style.transformOrigin = transformOrigin;
|
|
2773
|
+
element.style.transition = transition;
|
|
2774
|
+
element.style.willChange = willChange;
|
|
2775
|
+
this.draftPreview = void 0;
|
|
2776
|
+
}
|
|
2777
|
+
toCssNumber(value) {
|
|
2778
|
+
return Math.round(value * 1e3) / 1e3;
|
|
2779
|
+
}
|
|
2177
2780
|
createHeader() {
|
|
2178
2781
|
const header = document.createElement("div");
|
|
2179
2782
|
header.className = "dfwr-header";
|
|
@@ -2265,15 +2868,20 @@ var WebReviewKitView = class {
|
|
|
2265
2868
|
const group = document.createElement("div");
|
|
2266
2869
|
group.className = "dfwr-note-draft";
|
|
2267
2870
|
if (!environment) return group;
|
|
2268
|
-
const
|
|
2871
|
+
const isElementDraft = this.state.mode === "element" && Boolean(draft.selection);
|
|
2872
|
+
const hostPoint = toHostPoint(
|
|
2873
|
+
isElementDraft ? this.getAdjustedDraftPoint(draft.marker.viewport, draft) : draft.marker.viewport,
|
|
2874
|
+
environment
|
|
2875
|
+
);
|
|
2876
|
+
let selectionHighlight;
|
|
2269
2877
|
if (draft.selection) {
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
)
|
|
2878
|
+
const selection = toViewportSelection(draft.selection.viewport);
|
|
2879
|
+
selectionHighlight = this.createSelectionHighlight(
|
|
2880
|
+
isElementDraft ? this.getAdjustedDraftSelection(selection, draft) : selection,
|
|
2881
|
+
environment,
|
|
2882
|
+
true
|
|
2276
2883
|
);
|
|
2884
|
+
group.append(selectionHighlight);
|
|
2277
2885
|
}
|
|
2278
2886
|
const pin = document.createElement("button");
|
|
2279
2887
|
pin.className = "dfwr-note-pin";
|
|
@@ -2283,14 +2891,35 @@ var WebReviewKitView = class {
|
|
|
2283
2891
|
pin.style.top = `${hostPoint.y}px`;
|
|
2284
2892
|
const popover = document.createElement("div");
|
|
2285
2893
|
const position = getPopoverPosition(hostPoint, environment);
|
|
2286
|
-
popover.className =
|
|
2287
|
-
|
|
2288
|
-
|
|
2894
|
+
popover.className = `dfwr-note-popover${isElementDraft ? " is-composer" : ""}`;
|
|
2895
|
+
if (isElementDraft) {
|
|
2896
|
+
const selection = draft.selection ? toHostSelection(
|
|
2897
|
+
this.getAdjustedDraftSelection(
|
|
2898
|
+
toViewportSelection(draft.selection.viewport),
|
|
2899
|
+
draft
|
|
2900
|
+
),
|
|
2901
|
+
environment
|
|
2902
|
+
) : void 0;
|
|
2903
|
+
const composer = this.getDraftComposerPosition({
|
|
2904
|
+
selection,
|
|
2905
|
+
environment,
|
|
2906
|
+
composerPosition: draft.composerPosition,
|
|
2907
|
+
estimatedHeight: 252
|
|
2908
|
+
});
|
|
2909
|
+
popover.style.left = `${composer.left}px`;
|
|
2910
|
+
popover.style.top = `${composer.top}px`;
|
|
2911
|
+
popover.style.width = `${composer.width}px`;
|
|
2912
|
+
} else {
|
|
2913
|
+
popover.style.left = `${position.left}px`;
|
|
2914
|
+
popover.style.top = `${position.top}px`;
|
|
2915
|
+
}
|
|
2289
2916
|
const form = document.createElement("form");
|
|
2290
2917
|
form.className = "dfwr-form";
|
|
2291
|
-
const meta = document.createElement("div");
|
|
2292
|
-
meta
|
|
2293
|
-
|
|
2918
|
+
const meta = isElementDraft ? void 0 : document.createElement("div");
|
|
2919
|
+
if (meta) {
|
|
2920
|
+
meta.className = "dfwr-item-date";
|
|
2921
|
+
meta.textContent = formatNoteDraftMeta(draft);
|
|
2922
|
+
}
|
|
2294
2923
|
const textarea = document.createElement("textarea");
|
|
2295
2924
|
textarea.className = "dfwr-textarea";
|
|
2296
2925
|
textarea.placeholder = "Review comment";
|
|
@@ -2304,25 +2933,306 @@ var WebReviewKitView = class {
|
|
|
2304
2933
|
comment: textarea.value
|
|
2305
2934
|
});
|
|
2306
2935
|
});
|
|
2307
|
-
const
|
|
2936
|
+
const saveDraft = () => {
|
|
2308
2937
|
const comment = textarea.value.trim();
|
|
2309
2938
|
if (!comment) return;
|
|
2939
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2310
2940
|
void this.config.actions.createItem({
|
|
2311
2941
|
kind: "note",
|
|
2312
|
-
comment,
|
|
2313
|
-
viewport:
|
|
2314
|
-
anchor:
|
|
2315
|
-
marker:
|
|
2316
|
-
selection:
|
|
2942
|
+
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
2943
|
+
viewport: currentDraft.viewport,
|
|
2944
|
+
anchor: currentDraft.anchor,
|
|
2945
|
+
marker: currentDraft.marker,
|
|
2946
|
+
selection: currentDraft.selection
|
|
2317
2947
|
});
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2948
|
+
};
|
|
2949
|
+
const adjustmentHud = isElementDraft ? this.createAdjustmentHud(draft, environment) : void 0;
|
|
2950
|
+
if (adjustmentHud) {
|
|
2951
|
+
group.append(adjustmentHud);
|
|
2952
|
+
}
|
|
2953
|
+
const adjustmentControls = isElementDraft ? this.createAdjustmentControls({
|
|
2954
|
+
draft,
|
|
2955
|
+
hud: adjustmentHud,
|
|
2956
|
+
pin,
|
|
2957
|
+
popover,
|
|
2958
|
+
selectionHighlight,
|
|
2959
|
+
textarea
|
|
2960
|
+
}) : void 0;
|
|
2961
|
+
const actions = this.createFormActions("Save note", saveDraft);
|
|
2962
|
+
form.append(
|
|
2963
|
+
...meta ? [meta] : [],
|
|
2964
|
+
...adjustmentControls ? [adjustmentControls.panel] : [],
|
|
2965
|
+
textarea,
|
|
2966
|
+
actions
|
|
2967
|
+
);
|
|
2968
|
+
const dragHandle = isElementDraft ? this.createDraftDragHandle("Move DOM composer") : void 0;
|
|
2969
|
+
popover.append(...dragHandle ? [dragHandle] : [], form);
|
|
2321
2970
|
group.append(pin, popover);
|
|
2322
|
-
|
|
2323
|
-
|
|
2971
|
+
if (dragHandle) {
|
|
2972
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
2973
|
+
const noteDraft = this.state.noteDraft ?? draft;
|
|
2974
|
+
this.config.actions.setNoteDraft({
|
|
2975
|
+
...noteDraft,
|
|
2976
|
+
composerPosition,
|
|
2977
|
+
comment: textarea.value
|
|
2978
|
+
});
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
this.attachDraftPinDrag(
|
|
2982
|
+
pin,
|
|
2983
|
+
isElementDraft ? void 0 : popover,
|
|
2984
|
+
meta,
|
|
2985
|
+
textarea
|
|
2986
|
+
);
|
|
2987
|
+
window.setTimeout(() => {
|
|
2988
|
+
if (draft.adjustment?.isActive) {
|
|
2989
|
+
adjustmentControls?.focusTarget.focus();
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
textarea.focus();
|
|
2993
|
+
}, 0);
|
|
2324
2994
|
return group;
|
|
2325
2995
|
}
|
|
2996
|
+
createDraftDragHandle(label) {
|
|
2997
|
+
const handle = document.createElement("button");
|
|
2998
|
+
handle.className = "dfwr-draft-drag-handle";
|
|
2999
|
+
handle.type = "button";
|
|
3000
|
+
handle.setAttribute("aria-label", label);
|
|
3001
|
+
return handle;
|
|
3002
|
+
}
|
|
3003
|
+
createIcon(paths) {
|
|
3004
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3005
|
+
svg.setAttribute("aria-hidden", "true");
|
|
3006
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
3007
|
+
svg.setAttribute("fill", "none");
|
|
3008
|
+
svg.setAttribute("stroke", "currentColor");
|
|
3009
|
+
svg.setAttribute("stroke-width", "2.4");
|
|
3010
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
3011
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
3012
|
+
paths.forEach((d) => {
|
|
3013
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3014
|
+
path.setAttribute("d", d);
|
|
3015
|
+
svg.append(path);
|
|
3016
|
+
});
|
|
3017
|
+
return svg;
|
|
3018
|
+
}
|
|
3019
|
+
setAdjustmentToggleIcon(button, isActive) {
|
|
3020
|
+
const paths = isActive ? ["M20 6 9 17l-5-5"] : [
|
|
3021
|
+
"M12 2v20",
|
|
3022
|
+
"M2 12h20",
|
|
3023
|
+
"m9 5 3-3 3 3",
|
|
3024
|
+
"m9 19 3 3 3-3",
|
|
3025
|
+
"m5 9-3 3 3 3",
|
|
3026
|
+
"m19 9 3 3-3 3"
|
|
3027
|
+
];
|
|
3028
|
+
button.replaceChildren(this.createIcon(paths));
|
|
3029
|
+
}
|
|
3030
|
+
attachDraftComposerDrag(popover, handle, onMove) {
|
|
3031
|
+
let isDragging = false;
|
|
3032
|
+
let offsetX = 0;
|
|
3033
|
+
let offsetY = 0;
|
|
3034
|
+
const movePopover = (event) => {
|
|
3035
|
+
const environment = this.config.getEnvironment();
|
|
3036
|
+
if (!environment) return;
|
|
3037
|
+
const position = this.getClampedComposerPosition(
|
|
3038
|
+
{
|
|
3039
|
+
x: event.clientX - offsetX,
|
|
3040
|
+
y: event.clientY - offsetY
|
|
3041
|
+
},
|
|
3042
|
+
environment,
|
|
3043
|
+
{
|
|
3044
|
+
width: popover.offsetWidth,
|
|
3045
|
+
height: popover.offsetHeight
|
|
3046
|
+
},
|
|
3047
|
+
this.getHostComposerBounds()
|
|
3048
|
+
);
|
|
3049
|
+
popover.style.left = `${position.x}px`;
|
|
3050
|
+
popover.style.top = `${position.y}px`;
|
|
3051
|
+
onMove(position);
|
|
3052
|
+
};
|
|
3053
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
3054
|
+
if (event.button !== 0) return;
|
|
3055
|
+
const rect = popover.getBoundingClientRect();
|
|
3056
|
+
offsetX = event.clientX - rect.left;
|
|
3057
|
+
offsetY = event.clientY - rect.top;
|
|
3058
|
+
isDragging = true;
|
|
3059
|
+
event.preventDefault();
|
|
3060
|
+
event.stopPropagation();
|
|
3061
|
+
handle.setPointerCapture(event.pointerId);
|
|
3062
|
+
popover.classList.add("is-dragging");
|
|
3063
|
+
});
|
|
3064
|
+
handle.addEventListener("pointermove", (event) => {
|
|
3065
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
3066
|
+
event.preventDefault();
|
|
3067
|
+
movePopover(event);
|
|
3068
|
+
});
|
|
3069
|
+
const stopDrag = (event) => {
|
|
3070
|
+
if (!isDragging || !handle.hasPointerCapture(event.pointerId)) return;
|
|
3071
|
+
event.preventDefault();
|
|
3072
|
+
event.stopPropagation();
|
|
3073
|
+
isDragging = false;
|
|
3074
|
+
handle.releasePointerCapture(event.pointerId);
|
|
3075
|
+
popover.classList.remove("is-dragging");
|
|
3076
|
+
movePopover(event);
|
|
3077
|
+
};
|
|
3078
|
+
handle.addEventListener("pointerup", stopDrag);
|
|
3079
|
+
handle.addEventListener("pointercancel", stopDrag);
|
|
3080
|
+
}
|
|
3081
|
+
createAdjustmentControls({
|
|
3082
|
+
draft,
|
|
3083
|
+
hud,
|
|
3084
|
+
pin,
|
|
3085
|
+
popover,
|
|
3086
|
+
selectionHighlight,
|
|
3087
|
+
textarea
|
|
3088
|
+
}) {
|
|
3089
|
+
const panel = document.createElement("div");
|
|
3090
|
+
panel.className = "dfwr-adjust-panel is-dom-adjust-panel";
|
|
3091
|
+
const header = document.createElement("div");
|
|
3092
|
+
header.className = "dfwr-adjust-panel-header";
|
|
3093
|
+
const help = document.createElement("div");
|
|
3094
|
+
help.className = "dfwr-adjust-help";
|
|
3095
|
+
help.textContent = this.getAdjustmentLabel();
|
|
3096
|
+
const adjust = document.createElement("button");
|
|
3097
|
+
adjust.className = "dfwr-adjust-toggle";
|
|
3098
|
+
adjust.type = "button";
|
|
3099
|
+
adjust.title = "Adjust DOM element with keyboard arrows";
|
|
3100
|
+
adjust.setAttribute("aria-label", "Adjust DOM element with keyboard arrows");
|
|
3101
|
+
const xyStatus = document.createElement("div");
|
|
3102
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
3103
|
+
const scaleStatus = document.createElement("div");
|
|
3104
|
+
scaleStatus.className = "dfwr-adjust-status";
|
|
3105
|
+
const syncControls = (nextDraft) => {
|
|
3106
|
+
const isActive = nextDraft.adjustment?.isActive === true;
|
|
3107
|
+
panel.classList.toggle("is-active", isActive);
|
|
3108
|
+
adjust.classList.toggle("is-active", isActive);
|
|
3109
|
+
adjust.setAttribute("aria-pressed", isActive ? "true" : "false");
|
|
3110
|
+
this.setAdjustmentToggleIcon(adjust, isActive);
|
|
3111
|
+
adjust.title = isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows";
|
|
3112
|
+
adjust.setAttribute(
|
|
3113
|
+
"aria-label",
|
|
3114
|
+
isActive ? "Finish DOM adjustment" : "Adjust DOM element with keyboard arrows"
|
|
3115
|
+
);
|
|
3116
|
+
const [xyLine, scaleLine] = this.getDraftAdjustmentMetricLines(nextDraft);
|
|
3117
|
+
xyStatus.textContent = xyLine;
|
|
3118
|
+
scaleStatus.textContent = scaleLine;
|
|
3119
|
+
this.syncDraftAdjustmentUi({
|
|
3120
|
+
draft: nextDraft,
|
|
3121
|
+
hud,
|
|
3122
|
+
pin,
|
|
3123
|
+
selectionHighlight
|
|
3124
|
+
});
|
|
3125
|
+
};
|
|
3126
|
+
const updateDraft = (updater) => {
|
|
3127
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
3128
|
+
const nextDraft = updater(currentDraft);
|
|
3129
|
+
this.config.actions.setNoteDraft({
|
|
3130
|
+
...nextDraft,
|
|
3131
|
+
comment: textarea.value
|
|
3132
|
+
});
|
|
3133
|
+
syncControls(nextDraft);
|
|
3134
|
+
};
|
|
3135
|
+
adjust.addEventListener("click", () => {
|
|
3136
|
+
updateDraft((currentDraft) => ({
|
|
3137
|
+
...currentDraft,
|
|
3138
|
+
adjustment: {
|
|
3139
|
+
x: currentDraft.adjustment?.x ?? 0,
|
|
3140
|
+
y: currentDraft.adjustment?.y ?? 0,
|
|
3141
|
+
scale: currentDraft.adjustment?.scale ?? 0,
|
|
3142
|
+
isActive: currentDraft.adjustment?.isActive !== true
|
|
3143
|
+
}
|
|
3144
|
+
}));
|
|
3145
|
+
adjust.focus();
|
|
3146
|
+
});
|
|
3147
|
+
popover.addEventListener("keydown", (event) => {
|
|
3148
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
3149
|
+
if (currentDraft.adjustment?.isActive !== true) return;
|
|
3150
|
+
const keyDelta = this.getAdjustmentKeyDelta(event);
|
|
3151
|
+
if (!keyDelta) return;
|
|
3152
|
+
event.preventDefault();
|
|
3153
|
+
event.stopPropagation();
|
|
3154
|
+
updateDraft((activeDraft) => ({
|
|
3155
|
+
...activeDraft,
|
|
3156
|
+
adjustment: {
|
|
3157
|
+
x: (activeDraft.adjustment?.x ?? 0) + keyDelta.x,
|
|
3158
|
+
y: (activeDraft.adjustment?.y ?? 0) + keyDelta.y,
|
|
3159
|
+
scale: (activeDraft.adjustment?.scale ?? 0) + keyDelta.scale,
|
|
3160
|
+
isActive: true
|
|
3161
|
+
}
|
|
3162
|
+
}));
|
|
3163
|
+
});
|
|
3164
|
+
header.append(help, adjust);
|
|
3165
|
+
panel.append(header, xyStatus, scaleStatus);
|
|
3166
|
+
syncControls(draft);
|
|
3167
|
+
return {
|
|
3168
|
+
panel,
|
|
3169
|
+
focusTarget: adjust
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
getAdjustmentKeyDelta(event) {
|
|
3173
|
+
const step = event.shiftKey ? 10 : 1;
|
|
3174
|
+
if (event.key === "ArrowLeft") return { x: -step, y: 0, scale: 0 };
|
|
3175
|
+
if (event.key === "ArrowRight") return { x: step, y: 0, scale: 0 };
|
|
3176
|
+
if (event.key === "ArrowUp") return { x: 0, y: -step, scale: 0 };
|
|
3177
|
+
if (event.key === "ArrowDown") return { x: 0, y: step, scale: 0 };
|
|
3178
|
+
if (event.key.toLowerCase() === "w") return { x: 0, y: 0, scale: step };
|
|
3179
|
+
if (event.key.toLowerCase() === "s") return { x: 0, y: 0, scale: -step };
|
|
3180
|
+
return void 0;
|
|
3181
|
+
}
|
|
3182
|
+
createAdjustmentHud(draft, environment) {
|
|
3183
|
+
const hud = document.createElement("div");
|
|
3184
|
+
hud.className = "dfwr-adjust-hud";
|
|
3185
|
+
hud.setAttribute("aria-hidden", "true");
|
|
3186
|
+
this.syncAdjustmentHud(hud, draft, environment);
|
|
3187
|
+
return hud;
|
|
3188
|
+
}
|
|
3189
|
+
syncDraftAdjustmentUi({
|
|
3190
|
+
draft,
|
|
3191
|
+
hud,
|
|
3192
|
+
pin,
|
|
3193
|
+
selectionHighlight
|
|
3194
|
+
}) {
|
|
3195
|
+
const environment = this.config.getEnvironment();
|
|
3196
|
+
if (!environment) return;
|
|
3197
|
+
const hostPoint = toHostPoint(
|
|
3198
|
+
this.getAdjustedDraftPoint(draft.marker.viewport, draft),
|
|
3199
|
+
environment
|
|
3200
|
+
);
|
|
3201
|
+
pin.style.left = `${hostPoint.x}px`;
|
|
3202
|
+
pin.style.top = `${hostPoint.y}px`;
|
|
3203
|
+
if (draft.selection && selectionHighlight) {
|
|
3204
|
+
const rect = toHostSelection(
|
|
3205
|
+
this.getAdjustedDraftSelection(
|
|
3206
|
+
toViewportSelection(draft.selection.viewport),
|
|
3207
|
+
draft
|
|
3208
|
+
),
|
|
3209
|
+
environment
|
|
3210
|
+
);
|
|
3211
|
+
selectionHighlight.style.left = `${rect.left}px`;
|
|
3212
|
+
selectionHighlight.style.top = `${rect.top}px`;
|
|
3213
|
+
selectionHighlight.style.width = `${rect.width}px`;
|
|
3214
|
+
selectionHighlight.style.height = `${rect.height}px`;
|
|
3215
|
+
}
|
|
3216
|
+
if (hud) {
|
|
3217
|
+
this.syncAdjustmentHud(hud, draft, environment);
|
|
3218
|
+
}
|
|
3219
|
+
this.syncDraftPreview(draft);
|
|
3220
|
+
}
|
|
3221
|
+
syncAdjustmentHud(hud, draft, environment) {
|
|
3222
|
+
if (!draft.selection) return;
|
|
3223
|
+
const rect = toHostSelection(
|
|
3224
|
+
this.getAdjustedDraftSelection(
|
|
3225
|
+
toViewportSelection(draft.selection.viewport),
|
|
3226
|
+
draft
|
|
3227
|
+
),
|
|
3228
|
+
environment
|
|
3229
|
+
);
|
|
3230
|
+
const isVisible = draft.adjustment?.isActive === true || this.hasDraftAdjustment(draft);
|
|
3231
|
+
hud.hidden = !isVisible;
|
|
3232
|
+
hud.textContent = this.formatDraftAdjustmentStatus(draft);
|
|
3233
|
+
hud.style.left = `${Math.max(4, rect.left)}px`;
|
|
3234
|
+
hud.style.top = `${Math.max(4, rect.top - 28)}px`;
|
|
3235
|
+
}
|
|
2326
3236
|
createAreaForm() {
|
|
2327
3237
|
const form = document.createElement("form");
|
|
2328
3238
|
form.className = "dfwr-form";
|
|
@@ -2334,14 +3244,20 @@ var WebReviewKitView = class {
|
|
|
2334
3244
|
form.append(empty);
|
|
2335
3245
|
return form;
|
|
2336
3246
|
}
|
|
2337
|
-
|
|
2338
|
-
meta.className = "dfwr-item-date";
|
|
2339
|
-
meta.textContent = formatAreaDraftMeta(areaDraft);
|
|
2340
|
-
form.append(meta);
|
|
3247
|
+
form.append(this.createAreaMetricsPanel(areaDraft));
|
|
2341
3248
|
const textarea = document.createElement("textarea");
|
|
2342
3249
|
textarea.className = "dfwr-textarea";
|
|
2343
3250
|
textarea.placeholder = "Area comment";
|
|
2344
3251
|
textarea.rows = 4;
|
|
3252
|
+
textarea.value = areaDraft.comment ?? "";
|
|
3253
|
+
textarea.addEventListener("input", () => {
|
|
3254
|
+
const draft = this.state.areaDraft;
|
|
3255
|
+
if (!draft) return;
|
|
3256
|
+
this.config.actions.setAreaDraft({
|
|
3257
|
+
...draft,
|
|
3258
|
+
comment: textarea.value
|
|
3259
|
+
});
|
|
3260
|
+
});
|
|
2345
3261
|
const actions = this.createFormActions("Save area", () => {
|
|
2346
3262
|
const comment = textarea.value.trim();
|
|
2347
3263
|
const draft = this.state.areaDraft;
|
|
@@ -2358,6 +3274,25 @@ var WebReviewKitView = class {
|
|
|
2358
3274
|
form.append(textarea, actions);
|
|
2359
3275
|
return form;
|
|
2360
3276
|
}
|
|
3277
|
+
createAreaMetricsPanel(draft) {
|
|
3278
|
+
const panel = document.createElement("div");
|
|
3279
|
+
panel.className = "dfwr-adjust-panel is-area-metrics-panel";
|
|
3280
|
+
const help = document.createElement("div");
|
|
3281
|
+
help.className = "dfwr-adjust-help";
|
|
3282
|
+
const [labelLine, xyLine, sizeLine] = this.getSelectionMetricLines(
|
|
3283
|
+
this.getAreaDraftMetricSelection(draft),
|
|
3284
|
+
draft.viewport
|
|
3285
|
+
);
|
|
3286
|
+
help.textContent = labelLine;
|
|
3287
|
+
const xyStatus = document.createElement("div");
|
|
3288
|
+
xyStatus.className = "dfwr-adjust-status";
|
|
3289
|
+
xyStatus.textContent = xyLine;
|
|
3290
|
+
const sizeStatus = document.createElement("div");
|
|
3291
|
+
sizeStatus.className = "dfwr-adjust-status";
|
|
3292
|
+
sizeStatus.textContent = sizeLine;
|
|
3293
|
+
panel.append(help, xyStatus, sizeStatus);
|
|
3294
|
+
return panel;
|
|
3295
|
+
}
|
|
2361
3296
|
createAreaDraftOverlay(draft) {
|
|
2362
3297
|
const layer = document.createElement("div");
|
|
2363
3298
|
layer.className = "dfwr-area-preview-layer";
|
|
@@ -2386,23 +3321,37 @@ var WebReviewKitView = class {
|
|
|
2386
3321
|
createAreaDraftPopover(draft) {
|
|
2387
3322
|
const environment = this.config.getEnvironment();
|
|
2388
3323
|
const popover = document.createElement("div");
|
|
2389
|
-
popover.className = "dfwr-area-draft";
|
|
3324
|
+
popover.className = "dfwr-area-draft is-composer";
|
|
2390
3325
|
if (environment && draft.selection) {
|
|
2391
3326
|
const selection = toHostSelection(
|
|
2392
3327
|
toViewportSelection(draft.selection.viewport),
|
|
2393
3328
|
environment
|
|
2394
3329
|
);
|
|
2395
|
-
const
|
|
2396
|
-
|
|
2397
|
-
|
|
3330
|
+
const composer = this.getDraftComposerPosition({
|
|
3331
|
+
selection,
|
|
3332
|
+
environment,
|
|
3333
|
+
composerPosition: draft.composerPosition,
|
|
3334
|
+
estimatedHeight: 220
|
|
3335
|
+
});
|
|
3336
|
+
popover.style.left = `${composer.left}px`;
|
|
3337
|
+
popover.style.top = `${composer.top}px`;
|
|
3338
|
+
popover.style.width = `${composer.width}px`;
|
|
2398
3339
|
popover.style.right = "auto";
|
|
2399
3340
|
}
|
|
2400
|
-
|
|
3341
|
+
const dragHandle = this.createDraftDragHandle("Move area composer");
|
|
3342
|
+
popover.append(dragHandle, this.createAreaForm());
|
|
3343
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
3344
|
+
const areaDraft = this.state.areaDraft ?? draft;
|
|
3345
|
+
this.config.actions.setAreaDraft({
|
|
3346
|
+
...areaDraft,
|
|
3347
|
+
composerPosition
|
|
3348
|
+
});
|
|
3349
|
+
});
|
|
2401
3350
|
return popover;
|
|
2402
3351
|
}
|
|
2403
|
-
createFormActions(saveLabel, onSave) {
|
|
3352
|
+
createFormActions(saveLabel, onSave, options) {
|
|
2404
3353
|
const actions = document.createElement("div");
|
|
2405
|
-
actions.className = "dfwr-actions";
|
|
3354
|
+
actions.className = ["dfwr-actions", options?.className].filter(Boolean).join(" ");
|
|
2406
3355
|
const save = document.createElement("button");
|
|
2407
3356
|
save.className = "dfwr-button is-primary";
|
|
2408
3357
|
save.type = "button";
|
|
@@ -2417,6 +3366,10 @@ var WebReviewKitView = class {
|
|
|
2417
3366
|
this.config.actions.clearDrafts();
|
|
2418
3367
|
this.config.actions.render();
|
|
2419
3368
|
});
|
|
3369
|
+
if (options?.beforeSave?.length || options?.className) {
|
|
3370
|
+
actions.append(cancel, ...options.beforeSave ?? [], save);
|
|
3371
|
+
return actions;
|
|
3372
|
+
}
|
|
2420
3373
|
actions.append(save, cancel);
|
|
2421
3374
|
return actions;
|
|
2422
3375
|
}
|
|
@@ -2621,11 +3574,13 @@ ${formatItemMeta(item)}`;
|
|
|
2621
3574
|
if (!environment) return;
|
|
2622
3575
|
const nextPoint = clampPoint(toTargetPoint(hostPoint, environment), environment);
|
|
2623
3576
|
const nextHostPoint = toHostPoint(nextPoint, environment);
|
|
2624
|
-
const position = getPopoverPosition(nextHostPoint, environment);
|
|
2625
3577
|
pin.style.left = `${nextHostPoint.x}px`;
|
|
2626
3578
|
pin.style.top = `${nextHostPoint.y}px`;
|
|
2627
|
-
popover
|
|
2628
|
-
|
|
3579
|
+
if (popover) {
|
|
3580
|
+
const position = getPopoverPosition(nextHostPoint, environment);
|
|
3581
|
+
popover.style.left = `${position.left}px`;
|
|
3582
|
+
popover.style.top = `${position.top}px`;
|
|
3583
|
+
}
|
|
2629
3584
|
const noteDraft = this.state.noteDraft;
|
|
2630
3585
|
if (!noteDraft) return;
|
|
2631
3586
|
const nextDraft = {
|
|
@@ -2637,7 +3592,9 @@ ${formatItemMeta(item)}`;
|
|
|
2637
3592
|
comment: textarea.value
|
|
2638
3593
|
};
|
|
2639
3594
|
this.config.actions.setNoteDraft(nextDraft);
|
|
2640
|
-
|
|
3595
|
+
if (meta) {
|
|
3596
|
+
meta.textContent = formatNoteDraftMeta(nextDraft);
|
|
3597
|
+
}
|
|
2641
3598
|
};
|
|
2642
3599
|
pin.addEventListener("pointerdown", (event) => {
|
|
2643
3600
|
if (event.button !== 0) return;
|
|
@@ -2870,6 +3827,9 @@ var WebReviewKitApp = class {
|
|
|
2870
3827
|
setNoteDraft: (draft) => {
|
|
2871
3828
|
this.noteDraft = draft;
|
|
2872
3829
|
},
|
|
3830
|
+
setAreaDraft: (draft) => {
|
|
3831
|
+
this.areaDraft = draft;
|
|
3832
|
+
},
|
|
2873
3833
|
setSelectingArea: (isSelectingArea) => {
|
|
2874
3834
|
this.isSelectingArea = isSelectingArea;
|
|
2875
3835
|
},
|
|
@@ -2895,6 +3855,7 @@ var WebReviewKitApp = class {
|
|
|
2895
3855
|
this.render();
|
|
2896
3856
|
}
|
|
2897
3857
|
destroy() {
|
|
3858
|
+
this.view.clearDraftPreview();
|
|
2898
3859
|
document.removeEventListener("keydown", this.handleKeyDown, true);
|
|
2899
3860
|
window.removeEventListener("scroll", this.handleViewportChange, true);
|
|
2900
3861
|
window.removeEventListener("resize", this.handleViewportChange);
|
|
@@ -3105,7 +4066,7 @@ var WebReviewKitApp = class {
|
|
|
3105
4066
|
);
|
|
3106
4067
|
const elementSelection = anchor ? getElementViewportSelection(anchor, environment) : void 0;
|
|
3107
4068
|
const selection = elementSelection ?? getPointSelection(nextPoint);
|
|
3108
|
-
const markerPoint = getSelectionCenter(selection);
|
|
4069
|
+
const markerPoint = elementSelection ? { x: selection.left, y: selection.top } : getSelectionCenter(selection);
|
|
3109
4070
|
const reviewSelection = elementSelection ? {
|
|
3110
4071
|
viewport: toPublicSelection(elementSelection),
|
|
3111
4072
|
relative: getRelativeSelection(
|