react-feedback-surveys 1.0.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/LICENSE.md +10 -0
- package/README.md +456 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +913 -0
- package/package.json +78 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright 2025 feedback.tools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
10
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# react-feedback-surveys
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/react-feedback-surveys)
|
|
4
|
+
[](https://www.npmjs.com/package/react-feedback-surveys)
|
|
5
|
+
[](https://github.com/your-org/feedback-tools/blob/main/LICENSE)
|
|
6
|
+
[](https://bundlephobia.com/package/react-feedback-surveys)
|
|
7
|
+
|
|
8
|
+
> Lightweight, customizable survey widgets to collect user feedback in React apps.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [Survey Types](#survey-types)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
* [1. Install](#1-install)
|
|
16
|
+
* [2. Styles](#2-styles)
|
|
17
|
+
- [Survey Components](#survey-components)
|
|
18
|
+
* [CSAT5 (Customer Satisfaction Score, 5-Point Scale)](#csat5-customer-satisfaction-score-5-point-scale)
|
|
19
|
+
* [CSAT2 (Customer Satisfaction Score, 2-Point Scale)](#csat2-customer-satisfaction-score-2-point-scale)
|
|
20
|
+
* [NPS10 (Net Promoter Score, 0–10 Scale)](#nps10-net-promoter-score-010-scale)
|
|
21
|
+
* [CES7 (Customer Effort Score, 7-Point Scale)](#ces7-customer-effort-score-7-point-scale)
|
|
22
|
+
- [Layout Components](#layout-components)
|
|
23
|
+
* [Popup](#popup)
|
|
24
|
+
- [Props](#props)
|
|
25
|
+
* [Shared Props](#shared-props)
|
|
26
|
+
* [Scale Style Options](#scale-style-options)
|
|
27
|
+
+ [CSAT2Survey](#csat2survey)
|
|
28
|
+
+ [CSAT5Survey](#csat5survey)
|
|
29
|
+
+ [CES7Survey](#ces7survey)
|
|
30
|
+
+ [NPS10Survey](#nps10survey)
|
|
31
|
+
- [Styling](#styling)
|
|
32
|
+
* [CSS Variables](#css-variables)
|
|
33
|
+
* [Custom Classes](#custom-classes)
|
|
34
|
+
- [Demo](#demo)
|
|
35
|
+
- [Contributing](#contributing)
|
|
36
|
+
* [Local development (Storybook)](#local-development-storybook)
|
|
37
|
+
* [Library build (watch mode)](#library-build-watch-mode)
|
|
38
|
+
* [Production build](#production-build)
|
|
39
|
+
- [Roadmap](#roadmap)
|
|
40
|
+
- [Changelog](#changelog)
|
|
41
|
+
- [License](#license)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Ready-to-use survey widgets** – CSAT (2 or 5 points), CES (7 points), NPS (0–10)
|
|
47
|
+
- **Multiple scale styles** – emoji, stars, numbers, thumbs
|
|
48
|
+
- **Flexible placement** – embed inline or display as popup overlay
|
|
49
|
+
- **Follow-up feedback** – optional text input or multiple choice responses
|
|
50
|
+
- **Fully customizable** – CSS variables and custom class names
|
|
51
|
+
- **Zero dependencies**
|
|
52
|
+
- **TypeScript support**
|
|
53
|
+
|
|
54
|
+
## Survey Types
|
|
55
|
+
|
|
56
|
+
- **CSAT (Customer Satisfaction Score):** 2-point (`csat2`) or 5-point (`csat5`) scales
|
|
57
|
+
- **NPS (Net Promoter Score):** 0–10 numeric scale (`nps10`)
|
|
58
|
+
- **CES (Customer Effort Score):** 7-point numeric scale (`ces7`)
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
### 1) Install
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
npm i react-feedback-surveys
|
|
66
|
+
# or
|
|
67
|
+
yarn add react-feedback-surveys
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2) Styles
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import 'react-feedback-surveys/index.css';
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Survey Components
|
|
77
|
+
|
|
78
|
+
### CSAT5 (Customer Satisfaction Score, 5-Point Scale)
|
|
79
|
+
|
|
80
|
+
Surveys to ask users about their overall satisfaction.
|
|
81
|
+
|
|
82
|
+
**Example questions:**
|
|
83
|
+
- "How satisfied are you with our product?"
|
|
84
|
+
- "How would you rate your overall experience?"
|
|
85
|
+
- "How satisfied are you with our customer support?"
|
|
86
|
+
|
|
87
|
+
<img alt="CSAT5" src="docs/assets/csat5.png" width="400" />
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { CSAT5Survey } from 'react-feedback-surveys';
|
|
91
|
+
import 'react-feedback-surveys/index.css';
|
|
92
|
+
|
|
93
|
+
<CSAT5Survey
|
|
94
|
+
scaleStyle="emoji"
|
|
95
|
+
question="How would you rate your satisfaction with our product?"
|
|
96
|
+
minLabel="Very unsatisfied"
|
|
97
|
+
maxLabel="Very satisfied"
|
|
98
|
+
responseType="text"
|
|
99
|
+
textQuestion="We'd love to hear your thoughts — what can we improve?"
|
|
100
|
+
textButtonLabel="Send"
|
|
101
|
+
thankYouMessage="Thanks for your feedback!"
|
|
102
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
103
|
+
onFeedbackSubmit={({ value, comment }) => {/* ... */}}
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`scaleStyle`: `emoji` | `numbers` | `stars`.
|
|
108
|
+
|
|
109
|
+
### CSAT2 (Customer Satisfaction Score, 2-Point Scale)
|
|
110
|
+
|
|
111
|
+
Surveys to ask users about specific features or flows.
|
|
112
|
+
|
|
113
|
+
**Example questions:**
|
|
114
|
+
- "Was this search helpful?"
|
|
115
|
+
- "Did you find what you were looking for?"
|
|
116
|
+
- "Are you satisfied with the checkout process?"
|
|
117
|
+
|
|
118
|
+
<img alt="CSAT2" src="docs/assets/csat2.png" width="390" />
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { CSAT2Survey } from 'react-feedback-surveys';
|
|
122
|
+
import 'react-feedback-surveys/index.css';
|
|
123
|
+
|
|
124
|
+
<CSAT2Survey
|
|
125
|
+
scaleStyle="thumbs"
|
|
126
|
+
question="Are you satisfied with the result?"
|
|
127
|
+
responseType="text"
|
|
128
|
+
textQuestion="We'd love to hear your thoughts — what can we improve?"
|
|
129
|
+
textButtonLabel="Send"
|
|
130
|
+
thankYouMessage="Thank you for your feedback!"
|
|
131
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
132
|
+
onFeedbackSubmit={({ value, comment }) => {/* ... */}}
|
|
133
|
+
/>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`scaleStyle`: `emoji` | `thumbs`.
|
|
137
|
+
|
|
138
|
+
### NPS10 (Net Promoter Score, 0–10 Scale)
|
|
139
|
+
|
|
140
|
+
Surveys to ask users if they'd recommend your product.
|
|
141
|
+
|
|
142
|
+
**Example questions:**
|
|
143
|
+
- "How likely are you to recommend us to a friend or colleague?"
|
|
144
|
+
- "On a scale of 0-10, would you recommend our service?"
|
|
145
|
+
- "How likely are you to recommend this product to others?"
|
|
146
|
+
|
|
147
|
+
<img alt="NPS10" src="docs/assets/nps10.png" width="600" />
|
|
148
|
+
|
|
149
|
+
<img alt="NPS10 mobile" src="docs/assets/nps10-mobile.png" width="362" />
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import { NPS10Survey } from 'react-feedback-surveys';
|
|
153
|
+
import 'react-feedback-surveys/index.css';
|
|
154
|
+
|
|
155
|
+
<NPS10Survey
|
|
156
|
+
scaleStyle="numbers"
|
|
157
|
+
question="How likely are you to recommend our product/service to a friend or colleague?"
|
|
158
|
+
minLabel="Very unlikely"
|
|
159
|
+
maxLabel="Very likely"
|
|
160
|
+
responseType="text"
|
|
161
|
+
textQuestion="We'd love to hear your thoughts — what can we improve?"
|
|
162
|
+
textButtonLabel="Send"
|
|
163
|
+
thankYouMessage="Thank you for your feedback!"
|
|
164
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
165
|
+
onFeedbackSubmit={({ value, comment }) => {/* ... */}}
|
|
166
|
+
/>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`scaleStyle`: `numbers`.
|
|
170
|
+
|
|
171
|
+
### CES7 (Customer Effort Score, 7-Point Scale)
|
|
172
|
+
|
|
173
|
+
Surveys to ask users how easy it is to use your product.
|
|
174
|
+
|
|
175
|
+
**Example questions:**
|
|
176
|
+
- "How easy was it to complete your task?"
|
|
177
|
+
- "How much effort did it take to resolve your issue?"
|
|
178
|
+
- "How easy was it to sign up for an account?"
|
|
179
|
+
|
|
180
|
+
<img alt="CES7" src="docs/assets/ces7.png" width="420" />
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { CES7Survey } from 'react-feedback-surveys';
|
|
184
|
+
import 'react-feedback-surveys/index.css';
|
|
185
|
+
|
|
186
|
+
<CES7Survey
|
|
187
|
+
scaleStyle="numbers"
|
|
188
|
+
question="How easy was it to complete your task?"
|
|
189
|
+
minLabel="Very difficult"
|
|
190
|
+
maxLabel="Very easy"
|
|
191
|
+
responseType="text"
|
|
192
|
+
textQuestion="We'd love to hear your thoughts — what can we improve?"
|
|
193
|
+
textButtonLabel="Send"
|
|
194
|
+
thankYouMessage="Thank you for your feedback!"
|
|
195
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
196
|
+
onFeedbackSubmit={({ value, comment }) => {/* ... */}}
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`scaleStyle`: `numbers`.
|
|
201
|
+
|
|
202
|
+
## Layout Components
|
|
203
|
+
|
|
204
|
+
### Popup
|
|
205
|
+
|
|
206
|
+
The `<Popup>` component wraps survey widgets in a fixed overlay that slides in from the screen edge. It includes positioning, animations, and a close button for easy dismissal.
|
|
207
|
+
|
|
208
|
+
<img alt="CSAT5 Popup" src="docs/assets/csat5-popup.png" width="400" />
|
|
209
|
+
|
|
210
|
+
#### Usage
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { Popup, CSAT5Survey } from 'react-feedback-surveys';
|
|
214
|
+
import 'react-feedback-surveys/index.css';
|
|
215
|
+
|
|
216
|
+
<Popup
|
|
217
|
+
animated
|
|
218
|
+
classNames={{
|
|
219
|
+
base: 'custom-popup-base',
|
|
220
|
+
content: 'custom-popup-content',
|
|
221
|
+
close: 'custom-popup-close'
|
|
222
|
+
}}
|
|
223
|
+
placement="bottomRight"
|
|
224
|
+
onClose={() => console.log('Closed')}
|
|
225
|
+
>
|
|
226
|
+
<CSAT5Survey
|
|
227
|
+
scaleStyle="stars"
|
|
228
|
+
question="How would you rate your satisfaction?"
|
|
229
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
230
|
+
/>
|
|
231
|
+
</Popup>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Props
|
|
235
|
+
|
|
236
|
+
| Prop | Type | Required | Default | Description |
|
|
237
|
+
|--------------|------------------------------------------------------------|----------|-----------------|--------------------------------------------------------------------|
|
|
238
|
+
| `placement` | `'topLeft' \| 'topRight' \| 'bottomRight' \| 'bottomLeft'` | - | `'bottomRight'` | Position of the popup relative to the screen edges. |
|
|
239
|
+
| `animated` | `boolean` | - | `true` | Enables a fade-in animation when the popup appears. |
|
|
240
|
+
| `className` | `string` | - | - | Additional CSS class name for the popup container. |
|
|
241
|
+
| `classNames` | `{ base?: string; content?: string; close?: string }` | - | - | Optional class names for internal popup elements. |
|
|
242
|
+
| `children` | `React.ReactNode` | - | - | Content to render inside the popup (typically a survey component). |
|
|
243
|
+
| `onClose` | `() => void` | - | - | Callback fired when the close button is clicked. |
|
|
244
|
+
|
|
245
|
+
For more examples, check out the Storybook stories (e.g., `CSAT5Survey.stories.tsx`, `CSAT2Survey.stories.tsx`).
|
|
246
|
+
|
|
247
|
+
## Props
|
|
248
|
+
|
|
249
|
+
Most props are shared across all survey widgets. Each widget differs only in its `scaleStyle` values.
|
|
250
|
+
|
|
251
|
+
### Shared Props
|
|
252
|
+
|
|
253
|
+
| Prop | Type | Required | Description |
|
|
254
|
+
|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|------------------------------------------------------------------------------|
|
|
255
|
+
| `classNames` | `{ base?: { base?: string; head?: string; title?: string; body?: string; close?: string }; scale?: { base?: string; list?: string; button?: string; icon?: string; score?: string; labels?: string } }` | - | Optional class names to target internal parts. |
|
|
256
|
+
| `question` | `string` | required | Main survey question displayed on the first screen. |
|
|
257
|
+
| `minLabel` | `string` | - | Left label for the scale. |
|
|
258
|
+
| `maxLabel` | `string` | - | Right label for the scale. |
|
|
259
|
+
| `responseType` | `null \| 'text' \| 'choices'` | - | Enables optional follow-up feedback. |
|
|
260
|
+
| `textQuestion` | `string` | - | Follow-up question displayed when `responseType` is defined. |
|
|
261
|
+
| `textButtonLabel` | `string` | - | Submit label for the feedback screen. |
|
|
262
|
+
| `choiceOptions` | `string[] \| null` | - | Predefined choices (when `responseType === 'choices'`). |
|
|
263
|
+
| `thankYouMessage` | `string` | required | Message shown after submission. |
|
|
264
|
+
|
|
265
|
+
### Shared Events
|
|
266
|
+
|
|
267
|
+
| Prop | Type | Required | Description |
|
|
268
|
+
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------------|
|
|
269
|
+
| `onScoreSubmit` | `({ value: number }) => void \| Promise<void>` | - | Fires immediately when a score is selected, before any follow-up feedback screen. Captures the raw rating. |
|
|
270
|
+
| `onFeedbackSubmit` | `({ value: number; comment?: string \| string[] }) => void \| Promise<void>` | - | Fires when feedback is submitted. Includes the selected score and the user’s comment(s). |
|
|
271
|
+
|
|
272
|
+
> **Event behavior**
|
|
273
|
+
|
|
274
|
+
#### `onScoreSubmit`
|
|
275
|
+
|
|
276
|
+
Invoked immediately when the user selects a score on the rating scale — this callback runs *before* any optional follow-up screen is shown.
|
|
277
|
+
Use it to persist the rating instantly.
|
|
278
|
+
The actual `value` returned depends on the survey type:
|
|
279
|
+
|
|
280
|
+
- **CSAT2:** `1–2`
|
|
281
|
+
- **CSAT5:** `1–5`
|
|
282
|
+
- **CES7:** `1–7`
|
|
283
|
+
- **NPS10:** `0–10`
|
|
284
|
+
|
|
285
|
+
#### `onFeedbackSubmit`
|
|
286
|
+
|
|
287
|
+
Invoked when the user completes the follow-up step and submits their feedback (only applies when `responseType` is `text` or `choices`).
|
|
288
|
+
This callback provides both the original score and the user's input.
|
|
289
|
+
|
|
290
|
+
**Arguments:**
|
|
291
|
+
- `value: number` — the same score previously passed to `onScoreSubmit`
|
|
292
|
+
- `comment: string | string[]` — depends on `responseType`:
|
|
293
|
+
- `text`: a single text comment
|
|
294
|
+
- `choices`: an array of selected options (may include a free-text comment if enabled)
|
|
295
|
+
|
|
296
|
+
> **Important**
|
|
297
|
+
You should listen to **both** `onScoreSubmit` and `onFeedbackSubmit`.
|
|
298
|
+
A user may select a score but abandon the follow-up screen (close the widget, navigate away, refresh, etc.).
|
|
299
|
+
Handling both events ensures you capture at least the rating even when additional feedback is not provided — and still receive extended data when it is.
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
### Scale Style Options
|
|
303
|
+
|
|
304
|
+
Each survey type supports specific scale styles for displaying the rating interface:
|
|
305
|
+
|
|
306
|
+
#### CSAT2Survey
|
|
307
|
+
|
|
308
|
+
| Prop | Type | Required | Description |
|
|
309
|
+
|--------------------------|-------------------------|----------|-----------------------------------------------------------------------------------|
|
|
310
|
+
| `scaleStyle` | `'emoji'` \| `'thumbs'` | required | Emoji mood scale style (happy/sad faces) or thumbs up/down emoji scale style. |
|
|
311
|
+
|
|
312
|
+
#### CSAT5Survey
|
|
313
|
+
|
|
314
|
+
| Prop | Type | Required | Description |
|
|
315
|
+
|--------------------------|---------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------|
|
|
316
|
+
| `scaleStyle` | `'emoji'` \| `'numbers'` \| `'stars'` | required | Emoji scale style (5 emotion levels), numeric scale style (1–5), or star rating scale style (1–5 stars). |
|
|
317
|
+
|
|
318
|
+
#### CES7Survey
|
|
319
|
+
|
|
320
|
+
| Prop | Type | Required | Description |
|
|
321
|
+
|--------------------------|-------------|----------|------------------------------------|
|
|
322
|
+
| `scaleStyle` | `'numbers'` | required | Numeric scale style (1–7). |
|
|
323
|
+
|
|
324
|
+
#### NPS10Survey
|
|
325
|
+
|
|
326
|
+
| Prop | Type | Required | Description |
|
|
327
|
+
|--------------------------|-------------|----------|-------------------------------------|
|
|
328
|
+
| `scaleStyle` | `'numbers'` | required | Numeric scale style (0–10). |
|
|
329
|
+
|
|
330
|
+
Note: The numeric ranges are defined by the widget (e.g., CSAT5 uses a 1–5 scale, NPS10 uses 0–10).
|
|
331
|
+
|
|
332
|
+
## Styling
|
|
333
|
+
|
|
334
|
+
The package ships with minimal default styles. To use them:
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
import 'react-feedback-surveys/index.css';
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### CSS Variables
|
|
341
|
+
|
|
342
|
+
You can override colors and fonts via CSS variables:
|
|
343
|
+
|
|
344
|
+
```css
|
|
345
|
+
:root {
|
|
346
|
+
--ft-color-text: #272522;
|
|
347
|
+
--ft-color-muted: #667085;
|
|
348
|
+
--ft-control-bg: #F2F4F7;
|
|
349
|
+
--ft-shadow-color: rgba(0, 0, 0, 0.2);
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Or wrap the survey in your own class and target the generated markup.
|
|
354
|
+
|
|
355
|
+
For deeper customization strategies, see the section below.
|
|
356
|
+
|
|
357
|
+
### Custom Classes
|
|
358
|
+
|
|
359
|
+
All widgets accept a `classNames` prop with two optional groups: `base` (outer shell) and `scale` (the interactive
|
|
360
|
+
rating UI). Pass your own class names to override styles without relying on internal selectors.
|
|
361
|
+
|
|
362
|
+
When is this useful?
|
|
363
|
+
|
|
364
|
+
- Apply your design system spacing, typography or colors
|
|
365
|
+
- Adjust layout (e.g., make the scale full-width, change gaps)
|
|
366
|
+
- Restyle scale items (buttons, icons, numbers) consistently
|
|
367
|
+
|
|
368
|
+
Reference: available keys
|
|
369
|
+
|
|
370
|
+
| Key | Applies to |
|
|
371
|
+
|----------------|--------------------------------------------------------------|
|
|
372
|
+
| `base.base` | The outer widget container |
|
|
373
|
+
| `base.head` | Header row containing title and close button |
|
|
374
|
+
| `base.title` | The heading that shows main/feedback/success text |
|
|
375
|
+
| `base.body` | Main content region (rating scale, feedback form or success) |
|
|
376
|
+
| `base.close` | Close button |
|
|
377
|
+
| `scale.base` | Container around the scale style |
|
|
378
|
+
| `scale.list` | Wrapper for the interactive items (emoji/stars/numbers) |
|
|
379
|
+
| `scale.button` | Each clickable item in the scale |
|
|
380
|
+
| `scale.icon` | Icon inside a scale button (emoji, stars) |
|
|
381
|
+
| `scale.score` | Number inside a scale button (for numeric variants) |
|
|
382
|
+
| `scale.labels` | Left/Right labels displayed under the scale |
|
|
383
|
+
|
|
384
|
+
Example: customizing a CSAT5Survey widget
|
|
385
|
+
|
|
386
|
+
```tsx
|
|
387
|
+
import { CSAT5Survey } from 'react-feedback-surveys';
|
|
388
|
+
import 'react-feedback-surveys/index.css';
|
|
389
|
+
|
|
390
|
+
<CSAT5Survey
|
|
391
|
+
classNames={{
|
|
392
|
+
base: {
|
|
393
|
+
base: 'my-survey-base',
|
|
394
|
+
body: 'my-survey-body',
|
|
395
|
+
},
|
|
396
|
+
scale: {
|
|
397
|
+
list: 'my-scale-list',
|
|
398
|
+
button: 'my-scale-button',
|
|
399
|
+
score: 'my-scale-score',
|
|
400
|
+
labels: 'my-scale-labels',
|
|
401
|
+
}
|
|
402
|
+
}}
|
|
403
|
+
scaleStyle="numbers"
|
|
404
|
+
question="How would you rate your satisfaction with our product?"
|
|
405
|
+
minLabel="Very unsatisfied"
|
|
406
|
+
maxLabel="Very satisfied"
|
|
407
|
+
onScoreSubmit={({ value }) => {/* ... */}}
|
|
408
|
+
onFeedbackSubmit={({ value, comment }) => {/* ... */}}
|
|
409
|
+
/>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
You can then style these classes in your app stylesheet.
|
|
413
|
+
|
|
414
|
+
## Demo
|
|
415
|
+
|
|
416
|
+
- Live demo: [View Storybook](https://feedback.tools/react-feedback-surveys/storybook)
|
|
417
|
+
- Run locally: `npm run storybook`
|
|
418
|
+
|
|
419
|
+
## Contributing
|
|
420
|
+
|
|
421
|
+
### Local development (Storybook)
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
npm i
|
|
425
|
+
npm run storybook
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Storybook runs at http://localhost:6006 and is the recommended way to develop and review components.
|
|
429
|
+
|
|
430
|
+
### Library build (watch mode)
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
npm run dev
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
This builds the package to `dist/` and watches for changes.
|
|
437
|
+
|
|
438
|
+
### Production build
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
npm run build
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Roadmap
|
|
445
|
+
|
|
446
|
+
- [ ] Custom emoji & icon support
|
|
447
|
+
- [ ] Dark theme support
|
|
448
|
+
- [ ] RTL language support
|
|
449
|
+
|
|
450
|
+
## Changelog
|
|
451
|
+
|
|
452
|
+
For a detailed history of changes, see the [Changelog](https://feedback.tools/react-feedback-surveys/changelog).
|
|
453
|
+
|
|
454
|
+
## License
|
|
455
|
+
|
|
456
|
+
MIT © [feedback.tools](https://feedback.tools)
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root,:host{--ft-color-text: #272522;--ft-color-bg: #FFF;--ft-color-muted: #667085;--ft-control-bg: #F2F4F7;--ft-shadow-color: rgb(0 0 0 / 20%)}body{margin:0;box-sizing:border-box;padding:0}*,*:before,*:after{margin:0;box-sizing:border-box;padding:0}._base_1xl92_1{position:fixed;margin:0;box-sizing:border-box;max-height:calc(100vh - 48px);padding:0;overflow:auto;background-color:var(--ft-color-bg);border-radius:8px;box-shadow:0 0 10px var(--ft-shadow-color);transform-origin:50% 100%}._animated_1xl92_14{opacity:0;animation:_fadeForward_1xl92_1 .12s ease-in-out forwards}@keyframes _fadeForward_1xl92_1{0%{opacity:0;transform:translateY(8px) scale(.92)}to{opacity:1;transform:translateY(0) scale(1)}}._topLeft_1xl92_29{top:24px;left:24px}._top_1xl92_29{top:24px}._topRight_1xl92_38{top:24px;right:24px}._right_1xl92_43{top:50%;right:24px;transform:translateY(-50%)}._bottomRight_1xl92_49{right:24px;bottom:24px}._bottom_1xl92_49{bottom:24px}._bottomLeft_1xl92_58{bottom:24px;left:24px}._left_1xl92_63{left:24px}._content_1xl92_67{position:relative;padding:24px}._close_1xl92_72{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._close_1xl92_72:disabled{cursor:default}._close_1xl92_72{position:absolute;top:24px;right:24px;width:24px;height:24px;color:#98a2b3;transition:color .15s}._close_1xl92_72:hover{color:var(--ft-color-text)}._close_1xl92_72:before,._close_1xl92_72:after{position:absolute;top:50%;left:50%;content:"";background-color:currentcolor;border-radius:1px;transform:rotate(45deg)}._close_1xl92_72:before{margin:-1px 0 0 -8px;width:16px;height:2px}._close_1xl92_72:after{margin:-8px 0 0 -1px;width:2px;height:16px}._choices_1y2fs_1{margin:0 0 12px}._choice_1y2fs_1{display:flex}._choice_1y2fs_1+._choice_1y2fs_1{margin-top:12px}._label_1y2fs_12{position:relative;display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none}._sr_1y2fs_21{position:absolute;margin:-1px;width:1px;height:1px;padding:0;overflow:hidden;white-space:nowrap;border-width:0;clip:rect(0,0,0,0)}._checkbox_1y2fs_33{position:absolute;width:1px;height:1px;overflow:hidden;white-space:nowrap;clip-path:inset(50%)}._check_1y2fs_33{height:20px;min-width:20px;border:1px solid #aaa;border-radius:4px}._label_1y2fs_12:hover ._check_1y2fs_33{border-color:var(--ft-color-text)}._checkbox_1y2fs_33:checked+._check_1y2fs_33{position:relative;background-color:var(--ft-color-text);border-color:var(--ft-color-text)}._checkbox_1y2fs_33:checked+._check_1y2fs_33:after{position:absolute;top:50%;left:50%;width:10px;height:7px;content:"";border:2px solid;border-color:transparent transparent var(--ft-color-bg) var(--ft-color-bg);transform:translate(-45%,-75%) rotate(-45deg);pointer-events:none}._input_1y2fs_70{margin-top:8px;height:32px}._textarea_1y2fs_75{height:192px}._input_1y2fs_70,._textarea_1y2fs_75{width:100%;padding:8px 12px;font-size:16px;line-height:1.5;background-color:var(--ft-color-bg);border:1px solid #D0D5DD;border-radius:8px;outline:0 solid rgba(152,162,179,.14);resize:none;transition:background-color .15s,border-color .15s,outline-width .2s}._input_1y2fs_70:focus,._textarea_1y2fs_75:focus{outline:4px solid rgba(152,162,179,.14)}._submit_1y2fs_97{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._submit_1y2fs_97:disabled{cursor:default}._submit_1y2fs_97{padding:8px 32px;font-size:16px;font-weight:600;text-align:center;color:var(--ft-color-bg);background-color:var(--ft-color-text);border-radius:8px;transition:opacity .2s}._submit_1y2fs_97:hover{opacity:.85}._submit_1y2fs_97{margin-top:16px;width:100%}._success_1y2fs_129{padding:16px 0 32px;font-size:16px;font-weight:600;line-height:1.5;text-align:center}._base_1ilpx_1{padding:0 24px;text-align:center}._icon_1ilpx_6{display:inline-block}._base_1mrao_1{padding:0;font-family:Helvetica Neue,Arial Nova,Helvetica,Arial,sans-serif;color:var(--ft-color-text)}._head_1mrao_7{display:flex;gap:8px;padding:0 32px 20px 0}._title_1mrao_13{flex:1 0;font-family:inherit;font-size:16px;font-weight:500;font-style:normal;line-height:1.4}._base_15ezr_1{margin:10px 0 0;display:flex;justify-content:space-between}._label_15ezr_7{flex:0 0 50%;max-width:50%;font-size:14px;line-height:1.4286;color:#475467}._label_15ezr_7:first-child{text-align:left}._label_15ezr_7:last-child{text-align:right}._list_dm3po_1{display:flex;justify-content:center;gap:16px}._icon_dm3po_7{transition:transform .12s ease;transform:scale(1)}._button_dm3po_12{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_dm3po_12:disabled{cursor:default}._button_dm3po_12{display:flex;align-items:center;justify-content:center;width:56px;height:56px;background-color:#f9fafb;border-radius:50%}._button_dm3po_12:hover ._icon_dm3po_7{transform:scale(1.15)}._base_1uh9h_1{width:100vw;max-width:310px}._list_1j2mw_1{display:flex;justify-content:space-between}._icon_1j2mw_6{transition:transform .12s ease;transform:scale(1)}._button_1j2mw_11{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_1j2mw_11:disabled{cursor:default}._button_1j2mw_11{display:flex;align-items:center;justify-content:center;width:56px;height:56px;background-color:#f9fafb;border-radius:50%}._button_1j2mw_11:hover ._icon_1j2mw_6{transform:scale(1.15)}._list_f45j5_1{display:flex;justify-content:space-between}._button_f45j5_6{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_f45j5_6:disabled{cursor:default}._button_f45j5_6{display:flex;align-items:center;justify-content:center;width:40px;height:40px;font-size:18px;font-weight:700;color:var(--ft-color-muted);background-color:var(--ft-control-bg);border-radius:50%;transition:color .12s ease,transform .12s ease}._button_f45j5_6:hover{color:var(--ft-color-text);transform:scale(1.1)}._list_mtyej_1{display:flex;justify-content:space-between}._icon_mtyej_6{transition:transform .12s ease;transform:scale(1)}._button_mtyej_11{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_mtyej_11:disabled{cursor:default}._button_mtyej_11{display:flex;align-items:center;justify-content:center;width:40px;height:40px}._button_mtyej_11:hover ._icon_mtyej_6{transform:scale(1.1)}._base_1r0wo_1{width:100vw;max-width:320px}._list_1t0bv_1{display:flex;justify-content:space-between;gap:6px}@media(max-width:575px){._list_1t0bv_1{flex-direction:column-reverse;gap:4px}}._button_1t0bv_13{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_1t0bv_13:disabled{cursor:default}._button_1t0bv_13{display:inline-block;width:40px;height:40px;font-size:18px;font-weight:700;text-align:center;color:var(--ft-color-muted);background-color:var(--ft-control-bg);border-radius:50%;transition:color .12s ease,transform .12s ease;transform:scale(1)}._button_1t0bv_13:hover{color:var(--ft-color-text);transform:scale(1.1)}@media(max-width:575px){._button_1t0bv_13:hover{transform:none}}._button_1t0bv_13 ._score_1t0bv_49{display:inline}._button_1t0bv_13 ._label_1t0bv_52{display:none}@media(max-width:575px){._button_1t0bv_13 ._label_1t0bv_52{display:inline}}@media(max-width:575px){._button_1t0bv_13{width:100%;height:auto;padding:6px;font-size:14px;line-height:20px;border-radius:6px}}@media(max-width:575px){._labels_1t0bv_72{display:none}}._base_aftyp_1{width:100vw;max-width:340px}._list_1s7yb_1{display:flex;justify-content:space-between;gap:6px}@media(max-width:575px){._list_1s7yb_1{flex-direction:column-reverse;gap:4px}}._button_1s7yb_13{margin:0;appearance:none;padding:0;font-family:inherit;text-align:center;background-color:transparent;border:none;box-shadow:none;cursor:pointer}._button_1s7yb_13:disabled{cursor:default}._button_1s7yb_13{display:block;width:40px;height:40px;font-size:18px;font-weight:700;text-align:center;color:var(--ft-color-muted);background-color:var(--ft-control-bg);border-radius:50%;transition:color .12s ease,transform .12s ease;transform:scale(1)}._button_1s7yb_13:hover{color:var(--ft-color-text);transform:scale(1.1)}@media(max-width:575px){._button_1s7yb_13:hover{transform:none}}._button_1s7yb_13 ._score_1s7yb_49{display:inline}._button_1s7yb_13 ._label_1s7yb_52{display:none}@media(max-width:575px){._button_1s7yb_13 ._label_1s7yb_52{display:inline}}@media(max-width:575px){._button_1s7yb_13{width:100%;height:auto;padding:6px;font-size:14px;line-height:20px;border-radius:6px}}@media(max-width:575px){._labels_1s7yb_72{display:none}}._base_1xgqd_1{width:100%;max-width:520px}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { default as default_2 } from 'react';
|
|
2
|
+
|
|
3
|
+
export declare const CES7Survey: default_2.FC<CES7SurveyProps>;
|
|
4
|
+
|
|
5
|
+
export declare interface CES7SurveyProps extends SharedSurveyProps {
|
|
6
|
+
/** Visual style for the rating scale */
|
|
7
|
+
scaleStyle: 'numbers';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export declare const CSAT2Survey: default_2.FC<CSAT2SurveyProps>;
|
|
11
|
+
|
|
12
|
+
export declare interface CSAT2SurveyProps extends SharedSurveyProps {
|
|
13
|
+
/** Visual style for the rating scale */
|
|
14
|
+
scaleStyle: 'emoji' | 'thumbs';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare const CSAT5Survey: default_2.FC<CSAT5SurveyProps>;
|
|
18
|
+
|
|
19
|
+
export declare interface CSAT5SurveyProps extends SharedSurveyProps {
|
|
20
|
+
/** Visual style for the rating scale */
|
|
21
|
+
scaleStyle: 'emoji' | 'numbers' | 'stars';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare const NPS10Survey: default_2.FC<NPS10SurveyProps>;
|
|
25
|
+
|
|
26
|
+
export declare interface NPS10SurveyProps extends SharedSurveyProps {
|
|
27
|
+
/** Visual style for the rating scale */
|
|
28
|
+
scaleStyle: 'numbers';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare const Popup: React.FC<PopupProps>;
|
|
32
|
+
|
|
33
|
+
export declare interface PopupProps {
|
|
34
|
+
animated?: boolean;
|
|
35
|
+
className?: string;
|
|
36
|
+
classNames?: {
|
|
37
|
+
base?: string;
|
|
38
|
+
content?: string;
|
|
39
|
+
close?: string;
|
|
40
|
+
};
|
|
41
|
+
children?: React.ReactNode;
|
|
42
|
+
placement?: 'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft';
|
|
43
|
+
onClose?: () => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Class names for the root popup layout elements
|
|
48
|
+
*/
|
|
49
|
+
export declare interface RootClassNames {
|
|
50
|
+
/** Wrapper container */
|
|
51
|
+
base?: string;
|
|
52
|
+
/** Survey head wrapper (title + close) */
|
|
53
|
+
head?: string;
|
|
54
|
+
/** Survey main title text */
|
|
55
|
+
title?: string;
|
|
56
|
+
/** Survey content wrapper (scale or feedback screen) */
|
|
57
|
+
body?: string;
|
|
58
|
+
/** Close button element */
|
|
59
|
+
close?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Class names for rating scale components
|
|
64
|
+
*/
|
|
65
|
+
export declare interface ScaleClassNames {
|
|
66
|
+
/** Rating scale wrapper */
|
|
67
|
+
base?: string;
|
|
68
|
+
/** List wrapper for rating buttons */
|
|
69
|
+
list?: string;
|
|
70
|
+
/** Single rating button */
|
|
71
|
+
button?: string;
|
|
72
|
+
/** Optional icon used inside button */
|
|
73
|
+
icon?: string;
|
|
74
|
+
/** Score text or number indicator */
|
|
75
|
+
score?: string;
|
|
76
|
+
/** Labels below scale (left/right limits) */
|
|
77
|
+
labels?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Shared props for all survey components
|
|
82
|
+
*/
|
|
83
|
+
export declare interface SharedSurveyProps {
|
|
84
|
+
/** Optional classNames to customize internal parts */
|
|
85
|
+
classNames?: {
|
|
86
|
+
base?: RootClassNames;
|
|
87
|
+
scale?: ScaleClassNames;
|
|
88
|
+
};
|
|
89
|
+
/** Main survey question (screen 1) */
|
|
90
|
+
question: string;
|
|
91
|
+
/** Left label for the rating scale */
|
|
92
|
+
minLabel?: string;
|
|
93
|
+
/** Right label for the rating scale */
|
|
94
|
+
maxLabel?: string;
|
|
95
|
+
/** Type of feedback collection */
|
|
96
|
+
responseType?: null | 'text' | 'choices';
|
|
97
|
+
/** Follow-up feedback question (screen 2) */
|
|
98
|
+
textQuestion?: string;
|
|
99
|
+
/** Submit button text */
|
|
100
|
+
textButtonLabel?: string;
|
|
101
|
+
/** Optional predefined choices for feedback */
|
|
102
|
+
choiceOptions?: string[] | null;
|
|
103
|
+
/** Success message text */
|
|
104
|
+
thankYouMessage: string;
|
|
105
|
+
/** Callback when score data is submitted */
|
|
106
|
+
onScoreSubmit?: SurveyCallback;
|
|
107
|
+
/** Callback when survey data is submitted */
|
|
108
|
+
onFeedbackSubmit?: SurveyCallback;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Callback function for survey submission
|
|
113
|
+
* @param payload - The survey data to submit
|
|
114
|
+
* @returns void or Promise<void> for async operations
|
|
115
|
+
*/
|
|
116
|
+
export declare type SurveyCallback = (payload: SurveySubmitPayload) => void | Promise<void>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Available screens in survey flow
|
|
120
|
+
*/
|
|
121
|
+
export declare type SurveyScreen =
|
|
122
|
+
/** Rating screen (first screen) */
|
|
123
|
+
'main'
|
|
124
|
+
/** Final "thanks" message screen */
|
|
125
|
+
| 'success'
|
|
126
|
+
/** Feedback input screen */
|
|
127
|
+
| 'feedback';
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Payload sent when submitting survey data
|
|
131
|
+
*/
|
|
132
|
+
export declare interface SurveySubmitPayload {
|
|
133
|
+
/** Selected rating value */
|
|
134
|
+
value?: number;
|
|
135
|
+
/** Optional text or array of selected choices */
|
|
136
|
+
comment?: string | string[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { }
|