@feedvalue/react 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +124 -33
  2. package/package.json +13 -14
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @feedvalue/react
2
2
 
3
- React SDK for FeedValue feedback widget. Provides Provider, Hooks, and Components for React 18+.
3
+ React SDK for FeedValue feedback widget. Provides Provider and Hooks for React 18+.
4
4
 
5
5
  ## Installation
6
6
 
@@ -55,25 +55,71 @@ export function FeedbackButton() {
55
55
  }
56
56
  ```
57
57
 
58
- ### Using the Widget Component
58
+ ### Headless Mode
59
+
60
+ For complete UI control, use headless mode. The SDK fetches config and provides all API methods but renders no trigger button or modal:
59
61
 
60
62
  ```tsx
63
+ // app/layout.tsx
64
+ import { FeedValueProvider } from '@feedvalue/react';
65
+
66
+ export default function RootLayout({ children }) {
67
+ return (
68
+ <html>
69
+ <body>
70
+ <FeedValueProvider widgetId="your-widget-id" headless>
71
+ {children}
72
+ </FeedValueProvider>
73
+ </body>
74
+ </html>
75
+ );
76
+ }
77
+ ```
78
+
79
+ ```tsx
80
+ // components/custom-feedback.tsx
61
81
  'use client';
62
82
 
63
- import { FeedValueWidget } from '@feedvalue/react';
83
+ import { useState } from 'react';
84
+ import { useFeedValue } from '@feedvalue/react';
85
+
86
+ export function CustomFeedback() {
87
+ const { isReady, isOpen, open, close, submit, isSubmitting, isHeadless } = useFeedValue();
88
+ const [message, setMessage] = useState('');
89
+
90
+ const handleSubmit = async () => {
91
+ await submit({ message });
92
+ setMessage('');
93
+ close();
94
+ };
95
+
96
+ if (!isReady) return null;
64
97
 
65
- // Standalone widget (no Provider needed)
66
- export function FeedbackWidget() {
67
98
  return (
68
- <FeedValueWidget
69
- widgetId="your-widget-id"
70
- onSubmit={(feedback) => console.log('Submitted:', feedback)}
71
- />
99
+ <>
100
+ <button onClick={open}>Feedback</button>
101
+
102
+ {isOpen && (
103
+ <dialog open className="feedback-modal">
104
+ <textarea
105
+ value={message}
106
+ onChange={(e) => setMessage(e.target.value)}
107
+ placeholder="Your feedback..."
108
+ />
109
+ <div>
110
+ <button onClick={handleSubmit} disabled={isSubmitting}>
111
+ {isSubmitting ? 'Sending...' : 'Submit'}
112
+ </button>
113
+ <button onClick={close}>Cancel</button>
114
+ </div>
115
+ </dialog>
116
+ )}
117
+ </>
72
118
  );
73
119
  }
74
120
  ```
75
121
 
76
- ### Programmatic Control
122
+ ### Programmatic Submission
77
123
 
78
124
  ```tsx
79
125
  'use client';
@@ -107,8 +153,47 @@ export function FeedbackForm() {
107
153
  }
108
154
  ```
109
155
 
156
+ ### Custom Fields
157
+
158
+ Custom fields allow you to collect structured data beyond the main feedback message. **Custom fields must be defined in your widget configuration on the FeedValue dashboard before use.**
159
+
160
+ 1. Go to your widget settings in the FeedValue dashboard
161
+ 2. Add custom fields with types: `text`, `email`, or `emoji`
162
+ 3. Use `customFieldValues` when submitting:
163
+
164
+ ```tsx
165
+ 'use client';
166
+
167
+ import { useFeedValue } from '@feedvalue/react';
168
+
169
+ export function DetailedFeedback() {
170
+ const { submit, isReady } = useFeedValue();
171
+
172
+ const handleSubmit = async () => {
173
+ await submit({
174
+ message: 'Detailed feedback',
175
+ customFieldValues: {
176
+ // Field IDs must match those defined in your widget configuration
177
+ name: 'John Doe',
178
+ category: 'feature',
179
+ },
180
+ });
181
+ };
182
+
183
+ return (
184
+ <button onClick={handleSubmit} disabled={!isReady}>
185
+ Submit Feedback
186
+ </button>
187
+ );
188
+ }
189
+ ```
190
+
191
+ > **Important**: The field IDs in `customFieldValues` must match the field IDs defined in your widget configuration on the dashboard.
192
+
110
193
  ### User Identification
111
194
 
195
+ Attach user context to feedback submissions. This data is **not shown in the widget UI** but is stored with the submission and visible in your FeedValue dashboard:
196
+
112
197
  ```tsx
113
198
  'use client';
114
199
 
@@ -135,22 +220,27 @@ export function UserIdentifier({ user }) {
135
220
  }
136
221
  ```
137
222
 
223
+ > **User Data vs Custom Fields**
224
+ > - **User data** (`identify`/`setData`): Hidden from users, automatically attached to submissions. Use for internal context like user IDs, subscription plans, etc.
225
+ > - **Custom fields** (`customFieldValues`): Shown as form inputs in the widget. Users fill these in themselves. Must be defined in widget configuration first.
226
+
138
227
  ## API Reference
139
228
 
140
229
  ### `<FeedValueProvider>`
141
230
 
142
231
  Provider component for FeedValue context.
143
232
 
144
- | Prop | Type | Required | Description |
145
- |------|------|----------|-------------|
146
- | `widgetId` | `string` | Yes | Widget ID from FeedValue dashboard |
147
- | `apiBaseUrl` | `string` | No | Custom API URL (for self-hosted) |
148
- | `config` | `Partial<FeedValueConfig>` | No | Configuration overrides |
149
- | `onReady` | `() => void` | No | Called when widget is ready |
150
- | `onOpen` | `() => void` | No | Called when modal opens |
151
- | `onClose` | `() => void` | No | Called when modal closes |
152
- | `onSubmit` | `(feedback: FeedbackData) => void` | No | Called when feedback is submitted |
153
- | `onError` | `(error: Error) => void` | No | Called on errors |
233
+ | Prop | Type | Required | Default | Description |
234
+ |------|------|----------|---------|-------------|
235
+ | `widgetId` | `string` | Yes | - | Widget ID from FeedValue dashboard |
236
+ | `apiBaseUrl` | `string` | No | Production URL | Custom API URL (for self-hosted) |
237
+ | `config` | `Partial<FeedValueConfig>` | No | - | Configuration overrides |
238
+ | `headless` | `boolean` | No | `false` | Disable all DOM rendering |
239
+ | `onReady` | `() => void` | No | - | Called when widget is ready |
240
+ | `onOpen` | `() => void` | No | - | Called when modal opens |
241
+ | `onClose` | `() => void` | No | - | Called when modal closes |
242
+ | `onSubmit` | `(feedback: FeedbackData) => void` | No | - | Called when feedback is submitted |
243
+ | `onError` | `(error: Error) => void` | No | - | Called on errors |
154
244
 
155
245
  ### `useFeedValue()`
156
246
 
@@ -160,11 +250,13 @@ Returns:
160
250
 
161
251
  | Property | Type | Description |
162
252
  |----------|------|-------------|
253
+ | `instance` | `FeedValue \| null` | Raw FeedValue instance (advanced usage) |
163
254
  | `isReady` | `boolean` | Widget is initialized |
164
255
  | `isOpen` | `boolean` | Modal is open |
165
256
  | `isVisible` | `boolean` | Trigger button is visible |
166
257
  | `error` | `Error \| null` | Current error |
167
258
  | `isSubmitting` | `boolean` | Submission in progress |
259
+ | `isHeadless` | `boolean` | Running in headless mode |
168
260
  | `open` | `() => void` | Open the modal |
169
261
  | `close` | `() => void` | Close the modal |
170
262
  | `toggle` | `() => void` | Toggle modal |
@@ -179,19 +271,6 @@ Returns:
179
271
 
180
272
  Same as `useFeedValue()` but returns `null` if used outside provider instead of throwing.
181
273
 
182
- ### `<FeedValueWidget>`
183
-
184
- Standalone widget component that doesn't require a provider.
185
-
186
- | Prop | Type | Required | Description |
187
- |------|------|----------|-------------|
188
- | `widgetId` | `string` | Yes | Widget ID from FeedValue dashboard |
189
- | `apiBaseUrl` | `string` | No | Custom API URL |
190
- | `config` | `Partial<FeedValueConfig>` | No | Configuration overrides |
191
- | `onReady` | `() => void` | No | Ready callback |
192
- | `onSubmit` | `(feedback) => void` | No | Submit callback |
193
- | `onError` | `(error) => void` | No | Error callback |
194
-
195
274
  ## Server-Side Rendering
196
275
 
197
276
  The SDK is fully SSR-compatible. It uses `useSyncExternalStore` for concurrent mode support and returns safe default values during server rendering.
@@ -214,6 +293,18 @@ export function FeedbackButton() {
214
293
  }
215
294
  ```
216
295
 
296
+ ## Default vs Headless Mode
297
+
298
+ | Feature | Default Mode | Headless Mode |
299
+ |---------|--------------|---------------|
300
+ | Trigger button | Dashboard-styled | You build it |
301
+ | Modal | Dashboard-styled | You build it |
302
+ | API methods | Available | Available |
303
+ | User tracking | Available | Available |
304
+ | Dashboard config | Fetched | Fetched |
305
+
306
+ Use `headless={true}` when you want complete control over the UI.
307
+
217
308
  ## Requirements
218
309
 
219
310
  - React 18.0.0 or higher
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feedvalue/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "FeedValue React SDK - Provider, Hooks, and Components for React 18+",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -23,12 +23,22 @@
23
23
  "README.md"
24
24
  ],
