@designfever/web-review-kit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/dist/{chunk-QFNYQCTA.js → chunk-TWCSIBMY.js} +236 -116
- package/dist/chunk-TWCSIBMY.js.map +1 -0
- package/dist/index.cjs +233 -115
- 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 +2585 -971
- package/dist/react-shell.cjs.map +1 -1
- package/dist/react-shell.d.cts +19 -1
- package/dist/react-shell.d.ts +19 -1
- package/dist/react-shell.js +1967 -469
- package/dist/react-shell.js.map +1 -1
- package/dist/{types-D_qYtwTs.d.cts → types-RvVa5ns-.d.cts} +1 -0
- package/dist/{types-D_qYtwTs.d.ts → types-RvVa5ns-.d.ts} +1 -0
- package/dist/vite.cjs +50 -0
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +17 -1
- package/dist/vite.d.ts +17 -1
- package/dist/vite.js +49 -0
- package/dist/vite.js.map +1 -1
- package/docs/adaptor.sample.ts +2 -0
- package/docs/installation.md +36 -3
- package/docs/release-notes-0.5.0.md +134 -0
- package/package.json +1 -1
- package/dist/chunk-QFNYQCTA.js.map +0 -1
package/README.md
CHANGED
|
@@ -92,12 +92,15 @@ Browser env must use a Supabase `anon` key only. Do not put `service_role` or Op
|
|
|
92
92
|
```ts
|
|
93
93
|
import { createWebReviewKit, localAdapter } from '@designfever/web-review-kit';
|
|
94
94
|
import { mountReviewShell } from '@designfever/web-review-kit/react-shell';
|
|
95
|
-
import {
|
|
95
|
+
import {
|
|
96
|
+
reviewDataLocator,
|
|
97
|
+
reviewSourceLocator,
|
|
98
|
+
} from '@designfever/web-review-kit/vite';
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
- `@designfever/web-review-kit`: core API, adapters, shared types.
|
|
99
102
|
- `@designfever/web-review-kit/react-shell`: review shell UI, presence adapters, page glob helper.
|
|
100
|
-
- `@designfever/web-review-kit/vite`: dev-only
|
|
103
|
+
- `@designfever/web-review-kit/vite`: dev-only source/data locators for review hints.
|
|
101
104
|
- `src/*` is not a public import path.
|
|
102
105
|
|
|
103
106
|
## Optional Source Locator
|
|
@@ -106,7 +109,10 @@ For local QA, add the Vite plugin to inject source hints into rendered DOM nodes
|
|
|
106
109
|
|
|
107
110
|
```ts
|
|
108
111
|
import { defineConfig } from 'vite';
|
|
109
|
-
import {
|
|
112
|
+
import {
|
|
113
|
+
reviewDataLocator,
|
|
114
|
+
reviewSourceLocator,
|
|
115
|
+
} from '@designfever/web-review-kit/vite';
|
|
110
116
|
|
|
111
117
|
export default defineConfig({
|
|
112
118
|
plugins: [
|
|
@@ -115,11 +121,16 @@ export default defineConfig({
|
|
|
115
121
|
include: ['src'],
|
|
116
122
|
filePath: 'absolute',
|
|
117
123
|
}),
|
|
124
|
+
reviewDataLocator({
|
|
125
|
+
enabled: true,
|
|
126
|
+
include: ['src/data'],
|
|
127
|
+
filePath: 'absolute',
|
|
128
|
+
}),
|
|
118
129
|
],
|
|
119
130
|
});
|
|
120
131
|
```
|
|
121
132
|
|
|
122
|
-
When source hints are available, hold `Option` over the review target to inspect source candidates from the DOM ancestry. Click the target to pin the candidate list, then choose a file to open. DOM QA cards
|
|
133
|
+
When source hints are available, hold `Option` over the review target to inspect source candidates from the DOM ancestry. Click the target to pin the candidate list, then choose a file to open. The side rail can also open a Source Tree panel with section/source/data links. DOM QA cards show a source action when the saved item has source hints. Keep these plugins disabled for production builds because they write source paths into the DOM.
|
|
123
134
|
|
|
124
135
|
```tsx
|
|
125
136
|
mountReviewShell({
|
|
@@ -129,6 +140,10 @@ mountReviewShell({
|
|
|
129
140
|
sourceRoot: import.meta.env.VITE_REVIEW_SOURCE_ROOT,
|
|
130
141
|
sourceInspector: {
|
|
131
142
|
editor: 'cursor', // 'vscode' | 'cursor' | 'webstorm' | 'custom'
|
|
143
|
+
maxDepth: 9,
|
|
144
|
+
hoverOutline: true,
|
|
145
|
+
includePlacer: false,
|
|
146
|
+
ignore: ['core.section', 'control.render'],
|
|
132
147
|
// urlTemplate: 'my-editor://open?file={encodedPath}&line={line}&column={column}',
|
|
133
148
|
},
|
|
134
149
|
});
|
|
@@ -400,8 +400,22 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
|
|
|
400
400
|
source: getDomSourceHint(target)
|
|
401
401
|
};
|
|
402
402
|
}
|
|
403
|
-
function
|
|
404
|
-
|
|
403
|
+
function getDomAnchorFromElement(target, configuredAttribute = "data-qa-id", environment) {
|
|
404
|
+
if (target.ownerDocument !== environment.document) return void 0;
|
|
405
|
+
const candidates = createAnchorCandidates(target, configuredAttribute);
|
|
406
|
+
const primary = candidates[0];
|
|
407
|
+
if (!primary) return void 0;
|
|
408
|
+
return {
|
|
409
|
+
...primary,
|
|
410
|
+
candidates,
|
|
411
|
+
htmlSnippet: getElementHtmlSnippet(
|
|
412
|
+
getAnchorSourceElement(target, primary, configuredAttribute) ?? target
|
|
413
|
+
),
|
|
414
|
+
source: getDomSourceHint(target)
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function getElementViewportSelection(anchor, environment, preferredSelection) {
|
|
418
|
+
const element = getAnchorElement(anchor, environment, preferredSelection);
|
|
405
419
|
if (!element) return void 0;
|
|
406
420
|
const rect = element.getBoundingClientRect();
|
|
407
421
|
if (rect.width <= 0 || rect.height <= 0) return void 0;
|
|
@@ -440,22 +454,35 @@ function getAnchorCandidates(anchor) {
|
|
|
440
454
|
...anchor.candidates ?? []
|
|
441
455
|
]);
|
|
442
456
|
}
|
|
443
|
-
function resolveAnchorElement(anchor, environment) {
|
|
457
|
+
function resolveAnchorElement(anchor, environment, preferredSelection) {
|
|
444
458
|
const matches = getAnchorCandidates(anchor).flatMap((candidate) => {
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
+
const textFingerprint = candidate.textFingerprint ?? anchor.textFingerprint;
|
|
460
|
+
if (!preferredSelection) {
|
|
461
|
+
const match = queryBestAnchorCandidate(
|
|
462
|
+
candidate,
|
|
463
|
+
textFingerprint,
|
|
464
|
+
environment
|
|
465
|
+
);
|
|
466
|
+
if (!match) return [];
|
|
467
|
+
const confidence = roundRatio(
|
|
468
|
+
(candidate.confidence ?? 0.5) * match.score
|
|
469
|
+
);
|
|
470
|
+
return [{
|
|
471
|
+
element: match.element,
|
|
472
|
+
candidate,
|
|
473
|
+
confidence
|
|
474
|
+
}];
|
|
475
|
+
}
|
|
476
|
+
return queryAnchorElements(candidate.selector, environment).map((element) => {
|
|
477
|
+
const confidence = roundRatio(
|
|
478
|
+
(candidate.confidence ?? 0.5) * getTextFingerprintScore(textFingerprint, getTextFingerprint(element)) * getSelectionMatchScore(element, preferredSelection)
|
|
479
|
+
);
|
|
480
|
+
return {
|
|
481
|
+
element,
|
|
482
|
+
candidate,
|
|
483
|
+
confidence
|
|
484
|
+
};
|
|
485
|
+
});
|
|
459
486
|
});
|
|
460
487
|
return matches.sort((a, b) => b.confidence - a.confidence)[0];
|
|
461
488
|
}
|
|
@@ -465,8 +492,8 @@ function cssEscape(value) {
|
|
|
465
492
|
}
|
|
466
493
|
return value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
467
494
|
}
|
|
468
|
-
function getAnchorElement(anchor, environment) {
|
|
469
|
-
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment)?.element;
|
|
495
|
+
function getAnchorElement(anchor, environment, preferredSelection) {
|
|
496
|
+
return typeof anchor === "string" ? queryAnchorElement(anchor, environment) : resolveAnchorElement(anchor, environment, preferredSelection)?.element;
|
|
470
497
|
}
|
|
471
498
|
function createAnchorCandidates(target, configuredAttribute) {
|
|
472
499
|
const targetCandidates = [];
|
|
@@ -830,6 +857,38 @@ function getTextFingerprintScore(expected, actual) {
|
|
|
830
857
|
const matches = expectedTokens.filter((token) => actualTokens.has(token));
|
|
831
858
|
return clamp(matches.length / expectedTokens.length, 0.25, 0.76);
|
|
832
859
|
}
|
|
860
|
+
function getSelectionMatchScore(element, selection) {
|
|
861
|
+
const rect = element.getBoundingClientRect();
|
|
862
|
+
if (rect.width <= 0 || rect.height <= 0) return 0.05;
|
|
863
|
+
const overlapLeft = Math.max(rect.left, selection.left);
|
|
864
|
+
const overlapTop = Math.max(rect.top, selection.top);
|
|
865
|
+
const overlapRight = Math.min(rect.right, selection.left + selection.width);
|
|
866
|
+
const overlapBottom = Math.min(rect.bottom, selection.top + selection.height);
|
|
867
|
+
const overlapWidth = Math.max(0, overlapRight - overlapLeft);
|
|
868
|
+
const overlapHeight = Math.max(0, overlapBottom - overlapTop);
|
|
869
|
+
const overlapArea = overlapWidth * overlapHeight;
|
|
870
|
+
if (overlapArea > 0) {
|
|
871
|
+
const selectionArea = Math.max(1, selection.width * selection.height);
|
|
872
|
+
const rectArea = Math.max(1, rect.width * rect.height);
|
|
873
|
+
return 1 + overlapArea / Math.min(selectionArea, rectArea);
|
|
874
|
+
}
|
|
875
|
+
const rectCenterX = rect.left + rect.width / 2;
|
|
876
|
+
const rectCenterY = rect.top + rect.height / 2;
|
|
877
|
+
const selectionCenterX = selection.left + selection.width / 2;
|
|
878
|
+
const selectionCenterY = selection.top + selection.height / 2;
|
|
879
|
+
const distance = Math.hypot(
|
|
880
|
+
rectCenterX - selectionCenterX,
|
|
881
|
+
rectCenterY - selectionCenterY
|
|
882
|
+
);
|
|
883
|
+
const basis = Math.max(
|
|
884
|
+
1,
|
|
885
|
+
rect.width,
|
|
886
|
+
rect.height,
|
|
887
|
+
selection.width,
|
|
888
|
+
selection.height
|
|
889
|
+
);
|
|
890
|
+
return clamp(1 / (1 + distance / basis), 0.05, 0.95);
|
|
891
|
+
}
|
|
833
892
|
function getFingerprintTokens(value) {
|
|
834
893
|
return value.toLowerCase().split(/[\s/|,.:;()[\]{}"'`~!?<>]+/).map((token) => token.trim()).filter((token) => token.length > 1);
|
|
835
894
|
}
|
|
@@ -1791,6 +1850,12 @@ function createStyleElement() {
|
|
|
1791
1850
|
outline-offset: 1px;
|
|
1792
1851
|
}
|
|
1793
1852
|
|
|
1853
|
+
@media (hover: none) and (pointer: coarse) {
|
|
1854
|
+
.dfwr-textarea {
|
|
1855
|
+
font-size: 16px;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1794
1859
|
.dfwr-adjust-panel {
|
|
1795
1860
|
display: grid;
|
|
1796
1861
|
gap: 4px;
|
|
@@ -1864,32 +1929,6 @@ function createStyleElement() {
|
|
|
1864
1929
|
pointer-events: none;
|
|
1865
1930
|
}
|
|
1866
1931
|
|
|
1867
|
-
.dfwr-adjust-hud {
|
|
1868
|
-
position: fixed;
|
|
1869
|
-
z-index: 5;
|
|
1870
|
-
display: inline-flex;
|
|
1871
|
-
align-items: center;
|
|
1872
|
-
min-height: 22px;
|
|
1873
|
-
padding: 0 8px;
|
|
1874
|
-
border: 1px solid rgba(99, 215, 199, 0.72);
|
|
1875
|
-
border-radius: var(--df-review-radius-sm);
|
|
1876
|
-
background: rgba(21, 25, 29, 0.92);
|
|
1877
|
-
box-shadow:
|
|
1878
|
-
0 0 0 3px rgba(99, 215, 199, 0.14),
|
|
1879
|
-
0 8px 18px rgba(0, 0, 0, 0.26);
|
|
1880
|
-
color: #63d7c7;
|
|
1881
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
1882
|
-
font-size: var(--df-review-font-size-2xs);
|
|
1883
|
-
font-weight: 800;
|
|
1884
|
-
line-height: 1;
|
|
1885
|
-
pointer-events: none;
|
|
1886
|
-
white-space: nowrap;
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
.dfwr-adjust-hud[hidden] {
|
|
1890
|
-
display: none;
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
1932
|
.dfwr-empty,
|
|
1894
1933
|
.dfwr-error {
|
|
1895
1934
|
margin: 0;
|
|
@@ -2252,7 +2291,6 @@ var WebReviewKitView = class {
|
|
|
2252
2291
|
if (event.button !== 0) return;
|
|
2253
2292
|
cancel(event);
|
|
2254
2293
|
});
|
|
2255
|
-
layer.addEventListener("click", cancel);
|
|
2256
2294
|
return layer;
|
|
2257
2295
|
}
|
|
2258
2296
|
getDraftAdjustmentMetrics(draft) {
|
|
@@ -2432,14 +2470,6 @@ var WebReviewKitView = class {
|
|
|
2432
2470
|
if (!draft.selection) return void 0;
|
|
2433
2471
|
return toViewportSelection(draft.selection.viewport);
|
|
2434
2472
|
}
|
|
2435
|
-
formatDraftAdjustmentStatus(draft) {
|
|
2436
|
-
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2437
|
-
return [
|
|
2438
|
-
`x ${this.formatSignedPx(metrics.x)}`,
|
|
2439
|
-
`y ${this.formatSignedPx(metrics.y)}`,
|
|
2440
|
-
`scale ${this.formatSignedPx(metrics.scale)}`
|
|
2441
|
-
].join(" / ");
|
|
2442
|
-
}
|
|
2443
2473
|
getDraftAdjustmentMetricLines(draft) {
|
|
2444
2474
|
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2445
2475
|
return [
|
|
@@ -2451,6 +2481,7 @@ var WebReviewKitView = class {
|
|
|
2451
2481
|
}
|
|
2452
2482
|
withDraftAdjustmentComment(comment, draft) {
|
|
2453
2483
|
if (!this.hasDraftAdjustment(draft)) return comment;
|
|
2484
|
+
const trimmedComment = comment.trim();
|
|
2454
2485
|
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2455
2486
|
const adjustment = [
|
|
2456
2487
|
`${this.getAdjustmentLabel()}: x ${this.formatSignedPx(
|
|
@@ -2462,12 +2493,20 @@ var WebReviewKitView = class {
|
|
|
2462
2493
|
metrics.viewportWidth
|
|
2463
2494
|
)}/design ${Math.round(metrics.designWidth)})`
|
|
2464
2495
|
].join(" ");
|
|
2465
|
-
return `${
|
|
2466
|
-
${adjustment}
|
|
2496
|
+
return trimmedComment ? `${trimmedComment}
|
|
2497
|
+
${adjustment}` : adjustment;
|
|
2467
2498
|
}
|
|
2468
2499
|
getStyleableDraftElement(draft, environment) {
|
|
2500
|
+
if (draft.previewElement && draft.previewElement.ownerDocument === environment.document && "style" in draft.previewElement) {
|
|
2501
|
+
return draft.previewElement;
|
|
2502
|
+
}
|
|
2469
2503
|
if (!draft.anchor) return void 0;
|
|
2470
|
-
const
|
|
2504
|
+
const preferredSelection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2505
|
+
const element = resolveAnchorElement(
|
|
2506
|
+
draft.anchor,
|
|
2507
|
+
environment,
|
|
2508
|
+
preferredSelection
|
|
2509
|
+
)?.element;
|
|
2471
2510
|
if (!element) return void 0;
|
|
2472
2511
|
if ("style" in element) return element;
|
|
2473
2512
|
return void 0;
|
|
@@ -2487,39 +2526,77 @@ ${adjustment}`;
|
|
|
2487
2526
|
this.restoreDraftPreview();
|
|
2488
2527
|
}
|
|
2489
2528
|
if (!this.draftPreview) {
|
|
2490
|
-
const
|
|
2529
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2530
|
+
const clone = element.cloneNode(true);
|
|
2531
|
+
this.removeDuplicateIds(clone);
|
|
2532
|
+
this.copyComputedStyle(element, clone, environment);
|
|
2533
|
+
this.positionDraftPreviewClone(clone, element, computedStyle);
|
|
2534
|
+
environment.document.body?.appendChild(clone);
|
|
2491
2535
|
this.draftPreview = {
|
|
2492
2536
|
element,
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
transition: element.style.transition,
|
|
2496
|
-
willChange: element.style.willChange,
|
|
2497
|
-
baseTransform: element.style.transform || (computedTransform && computedTransform !== "none" ? computedTransform : "")
|
|
2537
|
+
clone,
|
|
2538
|
+
visibility: element.style.visibility
|
|
2498
2539
|
};
|
|
2540
|
+
element.style.visibility = "hidden";
|
|
2499
2541
|
}
|
|
2500
2542
|
const metrics = this.getDraftAdjustmentMetrics(draft);
|
|
2501
2543
|
const translate = `translate(${this.toCssNumber(metrics.cssX)}px, ${this.toCssNumber(
|
|
2502
2544
|
metrics.cssY
|
|
2503
2545
|
)}px)`;
|
|
2504
2546
|
const scale = metrics.scaleFactor === 1 ? "" : `scale(${this.toCssNumber(metrics.scaleFactor)})`;
|
|
2505
|
-
|
|
2506
|
-
element.style.willChange = "transform";
|
|
2507
|
-
element.style.transformOrigin = "top left";
|
|
2508
|
-
element.style.transform = [
|
|
2509
|
-
this.draftPreview.baseTransform,
|
|
2510
|
-
translate,
|
|
2511
|
-
scale
|
|
2512
|
-
].filter(Boolean).join(" ");
|
|
2547
|
+
this.draftPreview.clone.style.transform = [translate, scale].filter(Boolean).join(" ");
|
|
2513
2548
|
}
|
|
2514
2549
|
restoreDraftPreview() {
|
|
2515
2550
|
if (!this.draftPreview) return;
|
|
2516
|
-
const { element,
|
|
2517
|
-
|
|
2518
|
-
element.style.
|
|
2519
|
-
element.style.transition = transition;
|
|
2520
|
-
element.style.willChange = willChange;
|
|
2551
|
+
const { element, clone, visibility } = this.draftPreview;
|
|
2552
|
+
clone.remove();
|
|
2553
|
+
element.style.visibility = visibility;
|
|
2521
2554
|
this.draftPreview = void 0;
|
|
2522
2555
|
}
|
|
2556
|
+
positionDraftPreviewClone(clone, element, computedStyle) {
|
|
2557
|
+
const rect = element.getBoundingClientRect();
|
|
2558
|
+
clone.setAttribute("data-dfwr-adjust-preview", "true");
|
|
2559
|
+
clone.setAttribute("aria-hidden", "true");
|
|
2560
|
+
clone.style.position = "fixed";
|
|
2561
|
+
clone.style.left = `${this.toCssNumber(rect.left)}px`;
|
|
2562
|
+
clone.style.top = `${this.toCssNumber(rect.top)}px`;
|
|
2563
|
+
clone.style.right = "auto";
|
|
2564
|
+
clone.style.bottom = "auto";
|
|
2565
|
+
clone.style.width = `${this.toCssNumber(rect.width)}px`;
|
|
2566
|
+
clone.style.height = `${this.toCssNumber(rect.height)}px`;
|
|
2567
|
+
clone.style.maxWidth = "none";
|
|
2568
|
+
clone.style.maxHeight = "none";
|
|
2569
|
+
clone.style.margin = "0";
|
|
2570
|
+
clone.style.boxSizing = "border-box";
|
|
2571
|
+
clone.style.display = this.getDraftPreviewDisplay(computedStyle.display);
|
|
2572
|
+
clone.style.zIndex = "2147483646";
|
|
2573
|
+
clone.style.pointerEvents = "none";
|
|
2574
|
+
clone.style.transition = "none";
|
|
2575
|
+
clone.style.willChange = "transform";
|
|
2576
|
+
clone.style.transformOrigin = "top left";
|
|
2577
|
+
clone.style.transform = "none";
|
|
2578
|
+
}
|
|
2579
|
+
getDraftPreviewDisplay(display) {
|
|
2580
|
+
if (display === "inline" || display === "contents") return "inline-block";
|
|
2581
|
+
return display || "block";
|
|
2582
|
+
}
|
|
2583
|
+
copyComputedStyle(element, clone, environment) {
|
|
2584
|
+
const computedStyle = environment.window.getComputedStyle(element);
|
|
2585
|
+
for (let index = 0; index < computedStyle.length; index += 1) {
|
|
2586
|
+
const property = computedStyle.item(index);
|
|
2587
|
+
clone.style.setProperty(
|
|
2588
|
+
property,
|
|
2589
|
+
computedStyle.getPropertyValue(property),
|
|
2590
|
+
computedStyle.getPropertyPriority(property)
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
removeDuplicateIds(element) {
|
|
2595
|
+
element.removeAttribute("id");
|
|
2596
|
+
element.querySelectorAll("[id]").forEach((child) => {
|
|
2597
|
+
child.removeAttribute("id");
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2523
2600
|
toCssNumber(value) {
|
|
2524
2601
|
return Math.round(value * 1e3) / 1e3;
|
|
2525
2602
|
}
|
|
@@ -2681,8 +2758,8 @@ ${adjustment}`;
|
|
|
2681
2758
|
});
|
|
2682
2759
|
const saveDraft = () => {
|
|
2683
2760
|
const comment = textarea.value.trim();
|
|
2684
|
-
if (!comment) return;
|
|
2685
2761
|
const currentDraft = this.state.noteDraft ?? draft;
|
|
2762
|
+
if (!comment && !this.hasDraftAdjustment(currentDraft)) return;
|
|
2686
2763
|
void this.config.actions.createItem({
|
|
2687
2764
|
kind: "note",
|
|
2688
2765
|
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
@@ -2692,13 +2769,8 @@ ${adjustment}`;
|
|
|
2692
2769
|
selection: currentDraft.selection
|
|
2693
2770
|
});
|
|
2694
2771
|
};
|
|
2695
|
-
const adjustmentHud = isElementDraft ? this.createAdjustmentHud(draft, environment) : void 0;
|
|
2696
|
-
if (adjustmentHud) {
|
|
2697
|
-
group.append(adjustmentHud);
|
|
2698
|
-
}
|
|
2699
2772
|
const adjustmentControls = isElementDraft ? this.createAdjustmentControls({
|
|
2700
2773
|
draft,
|
|
2701
|
-
hud: adjustmentHud,
|
|
2702
2774
|
pin,
|
|
2703
2775
|
popover,
|
|
2704
2776
|
selectionHighlight,
|
|
@@ -2826,7 +2898,6 @@ ${adjustment}`;
|
|
|
2826
2898
|
}
|
|
2827
2899
|
createAdjustmentControls({
|
|
2828
2900
|
draft,
|
|
2829
|
-
hud,
|
|
2830
2901
|
pin,
|
|
2831
2902
|
popover,
|
|
2832
2903
|
selectionHighlight,
|
|
@@ -2864,7 +2935,6 @@ ${adjustment}`;
|
|
|
2864
2935
|
scaleStatus.textContent = scaleLine;
|
|
2865
2936
|
this.syncDraftAdjustmentUi({
|
|
2866
2937
|
draft: nextDraft,
|
|
2867
|
-
hud,
|
|
2868
2938
|
pin,
|
|
2869
2939
|
selectionHighlight
|
|
2870
2940
|
});
|
|
@@ -2925,16 +2995,8 @@ ${adjustment}`;
|
|
|
2925
2995
|
if (event.key.toLowerCase() === "s") return { x: 0, y: 0, scale: -step };
|
|
2926
2996
|
return void 0;
|
|
2927
2997
|
}
|
|
2928
|
-
createAdjustmentHud(draft, environment) {
|
|
2929
|
-
const hud = document.createElement("div");
|
|
2930
|
-
hud.className = "dfwr-adjust-hud";
|
|
2931
|
-
hud.setAttribute("aria-hidden", "true");
|
|
2932
|
-
this.syncAdjustmentHud(hud, draft, environment);
|
|
2933
|
-
return hud;
|
|
2934
|
-
}
|
|
2935
2998
|
syncDraftAdjustmentUi({
|
|
2936
2999
|
draft,
|
|
2937
|
-
hud,
|
|
2938
3000
|
pin,
|
|
2939
3001
|
selectionHighlight
|
|
2940
3002
|
}) {
|
|
@@ -2959,26 +3021,8 @@ ${adjustment}`;
|
|
|
2959
3021
|
selectionHighlight.style.width = `${rect.width}px`;
|
|
2960
3022
|
selectionHighlight.style.height = `${rect.height}px`;
|
|
2961
3023
|
}
|
|
2962
|
-
if (hud) {
|
|
2963
|
-
this.syncAdjustmentHud(hud, draft, environment);
|
|
2964
|
-
}
|
|
2965
3024
|
this.syncDraftPreview(draft);
|
|
2966
3025
|
}
|
|
2967
|
-
syncAdjustmentHud(hud, draft, environment) {
|
|
2968
|
-
if (!draft.selection) return;
|
|
2969
|
-
const rect = toHostSelection(
|
|
2970
|
-
this.getAdjustedDraftSelection(
|
|
2971
|
-
toViewportSelection(draft.selection.viewport),
|
|
2972
|
-
draft
|
|
2973
|
-
),
|
|
2974
|
-
environment
|
|
2975
|
-
);
|
|
2976
|
-
const isVisible = draft.adjustment?.isActive === true || this.hasDraftAdjustment(draft);
|
|
2977
|
-
hud.hidden = !isVisible;
|
|
2978
|
-
hud.textContent = this.formatDraftAdjustmentStatus(draft);
|
|
2979
|
-
hud.style.left = `${Math.max(4, rect.left)}px`;
|
|
2980
|
-
hud.style.top = `${Math.max(4, rect.top - 28)}px`;
|
|
2981
|
-
}
|
|
2982
3026
|
createAreaForm() {
|
|
2983
3027
|
const form = document.createElement("form");
|
|
2984
3028
|
form.className = "dfwr-form";
|
|
@@ -3102,12 +3146,18 @@ ${adjustment}`;
|
|
|
3102
3146
|
save.className = "dfwr-button is-primary";
|
|
3103
3147
|
save.type = "button";
|
|
3104
3148
|
save.textContent = saveLabel;
|
|
3105
|
-
save.addEventListener("click",
|
|
3149
|
+
save.addEventListener("click", (event) => {
|
|
3150
|
+
event.preventDefault();
|
|
3151
|
+
event.stopPropagation();
|
|
3152
|
+
onSave();
|
|
3153
|
+
});
|
|
3106
3154
|
const cancel = document.createElement("button");
|
|
3107
3155
|
cancel.className = "dfwr-button";
|
|
3108
3156
|
cancel.type = "button";
|
|
3109
3157
|
cancel.textContent = "Cancel";
|
|
3110
|
-
cancel.addEventListener("click", () => {
|
|
3158
|
+
cancel.addEventListener("click", (event) => {
|
|
3159
|
+
event.preventDefault();
|
|
3160
|
+
event.stopPropagation();
|
|
3111
3161
|
this.config.actions.setModeState("idle");
|
|
3112
3162
|
this.config.actions.clearDrafts();
|
|
3113
3163
|
this.config.actions.render();
|
|
@@ -3512,6 +3562,7 @@ function createWebReviewKit(options) {
|
|
|
3512
3562
|
close: () => app.close(),
|
|
3513
3563
|
toggle: () => app.toggle(),
|
|
3514
3564
|
setMode: (mode) => app.setMode(mode),
|
|
3565
|
+
startElementReview: (element, comment) => app.startElementReview(element, comment),
|
|
3515
3566
|
getMode: () => app.getMode(),
|
|
3516
3567
|
highlightItem: (itemId) => app.highlightItem(itemId),
|
|
3517
3568
|
setHiddenItemIds: (itemIds) => app.setHiddenItemIds(itemIds),
|
|
@@ -3642,6 +3693,16 @@ var WebReviewKitApp = class {
|
|
|
3642
3693
|
this.areaDraft = void 0;
|
|
3643
3694
|
this.render();
|
|
3644
3695
|
}
|
|
3696
|
+
async startElementReview(element, comment) {
|
|
3697
|
+
if (!this.isOpen) {
|
|
3698
|
+
this.isOpen = true;
|
|
3699
|
+
}
|
|
3700
|
+
this.setModeState("element");
|
|
3701
|
+
this.noteDraft = void 0;
|
|
3702
|
+
this.areaDraft = void 0;
|
|
3703
|
+
this.isSelectingArea = false;
|
|
3704
|
+
await this.bindElementDraftToElement(element, comment);
|
|
3705
|
+
}
|
|
3645
3706
|
getMode() {
|
|
3646
3707
|
return this.mode;
|
|
3647
3708
|
}
|
|
@@ -3805,13 +3866,26 @@ var WebReviewKitApp = class {
|
|
|
3805
3866
|
const viewport = getViewportSize(environment);
|
|
3806
3867
|
const nextPoint = clampPoint(point, environment);
|
|
3807
3868
|
const draft = await this.withOverlayHidden(() => {
|
|
3869
|
+
const pointSelection = getPointSelection(nextPoint);
|
|
3870
|
+
const targetElement = environment.document.elementFromPoint(
|
|
3871
|
+
nextPoint.x,
|
|
3872
|
+
nextPoint.y
|
|
3873
|
+
);
|
|
3874
|
+
const previewElement = targetElement && "style" in targetElement ? targetElement : void 0;
|
|
3875
|
+
const targetRect = targetElement?.getBoundingClientRect();
|
|
3876
|
+
const clickedSelection = targetRect && targetRect.width > 0 && targetRect.height > 0 ? {
|
|
3877
|
+
left: targetRect.left,
|
|
3878
|
+
top: targetRect.top,
|
|
3879
|
+
width: targetRect.width,
|
|
3880
|
+
height: targetRect.height
|
|
3881
|
+
} : void 0;
|
|
3808
3882
|
const anchor = getDomAnchorFromPoint(
|
|
3809
3883
|
nextPoint,
|
|
3810
3884
|
this.options.anchors?.attribute,
|
|
3811
3885
|
environment
|
|
3812
3886
|
);
|
|
3813
|
-
const elementSelection = anchor ? getElementViewportSelection(anchor, environment) : void 0;
|
|
3814
|
-
const selection = elementSelection ??
|
|
3887
|
+
const elementSelection = anchor ? clickedSelection ?? getElementViewportSelection(anchor, environment, pointSelection) : void 0;
|
|
3888
|
+
const selection = elementSelection ?? pointSelection;
|
|
3815
3889
|
const markerPoint = elementSelection ? { x: selection.left, y: selection.top } : getSelectionCenter(selection);
|
|
3816
3890
|
const reviewSelection = elementSelection ? {
|
|
3817
3891
|
viewport: toPublicSelection(elementSelection),
|
|
@@ -3830,9 +3904,51 @@ var WebReviewKitApp = class {
|
|
|
3830
3904
|
anchor,
|
|
3831
3905
|
marker,
|
|
3832
3906
|
selection: reviewSelection,
|
|
3833
|
-
comment
|
|
3907
|
+
comment,
|
|
3908
|
+
previewElement
|
|
3909
|
+
};
|
|
3910
|
+
});
|
|
3911
|
+
this.noteDraft = draft;
|
|
3912
|
+
this.render();
|
|
3913
|
+
}
|
|
3914
|
+
async bindElementDraftToElement(element, comment) {
|
|
3915
|
+
const environment = this.getEnvironment();
|
|
3916
|
+
if (!environment || element.ownerDocument !== environment.document) return;
|
|
3917
|
+
const viewport = getViewportSize(environment);
|
|
3918
|
+
const draft = await this.withOverlayHidden(() => {
|
|
3919
|
+
const rect = element.getBoundingClientRect();
|
|
3920
|
+
if (rect.width <= 0 || rect.height <= 0) return void 0;
|
|
3921
|
+
const selection = {
|
|
3922
|
+
left: rect.left,
|
|
3923
|
+
top: rect.top,
|
|
3924
|
+
width: rect.width,
|
|
3925
|
+
height: rect.height
|
|
3926
|
+
};
|
|
3927
|
+
const anchor = getDomAnchorFromElement(
|
|
3928
|
+
element,
|
|
3929
|
+
this.options.anchors?.attribute,
|
|
3930
|
+
environment
|
|
3931
|
+
);
|
|
3932
|
+
const markerPoint = { x: selection.left, y: selection.top };
|
|
3933
|
+
const marker = {
|
|
3934
|
+
viewport: roundPoint(markerPoint),
|
|
3935
|
+
relative: anchor ? getRelativePoint(markerPoint, anchor, environment) : void 0
|
|
3936
|
+
};
|
|
3937
|
+
const reviewSelection = {
|
|
3938
|
+
viewport: toPublicSelection(selection),
|
|
3939
|
+
relative: anchor ? getRelativeSelection(selection, anchor, environment) : void 0
|
|
3940
|
+
};
|
|
3941
|
+
const previewElement = "style" in element ? element : void 0;
|
|
3942
|
+
return {
|
|
3943
|
+
viewport,
|
|
3944
|
+
anchor,
|
|
3945
|
+
marker,
|
|
3946
|
+
selection: reviewSelection,
|
|
3947
|
+
comment,
|
|
3948
|
+
previewElement
|
|
3834
3949
|
};
|
|
3835
3950
|
});
|
|
3951
|
+
if (!draft) return;
|
|
3836
3952
|
this.noteDraft = draft;
|
|
3837
3953
|
this.render();
|
|
3838
3954
|
}
|
|
@@ -3940,6 +4056,8 @@ function createNoopController() {
|
|
|
3940
4056
|
},
|
|
3941
4057
|
setMode() {
|
|
3942
4058
|
},
|
|
4059
|
+
async startElementReview() {
|
|
4060
|
+
},
|
|
3943
4061
|
getMode() {
|
|
3944
4062
|
return "idle";
|
|
3945
4063
|
},
|
|
@@ -3962,12 +4080,14 @@ export {
|
|
|
3962
4080
|
REVIEW_WORKFLOW_STATUS_OPTIONS,
|
|
3963
4081
|
normalizeReviewItemStatus,
|
|
3964
4082
|
localAdapter,
|
|
4083
|
+
clamp,
|
|
3965
4084
|
DEFAULT_REVIEW_VIEWPORTS,
|
|
3966
4085
|
findReviewViewportPreset,
|
|
3967
4086
|
getReviewViewportScope,
|
|
3968
4087
|
getReviewItemScope,
|
|
3969
4088
|
getReviewItemScopeLabel,
|
|
3970
4089
|
getNumberedReviewItems,
|
|
4090
|
+
runWithAutoScrollBehavior,
|
|
3971
4091
|
createWebReviewKit
|
|
3972
4092
|
};
|
|
3973
|
-
//# sourceMappingURL=chunk-
|
|
4093
|
+
//# sourceMappingURL=chunk-TWCSIBMY.js.map
|