@kelet-ai/feedback-ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,7 +28,7 @@ import { ShadcnVoteFeedback } from '@/components/ui/vote-feedback';
28
28
  function App() {
29
29
  return (
30
30
  <ShadcnVoteFeedback
31
- identifier="my-feature"
31
+ tx_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} identifier="ai-response">
94
+ <VoteFeedback.Root onFeedback={handleFeedback} tx_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 identifier
162
- <VoteFeedback.Root identifier="session-abc123-ai-response-456"/>
161
+ // ✅ Good: Traceable tx_id
162
+ <VoteFeedback.Root tx_id="session-abc123-ai-response-456"/>
163
163
 
164
- // ✅ Good: Content-based identifier
165
- <VoteFeedback.Root identifier={`article-${articleId}-section-${sectionId}`}/>
164
+ // ✅ Good: Content-based tx_id
165
+ <VoteFeedback.Root tx_id={`article-${articleId}-section-${sectionId}`}/>
166
166
 
167
- // ❌ Poor: Generic identifier
168
- <VoteFeedback.Root identifier="feedback"/>
167
+ // ❌ Poor: Generic tx_id
168
+ <VoteFeedback.Root tx_id="feedback"/>
169
169
  ```
170
170
 
171
171
  ### **📊 Feedback Sources**
@@ -290,8 +290,8 @@ const [data, setData] = useFeedbackState(initial, 'tracker', {
290
290
  #### **Identifiers**
291
291
 
292
292
  ✅ Use traceable session/request IDs
293
- ✅ Include context in identifier structure
294
- ✅ Keep identifiers consistent across related actions
293
+ ✅ Include context in tx_id structure
294
+ ✅ Keep tx_ids consistent across related actions
295
295
 
296
296
  #### **Feedback Sources**
297
297
 
@@ -313,6 +313,23 @@ const [data, setData] = useFeedbackState(initial, 'tracker', {
313
313
 
314
314
  ---
315
315
 
316
+ ## 🔗 OpenTelemetry Integration
317
+
318
+ Automatically extract trace IDs to correlate feedback with distributed traces:
319
+
320
+ ```tsx
321
+ import { VoteFeedback, getOtelTraceId } from '@kelet-ai/feedback-ui';
322
+
323
+ <VoteFeedback.Root tx_id={getOtelTraceId} onFeedback={handleFeedback}>
324
+ <VoteFeedback.UpvoteButton>👍</VoteFeedback.UpvoteButton>
325
+ <VoteFeedback.DownvoteButton>👎</VoteFeedback.DownvoteButton>
326
+ </VoteFeedback.Root>
327
+ ```
328
+
329
+ Requires `@opentelemetry/api` and active Span to collect the trace_id from.
330
+
331
+ ---
332
+
316
333
  ## 🔧 Core Components
317
334
 
318
335
  ### **VoteFeedback.Root**
@@ -321,7 +338,7 @@ Main container component that manages feedback state.
321
338
 
322
339
  ```tsx
323
340
  <VoteFeedback.Root
324
- identifier="unique-id" // Required: Unique tracking ID
341
+ tx_id="unique-id" // Required: Unique tracking ID
325
342
  onFeedback={handleFeedback} // Required: Callback function
326
343
  trigger_name="user_feedback" // Optional: Categorization
327
344
  extra_metadata={{ page: 'home' }} // Optional: Additional data
@@ -370,7 +387,7 @@ const [count, setCount] = useFeedbackState(0, 'counter-widget');
370
387
  ```tsx
371
388
  const [profile, setProfile] = useFeedbackState(
372
389
  { name: '', email: '' },
373
- state => `profile-${state.email}`, // Dynamic identifier
390
+ state => `profile-${state.email}`, // Dynamic tx_id
374
391
  {
375
392
  debounceMs: 2000, // Wait time before sending feedback
376
393
  diffType: 'object', // Format: 'git' | 'object' | 'json'
@@ -460,7 +477,7 @@ dispatch({ type: 'custom' }, 'override'); // Custom trigger name
460
477
 
461
478
  ```tsx
462
479
  <VoteFeedback.Root
463
- identifier="ai-response-123"
480
+ tx_id="ai-response-123"
464
481
  onFeedback={handleFeedback}
465
482
  trigger_name="ai_evaluation"
466
483
  extra_metadata={{
@@ -486,7 +503,7 @@ dispatch({ type: 'custom' }, 'override'); // Custom trigger name
486
503
 
487
504
  ```typescript
488
505
  interface FeedbackData {
489
- identifier: string; // Unique tracking ID
506
+ tx_id: string; // Unique tracking ID
490
507
  vote: 'upvote' | 'downvote'; // User's vote
491
508
  explanation?: string; // Optional user comment
492
509
  extra_metadata?: Record<string, any>; // Additional context data
@@ -501,7 +518,7 @@ interface FeedbackData {
501
518
 
502
519
  | Prop | Type | Required | Description |
503
520
  | ---------------- | ------------------------------ | -------- | ----------------------------------- |
504
- | `identifier` | `string` | ✅ | Unique identifier for tracking |
521
+ | `tx_id` | `string` | ✅ | Unique transaction ID for tracking |
505
522
  | `onFeedback` | `(data: FeedbackData) => void` | ✅ | Callback when feedback is submitted |
506
523
  | `trigger_name` | `string` | ❌ | Optional categorization tag |
507
524
  | `extra_metadata` | `object` | ❌ | Additional context data |
@@ -586,9 +603,9 @@ bun run checks # Run all quality checks (lint, format, typecheck, tests)
586
603
  <VoteFeedback.UpvoteButton>👍</VoteFeedback.UpvoteButton>
587
604
  </VoteFeedback.Root>
588
605
 
589
- // ✅ Include required identifier and onFeedback
606
+ // ✅ Include required tx_id and onFeedback
590
607
  <VoteFeedback.Root
591
- identifier="my-feature"
608
+ tx_id="my-feature"
592
609
  onFeedback={handleFeedback}
593
610
  >
594
611
  <VoteFeedback.UpvoteButton>👍</VoteFeedback.UpvoteButton>
@@ -624,14 +641,14 @@ const [value, setValue] = useFeedbackState('initial', 'test', {
624
641
 
625
642
  ### **Best Practices**
626
643
 
627
- ✅ **Use unique identifiers** for each feedback instance - the identifier should be traceable back to the session's log
644
+ ✅ **Use unique tx_ids** for each feedback instance - the tx_id should be traceable back to the session's log
628
645
  and allow us to understand the context of the feedback.
629
646
  ✅ **Handle feedback data asynchronously** in your callback
630
647
  ✅ **Test keyboard navigation** in your implementation
631
648
  ✅ **Provide meaningful trigger names** for categorization
632
649
  ✅ **Include relevant metadata** for context
633
650
 
634
- ❌ **Don't use the same identifier** for multiple components. An identifier should be traced back to the session's log -
651
+ ❌ **Don't use the same tx_id** for multiple components. A tx_id should be traced back to the session's log -
635
652
  allows us to understand the context of the feedback.
636
653
 
637
654
  ---
@@ -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, identifier, extra_metadata, trigger_name, }: VoteFeedbackRootProps) => import("react/jsx-runtime").JSX.Element;
3
+ Root: ({ children, onFeedback, defaultText, tx_id: txIdProp, 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;