25
25
  "sideEffects": false,
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch",
29
+ "lint": "eslint src",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "test:coverage": "vitest run --coverage",
33
+ "typecheck": "tsc --noEmit",
34
+ "clean": "rm -rf dist"
35
+ },
26
36
  "peerDependencies": {
27
37
  "react": ">=18.0.0",
28
38
  "react-dom": ">=18.0.0"
29
39
  },
30
40
  "dependencies": {
31
- "@feedvalue/core": "^0.1.0"
41
+ "@feedvalue/core": "workspace:^"
32
42
  },
33
43
  "devDependencies": {
34
44
  "@testing-library/jest-dom": "^6.9.1",
@@ -36,7 +46,6 @@
36
46
  "@types/react": "^19.0.0",
37
47
  "@types/react-dom": "^19.0.0",
38
48
  "@vitest/coverage-v8": "^2.1.0",
39
- "eslint": "^9.17.0",
40
49
  "happy-dom": "^15.11.0",
41
50
  "react": "^19.0.0",
42
51
  "react-dom": "^19.0.0",
@@ -68,15 +77,5 @@
68
77
  ],
69
78
  "engines": {
70
79
  "node": ">=18"
71
- },
72
- "scripts": {
73
- "build": "tsup",
74
- "dev": "tsup --watch",
75
- "lint": "eslint src --ext .ts,.tsx",
76
- "test": "vitest run",
77
- "test:watch": "vitest",
78
- "test:coverage": "vitest run --coverage",
79
- "typecheck": "tsc --noEmit",
80
- "clean": "rm -rf dist"
81
80
  }
82
- }
81
+ }