@cxpinsight/survey-spec 0.7.0 → 0.9.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/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/validate.d.ts +346 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +489 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ export { evaluateTree, compareValues, MAX_TREE_DEPTH } from './evaluateTree';
|
|
|
15
15
|
export type { ConditionNode, Operand, TreeContext } from './evaluateTree';
|
|
16
16
|
export { resolveVariable } from './resolveVariable';
|
|
17
17
|
export { splitIntoPages } from './pageFlow';
|
|
18
|
-
export { complianceGate, questionForValidation, validateAnswer, impliedChoices, impliedActions, impliedStepActions, impliedEqualProminence, safeActionHref, safeImageSrc, isDeferChoice, canSwipeToDismiss, autoDismissMs, deadlineCountdown, formatCountdown, outcomeFor, voiceUsable, rewardToShow, cardClickTarget, cardHoverEffect, resolveAction } from './validate';
|
|
19
|
-
export type { ComplianceState, EscapeHatch, ComplianceInput, ComplianceVerdict, ValidatableQuestion, OutcomeKind, OutcomeInput, ActionKind, RawAction, ResolvedAction } from './validate';
|
|
18
|
+
export { complianceGate, questionForValidation, validateAnswer, impliedChoices, impliedActions, impliedStepActions, impliedEqualProminence, safeActionHref, safeImageSrc, isDeferChoice, canSwipeToDismiss, showsClose, autoDismissMs, deadlineCountdown, formatCountdown, outcomeFor, voiceUsable, rewardToShow, rewardTerms, showsConfirmation, confirmationText, showsQuestionLabel, collectsAnswer, answerShape, resolveBranding, resolveTheme, resolveThemeDecision, cardClickTarget, cardIsClickable, cardHoverEffect, showActionButton, imageLayout, imageScrim, imageDesign, triggerVariables, resolveAction } from './validate';
|
|
19
|
+
export type { ComplianceState, EscapeHatch, ComplianceInput, ComplianceVerdict, ValidatableQuestion, OutcomeKind, OutcomeInput, ActionKind, RawAction, ResolvedAction, ImageLayout, ImageDesign, TriggerContext } from './validate';
|
|
20
20
|
export { validateAnswerCode } from './validate';
|
|
21
21
|
export { wordMessage, EN_MESSAGES, MESSAGE_CODES } from './messages';
|
|
22
22
|
export type { ValidationMessage } from './messages';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7E,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7E,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzmB,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACpO,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EACL,mBAAmB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EACzE,kBAAkB,EAAE,SAAS,EAAE,iBAAiB,EAChD,YAAY,EAAE,cAAc,EAAE,mBAAmB,EACjD,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EACtE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,GAC7D,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.optionLabelsOf = exports.voiceOptionsOf = void 0;
|
|
3
|
+
exports.matchBoolean = exports.normalizeTranscript = exports.MESSAGE_CODES = exports.EN_MESSAGES = exports.wordMessage = exports.validateAnswerCode = exports.resolveAction = exports.triggerVariables = exports.imageDesign = exports.imageScrim = exports.imageLayout = exports.showActionButton = exports.cardHoverEffect = exports.cardIsClickable = exports.cardClickTarget = exports.resolveThemeDecision = exports.resolveTheme = exports.resolveBranding = exports.answerShape = exports.collectsAnswer = exports.showsQuestionLabel = exports.confirmationText = exports.showsConfirmation = exports.rewardTerms = exports.rewardToShow = exports.voiceUsable = exports.outcomeFor = exports.formatCountdown = exports.deadlineCountdown = exports.autoDismissMs = exports.showsClose = exports.canSwipeToDismiss = exports.isDeferChoice = exports.safeImageSrc = exports.safeActionHref = exports.impliedEqualProminence = exports.impliedStepActions = exports.impliedActions = exports.impliedChoices = exports.validateAnswer = exports.questionForValidation = exports.complianceGate = exports.splitIntoPages = exports.resolveVariable = exports.MAX_TREE_DEPTH = exports.compareValues = exports.evaluateTree = exports.isParseable = exports.evaluateCondition = exports.evaluateExpression = void 0;
|
|
4
|
+
exports.optionLabelsOf = exports.voiceOptionsOf = exports.optionValueOf = exports.optionLabelOf = exports.shortCode = exports.buildPromptText = exports.scaffoldFor = exports.skipNoteText = exports.voiceDisclaimer = exports.auditVoiceQuestions = exports.voiceCanHandle = exports.voiceSupport = exports.distinctiveLabels = exports.matchDate = exports.matchNumberInRange = exports.rankOptions = exports.matchOptions = exports.matchOption = void 0;
|
|
5
5
|
/**
|
|
6
6
|
* @cxpinsight/survey-spec
|
|
7
7
|
*
|
|
@@ -38,14 +38,30 @@ Object.defineProperty(exports, "safeActionHref", { enumerable: true, get: functi
|
|
|
38
38
|
Object.defineProperty(exports, "safeImageSrc", { enumerable: true, get: function () { return validate_1.safeImageSrc; } });
|
|
39
39
|
Object.defineProperty(exports, "isDeferChoice", { enumerable: true, get: function () { return validate_1.isDeferChoice; } });
|
|
40
40
|
Object.defineProperty(exports, "canSwipeToDismiss", { enumerable: true, get: function () { return validate_1.canSwipeToDismiss; } });
|
|
41
|
+
Object.defineProperty(exports, "showsClose", { enumerable: true, get: function () { return validate_1.showsClose; } });
|
|
41
42
|
Object.defineProperty(exports, "autoDismissMs", { enumerable: true, get: function () { return validate_1.autoDismissMs; } });
|
|
42
43
|
Object.defineProperty(exports, "deadlineCountdown", { enumerable: true, get: function () { return validate_1.deadlineCountdown; } });
|
|
43
44
|
Object.defineProperty(exports, "formatCountdown", { enumerable: true, get: function () { return validate_1.formatCountdown; } });
|
|
44
45
|
Object.defineProperty(exports, "outcomeFor", { enumerable: true, get: function () { return validate_1.outcomeFor; } });
|
|
45
46
|
Object.defineProperty(exports, "voiceUsable", { enumerable: true, get: function () { return validate_1.voiceUsable; } });
|
|
46
47
|
Object.defineProperty(exports, "rewardToShow", { enumerable: true, get: function () { return validate_1.rewardToShow; } });
|
|
48
|
+
Object.defineProperty(exports, "rewardTerms", { enumerable: true, get: function () { return validate_1.rewardTerms; } });
|
|
49
|
+
Object.defineProperty(exports, "showsConfirmation", { enumerable: true, get: function () { return validate_1.showsConfirmation; } });
|
|
50
|
+
Object.defineProperty(exports, "confirmationText", { enumerable: true, get: function () { return validate_1.confirmationText; } });
|
|
51
|
+
Object.defineProperty(exports, "showsQuestionLabel", { enumerable: true, get: function () { return validate_1.showsQuestionLabel; } });
|
|
52
|
+
Object.defineProperty(exports, "collectsAnswer", { enumerable: true, get: function () { return validate_1.collectsAnswer; } });
|
|
53
|
+
Object.defineProperty(exports, "answerShape", { enumerable: true, get: function () { return validate_1.answerShape; } });
|
|
54
|
+
Object.defineProperty(exports, "resolveBranding", { enumerable: true, get: function () { return validate_1.resolveBranding; } });
|
|
55
|
+
Object.defineProperty(exports, "resolveTheme", { enumerable: true, get: function () { return validate_1.resolveTheme; } });
|
|
56
|
+
Object.defineProperty(exports, "resolveThemeDecision", { enumerable: true, get: function () { return validate_1.resolveThemeDecision; } });
|
|
47
57
|
Object.defineProperty(exports, "cardClickTarget", { enumerable: true, get: function () { return validate_1.cardClickTarget; } });
|
|
58
|
+
Object.defineProperty(exports, "cardIsClickable", { enumerable: true, get: function () { return validate_1.cardIsClickable; } });
|
|
48
59
|
Object.defineProperty(exports, "cardHoverEffect", { enumerable: true, get: function () { return validate_1.cardHoverEffect; } });
|
|
60
|
+
Object.defineProperty(exports, "showActionButton", { enumerable: true, get: function () { return validate_1.showActionButton; } });
|
|
61
|
+
Object.defineProperty(exports, "imageLayout", { enumerable: true, get: function () { return validate_1.imageLayout; } });
|
|
62
|
+
Object.defineProperty(exports, "imageScrim", { enumerable: true, get: function () { return validate_1.imageScrim; } });
|
|
63
|
+
Object.defineProperty(exports, "imageDesign", { enumerable: true, get: function () { return validate_1.imageDesign; } });
|
|
64
|
+
Object.defineProperty(exports, "triggerVariables", { enumerable: true, get: function () { return validate_1.triggerVariables; } });
|
|
49
65
|
Object.defineProperty(exports, "resolveAction", { enumerable: true, get: function () { return validate_1.resolveAction; } });
|
|
50
66
|
var validate_2 = require("./validate");
|
|
51
67
|
Object.defineProperty(exports, "validateAnswerCode", { enumerable: true, get: function () { return validate_2.validateAnswerCode; } });
|
package/dist/validate.d.ts
CHANGED
|
@@ -177,6 +177,34 @@ export declare function canSwipeToDismiss(display: {
|
|
|
177
177
|
} | null | undefined, delivery?: {
|
|
178
178
|
mustShow?: unknown;
|
|
179
179
|
} | null): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Is the ✕ drawn?
|
|
182
|
+
*
|
|
183
|
+
* TWO RENDERERS, TWO ANSWERS, from one authored survey. Web resolved an unset
|
|
184
|
+
* `showClose` to "hidden on a notification, shown everywhere else" — a
|
|
185
|
+
* deliberate rule, written down: a banner is swiped away, and canSwipeToDismiss
|
|
186
|
+
* turns the gesture on precisely when the ✕ is off. The phone read
|
|
187
|
+
* `showClose !== false`, so an unset notification kept its ✕ AND, because its
|
|
188
|
+
* display is a plain merge that leaves the value undefined, never enabled the
|
|
189
|
+
* swipe. The same notification was dismissable two different ways depending on
|
|
190
|
+
* which screen you were looking at, and a panel describing it could only be
|
|
191
|
+
* right about one of them.
|
|
192
|
+
*
|
|
193
|
+
* ONLY WHERE THE GESTURE REPLACES IT. Dropping the ✕ from a notification that
|
|
194
|
+
* cannot be swiped — a modal, a fullscreen takeover, a must-show — would leave
|
|
195
|
+
* no way out at all. That trap was already live on web, which hid the mark on
|
|
196
|
+
* every notification regardless of mode; asking canSwipeToDismiss here closes
|
|
197
|
+
* it on both.
|
|
198
|
+
*
|
|
199
|
+
* An explicit value always wins: '' / null / undefined mean "inherit", the same
|
|
200
|
+
* convention the rest of `display` uses.
|
|
201
|
+
*/
|
|
202
|
+
export declare function showsClose(display: {
|
|
203
|
+
mode?: unknown;
|
|
204
|
+
showClose?: unknown;
|
|
205
|
+
} | null | undefined, interactionType?: unknown, delivery?: {
|
|
206
|
+
mustShow?: unknown;
|
|
207
|
+
} | null): boolean;
|
|
180
208
|
/**
|
|
181
209
|
* How long before this surface dismisses ITSELF, in ms. 0 = never.
|
|
182
210
|
*
|
|
@@ -367,6 +395,116 @@ export declare function complianceGate(input: ComplianceInput): ComplianceVerdic
|
|
|
367
395
|
* regardless of what the survey or the application says.
|
|
368
396
|
*/
|
|
369
397
|
export declare function voiceUsable(questions: ValidatableQuestion[] | null | undefined): boolean;
|
|
398
|
+
export declare function collectsAnswer(question: {
|
|
399
|
+
type?: unknown;
|
|
400
|
+
} | null | undefined): boolean;
|
|
401
|
+
/**
|
|
402
|
+
* The part of a question set that responses are keyed by.
|
|
403
|
+
*
|
|
404
|
+
* Two sets with the same shape can be swapped without orphaning a single
|
|
405
|
+
* answer — which is the only thing the lock has to protect. Order is included
|
|
406
|
+
* because a reordered set changes nothing about the keys but IS how a
|
|
407
|
+
* different survey can be smuggled in with matching ids.
|
|
408
|
+
*/
|
|
409
|
+
export declare function answerShape(questions: Array<{
|
|
410
|
+
id?: unknown;
|
|
411
|
+
name?: unknown;
|
|
412
|
+
type?: unknown;
|
|
413
|
+
}> | null | undefined): string;
|
|
414
|
+
export declare function resolveBranding(survey: {
|
|
415
|
+
branding?: Record<string, unknown> | null;
|
|
416
|
+
applicationBranding?: Record<string, unknown> | null;
|
|
417
|
+
settings?: {
|
|
418
|
+
themeDetached?: unknown;
|
|
419
|
+
} | null;
|
|
420
|
+
} | null | undefined): Record<string, unknown>;
|
|
421
|
+
/**
|
|
422
|
+
* LIGHT OR DARK, AND WHO GETS TO SAY.
|
|
423
|
+
*
|
|
424
|
+
* Five answers can arrive at once and they were ranked differently on each
|
|
425
|
+
* renderer, so the same card came out white on a phone and dark in a browser.
|
|
426
|
+
* The order, highest first:
|
|
427
|
+
*
|
|
428
|
+
* pinned a theme set on THIS interaction. An author who picked dark
|
|
429
|
+
* meant it; 'auto' or absent steps aside.
|
|
430
|
+
* user identify({ theme }) — the host telling us about this person.
|
|
431
|
+
* declared init({ theme }), or on the web a live <html data-theme>/dark
|
|
432
|
+
* class. The host telling us about the surface.
|
|
433
|
+
* appDefault the APPLICATION's theme. A default, with exactly the standing
|
|
434
|
+
* `defaultLanguage` has always had.
|
|
435
|
+
* device Appearance on a phone, prefers-color-scheme in a browser.
|
|
436
|
+
*
|
|
437
|
+
* `device` is LAST, which is the part that is easy to get wrong — it was
|
|
438
|
+
* ranked above `appDefault` for a day and broke both renderers in opposite
|
|
439
|
+
* directions. It describes the hardware, not the surface the card is drawn
|
|
440
|
+
* into: an app shipping `userInterfaceStyle: "dark"` is dark on a light
|
|
441
|
+
* handset, and a light website is light to a visitor whose desktop is dark.
|
|
442
|
+
* A card that trusts the device paints itself against the surface holding it.
|
|
443
|
+
* A host whose theme genuinely tracks the device says so through `declared`,
|
|
444
|
+
* which is a statement rather than a guess.
|
|
445
|
+
*/
|
|
446
|
+
export type ThemeSource = 'pinned' | 'user' | 'declared' | 'appDefault' | 'device' | 'fallback';
|
|
447
|
+
/**
|
|
448
|
+
* The same decision, with WHICH CANDIDATE WON attached.
|
|
449
|
+
*
|
|
450
|
+
* Diagnostics, and worth having: the question "why is this card light?" was
|
|
451
|
+
* asked four times across two renderers and answered wrongly twice, because
|
|
452
|
+
* from the outside every tier produces the same two words. A host running in
|
|
453
|
+
* debug can now read the reason instead of inferring it from a screenshot.
|
|
454
|
+
*/
|
|
455
|
+
export declare function resolveThemeDecision(input: {
|
|
456
|
+
pinned?: unknown;
|
|
457
|
+
user?: unknown;
|
|
458
|
+
declared?: unknown;
|
|
459
|
+
appDefault?: unknown;
|
|
460
|
+
device?: unknown;
|
|
461
|
+
} | null | undefined): {
|
|
462
|
+
theme: 'light' | 'dark';
|
|
463
|
+
from: ThemeSource;
|
|
464
|
+
};
|
|
465
|
+
export declare function resolveTheme(input: {
|
|
466
|
+
pinned?: unknown;
|
|
467
|
+
user?: unknown;
|
|
468
|
+
declared?: unknown;
|
|
469
|
+
appDefault?: unknown;
|
|
470
|
+
device?: unknown;
|
|
471
|
+
} | null | undefined): 'light' | 'dark';
|
|
472
|
+
/**
|
|
473
|
+
* DOES THE CARD SHOW A CONFIRMATION AFTER IT IS ACCEPTED?
|
|
474
|
+
*
|
|
475
|
+
* An offer's ending is hardcoded: "It's yours", "Use this at checkout." Two
|
|
476
|
+
* more sentences about somebody else's business, written by us, in a screen an
|
|
477
|
+
* author could neither reword nor turn off — the same shape as the small print
|
|
478
|
+
* that shipped inside a template.
|
|
479
|
+
*
|
|
480
|
+
* Off is a real answer: an offer whose reward is applied by the host app, or
|
|
481
|
+
* one that navigates somewhere it is already applied, has nothing to confirm —
|
|
482
|
+
* the card dwelling on a thank-you is a step between the customer and the thing
|
|
483
|
+
* they just asked for.
|
|
484
|
+
*
|
|
485
|
+
* WITH ONE REFUSAL. A code is handed over ON that screen and nowhere else, so
|
|
486
|
+
* hiding it would take the discount away at the moment of giving it. That is
|
|
487
|
+
* not a preference, so it is not offered as one: the flag is ignored and the
|
|
488
|
+
* screen shows.
|
|
489
|
+
*/
|
|
490
|
+
export declare function showsConfirmation(survey: {
|
|
491
|
+
settings?: {
|
|
492
|
+
showConfirmation?: unknown;
|
|
493
|
+
} | null;
|
|
494
|
+
reward?: {
|
|
495
|
+
type?: unknown;
|
|
496
|
+
value?: unknown;
|
|
497
|
+
} | null;
|
|
498
|
+
} | null | undefined): boolean;
|
|
499
|
+
/**
|
|
500
|
+
* The words on that screen, the author's where they wrote any.
|
|
501
|
+
*
|
|
502
|
+
* `thankYouMessage` is the field every other interaction already uses for
|
|
503
|
+
* this, so an offer reaching for a second one would be a second place to look.
|
|
504
|
+
*/
|
|
505
|
+
export declare function confirmationText(survey: {
|
|
506
|
+
thankYouMessage?: unknown;
|
|
507
|
+
} | null | undefined, fallback: string): string;
|
|
370
508
|
/** The reward, ready to show — or null when there is nothing to hand over. */
|
|
371
509
|
export declare function rewardToShow(survey: {
|
|
372
510
|
reward?: {
|
|
@@ -381,6 +519,63 @@ export declare function rewardToShow(survey: {
|
|
|
381
519
|
whereValid: string;
|
|
382
520
|
expiresAt: string | null;
|
|
383
521
|
} | null;
|
|
522
|
+
/**
|
|
523
|
+
* Does this question draw a label above itself?
|
|
524
|
+
*
|
|
525
|
+
* Every renderer emitted one unconditionally, so a question whose whole
|
|
526
|
+
* content IS its content — a picture, a block of copy — drew an EMPTY label
|
|
527
|
+
* and its margin above itself. The way round that was to compose such things
|
|
528
|
+
* outside the question flow, which puts things on a card that the survey
|
|
529
|
+
* schema does not describe.
|
|
530
|
+
*
|
|
531
|
+
* `hideLabel` is a declared question option now, and this is the one rule all
|
|
532
|
+
* three renderers ask:
|
|
533
|
+
*
|
|
534
|
+
* hideLabel === true → never, even with text
|
|
535
|
+
* hideLabel === false → always, even empty (an author who wants the space)
|
|
536
|
+
* unset → only if there is something to say
|
|
537
|
+
*/
|
|
538
|
+
export declare function showsQuestionLabel(question: {
|
|
539
|
+
type?: unknown;
|
|
540
|
+
hideLabel?: unknown;
|
|
541
|
+
text?: unknown;
|
|
542
|
+
title?: unknown;
|
|
543
|
+
label?: unknown;
|
|
544
|
+
} | null | undefined): boolean;
|
|
545
|
+
/**
|
|
546
|
+
* THE SMALL PRINT ON AN OFFER — the author's words, not ours.
|
|
547
|
+
*
|
|
548
|
+
* "Valid on your first order only. Cannot be combined with other offers."
|
|
549
|
+
* shipped as a `content` question in the first-purchase template, which made it
|
|
550
|
+
* three separate problems:
|
|
551
|
+
*
|
|
552
|
+
* • It is a claim about somebody else's business, stated by us.
|
|
553
|
+
* • A `content` question lives in `questions`, which is SCHEMA — so the one
|
|
554
|
+
* kind of text most likely to need correcting could not be corrected on a
|
|
555
|
+
* LIVE offer, which is the only time correcting it matters.
|
|
556
|
+
* • The template translated its title, description and choices into Arabic
|
|
557
|
+
* and not this, so an Arabic offer carried English legal text.
|
|
558
|
+
*
|
|
559
|
+
* It belongs to the reward, beside what the customer gets and where it is
|
|
560
|
+
* valid. Empty means no small print, which is the right default: an offer with
|
|
561
|
+
* no conditions should not be made to invent some.
|
|
562
|
+
*
|
|
563
|
+
* FALLS BACK TO THE LEGACY QUESTION so offers created before this keep showing
|
|
564
|
+
* what they already show. Tags are stripped rather than rendered — the text is
|
|
565
|
+
* drawn as text by all three renderers, and `<small>` was only ever standing in
|
|
566
|
+
* for the styling the card now does itself.
|
|
567
|
+
*/
|
|
568
|
+
export declare function rewardTerms(survey: {
|
|
569
|
+
reward?: {
|
|
570
|
+
terms?: unknown;
|
|
571
|
+
} | null;
|
|
572
|
+
questions?: Array<{
|
|
573
|
+
id?: unknown;
|
|
574
|
+
type?: unknown;
|
|
575
|
+
html?: unknown;
|
|
576
|
+
text?: unknown;
|
|
577
|
+
}> | null;
|
|
578
|
+
} | null | undefined): string;
|
|
384
579
|
/**
|
|
385
580
|
* Where clicking the CARD ITSELF should take someone, or null.
|
|
386
581
|
*
|
|
@@ -400,6 +595,148 @@ export declare function cardClickTarget(display: {
|
|
|
400
595
|
} | null | undefined, actions: Array<{
|
|
401
596
|
href?: string;
|
|
402
597
|
}> | null | undefined): string | null;
|
|
598
|
+
/**
|
|
599
|
+
* May the whole card be pressed?
|
|
600
|
+
*
|
|
601
|
+
* SEPARATE FROM WHERE IT GOES, and that separation is the fix. cardClickTarget
|
|
602
|
+
* answers "what destination does the card carry", and returns null when there
|
|
603
|
+
* is none — but a notification whose action is "tell your app" or "call an
|
|
604
|
+
* endpoint" has no destination and is still entirely pressable: pressing it
|
|
605
|
+
* records the answer and runs the action, which is the whole point of those
|
|
606
|
+
* two kinds.
|
|
607
|
+
*
|
|
608
|
+
* Reading the target as the permission meant that on any non-URL action the
|
|
609
|
+
* card lost its pointer cursor, its hover treatment and its click handler at
|
|
610
|
+
* once — so "What the card does under the cursor" did nothing, with no clue
|
|
611
|
+
* why.
|
|
612
|
+
*
|
|
613
|
+
* The safety argument is unchanged and lives here: exactly ONE action. That is
|
|
614
|
+
* the notification shape, and it excludes every consent choice — on a
|
|
615
|
+
* two-action compliance takeover a stray click anywhere would otherwise record
|
|
616
|
+
* agreement, which a consent record must never manufacture.
|
|
617
|
+
*/
|
|
618
|
+
export declare function cardIsClickable(display: {
|
|
619
|
+
cardClickable?: unknown;
|
|
620
|
+
} | null | undefined, actions: Array<{
|
|
621
|
+
href?: string;
|
|
622
|
+
}> | null | undefined): boolean;
|
|
623
|
+
/**
|
|
624
|
+
* Is the action BUTTON drawn?
|
|
625
|
+
*
|
|
626
|
+
* A card whose whole surface is the action does not always need a button
|
|
627
|
+
* repeating it — "Resume" written twice on a banner two lines tall is the
|
|
628
|
+
* button competing with the card for the same press. So an author may hide it
|
|
629
|
+
* and let the card carry the action alone.
|
|
630
|
+
*
|
|
631
|
+
* ONLY WHEN THE CARD CAN ACTUALLY TAKE THE PRESS. Hiding the button on a card
|
|
632
|
+
* that is not clickable leaves a surface with something to say and no way to
|
|
633
|
+
* say yes to it — the respondent's only exit is the dismissal, which records
|
|
634
|
+
* the opposite of what the author was asking for. So the hide is honoured
|
|
635
|
+
* strictly when cardIsClickable agrees, and ignored otherwise.
|
|
636
|
+
*
|
|
637
|
+
* That also inherits the one-action guard: a two-action consent takeover can
|
|
638
|
+
* never hide its buttons, because a card that silently picks one of two
|
|
639
|
+
* answers is the thing consent must never do.
|
|
640
|
+
*/
|
|
641
|
+
export declare function showActionButton(display: {
|
|
642
|
+
cardClickable?: unknown;
|
|
643
|
+
showAction?: unknown;
|
|
644
|
+
} | null | undefined, actions: Array<{
|
|
645
|
+
href?: string;
|
|
646
|
+
}> | null | undefined): boolean;
|
|
647
|
+
export interface TriggerContext {
|
|
648
|
+
definitionId?: unknown;
|
|
649
|
+
eventName?: unknown;
|
|
650
|
+
eventType?: unknown;
|
|
651
|
+
eventData?: unknown;
|
|
652
|
+
pathname?: unknown;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* The variables a response carries about what made the interaction appear.
|
|
656
|
+
*
|
|
657
|
+
* `eventData` is spread FIRST so a caller's own values (URL params, identify()
|
|
658
|
+
* traits) still win when merged on top — the triggering event describes the
|
|
659
|
+
* occasion, not the respondent.
|
|
660
|
+
*/
|
|
661
|
+
export declare function triggerVariables(tc: TriggerContext | null | undefined): Record<string, unknown>;
|
|
662
|
+
export type ImageLayout = 'beside' | 'above' | 'below' | 'background' | 'half' | 'none';
|
|
663
|
+
export declare function imageLayout(display: {
|
|
664
|
+
imageLayout?: unknown;
|
|
665
|
+
} | null | undefined, interactionType: unknown, hasImage: boolean): ImageLayout;
|
|
666
|
+
/**
|
|
667
|
+
* EVERYTHING ABOUT THE PICTURE, RESOLVED ONCE.
|
|
668
|
+
*
|
|
669
|
+
* Layout alone was enough while the answer was "a square, a band, or the whole
|
|
670
|
+
* card". An offer wants the picture to CARRY the card — half of it, cropped to
|
|
671
|
+
* the part that matters, with the seam between image and words softened — and
|
|
672
|
+
* that is five more decisions. Asked one at a time they drift: the preview
|
|
673
|
+
* centres a band the phone left-aligns, and nobody notices until an author
|
|
674
|
+
* says the two do not match.
|
|
675
|
+
*
|
|
676
|
+
* WHAT IS DELIBERATELY ABSENT: blur. The React Native SDK declares no
|
|
677
|
+
* dependencies beyond AsyncStorage, and React Native has no blur primitive —
|
|
678
|
+
* `react-native-svg` is an OPTIONAL peer, so it cannot be relied on either. A
|
|
679
|
+
* Blur control would work in the preview and do nothing on a phone, which is
|
|
680
|
+
* the exact class of control this codebase has spent a long time removing.
|
|
681
|
+
* Everything below works natively on both.
|
|
682
|
+
*/
|
|
683
|
+
export interface ImageDesign {
|
|
684
|
+
layout: ImageLayout;
|
|
685
|
+
/** For 'half': which half the picture takes. Mirrored in a right-to-left
|
|
686
|
+
* card, because the whole card is. */
|
|
687
|
+
side: 'left' | 'right' | 'top';
|
|
688
|
+
/** For 'half': the share of the card the picture takes, 20-80. */
|
|
689
|
+
split: number;
|
|
690
|
+
/** How wide a band is, as a share of the card, 20-100. Alignment only means
|
|
691
|
+
* something once this is less than the whole width. */
|
|
692
|
+
width: number;
|
|
693
|
+
/** Where the picture sits in the space it is given. Vertical for a square
|
|
694
|
+
* beside the text, horizontal for a band narrower than the card.
|
|
695
|
+
*
|
|
696
|
+
* BOX POSITION, NOT FOCAL POINT. The obvious reading — which part of a
|
|
697
|
+
* cropped photograph you see — is object-position, and React Native has no
|
|
698
|
+
* equivalent: it would work in the preview and do nothing on a phone. This
|
|
699
|
+
* moves the picture's box, which both runtimes do natively. */
|
|
700
|
+
align: 'start' | 'center' | 'end';
|
|
701
|
+
/** How it fills that space. 'contain' shows all of it and may letterbox. */
|
|
702
|
+
fit: 'cover' | 'contain';
|
|
703
|
+
/** WHICH PART STAYS VISIBLE when 'cover' crops, 0-100 on each axis, 50 being
|
|
704
|
+
* the centre crop every renderer does by default.
|
|
705
|
+
*
|
|
706
|
+
* The thing that makes one picture work at three different shapes: a face
|
|
707
|
+
* near the top survives a wide band, a product on the right survives a left
|
|
708
|
+
* half. Without it an author has to re-crop the file for each layout.
|
|
709
|
+
*
|
|
710
|
+
* Meaningless under 'contain', which shows all of it — the editor offers it
|
|
711
|
+
* only where it bites. */
|
|
712
|
+
focusX: number;
|
|
713
|
+
focusY: number;
|
|
714
|
+
/** Card colour painted over the picture, 0-100. Only where words sit ON it. */
|
|
715
|
+
scrim: number;
|
|
716
|
+
/** How far the picture dissolves into the card at the seam, 0-100. A hard
|
|
717
|
+
* edge between a photograph and a block of text is the main thing that
|
|
718
|
+
* makes a split card look unfinished. */
|
|
719
|
+
fade: number;
|
|
720
|
+
}
|
|
721
|
+
export declare function imageDesign(display: {
|
|
722
|
+
imageLayout?: unknown;
|
|
723
|
+
imageSide?: unknown;
|
|
724
|
+
imageSplit?: unknown;
|
|
725
|
+
imageWidth?: unknown;
|
|
726
|
+
imageAlign?: unknown;
|
|
727
|
+
imageFit?: unknown;
|
|
728
|
+
imageScrim?: unknown;
|
|
729
|
+
imageFade?: unknown;
|
|
730
|
+
imageFocusX?: unknown;
|
|
731
|
+
imageFocusY?: unknown;
|
|
732
|
+
} | null | undefined, interactionType: unknown, hasImage: boolean): ImageDesign;
|
|
733
|
+
/** How much of the card colour is painted over the picture, 0-100.
|
|
734
|
+
*
|
|
735
|
+
* Only where the words sit ON the picture: behind the whole card, or across
|
|
736
|
+
* a half. The layouts that keep image and text in separate boxes need none. */
|
|
737
|
+
export declare function imageScrim(display: {
|
|
738
|
+
imageScrim?: unknown;
|
|
739
|
+
} | null | undefined): number;
|
|
403
740
|
/** Hover treatment for a clickable card. Pointer devices only. */
|
|
404
741
|
export declare function cardHoverEffect(display: {
|
|
405
742
|
hoverEffect?: unknown;
|
|
@@ -407,7 +744,11 @@ export declare function cardHoverEffect(display: {
|
|
|
407
744
|
export type ActionKind = 'url' | 'event' | 'webhook';
|
|
408
745
|
export interface RawAction {
|
|
409
746
|
type?: unknown;
|
|
747
|
+
/** The endpoint for a webhook, or the legacy destination for type 'url'. */
|
|
410
748
|
value?: unknown;
|
|
749
|
+
/** Where the press navigates, independent of kind — so an action can both
|
|
750
|
+
* take someone somewhere and report that it happened. */
|
|
751
|
+
href?: unknown;
|
|
411
752
|
/** For 'event': the name the host application listens for. */
|
|
412
753
|
eventName?: unknown;
|
|
413
754
|
/** Template payload — values may contain {{variable}} references. */
|
|
@@ -415,8 +756,12 @@ export interface RawAction {
|
|
|
415
756
|
}
|
|
416
757
|
export interface ResolvedAction {
|
|
417
758
|
kind: ActionKind;
|
|
418
|
-
/** Navigable target for 'url', endpoint for 'webhook'. Null when unusable.
|
|
759
|
+
/** Navigable target for 'url', endpoint for 'webhook'. Null when unusable.
|
|
760
|
+
* Unchanged in meaning — hosts read it — see `destination` below. */
|
|
419
761
|
href: string | null;
|
|
762
|
+
/** Where the press NAVIGATES, whatever the kind. Set only from action.href,
|
|
763
|
+
* so it is never confused with an endpoint. Null when there is none. */
|
|
764
|
+
destination: string | null;
|
|
420
765
|
eventName: string | null;
|
|
421
766
|
/** Payload with every {{reference}} substituted. */
|
|
422
767
|
payload: Record<string, string>;
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/validate.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.safeImageSrc = safeImageSrc;
|
|
|
10
10
|
exports.impliedStepActions = impliedStepActions;
|
|
11
11
|
exports.impliedEqualProminence = impliedEqualProminence;
|
|
12
12
|
exports.canSwipeToDismiss = canSwipeToDismiss;
|
|
13
|
+
exports.showsClose = showsClose;
|
|
13
14
|
exports.autoDismissMs = autoDismissMs;
|
|
14
15
|
exports.deadlineCountdown = deadlineCountdown;
|
|
15
16
|
exports.formatCountdown = formatCountdown;
|
|
@@ -17,8 +18,23 @@ exports.outcomeFor = outcomeFor;
|
|
|
17
18
|
exports.questionForValidation = questionForValidation;
|
|
18
19
|
exports.complianceGate = complianceGate;
|
|
19
20
|
exports.voiceUsable = voiceUsable;
|
|
21
|
+
exports.collectsAnswer = collectsAnswer;
|
|
22
|
+
exports.answerShape = answerShape;
|
|
23
|
+
exports.resolveBranding = resolveBranding;
|
|
24
|
+
exports.resolveThemeDecision = resolveThemeDecision;
|
|
25
|
+
exports.resolveTheme = resolveTheme;
|
|
26
|
+
exports.showsConfirmation = showsConfirmation;
|
|
27
|
+
exports.confirmationText = confirmationText;
|
|
20
28
|
exports.rewardToShow = rewardToShow;
|
|
29
|
+
exports.showsQuestionLabel = showsQuestionLabel;
|
|
30
|
+
exports.rewardTerms = rewardTerms;
|
|
21
31
|
exports.cardClickTarget = cardClickTarget;
|
|
32
|
+
exports.cardIsClickable = cardIsClickable;
|
|
33
|
+
exports.showActionButton = showActionButton;
|
|
34
|
+
exports.triggerVariables = triggerVariables;
|
|
35
|
+
exports.imageLayout = imageLayout;
|
|
36
|
+
exports.imageDesign = imageDesign;
|
|
37
|
+
exports.imageScrim = imageScrim;
|
|
22
38
|
exports.cardHoverEffect = cardHoverEffect;
|
|
23
39
|
exports.resolveAction = resolveAction;
|
|
24
40
|
const messages_1 = require("./messages");
|
|
@@ -414,9 +430,15 @@ interpolate = (s) => s) {
|
|
|
414
430
|
// Interpolated BEFORE the scheme check, never after: a template that
|
|
415
431
|
// resolves to `javascript:` has to be caught on what it BECAME, not on
|
|
416
432
|
// the harmless-looking string it started as.
|
|
417
|
-
const
|
|
418
|
-
? o.action
|
|
433
|
+
const act = (o.action && typeof o.action === 'object')
|
|
434
|
+
? o.action
|
|
419
435
|
: undefined;
|
|
436
|
+
// href first — see safeActionHref. Interpolated the same way, because a
|
|
437
|
+
// destination is a template wherever it is stored.
|
|
438
|
+
const rawHref = act
|
|
439
|
+
? (typeof act.href === 'string' && act.href ? act.href : act.value)
|
|
440
|
+
: undefined;
|
|
441
|
+
const viaHref = !!(act && typeof act.href === 'string' && act.href);
|
|
420
442
|
const resolved = typeof rawHref === 'string' && rawHref
|
|
421
443
|
? interpolate(rawHref)
|
|
422
444
|
: rawHref;
|
|
@@ -427,7 +449,9 @@ interpolate = (s) => s) {
|
|
|
427
449
|
const usable = typeof resolved === 'string' && /\{\{.*\}\}/.test(resolved)
|
|
428
450
|
? undefined
|
|
429
451
|
: resolved;
|
|
430
|
-
const href = safeActionHref(usable === undefined ? undefined
|
|
452
|
+
const href = safeActionHref(usable === undefined ? undefined
|
|
453
|
+
: viaHref ? { ...o.action, href: usable }
|
|
454
|
+
: { ...o.action, value: usable });
|
|
431
455
|
if (value !== '' || label !== '') {
|
|
432
456
|
const entry = href ? { value, label: label || value, href } : { value, label: label || value };
|
|
433
457
|
// "Remind me later" — see isDeferChoice. Carried through because a
|
|
@@ -485,9 +509,21 @@ function safeActionHref(action) {
|
|
|
485
509
|
if (!action || typeof action !== 'object')
|
|
486
510
|
return undefined;
|
|
487
511
|
const a = action;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
512
|
+
// A DESTINATION IS NOT A KIND OF ACTION, IT IS A PROPERTY OF ONE.
|
|
513
|
+
//
|
|
514
|
+
// Reading the destination out of `value` meant `value` had to be a URL, which
|
|
515
|
+
// meant type had to be 'url', which made "take them somewhere" and "report
|
|
516
|
+
// this press" mutually exclusive. They are not: a button on an abandoned-cart
|
|
517
|
+
// nudge that opens the cart AND tells your backend is the ordinary case, and
|
|
518
|
+
// an author asked why it had to be one or the other.
|
|
519
|
+
//
|
|
520
|
+
// `href` carries the destination on its own, whatever the action's kind. The
|
|
521
|
+
// legacy pair (type 'url' + value) still resolves, so nothing already
|
|
522
|
+
// authored changes.
|
|
523
|
+
const explicit = typeof a.href === 'string' ? a.href.trim() : '';
|
|
524
|
+
const legacy = String(a.type || '').toLowerCase() === 'url'
|
|
525
|
+
&& typeof a.value === 'string' ? a.value.trim() : '';
|
|
526
|
+
const v = explicit || legacy;
|
|
491
527
|
if (!v)
|
|
492
528
|
return undefined; // '' = not configured yet
|
|
493
529
|
// Reject anything whose scheme could execute in the host document.
|
|
@@ -627,6 +663,36 @@ function canSwipeToDismiss(display, delivery) {
|
|
|
627
663
|
return false; // fullscreen / modal never swipe
|
|
628
664
|
return display.showClose === false; // the gesture REPLACES the ✕
|
|
629
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* Is the ✕ drawn?
|
|
668
|
+
*
|
|
669
|
+
* TWO RENDERERS, TWO ANSWERS, from one authored survey. Web resolved an unset
|
|
670
|
+
* `showClose` to "hidden on a notification, shown everywhere else" — a
|
|
671
|
+
* deliberate rule, written down: a banner is swiped away, and canSwipeToDismiss
|
|
672
|
+
* turns the gesture on precisely when the ✕ is off. The phone read
|
|
673
|
+
* `showClose !== false`, so an unset notification kept its ✕ AND, because its
|
|
674
|
+
* display is a plain merge that leaves the value undefined, never enabled the
|
|
675
|
+
* swipe. The same notification was dismissable two different ways depending on
|
|
676
|
+
* which screen you were looking at, and a panel describing it could only be
|
|
677
|
+
* right about one of them.
|
|
678
|
+
*
|
|
679
|
+
* ONLY WHERE THE GESTURE REPLACES IT. Dropping the ✕ from a notification that
|
|
680
|
+
* cannot be swiped — a modal, a fullscreen takeover, a must-show — would leave
|
|
681
|
+
* no way out at all. That trap was already live on web, which hid the mark on
|
|
682
|
+
* every notification regardless of mode; asking canSwipeToDismiss here closes
|
|
683
|
+
* it on both.
|
|
684
|
+
*
|
|
685
|
+
* An explicit value always wins: '' / null / undefined mean "inherit", the same
|
|
686
|
+
* convention the rest of `display` uses.
|
|
687
|
+
*/
|
|
688
|
+
function showsClose(display, interactionType, delivery) {
|
|
689
|
+
const raw = display?.showClose;
|
|
690
|
+
if (raw !== undefined && raw !== null && raw !== '')
|
|
691
|
+
return raw !== false;
|
|
692
|
+
if (String(interactionType || '').toLowerCase() !== 'notify')
|
|
693
|
+
return true;
|
|
694
|
+
return !canSwipeToDismiss({ ...(display || {}), showClose: false }, delivery);
|
|
695
|
+
}
|
|
630
696
|
/**
|
|
631
697
|
* How long before this surface dismisses ITSELF, in ms. 0 = never.
|
|
632
698
|
*
|
|
@@ -882,6 +948,178 @@ function voiceUsable(questions) {
|
|
|
882
948
|
&& t !== 'image' && t !== 'expression' && t !== 'pagebreak';
|
|
883
949
|
});
|
|
884
950
|
}
|
|
951
|
+
/**
|
|
952
|
+
* Does this question record an answer?
|
|
953
|
+
*
|
|
954
|
+
* WHAT THE QUESTION LOCK IS ACTUALLY FOR. A survey that has started collecting
|
|
955
|
+
* refuses edits to `questions`, because responses are keyed by question id and
|
|
956
|
+
* a moved key orphans the data already gathered. That is a real rule — and it
|
|
957
|
+
* was applied to the WHOLE array, including questions that record nothing.
|
|
958
|
+
*
|
|
959
|
+
* A `content` block, a picture, a page break: none of them has an answer, so
|
|
960
|
+
* changing their words cannot orphan anything. Locking them made the offer's
|
|
961
|
+
* small print — the text most likely to need correcting on a running offer —
|
|
962
|
+
* uneditable for the same reason a rating scale is, which is not the same
|
|
963
|
+
* reason at all. The headline and the description sit right beside it and were
|
|
964
|
+
* never locked, because they are not in `questions`.
|
|
965
|
+
*
|
|
966
|
+
* NOT voiceUsable's list. That one also excludes `implied`, because a button
|
|
967
|
+
* cannot be spoken — but an implied question very much records an answer, and
|
|
968
|
+
* for this question it must count.
|
|
969
|
+
*/
|
|
970
|
+
const RECORDS_NOTHING = ['html', 'content', 'image', 'expression', 'pagebreak', 'page_break'];
|
|
971
|
+
function collectsAnswer(question) {
|
|
972
|
+
if (!question)
|
|
973
|
+
return false;
|
|
974
|
+
return RECORDS_NOTHING.indexOf(String(question.type || '').toLowerCase()) < 0;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* The part of a question set that responses are keyed by.
|
|
978
|
+
*
|
|
979
|
+
* Two sets with the same shape can be swapped without orphaning a single
|
|
980
|
+
* answer — which is the only thing the lock has to protect. Order is included
|
|
981
|
+
* because a reordered set changes nothing about the keys but IS how a
|
|
982
|
+
* different survey can be smuggled in with matching ids.
|
|
983
|
+
*/
|
|
984
|
+
function answerShape(questions) {
|
|
985
|
+
if (!Array.isArray(questions))
|
|
986
|
+
return '';
|
|
987
|
+
return questions
|
|
988
|
+
.filter((q) => collectsAnswer(q))
|
|
989
|
+
.map((q) => `${String(q?.id ?? q?.name ?? '')}:${String(q?.type ?? '').toLowerCase()}`)
|
|
990
|
+
.join('|');
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* THE BRANDING CASCADE: survey.branding ▶ applicationBranding ▶ built-in.
|
|
994
|
+
*
|
|
995
|
+
* A survey stores only what its author changed, so everything else has to
|
|
996
|
+
* resolve up to the application at render time. The web SDK learned this once
|
|
997
|
+
* already — it read `surveyData.branding` alone and an application palette
|
|
998
|
+
* stopped there — and the React Native SDK never learned it at all: it took
|
|
999
|
+
* `raw.branding` and nothing else, so an interaction with no palette of its own
|
|
1000
|
+
* drew the SDK's built-in lime on a phone no matter what the application said,
|
|
1001
|
+
* and an application-level button padding never arrived either.
|
|
1002
|
+
*
|
|
1003
|
+
* Reported as both, separately, which is what an unresolved layer looks like
|
|
1004
|
+
* from the outside: a list of unrelated settings that "do not apply on mobile".
|
|
1005
|
+
*
|
|
1006
|
+
* Nested groups merge per KEY, and `palette` one level deeper again because it
|
|
1007
|
+
* is keyed by theme — a survey overriding one surface must not drop the
|
|
1008
|
+
* application's others. '' / null / undefined mean INHERIT, the same convention
|
|
1009
|
+
* `display` uses.
|
|
1010
|
+
*/
|
|
1011
|
+
const BRANDING_GROUPS = ['palette', 'style', 'typography', 'layout'];
|
|
1012
|
+
function resolveBranding(survey) {
|
|
1013
|
+
const own = (survey?.branding || {});
|
|
1014
|
+
// A detached survey carries its own theme and stops inheriting entirely.
|
|
1015
|
+
if (survey?.settings?.themeDetached)
|
|
1016
|
+
return own;
|
|
1017
|
+
const app = (survey?.applicationBranding || {});
|
|
1018
|
+
const keep = (v) => v !== undefined && v !== null && v !== '';
|
|
1019
|
+
const out = { ...app };
|
|
1020
|
+
for (const [k, v] of Object.entries(own))
|
|
1021
|
+
if (keep(v))
|
|
1022
|
+
out[k] = v;
|
|
1023
|
+
// THEME IS THE ONE FIELD THAT DOES NOT MERGE, because it is the one field a
|
|
1024
|
+
// respondent has an opinion about. Every other branding key is the brand's
|
|
1025
|
+
// to decide — a colour, a radius, a font. Light-vs-dark is the reader's, and
|
|
1026
|
+
// an application-level value folded into `theme` here became indistinguish-
|
|
1027
|
+
// able from an author pinning this one card, so it outranked the respondent's
|
|
1028
|
+
// own device on every surface. It is carried separately instead, and the
|
|
1029
|
+
// renderers place it where a default belongs: under everything the SDK can
|
|
1030
|
+
// tell us about the person, over nothing but the built-in. Exactly the
|
|
1031
|
+
// standing `defaultLanguage` has always had, which is why language was right
|
|
1032
|
+
// and theme was wrong.
|
|
1033
|
+
if (keep(app.theme))
|
|
1034
|
+
out.themeDefault = app.theme;
|
|
1035
|
+
if (!keep(own.theme))
|
|
1036
|
+
delete out.theme;
|
|
1037
|
+
for (const g of BRANDING_GROUPS) {
|
|
1038
|
+
const a = app[g];
|
|
1039
|
+
const o = own[g];
|
|
1040
|
+
if (!a || !o || typeof a !== 'object' || typeof o !== 'object')
|
|
1041
|
+
continue;
|
|
1042
|
+
const merged = { ...a };
|
|
1043
|
+
for (const [kk, ov] of Object.entries(o)) {
|
|
1044
|
+
const av = merged[kk];
|
|
1045
|
+
if (av && ov && typeof av === 'object' && typeof ov === 'object'
|
|
1046
|
+
&& !Array.isArray(av) && !Array.isArray(ov)) {
|
|
1047
|
+
const deep = { ...av };
|
|
1048
|
+
for (const [k3, v3] of Object.entries(ov)) {
|
|
1049
|
+
if (keep(v3))
|
|
1050
|
+
deep[k3] = v3;
|
|
1051
|
+
}
|
|
1052
|
+
merged[kk] = deep;
|
|
1053
|
+
}
|
|
1054
|
+
else if (keep(ov)) {
|
|
1055
|
+
merged[kk] = ov;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
out[g] = merged;
|
|
1059
|
+
}
|
|
1060
|
+
return out;
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* The same decision, with WHICH CANDIDATE WON attached.
|
|
1064
|
+
*
|
|
1065
|
+
* Diagnostics, and worth having: the question "why is this card light?" was
|
|
1066
|
+
* asked four times across two renderers and answered wrongly twice, because
|
|
1067
|
+
* from the outside every tier produces the same two words. A host running in
|
|
1068
|
+
* debug can now read the reason instead of inferring it from a screenshot.
|
|
1069
|
+
*/
|
|
1070
|
+
function resolveThemeDecision(input) {
|
|
1071
|
+
const pick = (v) => {
|
|
1072
|
+
const t = typeof v === 'string' ? v.toLowerCase() : '';
|
|
1073
|
+
return t === 'light' || t === 'dark' ? t : undefined; // 'auto' steps aside
|
|
1074
|
+
};
|
|
1075
|
+
const order = ['pinned', 'user', 'declared', 'appDefault', 'device'];
|
|
1076
|
+
for (const from of order) {
|
|
1077
|
+
const theme = pick(input?.[from]);
|
|
1078
|
+
if (theme)
|
|
1079
|
+
return { theme, from };
|
|
1080
|
+
}
|
|
1081
|
+
return { theme: 'dark', from: 'fallback' };
|
|
1082
|
+
}
|
|
1083
|
+
function resolveTheme(input) {
|
|
1084
|
+
return resolveThemeDecision(input).theme;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* DOES THE CARD SHOW A CONFIRMATION AFTER IT IS ACCEPTED?
|
|
1088
|
+
*
|
|
1089
|
+
* An offer's ending is hardcoded: "It's yours", "Use this at checkout." Two
|
|
1090
|
+
* more sentences about somebody else's business, written by us, in a screen an
|
|
1091
|
+
* author could neither reword nor turn off — the same shape as the small print
|
|
1092
|
+
* that shipped inside a template.
|
|
1093
|
+
*
|
|
1094
|
+
* Off is a real answer: an offer whose reward is applied by the host app, or
|
|
1095
|
+
* one that navigates somewhere it is already applied, has nothing to confirm —
|
|
1096
|
+
* the card dwelling on a thank-you is a step between the customer and the thing
|
|
1097
|
+
* they just asked for.
|
|
1098
|
+
*
|
|
1099
|
+
* WITH ONE REFUSAL. A code is handed over ON that screen and nowhere else, so
|
|
1100
|
+
* hiding it would take the discount away at the moment of giving it. That is
|
|
1101
|
+
* not a preference, so it is not offered as one: the flag is ignored and the
|
|
1102
|
+
* screen shows.
|
|
1103
|
+
*/
|
|
1104
|
+
function showsConfirmation(survey) {
|
|
1105
|
+
if (survey?.settings?.showConfirmation !== false)
|
|
1106
|
+
return true;
|
|
1107
|
+
// The only thing the customer cannot get any other way.
|
|
1108
|
+
const r = survey?.reward;
|
|
1109
|
+
const isCode = String(r?.type || '') === 'code' && !!String(r?.value ?? '').trim();
|
|
1110
|
+
return isCode;
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* The words on that screen, the author's where they wrote any.
|
|
1114
|
+
*
|
|
1115
|
+
* `thankYouMessage` is the field every other interaction already uses for
|
|
1116
|
+
* this, so an offer reaching for a second one would be a second place to look.
|
|
1117
|
+
*/
|
|
1118
|
+
function confirmationText(survey, fallback) {
|
|
1119
|
+
const own = String(survey?.thankYouMessage ?? '')
|
|
1120
|
+
.replace(/<[^>]*>/g, '').replace(/ /gi, ' ').trim();
|
|
1121
|
+
return own || fallback;
|
|
1122
|
+
}
|
|
885
1123
|
/** The reward, ready to show — or null when there is nothing to hand over. */
|
|
886
1124
|
function rewardToShow(survey) {
|
|
887
1125
|
const r = survey?.reward;
|
|
@@ -904,6 +1142,82 @@ function rewardToShow(survey) {
|
|
|
904
1142
|
expiresAt: survey?.endDate ? new Date(String(survey.endDate)).toISOString() : null,
|
|
905
1143
|
};
|
|
906
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Does this question draw a label above itself?
|
|
1147
|
+
*
|
|
1148
|
+
* Every renderer emitted one unconditionally, so a question whose whole
|
|
1149
|
+
* content IS its content — a picture, a block of copy — drew an EMPTY label
|
|
1150
|
+
* and its margin above itself. The way round that was to compose such things
|
|
1151
|
+
* outside the question flow, which puts things on a card that the survey
|
|
1152
|
+
* schema does not describe.
|
|
1153
|
+
*
|
|
1154
|
+
* `hideLabel` is a declared question option now, and this is the one rule all
|
|
1155
|
+
* three renderers ask:
|
|
1156
|
+
*
|
|
1157
|
+
* hideLabel === true → never, even with text
|
|
1158
|
+
* hideLabel === false → always, even empty (an author who wants the space)
|
|
1159
|
+
* unset → only if there is something to say
|
|
1160
|
+
*/
|
|
1161
|
+
function showsQuestionLabel(question) {
|
|
1162
|
+
if (!question)
|
|
1163
|
+
return false;
|
|
1164
|
+
// AN IMPLIED QUESTION NEVER SHOWS ONE, whatever it carries.
|
|
1165
|
+
//
|
|
1166
|
+
// Its `text` — "Offer accepted?" — is the analytics prompt, what the recorded
|
|
1167
|
+
// answer MEANS, not copy for the customer. Its choices are the buttons. Both
|
|
1168
|
+
// renderers had that as a special case beside this one, which is precisely
|
|
1169
|
+
// how a rule ends up applied in one place and not the other: the first thing
|
|
1170
|
+
// that happened when the phone started asking this function instead was the
|
|
1171
|
+
// stray authoring text coming back.
|
|
1172
|
+
if (String(question.type || '').toLowerCase() === 'implied')
|
|
1173
|
+
return false;
|
|
1174
|
+
if (question.hideLabel === true)
|
|
1175
|
+
return false;
|
|
1176
|
+
if (question.hideLabel === false)
|
|
1177
|
+
return true;
|
|
1178
|
+
const text = question.title ?? question.text ?? question.label ?? '';
|
|
1179
|
+
return String(text).trim().length > 0;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* THE SMALL PRINT ON AN OFFER — the author's words, not ours.
|
|
1183
|
+
*
|
|
1184
|
+
* "Valid on your first order only. Cannot be combined with other offers."
|
|
1185
|
+
* shipped as a `content` question in the first-purchase template, which made it
|
|
1186
|
+
* three separate problems:
|
|
1187
|
+
*
|
|
1188
|
+
* • It is a claim about somebody else's business, stated by us.
|
|
1189
|
+
* • A `content` question lives in `questions`, which is SCHEMA — so the one
|
|
1190
|
+
* kind of text most likely to need correcting could not be corrected on a
|
|
1191
|
+
* LIVE offer, which is the only time correcting it matters.
|
|
1192
|
+
* • The template translated its title, description and choices into Arabic
|
|
1193
|
+
* and not this, so an Arabic offer carried English legal text.
|
|
1194
|
+
*
|
|
1195
|
+
* It belongs to the reward, beside what the customer gets and where it is
|
|
1196
|
+
* valid. Empty means no small print, which is the right default: an offer with
|
|
1197
|
+
* no conditions should not be made to invent some.
|
|
1198
|
+
*
|
|
1199
|
+
* FALLS BACK TO THE LEGACY QUESTION so offers created before this keep showing
|
|
1200
|
+
* what they already show. Tags are stripped rather than rendered — the text is
|
|
1201
|
+
* drawn as text by all three renderers, and `<small>` was only ever standing in
|
|
1202
|
+
* for the styling the card now does itself.
|
|
1203
|
+
*/
|
|
1204
|
+
function rewardTerms(survey) {
|
|
1205
|
+
const own = survey?.reward?.terms;
|
|
1206
|
+
if (own != null && String(own).trim())
|
|
1207
|
+
return String(own).trim();
|
|
1208
|
+
const qs = Array.isArray(survey?.questions) ? survey.questions : [];
|
|
1209
|
+
for (const q of qs) {
|
|
1210
|
+
if (String(q?.id || '') !== 'offer_terms')
|
|
1211
|
+
continue;
|
|
1212
|
+
if (String(q?.type || '').toLowerCase() !== 'content')
|
|
1213
|
+
continue;
|
|
1214
|
+
const raw = String(q?.html ?? q?.text ?? '');
|
|
1215
|
+
const text = raw.replace(/<[^>]*>/g, '').replace(/ /gi, ' ').trim();
|
|
1216
|
+
if (text)
|
|
1217
|
+
return text;
|
|
1218
|
+
}
|
|
1219
|
+
return '';
|
|
1220
|
+
}
|
|
907
1221
|
/**
|
|
908
1222
|
* Where clicking the CARD ITSELF should take someone, or null.
|
|
909
1223
|
*
|
|
@@ -928,6 +1242,160 @@ function cardClickTarget(display, actions) {
|
|
|
928
1242
|
const own = safeActionHref({ type: 'url', value: display?.cardHref });
|
|
929
1243
|
return own || acts[0].href || null;
|
|
930
1244
|
}
|
|
1245
|
+
/**
|
|
1246
|
+
* May the whole card be pressed?
|
|
1247
|
+
*
|
|
1248
|
+
* SEPARATE FROM WHERE IT GOES, and that separation is the fix. cardClickTarget
|
|
1249
|
+
* answers "what destination does the card carry", and returns null when there
|
|
1250
|
+
* is none — but a notification whose action is "tell your app" or "call an
|
|
1251
|
+
* endpoint" has no destination and is still entirely pressable: pressing it
|
|
1252
|
+
* records the answer and runs the action, which is the whole point of those
|
|
1253
|
+
* two kinds.
|
|
1254
|
+
*
|
|
1255
|
+
* Reading the target as the permission meant that on any non-URL action the
|
|
1256
|
+
* card lost its pointer cursor, its hover treatment and its click handler at
|
|
1257
|
+
* once — so "What the card does under the cursor" did nothing, with no clue
|
|
1258
|
+
* why.
|
|
1259
|
+
*
|
|
1260
|
+
* The safety argument is unchanged and lives here: exactly ONE action. That is
|
|
1261
|
+
* the notification shape, and it excludes every consent choice — on a
|
|
1262
|
+
* two-action compliance takeover a stray click anywhere would otherwise record
|
|
1263
|
+
* agreement, which a consent record must never manufacture.
|
|
1264
|
+
*/
|
|
1265
|
+
function cardIsClickable(display, actions) {
|
|
1266
|
+
const acts = Array.isArray(actions) ? actions : [];
|
|
1267
|
+
if (acts.length !== 1)
|
|
1268
|
+
return false;
|
|
1269
|
+
// OPT IN, NOT OPT OUT.
|
|
1270
|
+
//
|
|
1271
|
+
// This read `!== false`, so a card with one action was pressable anywhere on
|
|
1272
|
+
// its surface unless someone had turned that off. A whole card that navigates
|
|
1273
|
+
// is a real behaviour to choose, not a default to discover: on a notification
|
|
1274
|
+
// it means the message and the dismissal target overlap, and the author who
|
|
1275
|
+
// never opened this panel never agreed to it.
|
|
1276
|
+
//
|
|
1277
|
+
// The guard above still holds either way — two actions are never
|
|
1278
|
+
// card-clickable, because a card that silently picks one of two answers is
|
|
1279
|
+
// the thing consent must never do.
|
|
1280
|
+
return display?.cardClickable === true;
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Is the action BUTTON drawn?
|
|
1284
|
+
*
|
|
1285
|
+
* A card whose whole surface is the action does not always need a button
|
|
1286
|
+
* repeating it — "Resume" written twice on a banner two lines tall is the
|
|
1287
|
+
* button competing with the card for the same press. So an author may hide it
|
|
1288
|
+
* and let the card carry the action alone.
|
|
1289
|
+
*
|
|
1290
|
+
* ONLY WHEN THE CARD CAN ACTUALLY TAKE THE PRESS. Hiding the button on a card
|
|
1291
|
+
* that is not clickable leaves a surface with something to say and no way to
|
|
1292
|
+
* say yes to it — the respondent's only exit is the dismissal, which records
|
|
1293
|
+
* the opposite of what the author was asking for. So the hide is honoured
|
|
1294
|
+
* strictly when cardIsClickable agrees, and ignored otherwise.
|
|
1295
|
+
*
|
|
1296
|
+
* That also inherits the one-action guard: a two-action consent takeover can
|
|
1297
|
+
* never hide its buttons, because a card that silently picks one of two
|
|
1298
|
+
* answers is the thing consent must never do.
|
|
1299
|
+
*/
|
|
1300
|
+
function showActionButton(display, actions) {
|
|
1301
|
+
if (display?.showAction !== false)
|
|
1302
|
+
return true; // shown unless hidden
|
|
1303
|
+
return !cardIsClickable(display, actions); // hide only if the card takes it
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* The variables a response carries about what made the interaction appear.
|
|
1307
|
+
*
|
|
1308
|
+
* `eventData` is spread FIRST so a caller's own values (URL params, identify()
|
|
1309
|
+
* traits) still win when merged on top — the triggering event describes the
|
|
1310
|
+
* occasion, not the respondent.
|
|
1311
|
+
*/
|
|
1312
|
+
function triggerVariables(tc) {
|
|
1313
|
+
const out = {};
|
|
1314
|
+
if (!tc || typeof tc !== 'object')
|
|
1315
|
+
return out;
|
|
1316
|
+
const data = tc.eventData;
|
|
1317
|
+
if (data && typeof data === 'object') {
|
|
1318
|
+
for (const [k, v] of Object.entries(data)) {
|
|
1319
|
+
if (v != null && v !== '')
|
|
1320
|
+
out[k] = v;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
// Underscore-prefixed so they cannot collide with an author's own event
|
|
1324
|
+
// field — `eventName` is a plausible thing to put in eventData.
|
|
1325
|
+
if (tc.definitionId)
|
|
1326
|
+
out._triggerDefinition = String(tc.definitionId);
|
|
1327
|
+
if (tc.eventName)
|
|
1328
|
+
out._triggerEvent = String(tc.eventName);
|
|
1329
|
+
if (tc.pathname)
|
|
1330
|
+
out._triggerPath = String(tc.pathname);
|
|
1331
|
+
return out;
|
|
1332
|
+
}
|
|
1333
|
+
const IMAGE_LAYOUTS = ['beside', 'above', 'below', 'background', 'half'];
|
|
1334
|
+
/** Which interactions compose their own picture. Everything else leaves the
|
|
1335
|
+
* `image` question where it is. */
|
|
1336
|
+
const COMPOSES_IMAGE = ['notify', 'offer'];
|
|
1337
|
+
function imageLayout(display, interactionType, hasImage) {
|
|
1338
|
+
if (!hasImage)
|
|
1339
|
+
return 'none';
|
|
1340
|
+
const kind = String(interactionType || '').toLowerCase();
|
|
1341
|
+
if (COMPOSES_IMAGE.indexOf(kind) < 0)
|
|
1342
|
+
return 'none';
|
|
1343
|
+
const raw = String(display?.imageLayout || '').toLowerCase();
|
|
1344
|
+
if (IMAGE_LAYOUTS.indexOf(raw) >= 0)
|
|
1345
|
+
return raw;
|
|
1346
|
+
// UNSET IS THE SHAPE EACH ONE ALREADY HAD. A notification has always drawn
|
|
1347
|
+
// the square beside its text, and changing that under every existing
|
|
1348
|
+
// notification would be a redesign nobody asked for. An offer has no
|
|
1349
|
+
// incumbent layout to preserve and the picture is the offer, so it leads.
|
|
1350
|
+
return kind === 'notify' ? 'beside' : 'above';
|
|
1351
|
+
}
|
|
1352
|
+
const SIDES = ['left', 'right', 'top'];
|
|
1353
|
+
const ALIGNS = ['start', 'center', 'end'];
|
|
1354
|
+
/** Clamped to a range with a stated default — never NaN, never out of bounds. */
|
|
1355
|
+
function pct(v, dflt, lo = 0, hi = 100) {
|
|
1356
|
+
const n = Number(v);
|
|
1357
|
+
if (!isFinite(n))
|
|
1358
|
+
return dflt;
|
|
1359
|
+
return Math.max(lo, Math.min(hi, Math.round(n)));
|
|
1360
|
+
}
|
|
1361
|
+
function imageDesign(display, interactionType, hasImage) {
|
|
1362
|
+
const layout = imageLayout(display, interactionType, hasImage);
|
|
1363
|
+
const rawSide = String(display?.imageSide || '').toLowerCase();
|
|
1364
|
+
const rawAlign = String(display?.imageAlign || '').toLowerCase();
|
|
1365
|
+
return {
|
|
1366
|
+
layout,
|
|
1367
|
+
side: (SIDES.indexOf(rawSide) >= 0 ? rawSide : 'left'),
|
|
1368
|
+
// 20-80 rather than 0-100: a 5% sliver is not a half, and a 95% one leaves
|
|
1369
|
+
// the words a gutter. A control should refuse what the layout cannot be.
|
|
1370
|
+
split: pct(display?.imageSplit, 50, 20, 80),
|
|
1371
|
+
width: pct(display?.imageWidth, 100, 20, 100),
|
|
1372
|
+
// Centre is right for a band and wrong for a square beside text, which
|
|
1373
|
+
// should sit level with the headline it belongs to.
|
|
1374
|
+
align: (ALIGNS.indexOf(rawAlign) >= 0 ? rawAlign
|
|
1375
|
+
: (layout === 'beside' ? 'start' : 'center')),
|
|
1376
|
+
fit: String(display?.imageFit || '').toLowerCase() === 'contain' ? 'contain' : 'cover',
|
|
1377
|
+
focusX: pct(display?.imageFocusX, 50),
|
|
1378
|
+
focusY: pct(display?.imageFocusY, 50),
|
|
1379
|
+
// 40 BEHIND THE CARD, 0 EVERYWHERE ELSE.
|
|
1380
|
+
//
|
|
1381
|
+
// The scrim exists because words sit ON the picture, which is true by
|
|
1382
|
+
// construction of a backdrop and not of a half — there the text has its own
|
|
1383
|
+
// side. Carrying the backdrop's default across would have dimmed every
|
|
1384
|
+
// split image by 40% that nobody asked to dim.
|
|
1385
|
+
scrim: layout === 'background' ? imageScrim(display) : pct(display?.imageScrim, 0),
|
|
1386
|
+
fade: pct(display?.imageFade, 0),
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
/** How much of the card colour is painted over the picture, 0-100.
|
|
1390
|
+
*
|
|
1391
|
+
* Only where the words sit ON the picture: behind the whole card, or across
|
|
1392
|
+
* a half. The layouts that keep image and text in separate boxes need none. */
|
|
1393
|
+
function imageScrim(display) {
|
|
1394
|
+
const n = Number(display?.imageScrim);
|
|
1395
|
+
if (!isFinite(n))
|
|
1396
|
+
return 40;
|
|
1397
|
+
return Math.max(0, Math.min(100, Math.round(n)));
|
|
1398
|
+
}
|
|
931
1399
|
/** Hover treatment for a clickable card. Pointer devices only. */
|
|
932
1400
|
function cardHoverEffect(display) {
|
|
933
1401
|
const v = String(display?.hoverEffect || '').toLowerCase();
|
|
@@ -954,6 +1422,19 @@ function resolveAction(action, interpolate = (s) => s) {
|
|
|
954
1422
|
const template = typeof action.value === 'string' ? action.value : '';
|
|
955
1423
|
const substituted = template ? interpolate(template) : '';
|
|
956
1424
|
const href = substituted ? safeActionHref({ type: 'url', value: substituted }) || null : null;
|
|
1425
|
+
// WHERE THE PRESS NAVIGATES, kept separate from `href` on purpose.
|
|
1426
|
+
//
|
|
1427
|
+
// `href` has always meant two different things depending on kind — the
|
|
1428
|
+
// destination for a 'url' action, the endpoint to call for a 'webhook' one —
|
|
1429
|
+
// and hosts read it that way, so it is left exactly as it was. Now that one
|
|
1430
|
+
// action can BOTH navigate and report, the navigation target needs a name of
|
|
1431
|
+
// its own: without it, a button with an endpoint in `value` and a destination
|
|
1432
|
+
// in `href` would send the customer to the customer's own backend.
|
|
1433
|
+
const destTemplate = typeof action.href === 'string' ? action.href : '';
|
|
1434
|
+
const destSubstituted = destTemplate ? interpolate(destTemplate) : '';
|
|
1435
|
+
const destination = destSubstituted
|
|
1436
|
+
? safeActionHref({ href: destSubstituted }) || null
|
|
1437
|
+
: null;
|
|
957
1438
|
const payload = {};
|
|
958
1439
|
const p = action.payload;
|
|
959
1440
|
if (p && typeof p === 'object' && !Array.isArray(p)) {
|
|
@@ -981,7 +1462,7 @@ function resolveAction(action, interpolate = (s) => s) {
|
|
|
981
1462
|
const eventName = typeof action.eventName === 'string' && action.eventName.trim()
|
|
982
1463
|
? action.eventName.trim() : null;
|
|
983
1464
|
// Nothing to do: no destination, no event name, no payload.
|
|
984
|
-
if (!href && !eventName && Object.keys(payload).length === 0)
|
|
1465
|
+
if (!href && !destination && !eventName && Object.keys(payload).length === 0)
|
|
985
1466
|
return null;
|
|
986
|
-
return { kind, href, eventName, payload };
|
|
1467
|
+
return { kind, href, destination, eventName, payload };
|
|
987
1468
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cxpinsight/survey-spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The survey specification the renderers share — expression evaluation first. Source of truth for behaviour that must be identical on web, links and mobile.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|