Skip to main content
userTourKit
@tour-kit/surveys

Types

TypeScript type definitions exported by @tour-kit/surveys — survey config, question config, scoring results, context, events, queue, and position types

domidex01Published Updated

All types are exported from the package root. Import them as type-only:

import type {
  SurveyConfig,
  QuestionConfig,
  NPSResult,
  SurveysProviderProps,
} from '@tour-kit/surveys';

Survey types

SurveyConfig

Main configuration object for a survey.

interface SurveyConfig {
  id: string;
  type: SurveyType;
  displayMode: DisplayMode;
  priority?: SurveyPriority;
  title?: string;
  description?: string | ReactNode;
  questions: QuestionConfig[];
  frequency?: FrequencyRule;
  schedule?: unknown;           // requires @tour-kit/scheduling
  audience?: AudienceCondition[];
  globalCooldownDays?: number;
  samplingRate?: number;        // 0–1
  maxSnoozeCount?: number;
  snoozeDelayDays?: number;
  maxPerSession?: number;
  modalOptions?: ModalOptions;
  slideoutOptions?: SlideoutOptions;
  bannerOptions?: BannerOptions;
  popoverOptions?: PopoverOptions;
  metadata?: Record<string, unknown>;
  onShow?: () => void;
  onDismiss?: (reason: DismissalReason) => void;
  onComplete?: (responses: Map<string, AnswerValue>) => void;
  onAnswer?: (questionId: string, value: AnswerValue) => void;
}

SurveyState

Runtime state for a single survey, managed internally by SurveysProvider.

interface SurveyState {
  id: string;
  isActive: boolean;
  isVisible: boolean;
  isDismissed: boolean;
  isSnoozed: boolean;
  isCompleted: boolean;
  viewCount: number;
  lastViewedAt: Date | null;
  dismissedAt: Date | null;
  dismissalReason: DismissalReason | null;
  completedAt: Date | null;
  snoozeCount: number;
  snoozeUntil: Date | null;
  currentStep: number;
  responses: Map<string, AnswerValue>;
}

SurveyType

type SurveyType = 'nps' | 'csat' | 'ces' | 'custom';

DisplayMode

type DisplayMode = 'popover' | 'modal' | 'slideout' | 'banner' | 'inline';

SurveyPriority

type SurveyPriority = 'critical' | 'high' | 'normal' | 'low';

FrequencyRule

type FrequencyRule =
  | 'once'
  | 'session'
  | 'always'
  | { type: 'times'; count: number }
  | { type: 'interval'; days: number };

DismissalReason

type DismissalReason =
  | 'close_button'
  | 'overlay_click'
  | 'escape_key'
  | 'snooze'
  | 'completed'
  | 'programmatic';

SurveyStorageAdapter

interface SurveyStorageAdapter {
  getItem(key: string): string | null | Promise<string | null>;
  setItem(key: string, value: string): void | Promise<void>;
  removeItem(key: string): void | Promise<void>;
}

Question types

QuestionConfig

interface QuestionConfig {
  id: string;
  type: QuestionType;
  text: string;
  description?: string;
  required?: boolean;
  placeholder?: string;
  ratingScale?: RatingScale;       // only for 'rating'
  options?: SelectOption[];         // only for 'single-select' | 'multi-select'
  maxLength?: number;               // only for 'text' | 'textarea'
  skipLogic?: SkipLogic[];
  validation?: (value: AnswerValue) => string | null;
}

QuestionType

type QuestionType =
  | 'rating'
  | 'text'
  | 'textarea'
  | 'single-select'
  | 'multi-select'
  | 'boolean';

AnswerValue

type AnswerValue = string | number | boolean | string[];

RatingScale

interface RatingScale {
  min: number;
  max: number;
  step?: number;
  labels?: {
    min?: string;
    max?: string;
  };
  style?: 'numeric' | 'stars' | 'emoji';
}

SelectOption

interface SelectOption {
  value: string;
  label: string;
  disabled?: boolean;
}

SkipLogic

interface SkipLogic {
  questionId: string;
  condition: (answer: AnswerValue) => boolean;
  skipTo: string;
}

Scoring types

NPSResult

