@designfever/web-review-kit 0.5.0 → 0.7.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/.env.sample +29 -0
- package/README.md +36 -10
- package/dist/chunk-AB5B6O77.js +584 -0
- package/dist/chunk-AB5B6O77.js.map +1 -0
- package/dist/{chunk-TWCSIBMY.js → chunk-RPVLRULC.js} +736 -201
- package/dist/chunk-RPVLRULC.js.map +1 -0
- package/dist/image.types-BmzkFSPX.d.cts +71 -0
- package/dist/image.types-BmzkFSPX.d.ts +71 -0
- package/dist/index.cjs +1251 -202
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -3
- package/dist/index.d.ts +27 -3
- package/dist/index.js +50 -3
- package/dist/index.js.map +1 -1
- package/dist/react-shell.cjs +10135 -4070
- package/dist/react-shell.cjs.map +1 -1
- package/dist/react-shell.d.cts +37 -4
- package/dist/react-shell.d.ts +37 -4
- package/dist/react-shell.js +9258 -3707
- package/dist/react-shell.js.map +1 -1
- package/dist/token-Dt-ZH-YO.d.cts +88 -0
- package/dist/token-nJXPPdYX.d.ts +88 -0
- package/dist/{types-RvVa5ns-.d.cts → types-DT9Z66mV.d.cts} +14 -1
- package/dist/{types-RvVa5ns-.d.ts → types-DT9Z66mV.d.ts} +14 -1
- package/dist/vite.cjs +1116 -5
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +45 -1
- package/dist/vite.d.ts +45 -1
- package/dist/vite.js +800 -5
- package/dist/vite.js.map +1 -1
- package/docs/README.md +11 -5
- package/docs/adapters.md +126 -0
- package/docs/adaptor.sample.ts +13 -1
- package/docs/architecture.md +6 -1
- package/docs/code-review-0.6.0.md +232 -0
- package/docs/db-setup.md +4 -2
- package/docs/figma-image-mvp-0.7.0.md +327 -0
- package/docs/installation.md +44 -8
- package/docs/release-notes-0.6.0.md +108 -0
- package/docs/release-notes-0.7.0.md +128 -0
- package/package.json +6 -2
- package/dist/chunk-TWCSIBMY.js.map +0 -1
|
@@ -111,6 +111,9 @@ function normalizeStoredReviewItem(value) {
|
|
|
111
111
|
};
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// src/figma/image.types.ts
|
|
115
|
+
var DEFAULT_REVIEW_FIGMA_IMAGE_FORMAT = "webp";
|
|
116
|
+
|
|
114
117
|
// src/core/review/scope.ts
|
|
115
118
|
var DEFAULT_REVIEW_VIEWPORTS = [
|
|
116
119
|
{ label: "Mobile", width: 390, height: 720, scope: "mobile" },
|
|
@@ -389,13 +392,13 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
|
|
|
389
392
|
const target = environment.document.elementFromPoint(point.x, point.y);
|
|
390
393
|
if (!target) return void 0;
|
|
391
394
|
const candidates = createAnchorCandidates(target, configuredAttribute);
|
|
392
|
-
const
|
|
393
|
-
if (!
|
|
395
|
+
const primaryCandidate = candidates[0];
|
|
396
|
+
if (!primaryCandidate) return void 0;
|
|
394
397
|
return {
|
|
395
|
-
...
|
|
398
|
+
...primaryCandidate,
|
|
396
399
|
candidates,
|
|
397
400
|
htmlSnippet: getElementHtmlSnippet(
|
|
398
|
-
getAnchorSourceElement(target,
|
|
401
|
+
getAnchorSourceElement(target, primaryCandidate, configuredAttribute) ?? target
|
|
399
402
|
),
|
|
400
403
|
source: getDomSourceHint(target)
|
|
401
404
|
};
|
|
@@ -403,13 +406,13 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
|
|
|
403
406
|
function getDomAnchorFromElement(target, configuredAttribute = "data-qa-id", environment) {
|
|
404
407
|
if (target.ownerDocument !== environment.document) return void 0;
|
|
405
408
|
const candidates = createAnchorCandidates(target, configuredAttribute);
|
|
406
|
-
const
|
|
407
|
-
if (!
|
|
409
|
+
const primaryCandidate = candidates[0];
|
|
410
|
+
if (!primaryCandidate) return void 0;
|
|
408
411
|
return {
|
|
409
|
-
...
|
|
412
|
+
...primaryCandidate,
|
|
410
413
|
candidates,
|
|
411
414
|
htmlSnippet: getElementHtmlSnippet(
|
|
412
|
-
getAnchorSourceElement(target,
|
|
415
|
+
getAnchorSourceElement(target, primaryCandidate, configuredAttribute) ?? target
|
|
413
416
|
),
|
|
414
417
|
source: getDomSourceHint(target)
|
|
415
418
|
};
|
|
@@ -580,7 +583,7 @@ function createAnchorCandidates(target, configuredAttribute) {
|
|
|
580
583
|
function findClosestAttributeAnchor(target, attributeNames, confidence, options) {
|
|
581
584
|
for (const attributeName of attributeNames) {
|
|
582
585
|
const selector = `[${attributeName}]`;
|
|
583
|
-
const element =
|
|
586
|
+
const element = tryClosest(target, selector);
|
|
584
587
|
if (!element) continue;
|
|
585
588
|
const value = getStableAttributeValue(element, attributeName);
|
|
586
589
|
if (!value) continue;
|
|
@@ -686,7 +689,7 @@ function getAnchorSourceElement(target, candidate, configuredAttribute) {
|
|
|
686
689
|
return target;
|
|
687
690
|
}
|
|
688
691
|
}
|
|
689
|
-
function
|
|
692
|
+
function tryClosest(element, selector) {
|
|
690
693
|
try {
|
|
691
694
|
return element.closest(selector);
|
|
692
695
|
} catch {
|
|
@@ -1190,18 +1193,90 @@ function setDocumentScrollInstantly(environment, position) {
|
|
|
1190
1193
|
);
|
|
1191
1194
|
}
|
|
1192
1195
|
|
|
1196
|
+
// src/core/draft.metrics.ts
|
|
1197
|
+
function getDraftViewportScale(viewport, presets) {
|
|
1198
|
+
const preset = findReviewViewportPreset(viewport, presets);
|
|
1199
|
+
const designWidth = typeof preset.designWidth === "number" && preset.designWidth > 0 ? preset.designWidth : viewport.width;
|
|
1200
|
+
const scale = designWidth > 0 ? viewport.width / designWidth : 1;
|
|
1201
|
+
return { scale, designWidth, presetLabel: preset.label };
|
|
1202
|
+
}
|
|
1203
|
+
function getDraftAdjustmentMetrics(draft, presets) {
|
|
1204
|
+
const adjustment = draft.adjustment;
|
|
1205
|
+
const x = adjustment?.x ?? 0;
|
|
1206
|
+
const y = adjustment?.y ?? 0;
|
|
1207
|
+
const scale = adjustment?.scale ?? 0;
|
|
1208
|
+
const {
|
|
1209
|
+
scale: viewportScale,
|
|
1210
|
+
designWidth,
|
|
1211
|
+
presetLabel
|
|
1212
|
+
} = getDraftViewportScale(draft.viewport, presets);
|
|
1213
|
+
const selection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
1214
|
+
const scaleCssDelta = scale * viewportScale;
|
|
1215
|
+
const scaleFactor = selection && selection.width > 0 ? Math.max(
|
|
1216
|
+
1 / selection.width,
|
|
1217
|
+
(selection.width + scaleCssDelta) / selection.width
|
|
1218
|
+
) : 1;
|
|
1219
|
+
return {
|
|
1220
|
+
x,
|
|
1221
|
+
y,
|
|
1222
|
+
scale,
|
|
1223
|
+
cssX: x * viewportScale,
|
|
1224
|
+
cssY: y * viewportScale,
|
|
1225
|
+
scaleFactor,
|
|
1226
|
+
viewportScale,
|
|
1227
|
+
designWidth,
|
|
1228
|
+
presetLabel,
|
|
1229
|
+
viewportWidth: draft.viewport.width
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
function hasDraftAdjustment(draft, presets) {
|
|
1233
|
+
const metrics = getDraftAdjustmentMetrics(draft, presets);
|
|
1234
|
+
return metrics.x !== 0 || metrics.y !== 0 || metrics.scale !== 0;
|
|
1235
|
+
}
|
|
1236
|
+
function getAdjustedDraftPoint(point, draft, presets) {
|
|
1237
|
+
const metrics = getDraftAdjustmentMetrics(draft, presets);
|
|
1238
|
+
return {
|
|
1239
|
+
x: point.x + metrics.cssX,
|
|
1240
|
+
y: point.y + metrics.cssY
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
function getAdjustedDraftSelection(selection, draft, presets) {
|
|
1244
|
+
const metrics = getDraftAdjustmentMetrics(draft, presets);
|
|
1245
|
+
return {
|
|
1246
|
+
...selection,
|
|
1247
|
+
left: selection.left + metrics.cssX,
|
|
1248
|
+
top: selection.top + metrics.cssY,
|
|
1249
|
+
width: selection.width * metrics.scaleFactor,
|
|
1250
|
+
height: selection.height * metrics.scaleFactor
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// src/core/typography.tokens.ts
|
|
1255
|
+
var reviewTypographyTokens = `
|
|
1256
|
+
--df-review-font-sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
1257
|
+
--df-review-font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
|
1258
|
+
--df-review-font-size-3xs: 9px;
|
|
1259
|
+
--df-review-font-size-2xs: 10px;
|
|
1260
|
+
--df-review-font-size-xs: 11px;
|
|
1261
|
+
--df-review-font-size-sm: 12px;
|
|
1262
|
+
--df-review-font-size-md: 13px;
|
|
1263
|
+
--df-review-font-size-lg: 14px;
|
|
1264
|
+
--df-review-font-size-xl: 15px;
|
|
1265
|
+
--df-review-font-size-2xl: 18px;
|
|
1266
|
+
--df-review-font-weight-normal: 400;
|
|
1267
|
+
--df-review-font-weight-emphasis: 500;
|
|
1268
|
+
--df-review-line-height-tight: 1.25;
|
|
1269
|
+
--df-review-line-height-base: 1.42;
|
|
1270
|
+
--df-review-line-height-relaxed: 1.55;
|
|
1271
|
+
`;
|
|
1272
|
+
|
|
1193
1273
|
// src/core/overlay.style.ts
|
|
1194
1274
|
function createStyleElement() {
|
|
1195
1275
|
const style = document.createElement("style");
|
|
1196
1276
|
style.textContent = `
|
|
1197
1277
|
:host {
|
|
1198
1278
|
color-scheme: dark;
|
|
1199
|
-
|
|
1200
|
-
--df-review-font-size-2xs: 10px;
|
|
1201
|
-
--df-review-font-size-xs: 11px;
|
|
1202
|
-
--df-review-font-size-sm: 12px;
|
|
1203
|
-
--df-review-font-size-md: 13px;
|
|
1204
|
-
--df-review-font-size-xl: 15px;
|
|
1279
|
+
${reviewTypographyTokens}
|
|
1205
1280
|
--df-review-space-1: 4px;
|
|
1206
1281
|
--df-review-space-1-5: 6px;
|
|
1207
1282
|
--df-review-space-2: 8px;
|
|
@@ -1266,6 +1341,14 @@ function createStyleElement() {
|
|
|
1266
1341
|
cursor: default;
|
|
1267
1342
|
}
|
|
1268
1343
|
|
|
1344
|
+
.dfwr-shell.is-docked-composer {
|
|
1345
|
+
position: relative;
|
|
1346
|
+
inset: auto;
|
|
1347
|
+
z-index: auto;
|
|
1348
|
+
padding: 0;
|
|
1349
|
+
pointer-events: auto;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1269
1352
|
.dfwr-panel {
|
|
1270
1353
|
position: fixed;
|
|
1271
1354
|
right: 16px;
|
|
@@ -1292,8 +1375,8 @@ function createStyleElement() {
|
|
|
1292
1375
|
}
|
|
1293
1376
|
|
|
1294
1377
|
.dfwr-title {
|
|
1295
|
-
font-size:
|
|
1296
|
-
font-weight:
|
|
1378
|
+
font-size: var(--df-review-font-size-xl);
|
|
1379
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1297
1380
|
line-height: 1.25;
|
|
1298
1381
|
}
|
|
1299
1382
|
|
|
@@ -1337,11 +1420,15 @@ function createStyleElement() {
|
|
|
1337
1420
|
}
|
|
1338
1421
|
|
|
1339
1422
|
.dfwr-button {
|
|
1423
|
+
display: inline-flex;
|
|
1424
|
+
align-items: center;
|
|
1425
|
+
justify-content: center;
|
|
1426
|
+
gap: 6px;
|
|
1340
1427
|
min-height: var(--df-review-control-height-md);
|
|
1341
1428
|
padding: 0 12px;
|
|
1342
1429
|
border-radius: var(--df-review-radius-sm);
|
|
1343
1430
|
font-size: var(--df-review-font-size-sm);
|
|
1344
|
-
font-weight:
|
|
1431
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1345
1432
|
}
|
|
1346
1433
|
|
|
1347
1434
|
.dfwr-button:hover,
|
|
@@ -1357,6 +1444,21 @@ function createStyleElement() {
|
|
|
1357
1444
|
color: var(--df-review-color-accent-contrast);
|
|
1358
1445
|
}
|
|
1359
1446
|
|
|
1447
|
+
.dfwr-button:disabled {
|
|
1448
|
+
cursor: default;
|
|
1449
|
+
opacity: 0.62;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
.dfwr-spinner {
|
|
1453
|
+
display: inline-block;
|
|
1454
|
+
width: 12px;
|
|
1455
|
+
height: 12px;
|
|
1456
|
+
border: 2px solid currentColor;
|
|
1457
|
+
border-right-color: transparent;
|
|
1458
|
+
border-radius: 999px;
|
|
1459
|
+
animation: dfwr-spin 720ms linear infinite;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1360
1462
|
.dfwr-icon-button {
|
|
1361
1463
|
display: inline-flex;
|
|
1362
1464
|
align-items: center;
|
|
@@ -1366,7 +1468,7 @@ function createStyleElement() {
|
|
|
1366
1468
|
padding: 0 8px;
|
|
1367
1469
|
border-radius: var(--df-review-radius-sm);
|
|
1368
1470
|
font-size: var(--df-review-font-size-xs);
|
|
1369
|
-
font-weight:
|
|
1471
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1370
1472
|
line-height: 1;
|
|
1371
1473
|
text-transform: uppercase;
|
|
1372
1474
|
}
|
|
@@ -1521,7 +1623,7 @@ function createStyleElement() {
|
|
|
1521
1623
|
0 8px 18px rgba(0, 0, 0, 0.28);
|
|
1522
1624
|
color: #111820;
|
|
1523
1625
|
font-size: var(--df-review-font-size-2xs);
|
|
1524
|
-
font-weight:
|
|
1626
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1525
1627
|
line-height: 1;
|
|
1526
1628
|
pointer-events: none;
|
|
1527
1629
|
}
|
|
@@ -1547,7 +1649,7 @@ function createStyleElement() {
|
|
|
1547
1649
|
box-shadow: 0 0 0 4px rgba(var(--dfwr-scope-rgb), 0.18);
|
|
1548
1650
|
color: var(--dfwr-scope);
|
|
1549
1651
|
font-size: var(--df-review-font-size-2xs);
|
|
1550
|
-
font-weight:
|
|
1652
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1551
1653
|
}
|
|
1552
1654
|
|
|
1553
1655
|
.dfwr-bound-marker.is-highlighted {
|
|
@@ -1766,6 +1868,20 @@ function createStyleElement() {
|
|
|
1766
1868
|
border-color: rgba(99, 215, 199, 0.56);
|
|
1767
1869
|
}
|
|
1768
1870
|
|
|
1871
|
+
.dfwr-shell.is-docked-composer .dfwr-note-popover.is-docked-composer,
|
|
1872
|
+
.dfwr-shell.is-docked-composer .dfwr-area-draft.is-docked-composer {
|
|
1873
|
+
position: relative;
|
|
1874
|
+
left: auto;
|
|
1875
|
+
right: auto;
|
|
1876
|
+
top: auto;
|
|
1877
|
+
z-index: auto;
|
|
1878
|
+
max-height: none;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
.dfwr-shell.is-docked-composer .dfwr-textarea {
|
|
1882
|
+
min-height: 184px;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1769
1885
|
.dfwr-note-popover.is-dragging,
|
|
1770
1886
|
.dfwr-area-draft.is-dragging {
|
|
1771
1887
|
user-select: none;
|
|
@@ -1814,6 +1930,50 @@ function createStyleElement() {
|
|
|
1814
1930
|
padding: 0;
|
|
1815
1931
|
}
|
|
1816
1932
|
|
|
1933
|
+
.dfwr-actions.has-leading {
|
|
1934
|
+
align-items: center;
|
|
1935
|
+
justify-content: space-between;
|
|
1936
|
+
gap: 12px;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
.dfwr-actions-leading,
|
|
1940
|
+
.dfwr-actions-primary {
|
|
1941
|
+
display: flex;
|
|
1942
|
+
align-items: center;
|
|
1943
|
+
gap: 8px;
|
|
1944
|
+
min-width: 0;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
.dfwr-actions-primary {
|
|
1948
|
+
margin-left: auto;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading {
|
|
1952
|
+
align-items: stretch;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-button,
|
|
1956
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle {
|
|
1957
|
+
height: var(--df-review-control-height-md);
|
|
1958
|
+
min-height: var(--df-review-control-height-md);
|
|
1959
|
+
border-radius: var(--df-review-radius-sm);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-button {
|
|
1963
|
+
min-width: 96px;
|
|
1964
|
+
padding: 0 12px;
|
|
1965
|
+
font-size: var(--df-review-font-size-sm);
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle {
|
|
1969
|
+
width: var(--df-review-control-height-md);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
.dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle svg {
|
|
1973
|
+
width: 18px;
|
|
1974
|
+
height: 18px;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1817
1977
|
.dfwr-note-actions {
|
|
1818
1978
|
justify-content: flex-end;
|
|
1819
1979
|
}
|
|
@@ -1831,10 +1991,18 @@ function createStyleElement() {
|
|
|
1831
1991
|
gap: 10px;
|
|
1832
1992
|
}
|
|
1833
1993
|
|
|
1994
|
+
.dfwr-form-error {
|
|
1995
|
+
margin: 0;
|
|
1996
|
+
color: #ff8f61;
|
|
1997
|
+
font-size: var(--df-review-font-size-sm);
|
|
1998
|
+
line-height: 1.4;
|
|
1999
|
+
overflow-wrap: anywhere;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
.dfwr-input,
|
|
2003
|
+
.dfwr-select,
|
|
1834
2004
|
.dfwr-textarea {
|
|
1835
2005
|
width: 100%;
|
|
1836
|
-
min-height: 92px;
|
|
1837
|
-
resize: vertical;
|
|
1838
2006
|
border: 1px solid rgba(255, 255, 255, 0.16);
|
|
1839
2007
|
border-radius: var(--df-review-radius-sm);
|
|
1840
2008
|
padding: 10px;
|
|
@@ -1845,14 +2013,39 @@ function createStyleElement() {
|
|
|
1845
2013
|
line-height: 1.45;
|
|
1846
2014
|
}
|
|
1847
2015
|
|
|
2016
|
+
.dfwr-input,
|
|
2017
|
+
.dfwr-select {
|
|
2018
|
+
min-height: 38px;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
.dfwr-select {
|
|
2022
|
+
appearance: none;
|
|
2023
|
+
cursor: pointer;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
.dfwr-textarea {
|
|
2027
|
+
min-height: 92px;
|
|
2028
|
+
resize: vertical;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
.dfwr-input:focus,
|
|
2032
|
+
.dfwr-select:focus,
|
|
1848
2033
|
.dfwr-textarea:focus {
|
|
1849
2034
|
outline: 2px solid var(--df-review-color-accent-ring);
|
|
1850
2035
|
outline-offset: 1px;
|
|
1851
2036
|
}
|
|
1852
2037
|
|
|
1853
2038
|
@media (hover: none) and (pointer: coarse) {
|
|
2039
|
+
.dfwr-input,
|
|
2040
|
+
.dfwr-select,
|
|
1854
2041
|
.dfwr-textarea {
|
|
1855
|
-
font-size:
|
|
2042
|
+
font-size: var(--df-review-font-size-xl);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
@keyframes dfwr-spin {
|
|
2047
|
+
to {
|
|
2048
|
+
transform: rotate(360deg);
|
|
1856
2049
|
}
|
|
1857
2050
|
}
|
|
1858
2051
|
|
|
@@ -1910,8 +2103,8 @@ function createStyleElement() {
|
|
|
1910
2103
|
color: var(--df-review-color-text);
|
|
1911
2104
|
cursor: pointer;
|
|
1912
2105
|
font: inherit;
|
|
1913
|
-
font-size:
|
|
1914
|
-
font-weight:
|
|
2106
|
+
font-size: var(--df-review-font-size-lg);
|
|
2107
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1915
2108
|
line-height: 1;
|
|
1916
2109
|
}
|
|
1917
2110
|
|
|
@@ -1964,7 +2157,7 @@ function createStyleElement() {
|
|
|
1964
2157
|
margin-bottom: 10px;
|
|
1965
2158
|
color: rgba(247, 247, 242, 0.74);
|
|
1966
2159
|
font-size: var(--df-review-font-size-sm);
|
|
1967
|
-
font-weight:
|
|
2160
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
1968
2161
|
}
|
|
1969
2162
|
|
|
1970
2163
|
.dfwr-item {
|
|
@@ -1986,6 +2179,8 @@ function createStyleElement() {
|
|
|
1986
2179
|
}
|
|
1987
2180
|
|
|
1988
2181
|
.dfwr-item-body {
|
|
2182
|
+
display: grid;
|
|
2183
|
+
gap: 4px;
|
|
1989
2184
|
min-width: 0;
|
|
1990
2185
|
flex: 1;
|
|
1991
2186
|
}
|
|
@@ -2005,7 +2200,7 @@ function createStyleElement() {
|
|
|
2005
2200
|
border-radius: var(--df-review-radius-pill);
|
|
2006
2201
|
padding: 0 7px;
|
|
2007
2202
|
font-size: var(--df-review-font-size-2xs);
|
|
2008
|
-
font-weight:
|
|
2203
|
+
font-weight: var(--df-review-font-weight-emphasis);
|
|
2009
2204
|
line-height: 1;
|
|
2010
2205
|
letter-spacing: 0;
|
|
2011
2206
|
text-transform: uppercase;
|
|
@@ -2023,13 +2218,29 @@ function createStyleElement() {
|
|
|
2023
2218
|
color: rgba(247, 247, 242, 0.64);
|
|
2024
2219
|
}
|
|
2025
2220
|
|
|
2221
|
+
.dfwr-item-title {
|
|
2222
|
+
margin: 4px 0 0;
|
|
2223
|
+
color: var(--df-review-color-text);
|
|
2224
|
+
font-size: var(--df-review-font-size-md);
|
|
2225
|
+
font-weight: var(--df-review-font-weight-normal);
|
|
2226
|
+
line-height: 1.35;
|
|
2227
|
+
overflow-wrap: anywhere;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2026
2230
|
.dfwr-item-comment {
|
|
2231
|
+
margin: 0;
|
|
2232
|
+
color: var(--df-review-color-text-muted);
|
|
2233
|
+
font-size: var(--df-review-font-size-sm);
|
|
2234
|
+
line-height: 1.45;
|
|
2235
|
+
overflow-wrap: anywhere;
|
|
2236
|
+
white-space: pre-wrap;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
.dfwr-item-comment.is-primary {
|
|
2027
2240
|
margin: 4px 0;
|
|
2028
2241
|
color: var(--df-review-color-text);
|
|
2029
2242
|
font-size: var(--df-review-font-size-md);
|
|
2030
2243
|
line-height: 1.42;
|
|
2031
|
-
overflow-wrap: anywhere;
|
|
2032
|
-
white-space: pre-wrap;
|
|
2033
2244
|
}
|
|
2034
2245
|
|
|
2035
2246
|
.dfwr-item-date {
|
|
@@ -2138,10 +2349,12 @@ function createStyleElement() {
|
|
|
2138
2349
|
|
|
2139
2350
|
@media (max-width: 520px) {
|
|
2140
2351
|
.dfwr-panel {
|
|
2352
|
+
left: 8px;
|
|
2141
2353
|
right: 8px;
|
|
2142
|
-
top:
|
|
2143
|
-
|
|
2144
|
-
|
|
2354
|
+
top: auto;
|
|
2355
|
+
bottom: 8px;
|
|
2356
|
+
width: auto;
|
|
2357
|
+
max-height: min(70vh, calc(100vh - 16px));
|
|
2145
2358
|
}
|
|
2146
2359
|
}
|
|
2147
2360
|
`;
|
|
@@ -2221,6 +2434,7 @@ var WebReviewKitView = class {
|
|
|
2221
2434
|
}
|
|
2222
2435
|
clearDraftPreview() {
|
|
2223
2436
|
this.restoreDraftPreview();
|
|
2437
|
+
this.clearShellComposer();
|
|
2224
2438
|
}
|
|
2225
2439
|
render(shadow, hiddenItemsStyle) {
|
|
2226
2440
|
const state = this.state;
|
|
@@ -2231,11 +2445,13 @@ var WebReviewKitView = class {
|
|
|
2231
2445
|
shadow.append(createStyleElement());
|
|
2232
2446
|
shadow.append(hiddenItemsStyle);
|
|
2233
2447
|
const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
|
|
2448
|
+
const shouldDockComposer = this.config.options.ui?.panel === false && hasDismissableDraft && Boolean(this.getShellComposerHost());
|
|
2449
|
+
let dockedComposer;
|
|
2234
2450
|
const shell = document.createElement("div");
|
|
2235
2451
|
shell.className = [
|
|
2236
2452
|
"dfwr-shell",
|
|
2237
2453
|
state.isOpen ? "is-open" : "",
|
|
2238
|
-
hasDismissableDraft ? "has-dismissible-draft" : ""
|
|
2454
|
+
hasDismissableDraft && !shouldDockComposer ? "has-dismissible-draft" : ""
|
|
2239
2455
|
].filter(Boolean).join(" ");
|
|
2240
2456
|
shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
|
|
2241
2457
|
if (this.config.options.ui?.panel !== false) {
|
|
@@ -2252,105 +2468,119 @@ var WebReviewKitView = class {
|
|
|
2252
2468
|
shell.append(panel);
|
|
2253
2469
|
}
|
|
2254
2470
|
shell.append(this.createMarkerLayer());
|
|
2255
|
-
if (state.isOpen && hasDismissableDraft) {
|
|
2471
|
+
if (state.isOpen && hasDismissableDraft && !shouldDockComposer) {
|
|
2256
2472
|
shell.append(this.createDraftCancelLayer());
|
|
2257
2473
|
}
|
|
2258
2474
|
if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2475
|
+
if (state.noteDraft) {
|
|
2476
|
+
const noteDraft = this.createNotePopover(state.noteDraft, {
|
|
2477
|
+
dockComposer: shouldDockComposer
|
|
2478
|
+
});
|
|
2479
|
+
shell.append(noteDraft.layer);
|
|
2480
|
+
dockedComposer = noteDraft.composer;
|
|
2481
|
+
} else {
|
|
2482
|
+
shell.append(
|
|
2483
|
+
state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
|
|
2484
|
+
);
|
|
2485
|
+
}
|
|
2262
2486
|
}
|
|
2263
|
-
if (state.isOpen && state.mode === "area" && !state.areaDraft) {
|
|
2487
|
+
if (state.isOpen && state.mode === "area" && !state.areaDraft && !state.isSelectingArea) {
|
|
2264
2488
|
shell.append(this.createAreaLayer());
|
|
2265
2489
|
}
|
|
2266
2490
|
if (state.isOpen && state.mode === "area" && state.areaDraft && this.config.options.ui?.panel === false) {
|
|
2267
2491
|
if (state.areaDraft.selection) {
|
|
2268
2492
|
shell.append(this.createAreaDraftOverlay(state.areaDraft));
|
|
2269
2493
|
}
|
|
2270
|
-
|
|
2494
|
+
const areaComposer = this.createAreaDraftPopover(state.areaDraft, {
|
|
2495
|
+
dockComposer: shouldDockComposer
|
|
2496
|
+
});
|
|
2497
|
+
if (shouldDockComposer) {
|
|
2498
|
+
dockedComposer = areaComposer;
|
|
2499
|
+
} else {
|
|
2500
|
+
shell.append(areaComposer);
|
|
2501
|
+
}
|
|
2271
2502
|
}
|
|
2272
2503
|
shadow.append(shell);
|
|
2504
|
+
this.renderShellComposer(dockedComposer);
|
|
2273
2505
|
}
|
|
2274
2506
|
get state() {
|
|
2275
2507
|
return this.config.getState();
|
|
2276
2508
|
}
|
|
2509
|
+
getShellComposerHost() {
|
|
2510
|
+
const environment = this.config.getEnvironment();
|
|
2511
|
+
if (this.config.options.ui?.panel !== false) return void 0;
|
|
2512
|
+
return environment?.composerHost ?? void 0;
|
|
2513
|
+
}
|
|
2514
|
+
renderShellComposer(composer) {
|
|
2515
|
+
const host = composer ? this.getShellComposerHost() : void 0;
|
|
2516
|
+
if (!host || !composer) {
|
|
2517
|
+
this.clearShellComposer();
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
if (this.shellComposerHost && this.shellComposerHost !== host) {
|
|
2521
|
+
this.clearShellComposer();
|
|
2522
|
+
}
|
|
2523
|
+
this.shellComposerHost = host;
|
|
2524
|
+
host.dataset.hasDraftComposer = "true";
|
|
2525
|
+
if (host.parentElement) {
|
|
2526
|
+
host.parentElement.dataset.hasDraftComposer = "true";
|
|
2527
|
+
}
|
|
2528
|
+
const shell = document.createElement("div");
|
|
2529
|
+
shell.className = "dfwr-shell is-open is-shell-draft is-docked-composer";
|
|
2530
|
+
shell.append(composer);
|
|
2531
|
+
host.replaceChildren(createStyleElement(), shell);
|
|
2532
|
+
}
|
|
2533
|
+
clearShellComposer() {
|
|
2534
|
+
const host = this.shellComposerHost;
|
|
2535
|
+
host?.replaceChildren();
|
|
2536
|
+
if (host) {
|
|
2537
|
+
delete host.dataset.hasDraftComposer;
|
|
2538
|
+
delete host.parentElement?.dataset.hasDraftComposer;
|
|
2539
|
+
}
|
|
2540
|
+
this.shellComposerHost = void 0;
|
|
2541
|
+
}
|
|
2277
2542
|
createDraftCancelLayer() {
|
|
2278
2543
|
const layer = document.createElement("div");
|
|
2279
2544
|
layer.className = "dfwr-draft-cancel-layer";
|
|
2280
2545
|
layer.setAttribute("aria-hidden", "true");
|
|
2281
|
-
const cancel = (event) => {
|
|
2282
|
-
event.preventDefault();
|
|
2283
|
-
event.stopPropagation();
|
|
2284
|
-
event.stopImmediatePropagation();
|
|
2285
|
-
this.config.actions.setModeState("idle");
|
|
2286
|
-
this.config.actions.clearDrafts();
|
|
2287
|
-
this.config.actions.setSelectingArea(false);
|
|
2288
|
-
this.config.actions.render();
|
|
2289
|
-
};
|
|
2290
2546
|
layer.addEventListener("pointerdown", (event) => {
|
|
2291
2547
|
if (event.button !== 0) return;
|
|
2292
|
-
|
|
2548
|
+
this.cancelDraft(event);
|
|
2293
2549
|
});
|
|
2294
2550
|
return layer;
|
|
2295
2551
|
}
|
|
2552
|
+
cancelDraft(event) {
|
|
2553
|
+
event?.preventDefault();
|
|
2554
|
+
event?.stopPropagation();
|
|
2555
|
+
event?.stopImmediatePropagation();
|
|
2556
|
+
this.config.actions.setModeState("idle");
|
|
2557
|
+
this.config.actions.clearDrafts();
|
|
2558
|
+
this.config.actions.setSelectingArea(false);
|
|
2559
|
+
this.config.actions.render();
|
|
2560
|
+
}
|
|
2561
|
+
// Draft adjustment geometry lives in draft.metrics.ts; these thin wrappers
|
|
2562
|
+
// supply the configured viewport presets so call sites stay unchanged.
|
|
2563
|
+
get viewportPresets() {
|
|
2564
|
+
return this.config.options.viewports?.presets;
|
|
2565
|
+
}
|
|
2296
2566
|
getDraftAdjustmentMetrics(draft) {
|
|
2297
|
-
|
|
2298
|
-
const x = adjustment?.x ?? 0;
|
|
2299
|
-
const y = adjustment?.y ?? 0;
|
|
2300
|
-
const scale = adjustment?.scale ?? 0;
|
|
2301
|
-
const {
|
|
2302
|
-
scale: viewportScale,
|
|
2303
|
-
designWidth,
|
|
2304
|
-
presetLabel
|
|
2305
|
-
} = this.getDraftViewportScale(draft.viewport);
|
|
2306
|
-
const selection = draft.selection ? toViewportSelection(draft.selection.viewport) : void 0;
|
|
2307
|
-
const scaleCssDelta = scale * viewportScale;
|
|
2308
|
-
const scaleFactor = selection && selection.width > 0 ? Math.max(
|
|
2309
|
-
1 / selection.width,
|
|
2310
|
-
(selection.width + scaleCssDelta) / selection.width
|
|
2311
|
-
) : 1;
|
|
2312
|
-
return {
|
|
2313
|
-
x,
|
|
2314
|
-
y,
|
|
2315
|
-
scale,
|
|
2316
|
-
cssX: x * viewportScale,
|
|
2317
|
-
cssY: y * viewportScale,
|
|
2318
|
-
scaleFactor,
|
|
2319
|
-
viewportScale,
|
|
2320
|
-
designWidth,
|
|
2321
|
-
presetLabel,
|
|
2322
|
-
viewportWidth: draft.viewport.width
|
|
2323
|
-
};
|
|
2567
|
+
return getDraftAdjustmentMetrics(draft, this.viewportPresets);
|
|
2324
2568
|
}
|
|
2325
2569
|
hasDraftAdjustment(draft) {
|
|
2326
|
-
|
|
2327
|
-
return metrics.x !== 0 || metrics.y !== 0 || metrics.scale !== 0;
|
|
2570
|
+
return hasDraftAdjustment(draft, this.viewportPresets);
|
|
2328
2571
|
}
|
|
2329
2572
|
getAdjustedDraftPoint(point, draft) {
|
|
2330
|
-
|
|
2331
|
-
return {
|
|
2332
|
-
x: point.x + metrics.cssX,
|
|
2333
|
-
y: point.y + metrics.cssY
|
|
2334
|
-
};
|
|
2573
|
+
return getAdjustedDraftPoint(point, draft, this.viewportPresets);
|
|
2335
2574
|
}
|
|
2336
2575
|
getAdjustedDraftSelection(selection, draft) {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
width: selection.width * metrics.scaleFactor,
|
|
2343
|
-
height: selection.height * metrics.scaleFactor
|
|
2344
|
-
};
|
|
2576
|
+
return getAdjustedDraftSelection(
|
|
2577
|
+
selection,
|
|
2578
|
+
draft,
|
|
2579
|
+
this.viewportPresets
|
|
2580
|
+
);
|
|
2345
2581
|
}
|
|
2346
2582
|
getDraftViewportScale(viewport) {
|
|
2347
|
-
|
|
2348
|
-
viewport,
|
|
2349
|
-
this.config.options.viewports?.presets
|
|
2350
|
-
);
|
|
2351
|
-
const designWidth = typeof preset.designWidth === "number" && preset.designWidth > 0 ? preset.designWidth : viewport.width;
|
|
2352
|
-
const scale = designWidth > 0 ? viewport.width / designWidth : 1;
|
|
2353
|
-
return { scale, designWidth, presetLabel: preset.label };
|
|
2583
|
+
return getDraftViewportScale(viewport, this.viewportPresets);
|
|
2354
2584
|
}
|
|
2355
2585
|
getDraftComposerWidth(environment) {
|
|
2356
2586
|
const bounds = environment.overlayRect;
|
|
@@ -2496,6 +2726,67 @@ var WebReviewKitView = class {
|
|
|
2496
2726
|
return trimmedComment ? `${trimmedComment}
|
|
2497
2727
|
${adjustment}` : adjustment;
|
|
2498
2728
|
}
|
|
2729
|
+
getAssigneeOption(assigneeId) {
|
|
2730
|
+
if (!assigneeId) return void 0;
|
|
2731
|
+
return this.config.options.assigneeOptions?.find(
|
|
2732
|
+
(option) => option.value === assigneeId
|
|
2733
|
+
);
|
|
2734
|
+
}
|
|
2735
|
+
getAssigneeName(assigneeId) {
|
|
2736
|
+
return this.getAssigneeOption(assigneeId)?.label;
|
|
2737
|
+
}
|
|
2738
|
+
createDraftTitleInput(value, onInput) {
|
|
2739
|
+
const input = document.createElement("input");
|
|
2740
|
+
input.className = "dfwr-input";
|
|
2741
|
+
input.placeholder = "Title";
|
|
2742
|
+
input.type = "text";
|
|
2743
|
+
input.value = value ?? "";
|
|
2744
|
+
input.addEventListener("input", () => onInput(input.value));
|
|
2745
|
+
return input;
|
|
2746
|
+
}
|
|
2747
|
+
isTitleFieldEnabled() {
|
|
2748
|
+
return this.config.options.fields?.title === true;
|
|
2749
|
+
}
|
|
2750
|
+
createDraftAssigneeSelect(value, fallbackLabel, onChange) {
|
|
2751
|
+
const assigneeOptions = this.config.options.assigneeOptions ?? [];
|
|
2752
|
+
if (assigneeOptions.length === 0) return void 0;
|
|
2753
|
+
const assigneeTitle = this.config.options.assigneeTitle?.trim() || "Assignee";
|
|
2754
|
+
const select = document.createElement("select");
|
|
2755
|
+
select.className = "dfwr-select";
|
|
2756
|
+
const emptyOption = document.createElement("option");
|
|
2757
|
+
emptyOption.value = "";
|
|
2758
|
+
emptyOption.textContent = assigneeTitle;
|
|
2759
|
+
select.append(emptyOption);
|
|
2760
|
+
const hasUnknownAssignee = Boolean(value) && !assigneeOptions.some((option) => option.value === value);
|
|
2761
|
+
if (hasUnknownAssignee && value) {
|
|
2762
|
+
const option = document.createElement("option");
|
|
2763
|
+
option.value = value;
|
|
2764
|
+
option.textContent = fallbackLabel ?? value;
|
|
2765
|
+
select.append(option);
|
|
2766
|
+
}
|
|
2767
|
+
assigneeOptions.forEach((assigneeOption) => {
|
|
2768
|
+
const option = document.createElement("option");
|
|
2769
|
+
option.value = assigneeOption.value;
|
|
2770
|
+
option.textContent = assigneeOption.label;
|
|
2771
|
+
select.append(option);
|
|
2772
|
+
});
|
|
2773
|
+
select.value = value ?? "";
|
|
2774
|
+
select.addEventListener("change", () => {
|
|
2775
|
+
onChange(select.value || null, this.getAssigneeName(select.value));
|
|
2776
|
+
});
|
|
2777
|
+
return select;
|
|
2778
|
+
}
|
|
2779
|
+
getDraftFields(titleInput, textarea, assigneeSelect) {
|
|
2780
|
+
const title = titleInput?.value.trim();
|
|
2781
|
+
const comment = textarea.value.trim();
|
|
2782
|
+
const assigneeId = assigneeSelect?.value.trim() || void 0;
|
|
2783
|
+
return {
|
|
2784
|
+
title: title || void 0,
|
|
2785
|
+
comment,
|
|
2786
|
+
assigneeId,
|
|
2787
|
+
assigneeName: this.getAssigneeName(assigneeId)
|
|
2788
|
+
};
|
|
2789
|
+
}
|
|
2499
2790
|
getStyleableDraftElement(draft, environment) {
|
|
2500
2791
|
if (draft.previewElement && draft.previewElement.ownerDocument === environment.document && "style" in draft.previewElement) {
|
|
2501
2792
|
return draft.previewElement;
|
|
@@ -2686,11 +2977,14 @@ ${adjustment}` : adjustment;
|
|
|
2686
2977
|
empty.textContent = this.state.noteDraft ? "Write the note in the page box." : this.state.mode === "element" ? "Click an element to add QA." : "Click on the page to place a note.";
|
|
2687
2978
|
return empty;
|
|
2688
2979
|
}
|
|
2689
|
-
|
|
2980
|
+
// Builds the note draft layer: the on-page marker/highlight plus its composer
|
|
2981
|
+
// popover. When dockComposer is set the composer renders into the side panel
|
|
2982
|
+
// instead of floating next to the marker (used for the docked review mode).
|
|
2983
|
+
createNotePopover(draft, options = {}) {
|
|
2690
2984
|
const environment = this.config.getEnvironment();
|
|
2691
2985
|
const group = document.createElement("div");
|
|
2692
2986
|
group.className = "dfwr-note-draft";
|
|
2693
|
-
if (!environment) return group;
|
|
2987
|
+
if (!environment) return { layer: group, composer: void 0 };
|
|
2694
2988
|
const isElementDraft = this.state.mode === "element" && Boolean(draft.selection);
|
|
2695
2989
|
const hostPoint = toHostPoint(
|
|
2696
2990
|
isElementDraft ? this.getAdjustedDraftPoint(draft.marker.viewport, draft) : draft.marker.viewport,
|
|
@@ -2714,8 +3008,14 @@ ${adjustment}` : adjustment;
|
|
|
2714
3008
|
pin.style.top = `${hostPoint.y}px`;
|
|
2715
3009
|
const popover = document.createElement("div");
|
|
2716
3010
|
const position = getPopoverPosition(hostPoint, environment);
|
|
2717
|
-
popover.className =
|
|
2718
|
-
|
|
3011
|
+
popover.className = [
|
|
3012
|
+
"dfwr-note-popover",
|
|
3013
|
+
isElementDraft ? "is-composer" : "",
|
|
3014
|
+
options.dockComposer ? "is-docked-composer" : ""
|
|
3015
|
+
].filter(Boolean).join(" ");
|
|
3016
|
+
if (options.dockComposer) {
|
|
3017
|
+
popover.style.width = "100%";
|
|
3018
|
+
} else if (isElementDraft) {
|
|
2719
3019
|
const selection = draft.selection ? toHostSelection(
|
|
2720
3020
|
this.getAdjustedDraftSelection(
|
|
2721
3021
|
toViewportSelection(draft.selection.viewport),
|
|
@@ -2743,6 +3043,14 @@ ${adjustment}` : adjustment;
|
|
|
2743
3043
|
meta.className = "dfwr-item-date";
|
|
2744
3044
|
meta.textContent = formatNoteDraftMeta(draft);
|
|
2745
3045
|
}
|
|
3046
|
+
const titleInput = this.isTitleFieldEnabled() ? this.createDraftTitleInput(draft.title, (title) => {
|
|
3047
|
+
const noteDraft = this.state.noteDraft;
|
|
3048
|
+
if (!noteDraft) return;
|
|
3049
|
+
this.config.actions.setNoteDraft({
|
|
3050
|
+
...noteDraft,
|
|
3051
|
+
title
|
|
3052
|
+
});
|
|
3053
|
+
}) : void 0;
|
|
2746
3054
|
const textarea = document.createElement("textarea");
|
|
2747
3055
|
textarea.className = "dfwr-textarea";
|
|
2748
3056
|
textarea.placeholder = "Review comment";
|
|
@@ -2756,13 +3064,30 @@ ${adjustment}` : adjustment;
|
|
|
2756
3064
|
comment: textarea.value
|
|
2757
3065
|
});
|
|
2758
3066
|
});
|
|
3067
|
+
const assigneeSelect = this.createDraftAssigneeSelect(
|
|
3068
|
+
draft.assigneeId,
|
|
3069
|
+
draft.assigneeName,
|
|
3070
|
+
(assigneeId, assigneeName) => {
|
|
3071
|
+
const noteDraft = this.state.noteDraft;
|
|
3072
|
+
if (!noteDraft) return;
|
|
3073
|
+
this.config.actions.setNoteDraft({
|
|
3074
|
+
...noteDraft,
|
|
3075
|
+
assigneeId,
|
|
3076
|
+
assigneeName
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
);
|
|
2759
3080
|
const saveDraft = () => {
|
|
2760
|
-
const comment = textarea.value.trim();
|
|
2761
3081
|
const currentDraft = this.state.noteDraft ?? draft;
|
|
3082
|
+
const fields = this.getDraftFields(titleInput, textarea, assigneeSelect);
|
|
3083
|
+
const comment = fields.comment;
|
|
2762
3084
|
if (!comment && !this.hasDraftAdjustment(currentDraft)) return;
|
|
2763
3085
|
void this.config.actions.createItem({
|
|
2764
3086
|
kind: "note",
|
|
3087
|
+
title: fields.title,
|
|
2765
3088
|
comment: this.withDraftAdjustmentComment(comment, currentDraft),
|
|
3089
|
+
assigneeId: fields.assigneeId,
|
|
3090
|
+
assigneeName: fields.assigneeName,
|
|
2766
3091
|
viewport: currentDraft.viewport,
|
|
2767
3092
|
anchor: currentDraft.anchor,
|
|
2768
3093
|
marker: currentDraft.marker,
|
|
@@ -2774,18 +3099,31 @@ ${adjustment}` : adjustment;
|
|
|
2774
3099
|
pin,
|
|
2775
3100
|
popover,
|
|
2776
3101
|
selectionHighlight,
|
|
2777
|
-
textarea
|
|
3102
|
+
textarea,
|
|
3103
|
+
dockToggle: options.dockComposer
|
|
2778
3104
|
}) : void 0;
|
|
2779
|
-
const actions = this.createFormActions("Save note", saveDraft
|
|
3105
|
+
const actions = this.createFormActions("Save note", saveDraft, {
|
|
3106
|
+
leading: adjustmentControls?.actionButton ? [adjustmentControls.actionButton] : void 0
|
|
3107
|
+
});
|
|
3108
|
+
const error = this.createDraftError();
|
|
2780
3109
|
form.append(
|
|
2781
3110
|
...meta ? [meta] : [],
|
|
2782
3111
|
...adjustmentControls ? [adjustmentControls.panel] : [],
|
|
3112
|
+
...titleInput ? [titleInput] : [],
|
|
2783
3113
|
textarea,
|
|
3114
|
+
...assigneeSelect ? [assigneeSelect] : [],
|
|
3115
|
+
...error ? [error] : [],
|
|
2784
3116
|
actions
|
|
2785
3117
|
);
|
|
2786
|
-
const dragHandle = isElementDraft ? this.createDraftDragHandle("Move DOM composer") : void 0;
|
|
2787
|
-
popover.append(
|
|
2788
|
-
|
|
3118
|
+
const dragHandle = isElementDraft && !options.dockComposer ? this.createDraftDragHandle("Move DOM composer") : void 0;
|
|
3119
|
+
popover.append(
|
|
3120
|
+
...dragHandle ? [dragHandle] : [],
|
|
3121
|
+
form
|
|
3122
|
+
);
|
|
3123
|
+
group.append(pin);
|
|
3124
|
+
if (!options.dockComposer) {
|
|
3125
|
+
group.append(popover);
|
|
3126
|
+
}
|
|
2789
3127
|
if (dragHandle) {
|
|
2790
3128
|
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
2791
3129
|
const noteDraft = this.state.noteDraft ?? draft;
|
|
@@ -2798,18 +3136,23 @@ ${adjustment}` : adjustment;
|
|
|
2798
3136
|
}
|
|
2799
3137
|
this.attachDraftPinDrag(
|
|
2800
3138
|
pin,
|
|
2801
|
-
isElementDraft ? void 0 : popover,
|
|
3139
|
+
isElementDraft || options.dockComposer ? void 0 : popover,
|
|
2802
3140
|
meta,
|
|
2803
3141
|
textarea
|
|
2804
3142
|
);
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
3143
|
+
if (!options.dockComposer) {
|
|
3144
|
+
window.setTimeout(() => {
|
|
3145
|
+
if (draft.adjustment?.isActive) {
|
|
3146
|
+
adjustmentControls?.focusTarget.focus();
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
3149
|
+
textarea.focus();
|
|
3150
|
+
}, 0);
|
|
3151
|
+
}
|
|
3152
|
+
return {
|
|
3153
|
+
layer: group,
|
|
3154
|
+
composer: options.dockComposer ? popover : void 0
|
|
3155
|
+
};
|
|
2813
3156
|
}
|
|
2814
3157
|
createDraftDragHandle(label) {
|
|
2815
3158
|
const handle = document.createElement("button");
|
|
@@ -2896,12 +3239,16 @@ ${adjustment}` : adjustment;
|
|
|
2896
3239
|
handle.addEventListener("pointerup", stopDrag);
|
|
2897
3240
|
handle.addEventListener("pointercancel", stopDrag);
|
|
2898
3241
|
}
|
|
3242
|
+
// Builds the element-adjustment controls (nudge the previewed element via
|
|
3243
|
+
// arrow keys / buttons). Wires keyboard deltas to the draft transform and
|
|
3244
|
+
// keeps the pin, popover, highlight and textarea in sync as the value changes.
|
|
2899
3245
|
createAdjustmentControls({
|
|
2900
3246
|
draft,
|
|
2901
3247
|
pin,
|
|
2902
3248
|
popover,
|
|
2903
3249
|
selectionHighlight,
|
|
2904
|
-
textarea
|
|
3250
|
+
textarea,
|
|
3251
|
+
dockToggle
|
|
2905
3252
|
}) {
|
|
2906
3253
|
const panel = document.createElement("div");
|
|
2907
3254
|
panel.className = "dfwr-adjust-panel is-dom-adjust-panel";
|
|
@@ -2977,12 +3324,16 @@ ${adjustment}` : adjustment;
|
|
|
2977
3324
|
}
|
|
2978
3325
|
}));
|
|
2979
3326
|
});
|
|
2980
|
-
header.append(help
|
|
3327
|
+
header.append(help);
|
|
3328
|
+
if (!dockToggle) {
|
|
3329
|
+
header.append(adjust);
|
|
3330
|
+
}
|
|
2981
3331
|
panel.append(header, xyStatus, scaleStatus);
|
|
2982
3332
|
syncControls(draft);
|
|
2983
3333
|
return {
|
|
2984
3334
|
panel,
|
|
2985
|
-
focusTarget: adjust
|
|
3335
|
+
focusTarget: adjust,
|
|
3336
|
+
actionButton: dockToggle ? adjust : void 0
|
|
2986
3337
|
};
|
|
2987
3338
|
}
|
|
2988
3339
|
getAdjustmentKeyDelta(event) {
|
|
@@ -3035,6 +3386,14 @@ ${adjustment}` : adjustment;
|
|
|
3035
3386
|
return form;
|
|
3036
3387
|
}
|
|
3037
3388
|
form.append(this.createAreaMetricsPanel(areaDraft));
|
|
3389
|
+
const titleInput = this.isTitleFieldEnabled() ? this.createDraftTitleInput(areaDraft.title, (title) => {
|
|
3390
|
+
const draft = this.state.areaDraft;
|
|
3391
|
+
if (!draft) return;
|
|
3392
|
+
this.config.actions.setAreaDraft({
|
|
3393
|
+
...draft,
|
|
3394
|
+
title
|
|
3395
|
+
});
|
|
3396
|
+
}) : void 0;
|
|
3038
3397
|
const textarea = document.createElement("textarea");
|
|
3039
3398
|
textarea.className = "dfwr-textarea";
|
|
3040
3399
|
textarea.placeholder = "Area comment";
|
|
@@ -3048,20 +3407,44 @@ ${adjustment}` : adjustment;
|
|
|
3048
3407
|
comment: textarea.value
|
|
3049
3408
|
});
|
|
3050
3409
|
});
|
|
3410
|
+
const assigneeSelect = this.createDraftAssigneeSelect(
|
|
3411
|
+
areaDraft.assigneeId,
|
|
3412
|
+
areaDraft.assigneeName,
|
|
3413
|
+
(assigneeId, assigneeName) => {
|
|
3414
|
+
const draft = this.state.areaDraft;
|
|
3415
|
+
if (!draft) return;
|
|
3416
|
+
this.config.actions.setAreaDraft({
|
|
3417
|
+
...draft,
|
|
3418
|
+
assigneeId,
|
|
3419
|
+
assigneeName
|
|
3420
|
+
});
|
|
3421
|
+
}
|
|
3422
|
+
);
|
|
3051
3423
|
const actions = this.createFormActions("Save area", () => {
|
|
3052
|
-
const comment = textarea.value.trim();
|
|
3053
3424
|
const draft = this.state.areaDraft;
|
|
3425
|
+
const fields = this.getDraftFields(titleInput, textarea, assigneeSelect);
|
|
3426
|
+
const comment = fields.comment;
|
|
3054
3427
|
if (!comment || !draft) return;
|
|
3055
3428
|
void this.config.actions.createItem({
|
|
3056
3429
|
kind: "area",
|
|
3430
|
+
title: fields.title,
|
|
3057
3431
|
comment,
|
|
3432
|
+
assigneeId: fields.assigneeId,
|
|
3433
|
+
assigneeName: fields.assigneeName,
|
|
3058
3434
|
viewport: draft.viewport,
|
|
3059
3435
|
anchor: draft.anchor,
|
|
3060
3436
|
marker: draft.marker,
|
|
3061
3437
|
selection: draft.selection
|
|
3062
3438
|
});
|
|
3063
3439
|
});
|
|
3064
|
-
|
|
3440
|
+
const error = this.createDraftError();
|
|
3441
|
+
form.append(
|
|
3442
|
+
...titleInput ? [titleInput] : [],
|
|
3443
|
+
textarea,
|
|
3444
|
+
...assigneeSelect ? [assigneeSelect] : [],
|
|
3445
|
+
...error ? [error] : [],
|
|
3446
|
+
actions
|
|
3447
|
+
);
|
|
3065
3448
|
return form;
|
|
3066
3449
|
}
|
|
3067
3450
|
createAreaMetricsPanel(draft) {
|
|
@@ -3108,11 +3491,17 @@ ${adjustment}` : adjustment;
|
|
|
3108
3491
|
}
|
|
3109
3492
|
return layer;
|
|
3110
3493
|
}
|
|
3111
|
-
createAreaDraftPopover(draft) {
|
|
3494
|
+
createAreaDraftPopover(draft, options = {}) {
|
|
3112
3495
|
const environment = this.config.getEnvironment();
|
|
3113
3496
|
const popover = document.createElement("div");
|
|
3114
|
-
popover.className =
|
|
3115
|
-
|
|
3497
|
+
popover.className = [
|
|
3498
|
+
"dfwr-area-draft",
|
|
3499
|
+
"is-composer",
|
|
3500
|
+
options.dockComposer ? "is-docked-composer" : ""
|
|
3501
|
+
].filter(Boolean).join(" ");
|
|
3502
|
+
if (options.dockComposer) {
|
|
3503
|
+
popover.style.width = "100%";
|
|
3504
|
+
} else if (environment && draft.selection) {
|
|
3116
3505
|
const selection = toHostSelection(
|
|
3117
3506
|
toViewportSelection(draft.selection.viewport),
|
|
3118
3507
|
environment
|
|
@@ -3128,40 +3517,61 @@ ${adjustment}` : adjustment;
|
|
|
3128
3517
|
popover.style.width = `${composer.width}px`;
|
|
3129
3518
|
popover.style.right = "auto";
|
|
3130
3519
|
}
|
|
3131
|
-
const dragHandle = this.createDraftDragHandle("Move area composer");
|
|
3132
|
-
popover.append(
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3520
|
+
const dragHandle = options.dockComposer ? void 0 : this.createDraftDragHandle("Move area composer");
|
|
3521
|
+
popover.append(
|
|
3522
|
+
...dragHandle ? [dragHandle] : [],
|
|
3523
|
+
this.createAreaForm()
|
|
3524
|
+
);
|
|
3525
|
+
if (dragHandle) {
|
|
3526
|
+
this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
|
|
3527
|
+
const areaDraft = this.state.areaDraft ?? draft;
|
|
3528
|
+
this.config.actions.setAreaDraft({
|
|
3529
|
+
...areaDraft,
|
|
3530
|
+
composerPosition
|
|
3531
|
+
});
|
|
3138
3532
|
});
|
|
3139
|
-
}
|
|
3533
|
+
}
|
|
3140
3534
|
return popover;
|
|
3141
3535
|
}
|
|
3142
3536
|
createFormActions(saveLabel, onSave, options) {
|
|
3143
3537
|
const actions = document.createElement("div");
|
|
3144
3538
|
actions.className = ["dfwr-actions", options?.className].filter(Boolean).join(" ");
|
|
3539
|
+
const isSaving = this.state.isCreatingItem;
|
|
3145
3540
|
const save = document.createElement("button");
|
|
3146
3541
|
save.className = "dfwr-button is-primary";
|
|
3147
3542
|
save.type = "button";
|
|
3148
|
-
save.
|
|
3543
|
+
save.disabled = isSaving;
|
|
3544
|
+
save.setAttribute("aria-busy", isSaving ? "true" : "false");
|
|
3545
|
+
if (isSaving) {
|
|
3546
|
+
save.append(this.createSpinner("dfwr-spinner"), "Saving...");
|
|
3547
|
+
} else {
|
|
3548
|
+
save.textContent = saveLabel;
|
|
3549
|
+
}
|
|
3149
3550
|
save.addEventListener("click", (event) => {
|
|
3150
3551
|
event.preventDefault();
|
|
3151
3552
|
event.stopPropagation();
|
|
3553
|
+
if (this.state.isCreatingItem) return;
|
|
3152
3554
|
onSave();
|
|
3153
3555
|
});
|
|
3154
3556
|
const cancel = document.createElement("button");
|
|
3155
3557
|
cancel.className = "dfwr-button";
|
|
3156
3558
|
cancel.type = "button";
|
|
3559
|
+
cancel.disabled = isSaving;
|
|
3157
3560
|
cancel.textContent = "Cancel";
|
|
3158
3561
|
cancel.addEventListener("click", (event) => {
|
|
3159
|
-
|
|
3160
|
-
event.stopPropagation();
|
|
3161
|
-
this.config.actions.setModeState("idle");
|
|
3162
|
-
this.config.actions.clearDrafts();
|
|
3163
|
-
this.config.actions.render();
|
|
3562
|
+
this.cancelDraft(event);
|
|
3164
3563
|
});
|
|
3564
|
+
if (options?.leading?.length) {
|
|
3565
|
+
actions.classList.add("has-leading");
|
|
3566
|
+
const leading = document.createElement("div");
|
|
3567
|
+
leading.className = "dfwr-actions-leading";
|
|
3568
|
+
leading.append(...options.leading);
|
|
3569
|
+
const primary = document.createElement("div");
|
|
3570
|
+
primary.className = "dfwr-actions-primary";
|
|
3571
|
+
primary.append(save, cancel);
|
|
3572
|
+
actions.append(leading, primary);
|
|
3573
|
+
return actions;
|
|
3574
|
+
}
|
|
3165
3575
|
if (options?.beforeSave?.length || options?.className) {
|
|
3166
3576
|
actions.append(cancel, ...options.beforeSave ?? [], save);
|
|
3167
3577
|
return actions;
|
|
@@ -3169,6 +3579,20 @@ ${adjustment}` : adjustment;
|
|
|
3169
3579
|
actions.append(save, cancel);
|
|
3170
3580
|
return actions;
|
|
3171
3581
|
}
|
|
3582
|
+
createSpinner(className) {
|
|
3583
|
+
const spinner = document.createElement("span");
|
|
3584
|
+
spinner.className = className;
|
|
3585
|
+
spinner.setAttribute("aria-hidden", "true");
|
|
3586
|
+
return spinner;
|
|
3587
|
+
}
|
|
3588
|
+
createDraftError() {
|
|
3589
|
+
if (!this.state.draftError) return void 0;
|
|
3590
|
+
const error = document.createElement("p");
|
|
3591
|
+
error.className = "dfwr-form-error";
|
|
3592
|
+
error.setAttribute("role", "alert");
|
|
3593
|
+
error.textContent = this.state.draftError;
|
|
3594
|
+
return error;
|
|
3595
|
+
}
|
|
3172
3596
|
createList() {
|
|
3173
3597
|
const section = document.createElement("div");
|
|
3174
3598
|
section.className = "dfwr-list";
|
|
@@ -3221,14 +3645,20 @@ ${adjustment}` : adjustment;
|
|
|
3221
3645
|
kind.className = "dfwr-item-kind";
|
|
3222
3646
|
kind.textContent = item.kind;
|
|
3223
3647
|
badges.append(scope, kind);
|
|
3648
|
+
const title = this.isTitleFieldEnabled() ? item.title?.trim() : "";
|
|
3649
|
+
const titleElement = title ? document.createElement("strong") : void 0;
|
|
3650
|
+
if (title && titleElement) {
|
|
3651
|
+
titleElement.className = "dfwr-item-title";
|
|
3652
|
+
titleElement.textContent = title;
|
|
3653
|
+
}
|
|
3224
3654
|
const comment = document.createElement("p");
|
|
3225
|
-
comment.className =
|
|
3655
|
+
comment.className = `dfwr-item-comment${title ? "" : " is-primary"}`;
|
|
3226
3656
|
comment.textContent = item.comment;
|
|
3227
3657
|
const date = document.createElement("time");
|
|
3228
3658
|
date.className = "dfwr-item-date";
|
|
3229
3659
|
date.dateTime = item.createdAt;
|
|
3230
3660
|
date.textContent = formatItemMeta(item);
|
|
3231
|
-
body.append(badges, comment, date);
|
|
3661
|
+
body.append(badges, ...titleElement ? [titleElement] : [], comment, date);
|
|
3232
3662
|
const actions = document.createElement("div");
|
|
3233
3663
|
actions.className = "dfwr-item-actions";
|
|
3234
3664
|
actions.addEventListener("click", (event) => event.stopPropagation());
|
|
@@ -3417,7 +3847,14 @@ ${formatItemMeta(item)}`;
|
|
|
3417
3847
|
event,
|
|
3418
3848
|
this.config.getEnvironment()
|
|
3419
3849
|
);
|
|
3420
|
-
|
|
3850
|
+
const currentDraft = this.state.noteDraft;
|
|
3851
|
+
const fields = {
|
|
3852
|
+
title: currentDraft?.title,
|
|
3853
|
+
comment: textarea.value,
|
|
3854
|
+
assigneeId: currentDraft?.assigneeId,
|
|
3855
|
+
assigneeName: currentDraft?.assigneeName
|
|
3856
|
+
};
|
|
3857
|
+
void (this.state.mode === "element" ? this.config.actions.bindElementDraftToPoint(nextPoint, fields) : this.config.actions.bindNoteDraftToPoint(nextPoint, fields));
|
|
3421
3858
|
});
|
|
3422
3859
|
}
|
|
3423
3860
|
createNoteLayer() {
|
|
@@ -3495,10 +3932,14 @@ ${formatItemMeta(item)}`;
|
|
|
3495
3932
|
let startX = 0;
|
|
3496
3933
|
let startY = 0;
|
|
3497
3934
|
let selection;
|
|
3935
|
+
let activePointerId;
|
|
3936
|
+
let isDragging = false;
|
|
3937
|
+
const ownerWindow = layer.ownerDocument.defaultView ?? window;
|
|
3498
3938
|
const updateBox = (event) => {
|
|
3939
|
+
const nextEnvironment = this.config.getEnvironment();
|
|
3499
3940
|
const nextPoint = toTargetPointFromHostEvent(
|
|
3500
3941
|
event,
|
|
3501
|
-
|
|
3942
|
+
nextEnvironment
|
|
3502
3943
|
);
|
|
3503
3944
|
const left = Math.min(startX, nextPoint.x);
|
|
3504
3945
|
const top = Math.min(startY, nextPoint.y);
|
|
@@ -3506,7 +3947,7 @@ ${formatItemMeta(item)}`;
|
|
|
3506
3947
|
const height = Math.abs(nextPoint.y - startY);
|
|
3507
3948
|
const hostPoint = toHostPoint(
|
|
3508
3949
|
{ x: left, y: top },
|
|
3509
|
-
|
|
3950
|
+
nextEnvironment
|
|
3510
3951
|
);
|
|
3511
3952
|
selection = { left, top, width, height };
|
|
3512
3953
|
box.style.left = `${hostPoint.x}px`;
|
|
@@ -3514,9 +3955,68 @@ ${formatItemMeta(item)}`;
|
|
|
3514
3955
|
box.style.width = `${width}px`;
|
|
3515
3956
|
box.style.height = `${height}px`;
|
|
3516
3957
|
};
|
|
3958
|
+
const addDragListeners = () => {
|
|
3959
|
+
ownerWindow.addEventListener("pointermove", handlePointerMove, true);
|
|
3960
|
+
ownerWindow.addEventListener("pointerup", handlePointerUp, true);
|
|
3961
|
+
ownerWindow.addEventListener("pointercancel", handlePointerCancel, true);
|
|
3962
|
+
};
|
|
3963
|
+
const removeDragListeners = () => {
|
|
3964
|
+
ownerWindow.removeEventListener("pointermove", handlePointerMove, true);
|
|
3965
|
+
ownerWindow.removeEventListener("pointerup", handlePointerUp, true);
|
|
3966
|
+
ownerWindow.removeEventListener(
|
|
3967
|
+
"pointercancel",
|
|
3968
|
+
handlePointerCancel,
|
|
3969
|
+
true
|
|
3970
|
+
);
|
|
3971
|
+
};
|
|
3972
|
+
const releasePointerCapture = (event) => {
|
|
3973
|
+
try {
|
|
3974
|
+
if (layer.hasPointerCapture(event.pointerId)) {
|
|
3975
|
+
layer.releasePointerCapture(event.pointerId);
|
|
3976
|
+
}
|
|
3977
|
+
} catch {
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
function isActivePointer(event) {
|
|
3981
|
+
return isDragging && event.pointerId === activePointerId;
|
|
3982
|
+
}
|
|
3983
|
+
const finishAreaSelection = (event) => {
|
|
3984
|
+
if (!isActivePointer(event)) return;
|
|
3985
|
+
event.preventDefault();
|
|
3986
|
+
updateBox(event);
|
|
3987
|
+
releasePointerCapture(event);
|
|
3988
|
+
removeDragListeners();
|
|
3989
|
+
isDragging = false;
|
|
3990
|
+
activePointerId = void 0;
|
|
3991
|
+
if (!selection || selection.width < 8 || selection.height < 8) return;
|
|
3992
|
+
this.config.actions.setSelectingArea(true);
|
|
3993
|
+
this.config.actions.render();
|
|
3994
|
+
void this.config.actions.createAreaDraft(selection);
|
|
3995
|
+
};
|
|
3996
|
+
function handlePointerMove(event) {
|
|
3997
|
+
if (!isActivePointer(event)) return;
|
|
3998
|
+
event.preventDefault();
|
|
3999
|
+
updateBox(event);
|
|
4000
|
+
}
|
|
4001
|
+
const handlePointerUp = (event) => {
|
|
4002
|
+
finishAreaSelection(event);
|
|
4003
|
+
};
|
|
4004
|
+
const handlePointerCancel = (event) => {
|
|
4005
|
+
if (!isActivePointer(event)) return;
|
|
4006
|
+
releasePointerCapture(event);
|
|
4007
|
+
removeDragListeners();
|
|
4008
|
+
isDragging = false;
|
|
4009
|
+
activePointerId = void 0;
|
|
4010
|
+
};
|
|
3517
4011
|
layer.addEventListener("pointerdown", (event) => {
|
|
4012
|
+
if (event.button !== 0) return;
|
|
3518
4013
|
event.preventDefault();
|
|
3519
|
-
|
|
4014
|
+
activePointerId = event.pointerId;
|
|
4015
|
+
isDragging = true;
|
|
4016
|
+
try {
|
|
4017
|
+
layer.setPointerCapture(event.pointerId);
|
|
4018
|
+
} catch {
|
|
4019
|
+
}
|
|
3520
4020
|
const startPoint = toTargetPointFromHostEvent(
|
|
3521
4021
|
event,
|
|
3522
4022
|
this.config.getEnvironment()
|
|
@@ -3524,20 +4024,11 @@ ${formatItemMeta(item)}`;
|
|
|
3524
4024
|
startX = startPoint.x;
|
|
3525
4025
|
startY = startPoint.y;
|
|
3526
4026
|
updateBox(event);
|
|
4027
|
+
addDragListeners();
|
|
3527
4028
|
});
|
|
3528
|
-
layer.addEventListener("pointermove",
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
});
|
|
3532
|
-
layer.addEventListener("pointerup", (event) => {
|
|
3533
|
-
if (!layer.hasPointerCapture(event.pointerId)) return;
|
|
3534
|
-
layer.releasePointerCapture(event.pointerId);
|
|
3535
|
-
updateBox(event);
|
|
3536
|
-
if (!selection || selection.width < 8 || selection.height < 8) return;
|
|
3537
|
-
this.config.actions.setSelectingArea(true);
|
|
3538
|
-
this.config.actions.render();
|
|
3539
|
-
void this.config.actions.createAreaDraft(selection);
|
|
3540
|
-
});
|
|
4029
|
+
layer.addEventListener("pointermove", handlePointerMove);
|
|
4030
|
+
layer.addEventListener("pointerup", handlePointerUp);
|
|
4031
|
+
layer.addEventListener("pointercancel", handlePointerCancel);
|
|
3541
4032
|
return layer;
|
|
3542
4033
|
}
|
|
3543
4034
|
};
|
|
@@ -3577,6 +4068,8 @@ var WebReviewKitApp = class {
|
|
|
3577
4068
|
this.isOpen = false;
|
|
3578
4069
|
this.mode = "idle";
|
|
3579
4070
|
this.items = [];
|
|
4071
|
+
this.draftError = "";
|
|
4072
|
+
this.isCreatingItem = false;
|
|
3580
4073
|
this.isSelectingArea = false;
|
|
3581
4074
|
this.handleKeyDown = (event) => {
|
|
3582
4075
|
if (event.key === "Escape" && this.cancelMode()) {
|
|
@@ -3590,9 +4083,10 @@ var WebReviewKitApp = class {
|
|
|
3590
4083
|
this.toggle();
|
|
3591
4084
|
};
|
|
3592
4085
|
this.handleViewportChange = () => {
|
|
3593
|
-
if (!this.isOpen || this.renderFrame) return;
|
|
4086
|
+
if (!this.isOpen || this.renderFrame || this.isDraftComposerFocused()) return;
|
|
3594
4087
|
this.renderFrame = window.requestAnimationFrame(() => {
|
|
3595
4088
|
this.renderFrame = void 0;
|
|
4089
|
+
if (this.isDraftComposerFocused()) return;
|
|
3596
4090
|
this.render();
|
|
3597
4091
|
});
|
|
3598
4092
|
};
|
|
@@ -3606,6 +4100,8 @@ var WebReviewKitApp = class {
|
|
|
3606
4100
|
items: this.items,
|
|
3607
4101
|
noteDraft: this.noteDraft,
|
|
3608
4102
|
areaDraft: this.areaDraft,
|
|
4103
|
+
draftError: this.draftError,
|
|
4104
|
+
isCreatingItem: this.isCreatingItem,
|
|
3609
4105
|
isSelectingArea: this.isSelectingArea,
|
|
3610
4106
|
highlightedItemId: this.highlightedItemId
|
|
3611
4107
|
}),
|
|
@@ -3620,19 +4116,22 @@ var WebReviewKitApp = class {
|
|
|
3620
4116
|
clearDrafts: () => {
|
|
3621
4117
|
this.noteDraft = void 0;
|
|
3622
4118
|
this.areaDraft = void 0;
|
|
4119
|
+
this.draftError = "";
|
|
3623
4120
|
},
|
|
3624
4121
|
setNoteDraft: (draft) => {
|
|
3625
4122
|
this.noteDraft = draft;
|
|
4123
|
+
this.draftError = "";
|
|
3626
4124
|
},
|
|
3627
4125
|
setAreaDraft: (draft) => {
|
|
3628
4126
|
this.areaDraft = draft;
|
|
4127
|
+
this.draftError = "";
|
|
3629
4128
|
},
|
|
3630
4129
|
setSelectingArea: (isSelectingArea) => {
|
|
3631
4130
|
this.isSelectingArea = isSelectingArea;
|
|
3632
4131
|
},
|
|
3633
4132
|
createItem: (input) => this.createItem(input),
|
|
3634
|
-
bindNoteDraftToPoint: (point,
|
|
3635
|
-
bindElementDraftToPoint: (point,
|
|
4133
|
+
bindNoteDraftToPoint: (point, fields) => this.bindNoteDraftToPoint(point, fields),
|
|
4134
|
+
bindElementDraftToPoint: (point, fields) => this.bindElementDraftToPoint(point, fields),
|
|
3636
4135
|
createAreaDraft: (selection) => this.createAreaDraft(selection)
|
|
3637
4136
|
}
|
|
3638
4137
|
});
|
|
@@ -3701,7 +4200,7 @@ var WebReviewKitApp = class {
|
|
|
3701
4200
|
this.noteDraft = void 0;
|
|
3702
4201
|
this.areaDraft = void 0;
|
|
3703
4202
|
this.isSelectingArea = false;
|
|
3704
|
-
await this.bindElementDraftToElement(element, comment);
|
|
4203
|
+
await this.bindElementDraftToElement(element, { comment });
|
|
3705
4204
|
}
|
|
3706
4205
|
getMode() {
|
|
3707
4206
|
return this.mode;
|
|
@@ -3769,6 +4268,14 @@ var WebReviewKitApp = class {
|
|
|
3769
4268
|
this.render();
|
|
3770
4269
|
return true;
|
|
3771
4270
|
}
|
|
4271
|
+
isDraftComposerFocused() {
|
|
4272
|
+
if (!this.noteDraft && !this.areaDraft) return false;
|
|
4273
|
+
const composerHost = this.getEnvironment()?.composerHost;
|
|
4274
|
+
const activeElement = composerHost?.ownerDocument.activeElement;
|
|
4275
|
+
return Boolean(
|
|
4276
|
+
composerHost && activeElement && composerHost.contains(activeElement)
|
|
4277
|
+
);
|
|
4278
|
+
}
|
|
3772
4279
|
getEnvironment() {
|
|
3773
4280
|
const target = typeof this.options.target === "function" ? this.options.target() : this.options.target;
|
|
3774
4281
|
if (!target) {
|
|
@@ -3797,6 +4304,7 @@ var WebReviewKitApp = class {
|
|
|
3797
4304
|
height: target.window.innerHeight
|
|
3798
4305
|
};
|
|
3799
4306
|
const overlayRect = target.getOverlayRect?.() ?? rect;
|
|
4307
|
+
const composerHost = target.getComposerHost?.();
|
|
3800
4308
|
return {
|
|
3801
4309
|
window: target.window,
|
|
3802
4310
|
document: target.document,
|
|
@@ -3811,7 +4319,8 @@ var WebReviewKitApp = class {
|
|
|
3811
4319
|
top: overlayRect.top,
|
|
3812
4320
|
width: overlayRect.width,
|
|
3813
4321
|
height: overlayRect.height
|
|
3814
|
-
}
|
|
4322
|
+
},
|
|
4323
|
+
composerHost
|
|
3815
4324
|
};
|
|
3816
4325
|
} catch {
|
|
3817
4326
|
return void 0;
|
|
@@ -3834,7 +4343,7 @@ var WebReviewKitApp = class {
|
|
|
3834
4343
|
if (!this.shadow) return;
|
|
3835
4344
|
this.view.render(this.shadow, this.createHiddenItemsStyleElement());
|
|
3836
4345
|
}
|
|
3837
|
-
async bindNoteDraftToPoint(point,
|
|
4346
|
+
async bindNoteDraftToPoint(point, fields = {}) {
|
|
3838
4347
|
const environment = this.getEnvironment();
|
|
3839
4348
|
if (!environment) return;
|
|
3840
4349
|
const viewport = getViewportSize(environment);
|
|
@@ -3854,13 +4363,13 @@ var WebReviewKitApp = class {
|
|
|
3854
4363
|
viewport,
|
|
3855
4364
|
anchor,
|
|
3856
4365
|
marker,
|
|
3857
|
-
|
|
4366
|
+
...fields
|
|
3858
4367
|
};
|
|
3859
4368
|
});
|
|
3860
4369
|
this.noteDraft = draft;
|
|
3861
4370
|
this.render();
|
|
3862
4371
|
}
|
|
3863
|
-
async bindElementDraftToPoint(point,
|
|
4372
|
+
async bindElementDraftToPoint(point, fields = {}) {
|
|
3864
4373
|
const environment = this.getEnvironment();
|
|
3865
4374
|
if (!environment) return;
|
|
3866
4375
|
const viewport = getViewportSize(environment);
|
|
@@ -3904,14 +4413,14 @@ var WebReviewKitApp = class {
|
|
|
3904
4413
|
anchor,
|
|
3905
4414
|
marker,
|
|
3906
4415
|
selection: reviewSelection,
|
|
3907
|
-
|
|
4416
|
+
...fields,
|
|
3908
4417
|
previewElement
|
|
3909
4418
|
};
|
|
3910
4419
|
});
|
|
3911
4420
|
this.noteDraft = draft;
|
|
3912
4421
|
this.render();
|
|
3913
4422
|
}
|
|
3914
|
-
async bindElementDraftToElement(element,
|
|
4423
|
+
async bindElementDraftToElement(element, fields = {}) {
|
|
3915
4424
|
const environment = this.getEnvironment();
|
|
3916
4425
|
if (!environment || element.ownerDocument !== environment.document) return;
|
|
3917
4426
|
const viewport = getViewportSize(environment);
|
|
@@ -3944,7 +4453,7 @@ var WebReviewKitApp = class {
|
|
|
3944
4453
|
anchor,
|
|
3945
4454
|
marker,
|
|
3946
4455
|
selection: reviewSelection,
|
|
3947
|
-
|
|
4456
|
+
...fields,
|
|
3948
4457
|
previewElement
|
|
3949
4458
|
};
|
|
3950
4459
|
});
|
|
@@ -3954,26 +4463,33 @@ var WebReviewKitApp = class {
|
|
|
3954
4463
|
}
|
|
3955
4464
|
async createAreaDraft(selection) {
|
|
3956
4465
|
const environment = this.getEnvironment();
|
|
3957
|
-
if (!environment)
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
)
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
4466
|
+
if (!environment) {
|
|
4467
|
+
this.isSelectingArea = false;
|
|
4468
|
+
this.render();
|
|
4469
|
+
return;
|
|
4470
|
+
}
|
|
4471
|
+
try {
|
|
4472
|
+
const viewport = getViewportSize(environment);
|
|
4473
|
+
this.areaDraft = await this.withOverlayHidden(() => {
|
|
4474
|
+
const marker = createSelectionCenterMarker(
|
|
4475
|
+
selection,
|
|
4476
|
+
void 0,
|
|
4477
|
+
environment
|
|
4478
|
+
);
|
|
4479
|
+
const reviewSelection = {
|
|
4480
|
+
viewport: toPublicSelection(selection)
|
|
4481
|
+
};
|
|
4482
|
+
return {
|
|
4483
|
+
viewport,
|
|
4484
|
+
marker,
|
|
4485
|
+
selection: reviewSelection
|
|
4486
|
+
};
|
|
4487
|
+
});
|
|
4488
|
+
this.setModeState("area");
|
|
4489
|
+
} finally {
|
|
4490
|
+
this.isSelectingArea = false;
|
|
4491
|
+
this.render();
|
|
4492
|
+
}
|
|
3977
4493
|
}
|
|
3978
4494
|
async withOverlayHidden(callback) {
|
|
3979
4495
|
if (!this.root) return callback();
|
|
@@ -3987,11 +4503,16 @@ var WebReviewKitApp = class {
|
|
|
3987
4503
|
}
|
|
3988
4504
|
async createItem(input) {
|
|
3989
4505
|
const environment = this.getEnvironment();
|
|
3990
|
-
if (!environment) return;
|
|
4506
|
+
if (!environment || this.isCreatingItem) return;
|
|
3991
4507
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3992
4508
|
const routeKey = getRouteKey(environment);
|
|
3993
4509
|
const viewport = input.viewport ?? getViewportSize(environment);
|
|
3994
4510
|
const createdBy = this.options.userId?.trim();
|
|
4511
|
+
const title = input.title?.trim();
|
|
4512
|
+
const assigneeId = input.assigneeId?.trim() || void 0;
|
|
4513
|
+
const assigneeOption = this.options.assigneeOptions?.find(
|
|
4514
|
+
(option) => option.value === assigneeId
|
|
4515
|
+
);
|
|
3995
4516
|
const item = {
|
|
3996
4517
|
id: createId(),
|
|
3997
4518
|
projectId: this.options.projectId,
|
|
@@ -4001,8 +4522,10 @@ var WebReviewKitApp = class {
|
|
|
4001
4522
|
normalizedPath: routeKey,
|
|
4002
4523
|
scope: input.scope ?? getReviewViewportScope(viewport, this.options.viewports?.presets),
|
|
4003
4524
|
kind: input.kind,
|
|
4004
|
-
title:
|
|
4525
|
+
title: title || void 0,
|
|
4005
4526
|
comment: input.comment,
|
|
4527
|
+
assigneeId,
|
|
4528
|
+
assigneeName: input.assigneeName ?? assigneeOption?.label,
|
|
4006
4529
|
createdBy: createdBy || void 0,
|
|
4007
4530
|
status: "todo",
|
|
4008
4531
|
viewport,
|
|
@@ -4017,13 +4540,23 @@ var WebReviewKitApp = class {
|
|
|
4017
4540
|
createdAt: now,
|
|
4018
4541
|
updatedAt: now
|
|
4019
4542
|
};
|
|
4020
|
-
|
|
4021
|
-
this.
|
|
4022
|
-
this.
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4543
|
+
this.draftError = "";
|
|
4544
|
+
this.isCreatingItem = true;
|
|
4545
|
+
this.render();
|
|
4546
|
+
try {
|
|
4547
|
+
const createdItem = await this.adapter.create(item);
|
|
4548
|
+
this.setModeState("idle");
|
|
4549
|
+
this.noteDraft = void 0;
|
|
4550
|
+
this.areaDraft = void 0;
|
|
4551
|
+
this.highlightItem(createdItem.id);
|
|
4552
|
+
await this.reload();
|
|
4553
|
+
await this.options.onCreateItem?.(createdItem);
|
|
4554
|
+
} catch (error) {
|
|
4555
|
+
this.draftError = error instanceof Error ? error.message : "Failed to save QA.";
|
|
4556
|
+
} finally {
|
|
4557
|
+
this.isCreatingItem = false;
|
|
4558
|
+
this.render();
|
|
4559
|
+
}
|
|
4027
4560
|
}
|
|
4028
4561
|
async restoreItem(item) {
|
|
4029
4562
|
this.setModeState("idle");
|
|
@@ -4080,6 +4613,7 @@ export {
|
|
|
4080
4613
|
REVIEW_WORKFLOW_STATUS_OPTIONS,
|
|
4081
4614
|
normalizeReviewItemStatus,
|
|
4082
4615
|
localAdapter,
|
|
4616
|
+
DEFAULT_REVIEW_FIGMA_IMAGE_FORMAT,
|
|
4083
4617
|
clamp,
|
|
4084
4618
|
DEFAULT_REVIEW_VIEWPORTS,
|
|
4085
4619
|
findReviewViewportPreset,
|
|
@@ -4088,6 +4622,7 @@ export {
|
|
|
4088
4622
|
getReviewItemScopeLabel,
|
|
4089
4623
|
getNumberedReviewItems,
|
|
4090
4624
|
runWithAutoScrollBehavior,
|
|
4625
|
+
reviewTypographyTokens,
|
|
4091
4626
|
createWebReviewKit
|
|
4092
4627
|
};
|
|
4093
|
-
//# sourceMappingURL=chunk-
|
|
4628
|
+
//# sourceMappingURL=chunk-RPVLRULC.js.map
|