@qaiddev/quests-embed 1.5.0 → 1.6.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 +40 -14
- package/dist/bootstrap.d.ts +20 -0
- package/dist/embed.d.ts +24 -0
- package/dist/index.d.ts +1 -1
- package/dist/qaid-quests.js +394 -226
- package/dist/qaid-quests.js.map +1 -1
- package/dist/qaid-quests.umd.cjs +3 -3
- package/dist/qaid-quests.umd.cjs.map +1 -1
- package/dist/types.d.ts +20 -6
- package/dist/visibility.d.ts +16 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,8 +78,8 @@ For complex configurations or inline questionnaires, use a separate JSON config
|
|
|
78
78
|
2. A response record is created on your server (`POST` to `endpoint`)
|
|
79
79
|
3. Questions render one at a time with a progress bar and Back/Next navigation
|
|
80
80
|
4. Answers autosave as the user moves between steps (`PATCH` per question). Text and currency fields debounce by `saveDebounceMs` (default 500ms)
|
|
81
|
-
5. On the final step,
|
|
82
|
-
6. A "thank you" screen appears
|
|
81
|
+
5. On the final step, the answers to the questions still visible are submitted in a single batch (`POST` to `{endpoint}/{id}/submit`). An answer to a question that `visibleIf` has since hidden is left out, and cleared on the server with a `PATCH` of `null`
|
|
82
|
+
6. A "thank you" screen appears once the server accepts the submit. If the create or the submit fails (a network error or a non-2xx reply), the embed shows "Couldn't send your answers" with a **Try again** button instead; the answers are kept, and Try again re-creates the response first if it has to
|
|
83
83
|
|
|
84
84
|
If `container` is set, the form renders inline inside that element. If not, it opens as a centered modal with a backdrop.
|
|
85
85
|
|
|
@@ -242,18 +242,18 @@ We offer a Free Plan that hosts both the endpoint and a dashboard for managing y
|
|
|
242
242
|
|
|
243
243
|
| Option | Type | Default | Description |
|
|
244
244
|
|--------|------|---------|-------------|
|
|
245
|
-
| `autoAdvance` | `boolean` | `false` | Advance automatically on
|
|
245
|
+
| `autoAdvance` | `boolean` | `false` | Advance automatically when an option is picked on a single-choice multiple-choice question. No other type auto-advances (multi-select, text, currency, range and date wait for Next / Enter) |
|
|
246
246
|
| `saveDebounceMs` | `number` | `500` | Debounce in ms for autosave on text/currency/range |
|
|
247
247
|
| `autoFocus` | `boolean` | `true` | Auto-focus the input on each step. Set `false` in preview/embedded contexts that shouldn't steal focus |
|
|
248
248
|
|
|
249
249
|
### Host integration
|
|
250
250
|
|
|
251
|
-
For programmatic embedding — e.g. launching a quest from another widget — these hooks let the host pass correlation data in and react to the quest's lifecycle.
|
|
251
|
+
For programmatic embedding — e.g. launching a quest from another widget — these hooks let the host pass correlation data in and react to the quest's lifecycle. `metadata` can also be set on the `<script>` tag as `data-metadata`; the two callbacks are functions, so they need you to construct `QaidQuests` yourself.
|
|
252
252
|
|
|
253
253
|
| Option | Type | Default | Description |
|
|
254
254
|
|--------|------|---------|-------------|
|
|
255
255
|
| `metadata` | `Record<string, unknown>` | — | Extra key/value pairs sent verbatim in the create-response `POST` body. The server decides which keys it persists; unknown keys are ignored. Used, for example, by `@qaiddev/thumbs-embed` to pass `{ feedbackId }` so the QAid backend joins the quest answers to the feedback record. |
|
|
256
|
-
| `onComplete` | `(answers) => void` | — | Called once when the quest is completed and
|
|
256
|
+
| `onComplete` | `(answers) => void` | — | Called once when the quest is completed and the server accepted the submit (just after the thank-you screen renders), with a copy of the submitted answers — answers to questions hidden by `visibleIf` are left out. Not called while the submit is failing. Fires in both modal and inline modes. |
|
|
257
257
|
| `onClose` | `() => void` | — | Called once when the embed is torn down — visitor close, host `destroy()`, or teardown after completion. Lets a host that launched the quest drop its reference. |
|
|
258
258
|
|
|
259
259
|
```typescript
|
|
@@ -297,25 +297,45 @@ Colors accept hex (`#ABC`, `#AABBCC`) or `rgb(r, g, b)` format. The text color u
|
|
|
297
297
|
|
|
298
298
|
## Script Tag Data Attributes
|
|
299
299
|
|
|
300
|
-
|
|
300
|
+
Every config option except the two callbacks (`onComplete`, `onClose`) has a `data-*` attribute, so the script tag alone can set anything else. If a JSON config block is also on the page, the block wins and the attributes are not read.
|
|
301
|
+
|
|
302
|
+
Object options take JSON. In HTML, wrap the value in single quotes so the JSON's double quotes survive: `data-metadata='{"feedbackId":"clx1"}'`.
|
|
301
303
|
|
|
302
304
|
| Attribute | Maps To |
|
|
303
305
|
|-----------|---------|
|
|
304
|
-
| `data-endpoint` | `endpoint` |
|
|
305
|
-
| `data-config-url` | `configUrl` |
|
|
306
|
+
| `data-endpoint` | `endpoint` (required) |
|
|
306
307
|
| `data-api-key` | `apiKey` |
|
|
308
|
+
| `data-questionnaire` | `questionnaire`: the questionnaire as JSON, with a `questions` array. Starts the quest without `data-config-url` |
|
|
309
|
+
| `data-config-url` | `configUrl` |
|
|
307
310
|
| `data-container` | `container` |
|
|
308
311
|
| `data-zindex` | `zIndex` |
|
|
309
|
-
| `data-
|
|
310
|
-
| `data-
|
|
311
|
-
| `data-
|
|
312
|
+
| `data-accent-color` | `colors.accent` |
|
|
313
|
+
| `data-error-color` | `colors.error` |
|
|
314
|
+
| `data-focus-color` | `colors.focus` |
|
|
315
|
+
| `data-positive-color` | `colors.positive` (deprecated alias for `colors.accent`) |
|
|
316
|
+
| `data-negative-color` | `colors.negative` (deprecated alias for `colors.error`) |
|
|
317
|
+
| `data-marker-color` | `colors.marker` (deprecated alias for `colors.focus`) |
|
|
312
318
|
| `data-modal-width` | `modalWidth` |
|
|
313
319
|
| `data-backdrop-opacity` | `backdropOpacity` |
|
|
314
320
|
| `data-font-family` | `fontFamily` |
|
|
315
321
|
| `data-font-size` | `fontSize` |
|
|
322
|
+
| `data-css` | `css` (wins over `data-css-selector`) |
|
|
323
|
+
| `data-css-selector` | `css`, taken from the `textContent` of the element this selector matches |
|
|
316
324
|
| `data-auto-advance` | `autoAdvance` (`"true"` to enable) |
|
|
317
325
|
| `data-save-debounce-ms` | `saveDebounceMs` |
|
|
318
|
-
| `data-
|
|
326
|
+
| `data-auto-focus` | `autoFocus` (`"true"` or `"false"`) |
|
|
327
|
+
| `data-animate` | `animate` (`"true"` or `"false"`) |
|
|
328
|
+
| `data-progress-position` | `progressPosition` (`"top"` or `"bottom"`) |
|
|
329
|
+
| `data-theme` | `theme` (`"light"`, `"dark"` or `"auto"`) |
|
|
330
|
+
| `data-unstyled` | `unstyled` (`"true"` to enable) |
|
|
331
|
+
| `data-preset` | `preset` (`"default"`, `"minimal"`, `"pill"` or `"dense"`) |
|
|
332
|
+
| `data-theme-url` | `themeUrl` |
|
|
333
|
+
| `data-theme-document` | `themeDocument`, as a JSON object |
|
|
334
|
+
| `data-metadata` | `metadata`, as a JSON object |
|
|
335
|
+
|
|
336
|
+
`onComplete` and `onClose` are functions, so they can only be passed from code (`new QaidQuests({ ... })`).
|
|
337
|
+
|
|
338
|
+
A value the embed can't use (malformed JSON, a questionnaire with no `questions` array, `data-auto-focus="yes"`, an unknown `data-progress-position`) is ignored with one `console.warn` naming the attribute, and the default stays.
|
|
319
339
|
|
|
320
340
|
## Modal vs. Inline
|
|
321
341
|
|
|
@@ -422,8 +442,14 @@ Your endpoint should return `{ "id": "..." }` (string or number). The form is us
|
|
|
422
442
|
```
|
|
423
443
|
|
|
424
444
|
`value` is `string | number | string[] | null` depending on the question type.
|
|
425
|
-
|
|
426
|
-
|
|
445
|
+
Just before submitting, the embed sends `"value": null` for every answered
|
|
446
|
+
question that `visibleIf` has since hidden, so a server that stores answers
|
|
447
|
+
from these PATCHes drops them too.
|
|
448
|
+
|
|
449
|
+
**3. Submit** — `POST {endpoint}/{id}/submit`. `answers` holds only the
|
|
450
|
+
questions visible at submit time. Reply with a 2xx; anything else (or a
|
|
451
|
+
network error) shows the visitor a retry screen instead of the thank-you
|
|
452
|
+
screen:
|
|
427
453
|
|
|
428
454
|
```json
|
|
429
455
|
{
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading config from the page for the script-tag install: the JSON config
|
|
3
|
+
* block and the embed's own `data-*` attributes.
|
|
4
|
+
*
|
|
5
|
+
* Kept out of `index.ts` so it can be tested: `index.ts` runs auto-init as a
|
|
6
|
+
* side effect of being imported and is excluded from coverage. Not re-exported
|
|
7
|
+
* from `index.ts`, so none of this is public API.
|
|
8
|
+
*/
|
|
9
|
+
import type { QuestsConfig } from "./types";
|
|
10
|
+
/**
|
|
11
|
+
* Config from `<script type="application/json" data-quests-config>`.
|
|
12
|
+
* When present and valid it wins outright; the attributes are not read.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseJsonConfig(): Partial<QuestsConfig> | null;
|
|
15
|
+
/**
|
|
16
|
+
* Config from the embed's own `data-*` attributes. Every option that can be
|
|
17
|
+
* written as text has one; only the `onComplete` / `onClose` callbacks need
|
|
18
|
+
* code.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseDataAttributes(script: HTMLScriptElement): Partial<QuestsConfig> | null;
|
package/dist/embed.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { Answers, Questionnaire, QuestsConfig } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* A random v4 UUID.
|
|
4
|
+
*
|
|
5
|
+
* `crypto.randomUUID` exists only in secure contexts (HTTPS and localhost). On
|
|
6
|
+
* a plain http:// page it is undefined, and calling it threw while mounting, so
|
|
7
|
+
* the quest never appeared. `crypto.getRandomValues` has no such restriction;
|
|
8
|
+
* `Math.random` covers a runtime with no `crypto` at all. The id only groups
|
|
9
|
+
* one browser's responses, so it needs to be unique, not secret.
|
|
10
|
+
*/
|
|
11
|
+
export declare function randomId(): string;
|
|
2
12
|
export declare class QaidQuests {
|
|
3
13
|
private config;
|
|
4
14
|
private questionnaire;
|
|
@@ -14,6 +24,10 @@ export declare class QaidQuests {
|
|
|
14
24
|
private answers;
|
|
15
25
|
private responseId;
|
|
16
26
|
private visitorId;
|
|
27
|
+
private createPromise;
|
|
28
|
+
private createPending;
|
|
29
|
+
private droppedSaves;
|
|
30
|
+
private submitting;
|
|
17
31
|
private pendingSaveTimer;
|
|
18
32
|
private pendingSaveQuestionId;
|
|
19
33
|
private pendingSaveValue;
|
|
@@ -72,6 +86,13 @@ export declare class QaidQuests {
|
|
|
72
86
|
private renderHeader;
|
|
73
87
|
private renderStep;
|
|
74
88
|
private renderDone;
|
|
89
|
+
/**
|
|
90
|
+
* Shown instead of the thank-you screen when the response could not be
|
|
91
|
+
* created or the submit was refused. The answers stay in memory, so
|
|
92
|
+
* "Try again" re-runs the whole submit (re-creating the response first
|
|
93
|
+
* if needed) without the visitor re-entering anything.
|
|
94
|
+
*/
|
|
95
|
+
private renderSubmitError;
|
|
75
96
|
private advance;
|
|
76
97
|
private back;
|
|
77
98
|
private recomputeVisible;
|
|
@@ -79,8 +100,11 @@ export declare class QaidQuests {
|
|
|
79
100
|
private flushPendingSave;
|
|
80
101
|
private saveAnswer;
|
|
81
102
|
private doSave;
|
|
103
|
+
private patchAnswer;
|
|
104
|
+
private startCreate;
|
|
82
105
|
private createResponse;
|
|
83
106
|
private submit;
|
|
107
|
+
private trySubmit;
|
|
84
108
|
private jsonHeaders;
|
|
85
109
|
private showSaving;
|
|
86
110
|
private handleKeyDown;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { QaidQuests } from "./embed";
|
|
34
34
|
export { QaidQuests };
|
|
35
|
-
export { getVisibleQuestions, evaluateRule } from "./visibility";
|
|
35
|
+
export { getVisibleQuestions, getVisibleAnswers, evaluateRule, } from "./visibility";
|
|
36
36
|
export type { QuestsConfig, ResolvedQuestsConfig, Questionnaire, Question, TextQuestion, CurrencyQuestion, RangeQuestion, DateQuestion, MultipleChoiceQuestion, MultipleChoiceOption, Answers, AnswerValue, VisibilityRule, CreateResponsePayload, CreateResponseResult, UpdateAnswerPayload, SubmitPayload, } from "./types";
|