interface NPSResult {
  score: number;         // −100 to 100
  promoters: number;
  passives: number;
  detractors: number;
  promoterPct: number;
  passivePct: number;
  detractorPct: number;
  total: number;
  responses: number[];
}

CSATResult

interface CSATResult {
  score: number;         // 0–100 (percentage)
  positive: number;
  negative: number;
  total: number;
  threshold: number;
  responses: number[];
}

CESResult

interface CESResult {
  score: number;         // average response value
  easy: number;          // responses ≥ 5
  difficult: number;     // responses ≤ 3
  neutral: number;       // responses = 4
  total: number;
  responses: number[];
}

Context types

SurveysContextValue

interface SurveysContextValue {
  surveys: Map<string, SurveyState>;
  activeSurvey: string | null;
  queue: string[];
  register: (config: SurveyConfig) => void;
  unregister: (id: string) => void;
  show: (id: string) => void;
  hide: (id: string) => void;
  dismiss: (id: string, reason?: DismissalReason) => void;
  snooze: (id: string) => void;
  answer: (surveyId: string, questionId: string, value: AnswerValue) => void;
  nextQuestion: (surveyId: string) => void;
  prevQuestion: (surveyId: string) => void;
  complete: (surveyId: string) => void;
  reset: (id: string) => void;
  resetAll: () => void;
  getState: (id: string) => SurveyState | undefined;
  getConfig: (id: string) => SurveyConfig | undefined;
  canShow: (id: string) => boolean;
}

SurveysProviderProps

interface SurveysProviderProps {
  children: ReactNode;
  surveys?: SurveyConfig[];
  queueConfig?: Partial<SurveyQueueConfig>;
  storage?: Storage | null;
  storageKey?: string;
  userContext?: Record<string, unknown>;
  globalCooldownDays?: number;
  samplingRate?: number;
  maxPerSession?: number;
  onSurveyShow?: (id: string) => void;
  onSurveyDismiss?: (id: string, reason: DismissalReason) => void;
  onSurveyComplete?: (id: string, responses: Map<string, AnswerValue>) => void;
  onSurveyAnswer?: (surveyId: string, questionId: string, value: AnswerValue) => void;
  onSurveySnooze?: (id: string) => void;
  onQuestionAnswered?: (surveyId: string, questionId: string, value: AnswerValue) => void;
  onScoreCalculated?: (
    surveyId: string,
    scoreType: 'nps' | 'csat' | 'ces',
    result: NPSResult | CSATResult | CESResult
  ) => void;
}

Events types

SurveyEventType

type SurveyEventType =
  | 'survey_registered'
  | 'survey_shown'
  | 'survey_dismissed'
  | 'survey_snoozed'
  | 'survey_completed'
  | 'survey_question_answered'
  | 'survey_score_calculated';

BaseSurveyEvent

interface BaseSurveyEvent {
  type: SurveyEventType;
  surveyId: string;
  surveyType: SurveyType;
  displayMode: DisplayMode;
  timestamp: number;
  metadata?: Record<string, unknown>;
}

SurveyEvent (discriminated union)

type SurveyEvent =
  | SurveyShownEvent
  | SurveyDismissedEvent
  | SurveySnoozedEvent
  | SurveyCompletedEvent
  | SurveyQuestionAnsweredEvent
  | SurveyScoreCalculatedEvent;

Individual event shapes:

interface SurveyShownEvent extends BaseSurveyEvent {
  type: 'survey_shown';
  viewCount: number;
  fromQueue: boolean;
}

interface SurveyDismissedEvent extends BaseSurveyEvent {
  type: 'survey_dismissed';
  reason: DismissalReason;
  viewDuration: number;
}

interface SurveySnoozedEvent extends BaseSurveyEvent {
  type: 'survey_snoozed';
  snoozeCount: number;
  snoozeUntil: Date;
}

interface SurveyCompletedEvent extends BaseSurveyEvent {
  type: 'survey_completed';
  viewDuration: number;
  responses: Map<string, AnswerValue>;
  completionRate: number;   // 0–100
}

interface SurveyQuestionAnsweredEvent extends BaseSurveyEvent {
  type: 'survey_question_answered';
  questionId: string;
  questionType: QuestionType;
  stepIndex: number;
}

interface SurveyScoreCalculatedEvent extends BaseSurveyEvent {
  type: 'survey_score_calculated';
  scoreType: 'nps' | 'csat' | 'ces';
  score: number;
}

