@sapia-ai/chatbot-v3 1.0.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 (108) hide show
  1. package/dist/EmbeddedVideoPlayer-SaMMfDIW.js +1277 -0
  2. package/dist/EmbeddedVideoPlayer-SaMMfDIW.js.map +1 -0
  3. package/dist/Preview-Db-hgkTh.js +83 -0
  4. package/dist/Preview-Db-hgkTh.js.map +1 -0
  5. package/dist/api/client.d.ts +60 -0
  6. package/dist/api/config.d.ts +18 -0
  7. package/dist/api/constants.d.ts +5 -0
  8. package/dist/api/index.d.ts +5 -0
  9. package/dist/api/sse.d.ts +12 -0
  10. package/dist/api/types/branding.d.ts +17 -0
  11. package/dist/api/types/messages.d.ts +148 -0
  12. package/dist/api/types/responses.d.ts +106 -0
  13. package/dist/api.js +2 -0
  14. package/dist/classPrivateFieldSet2-DtQPURVD.js +32 -0
  15. package/dist/core/bubbles/convert.d.ts +18 -0
  16. package/dist/core/bubbles/types.d.ts +55 -0
  17. package/dist/core/constants.d.ts +14 -0
  18. package/dist/core/events.d.ts +44 -0
  19. package/dist/core/i18n/fallback.d.ts +2 -0
  20. package/dist/core/i18n/languages.d.ts +11 -0
  21. package/dist/core/i18n/translator.d.ts +13 -0
  22. package/dist/core/interview.d.ts +207 -0
  23. package/dist/core/media/mimeTypes.d.ts +10 -0
  24. package/dist/core/media/recorder.d.ts +61 -0
  25. package/dist/core/persistence.d.ts +4 -0
  26. package/dist/core/store.d.ts +49 -0
  27. package/dist/core/theme/branding.d.ts +6 -0
  28. package/dist/core/theme/cssVariables.d.ts +16 -0
  29. package/dist/core/theme/types.d.ts +11 -0
  30. package/dist/core/validation/phoneCountries.d.ts +21 -0
  31. package/dist/core/validation/pii.d.ts +30 -0
  32. package/dist/dash.all.min-DZ1yEcJk.js +27302 -0
  33. package/dist/dash.all.min-DZ1yEcJk.js.map +1 -0
  34. package/dist/defineProperty-DiFpLzd2.js +39 -0
  35. package/dist/dist-BSi28_cP.js +702 -0
  36. package/dist/dist-BSi28_cP.js.map +1 -0
  37. package/dist/dist-DGBYKC8c.js +14327 -0
  38. package/dist/dist-DGBYKC8c.js.map +1 -0
  39. package/dist/dist-FvHBWiRa.js +76 -0
  40. package/dist/dist-FvHBWiRa.js.map +1 -0
  41. package/dist/embed/compat.d.ts +82 -0
  42. package/dist/embed/constants.d.ts +2 -0
  43. package/dist/embed/createChatbot.d.ts +22 -0
  44. package/dist/fix-webm-duration-BW9Fbdzt.js +1057 -0
  45. package/dist/fix-webm-duration-BW9Fbdzt.js.map +1 -0
  46. package/dist/hls-mBncGwsE.js +18657 -0
  47. package/dist/hls-mBncGwsE.js.map +1 -0
  48. package/dist/index.d.ts +7 -0
  49. package/dist/index.js +4428 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/max-Btet1snX.js +12212 -0
  52. package/dist/max-Btet1snX.js.map +1 -0
  53. package/dist/messages-C4jqrtSG.js +187 -0
  54. package/dist/messages-C4jqrtSG.js.map +1 -0
  55. package/dist/react/AnswerInput.d.ts +21 -0
  56. package/dist/react/SapiaChatbot.d.ts +23 -0
  57. package/dist/react/bubbleViewModel.d.ts +50 -0
  58. package/dist/react/strings.d.ts +98 -0
  59. package/dist/react/useBeforeUnload.d.ts +5 -0
  60. package/dist/react/useVideoRecorder.d.ts +24 -0
  61. package/dist/react-BGJ7Szvq.js +216 -0
  62. package/dist/react-BGJ7Szvq.js.map +1 -0
  63. package/dist/react-BMxM8TWJ.js +192 -0
  64. package/dist/react-BMxM8TWJ.js.map +1 -0
  65. package/dist/react-BVzcquey.js +457 -0
  66. package/dist/react-BVzcquey.js.map +1 -0
  67. package/dist/react-BrCGR7Ca.js +2208 -0
  68. package/dist/react-BrCGR7Ca.js.map +1 -0
  69. package/dist/react-Bujo1aK5.js +334 -0
  70. package/dist/react-Bujo1aK5.js.map +1 -0
  71. package/dist/react-CRTg4gz8.js +367 -0
  72. package/dist/react-CRTg4gz8.js.map +1 -0
  73. package/dist/react-GXf8sbzf.js +311 -0
  74. package/dist/react-GXf8sbzf.js.map +1 -0
  75. package/dist/react-lp7yfM94.js +371 -0
  76. package/dist/react-lp7yfM94.js.map +1 -0
  77. package/dist/sapia-chatbot.css +3 -0
  78. package/dist/sapia.d.ts +4 -0
  79. package/dist/ui/chat/ChatBubble/ChatBubble.d.ts +47 -0
  80. package/dist/ui/chat/ChatLog/ChatLog.d.ts +33 -0
  81. package/dist/ui/chat/TypingIndicator/TypingIndicator.d.ts +17 -0
  82. package/dist/ui/chat/types.d.ts +71 -0
  83. package/dist/ui/constants.d.ts +2 -0
  84. package/dist/ui/inputs/DropdownInput/DropdownInput.d.ts +18 -0
  85. package/dist/ui/inputs/OptionList/OptionList.d.ts +18 -0
  86. package/dist/ui/inputs/PhoneAnswerInput/PhoneAnswerInput.d.ts +19 -0
  87. package/dist/ui/inputs/SliderInput/SliderInput.d.ts +19 -0
  88. package/dist/ui/inputs/TextAnswerInput/TextAnswerInput.d.ts +32 -0
  89. package/dist/ui/inputs/VideoRecorder/VideoRecorder.d.ts +54 -0
  90. package/dist/ui/media/EmbeddedVideo/EmbeddedVideo.d.ts +11 -0
  91. package/dist/ui/media/EmbeddedVideo/EmbeddedVideoPlayer.d.ts +16 -0
  92. package/dist/ui/media/EmbeddedVideo/VimeoPlayer.d.ts +20 -0
  93. package/dist/ui/media/UploadProgress/UploadProgress.d.ts +7 -0
  94. package/dist/ui/media/VideoPlayer/VideoPlayer.d.ts +13 -0
  95. package/dist/ui/primitives/Button/Button.d.ts +6 -0
  96. package/dist/ui/primitives/Dialog/Dialog.d.ts +16 -0
  97. package/dist/ui/richText.d.ts +6 -0
  98. package/dist/ui/shell/AccessVerificationForm/AccessVerificationForm.d.ts +21 -0
  99. package/dist/ui/shell/CopyLinkButton/CopyLinkButton.d.ts +11 -0
  100. package/dist/ui/shell/DoneScreen/DoneScreen.d.ts +15 -0
  101. package/dist/ui/shell/Header/Header.d.ts +13 -0
  102. package/dist/ui/shell/PreparingScreen/PreparingScreen.d.ts +9 -0
  103. package/dist/ui/shell/ProgressBar/ProgressBar.d.ts +9 -0
  104. package/dist/ui/shell/WelcomeScreen/WelcomeScreen.d.ts +22 -0
  105. package/dist/ui/shell/WidgetRoot/WidgetRoot.d.ts +12 -0
  106. package/dist-umd/sapia-chatbot.umd.js +3655 -0
  107. package/dist-umd/sapia-chatbot.umd.js.map +1 -0
  108. package/package.json +94 -0
