@designfever/web-review-kit 0.2.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 +40 -0
- package/dist/{chunk-EJDROXJM.js → chunk-QFNYQCTA.js} +1081 -92
- package/dist/chunk-QFNYQCTA.js.map +1 -0
- package/dist/index.cjs +1081 -92
- 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 +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react-shell.cjs +3637 -777
- package/dist/react-shell.cjs.map +1 -1
- package/dist/react-shell.d.cts +12 -3
- package/dist/react-shell.d.ts +12 -3
- package/dist/react-shell.js +2520 -643
- package/dist/react-shell.js.map +1 -1
- package/dist/{types-NiCp9JJQ.d.cts → types-D_qYtwTs.d.cts} +6 -1
- package/dist/{types-NiCp9JJQ.d.ts → types-D_qYtwTs.d.ts} +6 -1
- package/dist/vite.cjs +186 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +16 -0
- package/dist/vite.d.ts +16 -0
- package/dist/vite.js +161 -0
- package/dist/vite.js.map +1 -0
- package/docs/architecture.md +3 -0
- package/docs/installation.md +39 -0
- package/docs/release-notes-0.3.0.md +94 -0
- package/docs/release-notes-0.4.0.md +144 -0
- package/package.json +16 -5
- package/dist/chunk-EJDROXJM.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -176,7 +176,7 @@ function supabaseAdapter(options) {
|
|
|
176
176
|
);
|
|
177
177
|
}
|
|
178
178
|
const rows = await unwrapResponse(
|
|
179
|
-
request.order("
|
|
179
|
+
request.order("created_at", { ascending: false }),
|
|
180
180
|
"supabase list review items"
|
|
181
181
|
);
|
|
182
182
|
return (rows ?? []).flatMap((row) => {
|
|
@@ -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;
|
|
@@ -718,18 +846,39 @@ function decodeHtmlEntities(value) {
|
|
|
718
846
|
}
|
|
719
847
|
function getDomSourceHint(target) {
|
|
720
848
|
const sourceElement = target.closest(
|
|
721
|
-
|
|
849
|
+
[
|
|
850
|
+
"[data-wrk-source-file]",
|
|
851
|
+
"[data-wrk-source-component]",
|
|
852
|
+
"[data-wrk-source-line]",
|
|
853
|
+
"[data-wrk-source-column]",
|
|
854
|
+
"[data-file]",
|
|
855
|
+
"[data-component]",
|
|
856
|
+
"[data-section-index]",
|
|
857
|
+
"[data-section-id]"
|
|
858
|
+
].join(", ")
|
|
722
859
|
);
|
|
723
860
|
if (!sourceElement) return void 0;
|
|
724
|
-
const dataset = sourceElement.dataset;
|
|
725
861
|
const source = {
|
|
726
|
-
component:
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
862
|
+
component: getSourceAttribute(
|
|
863
|
+
sourceElement,
|
|
864
|
+
"data-wrk-source-component",
|
|
865
|
+
"data-component"
|
|
866
|
+
),
|
|
867
|
+
file: getSourceAttribute(sourceElement, "data-wrk-source-file", "data-file"),
|
|
868
|
+
line: getSourceAttribute(sourceElement, "data-wrk-source-line"),
|
|
869
|
+
column: getSourceAttribute(sourceElement, "data-wrk-source-column"),
|
|
870
|
+
sectionId: getSourceAttribute(sourceElement, "data-section-id"),
|
|
871
|
+
sectionIndex: getSourceAttribute(sourceElement, "data-section-index")
|
|
730
872
|
};
|
|
731
873
|
return Object.values(source).some(Boolean) ? source : void 0;
|
|
732
874
|
}
|
|
875
|
+
function getSourceAttribute(element, ...names) {
|
|
876
|
+
for (const name of names) {
|
|
877
|
+
const value = element.getAttribute(name)?.trim();
|
|
878
|
+
if (value) return value;
|
|
879
|
+
}
|
|
880
|
+
return void 0;
|
|
881
|
+
}
|
|
733
882
|
function dedupeAnchorCandidates(candidates) {
|
|
734
883
|
const seen = /* @__PURE__ */ new Set();
|
|
735
884
|
return candidates.filter((candidate) => {
|
|
@@ -796,10 +945,38 @@ function getDomPath(element) {
|
|
|
796
945
|
}
|
|
797
946
|
return `body > ${parts.join(" > ")}`;
|
|
798
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
|
+
}
|
|
799
969
|
function getTextFingerprint(element) {
|
|
800
970
|
const text = element.textContent?.replace(/\s+/g, " ").trim();
|
|
801
971
|
return text ? text.slice(0, 120) : void 0;
|
|
802
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
|
+
}
|
|
803
980
|
function getTextFingerprintScore(expected, actual) {
|
|
804
981
|
if (!expected) return 1;
|
|
805
982
|
if (!actual) return 0.5;
|
|
@@ -1271,6 +1448,19 @@ function createStyleElement() {
|
|
|
1271
1448
|
display: block;
|
|
1272
1449
|
}
|
|
1273
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
|
+
|
|
1274
1464
|
.dfwr-panel {
|
|
1275
1465
|
position: fixed;
|
|
1276
1466
|
right: 16px;
|
|
@@ -1764,6 +1954,40 @@ function createStyleElement() {
|
|
|
1764
1954
|
box-shadow: var(--df-review-shadow-popover);
|
|
1765
1955
|
}
|
|
1766
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
|
+
|
|
1767
1991
|
.dfwr-area-draft {
|
|
1768
1992
|
position: fixed;
|
|
1769
1993
|
right: 16px;
|
|
@@ -1785,6 +2009,14 @@ function createStyleElement() {
|
|
|
1785
2009
|
padding: 0;
|
|
1786
2010
|
}
|
|
1787
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
|
+
|
|
1788
2020
|
.dfwr-area-draft .dfwr-actions {
|
|
1789
2021
|
padding: 0;
|
|
1790
2022
|
}
|
|
@@ -1813,6 +2045,105 @@ function createStyleElement() {
|
|
|
1813
2045
|
outline-offset: 1px;
|
|
1814
2046
|
}
|
|
1815
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
|
+
|
|
1816
2147
|
.dfwr-empty,
|
|
1817
2148
|
.dfwr-error {
|
|
1818
2149
|
margin: 0;
|
|
@@ -2033,16 +2364,6 @@ function createStyleElement() {
|
|
|
2033
2364
|
}
|
|
2034
2365
|
|
|
2035
2366
|
// src/core/review/format.ts
|
|
2036
|
-
function formatAreaDraftMeta(draft) {
|
|
2037
|
-
const parts = [`viewport ${formatSize(draft.viewport)}`];
|
|
2038
|
-
if (draft.selection) {
|
|
2039
|
-
parts.push(`rect ${formatSelection(draft.selection.viewport)}`);
|
|
2040
|
-
}
|
|
2041
|
-
if (draft.marker) {
|
|
2042
|
-
parts.push(`point ${formatPoint(draft.marker.viewport)}`);
|
|
2043
|
-
}
|
|
2044
|
-
return parts.join(" / ");
|
|
2045
|
-
}
|
|
2046
2367
|
function formatNoteDraftMeta(draft) {
|
|
2047
2368
|
const parts = [
|
|
2048
2369
|
`viewport ${formatSize(draft.viewport)}`,
|
|
@@ -2108,17 +2429,29 @@ function formatAnchorMeta(anchor) {
|
|
|
2108
2429
|
}
|
|
2109
2430
|
|
|
2110
2431
|
// src/core/web.review.kit.view.ts
|
|
2432
|
+
var DEFAULT_ADJUSTMENT_LABEL = "Responsive CSS px adjustments";
|
|
2111
2433
|
var WebReviewKitView = class {
|
|
2112
2434
|
constructor(config) {
|
|
2113
2435
|
this.config = config;
|
|
2114
2436
|
}
|
|
2437
|
+
clearDraftPreview() {
|
|
2438
|
+
this.restoreDraftPreview();
|
|
2439
|
+
}
|
|
2115
2440
|
render(shadow, hiddenItemsStyle) {
|
|
2116
2441
|
const state = this.state;
|
|
2442
|
+
this.syncDraftPreview(
|
|
2443
|
+
state.isOpen && state.mode === "element" ? state.noteDraft : void 0
|
|
2444
|
+
);
|
|
2117
2445
|
shadow.replaceChildren();
|
|
2118
2446
|
shadow.append(createStyleElement());
|
|
2119
2447
|
shadow.append(hiddenItemsStyle);
|
|
2448
|
+
const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
|
|
2120
2449
|
const shell = document.createElement("div");
|
|
2121
|
-
shell.className =
|
|
2450
|
+
shell.className = [
|
|
2451
|
+
"dfwr-shell",
|
|
2452
|
+
state.isOpen ? "is-open" : "",
|
|
2453
|
+
hasDismissableDraft ? "has-dismissible-draft" : ""
|
|
2454
|
+
].filter(Boolean).join(" ");
|
|
2122
2455
|
shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
|
|
2123
2456
|
if (this.config.options.ui?.panel !== false) {
|
|
2124
2457
|
const panel = document.createElement("div");
|
|
@@ -2134,6 +2467,9 @@ var WebReviewKitView = class {
|
|
|
2134
2467
|
shell.append(panel);
|
|
2135
2468
|
}
|
|
2136
2469
|
shell.append(this.createMarkerLayer());
|
|
2470
|
+
if (state.isOpen && hasDismissableDraft) {
|
|
2471
|
+
shell.append(this.createDraftCancelLayer());
|
|
2472
|
+
}
|
|
2137
2473
|
if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
|
|
2138
2474
|
shell.append(
|
|
2139
2475
|
state.noteDraft ? this.createNotePopover(state.noteDraft) : state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
|
|
@@ -2153,6 +2489,294 @@ var WebReviewKitView = class {
|
|
|
2153
2489
|
get state() {
|
|
2154
2490
|
return this.config.getState();
|
|
2155
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
|
+
}
|
|
2156
2780
|
createHeader() {
|
|
2157
2781
|
const header = document.createElement("div");
|
|
2158
2782
|
header.className = "dfwr-header";
|
|
@@ -2244,15 +2868,20 @@ var WebReviewKitView = class {
|
|
|
2244
2868
|
const group = document.createElement("div");
|
|
2245
2869
|
group.className = "dfwr-note-draft";
|
|
2246
2870
|
if (!environment) return group;
|
|
2247
|
-
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;
|
|
2248
2877
|
if (draft.selection) {
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
)
|
|
2878
|
+
const selection = toViewportSelection(draft.selection.viewport);
|
|
2879
|
+
selectionHighlight = this.createSelectionHighlight(
|
|
2880
|
+
isElementDraft ? this.getAdjustedDraftSelection(selection, draft) : selection,
|
|
2881
|
+
environment,
|
|
2882
|
+
true
|
|
2255
2883
|
);
|
|
2884
|
+
group.append(selectionHighlight);
|
|
2256
2885
|
}
|
|
2257
2886
|
const pin = document.createElement("button");
|
|
2258
2887
|
pin.className = "dfwr-note-pin";
|
|
@@ -2262,14 +2891,35 @@ var WebReviewKitView = class {
|
|
|
2262
2891
|
pin.style.top = `${hostPoint.y}px`;
|
|
2263
2892
|
const popover = document.createElement("div");
|
|
2264
2893
|
const position = getPopoverPosition(hostPoint, environment);
|
|
2265
|
-
popover.className =
|
|
2266
|
-
|
|
2267
|
-
|
|
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
|
+
}
|
|
2268
2916
|
const form = document.createElement("form");
|
|
2269
2917
|
form.className = "dfwr-form";
|
|
2270
|
-
const meta = document.createElement("div");
|
|
2271
|
-
meta
|
|
2272
|
-
|
|
2918
|
+
const meta = isElementDraft ? void 0 : document.createElement("div");
|
|
2919
|
+
if (meta) {
|
|
2920
|
+
meta.className = "dfwr-item-date";
|
|
2921
|
+
meta.textContent = formatNoteDraftMeta(draft);
|
|
2922
|
+
}
|
|
2273
2923
|
const textarea = document.createElement("textarea");
|
|
2274
2924
|
textarea.className = "dfwr-textarea";
|
|
2275
2925
|
textarea.placeholder = "Review comment";
|
|
@@ -2283,25 +2933,306 @@ var WebReviewKitView = class {
|
|
|
2283
2933
|
comment: textarea.value
|
|
2284
2934
|
});
|
|
2285
2935
|
});
|
|
2286
|
-
const
|
|
2936
|
+
const saveDraft = () => {
|
|
2287
2937
|
const comment = textarea.value.trim();
|
|
2288
2938
|
if (!comment) return;
|
|
2939
|
+
const currentDraft = this.state.noteDraft ?? draft;
|
|
2289
2940
|
void this.config.actions.createItem({
|
|
2290
2941
|
kind: "note",
|
|
2291
|
-
comment,
|
|
2292
|
-
viewport:
|
|
2293
|
-
anchor:
|
|
2294
|
-
marker:
|
|
2295
|
-
selection:
|
|
2942
|
+
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
2943
|
+
viewport: currentDraft.viewport,
|
|
2944
|
+
anchor: currentDraft.anchor,
|
|
2945
|
+
marker: currentDraft.marker,
|
|
2946
|
+
selection: currentDraft.selection
|
|
2296
2947
|
});
|
|
2297
|
-
}
|
|
2298
|
-
|
|
2299
|
-
|
|
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);
|
|
2300
2970
|
group.append(pin, popover);
|
|
2301
|
-
|
|
2302
|
-
|
|
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);
|
|
2303
2994
|
return group;
|
|
2304
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
|
+
}
|
|
2305
3236
|
createAreaForm() {
|
|
2306
3237
|
const form = document.createElement("form");
|
|
2307
3238
|
form.className = "dfwr-form";
|
|
@@ -2313,14 +3244,20 @@ var WebReviewKitView = class {
|
|
|
2313
3244
|
form.append(empty);
|
|
2314
3245
|
return form;
|
|
2315
3246
|
}
|
|
2316
|
-
|
|
2317
|
-
meta.className = "dfwr-item-date";
|
|
2318
|
-
meta.textContent = formatAreaDraftMeta(areaDraft);
|
|
2319
|
-
form.append(meta);
|
|
3247
|
+
form.append(this.createAreaMetricsPanel(areaDraft));
|
|
2320
3248
|
const textarea = document.createElement("textarea");
|
|
2321
3249
|
textarea.className = "dfwr-textarea";
|
|
2322
3250
|
textarea.placeholder = "Area comment";
|
|
2323
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
|
+
});
|
|
2324
3261
|
const actions = this.createFormActions("Save area", () => {
|
|
2325
3262
|
const comment = textarea.value.trim();
|
|
2326
3263
|
const draft = this.state.areaDraft;
|
|
@@ -2337,6 +3274,25 @@ var WebReviewKitView = class {
|
|
|
2337
3274
|
form.append(textarea, actions);
|
|
2338
3275
|
return form;
|
|
2339
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
|
+
}
|
|
2340
3296
|
createAreaDraftOverlay(draft) {
|
|
2341
3297
|
const layer = document.createElement("div");
|
|
2342
3298
|
layer.className = "dfwr-area-preview-layer";
|
|
@@ -2365,23 +3321,37 @@ var WebReviewKitView = class {
|
|
|
2365
3321
|
createAreaDraftPopover(draft) {
|
|
2366
3322
|
const environment = this.config.getEnvironment();
|
|
2367
3323
|
const popover = document.createElement("div");
|
|
2368
|
-
popover.className = "dfwr-area-draft";
|
|
3324
|
+
popover.className = "dfwr-area-draft is-composer";
|
|
2369
3325
|
if (environment && draft.selection) {
|
|
2370
3326
|
const selection = toHostSelection(
|
|
2371
3327
|
toViewportSelection(draft.selection.viewport),
|
|
2372
3328
|
environment
|
|
2373
3329
|
);
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2376
|
-
|
|
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`;
|
|
2377
3339
|
popover.style.right = "auto";
|
|
2378
3340
|
}
|
|
2379
|
-
|
|
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
|
+
});
|
|
2380
3350
|
return popover;
|
|
2381
3351
|
}
|
|
2382
|
-
createFormActions(saveLabel, onSave) {
|
|
3352
|
+
createFormActions(saveLabel, onSave, options) {
|
|
2383
3353
|
const actions = document.createElement("div");
|
|
2384
|
-
actions.className = "dfwr-actions";
|
|
3354
|
+
actions.className = ["dfwr-actions", options?.className].filter(Boolean).join(" ");
|
|
2385
3355
|
const save = document.createElement("button");
|
|
2386
3356
|
save.className = "dfwr-button is-primary";
|
|
2387
3357
|
save.type = "button";
|
|
@@ -2396,6 +3366,10 @@ var WebReviewKitView = class {
|
|
|
2396
3366
|
this.config.actions.clearDrafts();
|
|
2397
3367
|
this.config.actions.render();
|
|
2398
3368
|
});
|
|
3369
|
+
if (options?.beforeSave?.length || options?.className) {
|
|
3370
|
+
actions.append(cancel, ...options.beforeSave ?? [], save);
|
|
3371
|
+
return actions;
|
|
3372
|
+
}
|
|
2399
3373
|
actions.append(save, cancel);
|
|
2400
3374
|
return actions;
|
|
2401
3375
|
}
|
|
@@ -2600,11 +3574,13 @@ ${formatItemMeta(item)}`;
|
|
|
2600
3574
|
if (!environment) return;
|
|
2601
3575
|
const nextPoint = clampPoint(toTargetPoint(hostPoint, environment), environment);
|
|
2602
3576
|
const nextHostPoint = toHostPoint(nextPoint, environment);
|
|
2603
|
-
const position = getPopoverPosition(nextHostPoint, environment);
|
|
2604
3577
|
pin.style.left = `${nextHostPoint.x}px`;
|
|
2605
3578
|
pin.style.top = `${nextHostPoint.y}px`;
|
|
2606
|
-
popover
|
|
2607
|
-
|
|
3579
|
+
if (popover) {
|
|
3580
|
+
const position = getPopoverPosition(nextHostPoint, environment);
|
|
3581
|
+
popover.style.left = `${position.left}px`;
|
|
3582
|
+
popover.style.top = `${position.top}px`;
|
|
3583
|
+
}
|
|
2608
3584
|
const noteDraft = this.state.noteDraft;
|
|
2609
3585
|
if (!noteDraft) return;
|
|
2610
3586
|
const nextDraft = {
|
|
@@ -2616,7 +3592,9 @@ ${formatItemMeta(item)}`;
|
|
|
2616
3592
|
comment: textarea.value
|
|
2617
3593
|
};
|
|
2618
3594
|
this.config.actions.setNoteDraft(nextDraft);
|
|
2619
|
-
|
|
3595
|
+
if (meta) {
|
|
3596
|
+
meta.textContent = formatNoteDraftMeta(nextDraft);
|
|
3597
|
+
}
|
|
2620
3598
|
};
|
|
2621
3599
|
pin.addEventListener("pointerdown", (event) => {
|
|
2622
3600
|
if (event.button !== 0) return;
|
|
@@ -2770,6 +3748,13 @@ ${formatItemMeta(item)}`;
|
|
|
2770
3748
|
|
|
2771
3749
|
// src/core/web.review.kit.app.ts
|
|
2772
3750
|
var ROOT_ID = "df-web-review-kit-root";
|
|
3751
|
+
function isEditableEventTarget(event) {
|
|
3752
|
+
const path = event.composedPath?.() ?? [];
|
|
3753
|
+
const element = path[0] ?? event.target;
|
|
3754
|
+
if (!element || typeof element.tagName !== "string") return false;
|
|
3755
|
+
const tag = element.tagName;
|
|
3756
|
+
return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || element.isContentEditable === true;
|
|
3757
|
+
}
|
|
2773
3758
|
function createWebReviewKit(options) {
|
|
2774
3759
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
2775
3760
|
return createNoopController();
|
|
@@ -2802,7 +3787,7 @@ var WebReviewKitApp = class {
|
|
|
2802
3787
|
event.stopPropagation();
|
|
2803
3788
|
return;
|
|
2804
3789
|
}
|
|
2805
|
-
if (!isHotkey(event, this.hotkey)) return;
|
|
3790
|
+
if (isEditableEventTarget(event) || !isHotkey(event, this.hotkey)) return;
|
|
2806
3791
|
event.preventDefault();
|
|
2807
3792
|
event.stopPropagation();
|
|
2808
3793
|
this.toggle();
|
|
@@ -2842,6 +3827,9 @@ var WebReviewKitApp = class {
|
|
|
2842
3827
|
setNoteDraft: (draft) => {
|
|
2843
3828
|
this.noteDraft = draft;
|
|
2844
3829
|
},
|
|
3830
|
+
setAreaDraft: (draft) => {
|
|
3831
|
+
this.areaDraft = draft;
|
|
3832
|
+
},
|
|
2845
3833
|
setSelectingArea: (isSelectingArea) => {
|
|
2846
3834
|
this.isSelectingArea = isSelectingArea;
|
|
2847
3835
|
},
|
|
@@ -2867,6 +3855,7 @@ var WebReviewKitApp = class {
|
|
|
2867
3855
|
this.render();
|
|
2868
3856
|
}
|
|
2869
3857
|
destroy() {
|
|
3858
|
+
this.view.clearDraftPreview();
|
|
2870
3859
|
document.removeEventListener("keydown", this.handleKeyDown, true);
|
|
2871
3860
|
window.removeEventListener("scroll", this.handleViewportChange, true);
|
|
2872
3861
|
window.removeEventListener("resize", this.handleViewportChange);
|
|
@@ -3077,7 +4066,7 @@ var WebReviewKitApp = class {
|
|
|
3077
4066
|
);
|
|
3078
4067
|
const elementSelection = anchor ? getElementViewportSelection(anchor, environment) : void 0;
|
|
3079
4068
|
const selection = elementSelection ?? getPointSelection(nextPoint);
|
|
3080
|
-
const markerPoint = getSelectionCenter(selection);
|
|
4069
|
+
const markerPoint = elementSelection ? { x: selection.left, y: selection.top } : getSelectionCenter(selection);
|
|
3081
4070
|
const reviewSelection = elementSelection ? {
|
|
3082
4071
|
viewport: toPublicSelection(elementSelection),
|
|
3083
4072
|
relative: getRelativeSelection(
|