@kelet-ai/feedback-ui 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/dist/components/vote-feedback.d.ts +1 -1
- package/dist/feedback-ui.es.js +120 -22
- package/dist/feedback-ui.es.js.map +1 -1
- package/dist/feedback-ui.es.min.js +690 -617
- package/dist/feedback-ui.es.min.js.map +1 -1
- package/dist/feedback-ui.umd.js +119 -21
- package/dist/feedback-ui.umd.js.map +1 -1
- package/dist/feedback-ui.umd.min.js +12 -12
- package/dist/feedback-ui.umd.min.js.map +1 -1
- package/dist/hooks/feedback-state/use-feedback-reducer.d.ts +5 -5
- package/dist/hooks/feedback-state/use-feedback-state.d.ts +6 -6
- package/dist/hooks/feedback-state/use-state-change-tracking.d.ts +2 -2
- package/dist/lib/event-capture.d.ts +22 -0
- package/dist/types/index.d.ts +22 -2
- package/package.json +1 -1
package/dist/feedback-ui.umd.js
CHANGED
|
@@ -355,6 +355,88 @@
|
|
|
355
355
|
return jsxRuntime.exports;
|
|
356
356
|
}
|
|
357
357
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
358
|
+
let latestEvent = null;
|
|
359
|
+
let isInitialized = false;
|
|
360
|
+
function serializeTarget(target) {
|
|
361
|
+
if (!target || !(target instanceof Element)) return "unknown";
|
|
362
|
+
const el = target;
|
|
363
|
+
if (el.id) return `#${el.id}`;
|
|
364
|
+
const dataId = el.getAttribute("data-feedback-id");
|
|
365
|
+
if (dataId) return `[data-feedback-id="${dataId}"]`;
|
|
366
|
+
const path = [];
|
|
367
|
+
let current = el;
|
|
368
|
+
let depth = 0;
|
|
369
|
+
const MAX_DEPTH = 5;
|
|
370
|
+
while (current && current !== document.body && depth < MAX_DEPTH) {
|
|
371
|
+
let selector = current.tagName.toLowerCase();
|
|
372
|
+
if (current.classList.length > 0) {
|
|
373
|
+
const className = Array.from(current.classList)[0];
|
|
374
|
+
selector += `.${className}`;
|
|
375
|
+
}
|
|
376
|
+
const parent = current.parentElement;
|
|
377
|
+
if (parent) {
|
|
378
|
+
const siblings = Array.from(parent.children);
|
|
379
|
+
const index = siblings.indexOf(current) + 1;
|
|
380
|
+
if (siblings.length > 1) {
|
|
381
|
+
selector += `:nth-child(${index})`;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
path.unshift(selector);
|
|
385
|
+
current = parent;
|
|
386
|
+
depth++;
|
|
387
|
+
}
|
|
388
|
+
return path.join(" > ");
|
|
389
|
+
}
|
|
390
|
+
function getTargetText(target) {
|
|
391
|
+
if (!target || !(target instanceof Element)) return "";
|
|
392
|
+
const el = target;
|
|
393
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
394
|
+
if (ariaLabel) return ariaLabel.substring(0, 50);
|
|
395
|
+
const text = el.textContent?.trim() || "";
|
|
396
|
+
return text.substring(0, 50);
|
|
397
|
+
}
|
|
398
|
+
function captureEvent(e) {
|
|
399
|
+
const captured = {
|
|
400
|
+
type: e.type,
|
|
401
|
+
targetSelector: serializeTarget(e.target),
|
|
402
|
+
targetText: getTargetText(e.target),
|
|
403
|
+
timestamp: Date.now()
|
|
404
|
+
};
|
|
405
|
+
if (e instanceof MouseEvent) {
|
|
406
|
+
captured.coordinates = { x: e.clientX, y: e.clientY };
|
|
407
|
+
} else if (e instanceof KeyboardEvent) {
|
|
408
|
+
captured.key = e.key;
|
|
409
|
+
}
|
|
410
|
+
return captured;
|
|
411
|
+
}
|
|
412
|
+
function initEventCapture() {
|
|
413
|
+
if (isInitialized || typeof window === "undefined") return;
|
|
414
|
+
const eventTypes = ["click", "keydown", "submit", "change"];
|
|
415
|
+
eventTypes.forEach((type) => {
|
|
416
|
+
window.addEventListener(
|
|
417
|
+
type,
|
|
418
|
+
(e) => {
|
|
419
|
+
latestEvent = captureEvent(e);
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
capture: true,
|
|
423
|
+
// Intercept before React handlers
|
|
424
|
+
passive: true
|
|
425
|
+
// Better scroll performance
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
});
|
|
429
|
+
isInitialized = true;
|
|
430
|
+
}
|
|
431
|
+
function getLatestEvent() {
|
|
432
|
+
if (!latestEvent) return null;
|
|
433
|
+
const age = Date.now() - latestEvent.timestamp;
|
|
434
|
+
if (age > 1e4) {
|
|
435
|
+
latestEvent = null;
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
return { ...latestEvent };
|
|
439
|
+
}
|
|
358
440
|
const KeletContext = require$$0$1.createContext(null);
|
|
359
441
|
const DefaultKeletBaseUrl = "https://api.kelet.ai/api";
|
|
360
442
|
const useKelet = () => {
|
|
@@ -377,6 +459,9 @@
|
|
|
377
459
|
}
|
|
378
460
|
};
|
|
379
461
|
const KeletProvider = ({ apiKey, project, baseUrl, children }) => {
|
|
462
|
+
require$$0$1.useEffect(() => {
|
|
463
|
+
initEventCapture();
|
|
464
|
+
}, []);
|
|
380
465
|
const parentContext = require$$0$1.useContext(KeletContext);
|
|
381
466
|
const resolvedApiKey = apiKey || parentContext?.api_key;
|
|
382
467
|
if (!resolvedApiKey) {
|
|
@@ -386,15 +471,21 @@
|
|
|
386
471
|
}
|
|
387
472
|
const feedback = async (data) => {
|
|
388
473
|
const resolvedBaseUrl = baseUrl || DefaultKeletBaseUrl;
|
|
389
|
-
const url = `${resolvedBaseUrl}/projects/${project}/
|
|
474
|
+
const url = `${resolvedBaseUrl}/projects/${project}/signal`;
|
|
475
|
+
const capturedEvent = getLatestEvent();
|
|
476
|
+
const metadata = {
|
|
477
|
+
...data.extra_metadata ?? {},
|
|
478
|
+
...capturedEvent && { $dom_event: capturedEvent }
|
|
479
|
+
};
|
|
390
480
|
const req = {
|
|
391
|
-
|
|
481
|
+
session_id: data.session_id,
|
|
392
482
|
source: data.source || "EXPLICIT",
|
|
393
483
|
vote: data.vote,
|
|
394
484
|
explanation: data.explanation,
|
|
395
485
|
correction: data.correction,
|
|
396
|
-
selection: data.selection
|
|
397
|
-
|
|
486
|
+
selection: data.selection,
|
|
487
|
+
trigger_name: data.trigger_name,
|
|
488
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
398
489
|
};
|
|
399
490
|
const response = await fetch(url, {
|
|
400
491
|
method: "POST",
|
|
@@ -456,11 +547,11 @@
|
|
|
456
547
|
children,
|
|
457
548
|
onFeedback,
|
|
458
549
|
defaultText = "",
|
|
459
|
-
|
|
550
|
+
session_id: sessionIdProp,
|
|
460
551
|
extra_metadata,
|
|
461
552
|
trigger_name
|
|
462
553
|
}) => {
|
|
463
|
-
const
|
|
554
|
+
const session_id = typeof sessionIdProp === "function" ? sessionIdProp() : sessionIdProp;
|
|
464
555
|
const [showPopover, setShowPopover] = require$$0$1.useState(false);
|
|
465
556
|
const [feedbackText, setFeedbackText] = require$$0$1.useState(defaultText);
|
|
466
557
|
const [isSubmitting, setIsSubmitting] = require$$0$1.useState(false);
|
|
@@ -477,11 +568,11 @@
|
|
|
477
568
|
setIsSubmitting(false);
|
|
478
569
|
setVote(null);
|
|
479
570
|
setTimeout(() => triggerRef.current?.focus(), 0);
|
|
480
|
-
}, [
|
|
571
|
+
}, [session_id, defaultText]);
|
|
481
572
|
const handleUpvote = require$$0$1.useCallback(async () => {
|
|
482
573
|
setVote("upvote");
|
|
483
574
|
const data = {
|
|
484
|
-
|
|
575
|
+
session_id,
|
|
485
576
|
vote: "upvote",
|
|
486
577
|
...extra_metadata && { extra_metadata },
|
|
487
578
|
...trigger_name && { trigger_name }
|
|
@@ -492,12 +583,12 @@
|
|
|
492
583
|
} finally {
|
|
493
584
|
setIsSubmitting(false);
|
|
494
585
|
}
|
|
495
|
-
}, [handler,
|
|
586
|
+
}, [handler, session_id, extra_metadata, trigger_name]);
|
|
496
587
|
const handleDownvote = require$$0$1.useCallback(async () => {
|
|
497
588
|
setVote("downvote");
|
|
498
589
|
if (handler) {
|
|
499
590
|
const data = {
|
|
500
|
-
|
|
591
|
+
session_id,
|
|
501
592
|
vote: "downvote",
|
|
502
593
|
...extra_metadata && { extra_metadata },
|
|
503
594
|
...trigger_name && { trigger_name }
|
|
@@ -520,7 +611,7 @@
|
|
|
520
611
|
document.body.appendChild(announcement);
|
|
521
612
|
setTimeout(() => document.body.removeChild(announcement), 1e3);
|
|
522
613
|
}, 0);
|
|
523
|
-
}, [handler,
|
|
614
|
+
}, [handler, session_id, extra_metadata, trigger_name]);
|
|
524
615
|
const handleTextareaChange = require$$0$1.useCallback(
|
|
525
616
|
(e) => {
|
|
526
617
|
setFeedbackText(e.target.value);
|
|
@@ -531,7 +622,7 @@
|
|
|
531
622
|
const hasText = feedbackText.trim().length > 0;
|
|
532
623
|
if (hasText) {
|
|
533
624
|
const data = {
|
|
534
|
-
|
|
625
|
+
session_id,
|
|
535
626
|
vote: "downvote",
|
|
536
627
|
explanation: feedbackText,
|
|
537
628
|
...extra_metadata && { extra_metadata },
|
|
@@ -555,7 +646,14 @@
|
|
|
555
646
|
document.body.appendChild(announcement);
|
|
556
647
|
setTimeout(() => document.body.removeChild(announcement), 1e3);
|
|
557
648
|
}
|
|
558
|
-
}, [
|
|
649
|
+
}, [
|
|
650
|
+
handler,
|
|
651
|
+
feedbackText,
|
|
652
|
+
defaultText,
|
|
653
|
+
session_id,
|
|
654
|
+
extra_metadata,
|
|
655
|
+
trigger_name
|
|
656
|
+
]);
|
|
559
657
|
const handleKeyDown = require$$0$1.useCallback(
|
|
560
658
|
(e) => {
|
|
561
659
|
if (e.key === "Escape") {
|
|
@@ -604,7 +702,7 @@
|
|
|
604
702
|
triggerRef,
|
|
605
703
|
popoverId,
|
|
606
704
|
triggerId,
|
|
607
|
-
|
|
705
|
+
session_id,
|
|
608
706
|
extra_metadata,
|
|
609
707
|
trigger_name
|
|
610
708
|
};
|
|
@@ -2019,7 +2117,7 @@
|
|
|
2019
2117
|
return String(value);
|
|
2020
2118
|
}
|
|
2021
2119
|
}
|
|
2022
|
-
function useStateChangeTracking(currentState,
|
|
2120
|
+
function useStateChangeTracking(currentState, session_id, options) {
|
|
2023
2121
|
const defaultFeedbackHandler = useDefaultFeedbackHandler();
|
|
2024
2122
|
const feedbackHandler = options?.onFeedback || defaultFeedbackHandler;
|
|
2025
2123
|
const debounceMs = options?.debounceMs ?? 3e3;
|
|
@@ -2054,9 +2152,9 @@
|
|
|
2054
2152
|
} else {
|
|
2055
2153
|
vote = diffPercentage > 0.5 ? "downvote" : "upvote";
|
|
2056
2154
|
}
|
|
2057
|
-
const idString = typeof
|
|
2155
|
+
const idString = typeof session_id === "function" ? session_id(endState) : session_id;
|
|
2058
2156
|
feedbackHandler({
|
|
2059
|
-
|
|
2157
|
+
session_id: idString,
|
|
2060
2158
|
vote,
|
|
2061
2159
|
explanation: `State change with diff percentage: ${(diffPercentage * 100).toFixed(1)}%`,
|
|
2062
2160
|
correction: diffString,
|
|
@@ -2065,7 +2163,7 @@
|
|
|
2065
2163
|
trigger_name: triggerName
|
|
2066
2164
|
});
|
|
2067
2165
|
},
|
|
2068
|
-
[options,
|
|
2166
|
+
[options, session_id, diffType, feedbackHandler]
|
|
2069
2167
|
);
|
|
2070
2168
|
const notifyChange = require$$0$1.useCallback(
|
|
2071
2169
|
(trigger_name) => {
|
|
@@ -2134,7 +2232,7 @@
|
|
|
2134
2232
|
};
|
|
2135
2233
|
}, [
|
|
2136
2234
|
currentState,
|
|
2137
|
-
|
|
2235
|
+
session_id,
|
|
2138
2236
|
options,
|
|
2139
2237
|
feedbackHandler,
|
|
2140
2238
|
diffType,
|
|
@@ -2148,9 +2246,9 @@
|
|
|
2148
2246
|
notifyChange
|
|
2149
2247
|
};
|
|
2150
2248
|
}
|
|
2151
|
-
function useFeedbackState(initialState,
|
|
2249
|
+
function useFeedbackState(initialState, session_id, options) {
|
|
2152
2250
|
const [state, setStateInternal] = require$$0$1.useState(initialState);
|
|
2153
|
-
const { notifyChange } = useStateChangeTracking(state,
|
|
2251
|
+
const { notifyChange } = useStateChangeTracking(state, session_id, options);
|
|
2154
2252
|
const setState = require$$0$1.useCallback(
|
|
2155
2253
|
(value, trigger_name) => {
|
|
2156
2254
|
notifyChange(trigger_name);
|