@@ -0,0 +1,4 @@
1
+ export { createChatbot, type Chatbot, type CreateChatbotOptions } from './embed/createChatbot';
2
+ export { DEFAULT_CONTAINER_ID } from './embed/constants';
3
+ export { CHATBOT_EVENTS } from './core/events';
4
+ export { PHChatBot, PHChatBotCallbackFunction, CHATBOT_CONTAINER_ID } from './embed/compat';
@@ -0,0 +1,47 @@
1
+ import { ReactNode, Ref } from 'react';
2
+ import { ChatLogItem } from '../types';
3
+ export type SliderLabels = {
4
+ label: string;
5
+ hint: string;
6
+ submitLabel: string;
7
+ };
8
+ export type DropdownLabels = {
9
+ searchPlaceholder: string;
10
+ searchLabel: string;
11
+ };
12
+ export type MediaLabels = {
13
+ uploadProgress: string;
14
+ uploadFailed: string;
15
+ retryUpload: string;
16
+ playVideo: string;
17
+ videoAnswer: string;
18
+ /** Accessible title for a backend-delivered embedded agent video. */
19
+ embeddedVideo: string;
20
+ };
21
+ export type ChatBubbleLabels = {
22
+ retry: string;
23
+ optionsGroup: string;
24
+ edit: string;
25
+ cancelEdit: string;
26
+ /** Eyebrow on every agent transcript turn, e.g. "Interviewer". */
27
+ speakerLabel: string;
28
+ };
29
+ export type ChatBubbleProps = {
30
+ item: ChatLogItem;
31
+ labels: ChatBubbleLabels;
32
+ sliderLabels: SliderLabels;
33
+ dropdownLabels: DropdownLabels;
34
+ mediaLabels: MediaLabels;
35
+ onRetry?: () => void;
36
+ onSelectOption?: (optionId: string) => void;
37
+ onSubmitSlider?: (score: number) => void;
38
+ onEdit?: (questionId: string) => void;
39
+ onCancelEdit?: () => void;
40
+ onRetryVideo?: () => void;
41
+ onResolveVideoUrl?: (questionId: string, extension: string) => Promise<string>;
42
+ /** Attaches to the bubble's root <li> so the log can scroll it into view. */
43
+ rootRef?: Ref<HTMLLIElement>;
44
+ /** Rendered inside the question card body (e.g. the video recorder). */
45
+ footer?: ReactNode;
46
+ };
47
+ export declare const ChatBubble: ({ item, labels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onCancelEdit, onRetryVideo, onResolveVideoUrl, rootRef, footer, }: ChatBubbleProps) => import("react").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { ReactNode } from 'react';
2
+ import { ChatBubbleLabels, DropdownLabels, MediaLabels, SliderLabels } from '../ChatBubble/ChatBubble';
3
+ import { ChatLogItem } from '../types';
4
+ export type ChatLogProps = {
5
+ items: ChatLogItem[];
6
+ typing: boolean;
7
+ /** Stable screen-reader label for the loading status, e.g. "Interviewer is typing". */
8
+ typingLabel: string;
9
+ /** Phase-1 loading phrase shown after a candidate answer. */
10
+ typingReadingLabel: string;
11
+ /** Phase-2 loading phrase (and the only one on the first agent turn). */
12
+ typingThinkingLabel: string;
13
+ bubbleLabels: ChatBubbleLabels;
14
+ sliderLabels: SliderLabels;
15
+ dropdownLabels: DropdownLabels;
16
+ mediaLabels: MediaLabels;
17
+ onRetry?: () => void;
18
+ onSelectOption?: (optionId: string) => void;
19
+ onSubmitSlider?: (score: number) => void;
20
+ onEdit?: (questionId: string) => void;
21
+ onCancelEdit?: () => void;
22
+ onRetryVideo?: () => void;
23
+ onResolveVideoUrl?: (questionId: string, extension: string) => Promise<string>;
24
+ /** Node rendered inside the question card identified by cardFooterItemId (e.g. video recorder). */
25
+ cardFooter?: ReactNode;
26
+ /** Bubble id whose card receives cardFooter. */
27
+ cardFooterItemId?: string;
28
+ };
29
+ /**
30
+ * Scrollable interview transcript. aria-live announces new bubbles to screen
31
+ * readers; the log auto-scrolls to the newest message.
32
+ */
33
+ export declare const ChatLog: ({ items, typing, typingLabel, typingReadingLabel, typingThinkingLabel, bubbleLabels, sliderLabels, dropdownLabels, mediaLabels, onRetry, onSelectOption, onSubmitSlider, onEdit, onCancelEdit, onRetryVideo, onResolveVideoUrl, cardFooter, cardFooterItemId, }: ChatLogProps) => import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ export type TypingIndicatorProps = {
2
+ /** Stable accessible description for screen readers, e.g. "Interviewer is typing". */
3
+ ariaLabel: string;
4
+ /** Phase-1 status shown briefly when responding to a candidate answer. */
5
+ readingLabel: string;
6
+ /** Phase-2 status (and the only status when there's no answer to read). */
7
+ thinkingLabel: string;
8
+ /** True when the previous message is a candidate answer (enables the "reading" phase). */
9
+ afterAnswer: boolean;
10
+ };
11
+ /**
12
+ * Pre-stream loading status: a phrase + animated dots rendered directly in the
13
+ * transcript (no bubble/background) under the interviewer left rule. When
14
+ * responding to an answer it reads "Reading your response…" then "Thinking about
15
+ * it…"; on the first agent turn it shows only the "thinking" phrase.
16
+ */
17
+ export declare const TypingIndicator: ({ ariaLabel, readingLabel, thinkingLabel, afterAnswer, }: TypingIndicatorProps) => import("react").JSX.Element;
@@ -0,0 +1,71 @@
1
+ export type ChatItemSender = 'agent' | 'candidate';
2
+ /** A selectable answer option (MCQ/dropdown option or button-group button). */
3
+ export type ChatOptionItem = {
4
+ id: string;
5
+ text: string;
6
+ };
7
+ /** Video answer state rendered inside a candidate bubble. */
8
+ export type ChatVideoItem = {
9
+ /** Upload in flight: progress 0–1. */
10
+ uploadProgress?: number;
11
+ /** Local recorded blob for immediate playback (just-submitted answer). */
12
+ blob?: Blob;
13
+ /** For historical answers: fetch a signed playback URL via these. */
14
+ questionId: string;
15
+ extension?: string;
16
+ /** Upload failed; retry available. */
17
+ failed?: boolean;
18
+ };
19
+ /** A backend-delivered embedded video shown inside an agent bubble (intro/explainer). */
20
+ export type ChatEmbeddedVideoItem = {
21
+ /** The raw video URL from the agent content (YouTube/Vimeo/generic). */
22
+ url: string;
23
+ };
24
+ /** Rating-slider state rendered inside a candidate bubble. */
25
+ export type ChatSliderItem = {
26
+ min: number;
27
+ max: number;
28
+ defaultValue: number;
29
+ /** The submitted score once answered. */
30
+ submittedValue?: number;
31
+ /** Slider accepts input (current unanswered question only). */
32
+ enabled: boolean;
33
+ };
34
+ export type ChatLogItem = {
35
+ id: string;
36
+ sender: ChatItemSender;
37
+ /** Message paragraphs in display order. */
38
+ paragraphs: string[];
39
+ /** Visual treatment: plain conversational bubble, or the elevated question card. */
40
+ variant?: 'bubble' | 'card';
41
+ /** Card-only eyebrow, e.g. "Question 2 of 4" or "Single choice question". */
42
+ questionLabel?: string;
43
+ /** Card-only dark badge, e.g. "Video". Present only on video question cards. */
44
+ questionBadge?: string;
45
+ /** Sanitized rich-text HTML for a candidate answer; rendered instead of plain paragraphs. */
46
+ answerHtml?: string;
47
+ /** Selectable options rendered inside the bubble (option-type questions). */
48
+ options?: ChatOptionItem[];
49
+ /** How the options render: a button list (MCQ/BGQ) or a searchable dropdown. */
50
+ optionsKind?: 'list' | 'dropdown';
51
+ /** The chosen option once answered (or while submitting). */
52
+ selectedOptionId?: string;
53
+ /** Options accept clicks (current unanswered question only). */
54
+ optionsEnabled?: boolean;
55
+ /** Rating slider rendered inside the bubble (slider questions). */
56
+ slider?: ChatSliderItem;
57
+ /** Video answer rendered inside the bubble (video questions). */
58
+ video?: ChatVideoItem;
59
+ /** Backend-delivered video embedded inside an agent bubble. */
60
+ embeddedVideo?: ChatEmbeddedVideoItem;
61
+ /** Answer submission in flight. */
62
+ pending?: boolean;
63
+ /** Answer submission failed; retry available. */
64
+ failed?: boolean;
65
+ /** An answered bubble whose answer can be re-edited; carries the question id. */
66
+ editableQuestionId?: string;
67
+ /** This bubble's answer is currently being re-edited. */
68
+ editing?: boolean;
69
+ /** Agent text is still streaming in; renders a blinking caret at the end. */
70
+ streaming?: boolean;
71
+ };
@@ -0,0 +1,2 @@
1
+ /** Class scoping every style in dist/sapia-chatbot.css (see src/styles/index.css). */
2
+ export declare const WIDGET_ROOT_CLASS = "sapia-chatbot";
@@ -0,0 +1,18 @@
1
+ import { ChatOptionItem } from '../../chat/types';
2
+ export type DropdownInputProps = {
3
+ options: ChatOptionItem[];
4
+ selectedOptionId?: string;
5
+ /** Accepts input; false once answered or while submitting. */
6
+ enabled?: boolean;
7
+ pending?: boolean;
8
+ searchPlaceholder: string;
9
+ searchLabel: string;
10
+ groupLabel: string;
11
+ onSelect?: (optionId: string) => void;
12
+ };
13
+ /**
14
+ * Searchable option picker for DROPDOWN questions (ported from legacy
15
+ * components/Dropdown): a filter input over a visible option list — clicking
16
+ * an option submits it. AntD/ahooks-free.
17
+ */
18
+ export declare const DropdownInput: ({ options, selectedOptionId, enabled, pending, searchPlaceholder, searchLabel, groupLabel, onSelect, }: DropdownInputProps) => import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { ChatOptionItem } from '../../chat/types';
2
+ export type OptionListProps = {
3
+ options: ChatOptionItem[];
4
+ /** The chosen option (highlighted; stays highlighted after answering). */
5
+ selectedOptionId?: string;
6
+ /** Options accept clicks; false once answered or while submitting. */
7
+ enabled?: boolean;
8
+ /** Submission in flight for the selected option. */
9
+ pending?: boolean;
10
+ groupLabel: string;
11
+ onSelect?: (optionId: string) => void;
12
+ };
13
+ /**
14
+ * Selectable answer options for MCQ/terms-accept/button-group questions.
15
+ * Pure presentational: single select, real buttons, keyboard accessible.
16
+ * Replaces legacy components/OptionList (AntD-free).
17
+ */
18
+ export declare const OptionList: ({ options, selectedOptionId, enabled, pending, groupLabel, onSelect, }: OptionListProps) => import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ export type PhoneCountryOption = {
2
+ code: string;
3
+ callingCode: string;
4
+ name: string;
5
+ flag: string;
6
+ };
7
+ export type PhoneAnswerInputProps = {
8
+ countries: PhoneCountryOption[];
9
+ defaultCountryCode: string;
10
+ disabled?: boolean;
11
+ countryLabel: string;
12
+ inputLabel: string;
13
+ placeholder: string;
14
+ sendLabel: string;
15
+ /** Receives the national number text and the selected ISO country code. */
16
+ onSubmit: (text: string, countryCode: string) => void;
17
+ };
18
+ /** Phone PII input: country picker + national number (replaces legacy PhoneEditor). */
19
+ export declare const PhoneAnswerInput: ({ countries, defaultCountryCode, disabled, countryLabel, inputLabel, placeholder, sendLabel, onSubmit, }: PhoneAnswerInputProps) => import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ export type SliderInputProps = {
2
+ min: number;
3
+ max: number;
4
+ defaultValue: number;
5
+ /** The submitted score once answered (renders read-only at this value). */
6
+ submittedValue?: number;
7
+ /** Slider accepts input; false once answered or while submitting. */
8
+ enabled?: boolean;
9
+ pending?: boolean;
10
+ label: string;
11
+ hint: string;
12
+ submitLabel: string;
13
+ onSubmit?: (score: number) => void;
14
+ };
15
+ /**
16
+ * Experience-rating slider (legacy renderSlider, AntD-free). Native range
17
+ * input: keyboard accessible (arrow keys) out of the box.
18
+ */
19
+ export declare const SliderInput: ({ min, max, defaultValue, submittedValue, enabled, pending, label, hint, submitLabel, onSubmit, }: SliderInputProps) => import("react").JSX.Element;
@@ -0,0 +1,32 @@
1
+ export type RichToolbarLabels = {
2
+ toolbar: string;
3
+ bold: string;
4
+ italic: string;
5
+ underline: string;
6
+ bulletList: string;
7
+ numberList: string;
8
+ };
9
+ export type TextAnswerInputProps = {
10
+ /** Receives plain text and, in rich mode, the sanitized HTML rendering. */
11
+ onSubmit: (text: string, html?: string) => void;
12
+ disabled?: boolean;
13
+ /** Character rules from the current question (legacy RuleName min/max/recommended). */
14
+ minLength?: number;
15
+ maxLength?: number;
16
+ recommendedLength?: number;
17
+ placeholder: string;
18
+ sendLabel: string;
19
+ /** Hint shown while below minLength, e.g. "Please write at least {min} characters". */
20
+ minLengthHint?: string;
21
+ /** Affirmation shown once the minimum is met, e.g. "Looking good". */
22
+ okHint?: string;
23
+ /** Reassurance caption under the composer. */
24
+ footer?: string;
25
+ inputLabel: string;
26
+ /** Enables the rich-text editor + formatting toolbar (plain-text FTQ only). */
27
+ richText?: boolean;
28
+ toolbarLabels?: RichToolbarLabels;
29
+ /** Called when the candidate pastes (AGC paste logging). */
30
+ onPaste?: () => void;
31
+ };
32
+ export declare const TextAnswerInput: ({ onSubmit, disabled, minLength, maxLength, recommendedLength, placeholder, sendLabel, minLengthHint, okHint, footer, inputLabel, richText, toolbarLabels, onPaste, }: TextAnswerInputProps) => import("react").JSX.Element;
@@ -0,0 +1,54 @@
1
+ import { RefObject } from 'react';
2
+ export type VideoRecorderLabels = {
3
+ openCamera: string;
4
+ startRecording: string;
5
+ stopRecording: string;
6
+ reRecord: string;
7
+ submit: string;
8
+ cameraError: string;
9
+ preview: string;
10
+ /** Design-only setup/recording labels (optional; fall back to no chrome). */
11
+ camera?: string;
12
+ microphone?: string;
13
+ on?: string;
14
+ off?: string;
15
+ finishHint?: string;
16
+ cameraOff?: string;
17
+ };
18
+ export type VideoRecorderPhase = 'idle' | 'preview' | 'recording' | 'review' | 'error';
19
+ export type VideoRecorderProps = {
20
+ phase: VideoRecorderPhase;
21
+ elapsedSeconds: number;
22
+ maxSeconds: number;
23
+ /** True once a recording is captured and ready to submit. */
24
+ hasResult: boolean;
25
+ showPreview: boolean;
26
+ videoRef: RefObject<HTMLVideoElement | null>;
27
+ disabled?: boolean;
28
+ labels: VideoRecorderLabels;
29
+ onOpenCamera: () => void;
30
+ /** Begins the 3-2-1 countdown before recording (preferred over onStartRecording). */
31
+ onBeginCountdown?: () => void;
32
+ onStartRecording?: () => void;
33
+ onStopRecording: () => void;
34
+ onReRecord: () => void;
35
+ onSubmit: () => void;
36
+ /** Camera/mic toggle state + handlers (setup phase). */
37
+ camOn?: boolean;
38
+ micOn?: boolean;
39
+ onToggleCamera?: () => void;
40
+ onToggleMicrophone?: () => void;
41
+ /** 3-2-1 countdown value before recording (null/<=0 = hidden). */
42
+ countdown?: number | null;
43
+ /** Precomposed "n/max attempts" label; hides the re-record button at the cap. */
44
+ attemptsLabel?: string;
45
+ canRetake?: boolean;
46
+ /** Object URL for the recorded take, played back in review. */
47
+ reviewUrl?: string | null;
48
+ };
49
+ /**
50
+ * Camera preview + record/review controls, styled to the Chat-3000 design.
51
+ * The MediaRecorder lifecycle, countdown, toggles and attempts live in
52
+ * react/useVideoRecorder; this component only renders state + buttons.
53
+ */
54
+ export declare const VideoRecorder: ({ phase, elapsedSeconds, maxSeconds, hasResult, showPreview, videoRef, disabled, labels, onOpenCamera, onBeginCountdown, onStartRecording, onStopRecording, onReRecord, onSubmit, camOn, micOn, onToggleCamera, onToggleMicrophone, countdown, attemptsLabel, canRetake, reviewUrl, }: VideoRecorderProps) => import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ export type EmbeddedVideoProps = {
2
+ /** Raw agent-delivered video URL (YouTube/Vimeo/generic). */
3
+ url: string;
4
+ /** Accessible title/label for the embed. */
5
+ label: string;
6
+ };
7
+ /**
8
+ * Backend-delivered video embedded inside an agent bubble (intro/explainer).
9
+ * Thin wrapper that lazy-loads the heavy player stack on demand.
10
+ */
11
+ export declare const EmbeddedVideo: ({ url, label }: EmbeddedVideoProps) => import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ export type EmbeddedVideoPlayerProps = {
2
+ /** Raw agent-delivered video URL (YouTube/Vimeo/generic). */
3
+ url: string;
4
+ /** Accessible title/label for the embed. */
5
+ label: string;
6
+ };
7
+ /**
8
+ * Renders a backend-delivered embedded video inside an agent bubble. Ported from
9
+ * legacy phapp-fi-widget components/VideoPlayer: Vimeo URLs use the dedicated
10
+ * VimeoPlayer (custom iframe attributes / referrerPolicy), everything else
11
+ * (YouTube etc.) uses react-player. Lazy-loaded by ./EmbeddedVideo so react-player
12
+ * and @vimeo/player land in a separate chunk (size budget, ADR-024/ADR-025).
13
+ * Deviation from legacy: dropped the isVideoModuleOpen auto-pause coupling and the
14
+ * fixed-pixel responsive sizing — the embed now fills the full bubble width.
15
+ */
16
+ export declare const EmbeddedVideoPlayer: ({ url, label }: EmbeddedVideoPlayerProps) => import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ export type VimeoPlayerProps = {
2
+ src: string;
3
+ /** Accessible title applied to the embed iframe. */
4
+ title: string;
5
+ width?: string;
6
+ height?: string;
7
+ onPlay?: () => void;
8
+ onPause?: () => void;
9
+ onEnded?: () => void;
10
+ onError?: (error: Error) => void;
11
+ };
12
+ /**
13
+ * Vimeo embed via @vimeo/player. Ported from legacy phapp-fi-widget
14
+ * components/VimeoPlayer — the iframe is created manually so the required
15
+ * attributes (notably referrerPolicy="origin", critical for domain-restricted
16
+ * videos, and the autoplay/fullscreen allow-list) are present on first render.
17
+ * Deviation from legacy: dropped the useAssessmentStateContext "pause when the
18
+ * recorder opens" coupling — the v3 library has no such global state.
19
+ */
20
+ export declare const VimeoPlayer: ({ src, title, width, height, onPlay, onPause, onEnded, onError, }: VimeoPlayerProps) => import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ export type UploadProgressProps = {
2
+ /** 0–1. */
3
+ value: number;
4
+ label: string;
5
+ };
6
+ /** Accessible determinate progress bar for a video upload. */
7
+ export declare const UploadProgress: ({ value, label }: UploadProgressProps) => import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ export type VideoPlayerProps = {
2
+ /** Local recorded blob (just-submitted answer), played without a network call. */
3
+ blob?: Blob;
4
+ /** Lazily resolves a signed playback URL (historical answers). */
5
+ resolveUrl?: () => Promise<string>;
6
+ playLabel: string;
7
+ label: string;
8
+ };
9
+ /**
10
+ * Plays a recorded video answer. Uses the local blob when available, otherwise
11
+ * fetches a signed URL on demand. Native <video controls> — keyboard accessible.
12
+ */
13
+ export declare const VideoPlayer: ({ blob, resolveUrl, playLabel, label }: VideoPlayerProps) => import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ export type ButtonProps = {
3
+ children: ReactNode;
4
+ variant?: 'primary' | 'ghost';
5
+ } & ButtonHTMLAttributes<HTMLButtonElement>;
6
+ export declare const Button: ({ children, variant, type, className, ...rest }: ButtonProps) => import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from 'react';
2
+ export type DialogAction = {
3
+ label: string;
4
+ onClick: () => void;
5
+ variant?: 'primary' | 'ghost';
6
+ };
7
+ export type DialogProps = {
8
+ open: boolean;
9
+ title: string;
10
+ children?: ReactNode;
11
+ actions: DialogAction[];
12
+ /** Called on Escape / overlay click; omit to force an action choice. */
13
+ onClose?: () => void;
14
+ };
15
+ /** Modal dialog on Radix (focus trap, aria handled). Replaces AntD Modal. */
16
+ export declare const Dialog: ({ open, title, children, actions, onClose }: DialogProps) => import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Strips everything except a small inline/list formatting allow-list and removes
3
+ * all attributes (class/style/href/on*), re-adding only controlled list/block
4
+ * spacing. Returns "" when no DOM is available (SSR).
5
+ */
6
+ export declare const sanitizeRichText: (html: string) => string;
@@ -0,0 +1,21 @@
1
+ export type AccessVerificationLabels = {
2
+ title: string;
3
+ description: string;
4
+ inputLabel: string;
5
+ placeholder: string;
6
+ submit: string;
7
+ mismatchError: string;
8
+ };
9
+ export type AccessVerificationFormProps = {
10
+ /** Masked email hint, e.g. "du*****@sapia.ai". */
11
+ emailHint?: string;
12
+ mismatch?: boolean;
13
+ submitting?: boolean;
14
+ labels: AccessVerificationLabels;
15
+ onSubmit: (email: string) => void;
16
+ };
17
+ /**
18
+ * Email gate shown before the interview when the assessment requires
19
+ * verification (legacy AccessVerification). Pure presentational.
20
+ */
21
+ export declare const AccessVerificationForm: ({ emailHint, mismatch, submitting, labels, onSubmit, }: AccessVerificationFormProps) => import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ export type CopyLinkButtonProps = {
2
+ copyLabel: string;
3
+ copiedLabel: string;
4
+ /** Style overrides; the base only sets cursor/transition. */
5
+ className?: string;
6
+ };
7
+ /**
8
+ * Copies the current page URL (the pause-and-resume link) and flashes a
9
+ * confirmation. Purely client-side — no core/api involvement.
10
+ */
11
+ export declare const CopyLinkButton: ({ copyLabel, copiedLabel, className }: CopyLinkButtonProps) => import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ export type DoneScreenLabels = {
2
+ title: string;
3
+ subtitle: string;
4
+ nextLabel: string;
5
+ steps: [string, string, string];
6
+ ratingPrompt: string;
7
+ };
8
+ export type DoneScreenProps = {
9
+ labels: DoneScreenLabels;
10
+ };
11
+ /**
12
+ * Completion screen shown when the interview has ended. The star rating is
13
+ * decorative only (no submission) per the redesign scope decision.
14
+ */
15
+ export declare const DoneScreen: ({ labels }: DoneScreenProps) => import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ export type HeaderProps = {
2
+ title: string;
3
+ /** Muted second line, e.g. "Sapia chat interview". */
4
+ subtitle?: string;
5
+ logoUrl?: string;
6
+ logoAlt?: string;
7
+ /** Progress pill text, e.g. "Question 2 of 4" or "Getting started". */
8
+ progressLabel?: string;
9
+ };
10
+ /**
11
+ * Interview header: branding/title, a muted subtitle, and a progress pill.
12
+ */
13
+ export declare const Header: ({ title, subtitle, logoUrl, logoAlt, progressLabel, }: HeaderProps) => import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ export type PreparingScreenProps = {
2
+ /** Status text, e.g. "Preparing your interview…". */
3
+ label: string;
4
+ };
5
+ /**
6
+ * Full-screen loading state shown while the interview is being fetched/started.
7
+ * Re-skin of the previous loading paragraph; announced via role="status".
8
+ */
9
+ export declare const PreparingScreen: ({ label }: PreparingScreenProps) => import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ export type ProgressBarProps = {
2
+ /** Answered question count. */
3
+ value: number;
4
+ /** Total question count; bar hidden when 0. */
5
+ max: number;
6
+ /** Accessible name, e.g. "Interview progress". */
7
+ label: string;
8
+ };
9
+ export declare const ProgressBar: ({ value, max, label }: ProgressBarProps) => import("react").JSX.Element | null;
@@ -0,0 +1,22 @@
1
+ export type WelcomeScreenLabels = {
2
+ /** Eyebrow above the greeting, e.g. "Chat interview". */
3
+ eyebrow: string;
4
+ greeting: string;
5
+ intro: string;
6
+ /** Copy-link affordance, e.g. "Copy link · resume later". */
7
+ copyLinkResume: string;
8
+ copied: string;
9
+ next: string;
10
+ };
11
+ export type WelcomeScreenProps = {
12
+ labels: WelcomeScreenLabels;
13
+ logoUrl?: string;
14
+ logoAlt?: string;
15
+ onNext: () => void;
16
+ };
17
+ /**
18
+ * Pre-interview welcome gate. Greets the candidate (name/role/company when the
19
+ * API supplies them) and starts the interview on "Begin". A centred column with
20
+ * a smile eyebrow — the library bundles no stock photography.
21
+ */
22
+ export declare const WelcomeScreen: ({ labels, logoUrl, logoAlt, onNext }: WelcomeScreenProps) => import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ export type WidgetRootProps = {
3
+ children: ReactNode;
4
+ /** CSS custom properties (--sc-*) produced by core/theme. */
5
+ themeVariables?: Record<string, string>;
6
+ dir?: 'ltr' | 'rtl';
7
+ };
8
+ /**
9
+ * Root element of the widget. Carries the scoping class for all packaged
10
+ * styles plus the theme CSS variables, so theming never re-renders children.
11
+ */
12
+ export declare const WidgetRoot: ({ children, themeVariables, dir }: WidgetRootProps) => import("react").JSX.Element;