@sapia-ai/chatbot-v3 1.2.0 → 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.
Files changed (51) hide show
  1. package/dist/{EmbeddedVideoPlayer-C_8tKis8.js → EmbeddedVideoPlayer-DTzRqNcQ.js} +14 -14
  2. package/dist/{Preview-CbNUoib5.js → Preview-Dd7KyhMk.js} +3 -3
  3. package/dist/api/client.d.ts +10 -6
  4. package/dist/api/places.d.ts +33 -0
  5. package/dist/api/types/messages.d.ts +26 -3
  6. package/dist/api/types/responses.d.ts +19 -17
  7. package/dist/api.js +2 -2
  8. package/dist/core/bubbles/cards.d.ts +14 -0
  9. package/dist/core/bubbles/convert.d.ts +14 -2
  10. package/dist/core/bubbles/counters.d.ts +10 -0
  11. package/dist/core/bubbles/types.d.ts +20 -0
  12. package/dist/core/constants.d.ts +13 -0
  13. package/dist/core/interview.d.ts +20 -7
  14. package/dist/core/store.d.ts +7 -8
  15. package/dist/{dist-7zan-9V3.js → dist-waE-4cub.js} +3 -3
  16. package/dist/embed/createChatbot.d.ts +2 -0
  17. package/dist/{fix-webm-duration-CJ-IsmuV.js → fix-webm-duration-IniZA6tF.js} +2 -2
  18. package/dist/index.js +5139 -4739
  19. package/dist/{jsx-runtime-CpK9sRtl.js → jsx-runtime-DN_m6Qdv.js} +2 -2
  20. package/dist/{messages-t5h3u6nr.js → messages-C00e82NS.js} +43 -38
  21. package/dist/places-CT6PNW7B.js +52 -0
  22. package/dist/react/AnswerInput.d.ts +6 -1
  23. package/dist/react/SapiaChatbot.d.ts +3 -1
  24. package/dist/react/bubbleViewModel.d.ts +9 -5
  25. package/dist/react/strings.d.ts +17 -7
  26. package/dist/react/usePlacesSuggestions.d.ts +16 -0
  27. package/dist/{react-Bx1VLQqP.js → react-A0_ZwPyM.js} +3 -3
  28. package/dist/{react--hlAJW6n.js → react-BDGt_WsZ.js} +3 -3
  29. package/dist/{react-BKQw6USG.js → react-B_YNH2g9.js} +3 -3
  30. package/dist/{react-yXcg2glq.js → react-ByP48xLV.js} +3 -3
  31. package/dist/{react-DFkljL-6.js → react-C9oBRlX8.js} +3 -3
  32. package/dist/{react-Bh9U4IBe.js → react-D5yWOfXN.js} +3 -3
  33. package/dist/{react-BtFG4mMU.js → react-DkQKleWD.js} +2 -2
  34. package/dist/{react-B6p_EGvt.js → react-d-THpGrV.js} +3 -3
  35. package/dist/{react-DJK2_GuR.js → react-euSb4sIX.js} +3 -3
  36. package/dist/ui/chat/ActionDock/ActionDock.d.ts +15 -0
  37. package/dist/ui/chat/ChatBubble/ChatBubble.d.ts +9 -2
  38. package/dist/ui/chat/ChatLog/ChatLog.d.ts +6 -4
  39. package/dist/ui/chat/EditBanner/EditBanner.d.ts +9 -3
  40. package/dist/ui/chat/SummaryCard/SummaryCard.d.ts +18 -23
  41. package/dist/ui/chat/types.d.ts +13 -2
  42. package/dist/ui/inputs/LocationAnswerInput/LocationAnswerInput.d.ts +34 -0
  43. package/dist/ui/inputs/PhoneAnswerInput/PhoneAnswerInput.d.ts +5 -2
  44. package/dist/ui/inputs/TextAnswerInput/TextAnswerInput.d.ts +11 -1
  45. package/dist/ui/shell/CopyLinkButton/CopyLinkButton.d.ts +10 -3
  46. package/dist/ui/shell/Header/AutoScrollTitle.d.ts +15 -0
  47. package/dist/ui/shell/Header/Header.d.ts +7 -4
  48. package/dist/ui/shell/Header/useAutoScrollTitle.d.ts +16 -0
  49. package/dist/ui/shell/WidgetRoot/themeVariables.d.ts +8 -0
  50. package/dist-umd/sapia-chatbot.umd.js +304 -304
  51. package/package.json +1 -1
@@ -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 FE-owned label and (optional) description. */
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
- /** Backend-authored heading, e.g. "Welcome to your interview — here's what to expect.". */
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
- /** Total-questions meta, e.g. "3 questions". */
25
- questionsLabel: string;
26
- /** Estimated-time meta, e.g. "~9 min". */
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
- /** BE-authored Continue label; rendered as a button only when onContinue is set (gate mode). */
31
- continueLabel?: string;
32
- /** Continue handler; its presence switches the card into blocking gate mode. */
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
- * Pre-interview summary. An elevated white card with the agent's welcome title,
43
- * a centred TOTAL panel (question count + estimated time), and an accent-barred
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: ({ title, totalLabel, questionsLabel, minutesLabel, categories, continueLabel, onContinue, animate, typingLabel, thinkingLabel, }: SummaryCardProps) => import("react").JSX.Element;
41
+ export declare const SummaryCard: ({ totalLabel, countLabel, categories, privacy, opensNewTab, }: SummaryCardProps) => import("react").JSX.Element;
@@ -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), a searchable dropdown, or a
12
- * single full-width CTA pill for one-off control prompts (consent / submit).
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;
@@ -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
- /** Phone PII input: country picker + national number (replaces legacy PhoneEditor). */
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;
@@ -4,6 +4,10 @@ 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. */
@@ -52,5 +56,11 @@ export type TextAnswerInputProps = {
52
56
  initialMarkdown?: string;
53
57
  /** Moves focus to the editor on mount (used when an edit opens the composer). */
54
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;
55
65
  };
56
- 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, }: TextAnswerInputProps) => import("react").JSX.Element;
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;
@@ -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 current page URL (the pause-and-resume link) and flashes a
9
- * confirmation. Purely client-side — no core/api involvement.
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;
@@ -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;
@@ -14,9 +14,12 @@ export type HeaderProps = {
14
14
  * host-page accessibility overlay — pins its launcher to the top-right of the page, on top of
15
15
  * whatever the widget drew there, and the count used to be the casualty.
16
16
  *
17
- * Below 640px of *container* width there is no room for a pill beside a truncating title, so the
18
- * count renders as a subtitle suffix instead. Container width, not viewport: hosts embed the
19
- * widget at arbitrary widths, so a media query would answer the wrong question. `px` and not
20
- * `rem` so a host that changes the root font size cannot move the breakpoint.
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.
21
24
  */
22
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,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;