@magicfeedback/native 2.1.7-alpha.8 → 2.1.11
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 +315 -467
- package/dist/magicfeedback-sdk.browser.js +1 -1
- package/dist/magicfeedback-sdk.node.js +1 -1
- package/dist/styles/magicfeedback-default.css +268 -148
- package/dist/types/src/models/pageGraphs.d.ts +52 -0
- package/dist/types/src/models/types.d.ts +92 -3
- package/dist/types/src/render/helpers.d.ts +3 -0
- package/dist/types/src/render/ratingHelpers.d.ts +3 -0
- package/dist/types/src/render/registry.d.ts +3 -0
- package/dist/types/src/render/renderBoolean.d.ts +2 -0
- package/dist/types/src/render/renderChoice.d.ts +2 -0
- package/dist/types/src/render/renderConsent.d.ts +2 -0
- package/dist/types/src/render/renderDate.d.ts +2 -0
- package/dist/types/src/render/renderEmail.d.ts +2 -0
- package/dist/types/src/render/renderInfoPage.d.ts +2 -0
- package/dist/types/src/render/renderLongText.d.ts +2 -0
- package/dist/types/src/render/renderMatrix.d.ts +2 -0
- package/dist/types/src/render/renderMultipleChoiceImage.d.ts +2 -0
- package/dist/types/src/render/renderNumber.d.ts +2 -0
- package/dist/types/src/render/renderPassword.d.ts +2 -0
- package/dist/types/src/render/renderPointSystem.d.ts +2 -0
- package/dist/types/src/render/renderPriorityList.d.ts +2 -0
- package/dist/types/src/render/renderRatingEmoji.d.ts +2 -0
- package/dist/types/src/render/renderRatingNumber.d.ts +2 -0
- package/dist/types/src/render/renderRatingStar.d.ts +2 -0
- package/dist/types/src/render/renderSelect.d.ts +2 -0
- package/dist/types/src/render/renderText.d.ts +2 -0
- package/dist/types/src/render/renderUploadFile.d.ts +2 -0
- package/dist/types/src/render/renderUploadImage.d.ts +2 -0
- package/dist/types/src/render/types.d.ts +20 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,552 +1,400 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MagicFeedback SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
of [MagicFeedback.io](https://magicfeedback.io/) into your web applications. With minimal code, you can capture valuable
|
|
5
|
-
user feedback and insights, driving continuous improvement and enhancing user experience.
|
|
3
|
+
Browser SDK for rendering MagicFeedback surveys/forms, resuming sessions, previewing question definitions, and sending feedback directly from your app.
|
|
6
4
|
|
|
7
|
-
##
|
|
5
|
+
## What this SDK covers
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
- Render a hosted MagicFeedback form with `appId` + `publicKey`
|
|
8
|
+
- Resume an existing survey flow with `sessionId`
|
|
9
|
+
- Submit feedback directly when you already own the UI
|
|
10
|
+
- Preview one or more question objects locally
|
|
11
|
+
- Use the bundled default theme or override CSS variables
|
|
12
|
+
|
|
13
|
+
## Important before you start
|
|
14
|
+
|
|
15
|
+
- This is a browser-oriented SDK. It relies on `window`, `document`, `navigator`, and `localStorage`.
|
|
16
|
+
- Use it on the client side only. Server-side rendering and Node-only execution are not supported.
|
|
17
|
+
- Call `magicfeedback.init()` before `form()`, `session()`, or `send()`. `init()` sets the API base URL.
|
|
18
|
+
- `form.generate()` expects a DOM element id such as `"survey-root"`, not a CSS selector such as `"#survey-root"`.
|
|
13
19
|
|
|
14
20
|
## Install
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
project using NPM with a front-end packager such as [Browserify](http://browserify.org/)
|
|
18
|
-
or [Webpack](https://webpack.github.io/):
|
|
22
|
+
Install from [npm](https://www.npmjs.com/package/@magicfeedback/native):
|
|
19
23
|
|
|
20
24
|
```sh
|
|
21
|
-
npm
|
|
25
|
+
npm install @magicfeedback/native
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
var magicfeedback = require("@magicfeedback/native");
|
|
28
|
-
|
|
29
|
-
// or
|
|
28
|
+
## Quick start
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
### Plain HTML
|
|
32
31
|
|
|
32
|
+
```html
|
|
33
|
+
<link
|
|
34
|
+
rel="stylesheet"
|
|
35
|
+
href="./node_modules/@magicfeedback/native/dist/styles/magicfeedback-default.css"
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
<div id="survey-root"></div>
|
|
39
|
+
|
|
40
|
+
<script src="./node_modules/@magicfeedback/native/dist/magicfeedback-sdk.browser.js"></script>
|
|
41
|
+
<script>
|
|
42
|
+
window.magicfeedback.init({
|
|
43
|
+
env: "prod",
|
|
44
|
+
debug: false
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const form = window.magicfeedback.form("APP_ID", "PUBLIC_KEY");
|
|
48
|
+
|
|
49
|
+
form.generate("survey-root", {
|
|
50
|
+
addButton: true,
|
|
51
|
+
addSuccessScreen: true
|
|
52
|
+
});
|
|
53
|
+
</script>
|
|
33
54
|
```
|
|
34
55
|
|
|
35
|
-
|
|
56
|
+
### Vite / Webpack / SPA
|
|
36
57
|
|
|
37
|
-
|
|
58
|
+
```ts
|
|
59
|
+
import magicfeedback from "@magicfeedback/native";
|
|
60
|
+
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
|
|
38
61
|
|
|
39
|
-
```js
|
|
40
62
|
magicfeedback.init({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
})
|
|
63
|
+
env: "prod"
|
|
64
|
+
});
|
|
44
65
|
|
|
45
|
-
|
|
66
|
+
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
|
|
46
67
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
### A. Generate feedback forms
|
|
53
|
-
|
|
54
|
-
The feedback form generation functionality allows you to easily create and display feedback forms on your website. This
|
|
55
|
-
section provides an overview of how to use this feature and the necessary code snippets.
|
|
56
|
-
|
|
57
|
-
To generate a feedback form, you need to include the following HTML code snippet in your web page:
|
|
68
|
+
await form.generate("survey-root", {
|
|
69
|
+
addButton: true,
|
|
70
|
+
addSuccessScreen: true
|
|
71
|
+
});
|
|
72
|
+
```
|
|
58
73
|
|
|
59
74
|
```html
|
|
60
|
-
|
|
61
|
-
<div id="demo_form_div"></div>
|
|
75
|
+
<div id="survey-root"></div>
|
|
62
76
|
```
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Next, you need to include the following JavaScript code snippet in your application:
|
|
78
|
+
## Initialization
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
let form = window.magicfeedback.form(
|
|
70
|
-
"$_APP_ID",
|
|
71
|
-
"$_PUBLIC_KEY"
|
|
72
|
-
);
|
|
73
|
-
// or
|
|
74
|
-
let form = window.magicfeedback.session(
|
|
75
|
-
"$_SESSION_ID",
|
|
76
|
-
);
|
|
80
|
+
`init()` should be called once before any networked usage.
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
nextButtonText: string, // Default "Next", option to change the text of the next button
|
|
85
|
-
addSuccessScreen: boolean, // Default flase, option to add a success screen after send the form
|
|
86
|
-
successMessage: string, // Default "Thank you for your feedback!", option to change the success message
|
|
87
|
-
questionFormat: "standard" | "slim", // Default "standard", option to change the format of the questions.
|
|
88
|
-
getMetaData: boolean, // Default true, option to get the metadata of the form
|
|
89
|
-
beforeSubmitEvent: ({
|
|
90
|
-
loading: boolean,
|
|
91
|
-
progress: number,
|
|
92
|
-
total: number
|
|
93
|
-
}) => {
|
|
94
|
-
}, //Function to execute before send the form
|
|
95
|
-
afterSubmitEvent: ({
|
|
96
|
-
loading: boolean,
|
|
97
|
-
progress: number,
|
|
98
|
-
total: number,
|
|
99
|
-
response: string, // Response of the server if everything is ok
|
|
100
|
-
error: string, // Error of the server if something is wrong
|
|
101
|
-
}) => {
|
|
102
|
-
}, //Function to execute after send the form with the response
|
|
103
|
-
onLoadedEvent: ({
|
|
104
|
-
loading: boolean,
|
|
105
|
-
progress: number,
|
|
106
|
-
total: number,
|
|
107
|
-
formData: FormData
|
|
108
|
-
}) => {
|
|
109
|
-
}, //Function to execute after load the form
|
|
110
|
-
onBackEvent: ({
|
|
111
|
-
loading: boolean,
|
|
112
|
-
progress: number,
|
|
113
|
-
followup: boolean,
|
|
114
|
-
error: string, // Error of the server if something is wrong
|
|
115
|
-
}) => {
|
|
116
|
-
} //Function to execute after back the form
|
|
117
|
-
/*
|
|
118
|
-
class FormData {
|
|
119
|
-
id: string;
|
|
120
|
-
name: string;
|
|
121
|
-
description: string;
|
|
122
|
-
type: string;
|
|
123
|
-
identity: string;
|
|
124
|
-
status: string;
|
|
125
|
-
createdAt: Date;
|
|
126
|
-
updatedAt: Date;
|
|
127
|
-
externalId?: string | null;
|
|
128
|
-
companyId: string;
|
|
129
|
-
productId: string;
|
|
130
|
-
userId: string;
|
|
131
|
-
setting: Record<string, any>;
|
|
132
|
-
conf: Record<string, any>;
|
|
133
|
-
*/
|
|
134
|
-
}
|
|
135
|
-
)
|
|
82
|
+
```ts
|
|
83
|
+
magicfeedback.init({
|
|
84
|
+
env: "prod",
|
|
85
|
+
debug: false,
|
|
86
|
+
dryRun: false
|
|
87
|
+
});
|
|
136
88
|
```
|
|
137
89
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
90
|
+
| Option | Type | Default | Description |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| `env` | `"prod" \| "dev"` | `"prod"` | Selects the production or development API host. |
|
|
93
|
+
| `debug` | `boolean` | `false` | Enables console logging. |
|
|
94
|
+
| `dryRun` | `boolean` | `false` | Loads and navigates forms without sending feedback or requesting follow-up questions. |
|
|
143
95
|
|
|
144
|
-
|
|
145
|
-
themselves. By default, this value is set to false, indicating that the button will not be displayed.
|
|
146
|
-
* **beforeSubmitEvent**: An optional function that you can define to execute some actions or validations before the form
|
|
147
|
-
is submitted.
|
|
148
|
-
* **afterSubmitEvent**: An optional function that you can define to execute actions after the form is submitted. This
|
|
149
|
-
function receives the server response as a parameter.
|
|
150
|
-
* **onLoadedEvent**: An optional function that you can define to execute actions after the form is loaded.
|
|
96
|
+
`dryRun` is the safest way to QA a survey before giving it to a client.
|
|
151
97
|
|
|
152
|
-
|
|
153
|
-
following functions to manage the form.
|
|
98
|
+
## Render a form
|
|
154
99
|
|
|
155
|
-
|
|
156
|
-
form.send() // Get the answers in the form to send and go to the next question or finish.
|
|
100
|
+
Create a form instance with an app id and public key:
|
|
157
101
|
|
|
158
|
-
|
|
102
|
+
```ts
|
|
103
|
+
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
|
|
159
104
|
```
|
|
160
105
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
106
|
+
Then render it into a container:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
await form.generate("survey-root", {
|
|
110
|
+
addButton: true,
|
|
111
|
+
sendButtonText: "Send",
|
|
112
|
+
backButtonText: "Back",
|
|
113
|
+
nextButtonText: "Next",
|
|
114
|
+
startButtonText: "Start",
|
|
115
|
+
addSuccessScreen: true,
|
|
116
|
+
successMessage: "Thank you for your feedback!",
|
|
117
|
+
questionFormat: "standard",
|
|
118
|
+
getMetaData: true,
|
|
119
|
+
customMetaData: [
|
|
120
|
+
{ key: "customer-id", value: ["acme-42"] },
|
|
121
|
+
{ key: "plan", value: ["enterprise"] }
|
|
122
|
+
],
|
|
123
|
+
onLoadedEvent: ({ formData, progress, total, error }) => {
|
|
124
|
+
console.log("loaded", { formData, progress, total, error });
|
|
169
125
|
},
|
|
170
|
-
{
|
|
171
|
-
"
|
|
172
|
-
|
|
126
|
+
beforeSubmitEvent: ({ progress, total }) => {
|
|
127
|
+
console.log("before submit", { progress, total });
|
|
128
|
+
},
|
|
129
|
+
afterSubmitEvent: ({ response, progress, total, completed, followup, error }) => {
|
|
130
|
+
console.log("after submit", {
|
|
131
|
+
response,
|
|
132
|
+
progress,
|
|
133
|
+
total,
|
|
134
|
+
completed,
|
|
135
|
+
followup,
|
|
136
|
+
error
|
|
137
|
+
});
|
|
173
138
|
},
|
|
174
|
-
|
|
175
|
-
|
|
139
|
+
onBackEvent: ({ progress, followup, error }) => {
|
|
140
|
+
console.log("back", { progress, followup, error });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
176
143
|
```
|
|
177
144
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
145
|
+
### `generate()` options used by the current runtime
|
|
146
|
+
|
|
147
|
+
| Option | Default | Description |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `addButton` | `true` | Renders the built-in action buttons. |
|
|
150
|
+
| `sendButtonText` | `"Send"` | Label for the final submit button. |
|
|
151
|
+
| `backButtonText` | `"Back"` | Label for the back button. |
|
|
152
|
+
| `nextButtonText` | `"Next"` | Label for the next button in multi-step flows. |
|
|
153
|
+
| `startButtonText` | `"Go!"` | Label for the start button when the form has a backend start message. |
|
|
154
|
+
| `addSuccessScreen` | `true` | Shows the built-in success view when the flow finishes. |
|
|
155
|
+
| `successMessage` | `"Thank you for your feedback!"` | Custom success text. |
|
|
156
|
+
| `questionFormat` | `"standard"` | `"standard"` or `"slim"`. |
|
|
157
|
+
| `getMetaData` | `true` | Appends browser and page metadata automatically. |
|
|
158
|
+
| `customMetaData` | `[]` | Extra metadata merged into `feedback.metadata` when `getMetaData` is enabled. |
|
|
159
|
+
| `onLoadedEvent` | `undefined` | Called after the form or start screen is ready. |
|
|
160
|
+
| `beforeSubmitEvent` | `undefined` | Called before a page is submitted. |
|
|
161
|
+
| `afterSubmitEvent` | `undefined` | Called after a page submit, follow-up render, or final completion. |
|
|
162
|
+
| `onBackEvent` | `undefined` | Called after navigating back. |
|
|
163
|
+
|
|
164
|
+
When `getMetaData` is enabled, the SDK includes the current URL, origin, pathname, query string, user agent, browser language, platform, app metadata, screen size, and the session id when rendering from `session()`.
|
|
165
|
+
|
|
166
|
+
## Resume an existing session
|
|
167
|
+
|
|
168
|
+
If you already have a MagicFeedback session id, render it directly:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
magicfeedback.init({ env: "prod" });
|
|
172
|
+
|
|
173
|
+
const form = magicfeedback.session("SESSION_ID");
|
|
174
|
+
await form.generate("survey-root", {
|
|
175
|
+
addButton: true
|
|
176
|
+
});
|
|
186
177
|
```
|
|
187
178
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-

|
|
179
|
+
## Manual navigation
|
|
191
180
|
|
|
192
|
-
|
|
193
|
-
display feedback forms on your website using the magicfeedback service.
|
|
181
|
+
If you want to control your own buttons, disable the built-in actions and call `send()` / `back()` yourself.
|
|
194
182
|
|
|
195
|
-
|
|
183
|
+
```ts
|
|
184
|
+
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
|
|
196
185
|
|
|
197
|
-
|
|
198
|
-
|
|
186
|
+
await form.generate("survey-root", {
|
|
187
|
+
addButton: false
|
|
188
|
+
});
|
|
199
189
|
|
|
200
|
-
|
|
190
|
+
document.getElementById("next-btn")?.addEventListener("click", () => {
|
|
191
|
+
form.send(
|
|
192
|
+
[{ key: "source", value: ["pricing-page"] }],
|
|
193
|
+
[{ key: "account-score", value: ["92"] }],
|
|
194
|
+
[{ key: "customer-email", value: ["user@example.com"] }]
|
|
195
|
+
);
|
|
196
|
+
});
|
|
201
197
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"$_PUBLIC_KEY",
|
|
206
|
-
feedbackData,
|
|
207
|
-
completed, // Default true
|
|
208
|
-
"$_ID", // Optional
|
|
209
|
-
"$_PRIVATE_KEY", // Optional
|
|
210
|
-
)
|
|
198
|
+
document.getElementById("back-btn")?.addEventListener("click", () => {
|
|
199
|
+
form.back();
|
|
200
|
+
});
|
|
211
201
|
```
|
|
212
202
|
|
|
213
|
-
|
|
214
|
-
with the public key of your feedback application. This ID and key is provided by the magicfeedback service.
|
|
203
|
+
`form.send()` accepts arguments in this order:
|
|
215
204
|
|
|
216
|
-
|
|
205
|
+
1. `metadata`
|
|
206
|
+
2. `metrics`
|
|
207
|
+
3. `profile`
|
|
217
208
|
|
|
218
|
-
|
|
209
|
+
Each item should follow the same shape:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
{ key: "some-key", value: ["some-value"] }
|
|
213
|
+
```
|
|
219
214
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
215
|
+
## Send feedback directly
|
|
216
|
+
|
|
217
|
+
Use `magicfeedback.send()` when you do not want the SDK to render any UI.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
await magicfeedback.send(
|
|
221
|
+
"APP_ID",
|
|
222
|
+
"PUBLIC_KEY",
|
|
223
|
+
{
|
|
224
|
+
text: "",
|
|
223
225
|
answers: [
|
|
224
|
-
{
|
|
225
|
-
|
|
226
|
-
value: ["string"]
|
|
227
|
-
},
|
|
226
|
+
{ key: "nps", value: ["9"] },
|
|
227
|
+
{ key: "favorite-feature", value: ["Conditional logic"] }
|
|
228
228
|
],
|
|
229
229
|
metadata: [
|
|
230
|
-
{
|
|
231
|
-
key: 'string',
|
|
232
|
-
value: "string"
|
|
233
|
-
},
|
|
230
|
+
{ key: "source", value: ["pricing-page"] }
|
|
234
231
|
],
|
|
235
232
|
metrics: [
|
|
236
|
-
{
|
|
237
|
-
key: 'string',
|
|
238
|
-
value: "string"
|
|
239
|
-
},
|
|
233
|
+
{ key: "plan", value: ["pro"] }
|
|
240
234
|
],
|
|
241
235
|
profile: [
|
|
242
|
-
{
|
|
243
|
-
key: 'string',
|
|
244
|
-
value: "string"
|
|
245
|
-
},
|
|
236
|
+
{ key: "email", value: ["user@example.com"] }
|
|
246
237
|
]
|
|
247
|
-
}
|
|
238
|
+
},
|
|
239
|
+
true
|
|
240
|
+
);
|
|
248
241
|
```
|
|
249
242
|
|
|
250
|
-
|
|
251
|
-
* **value**: This setting determines the value of the feedback data.
|
|
252
|
-
|
|
253
|
-
Not all the fields are required. You can send only the fields that you need. But you need to send one of that minimal.
|
|
243
|
+
Signature:
|
|
254
244
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
245
|
+
```ts
|
|
246
|
+
magicfeedback.send(
|
|
247
|
+
appId,
|
|
248
|
+
publicKey,
|
|
249
|
+
feedback,
|
|
250
|
+
completed = true,
|
|
251
|
+
id?,
|
|
252
|
+
privateKey?
|
|
253
|
+
);
|
|
263
254
|
```
|
|
264
255
|
|
|
265
|
-
|
|
256
|
+
## Preview a question locally
|
|
257
|
+
|
|
258
|
+
`previewQuestion()` renders one question or an array of questions without changing the internal flow state.
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
const previewForm = magicfeedback.form("demo", "demo");
|
|
262
|
+
|
|
263
|
+
previewForm.previewQuestion("preview-root", {
|
|
264
|
+
id: "q_text",
|
|
265
|
+
title: "What is your name?",
|
|
266
|
+
type: "TEXT",
|
|
267
|
+
questionType: { conf: [] },
|
|
268
|
+
ref: "name",
|
|
269
|
+
require: true,
|
|
270
|
+
external_id: "",
|
|
271
|
+
value: [],
|
|
272
|
+
defaultValue: "",
|
|
273
|
+
followup: false,
|
|
274
|
+
position: 1,
|
|
275
|
+
assets: {
|
|
276
|
+
placeholder: "Type your name",
|
|
277
|
+
subtitle: "Used only for preview"
|
|
278
|
+
},
|
|
279
|
+
refMetric: "",
|
|
280
|
+
integrationId: "demo",
|
|
281
|
+
integrationPageId: "demo"
|
|
282
|
+
}, {
|
|
283
|
+
format: "standard",
|
|
284
|
+
language: "en",
|
|
285
|
+
product: { customIcons: false },
|
|
286
|
+
clearContainer: true,
|
|
287
|
+
wrap: true
|
|
288
|
+
});
|
|
289
|
+
```
|
|
266
290
|
|
|
267
|
-
|
|
268
|
-
|
|
291
|
+
This is useful for QA, local demos, and visual regression checks.
|
|
292
|
+
|
|
293
|
+
## Supported rendered question types
|
|
294
|
+
|
|
295
|
+
The renderer currently supports these question types:
|
|
296
|
+
|
|
297
|
+
- `TEXT`
|
|
298
|
+
- `LONGTEXT`
|
|
299
|
+
- `NUMBER`
|
|
300
|
+
- `RADIO`
|
|
301
|
+
- `MULTIPLECHOICE`
|
|
302
|
+
- `SELECT`
|
|
303
|
+
- `DATE`
|
|
304
|
+
- `EMAIL`
|
|
305
|
+
- `PASSWORD`
|
|
306
|
+
- `BOOLEAN`
|
|
307
|
+
- `CONSENT`
|
|
308
|
+
- `RATING_STAR`
|
|
309
|
+
- `RATING_EMOJI`
|
|
310
|
+
- `RATING_NUMBER`
|
|
311
|
+
- `MULTIPLECHOISE_IMAGE`
|
|
312
|
+
- `MULTI_QUESTION_MATRIX`
|
|
313
|
+
- `POINT_SYSTEM`
|
|
314
|
+
- `PRIORITY_LIST`
|
|
315
|
+
- `INFO_PAGE`
|
|
316
|
+
- `UPLOAD_FILE`
|
|
317
|
+
- `UPLOAD_IMAGE`
|
|
318
|
+
|
|
319
|
+
For the output payload generated by `Form.answer()`, see [docs/answer-format.md](docs/answer-format.md). That document describes payload serialization, while the list above reflects the question types currently rendered by the browser UI.
|
|
320
|
+
|
|
321
|
+
Important payload notes:
|
|
322
|
+
|
|
323
|
+
- `EMAIL` answers are also copied into `feedback.profile` as `email`.
|
|
324
|
+
- `POINT_SYSTEM` answers are serialized as values such as `"Quality:60%"`.
|
|
325
|
+
- `MULTI_QUESTION_MATRIX` answers are grouped into a single JSON string entry.
|
|
326
|
+
- Required `MULTI_QUESTION_MATRIX` questions must have an answer in every row before the SDK allows submission.
|
|
327
|
+
- `INFO_PAGE`, `UPLOAD_FILE`, and `UPLOAD_IMAGE` render in the UI but do not currently create answer entries.
|
|
328
|
+
|
|
329
|
+
## Styling
|
|
330
|
+
|
|
331
|
+
Import the bundled stylesheet:
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
|
|
269
335
|
```
|
|
270
336
|
|
|
271
|
-
|
|
337
|
+
Or with plain HTML:
|
|
272
338
|
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
--mf-primary-light: #dbeafe;
|
|
279
|
-
|
|
280
|
-
--mf-text-primary: #0f172a;
|
|
281
|
-
--mf-text-secondary: #64748b;
|
|
282
|
-
--mf-text-muted: #94a3b8;
|
|
283
|
-
|
|
284
|
-
--mf-bg-primary: #ffffff;
|
|
285
|
-
--mf-bg-secondary: #f8fafc;
|
|
286
|
-
--mf-bg-hover: #f1f5f9;
|
|
287
|
-
|
|
288
|
-
--mf-border: #e2e8f0;
|
|
289
|
-
--mf-border-focus: #2563eb;
|
|
290
|
-
|
|
291
|
-
--mf-success: #10b981;
|
|
292
|
-
--mf-error: #ef4444;
|
|
293
|
-
--mf-warning: #f59e0b;
|
|
294
|
-
|
|
295
|
-
/* Spacing */
|
|
296
|
-
--mf-space-xs: 0.25rem;
|
|
297
|
-
--mf-space-sm: 0.5rem;
|
|
298
|
-
--mf-space-md: 0.75rem;
|
|
299
|
-
--mf-space-lg: 1rem;
|
|
300
|
-
--mf-space-xl: 1.5rem;
|
|
301
|
-
|
|
302
|
-
/* Border Radius */
|
|
303
|
-
--mf-radius-sm: 0.375rem;
|
|
304
|
-
--mf-radius-md: 0.5rem;
|
|
305
|
-
--mf-radius-lg: 0.75rem;
|
|
306
|
-
--mf-radius-full: 9999px;
|
|
307
|
-
|
|
308
|
-
/* Shadows */
|
|
309
|
-
--mf-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
310
|
-
--mf-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
311
|
-
--mf-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
312
|
-
--mf-shadow-focus: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
313
|
-
|
|
314
|
-
/* Typography */
|
|
315
|
-
--mf-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica", "Arial", sans-serif;
|
|
316
|
-
--mf-font-size-sm: 0.875rem;
|
|
317
|
-
--mf-font-size-base: 1rem;
|
|
318
|
-
--mf-font-size-lg: 1.125rem;
|
|
319
|
-
--mf-font-size-xl: 1.25rem;
|
|
320
|
-
--mf-line-height: 1.6;
|
|
321
|
-
|
|
322
|
-
/* Transitions */
|
|
323
|
-
--mf-transition: all 0.2s ease;
|
|
324
|
-
--mf-transition-fast: all 0.15s ease;
|
|
325
|
-
}
|
|
339
|
+
```html
|
|
340
|
+
<link
|
|
341
|
+
rel="stylesheet"
|
|
342
|
+
href="./node_modules/@magicfeedback/native/dist/styles/magicfeedback-default.css"
|
|
343
|
+
/>
|
|
326
344
|
```
|
|
327
345
|
|
|
328
|
-
|
|
346
|
+
You can override the main CSS variables without modifying the distributed file:
|
|
329
347
|
|
|
330
348
|
```css
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
/* Main form element */
|
|
337
|
-
.magicfeedback-form {
|
|
338
|
-
/* ... add your form styles here ... */
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/* Section for questions */
|
|
342
|
-
.magicfeedback-questions {
|
|
343
|
-
/* ... add your questions section styles here ... */
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/* Section for div */
|
|
347
|
-
.magicfeedback-div {
|
|
348
|
-
/* ... add your generic div styles here ... */
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/* Generic styles for various input elements */
|
|
352
|
-
.magicfeedback-label,
|
|
353
|
-
.magicfeedback-input,
|
|
354
|
-
.magicfeedback-contact,
|
|
355
|
-
.magicfeedback-password,
|
|
356
|
-
.magicfeedback-email,
|
|
357
|
-
.magicfeedback-boolean,
|
|
358
|
-
.magicfeedback-consent,
|
|
359
|
-
.magicfeedback-date,
|
|
360
|
-
.magicfeedback-select,
|
|
361
|
-
.magicfeedback-radio,
|
|
362
|
-
.magicfeedback-checkbox,
|
|
363
|
-
.magicfeedback-rating,
|
|
364
|
-
.magicfeedback-rating-container,
|
|
365
|
-
.magicfeedback-rating-option,
|
|
366
|
-
.magicfeedback-rating-option-label-container,
|
|
367
|
-
.magicfeedback-number,
|
|
368
|
-
.magicfeedback-longtext,
|
|
369
|
-
.magicfeedback-text,
|
|
370
|
-
.magicfeedback-priority-list{
|
|
371
|
-
/* ... add your generic input styles here ... */
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.magicfeedback-skip-container {
|
|
375
|
-
/* ... add your skip container styles here ... */
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.magicfeedback-skip{
|
|
379
|
-
/* ... add your skip button styles here ... */
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
.magicfeedback-image {
|
|
383
|
-
/* ... add your image styles here ... */
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/* Specific styles for individual input types */
|
|
387
|
-
.magicfeedback-radio-container,
|
|
388
|
-
.magicfeedback-boolean-container,
|
|
389
|
-
.magicfeedback-consent-container,
|
|
390
|
-
.magicfeedback-checkbox-container,
|
|
391
|
-
.magicfeedback-longtext-container,
|
|
392
|
-
.magicfeedback-priority-list-container{
|
|
393
|
-
/* ... add styles for radio/checkbox containers ... */
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
.magicfeedback-rating-placeholder {
|
|
397
|
-
/* ... add your rating placeholder styles here ... */
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
.magicfeedback-rating-placeholder-min {
|
|
401
|
-
/* ... add your rating placeholder min styles here ... */
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
.magicfeedback-rating-placeholder-max {
|
|
405
|
-
/* ... add your rating placeholder max styles here ... */
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
.magicfeedback-rating-image1,
|
|
409
|
-
.magicfeedback-rating-image2,
|
|
410
|
-
.magicfeedback-rating-image3,
|
|
411
|
-
.magicfeedback-rating-image4,
|
|
412
|
-
.magicfeedback-rating-image5,
|
|
413
|
-
.magicfeedback-rating-image6,
|
|
414
|
-
.magicfeedback-rating-image7,
|
|
415
|
-
.magicfeedback-rating-image8,
|
|
416
|
-
.magicfeedback-rating-image9,
|
|
417
|
-
.magicfeedback-rating-image10,
|
|
418
|
-
.magicfeedback-rating-image-extra {
|
|
419
|
-
/* ... add styles for rating images ... */
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/* Section for number rating */
|
|
423
|
-
.magicfeedback-rating-number-container {
|
|
424
|
-
/* ... add your number rating container styles here ... */
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
.magicfeedback-rating-number-placeholder {
|
|
428
|
-
/* ... add your number rating placeholder styles here ... */
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
.magicfeedback-rating-number-placeholder-min {
|
|
432
|
-
/* ... add your number rating placeholder min styles here ... */
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
.magicfeedback-rating-number-placeholder-max {
|
|
436
|
-
/* ... add your number rating placeholder max styles here ... */
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
.magicfeedback-rating-number-option {
|
|
440
|
-
/* ... add your number rating option styles here ... */
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
.magicfeedback-rating-number-option-label-container {
|
|
444
|
-
/* ... add your number rating option label container styles here ... */
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
/* Section for star rating */
|
|
449
|
-
.magicfeedback-rating-star {
|
|
450
|
-
/* ... add your star rating container styles here ... */
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
.magicfeedback-rating-star-container {
|
|
454
|
-
/* ... add your star rating styles here ... */
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
.magicfeedback-rating-star-option {
|
|
458
|
-
/* ... add your star rating option styles here ... */
|
|
459
|
-
}
|
|
349
|
+
:root {
|
|
350
|
+
--mf-primary: #0f766e;
|
|
351
|
+
--mf-primary-hover: #115e59;
|
|
352
|
+
--mf-primary-light: #ccfbf1;
|
|
460
353
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
354
|
+
--mf-text-primary: #0f172a;
|
|
355
|
+
--mf-text-secondary: #475569;
|
|
464
356
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
/* ... add your multiple choice image container styles here ... */
|
|
468
|
-
}
|
|
357
|
+
--mf-bg-primary: #ffffff;
|
|
358
|
+
--mf-bg-secondary: #f8fafc;
|
|
469
359
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
360
|
+
--mf-border: #cbd5e1;
|
|
361
|
+
--mf-border-focus: #0f766e;
|
|
473
362
|
|
|
474
|
-
|
|
475
|
-
|
|
363
|
+
--mf-radius-md: 0.5rem;
|
|
364
|
+
--mf-shadow-md: 0 10px 20px rgba(15, 23, 42, 0.08);
|
|
476
365
|
}
|
|
366
|
+
```
|
|
477
367
|
|
|
478
|
-
|
|
479
|
-
/* ... add your multiple choice image option label container styles here ... */
|
|
480
|
-
}
|
|
368
|
+
For deeper customization, inspect `dist/styles/magicfeedback-default.css` and override the generated classes from your own stylesheet.
|
|
481
369
|
|
|
482
|
-
|
|
483
|
-
/* ... add your multiple choice image label styles here ... */
|
|
484
|
-
}
|
|
370
|
+
## QA and staging
|
|
485
371
|
|
|
486
|
-
|
|
487
|
-
/* ... add your multiple choice image input styles here ... */
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
.magicfeedback-multiple-choice-image-image {
|
|
491
|
-
/* ... add your multiple choice image image styles here ... */
|
|
492
|
-
}
|
|
372
|
+
Recommended setup for client review:
|
|
493
373
|
|
|
494
|
-
|
|
495
|
-
.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
.magicfeedback-priority-list-item{
|
|
502
|
-
/* ... add your priority list item styles here ... */
|
|
503
|
-
}
|
|
504
|
-
.magicfeedback-priority-list-item-label{
|
|
505
|
-
/* ... add your priority list item label styles here ... */
|
|
506
|
-
}
|
|
507
|
-
.magicfeedback-priority-list-arrow-up,
|
|
508
|
-
.magicfeedback-priority-list-arrow-down{
|
|
509
|
-
/* ... add your priority list arrow up styles here ... */
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
/* Action buttons container */
|
|
513
|
-
.magicfeedback-action-container {
|
|
514
|
-
/* ... add your action button container styles here ... */
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/* Submit button */
|
|
518
|
-
.magicfeedback-submit {
|
|
519
|
-
/* ... add your submit button styles here ... */
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/* Back button */
|
|
523
|
-
.magicfeedback-back {
|
|
524
|
-
/* ... add your back button styles here ... */
|
|
525
|
-
}
|
|
374
|
+
```ts
|
|
375
|
+
magicfeedback.init({
|
|
376
|
+
env: "dev",
|
|
377
|
+
debug: true,
|
|
378
|
+
dryRun: true
|
|
379
|
+
});
|
|
380
|
+
```
|
|
526
381
|
|
|
527
|
-
|
|
528
|
-
.magicfeedback-start-message-container {
|
|
529
|
-
/* ... add your start message container styles here ... */
|
|
530
|
-
}
|
|
382
|
+
This combination lets you load the survey, navigate questions, and inspect callbacks without creating real feedback records.
|
|
531
383
|
|
|
532
|
-
|
|
533
|
-
/* ... add your start message styles here ... */
|
|
534
|
-
}
|
|
384
|
+
## Examples in this repository
|
|
535
385
|
|
|
536
|
-
.
|
|
537
|
-
|
|
538
|
-
|
|
386
|
+
- `examples/frontend/browser.html` - minimal browser integration
|
|
387
|
+
- `examples/frontend/browser_static.html` - live form plus local previews for all supported question types
|
|
388
|
+
- `examples/frontend/form.html` - embed the SDK inside an existing page layout
|
|
389
|
+
- `examples/frontend/embedded_in_form.html` - combine static inputs with SDK-managed questions
|
|
390
|
+
- `docs/answer-format.md` - exact payload format produced by `Form.answer()`
|
|
539
391
|
|
|
540
|
-
|
|
541
|
-
/* ... add your info page styles here ... */
|
|
542
|
-
}
|
|
392
|
+
## Troubleshooting
|
|
543
393
|
|
|
544
|
-
|
|
545
|
-
/* ... add your info message styles here ... */
|
|
546
|
-
}
|
|
394
|
+
If the form does not load:
|
|
547
395
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
396
|
+
- Confirm that `magicfeedback.init()` has been called.
|
|
397
|
+
- Confirm that the container id passed to `generate()` exists in the DOM.
|
|
398
|
+
- Check that you are using the correct `APP_ID`, `PUBLIC_KEY`, or `SESSION_ID`.
|
|
399
|
+
- Turn on `debug: true` to inspect SDK logs.
|
|
400
|
+
- Use `dryRun: true` when validating the flow before production rollout.
|