@kelet-ai/feedback-ui 1.0.2 → 1.1.3
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 +128 -24
- package/dist/feedback-ui.es.js.map +1 -1
- package/dist/feedback-ui.es.min.js +732 -657
- package/dist/feedback-ui.es.min.js.map +1 -1
- package/dist/feedback-ui.umd.js +127 -23
- 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/README.md
CHANGED
|
@@ -28,7 +28,7 @@ import { ShadcnVoteFeedback } from '@/components/ui/vote-feedback';
|
|
|
28
28
|
function App() {
|
|
29
29
|
return (
|
|
30
30
|
<ShadcnVoteFeedback
|
|
31
|
-
|
|
31
|
+
session_id="my-feature"
|
|
32
32
|
onFeedback={feedback => console.log(feedback)}
|
|
33
33
|
variant="outline"
|
|
34
34
|
/>
|
|
@@ -91,7 +91,7 @@ Users explicitly vote and provide comments:
|
|
|
91
91
|
```tsx
|
|
92
92
|
import { VoteFeedback } from '@kelet-ai/feedback-ui';
|
|
93
93
|
|
|
94
|
-
<VoteFeedback.Root onFeedback={handleFeedback}
|
|
94
|
+
<VoteFeedback.Root onFeedback={handleFeedback} session_id="ai-response">
|
|
95
95
|
<VoteFeedback.UpvoteButton>👍 Helpful</VoteFeedback.UpvoteButton>
|
|
96
96
|
<VoteFeedback.DownvoteButton>👎 Not helpful</VoteFeedback.DownvoteButton>
|
|
97
97
|
<VoteFeedback.Popover>
|
|
@@ -158,14 +158,14 @@ Understanding these fundamental concepts will help you implement feedback collec
|
|
|
158
158
|
**Best Practice**: Use traceable IDs from your logging system (session ID, trace ID, request ID)
|
|
159
159
|
|
|
160
160
|
```tsx
|
|
161
|
-
// ✅ Good: Traceable
|
|
162
|
-
<VoteFeedback.Root
|
|
161
|
+
// ✅ Good: Traceable session_id
|
|
162
|
+
<VoteFeedback.Root session_id="session-abc123-ai-response-456"/>
|
|
163
163
|
|
|
164
|
-
// ✅ Good: Content-based
|
|
165
|
-
<VoteFeedback.Root
|
|
164
|
+
// ✅ Good: Content-based session_id
|
|
165
|
+
<VoteFeedback.Root session_id={`article-${articleId}-section-${sectionId}`}/>
|
|
166
166
|
|
|
167
|
-
// ❌ Poor: Generic
|
|
168
|
-
<VoteFeedback.Root
|
|
167
|
+
// ❌ Poor: Generic session_id
|
|
168
|
+
<VoteFeedback.Root session_id="feedback"/>
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
### **📊 Feedback Sources**
|
|
@@ -296,8 +296,8 @@ const [data, setData] = useFeedbackState(initial, 'tracker', {
|
|
|
296
296
|
#### **Identifiers**
|
|
297
297
|
|
|
298
298
|
✅ Use traceable session/request IDs
|
|
299
|
-
✅ Include context in
|
|
300
|
-
✅ Keep
|
|
299
|
+
✅ Include context in session_id structure
|
|
300
|
+
✅ Keep session_ids consistent across related actions
|
|
301
301
|
|
|
302
302
|
#### **Feedback Sources**
|
|
303
303
|
|
|
@@ -327,7 +327,7 @@ Main container component that manages feedback state.
|
|
|
327
327
|
|
|
328
328
|
```tsx
|
|
329
329
|
<VoteFeedback.Root
|
|
330
|
-
|
|
330
|
+
session_id="unique-id" // Required: Unique tracking ID
|
|
331
331
|
onFeedback={handleFeedback} // Required: Callback function
|
|
332
332
|
trigger_name="user_feedback" // Optional: Categorization
|
|
333
333
|
extra_metadata={{ page: 'home' }} // Optional: Additional data
|
|
@@ -376,7 +376,7 @@ const [count, setCount] = useFeedbackState(0, 'counter-widget');
|
|
|
376
376
|
```tsx
|
|
377
377
|
const [profile, setProfile] = useFeedbackState(
|
|
378
378
|
{ name: '', email: '' },
|
|
379
|
-
state => `profile-${state.email}`, // Dynamic
|
|
379
|
+
state => `profile-${state.email}`, // Dynamic session_id
|
|
380
380
|
{
|
|
381
381
|
debounceMs: 2000, // Wait time before sending feedback
|
|
382
382
|
diffType: 'object', // Format: 'git' | 'object' | 'json'
|
|
@@ -466,7 +466,7 @@ dispatch({ type: 'custom' }, 'override'); // Custom trigger name
|
|
|
466
466
|
|
|
467
467
|
```tsx
|
|
468
468
|
<VoteFeedback.Root
|
|
469
|
-
|
|
469
|
+
session_id="ai-response-123"
|
|
470
470
|
onFeedback={handleFeedback}
|
|
471
471
|
trigger_name="ai_evaluation"
|
|
472
472
|
extra_metadata={{
|
|
@@ -492,7 +492,7 @@ dispatch({ type: 'custom' }, 'override'); // Custom trigger name
|
|
|
492
492
|
|
|
493
493
|
```typescript
|
|
494
494
|
interface FeedbackData {
|
|
495
|
-
|
|
495
|
+
session_id: string; // Unique tracking ID
|
|
496
496
|
vote: 'upvote' | 'downvote'; // User's vote
|
|
497
497
|
explanation?: string; // Optional user comment
|
|
498
498
|
extra_metadata?: Record<string, any>; // Additional context data
|
|
@@ -507,7 +507,7 @@ interface FeedbackData {
|
|
|
507
507
|
|
|
508
508
|
| Prop | Type | Required | Description |
|
|
509
509
|
| ---------------- | ------------------------------ | -------- | ----------------------------------- |
|
|
510
|
-
| `
|
|
510
|
+
| `session_id` | `string` | ✅ | Unique session ID for tracking |
|
|
511
511
|
| `onFeedback` | `(data: FeedbackData) => void` | ✅ | Callback when feedback is submitted |
|
|
512
512
|
| `trigger_name` | `string` | ❌ | Optional categorization tag |
|
|
513
513
|
| `extra_metadata` | `object` | ❌ | Additional context data |
|
|
@@ -593,9 +593,9 @@ bun run checks # Run all quality checks (lint, format, typecheck, tests)
|
|
|
593
593
|
<VoteFeedback.UpvoteButton>👍</VoteFeedback.UpvoteButton>
|
|
594
594
|
</VoteFeedback.Root>
|
|
595
595
|
|
|
596
|
-
// ✅ Include required
|
|
596
|
+
// ✅ Include required session_id and onFeedback
|
|
597
597
|
<VoteFeedback.Root
|
|
598
|
-
|
|
598
|
+
session_id="my-feature"
|
|
599
599
|
onFeedback={handleFeedback}
|
|
600
600
|
>
|
|
601
601
|
<VoteFeedback.UpvoteButton>👍</VoteFeedback.UpvoteButton>
|
|
@@ -631,14 +631,14 @@ const [value, setValue] = useFeedbackState('initial', 'test', {
|
|
|
631
631
|
|
|
632
632
|
### **Best Practices**
|
|
633
633
|
|
|
634
|
-
✅ **Use unique
|
|
634
|
+
✅ **Use unique session_ids** for each feedback instance - the session_id should be traceable back to the session's log
|
|
635
635
|
and allow us to understand the context of the feedback.
|
|
636
636
|
✅ **Handle feedback data asynchronously** in your callback
|
|
637
637
|
✅ **Test keyboard navigation** in your implementation
|
|
638
638
|
✅ **Provide meaningful trigger names** for categorization
|
|
639
639
|
✅ **Include relevant metadata** for context
|
|
640
640
|
|
|
641
|
-
❌ **Don't use the same
|
|
641
|
+
❌ **Don't use the same session_id** for multiple components. A session_id should be traced back to the session's log -
|
|
642
642
|
allows us to understand the context of the feedback.
|
|
643
643
|
|
|
644
644
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DownvoteButtonProps, PopoverProps, SubmitButtonProps, TextareaProps, UpvoteButtonProps, VoteFeedbackRootProps } from '../types';
|
|
2
2
|
export declare const VoteFeedback: {
|
|
3
|
-
Root: ({ children, onFeedback, defaultText,
|
|
3
|
+
Root: ({ children, onFeedback, defaultText, session_id: sessionIdProp, extra_metadata, trigger_name, }: VoteFeedbackRootProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
UpvoteButton: ({ asChild, children, onClick, ...props }: UpvoteButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
DownvoteButton: ({ asChild, children, onClick, ...props }: DownvoteButtonProps) => string | number | bigint | true | Iterable<import('react').ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<import('react').ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
Popover: ({ asChild, children, ...props }: PopoverProps) => import("react/jsx-runtime").JSX.Element | null;
|
package/dist/feedback-ui.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import require$$0$1, { createContext, useContext, useCallback, isValidElement, cloneElement, useState, useRef, useId
|
|
1
|
+
import require$$0$1, { createContext, useEffect, useContext, useCallback, isValidElement, cloneElement, useState, useRef, useId } from "react";
|
|
2
2
|
function getDefaultExportFromCjs(x) {
|
|
3
3
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
4
4
|
}
|
|
@@ -352,8 +352,90 @@ function requireJsxRuntime() {
|
|
|
352
352
|
return jsxRuntime.exports;
|
|
353
353
|
}
|
|
354
354
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
355
|
+
let latestEvent = null;
|
|
356
|
+
let isInitialized = false;
|
|
357
|
+
function serializeTarget(target) {
|
|
358
|
+
if (!target || !(target instanceof Element)) return "unknown";
|
|
359
|
+
const el = target;
|
|
360
|
+
if (el.id) return `#${el.id}`;
|
|
361
|
+
const dataId = el.getAttribute("data-feedback-id");
|
|
362
|
+
if (dataId) return `[data-feedback-id="${dataId}"]`;
|
|
363
|
+
const path = [];
|
|
364
|
+
let current = el;
|
|
365
|
+
let depth = 0;
|
|
366
|
+
const MAX_DEPTH = 5;
|
|
367
|
+
while (current && current !== document.body && depth < MAX_DEPTH) {
|
|
368
|
+
let selector = current.tagName.toLowerCase();
|
|
369
|
+
if (current.classList.length > 0) {
|
|
370
|
+
const className = Array.from(current.classList)[0];
|
|
371
|
+
selector += `.${className}`;
|
|
372
|
+
}
|
|
373
|
+
const parent = current.parentElement;
|
|
374
|
+
if (parent) {
|
|
375
|
+
const siblings = Array.from(parent.children);
|
|
376
|
+
const index = siblings.indexOf(current) + 1;
|
|
377
|
+
if (siblings.length > 1) {
|
|
378
|
+
selector += `:nth-child(${index})`;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
path.unshift(selector);
|
|
382
|
+
current = parent;
|
|
383
|
+
depth++;
|
|
384
|
+
}
|
|
385
|
+
return path.join(" > ");
|
|
386
|
+
}
|
|
387
|
+
function getTargetText(target) {
|
|
388
|
+
if (!target || !(target instanceof Element)) return "";
|
|
389
|
+
const el = target;
|
|
390
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
391
|
+
if (ariaLabel) return ariaLabel.substring(0, 50);
|
|
392
|
+
const text = el.textContent?.trim() || "";
|
|
393
|
+
return text.substring(0, 50);
|
|
394
|
+
}
|
|
395
|
+
function captureEvent(e) {
|
|
396
|
+
const captured = {
|
|
397
|
+
type: e.type,
|
|
398
|
+
targetSelector: serializeTarget(e.target),
|
|
399
|
+
targetText: getTargetText(e.target),
|
|
400
|
+
timestamp: Date.now()
|
|
401
|
+
};
|
|
402
|
+
if (e instanceof MouseEvent) {
|
|
403
|
+
captured.coordinates = { x: e.clientX, y: e.clientY };
|
|
404
|
+
} else if (e instanceof KeyboardEvent) {
|
|
405
|
+
captured.key = e.key;
|
|
406
|
+
}
|
|
407
|
+
return captured;
|
|
408
|
+
}
|
|
409
|
+
function initEventCapture() {
|
|
410
|
+
if (isInitialized || typeof window === "undefined") return;
|
|
411
|
+
const eventTypes = ["click", "keydown", "submit", "change"];
|
|
412
|
+
eventTypes.forEach((type) => {
|
|
413
|
+
window.addEventListener(
|
|
414
|
+
type,
|
|
415
|
+
(e) => {
|
|
416
|
+
latestEvent = captureEvent(e);
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
capture: true,
|
|
420
|
+
// Intercept before React handlers
|
|
421
|
+
passive: true
|
|
422
|
+
// Better scroll performance
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
isInitialized = true;
|
|
427
|
+
}
|
|
428
|
+
function getLatestEvent() {
|
|
429
|
+
if (!latestEvent) return null;
|
|
430
|
+
const age = Date.now() - latestEvent.timestamp;
|
|
431
|
+
if (age > 1e4) {
|
|
432
|
+
latestEvent = null;
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
return { ...latestEvent };
|
|
436
|
+
}
|
|
355
437
|
const KeletContext = createContext(null);
|
|
356
|
-
const DefaultKeletBaseUrl = "https://api.kelet.ai
|
|
438
|
+
const DefaultKeletBaseUrl = "https://api.kelet.ai";
|
|
357
439
|
const useKelet = () => {
|
|
358
440
|
const context = useContext(KeletContext);
|
|
359
441
|
if (!context) {
|
|
@@ -374,6 +456,9 @@ const useDefaultFeedbackHandler = () => {
|
|
|
374
456
|
}
|
|
375
457
|
};
|
|
376
458
|
const KeletProvider = ({ apiKey, project, baseUrl, children }) => {
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
initEventCapture();
|
|
461
|
+
}, []);
|
|
377
462
|
const parentContext = useContext(KeletContext);
|
|
378
463
|
const resolvedApiKey = apiKey || parentContext?.api_key;
|
|
379
464
|
if (!resolvedApiKey) {
|
|
@@ -381,17 +466,29 @@ const KeletProvider = ({ apiKey, project, baseUrl, children }) => {
|
|
|
381
466
|
"apiKey is required either directly or from a parent KeletProvider"
|
|
382
467
|
);
|
|
383
468
|
}
|
|
469
|
+
let resolvedBaseUrl = baseUrl || DefaultKeletBaseUrl;
|
|
470
|
+
if (resolvedBaseUrl.endsWith("/api")) {
|
|
471
|
+
resolvedBaseUrl = resolvedBaseUrl.slice(0, -4);
|
|
472
|
+
}
|
|
473
|
+
if (resolvedBaseUrl.endsWith("/")) {
|
|
474
|
+
resolvedBaseUrl = resolvedBaseUrl.slice(0, -1);
|
|
475
|
+
}
|
|
384
476
|
const feedback = async (data) => {
|
|
385
|
-
const
|
|
386
|
-
const
|
|
477
|
+
const url = `${resolvedBaseUrl}/api/projects/${project}/signal`;
|
|
478
|
+
const capturedEvent = getLatestEvent();
|
|
479
|
+
const metadata = {
|
|
480
|
+
...data.extra_metadata ?? {},
|
|
481
|
+
...capturedEvent && { $dom_event: capturedEvent }
|
|
482
|
+
};
|
|
387
483
|
const req = {
|
|
388
|
-
|
|
484
|
+
session_id: data.session_id,
|
|
389
485
|
source: data.source || "EXPLICIT",
|
|
390
486
|
vote: data.vote,
|
|
391
487
|
explanation: data.explanation,
|
|
392
488
|
correction: data.correction,
|
|
393
|
-
selection: data.selection
|
|
394
|
-
|
|
489
|
+
selection: data.selection,
|
|
490
|
+
trigger_name: data.trigger_name,
|
|
491
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
395
492
|
};
|
|
396
493
|
const response = await fetch(url, {
|
|
397
494
|
method: "POST",
|
|
@@ -453,11 +550,11 @@ const VoteFeedbackRoot = ({
|
|
|
453
550
|
children,
|
|
454
551
|
onFeedback,
|
|
455
552
|
defaultText = "",
|
|
456
|
-
|
|
553
|
+
session_id: sessionIdProp,
|
|
457
554
|
extra_metadata,
|
|
458
555
|
trigger_name
|
|
459
556
|
}) => {
|
|
460
|
-
const
|
|
557
|
+
const session_id = typeof sessionIdProp === "function" ? sessionIdProp() : sessionIdProp;
|
|
461
558
|
const [showPopover, setShowPopover] = useState(false);
|
|
462
559
|
const [feedbackText, setFeedbackText] = useState(defaultText);
|
|
463
560
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
@@ -474,11 +571,11 @@ const VoteFeedbackRoot = ({
|
|
|
474
571
|
setIsSubmitting(false);
|
|
475
572
|
setVote(null);
|
|
476
573
|
setTimeout(() => triggerRef.current?.focus(), 0);
|
|
477
|
-
}, [
|
|
574
|
+
}, [session_id, defaultText]);
|
|
478
575
|
const handleUpvote = useCallback(async () => {
|
|
479
576
|
setVote("upvote");
|
|
480
577
|
const data = {
|
|
481
|
-
|
|
578
|
+
session_id,
|
|
482
579
|
vote: "upvote",
|
|
483
580
|
...extra_metadata && { extra_metadata },
|
|
484
581
|
...trigger_name && { trigger_name }
|
|
@@ -489,12 +586,12 @@ const VoteFeedbackRoot = ({
|
|
|
489
586
|
} finally {
|
|
490
587
|
setIsSubmitting(false);
|
|
491
588
|
}
|
|
492
|
-
}, [handler,
|
|
589
|
+
}, [handler, session_id, extra_metadata, trigger_name]);
|
|
493
590
|
const handleDownvote = useCallback(async () => {
|
|
494
591
|
setVote("downvote");
|
|
495
592
|
if (handler) {
|
|
496
593
|
const data = {
|
|
497
|
-
|
|
594
|
+
session_id,
|
|
498
595
|
vote: "downvote",
|
|
499
596
|
...extra_metadata && { extra_metadata },
|
|
500
597
|
...trigger_name && { trigger_name }
|
|
@@ -517,7 +614,7 @@ const VoteFeedbackRoot = ({
|
|
|
517
614
|
document.body.appendChild(announcement);
|
|
518
615
|
setTimeout(() => document.body.removeChild(announcement), 1e3);
|
|
519
616
|
}, 0);
|
|
520
|
-
}, [handler,
|
|
617
|
+
}, [handler, session_id, extra_metadata, trigger_name]);
|
|
521
618
|
const handleTextareaChange = useCallback(
|
|
522
619
|
(e) => {
|
|
523
620
|
setFeedbackText(e.target.value);
|
|
@@ -528,7 +625,7 @@ const VoteFeedbackRoot = ({
|
|
|
528
625
|
const hasText = feedbackText.trim().length > 0;
|
|
529
626
|
if (hasText) {
|
|
530
627
|
const data = {
|
|
531
|
-
|
|
628
|
+
session_id,
|
|
532
629
|
vote: "downvote",
|
|
533
630
|
explanation: feedbackText,
|
|
534
631
|
...extra_metadata && { extra_metadata },
|
|
@@ -552,7 +649,14 @@ const VoteFeedbackRoot = ({
|
|
|
552
649
|
document.body.appendChild(announcement);
|
|
553
650
|
setTimeout(() => document.body.removeChild(announcement), 1e3);
|
|
554
651
|
}
|
|
555
|
-
}, [
|
|
652
|
+
}, [
|
|
653
|
+
handler,
|
|
654
|
+
feedbackText,
|
|
655
|
+
defaultText,
|
|
656
|
+
session_id,
|
|
657
|
+
extra_metadata,
|
|
658
|
+
trigger_name
|
|
659
|
+
]);
|
|
556
660
|
const handleKeyDown = useCallback(
|
|
557
661
|
(e) => {
|
|
558
662
|
if (e.key === "Escape") {
|
|
@@ -601,7 +705,7 @@ const VoteFeedbackRoot = ({
|
|
|
601
705
|
triggerRef,
|
|
602
706
|
popoverId,
|
|
603
707
|
triggerId,
|
|
604
|
-
|
|
708
|
+
session_id,
|
|
605
709
|
extra_metadata,
|
|
606
710
|
trigger_name
|
|
607
711
|
};
|
|
@@ -2016,7 +2120,7 @@ function stringify(value) {
|
|
|
2016
2120
|
return String(value);
|
|
2017
2121
|
}
|
|
2018
2122
|
}
|
|
2019
|
-
function useStateChangeTracking(currentState,
|
|
2123
|
+
function useStateChangeTracking(currentState, session_id, options) {
|
|
2020
2124
|
const defaultFeedbackHandler = useDefaultFeedbackHandler();
|
|
2021
2125
|
const feedbackHandler = options?.onFeedback || defaultFeedbackHandler;
|
|
2022
2126
|
const debounceMs = options?.debounceMs ?? 3e3;
|
|
@@ -2051,9 +2155,9 @@ function useStateChangeTracking(currentState, tx_id, options) {
|
|
|
2051
2155
|
} else {
|
|
2052
2156
|
vote = diffPercentage > 0.5 ? "downvote" : "upvote";
|
|
2053
2157
|
}
|
|
2054
|
-
const idString = typeof
|
|
2158
|
+
const idString = typeof session_id === "function" ? session_id(endState) : session_id;
|
|
2055
2159
|
feedbackHandler({
|
|
2056
|
-
|
|
2160
|
+
session_id: idString,
|
|
2057
2161
|
vote,
|
|
2058
2162
|
explanation: `State change with diff percentage: ${(diffPercentage * 100).toFixed(1)}%`,
|
|
2059
2163
|
correction: diffString,
|
|
@@ -2062,7 +2166,7 @@ function useStateChangeTracking(currentState, tx_id, options) {
|
|
|
2062
2166
|
trigger_name: triggerName
|
|
2063
2167
|
});
|
|
2064
2168
|
},
|
|
2065
|
-
[options,
|
|
2169
|
+
[options, session_id, diffType, feedbackHandler]
|
|
2066
2170
|
);
|
|
2067
2171
|
const notifyChange = useCallback(
|
|
2068
2172
|
(trigger_name) => {
|
|
@@ -2131,7 +2235,7 @@ function useStateChangeTracking(currentState, tx_id, options) {
|
|
|
2131
2235
|
};
|
|
2132
2236
|
}, [
|
|
2133
2237
|
currentState,
|
|
2134
|
-
|
|
2238
|
+
session_id,
|
|
2135
2239
|
options,
|
|
2136
2240
|
feedbackHandler,
|
|
2137
2241
|
diffType,
|
|
@@ -2145,9 +2249,9 @@ function useStateChangeTracking(currentState, tx_id, options) {
|
|
|
2145
2249
|
notifyChange
|
|
2146
2250
|
};
|
|
2147
2251
|
}
|
|
2148
|
-
function useFeedbackState(initialState,
|
|
2252
|
+
function useFeedbackState(initialState, session_id, options) {
|
|
2149
2253
|
const [state, setStateInternal] = useState(initialState);
|
|
2150
|
-
const { notifyChange } = useStateChangeTracking(state,
|
|
2254
|
+
const { notifyChange } = useStateChangeTracking(state, session_id, options);
|
|
2151
2255
|
const setState = useCallback(
|
|
2152
2256
|
(value, trigger_name) => {
|
|
2153
2257
|
notifyChange(trigger_name);
|