@solhun/feedback-kit-web 0.7.0 → 0.9.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/dist/index.cjs +462 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -3
- package/dist/index.d.ts +99 -3
- package/dist/index.js +426 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -30,52 +30,56 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
COMMENT_MAX_CHARS: () =>
|
|
34
|
-
COMMENT_REQUIRED_MESSAGE: () =>
|
|
35
|
-
COMMENT_TOO_LONG_MESSAGE: () =>
|
|
33
|
+
COMMENT_MAX_CHARS: () => import_feedback_kit_core7.COMMENT_MAX_CHARS,
|
|
34
|
+
COMMENT_REQUIRED_MESSAGE: () => import_feedback_kit_core7.COMMENT_REQUIRED_MESSAGE,
|
|
35
|
+
COMMENT_TOO_LONG_MESSAGE: () => import_feedback_kit_core7.COMMENT_TOO_LONG_MESSAGE,
|
|
36
36
|
ELEMENT_TEXT_MAX_CHARS: () => ELEMENT_TEXT_MAX_CHARS,
|
|
37
37
|
ElementPickingController: () => ElementPickingController,
|
|
38
|
-
FLOATING_BUTTON_ID: () =>
|
|
38
|
+
FLOATING_BUTTON_ID: () => import_feedback_kit_core7.FLOATING_BUTTON_ID,
|
|
39
39
|
FeedbackKit: () => FeedbackKit,
|
|
40
|
-
HintProvider: () =>
|
|
40
|
+
HintProvider: () => import_feedback_kit_core8.HintProvider,
|
|
41
41
|
MARKER_KEY_PREFIX: () => MARKER_KEY_PREFIX,
|
|
42
42
|
MAX_MARKERS_PER_PATH: () => MAX_MARKERS_PER_PATH,
|
|
43
|
-
MODAL_ACTION_HINT_TOGGLE: () =>
|
|
44
|
-
MODAL_ACTION_PICK: () =>
|
|
43
|
+
MODAL_ACTION_HINT_TOGGLE: () => import_feedback_kit_core7.MODAL_ACTION_HINT_TOGGLE,
|
|
44
|
+
MODAL_ACTION_PICK: () => import_feedback_kit_core7.MODAL_ACTION_PICK,
|
|
45
45
|
MarkerStore: () => MarkerStore,
|
|
46
46
|
OWN_UI_ATTR: () => OWN_UI_ATTR,
|
|
47
47
|
PICKING_MODE_KEY: () => PICKING_MODE_KEY,
|
|
48
|
-
ReportModalController: () =>
|
|
49
|
-
SCREENSHOT_FAILED_MESSAGE: () =>
|
|
48
|
+
ReportModalController: () => import_feedback_kit_core7.ReportModalController,
|
|
49
|
+
SCREENSHOT_FAILED_MESSAGE: () => import_feedback_kit_core7.SCREENSHOT_FAILED_MESSAGE,
|
|
50
50
|
SELECTOR_MAX_DEPTH: () => SELECTOR_MAX_DEPTH,
|
|
51
|
-
SOURCE_ATTR: () =>
|
|
52
|
-
SUBMIT_DONE_MESSAGE: () =>
|
|
53
|
-
SUBMIT_PENDING_MESSAGE: () =>
|
|
54
|
-
WidgetController: () =>
|
|
51
|
+
SOURCE_ATTR: () => import_feedback_kit_core6.SOURCE_ATTR,
|
|
52
|
+
SUBMIT_DONE_MESSAGE: () => import_feedback_kit_core7.SUBMIT_DONE_MESSAGE,
|
|
53
|
+
SUBMIT_PENDING_MESSAGE: () => import_feedback_kit_core7.SUBMIT_PENDING_MESSAGE,
|
|
54
|
+
WidgetController: () => import_feedback_kit_core7.WidgetController,
|
|
55
55
|
captureWebScreenshot: () => captureWebScreenshot,
|
|
56
|
+
createRouteWatcher: () => createRouteWatcher,
|
|
56
57
|
createWebStorage: () => createWebStorage,
|
|
57
58
|
createWebWidget: () => createWebWidget,
|
|
58
59
|
cssSelectorPath: () => cssSelectorPath,
|
|
59
|
-
denormalizePin: () =>
|
|
60
|
+
denormalizePin: () => import_feedback_kit_core7.denormalizePin,
|
|
60
61
|
describeElement: () => describeElement,
|
|
61
62
|
isOwnUi: () => isOwnUi2,
|
|
62
|
-
normalizePin: () =>
|
|
63
|
-
parseSourceAttr: () =>
|
|
64
|
-
rankHints: () =>
|
|
63
|
+
normalizePin: () => import_feedback_kit_core7.normalizePin,
|
|
64
|
+
parseSourceAttr: () => import_feedback_kit_core6.parseSourceAttr,
|
|
65
|
+
rankHints: () => import_feedback_kit_core8.rankHints,
|
|
65
66
|
reactComponentPath: () => reactComponentPath,
|
|
66
67
|
reactComponentSummary: () => reactComponentSummary,
|
|
67
68
|
reencodeWebScreenshot: () => reencodeWebScreenshot,
|
|
68
|
-
resolveConfig: () =>
|
|
69
|
-
shouldShowWidget: () =>
|
|
70
|
-
sourceFromElement: () =>
|
|
69
|
+
resolveConfig: () => import_feedback_kit_core5.resolveConfig,
|
|
70
|
+
shouldShowWidget: () => import_feedback_kit_core5.shouldShowWidget,
|
|
71
|
+
sourceFromElement: () => import_feedback_kit_core6.sourceFromElement,
|
|
71
72
|
visibleText: () => visibleText,
|
|
72
|
-
webContextProviders: () => webContextProviders
|
|
73
|
+
webContextProviders: () => webContextProviders,
|
|
74
|
+
webDiagnosticsOptions: () => webDiagnosticsOptions,
|
|
75
|
+
webRouteStorage: () => webRouteStorage,
|
|
76
|
+
webRouteWatcher: () => webRouteWatcher
|
|
73
77
|
});
|
|
74
78
|
module.exports = __toCommonJS(index_exports);
|
|
75
|
-
var import_feedback_kit_core4 = require("@solhun/feedback-kit-core");
|
|
76
79
|
var import_feedback_kit_core5 = require("@solhun/feedback-kit-core");
|
|
77
80
|
var import_feedback_kit_core6 = require("@solhun/feedback-kit-core");
|
|
78
81
|
var import_feedback_kit_core7 = require("@solhun/feedback-kit-core");
|
|
82
|
+
var import_feedback_kit_core8 = require("@solhun/feedback-kit-core");
|
|
79
83
|
|
|
80
84
|
// src/react-tree.ts
|
|
81
85
|
var FRAMEWORK_INTERNALS = /* @__PURE__ */ new Set([
|
|
@@ -162,6 +166,7 @@ function reactComponentSummary(node) {
|
|
|
162
166
|
// src/element-info.ts
|
|
163
167
|
var ELEMENT_TEXT_MAX_CHARS = 200;
|
|
164
168
|
var SELECTOR_MAX_DEPTH = 8;
|
|
169
|
+
var PICK_TARGET_SNAP_PX = 24;
|
|
165
170
|
var KEPT_ATTRS = [
|
|
166
171
|
"id",
|
|
167
172
|
"class",
|
|
@@ -234,6 +239,55 @@ function visibleText(el) {
|
|
|
234
239
|
if (collapsed === "") return null;
|
|
235
240
|
return collapsed.length > ELEMENT_TEXT_MAX_CHARS ? collapsed.slice(0, ELEMENT_TEXT_MAX_CHARS) : collapsed;
|
|
236
241
|
}
|
|
242
|
+
function elementRect(element) {
|
|
243
|
+
try {
|
|
244
|
+
const rect = element.getBoundingClientRect();
|
|
245
|
+
const left = rect.left;
|
|
246
|
+
const top = rect.top;
|
|
247
|
+
const width = rect.width;
|
|
248
|
+
const height = rect.height;
|
|
249
|
+
if (![left, top, width, height].every(Number.isFinite) || width <= 0 || height <= 0) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
element,
|
|
254
|
+
left,
|
|
255
|
+
top,
|
|
256
|
+
right: left + width,
|
|
257
|
+
bottom: top + height,
|
|
258
|
+
width,
|
|
259
|
+
height
|
|
260
|
+
};
|
|
261
|
+
} catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function distanceFromPoint(rect, point) {
|
|
266
|
+
const dx = Math.max(rect.left - point.x, 0, point.x - rect.right);
|
|
267
|
+
const dy = Math.max(rect.top - point.y, 0, point.y - rect.bottom);
|
|
268
|
+
return Math.hypot(dx, dy);
|
|
269
|
+
}
|
|
270
|
+
function resolvePickTarget(target, point) {
|
|
271
|
+
if (!target || typeof target.tagName !== "string") return null;
|
|
272
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return target;
|
|
273
|
+
let current = target;
|
|
274
|
+
while (true) {
|
|
275
|
+
const currentRect = elementRect(current);
|
|
276
|
+
const children = Array.from(current.children).map(elementRect).filter((rect) => rect !== null).map((rect) => ({ rect, distance: distanceFromPoint(rect, point) }));
|
|
277
|
+
if (children.length === 0) return current;
|
|
278
|
+
const containing = children.filter(({ distance }) => distance === 0).sort((a, b) => a.rect.width * a.rect.height - b.rect.width * b.rect.height);
|
|
279
|
+
if (containing[0]) {
|
|
280
|
+
current = containing[0].rect.element;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const nearest = children.sort((a, b) => a.distance - b.distance)[0];
|
|
284
|
+
const isMorePrecise = currentRect ? nearest.rect.width * nearest.rect.height < currentRect.width * currentRect.height : true;
|
|
285
|
+
if (nearest.distance <= PICK_TARGET_SNAP_PX && isMorePrecise) {
|
|
286
|
+
return nearest.rect.element;
|
|
287
|
+
}
|
|
288
|
+
return current;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
237
291
|
function describeElement(el) {
|
|
238
292
|
if (!el || typeof el.tagName !== "string") return null;
|
|
239
293
|
const attributes = {};
|
|
@@ -354,6 +408,84 @@ var MarkerStore = class {
|
|
|
354
408
|
|
|
355
409
|
// src/picking.ts
|
|
356
410
|
var import_feedback_kit_core = require("@solhun/feedback-kit-core");
|
|
411
|
+
|
|
412
|
+
// src/route-watcher.ts
|
|
413
|
+
function defaultTarget() {
|
|
414
|
+
const g = globalThis;
|
|
415
|
+
return g.location ? g : null;
|
|
416
|
+
}
|
|
417
|
+
function createRouteWatcher(target = defaultTarget()) {
|
|
418
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
419
|
+
let detach = null;
|
|
420
|
+
const currentPath = () => {
|
|
421
|
+
const p = target?.location?.pathname;
|
|
422
|
+
return typeof p === "string" && p.length > 0 ? p : "/";
|
|
423
|
+
};
|
|
424
|
+
const emit = () => {
|
|
425
|
+
const path = currentPath();
|
|
426
|
+
for (const listener of [...listeners]) {
|
|
427
|
+
try {
|
|
428
|
+
listener(path);
|
|
429
|
+
} catch {
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
const attach = () => {
|
|
434
|
+
if (detach !== null || !target) return;
|
|
435
|
+
const onPop = () => emit();
|
|
436
|
+
target.addEventListener?.("popstate", onPop);
|
|
437
|
+
const history = target.history;
|
|
438
|
+
const originalPush = typeof history?.pushState === "function" ? history.pushState : null;
|
|
439
|
+
const originalReplace = typeof history?.replaceState === "function" ? history.replaceState : null;
|
|
440
|
+
if (history && originalPush) {
|
|
441
|
+
history.pushState = function patched(...args) {
|
|
442
|
+
const out = originalPush.apply(this, args);
|
|
443
|
+
emit();
|
|
444
|
+
return out;
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (history && originalReplace) {
|
|
448
|
+
history.replaceState = function patched(...args) {
|
|
449
|
+
const out = originalReplace.apply(this, args);
|
|
450
|
+
emit();
|
|
451
|
+
return out;
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
detach = () => {
|
|
455
|
+
target.removeEventListener?.("popstate", onPop);
|
|
456
|
+
if (history && originalPush) history.pushState = originalPush;
|
|
457
|
+
if (history && originalReplace) history.replaceState = originalReplace;
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
return (onPath) => {
|
|
461
|
+
listeners.add(onPath);
|
|
462
|
+
if (listeners.size === 1) attach();
|
|
463
|
+
try {
|
|
464
|
+
onPath(currentPath());
|
|
465
|
+
} catch {
|
|
466
|
+
}
|
|
467
|
+
return () => {
|
|
468
|
+
listeners.delete(onPath);
|
|
469
|
+
if (listeners.size === 0 && detach) {
|
|
470
|
+
detach();
|
|
471
|
+
detach = null;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
var webRouteWatcher = createRouteWatcher();
|
|
477
|
+
function webRouteStorage() {
|
|
478
|
+
try {
|
|
479
|
+
const s = globalThis.sessionStorage;
|
|
480
|
+
if (!s || typeof s.getItem !== "function" || typeof s.setItem !== "function") return null;
|
|
481
|
+
s.getItem("feedback-kit:probe");
|
|
482
|
+
return s;
|
|
483
|
+
} catch {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/picking.ts
|
|
357
489
|
var OWN_UI_ATTR = "data-feedback-kit";
|
|
358
490
|
function defaultDocument() {
|
|
359
491
|
return globalThis.document ?? null;
|
|
@@ -382,10 +514,13 @@ var ElementPickingController = class {
|
|
|
382
514
|
*/
|
|
383
515
|
this.paused = false;
|
|
384
516
|
this.attached = false;
|
|
517
|
+
/** 같은 요소 위 mousemove 마다 React 경로·선택자를 다시 만들지 않기 위한 캐시. */
|
|
518
|
+
this.hoveredTarget = null;
|
|
385
519
|
this.hovered = null;
|
|
386
520
|
this.popup = null;
|
|
387
521
|
this.markers = [];
|
|
388
|
-
|
|
522
|
+
/** 경로 감시 해제. 감시 중이 아니면 null. */
|
|
523
|
+
this.unwatchRoutes = null;
|
|
389
524
|
this.saving = false;
|
|
390
525
|
/** 늦게 끝난 캡처가 다음 주석의 그림을 덮지 못하게 하는 세대 번호. */
|
|
391
526
|
this.shotGeneration = 0;
|
|
@@ -398,6 +533,7 @@ var ElementPickingController = class {
|
|
|
398
533
|
this.userToggledHints = false;
|
|
399
534
|
this.onClick = (event) => this.handleClick(event);
|
|
400
535
|
this.onMouseOver = (event) => this.handleMouseOver(event);
|
|
536
|
+
this.onMouseMove = (event) => this.handleMouseOver(event);
|
|
401
537
|
this.queue = opts.queue;
|
|
402
538
|
this.createReport = opts.createReport;
|
|
403
539
|
this.store = opts.store ?? new MarkerStore();
|
|
@@ -409,6 +545,7 @@ var ElementPickingController = class {
|
|
|
409
545
|
this.reencode = opts.reencode ?? null;
|
|
410
546
|
this.screenshotLimitBytes = opts.screenshotLimitBytes;
|
|
411
547
|
this.rankHintsFor = opts.rankHintsFor ?? null;
|
|
548
|
+
this.watchRoutes = opts.watchRoutes === void 0 ? webRouteWatcher : opts.watchRoutes;
|
|
412
549
|
this.lastPathname = this.getPathname();
|
|
413
550
|
this.markers = this.store.list(this.lastPathname);
|
|
414
551
|
this.unsubscribeQueue = this.queue.subscribe?.(() => {
|
|
@@ -457,6 +594,7 @@ var ElementPickingController = class {
|
|
|
457
594
|
this.store.setPickingActive(false);
|
|
458
595
|
this.detach();
|
|
459
596
|
this.stopPathWatch();
|
|
597
|
+
this.hoveredTarget = null;
|
|
460
598
|
this.hovered = null;
|
|
461
599
|
this.popup = null;
|
|
462
600
|
this.emit();
|
|
@@ -472,6 +610,7 @@ var ElementPickingController = class {
|
|
|
472
610
|
if (!this.active || this.paused) return;
|
|
473
611
|
this.paused = true;
|
|
474
612
|
this.detach();
|
|
613
|
+
this.hoveredTarget = null;
|
|
475
614
|
this.hovered = null;
|
|
476
615
|
this.emit();
|
|
477
616
|
}
|
|
@@ -499,6 +638,22 @@ var ElementPickingController = class {
|
|
|
499
638
|
this.start();
|
|
500
639
|
return true;
|
|
501
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* 이 화면에 쌓인 마커 표시를 지운다.
|
|
643
|
+
*
|
|
644
|
+
* 지워지는 건 **화면 표시뿐**이다. 제보는 이미 큐를 거쳐 수집처로 갔으므로 없어지지 않는다.
|
|
645
|
+
* 마커는 `localStorage` 에 남아 새로고침에도 살아남는데(그게 원래 목적이다) 정작 치울
|
|
646
|
+
* 수단이 없어서, 한 번 보낸 [완료] 배지가 그 화면을 볼 때마다 계속 따라다녔다.
|
|
647
|
+
*
|
|
648
|
+
* 화면에 보이는 목록의 기준은 `lastPathname` 이다(`reconcileMarkerOutcomes` 와 같다).
|
|
649
|
+
* 이동 직후 아직 `syncPath` 가 안 돈 순간에도 "지금 눈에 보이는 것"이 지워져야 한다.
|
|
650
|
+
*/
|
|
651
|
+
clearMarkers() {
|
|
652
|
+
if (this.markers.length === 0) return;
|
|
653
|
+
this.store.clear(this.lastPathname);
|
|
654
|
+
this.markers = [];
|
|
655
|
+
this.emit();
|
|
656
|
+
}
|
|
502
657
|
/** 경로가 바뀌었을 때 그 경로의 마커로 갈아 끼운다. */
|
|
503
658
|
syncPath() {
|
|
504
659
|
if (this.paused) this.resume();
|
|
@@ -506,6 +661,7 @@ var ElementPickingController = class {
|
|
|
506
661
|
this.markers = this.store.list(this.lastPathname);
|
|
507
662
|
this.reconcileMarkerOutcomes();
|
|
508
663
|
this.popup = null;
|
|
664
|
+
this.hoveredTarget = null;
|
|
509
665
|
this.hovered = null;
|
|
510
666
|
this.emit();
|
|
511
667
|
return this.markers;
|
|
@@ -521,17 +677,26 @@ var ElementPickingController = class {
|
|
|
521
677
|
if (this.attached || !this.doc) return;
|
|
522
678
|
this.doc.addEventListener("click", this.onClick, true);
|
|
523
679
|
this.doc.addEventListener("mouseover", this.onMouseOver, true);
|
|
680
|
+
this.doc.addEventListener("mousemove", this.onMouseMove, true);
|
|
524
681
|
this.attached = true;
|
|
525
682
|
}
|
|
526
683
|
detach() {
|
|
527
684
|
if (!this.attached || !this.doc) return;
|
|
528
685
|
this.doc.removeEventListener("click", this.onClick, true);
|
|
529
686
|
this.doc.removeEventListener("mouseover", this.onMouseOver, true);
|
|
687
|
+
this.doc.removeEventListener("mousemove", this.onMouseMove, true);
|
|
530
688
|
this.attached = false;
|
|
531
689
|
}
|
|
532
690
|
handleMouseOver(event) {
|
|
533
691
|
if (!this.active || this.paused || isOwnUi(event.target)) return;
|
|
534
|
-
|
|
692
|
+
const mouse = event;
|
|
693
|
+
const target = resolvePickTarget(event.target, {
|
|
694
|
+
x: mouse.clientX ?? 0,
|
|
695
|
+
y: mouse.clientY ?? 0
|
|
696
|
+
});
|
|
697
|
+
if (target === this.hoveredTarget) return;
|
|
698
|
+
this.hoveredTarget = target;
|
|
699
|
+
this.hovered = describeElement(target);
|
|
535
700
|
this.emit();
|
|
536
701
|
}
|
|
537
702
|
handleClick(event) {
|
|
@@ -552,11 +717,12 @@ var ElementPickingController = class {
|
|
|
552
717
|
/** 클릭 지점 기준으로 주석 팝업을 연다. 좌표는 해상도 무관한 상대값으로 접어 둔다. */
|
|
553
718
|
openAnnotation(element, clientPoint) {
|
|
554
719
|
const point = (0, import_feedback_kit_core.normalizePin)(clientPoint, this.getViewport());
|
|
720
|
+
const target = resolvePickTarget(element, clientPoint);
|
|
555
721
|
if (this.onPick) {
|
|
556
|
-
this.onPick(describeElement(
|
|
722
|
+
this.onPick(describeElement(target), point);
|
|
557
723
|
return;
|
|
558
724
|
}
|
|
559
|
-
const info = describeElement(
|
|
725
|
+
const info = describeElement(target);
|
|
560
726
|
this.userToggledHints = false;
|
|
561
727
|
const hints = this.rankHintsFor ? this.rankHintsFor(info) : [];
|
|
562
728
|
this.popup = {
|
|
@@ -771,17 +937,17 @@ ${hint.draft}`;
|
|
|
771
937
|
return outcome;
|
|
772
938
|
}
|
|
773
939
|
startPathWatch() {
|
|
774
|
-
if (this.
|
|
940
|
+
if (this.unwatchRoutes !== null || !this.watchRoutes) return;
|
|
775
941
|
this.lastPathname = this.getPathname();
|
|
776
|
-
this.
|
|
942
|
+
this.unwatchRoutes = this.watchRoutes(() => {
|
|
777
943
|
const pathname = this.getPathname();
|
|
778
944
|
if (pathname !== this.lastPathname) this.syncPath();
|
|
779
|
-
}
|
|
945
|
+
});
|
|
780
946
|
}
|
|
781
947
|
stopPathWatch() {
|
|
782
|
-
if (this.
|
|
783
|
-
|
|
784
|
-
this.
|
|
948
|
+
if (this.unwatchRoutes === null) return;
|
|
949
|
+
this.unwatchRoutes();
|
|
950
|
+
this.unwatchRoutes = null;
|
|
785
951
|
}
|
|
786
952
|
/** 전역 pending 수가 아니라 마커와 같은 clientSubmissionId의 확정 성공만 완료로 바꾼다. */
|
|
787
953
|
reconcileMarkerOutcomes() {
|
|
@@ -1044,11 +1210,57 @@ function createWebWidget(opts) {
|
|
|
1044
1210
|
}
|
|
1045
1211
|
|
|
1046
1212
|
// src/feedback-kit.tsx
|
|
1047
|
-
var
|
|
1213
|
+
var import_feedback_kit_core4 = require("@solhun/feedback-kit-core");
|
|
1048
1214
|
var import_react = require("react");
|
|
1049
1215
|
|
|
1050
1216
|
// src/version.ts
|
|
1051
|
-
var VERSION = true ? "0.
|
|
1217
|
+
var VERSION = true ? "0.9.0" : "dev";
|
|
1218
|
+
|
|
1219
|
+
// src/dev-clipboard.ts
|
|
1220
|
+
var import_feedback_kit_core3 = require("@solhun/feedback-kit-core");
|
|
1221
|
+
function sourceLine(item) {
|
|
1222
|
+
const mapping = (0, import_feedback_kit_core3.sourceFromElement)(item.element ?? void 0);
|
|
1223
|
+
if (!mapping.sourceFile) return null;
|
|
1224
|
+
return mapping.sourceLine === null ? `\uC18C\uC2A4: ${mapping.sourceFile}` : `\uC18C\uC2A4: ${mapping.sourceFile}:${mapping.sourceLine}`;
|
|
1225
|
+
}
|
|
1226
|
+
function elementLine(element) {
|
|
1227
|
+
if (!element) return null;
|
|
1228
|
+
const selector = element.selector ?? element.tag;
|
|
1229
|
+
const text = element.text?.trim();
|
|
1230
|
+
return text ? `\uC694\uC18C: ${selector} "${text}"` : `\uC694\uC18C: ${selector}`;
|
|
1231
|
+
}
|
|
1232
|
+
function componentLine(element) {
|
|
1233
|
+
const summary = element?.attributes?.["react-components"];
|
|
1234
|
+
return summary ? `\uCEF4\uD3EC\uB10C\uD2B8: ${summary}` : null;
|
|
1235
|
+
}
|
|
1236
|
+
function renderDevClipItem(item) {
|
|
1237
|
+
const lines = [`[\uD53C\uB4DC\uBC31] ${item.comment.trim()}`];
|
|
1238
|
+
const screen = item.screen?.trim();
|
|
1239
|
+
if (screen) lines.push(`\uD654\uBA74: ${screen}`);
|
|
1240
|
+
const element = elementLine(item.element);
|
|
1241
|
+
if (element) lines.push(element);
|
|
1242
|
+
const component = componentLine(item.element);
|
|
1243
|
+
if (component) lines.push(component);
|
|
1244
|
+
const source = sourceLine(item);
|
|
1245
|
+
if (source) lines.push(source);
|
|
1246
|
+
if (item.priority && item.priority !== "unset") lines.push(`\uC6B0\uC120\uC21C\uC704: ${item.priority}`);
|
|
1247
|
+
return lines.join("\n");
|
|
1248
|
+
}
|
|
1249
|
+
function renderDevClipList(items) {
|
|
1250
|
+
if (items.length === 0) return "";
|
|
1251
|
+
if (items.length === 1) return renderDevClipItem(items[0]);
|
|
1252
|
+
return items.map((item, index) => `${index + 1}. ${renderDevClipItem(item).split("\n").join("\n ")}`).join("\n\n");
|
|
1253
|
+
}
|
|
1254
|
+
async function writeToClipboard(text) {
|
|
1255
|
+
const clipboard = globalThis.navigator?.clipboard;
|
|
1256
|
+
if (!clipboard?.writeText) return false;
|
|
1257
|
+
try {
|
|
1258
|
+
await clipboard.writeText(text);
|
|
1259
|
+
return true;
|
|
1260
|
+
} catch {
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1052
1264
|
|
|
1053
1265
|
// src/feedback-kit.tsx
|
|
1054
1266
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -1314,8 +1526,13 @@ function PickToggle({
|
|
|
1314
1526
|
}
|
|
1315
1527
|
function PickBar({
|
|
1316
1528
|
paused,
|
|
1529
|
+
markerCount,
|
|
1317
1530
|
onToggle,
|
|
1318
|
-
onTogglePause
|
|
1531
|
+
onTogglePause,
|
|
1532
|
+
onClearMarkers,
|
|
1533
|
+
onReportWholeScreen,
|
|
1534
|
+
devClipCount,
|
|
1535
|
+
onCopyAll
|
|
1319
1536
|
}) {
|
|
1320
1537
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1321
1538
|
"div",
|
|
@@ -1323,10 +1540,20 @@ function PickBar({
|
|
|
1323
1540
|
style: {
|
|
1324
1541
|
position: "fixed",
|
|
1325
1542
|
top: 16,
|
|
1326
|
-
left:
|
|
1327
|
-
transform
|
|
1543
|
+
// `left:50% + translateX(-50%)` 로 가운데를 잡으면 **쓸 수 있는 폭이 화면의 절반**이
|
|
1544
|
+
// 된다(transform 은 레이아웃 계산에 안 들어간다). 버튼이 셋이 되면서 그 절반에
|
|
1545
|
+
// 안 맞아 좁은 화면에서 버튼이 한 줄에 하나씩 세로로 쌓였다(390px 에서 3줄).
|
|
1546
|
+
// 양끝을 물리고 auto 마진으로 가운데를 잡으면 화면 전체 폭을 쓴다 — 같은 화면이 2줄.
|
|
1547
|
+
left: 0,
|
|
1548
|
+
right: 0,
|
|
1549
|
+
marginInline: "auto",
|
|
1550
|
+
width: "fit-content",
|
|
1551
|
+
maxWidth: "calc(100% - 32px)",
|
|
1328
1552
|
display: "flex",
|
|
1329
1553
|
alignItems: "stretch",
|
|
1554
|
+
justifyContent: "center",
|
|
1555
|
+
// 셋이 한 줄에 안 들어가는 폭에서는 줄을 바꾼다 — 안 그러면 화면 밖으로 나간다.
|
|
1556
|
+
flexWrap: "wrap",
|
|
1330
1557
|
gap: 8,
|
|
1331
1558
|
// 오버레이 자체는 클릭을 통과시킨다(pointerEvents:none) — 이 막대만 되살린다.
|
|
1332
1559
|
pointerEvents: "auto",
|
|
@@ -1359,7 +1586,72 @@ function PickBar({
|
|
|
1359
1586
|
paused ? "\uC9C0\uBAA9 \uC7AC\uAC1C" : "\uC7A0\uC2DC \uBA48\uCDA4"
|
|
1360
1587
|
]
|
|
1361
1588
|
}
|
|
1362
|
-
)
|
|
1589
|
+
),
|
|
1590
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1591
|
+
"button",
|
|
1592
|
+
{
|
|
1593
|
+
type: "button",
|
|
1594
|
+
"data-fk-pick-whole": "",
|
|
1595
|
+
title: "\uAC00\uB9AC\uD0A8 \uC694\uC18C \uC5C6\uC774 \uC774 \uD654\uBA74 \uC804\uCCB4\uC5D0 \uB300\uD574 \uC81C\uBCF4\uD569\uB2C8\uB2E4.",
|
|
1596
|
+
onClick: onReportWholeScreen,
|
|
1597
|
+
style: {
|
|
1598
|
+
...baseButton,
|
|
1599
|
+
display: "inline-flex",
|
|
1600
|
+
alignItems: "center",
|
|
1601
|
+
gap: 6,
|
|
1602
|
+
whiteSpace: "nowrap"
|
|
1603
|
+
},
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "\u25A3" }),
|
|
1606
|
+
"\uD654\uBA74 \uC804\uCCB4\uB85C \uBCF4\uB0B4\uAE30"
|
|
1607
|
+
]
|
|
1608
|
+
}
|
|
1609
|
+
),
|
|
1610
|
+
devClipCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1611
|
+
"button",
|
|
1612
|
+
{
|
|
1613
|
+
type: "button",
|
|
1614
|
+
"data-fk-copy-all": devClipCount,
|
|
1615
|
+
title: "\uC774\uBC88 \uC138\uC158\uC5D0 \uCC0D\uC740 \uAC83\uC744 \uBC88\uD638 \uB9E4\uAE34 \uBAA9\uB85D \uD558\uB098\uB85C \uBCF5\uC0AC\uD569\uB2C8\uB2E4.",
|
|
1616
|
+
onClick: onCopyAll,
|
|
1617
|
+
style: {
|
|
1618
|
+
...baseButton,
|
|
1619
|
+
display: "inline-flex",
|
|
1620
|
+
alignItems: "center",
|
|
1621
|
+
gap: 6,
|
|
1622
|
+
whiteSpace: "nowrap",
|
|
1623
|
+
fontWeight: 600
|
|
1624
|
+
},
|
|
1625
|
+
children: [
|
|
1626
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "\u29C9" }),
|
|
1627
|
+
"\uC804\uBD80 \uBCF5\uC0AC ",
|
|
1628
|
+
devClipCount
|
|
1629
|
+
]
|
|
1630
|
+
}
|
|
1631
|
+
) : null,
|
|
1632
|
+
markerCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1633
|
+
"button",
|
|
1634
|
+
{
|
|
1635
|
+
type: "button",
|
|
1636
|
+
"data-fk-pick-clear": markerCount,
|
|
1637
|
+
title: "\uD654\uBA74\uC758 \uD45C\uC2DC\uB9CC \uC9C0\uC6C1\uB2C8\uB2E4. \uBCF4\uB0B8 \uC81C\uBCF4\uB294 \uADF8\uB300\uB85C \uB0A8\uC2B5\uB2C8\uB2E4.",
|
|
1638
|
+
"aria-label": `\uC774 \uD654\uBA74\uC758 \uC8FC\uC11D \uD45C\uC2DC ${markerCount}\uAC1C \uC9C0\uC6B0\uAE30 (\uBCF4\uB0B8 \uC81C\uBCF4\uB294 \uADF8\uB300\uB85C \uB0A8\uC2B5\uB2C8\uB2E4)`,
|
|
1639
|
+
onClick: onClearMarkers,
|
|
1640
|
+
style: {
|
|
1641
|
+
...baseButton,
|
|
1642
|
+
display: "inline-flex",
|
|
1643
|
+
alignItems: "center",
|
|
1644
|
+
gap: 6,
|
|
1645
|
+
whiteSpace: "nowrap",
|
|
1646
|
+
color: TOKENS.muted
|
|
1647
|
+
},
|
|
1648
|
+
children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "\u2715" }),
|
|
1650
|
+
"\uD45C\uC2DC \uC9C0\uC6B0\uAE30 ",
|
|
1651
|
+
markerCount
|
|
1652
|
+
]
|
|
1653
|
+
}
|
|
1654
|
+
) : null
|
|
1363
1655
|
]
|
|
1364
1656
|
}
|
|
1365
1657
|
);
|
|
@@ -1391,7 +1683,7 @@ function HintChips({
|
|
|
1391
1683
|
"button",
|
|
1392
1684
|
{
|
|
1393
1685
|
type: "button",
|
|
1394
|
-
"data-fk-focus-id":
|
|
1686
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_ACTION_HINT_TOGGLE,
|
|
1395
1687
|
"aria-expanded": hintsExpanded,
|
|
1396
1688
|
disabled,
|
|
1397
1689
|
onClick: onToggle,
|
|
@@ -1465,6 +1757,10 @@ function FeedbackKit(props) {
|
|
|
1465
1757
|
const [widgetState, setWidgetState] = (0, import_react.useState)(null);
|
|
1466
1758
|
const [pickingState, setPickingState] = (0, import_react.useState)(INITIAL_PICKING_STATE);
|
|
1467
1759
|
const [announcement, setAnnouncement] = (0, import_react.useState)(null);
|
|
1760
|
+
const [devMode] = (0, import_react.useState)(() => props.devMode === true);
|
|
1761
|
+
const devClipsRef = (0, import_react.useRef)([]);
|
|
1762
|
+
const [devClipCount, setDevClipCount] = (0, import_react.useState)(0);
|
|
1763
|
+
const [devFallbackText, setDevFallbackText] = (0, import_react.useState)(null);
|
|
1468
1764
|
const {
|
|
1469
1765
|
queue,
|
|
1470
1766
|
createReport,
|
|
@@ -1525,7 +1821,7 @@ function FeedbackKit(props) {
|
|
|
1525
1821
|
}
|
|
1526
1822
|
if (modal2.closeConfirmVisible && !previousConfirmVisibleRef.current) confirmRef.current?.focus();
|
|
1527
1823
|
const wasModal = previousScreenRef.current === "modal";
|
|
1528
|
-
if (wasModal && screen2 === "button" && modal2.restoreFocusTo ===
|
|
1824
|
+
if (wasModal && screen2 === "button" && modal2.restoreFocusTo === import_feedback_kit_core4.FLOATING_BUTTON_ID) {
|
|
1529
1825
|
void nextPaint().then(() => floatingButtonRef.current?.focus());
|
|
1530
1826
|
}
|
|
1531
1827
|
previousScreenRef.current = screen2;
|
|
@@ -1589,6 +1885,39 @@ function FeedbackKit(props) {
|
|
|
1589
1885
|
if (root) root.style.visibility = previousVisibility;
|
|
1590
1886
|
}
|
|
1591
1887
|
}
|
|
1888
|
+
function currentClip() {
|
|
1889
|
+
const state = pickingState.popup;
|
|
1890
|
+
if (!state) return null;
|
|
1891
|
+
return {
|
|
1892
|
+
comment: state.comment,
|
|
1893
|
+
element: state.element ?? null,
|
|
1894
|
+
screen: typeof location === "undefined" ? null : location.pathname
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
async function putOnClipboard(text) {
|
|
1898
|
+
const ok = await writeToClipboard(text);
|
|
1899
|
+
setDevFallbackText(ok ? null : text);
|
|
1900
|
+
}
|
|
1901
|
+
async function copyOne() {
|
|
1902
|
+
const clip = currentClip();
|
|
1903
|
+
if (!clip || clip.comment.trim() === "") return;
|
|
1904
|
+
devClipsRef.current = [...devClipsRef.current, clip];
|
|
1905
|
+
setDevClipCount(devClipsRef.current.length);
|
|
1906
|
+
activeKit.picking.cancelAnnotation();
|
|
1907
|
+
await putOnClipboard(renderDevClipItem(clip));
|
|
1908
|
+
}
|
|
1909
|
+
async function copyAll() {
|
|
1910
|
+
if (devClipsRef.current.length === 0) return;
|
|
1911
|
+
await putOnClipboard(renderDevClipList(devClipsRef.current));
|
|
1912
|
+
}
|
|
1913
|
+
async function pressFloatingButton() {
|
|
1914
|
+
if (props.defaultMode !== "report" && !pickingActive) {
|
|
1915
|
+
setAnnouncement(null);
|
|
1916
|
+
activeKit.widget.startPicking();
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
await openReport();
|
|
1920
|
+
}
|
|
1592
1921
|
async function openReport() {
|
|
1593
1922
|
setAnnouncement(null);
|
|
1594
1923
|
await withOwnUiHidden(() => activeKit.widget.openReport());
|
|
@@ -1655,10 +1984,10 @@ function FeedbackKit(props) {
|
|
|
1655
1984
|
"button",
|
|
1656
1985
|
{
|
|
1657
1986
|
ref: floatingButtonRef,
|
|
1658
|
-
id:
|
|
1987
|
+
id: import_feedback_kit_core4.FLOATING_BUTTON_ID,
|
|
1659
1988
|
type: "button",
|
|
1660
1989
|
"aria-label": "\uD53C\uB4DC\uBC31 \uBCF4\uB0B4\uAE30",
|
|
1661
|
-
onClick: () => void
|
|
1990
|
+
onClick: () => void pressFloatingButton(),
|
|
1662
1991
|
style: {
|
|
1663
1992
|
...primaryButton,
|
|
1664
1993
|
position: "fixed",
|
|
@@ -1673,6 +2002,66 @@ function FeedbackKit(props) {
|
|
|
1673
2002
|
children: "\uD53C\uB4DC\uBC31"
|
|
1674
2003
|
}
|
|
1675
2004
|
) : null,
|
|
2005
|
+
floating && devMode ? (
|
|
2006
|
+
// 켠 줄 모르고 제보하면 "보냈다"고 믿는데 수집처엔 아무것도 안 남는다.
|
|
2007
|
+
// 조용한 유실이라 이 표시가 유일한 방어다. 버튼 **밖**에 두는 이유는 버튼의
|
|
2008
|
+
// 접근성 이름을 오염시키지 않기 위해서다.
|
|
2009
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2010
|
+
"span",
|
|
2011
|
+
{
|
|
2012
|
+
"data-fk-dev-badge": "",
|
|
2013
|
+
"aria-label": "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uAC00 \uCF1C\uC838 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uC81C\uBCF4\uAC00 \uC218\uC9D1\uCC98\uB85C \uAC00\uC9C0 \uC54A\uACE0 \uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC\uB429\uB2C8\uB2E4",
|
|
2014
|
+
style: {
|
|
2015
|
+
position: "fixed",
|
|
2016
|
+
right: 24,
|
|
2017
|
+
bottom: 62,
|
|
2018
|
+
zIndex: 2147483601,
|
|
2019
|
+
padding: "2px 8px",
|
|
2020
|
+
borderRadius: 6,
|
|
2021
|
+
background: TOKENS.warning,
|
|
2022
|
+
color: "#1f2933",
|
|
2023
|
+
fontSize: 11,
|
|
2024
|
+
fontWeight: 700,
|
|
2025
|
+
pointerEvents: "none"
|
|
2026
|
+
},
|
|
2027
|
+
children: "\uAC1C\uBC1C\uC6A9 \u2014 \uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC"
|
|
2028
|
+
}
|
|
2029
|
+
)
|
|
2030
|
+
) : null,
|
|
2031
|
+
devFallbackText !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2032
|
+
"div",
|
|
2033
|
+
{
|
|
2034
|
+
role: "dialog",
|
|
2035
|
+
"aria-label": "\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBABB \uC368\uC11C \uB300\uC2E0 \uBCF4\uC5EC\uC90D\uB2C8\uB2E4",
|
|
2036
|
+
"data-fk-dev-fallback": "",
|
|
2037
|
+
style: {
|
|
2038
|
+
position: "fixed",
|
|
2039
|
+
right: 24,
|
|
2040
|
+
bottom: 92,
|
|
2041
|
+
zIndex: 2147483602,
|
|
2042
|
+
width: "min(420px, calc(100vw - 48px))",
|
|
2043
|
+
border: `1px solid ${TOKENS.line}`,
|
|
2044
|
+
borderRadius: 12,
|
|
2045
|
+
background: TOKENS.surface,
|
|
2046
|
+
padding: 12,
|
|
2047
|
+
boxShadow: TOKENS.shadow,
|
|
2048
|
+
pointerEvents: "auto"
|
|
2049
|
+
},
|
|
2050
|
+
children: [
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: 6, color: TOKENS.muted, fontSize: 12 }, children: "\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC544\uB798\uC5D0\uC11C \uC9C1\uC811 \uBCF5\uC0AC\uD558\uC138\uC694." }),
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2053
|
+
"textarea",
|
|
2054
|
+
{
|
|
2055
|
+
readOnly: true,
|
|
2056
|
+
value: devFallbackText,
|
|
2057
|
+
onFocus: (event) => event.currentTarget.select(),
|
|
2058
|
+
style: { ...inputStyle, height: 140, fontFamily: "ui-monospace, monospace", fontSize: 12 }
|
|
2059
|
+
}
|
|
2060
|
+
),
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => setDevFallbackText(null), style: baseButton, children: "\uB2EB\uAE30" }) })
|
|
2062
|
+
]
|
|
2063
|
+
}
|
|
2064
|
+
) : null,
|
|
1676
2065
|
announcement && !modal.open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1677
2066
|
"div",
|
|
1678
2067
|
{
|
|
@@ -1770,7 +2159,7 @@ function FeedbackKit(props) {
|
|
|
1770
2159
|
active: pickingActive,
|
|
1771
2160
|
paused: pickingState.paused,
|
|
1772
2161
|
disabled: draftLocked,
|
|
1773
|
-
focusId:
|
|
2162
|
+
focusId: import_feedback_kit_core4.MODAL_ACTION_PICK,
|
|
1774
2163
|
onToggle: togglePicking
|
|
1775
2164
|
}
|
|
1776
2165
|
),
|
|
@@ -1804,7 +2193,7 @@ function FeedbackKit(props) {
|
|
|
1804
2193
|
"button",
|
|
1805
2194
|
{
|
|
1806
2195
|
type: "button",
|
|
1807
|
-
"data-fk-focus-id":
|
|
2196
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_ACTION_REMOVE_SCREENSHOT,
|
|
1808
2197
|
disabled: draftLocked,
|
|
1809
2198
|
onClick: () => kit.widget.modal.removeScreenshot(),
|
|
1810
2199
|
style: baseButton,
|
|
@@ -1864,7 +2253,7 @@ function FeedbackKit(props) {
|
|
|
1864
2253
|
"textarea",
|
|
1865
2254
|
{
|
|
1866
2255
|
id: "feedback-kit-comment",
|
|
1867
|
-
"data-fk-focus-id":
|
|
2256
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_FIELD_COMMENT,
|
|
1868
2257
|
value: modal.comment,
|
|
1869
2258
|
disabled: draftLocked,
|
|
1870
2259
|
"aria-required": "true",
|
|
@@ -1885,7 +2274,7 @@ function FeedbackKit(props) {
|
|
|
1885
2274
|
"select",
|
|
1886
2275
|
{
|
|
1887
2276
|
id: "feedback-kit-priority",
|
|
1888
|
-
"data-fk-focus-id":
|
|
2277
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_FIELD_PRIORITY,
|
|
1889
2278
|
value: modal.priority,
|
|
1890
2279
|
disabled: draftLocked,
|
|
1891
2280
|
onChange: (event) => kit.widget.modal.setPriority(event.currentTarget.value),
|
|
@@ -1917,7 +2306,7 @@ function FeedbackKit(props) {
|
|
|
1917
2306
|
"button",
|
|
1918
2307
|
{
|
|
1919
2308
|
type: "button",
|
|
1920
|
-
"data-fk-focus-id":
|
|
2309
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_ACTION_RETRY,
|
|
1921
2310
|
onClick: () => void kit.widget.retryReport(),
|
|
1922
2311
|
style: { ...baseButton, marginLeft: 10 },
|
|
1923
2312
|
children: "\uB2E4\uC2DC \uBCF4\uB0B4\uAE30"
|
|
@@ -1931,7 +2320,7 @@ function FeedbackKit(props) {
|
|
|
1931
2320
|
"button",
|
|
1932
2321
|
{
|
|
1933
2322
|
type: "button",
|
|
1934
|
-
"data-fk-focus-id":
|
|
2323
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_ACTION_CANCEL,
|
|
1935
2324
|
onClick: closeReport,
|
|
1936
2325
|
style: baseButton,
|
|
1937
2326
|
children: "\uCDE8\uC18C"
|
|
@@ -1941,7 +2330,7 @@ function FeedbackKit(props) {
|
|
|
1941
2330
|
"button",
|
|
1942
2331
|
{
|
|
1943
2332
|
type: "submit",
|
|
1944
|
-
"data-fk-focus-id":
|
|
2333
|
+
"data-fk-focus-id": import_feedback_kit_core4.MODAL_ACTION_SEND,
|
|
1945
2334
|
disabled: !modal.canSubmit,
|
|
1946
2335
|
style: {
|
|
1947
2336
|
...primaryButton,
|
|
@@ -2024,8 +2413,13 @@ function FeedbackKit(props) {
|
|
|
2024
2413
|
PickBar,
|
|
2025
2414
|
{
|
|
2026
2415
|
paused: pickingState.paused,
|
|
2416
|
+
markerCount: pickingState.markers.length,
|
|
2027
2417
|
onToggle: togglePicking,
|
|
2028
|
-
onTogglePause: () => activeKit.picking.togglePause()
|
|
2418
|
+
onTogglePause: () => activeKit.picking.togglePause(),
|
|
2419
|
+
onClearMarkers: () => activeKit.picking.clearMarkers(),
|
|
2420
|
+
onReportWholeScreen: () => void openReport(),
|
|
2421
|
+
devClipCount: devMode ? devClipCount : 0,
|
|
2422
|
+
onCopyAll: () => void copyAll()
|
|
2029
2423
|
}
|
|
2030
2424
|
),
|
|
2031
2425
|
pickingState.markers.map((marker, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -2062,6 +2456,10 @@ function FeedbackKit(props) {
|
|
|
2062
2456
|
"aria-label": "\uC694\uC18C \uC8FC\uC11D",
|
|
2063
2457
|
onSubmit: (event) => {
|
|
2064
2458
|
event.preventDefault();
|
|
2459
|
+
if (devMode) {
|
|
2460
|
+
void copyOne();
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2065
2463
|
void kit.picking.saveAnnotation();
|
|
2066
2464
|
},
|
|
2067
2465
|
onPaste: (event) => {
|
|
@@ -2151,7 +2549,7 @@ function FeedbackKit(props) {
|
|
|
2151
2549
|
style: { ...inputStyle, resize: "vertical", minHeight: 58 }
|
|
2152
2550
|
}
|
|
2153
2551
|
),
|
|
2154
|
-
popup.comment.length >
|
|
2552
|
+
popup.comment.length > import_feedback_kit_core4.COMMENT_MAX_CHARS ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "alert", style: { marginTop: 4, color: TOKENS.danger }, children: "4,000\uC790 \uC774\uD558\uB85C \uC785\uB825\uD574\uC8FC\uC138\uC694" }) : null,
|
|
2155
2553
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2156
2554
|
"div",
|
|
2157
2555
|
{
|
|
@@ -2215,7 +2613,7 @@ function FeedbackKit(props) {
|
|
|
2215
2613
|
opacity: popup.canSave && !popup.saving ? 1 : 0.5,
|
|
2216
2614
|
cursor: popup.canSave && !popup.saving ? "pointer" : "not-allowed"
|
|
2217
2615
|
},
|
|
2218
|
-
children: popup.saving ? "\uBCF4\uB0B4\uB294 \uC911\u2026" : "\uBCF4\uB0B4\uAE30"
|
|
2616
|
+
children: popup.saving ? "\uBCF4\uB0B4\uB294 \uC911\u2026" : devMode ? "\uBCF5\uC0AC" : "\uBCF4\uB0B4\uAE30"
|
|
2219
2617
|
}
|
|
2220
2618
|
)
|
|
2221
2619
|
] })
|
|
@@ -2251,6 +2649,13 @@ function webContextProviders() {
|
|
|
2251
2649
|
}
|
|
2252
2650
|
};
|
|
2253
2651
|
}
|
|
2652
|
+
function webDiagnosticsOptions(opts = {}) {
|
|
2653
|
+
return {
|
|
2654
|
+
watchRoutes: webRouteWatcher,
|
|
2655
|
+
routeStorage: webRouteStorage(),
|
|
2656
|
+
...opts
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2254
2659
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2255
2660
|
0 && (module.exports = {
|
|
2256
2661
|
COMMENT_MAX_CHARS,
|
|
@@ -2276,6 +2681,7 @@ function webContextProviders() {
|
|
|
2276
2681
|
SUBMIT_PENDING_MESSAGE,
|
|
2277
2682
|
WidgetController,
|
|
2278
2683
|
captureWebScreenshot,
|
|
2684
|
+
createRouteWatcher,
|
|
2279
2685
|
createWebStorage,
|
|
2280
2686
|
createWebWidget,
|
|
2281
2687
|
cssSelectorPath,
|
|
@@ -2292,6 +2698,9 @@ function webContextProviders() {
|
|
|
2292
2698
|
shouldShowWidget,
|
|
2293
2699
|
sourceFromElement,
|
|
2294
2700
|
visibleText,
|
|
2295
|
-
webContextProviders
|
|
2701
|
+
webContextProviders,
|
|
2702
|
+
webDiagnosticsOptions,
|
|
2703
|
+
webRouteStorage,
|
|
2704
|
+
webRouteWatcher
|
|
2296
2705
|
});
|
|
2297
2706
|
//# sourceMappingURL=index.cjs.map
|