@sapia-ai/chatbot-v3 1.1.1 → 1.3.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/{EmbeddedVideoPlayer-COUZHpPa.js → EmbeddedVideoPlayer-DTzRqNcQ.js} +176 -186
- package/dist/{Preview-wPnYtccF.js → Preview-Dd7KyhMk.js} +3 -3
- package/dist/api/client.d.ts +10 -6
- package/dist/api/places.d.ts +33 -0
- package/dist/api/types/messages.d.ts +35 -4
- package/dist/api/types/responses.d.ts +20 -17
- package/dist/api.js +2 -2
- package/dist/core/bubbles/cards.d.ts +14 -0
- package/dist/core/bubbles/convert.d.ts +24 -2
- package/dist/core/bubbles/counters.d.ts +10 -0
- package/dist/core/bubbles/types.d.ts +21 -1
- package/dist/core/constants.d.ts +31 -0
- package/dist/core/events.d.ts +7 -0
- package/dist/core/internalUser.d.ts +13 -0
- package/dist/core/interview.d.ts +26 -9
- package/dist/core/persistence.d.ts +3 -0
- package/dist/core/redirect.d.ts +2 -0
- package/dist/core/store.d.ts +22 -9
- package/dist/core/validation/wordCount.d.ts +1 -0
- package/dist/{dist-Bwlks_W8.js → dist-waE-4cub.js} +3 -3
- package/dist/embed/compat.d.ts +1 -1
- package/dist/embed/createChatbot.d.ts +6 -0
- package/dist/{fix-webm-duration-QAy9T6AR.js → fix-webm-duration-IniZA6tF.js} +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6218 -5384
- package/dist/{jsx-runtime-24G8w2Bf.js → jsx-runtime-DN_m6Qdv.js} +2 -2
- package/dist/{messages-DCvBcspv.js → messages-C00e82NS.js} +44 -37
- package/dist/places-CT6PNW7B.js +52 -0
- package/dist/react/AnswerInput.d.ts +16 -5
- package/dist/react/SapiaChatbot.d.ts +7 -1
- package/dist/react/bubbleViewModel.d.ts +38 -11
- package/dist/react/strings.d.ts +46 -10
- package/dist/react/usePlacesSuggestions.d.ts +16 -0
- package/dist/{react-Bw5AugJc.js → react-A0_ZwPyM.js} +3 -3
- package/dist/{react-DEF8h8hc.js → react-BDGt_WsZ.js} +3 -3
- package/dist/{react-DDjfkpOE.js → react-B_YNH2g9.js} +3 -3
- package/dist/{react-D8hV9uow.js → react-ByP48xLV.js} +3 -3
- package/dist/{react-DPFikgTM.js → react-C9oBRlX8.js} +3 -3
- package/dist/{react-qa12DkXH.js → react-D5yWOfXN.js} +3 -3
- package/dist/{react-DOgLiyZi.js → react-DkQKleWD.js} +2 -2
- package/dist/{react-y4vaW3OH.js → react-d-THpGrV.js} +3 -3
- package/dist/{react-BjO903pN.js → react-euSb4sIX.js} +3 -3
- package/dist/ui/chat/ActionDock/ActionDock.d.ts +15 -0
- package/dist/ui/chat/ChatBubble/ChatBubble.d.ts +10 -3
- package/dist/ui/chat/ChatLog/ChatLog.d.ts +9 -4
- package/dist/ui/chat/EditBanner/EditBanner.d.ts +9 -3
- package/dist/ui/chat/HintDisclosure/HintDisclosure.d.ts +20 -0
- package/dist/ui/chat/SummaryCard/SummaryCard.d.ts +18 -23
- package/dist/ui/chat/types.d.ts +18 -2
- package/dist/ui/constants.d.ts +5 -0
- package/dist/ui/hooks/usePreventPaste.d.ts +17 -0
- package/dist/ui/inputs/LocationAnswerInput/LocationAnswerInput.d.ts +34 -0
- package/dist/ui/inputs/PhoneAnswerInput/PhoneAnswerInput.d.ts +5 -2
- package/dist/ui/inputs/SliderInput/SliderInput.d.ts +1 -2
- package/dist/ui/inputs/TextAnswerInput/TextAnswerInput.d.ts +38 -11
- package/dist/ui/media/EmbeddedVideo/EmbeddedVideoPlayer.d.ts +1 -1
- package/dist/ui/primitives/MarkdownText/MarkdownText.d.ts +24 -0
- package/dist/ui/shell/CohortClosedScreen/CohortClosedScreen.d.ts +9 -0
- package/dist/ui/shell/CopyLinkButton/CopyLinkButton.d.ts +10 -3
- package/dist/ui/shell/DoneScreen/DoneScreen.d.ts +4 -1
- package/dist/ui/shell/Header/AutoScrollTitle.d.ts +15 -0
- package/dist/ui/shell/Header/Header.d.ts +12 -0
- package/dist/ui/shell/Header/useAutoScrollTitle.d.ts +16 -0
- package/dist/ui/shell/TerminalMessageScreen/TerminalMessageScreen.d.ts +10 -0
- package/dist/ui/shell/WidgetRoot/themeVariables.d.ts +8 -0
- package/dist-umd/sapia-chatbot.umd.js +309 -309
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ReactNode, Ref } from 'react';
|
|
2
|
-
import { ChatLogItem } from '../types';
|
|
2
|
+
import { ChatCardKind, ChatLogItem } from '../types';
|
|
3
3
|
export type SliderLabels = {
|
|
4
|
+
/** Accessible name for the range input — the backend's question is the visible prompt. */
|
|
4
5
|
label: string;
|
|
5
|
-
hint: string;
|
|
6
6
|
submitLabel: string;
|
|
7
7
|
};
|
|
8
8
|
export type DropdownLabels = {
|
|
@@ -47,10 +47,17 @@ export type ChatBubbleProps = {
|
|
|
47
47
|
rootRef?: Ref<HTMLLIElement>;
|
|
48
48
|
/** Rendered inside the question card body (e.g. the video recorder). */
|
|
49
49
|
footer?: ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Replaces the quiet editing marker on the bubble under edit (the edit banner, for an
|
|
52
|
+
* option question that opens no composer for a docked one to sit above).
|
|
53
|
+
*/
|
|
54
|
+
editingFooter?: ReactNode;
|
|
55
|
+
/** Draws one card the item names; the react glue owns each card's copy and data. */
|
|
56
|
+
renderCard?: (kind: ChatCardKind) => ReactNode;
|
|
50
57
|
};
|
|
51
58
|
/**
|
|
52
59
|
* Memoized: the transcript re-renders on every store write (roughly 60/s while an agent message
|
|
53
60
|
* streams in), and each render re-parses every settled paragraph's markdown from scratch. Default
|
|
54
61
|
* shallow comparison suffices — ChatLog is passed stable item and label references.
|
|
55
62
|
*/
|
|
56
|
-
export declare const ChatBubble: import('react').MemoExoticComponent<({ item, labels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onRetryVideo, onResolveVideoUrl, rootRef, footer, }: ChatBubbleProps) => import("react").JSX.Element>;
|
|
63
|
+
export declare const ChatBubble: import('react').MemoExoticComponent<({ item, labels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onRetryVideo, onResolveVideoUrl, rootRef, footer, editingFooter, renderCard, }: ChatBubbleProps) => import("react").JSX.Element>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { ChatBubbleLabels, DropdownLabels, MediaLabels, SliderLabels } from '../ChatBubble/ChatBubble';
|
|
3
|
-
import {
|
|
3
|
+
import { HintDisclosureLabels } from '../HintDisclosure/HintDisclosure';
|
|
4
|
+
import { ChatCardKind, ChatLogItem } from '../types';
|
|
4
5
|
export type ChatLogProps = {
|
|
5
6
|
items: ChatLogItem[];
|
|
6
7
|
typing: boolean;
|
|
@@ -11,6 +12,8 @@ export type ChatLogProps = {
|
|
|
11
12
|
/** Phase-2 loading phrase (and the only one on the first agent turn). */
|
|
12
13
|
typingThinkingLabel: string;
|
|
13
14
|
bubbleLabels: ChatBubbleLabels;
|
|
15
|
+
/** Copy for the collapse/expand toggle on a folded hint run. */
|
|
16
|
+
hintLabels: HintDisclosureLabels;
|
|
14
17
|
sliderLabels: SliderLabels;
|
|
15
18
|
dropdownLabels: DropdownLabels;
|
|
16
19
|
mediaLabels: MediaLabels;
|
|
@@ -24,12 +27,14 @@ export type ChatLogProps = {
|
|
|
24
27
|
cardFooter?: ReactNode;
|
|
25
28
|
/** Bubble id whose card receives cardFooter. */
|
|
26
29
|
cardFooterItemId?: string;
|
|
27
|
-
/** Node
|
|
28
|
-
|
|
30
|
+
/** Node rendered under the bubble being re-edited, in place of its quiet editing marker. */
|
|
31
|
+
editingFooter?: ReactNode;
|
|
32
|
+
/** Draws one card an item names (the summary, the resume link); passed through to ChatBubble. */
|
|
33
|
+
renderCard?: (kind: ChatCardKind) => ReactNode;
|
|
29
34
|
};
|
|
30
35
|
/**
|
|
31
36
|
* Scrollable interview transcript. The log auto-scrolls to the newest message; settled turns
|
|
32
37
|
* are announced once through a separate visually-hidden live region (the transcript itself is
|
|
33
38
|
* deliberately not one — see the announcer effect below).
|
|
34
39
|
*/
|
|
35
|
-
export declare const ChatLog: ({ items, typing, typingLabel, typingReadingLabel, typingThinkingLabel, bubbleLabels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onRetryVideo, onResolveVideoUrl, cardFooter, cardFooterItemId,
|
|
40
|
+
export declare const ChatLog: ({ items, typing, typingLabel, typingReadingLabel, typingThinkingLabel, bubbleLabels, hintLabels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onRetryVideo, onResolveVideoUrl, cardFooter, cardFooterItemId, editingFooter, renderCard, }: ChatLogProps) => import("react").JSX.Element;
|
|
@@ -6,11 +6,17 @@ export type EditBannerProps = {
|
|
|
6
6
|
/** Cancel copy, server-supplied ("Press ESC or click here to cancel editing"). */
|
|
7
7
|
cancelLabel: string;
|
|
8
8
|
onCancel: () => void;
|
|
9
|
+
/**
|
|
10
|
+
* Drops the docking chrome so the strip can sit in the transcript instead. An option
|
|
11
|
+
* question opens no composer, so a docked strip would strand the cancel control at the
|
|
12
|
+
* bottom of the widget while the options it belongs to sit further up the log.
|
|
13
|
+
*/
|
|
14
|
+
inline?: boolean;
|
|
9
15
|
};
|
|
10
16
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
17
|
+
* Strip naming the answer under edit and offering the single cancel control. Docked, it
|
|
18
|
+
* repeats the composer's own column classes so it lines up with the input box at any
|
|
13
19
|
* container width. role="status" so entering edit mode is announced; the Escape
|
|
14
20
|
* shortcut it advertises is bound in react/SapiaChatbot.
|
|
15
21
|
*/
|
|
16
|
-
export declare const EditBanner: ({ label, questionLabel, cancelLabel, onCancel }: EditBannerProps) => import("react").JSX.Element;
|
|
22
|
+
export declare const EditBanner: ({ label, questionLabel, cancelLabel, onCancel, inline, }: EditBannerProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type HintDisclosureLabels = {
|
|
3
|
+
/** Opens the folded hints, e.g. "Read the full brief". */
|
|
4
|
+
expand: string;
|
|
5
|
+
/** Closes them again, e.g. "Show less". */
|
|
6
|
+
collapse: string;
|
|
7
|
+
};
|
|
8
|
+
export type HintDisclosureProps = {
|
|
9
|
+
/** The foldable hint bubbles — each renders its own <li>. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
labels: HintDisclosureLabels;
|
|
12
|
+
/** Open state, owned by ChatLog: the bubble above needs it too, for the trailing ellipsis. */
|
|
13
|
+
expanded: boolean;
|
|
14
|
+
onToggle: () => void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Progressive disclosure for a stack of agent hints. Open on arrival so the brief is read as it
|
|
18
|
+
* streams, then folded away once it has served its purpose.
|
|
19
|
+
*/
|
|
20
|
+
export declare const HintDisclosure: ({ children, labels, expanded, onToggle }: HintDisclosureProps) => import("react").JSX.Element;
|
|
@@ -8,39 +8,34 @@ export declare enum SummaryKind {
|
|
|
8
8
|
RATING = "rating",
|
|
9
9
|
GENERIC = "generic"
|
|
10
10
|
}
|
|
11
|
-
/** One breakdown row: a count with its
|
|
11
|
+
/** One breakdown row: a count with its resolved label and (optional) description. */
|
|
12
12
|
export type SummaryCategory = {
|
|
13
13
|
count: number;
|
|
14
14
|
label: string;
|
|
15
|
+
/** May carry markdown emphasis — the video row bolds its retry budget. */
|
|
15
16
|
description?: string;
|
|
16
17
|
/** Drives the row icon; falls back to a generic mark when omitted. */
|
|
17
18
|
kind?: SummaryKind;
|
|
18
19
|
};
|
|
20
|
+
/** Footer line linking out to the privacy policy; omitted when no URL is configured. */
|
|
21
|
+
export type SummaryPrivacy = {
|
|
22
|
+
text: string;
|
|
23
|
+
linkLabel: string;
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
19
26
|
export type SummaryCardProps = {
|
|
20
|
-
/**
|
|
21
|
-
title: string;
|
|
22
|
-
/** Uppercase label for the total panel, e.g. "Total". */
|
|
27
|
+
/** Uppercase label for the total panel, e.g. "TOTAL". */
|
|
23
28
|
totalLabel: string;
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
minutesLabel: string;
|
|
28
|
-
/** Per-category breakdown rows (already mapped to FE labels). */
|
|
29
|
+
/** Resolved total line, e.g. "10 Questions (~ 30 minutes)". */
|
|
30
|
+
countLabel: string;
|
|
31
|
+
/** Per-category breakdown rows (already mapped to their labels). */
|
|
29
32
|
categories: SummaryCategory[];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
onContinue?: () => void;
|
|
34
|
-
/** Play the pre-interview reveal (typing dots → title types in → card fades in). */
|
|
35
|
-
animate?: boolean;
|
|
36
|
-
/** Accessible label for the reveal's typing-dots phase. */
|
|
37
|
-
typingLabel?: string;
|
|
38
|
-
/** Phrase shown beside the dots during the reveal ("Thinking…"). */
|
|
39
|
-
thinkingLabel?: string;
|
|
33
|
+
privacy?: SummaryPrivacy;
|
|
34
|
+
/** Appended inside links that open a new tab. */
|
|
35
|
+
opensNewTab: string;
|
|
40
36
|
};
|
|
41
37
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* breakdown list — one icon row per question type.
|
|
38
|
+
* "What to expect": an elevated white card with a centred TOTAL panel (question count and time
|
|
39
|
+
* estimate) and an accent-barred breakdown list — one icon row per question type.
|
|
45
40
|
*/
|
|
46
|
-
export declare const SummaryCard: ({
|
|
41
|
+
export declare const SummaryCard: ({ totalLabel, countLabel, categories, privacy, opensNewTab, }: SummaryCardProps) => import("react").JSX.Element;
|
package/dist/ui/chat/types.d.ts
CHANGED
|
@@ -8,14 +8,20 @@ export declare enum ChatBubbleVariant {
|
|
|
8
8
|
CARD = "card"
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* How options render: a numbered button list (MCQ/BGQ)
|
|
12
|
-
*
|
|
11
|
+
* How options render: a numbered button list (MCQ/BGQ) or a searchable dropdown, both drawn inside
|
|
12
|
+
* the bubble, or ACTION — a one-off control prompt (consent / submit / break acknowledgement) whose
|
|
13
|
+
* single option is drawn by the bottom dock instead, so it survives an arbitrarily tall step.
|
|
13
14
|
*/
|
|
14
15
|
export declare enum ChatOptionsKind {
|
|
15
16
|
LIST = "list",
|
|
16
17
|
DROPDOWN = "dropdown",
|
|
17
18
|
ACTION = "action"
|
|
18
19
|
}
|
|
20
|
+
/** A card drawn in place of one agent content bubble, instead of that bubble's text. */
|
|
21
|
+
export declare enum ChatCardKind {
|
|
22
|
+
ASSESSMENT_SUMMARY = "assessment-summary",
|
|
23
|
+
COPY_LINK = "copy-link"
|
|
24
|
+
}
|
|
19
25
|
/** A selectable answer option (MCQ/dropdown option or button-group button). */
|
|
20
26
|
export type ChatOptionItem = {
|
|
21
27
|
id: string;
|
|
@@ -58,6 +64,11 @@ export type ChatLogItem = {
|
|
|
58
64
|
questionLabel?: string;
|
|
59
65
|
/** Card-only dark badge, e.g. "Video". Present only on video question cards. */
|
|
60
66
|
questionBadge?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Cards drawn after this bubble's paragraphs. The backend authors a marker bubble as the last
|
|
69
|
+
* bubble of its step, so appending them is the bubble's own order.
|
|
70
|
+
*/
|
|
71
|
+
cards?: ChatCardKind[];
|
|
61
72
|
/** Selectable options rendered inside the bubble (option-type questions). */
|
|
62
73
|
options?: ChatOptionItem[];
|
|
63
74
|
optionsKind?: ChatOptionsKind;
|
|
@@ -81,4 +92,9 @@ export type ChatLogItem = {
|
|
|
81
92
|
editing?: boolean;
|
|
82
93
|
/** Agent text is still streaming in; renders a blinking caret at the end. */
|
|
83
94
|
streaming?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* An unanswerable agent aside. More than two in a row collapse behind a disclosure —
|
|
97
|
+
* a long intro brief otherwise pushes the first question off screen.
|
|
98
|
+
*/
|
|
99
|
+
isHint?: boolean;
|
|
84
100
|
};
|
package/dist/ui/constants.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flat ceiling on an answer regardless of the question's word rule (legacy
|
|
3
|
+
* MAX_CHARACTER_COUNT). Guards the request body when a question ships no maximum.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MAX_ANSWER_CHARACTERS = 5000;
|
|
1
6
|
/** Class scoping every style in dist/sapia-chatbot.css (see src/styles/index.css). */
|
|
2
7
|
export declare const WIDGET_ROOT_CLASS = "sapia-chatbot";
|
|
3
8
|
export declare const SLIM_SCROLLBAR = "sc:[scrollbar-width:thin] sc:[scrollbar-color:#8f8f96_transparent] sc:[&::-webkit-scrollbar]:w-1.5 sc:[&::-webkit-scrollbar-track]:bg-transparent sc:[&::-webkit-scrollbar-thumb]:rounded-full sc:[&::-webkit-scrollbar-thumb]:bg-field-border";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
type UsePreventPasteParams = {
|
|
3
|
+
/** When true the hook is a no-op (paste is permitted). */
|
|
4
|
+
allowPaste: boolean;
|
|
5
|
+
/** Wrapper element of the composer; only events inside it are blocked. */
|
|
6
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
7
|
+
/** Called for each blocked attempt (drives the INVALID_PASTE_ANSWER_ACTION log). */
|
|
8
|
+
onBlockedPaste?: () => void;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Blocks paste and drop inside a composer. Listeners are bound to `document` in the capture phase
|
|
12
|
+
* rather than to the element: assistive overlays such as ReciteMe re-parse the host DOM, which
|
|
13
|
+
* detaches per-node and React-synthetic handlers (legacy TG-21437). `beforeinput` covers keyboards
|
|
14
|
+
* that insert pasted text without firing a `paste` event.
|
|
15
|
+
*/
|
|
16
|
+
export declare const usePreventPaste: ({ allowPaste, containerRef, onBlockedPaste, }: UsePreventPasteParams) => void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type LocationSuggestionItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
/** Accessible option label — the full prediction text. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Emphasised leading part ("Melbourne"). */
|
|
6
|
+
mainText: string;
|
|
7
|
+
/** Trailing context ("VIC, Australia"); may be empty. */
|
|
8
|
+
secondaryText: string;
|
|
9
|
+
};
|
|
10
|
+
export type LocationAnswerInputProps = {
|
|
11
|
+
suggestions: LocationSuggestionItem[];
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Autocomplete is unavailable: the listbox never opens and Send is the only path. */
|
|
14
|
+
manualMode?: boolean;
|
|
15
|
+
placeholder: string;
|
|
16
|
+
inputLabel: string;
|
|
17
|
+
sendLabel: string;
|
|
18
|
+
suggestionsLabel: string;
|
|
19
|
+
/** Announced once a set of predictions settles, e.g. "5 locations found". */
|
|
20
|
+
suggestionsAnnouncement: (count: number) => string;
|
|
21
|
+
/** Text the input opens on when re-editing an answered location. */
|
|
22
|
+
initialText?: string;
|
|
23
|
+
onSearch: (input: string) => void;
|
|
24
|
+
onSelectSuggestion: (suggestion: LocationSuggestionItem) => void;
|
|
25
|
+
/** Send pressed with typed text and no prediction chosen. */
|
|
26
|
+
onSubmitText: (text: string) => void;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Location PII input: an ARIA combobox over the composer's chrome, backed by Google Places
|
|
30
|
+
* predictions (ported from legacy PlacesAutoComplete). Choosing a prediction submits immediately,
|
|
31
|
+
* as legacy does; Send always submits whatever is typed, so an unlisted town or an unreachable
|
|
32
|
+
* Places API never traps the candidate.
|
|
33
|
+
*/
|
|
34
|
+
export declare const LocationAnswerInput: ({ suggestions, disabled, manualMode, placeholder, inputLabel, sendLabel, suggestionsLabel, suggestionsAnnouncement, initialText, onSearch, onSelectSuggestion, onSubmitText, }: LocationAnswerInputProps) => import("react").JSX.Element;
|
|
@@ -2,7 +2,6 @@ export type PhoneCountryOption = {
|
|
|
2
2
|
code: string;
|
|
3
3
|
callingCode: string;
|
|
4
4
|
name: string;
|
|
5
|
-
flag: string;
|
|
6
5
|
};
|
|
7
6
|
export type PhoneAnswerInputProps = {
|
|
8
7
|
countries: PhoneCountryOption[];
|
|
@@ -15,5 +14,9 @@ export type PhoneAnswerInputProps = {
|
|
|
15
14
|
/** Receives the national number text and the selected ISO country code. */
|
|
16
15
|
onSubmit: (text: string, countryCode: string) => void;
|
|
17
16
|
};
|
|
18
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Phone PII input: country picker + national number (replaces legacy PhoneEditor). The picker is a
|
|
19
|
+
* native select behind a compact trigger, so a phone keeps its own wheel picker over the 240-odd
|
|
20
|
+
* countries without the closed control having to be wide enough for a country name.
|
|
21
|
+
*/
|
|
19
22
|
export declare const PhoneAnswerInput: ({ countries, defaultCountryCode, disabled, countryLabel, inputLabel, placeholder, sendLabel, onSubmit, }: PhoneAnswerInputProps) => import("react").JSX.Element;
|
|
@@ -8,7 +8,6 @@ export type SliderInputProps = {
|
|
|
8
8
|
enabled?: boolean;
|
|
9
9
|
pending?: boolean;
|
|
10
10
|
label: string;
|
|
11
|
-
hint: string;
|
|
12
11
|
submitLabel: string;
|
|
13
12
|
onSubmit?: (score: number) => void;
|
|
14
13
|
};
|
|
@@ -16,4 +15,4 @@ export type SliderInputProps = {
|
|
|
16
15
|
* Experience-rating slider (legacy renderSlider, AntD-free). Native range
|
|
17
16
|
* input: keyboard accessible (arrow keys) out of the box.
|
|
18
17
|
*/
|
|
19
|
-
export declare const SliderInput: ({ min, max, defaultValue, submittedValue, enabled, pending, label,
|
|
18
|
+
export declare const SliderInput: ({ min, max, defaultValue, submittedValue, enabled, pending, label, submitLabel, onSubmit, }: SliderInputProps) => import("react").JSX.Element;
|
|
@@ -4,29 +4,50 @@ export type RichToolbarLabels = {
|
|
|
4
4
|
italic: string;
|
|
5
5
|
bulletList: string;
|
|
6
6
|
numberList: string;
|
|
7
|
+
/** Opens the composer over the transcript, filling the widget below its chrome. */
|
|
8
|
+
expand: string;
|
|
9
|
+
/** Returns it to the inline height. */
|
|
10
|
+
collapse: string;
|
|
7
11
|
};
|
|
8
12
|
export type TextAnswerInputProps = {
|
|
9
13
|
/** Receives the answer text — markdown in rich mode, plain text otherwise. */
|
|
10
14
|
onSubmit: (text: string) => void;
|
|
11
15
|
disabled?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Permits sending an empty composer. Off by default — an empty answer is only meaningful where
|
|
18
|
+
* the question is optional (the post-interview feedback comment sends a skip).
|
|
19
|
+
*/
|
|
20
|
+
allowEmptySubmit?: boolean;
|
|
21
|
+
/** Word bounds from the current question (the BE *TextLength rules are word counts). */
|
|
22
|
+
minWords?: number;
|
|
23
|
+
maxWords?: number;
|
|
24
|
+
recommendedWords?: number;
|
|
16
25
|
placeholder: string;
|
|
17
26
|
sendLabel: string;
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Called instead of onSubmit when the answer is under minWords, with the count and a
|
|
29
|
+
* submit callback to run if the candidate chooses to send it anyway. Omit to send short
|
|
30
|
+
* answers straight through — the minimum only ever warns, it never withholds Send.
|
|
31
|
+
*/
|
|
32
|
+
onBelowMinimum?: (words: number, submit: () => void) => void;
|
|
33
|
+
/** Counter label for a word count, e.g. "42 words". */
|
|
34
|
+
wordCountLabel?: (count: number) => string;
|
|
35
|
+
/** Counter message while under minWords. */
|
|
36
|
+
shortResponseHint?: string;
|
|
37
|
+
/** Counter message between the minimum and the maximum. */
|
|
38
|
+
goodResponseHint?: string;
|
|
39
|
+
/** Counter message once maxWords is reached. */
|
|
40
|
+
maxWordsHint?: string;
|
|
22
41
|
/** Reassurance caption under the composer. */
|
|
23
42
|
footer?: string;
|
|
24
43
|
inputLabel: string;
|
|
25
44
|
/** Enables the rich-text editor + formatting toolbar (plain-text FTQ only). */
|
|
26
45
|
richText?: boolean;
|
|
27
46
|
toolbarLabels?: RichToolbarLabels;
|
|
28
|
-
/**
|
|
29
|
-
|
|
47
|
+
/** Permits paste for this question (ALLOW_PASTE tag or an internal session). Blocked by default. */
|
|
48
|
+
allowPaste?: boolean;
|
|
49
|
+
/** Called for each blocked paste attempt (AGC paste logging). */
|
|
50
|
+
onBlockedPaste?: () => void;
|
|
30
51
|
/** SC 1.3.5 token for PII questions (e.g. "email", "name"); omitted for free-text answers. */
|
|
31
52
|
autoComplete?: string;
|
|
32
53
|
/** Plain text the composer opens on (re-editing a submitted answer). */
|
|
@@ -35,5 +56,11 @@ export type TextAnswerInputProps = {
|
|
|
35
56
|
initialMarkdown?: string;
|
|
36
57
|
/** Moves focus to the editor on mount (used when an edit opens the composer). */
|
|
37
58
|
focusOnMount?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Fullscreen state. Owned by the shell rather than here: expanding covers the transcript, which
|
|
61
|
+
* is a sibling of this component and has to go inert at the same moment.
|
|
62
|
+
*/
|
|
63
|
+
expanded?: boolean;
|
|
64
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
38
65
|
};
|
|
39
|
-
export declare const TextAnswerInput: ({ onSubmit, disabled,
|
|
66
|
+
export declare const TextAnswerInput: ({ onSubmit, disabled, allowEmptySubmit, minWords, maxWords, recommendedWords, placeholder, sendLabel, onBelowMinimum, wordCountLabel, shortResponseHint, goodResponseHint, maxWordsHint, footer, inputLabel, richText, toolbarLabels, allowPaste, onBlockedPaste, autoComplete, initialText, initialMarkdown, focusOnMount, expanded, onExpandedChange, }: TextAnswerInputProps) => import("react").JSX.Element;
|
|
@@ -11,6 +11,6 @@ export type EmbeddedVideoPlayerProps = {
|
|
|
11
11
|
* (YouTube etc.) uses react-player. Lazy-loaded by ./EmbeddedVideo so react-player
|
|
12
12
|
* and @vimeo/player land in a separate chunk (size budget, ADR-024/ADR-025).
|
|
13
13
|
* Deviation from legacy: dropped the isVideoModuleOpen auto-pause coupling and the
|
|
14
|
-
* fixed-pixel responsive sizing — the
|
|
14
|
+
* fixed-pixel responsive sizing — the player fills the frame ./EmbeddedVideo supplies.
|
|
15
15
|
*/
|
|
16
16
|
export declare const EmbeddedVideoPlayer: ({ url, label }: EmbeddedVideoPlayerProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare enum MarkdownFlow {
|
|
2
|
+
/** No block wrapper — for copy that sits inside an existing heading, span or label. */
|
|
3
|
+
INLINE = "inline",
|
|
4
|
+
/** Paragraphs with the chat log's spacing, for multi-paragraph copy. */
|
|
5
|
+
BLOCK = "block"
|
|
6
|
+
}
|
|
7
|
+
export type MarkdownTextProps = {
|
|
8
|
+
/** Translated copy, possibly carrying markdown emphasis or links. */
|
|
9
|
+
children: string;
|
|
10
|
+
flow?: MarkdownFlow;
|
|
11
|
+
/**
|
|
12
|
+
* Label for the visually-hidden new-tab warning, e.g. "opens in a new tab". Supplying it is
|
|
13
|
+
* what makes links open in a new tab: without a warning to announce, a new tab would be an
|
|
14
|
+
* unannounced context change (SC 3.2.5), so those links stay in the current one.
|
|
15
|
+
*/
|
|
16
|
+
opensNewTab?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Renders translated copy as markdown — the backend writes emphasis and links into the
|
|
20
|
+
* translation file, so the raw template cannot go straight into the DOM. Raw HTML in the
|
|
21
|
+
* source is ignored rather than injected: react-markdown skips it without rehype-raw, so
|
|
22
|
+
* no sanitizer is needed here.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MarkdownText: ({ children, flow, opensNewTab, }: MarkdownTextProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type CohortClosedScreenLabels = {
|
|
2
|
+
title: string;
|
|
3
|
+
message: string;
|
|
4
|
+
};
|
|
5
|
+
export type CohortClosedScreenProps = {
|
|
6
|
+
labels: CohortClosedScreenLabels;
|
|
7
|
+
};
|
|
8
|
+
/** Terminal screen for an assessment whose cohort has closed — nothing here can be answered. */
|
|
9
|
+
export declare const CohortClosedScreen: ({ labels }: CohortClosedScreenProps) => import("react").JSX.Element;
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
export type CopyLinkButtonProps = {
|
|
2
2
|
copyLabel: string;
|
|
3
3
|
copiedLabel: string;
|
|
4
|
+
/**
|
|
5
|
+
* Link to copy. The widget can be embedded on a host page, so the current URL is only correct
|
|
6
|
+
* when the widget owns the address bar — pass the assessment's own link whenever it is known.
|
|
7
|
+
*/
|
|
8
|
+
url?: string;
|
|
9
|
+
/** Render the duplicate-squares glyph before the label (in-transcript pill). */
|
|
10
|
+
withIcon?: boolean;
|
|
4
11
|
/** Style overrides; the base only sets cursor/transition. */
|
|
5
12
|
className?: string;
|
|
6
13
|
};
|
|
7
14
|
/**
|
|
8
|
-
* Copies the
|
|
9
|
-
*
|
|
15
|
+
* Copies the pause-and-resume link and flashes a confirmation. Purely client-side — no core/api
|
|
16
|
+
* involvement beyond the URL it is handed.
|
|
10
17
|
*/
|
|
11
|
-
export declare const CopyLinkButton: ({ copyLabel, copiedLabel, className }: CopyLinkButtonProps) => import("react").JSX.Element;
|
|
18
|
+
export declare const CopyLinkButton: ({ copyLabel, copiedLabel, url, withIcon, className, }: CopyLinkButtonProps) => import("react").JSX.Element;
|
|
@@ -7,9 +7,12 @@ export type DoneScreenLabels = {
|
|
|
7
7
|
};
|
|
8
8
|
export type DoneScreenProps = {
|
|
9
9
|
labels: DoneScreenLabels;
|
|
10
|
+
/** Pre-validated absolute URL to continue to; omitted when the host supplied none. */
|
|
11
|
+
redirectUrl?: string;
|
|
12
|
+
redirectLabel?: string;
|
|
10
13
|
};
|
|
11
14
|
/**
|
|
12
15
|
* Completion screen shown when the interview has ended. The star rating is
|
|
13
16
|
* decorative only (no submission) per the redesign scope decision.
|
|
14
17
|
*/
|
|
15
|
-
export declare const DoneScreen: ({ labels }: DoneScreenProps) => import("react").JSX.Element;
|
|
18
|
+
export declare const DoneScreen: ({ labels, redirectUrl, redirectLabel }: DoneScreenProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AutoScrollTitleProps = {
|
|
2
|
+
title: string;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* The header's branded title. Scrolls itself when it is too long for the container, so the
|
|
6
|
+
* employer and role can be read in full on a phone instead of clipping forever.
|
|
7
|
+
*
|
|
8
|
+
* Motion that starts on its own has to be stoppable: hover, keyboard focus, and touch-and-hold
|
|
9
|
+
* each pause it. The heading is a tab stop only while it is actually moving — a static title
|
|
10
|
+
* would be a focus stop that does nothing. Reduced motion drops back to truncation.
|
|
11
|
+
*
|
|
12
|
+
* The whole string is always in the DOM, so assistive tech gets the full title whatever is
|
|
13
|
+
* visible.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AutoScrollTitle: ({ title }: AutoScrollTitleProps) => import("react").JSX.Element;
|
|
@@ -9,5 +9,17 @@ export type HeaderProps = {
|
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
11
|
* Interview header: branding/title, a muted subtitle, and a progress pill.
|
|
12
|
+
*
|
|
13
|
+
* The right-hand end of the row always keeps a 44px slot free. Recite Me — and any other
|
|
14
|
+
* host-page accessibility overlay — pins its launcher to the top-right of the page, on top of
|
|
15
|
+
* whatever the widget drew there, and the count used to be the casualty.
|
|
16
|
+
*
|
|
17
|
+
* Below 640px of *container* width there is no room for a pill beside the title, so the count
|
|
18
|
+
* renders as a subtitle suffix instead. Container width, not viewport: hosts embed the widget at
|
|
19
|
+
* arbitrary widths, so a media query would answer the wrong question. `px` and not `rem` so a
|
|
20
|
+
* host that changes the root font size cannot move the breakpoint.
|
|
21
|
+
*
|
|
22
|
+
* The title scrolls itself when it does not fit — see AutoScrollTitle. The subtitle truncates
|
|
23
|
+
* instead, because it is fixed chrome the candidate loses nothing by not finishing.
|
|
12
24
|
*/
|
|
13
25
|
export declare const Header: ({ title, subtitle, logoUrl, logoAlt, progressLabel, }: HeaderProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export type AutoScrollMetrics = {
|
|
3
|
+
shouldScroll: boolean;
|
|
4
|
+
/** Pixels of overflow, i.e. how far left the text must travel to end flush right. */
|
|
5
|
+
distancePx: number;
|
|
6
|
+
durationMs: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Measures whether the header title overflows its window and how far it has to travel to be read
|
|
10
|
+
* in full. Returns `shouldScroll: false` when it fits, or when the OS asks for reduced motion.
|
|
11
|
+
*
|
|
12
|
+
* One observer on one node: `scrollWidth` reports the full content width through `overflow:
|
|
13
|
+
* hidden`, so the overflow is a single subtraction and there is nothing to gain from watching the
|
|
14
|
+
* text separately.
|
|
15
|
+
*/
|
|
16
|
+
export declare const useAutoScrollTitle: (windowRef: RefObject<HTMLElement | null>) => AutoScrollMetrics;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type TerminalMessageScreenProps = {
|
|
2
|
+
/** Backend copy (markdown) explaining why the interview stopped. */
|
|
3
|
+
message: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Terminal screen for an interview the backend ended with an explanation rather than a
|
|
7
|
+
* completion — archived cohort or reused assessment. No title: the backend copy is a
|
|
8
|
+
* self-contained message.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TerminalMessageScreen: ({ message }: TerminalMessageScreenProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The widget's --sc-* custom properties, for subtrees that render outside the widget root.
|
|
3
|
+
* Radix portals a dialog to document.body, where the root's inline style no longer cascades and
|
|
4
|
+
* every brand token silently falls back to its default — a black CTA on a purple-branded
|
|
5
|
+
* interview. Anything portalled has to paint these on its own outermost node.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ThemeVariablesContext: import('react').Context<Record<string, string> | undefined>;
|
|
8
|
+
export declare const useThemeVariables: () => Record<string, string> | undefined;
|