Queue types

SurveyQueueConfig

interface SurveyQueueConfig {
  maxConcurrent: number;                          // default: 1
  priorityOrder: PriorityOrder;                   // default: 'priority'
  stackBehavior: StackBehavior;                   // default: 'queue'
  delayBetween: number;                           // ms, default: 500
  priorityWeights: Record<SurveyPriority, number>; // critical: 1000, high: 100, normal: 10, low: 1
  autoShow: boolean;                              // default: true
}

PriorityOrder

type PriorityOrder = 'priority' | 'fifo' | 'lifo';

StackBehavior

type StackBehavior = 'queue' | 'replace' | 'stack';

SurveyQueueItem

interface SurveyQueueItem {
  id: string;
  priority: SurveyPriority;
  addedAt: number;
  weight: number;
  sequence: number;
}

Variant option types

ModalOptions

interface ModalOptions {
  size?: 'sm' | 'md' | 'lg';
  closeOnOverlayClick?: boolean;
  closeOnEscape?: boolean;
  showCloseButton?: boolean;
}

SlideoutOptions

interface SlideoutOptions {
  position?: SlideoutPosition;
  size?: 'sm' | 'md' | 'lg';
  closeOnOverlayClick?: boolean;
  closeOnEscape?: boolean;
  showCloseButton?: boolean;
}

BannerOptions

interface BannerOptions {
  position?: BannerPosition;
  sticky?: boolean;
  dismissable?: boolean;
  intent?: 'info' | 'feedback';
}

PopoverOptions

interface PopoverOptions {
  position?: PopoverPosition;
  offset?: number;
  showCloseButton?: boolean;
}

Position types

SlideoutPosition

type SlideoutPosition = 'left' | 'right';

BannerPosition

type BannerPosition = 'top' | 'bottom';

PopoverPosition

type PopoverPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';

Audience types

AudienceCondition

interface AudienceCondition {
  type: 'user_property' | 'segment' | 'feature_flag' | 'custom';
  key: string;
  operator:
    | 'equals'
    | 'not_equals'
    | 'contains'
    | 'not_contains'
    | 'in'
    | 'not_in'
    | 'exists'
    | 'not_exists';
  value?: unknown;
}

Component Props

The headless API exposes per-question render-prop callbacks (Question*RenderProps); the styled components below export their own Question*Props interfaces. Use the *Props types when wrapping or theming the styled components, and the *RenderProps types when building custom UI on top of the headless primitives.

QuestionRatingProps

interface QuestionRatingProps {
  id: string
  min?: number   // default 0
  max?: number   // default 10
  style?: 'numeric' | 'stars' | 'emoji'
  size?: 'sm' | 'md' | 'lg'
  value?: number | null
  onChange?: (value: number) => void
  label: string
  lowLabel?: string
  highLabel?: string
  isRequired?: boolean
  emojiMap?: Record<number, string>
  className?: string
}

QuestionTextProps

interface QuestionTextProps {
  id: string
  mode?: 'text' | 'textarea'
  value?: string
  onChange?: (value: string) => void
  placeholder?: string
  maxLength?: number
  showCharacterCount?: boolean
  rows?: number
  isRequired?: boolean
  label: string
  isAutoFocus?: boolean
  size?: 'sm' | 'md' | 'lg'
  className?: string
}

QuestionSelectProps

interface QuestionSelectProps {
  id: string
  mode?: 'single' | 'multi'
  options: SelectOption[]
  value?: string | string[]
  onChange?: (value: string | string[]) => void
  label: string
  isRequired?: boolean
  size?: 'sm' | 'md' | 'lg'
  className?: string
}

QuestionBooleanProps

interface QuestionBooleanProps {
  id: string
  value?: boolean | null
  onChange?: (value: boolean) => void
  label: string
  yesLabel?: string
  noLabel?: string
  isRequired?: boolean
  size?: 'sm' | 'md' | 'lg'
  className?: string
}

SurveyProgressProps

interface SurveyProgressProps {
  current: number
  total: number
  mode?: 'text' | 'bar' | 'both'
  labelTemplate?: string
  size?: 'sm' | 'md' | 'lg'
  className?: string
}