import { FC, ReactNode } from 'react'; type QuestionBase = { /** * Unique identifier for the question. */ id: string; /** * Type of the question, e.g. `freeform`, `single-choice`, `rating`. */ type: T; /** * Title of the question. May contain HTML. */ title: string; /** * Description of the question. May contain HTML. */ description: string; /** * When true, the user may skip this question without providing an answer. * Only applies to questions with user input: `freeform`, `single-choice`, `multiple-choice`, and `rating`. */ optional: boolean; }; type FreeformQuestion = QuestionBase<"freeform"> & { /** * Placeholder text for the freeform question input field, shown when the field is empty. */ placeholder: string; /** * Returns the current text value entered by the user for the freeform question, * or `undefined` if the field has not been filled in yet. */ getValue: () => string | undefined; /** * Sets the current text value for the freeform question. * @param value - The text to set as the current input value. */ setValue: (value: string) => void; }; type QuestionOption = { /** * Unique identifier for the option. Used to track selection state via the * `getSelectedOptionIds` and `setSelectedOptionIds` methods on choice question types. */ id: string; /** * Display label shown to the user for this option. */ label: string; }; type SingleChoiceQuestion = QuestionBase<"single-choice"> & { /** * Ordered list of available options for the single-choice question. */ options: QuestionOption[]; /** * When true, an additional "other" option should be rendered. Its label is provided in `otherLabel`. * When the user selects "other", also show a text input — use `getValue`/`setValue` for its value * and `getOtherSelected`/`setOtherSelected` to track whether it is selected. */ otherOption: boolean; /** * Label for the "other" option. Only relevant when `otherOption` is true. */ otherLabel: string; /** * Returns the currently selected option id as a single-element array, * or an empty array if no option is selected. * For single-choice questions, the array will never contain more than one id. */ getSelectedOptionIds: () => string[]; /** * Sets the currently selected option for the single-choice question. * Pass a single-element array with the option id to select it, or an empty array to deselect. * @param optionIds - Array containing zero or one option id. */ setSelectedOptionIds: (optionIds: string[]) => void; /** * Returns the current text entered in the "other" option input field, * or `undefined` if it has not been filled in. Only relevant when `otherOption` is true. */ getValue: () => string | undefined; /** * Sets the text value of the "other" option input field. Only relevant when `otherOption` is true. * @param value - The text to set as the current "other" input value. */ setValue: (value: string) => void; /** * Returns whether the "other" option is currently selected. Only relevant when `otherOption` is true. */ getOtherSelected: () => boolean; /** * Sets whether the "other" option is selected. Only relevant when `otherOption` is true. * @param selected - Pass `true` to select the "other" option, `false` to deselect it. */ setOtherSelected: (selected: boolean) => void; }; type MultipleChoiceQuestion = QuestionBase<"multiple-choice"> & { /** * Ordered list of available options for the multiple-choice question. */ options: QuestionOption[]; /** * When true, an additional "other" option should be rendered. Its label is provided in `otherLabel`. * When the user selects "other", also show a text input — use `getValue`/`setValue` for its value * and `getOtherSelected`/`setOtherSelected` to track whether it is selected. */ otherOption: boolean; /** * Label for the "other" option. Only relevant when `otherOption` is true. */ otherLabel: string; /** * Returns the ids of all currently selected options. * For multiple-choice questions, the array can contain zero or more option ids. */ getSelectedOptionIds: () => string[]; /** * Sets the currently selected options for the multiple-choice question. * Pass an array of option ids to select them, or an empty array to deselect all. * @param optionIds - Array of selected option ids. */ setSelectedOptionIds: (optionIds: string[]) => void; /** * Returns the current text entered in the "other" option input field, * or `undefined` if it has not been filled in. Only relevant when `otherOption` is true. */ getValue: () => string | undefined; /** * Sets the text value of the "other" option input field. Only relevant when `otherOption` is true. * @param value - The text to set as the current "other" input value. */ setValue: (value: string) => void; /** * Returns whether the "other" option is currently selected. Only relevant when `otherOption` is true. */ getOtherSelected: () => boolean; /** * Sets whether the "other" option is selected. Only relevant when `otherOption` is true. * @param selected - Pass `true` to select the "other" option, `false` to deselect it. */ setOtherSelected: (selected: boolean) => void; }; type RatingDisplayType = "numbers" | "stars" | "emojis"; type RatingQuestion = QuestionBase<"rating"> & { /** * Visual style of the rating buttons in the rating question. */ displayType: RatingDisplayType; /** * Minimum selectable value on the rating scale. */ minValue: number; /** * Maximum selectable value on the rating scale. */ maxValue: number; /** * Label shown at the low end of the rating scale, e.g. `"Not satisfied"`. */ lowerBoundLabel: string; /** * Label shown at the high end of the rating scale, e.g. `"Very satisfied"`. */ upperBoundLabel: string; /** * Returns the rating value currently selected by the user as a numeric string, * or `undefined` if no rating has been selected yet. * The value will be within the range defined by `minValue` and `maxValue`. * @returns e.g. `"2"` or `undefined` */ getValue: () => string | undefined; /** * Sets the currently selected rating value for the rating question. * The value must be a numeric string within the range defined by `minValue` and `maxValue`. * @param value - The rating value to select, e.g. `"3"`. */ setValue: (value: string) => void; }; type LinkQuestion = QuestionBase<"link"> & { /** * Display label for the clickable link shown in the link question. */ linkLabel: string; /** * URL the user is navigated to when they click the link. * Can be empty when the link question is used as an announcement only without navigation. */ url: string; /** * When true, the link opens in a new browser tab. */ openInNew: boolean; /** * Marks the link question as clicked. Call this when the user activates the link * so the interaction is recorded in the survey response. */ setClicked: () => void; }; type EndScreenQuestion = QuestionBase<"end-screen"> & { /** * Display label for the optional link shown on the end screen. */ linkLabel: string; /** * URL the user is navigated to when they click the link on the end screen. */ url: string; /** * When true, the link opens in a new browser tab. */ openInNew: boolean; }; type SurveyQuestion = FreeformQuestion | SingleChoiceQuestion | MultipleChoiceQuestion | RatingQuestion | LinkQuestion | EndScreenQuestion; type Survey = { /** * Ordered list of all questions in the survey. Use `getCurrentQuestionIndex` to determine * which question is currently active, and `nextQuestion`/`previousQuestion` to navigate between them. */ questions: SurveyQuestion[]; /** * Returns the zero-based index of the currently displayed question. * Use this to look up the active question in the `questions` array. * @returns Index of the current question, starting at `0`. */ getCurrentQuestionIndex: () => number; /** * Advances to the next question in the survey and returns the new index. * If the user is already on the last question, this method does nothing and returns the current index. * @returns New question index after advancing. */ nextQuestion: () => number; /** * Moves back to the previous question in the survey and returns the new index. * If the user is already on the first question, this method does nothing and returns the current index. * @returns New question index after moving back. */ previousQuestion: () => number; /** * Submits the survey response. The survey component remains visible after submission — * call the `complete` exit node method to close the survey block. * * Note: when using the `end-screen` question type with built-in navigation via `nextQuestion`, * the survey is submitted automatically when the user reaches the end screen. */ submit: () => Promise; }; /** * Properties provided by Flows based on block and block template setup. */ interface FlowsProperties { /** * Unique identifier of the block, useful for stable key during rendering. Keep in mind each workflow version will have a different id for each block. */ id: string; /** * User defined key for identifying the block. */ key?: string; /** * Id of the workflow this block belongs to. You can find it in the Flows app in the workflow detail by opening the three dot menu in the top right corner. */ workflowId: string; /** * Name of the component library this component block was created from. */ componentLibraryName?: string; /** * Total number of visible tour steps (components) in the current tour. Logic steps (e.g. wait) are not counted. */ tourVisibleStepCount?: number; /** * 0-based index of the currently visible tour step (component) in the current tour. Logic steps (e.g. wait) are not counted. */ tourVisibleStepIndex?: number; /** * Indicates whether the organization is a free organization. */ freeOrg: boolean; } type ComponentProps = any> = { /** * Properties provided by Flows based on block and block template setup. */ __flows: FlowsProperties; } & T; type TourComponentProps = any> = { /** * Properties provided by Flows based on block and block template setup. */ __flows: FlowsProperties; continue: () => void; previous?: () => void; cancel: () => void; } & T; type SurveyComponentProps = any> = { /** * Properties provided by Flows based on block and block template setup. */ __flows: FlowsProperties; /** * The survey object provided by Flows, containing information about the survey and functions to interact with it. */ survey: Survey; /** * Exits the survey block with `complete` exit node. */ complete: () => void; /** * Exits the survey block with `cancel` exit node. */ cancel: () => void; } & T; type StateMemoryTriggerType = "transition" | "manual"; interface StateMemoryTrigger { /** * Type of the trigger. */ type: StateMemoryTriggerType; /** * Id of the block that will set the state memory to true when it is exited. */ blockId?: string; /** * User defined key for identifying the tracked block. */ blockKey?: string; } /** * The object representing state memory property in your component properties. */ interface StateMemory { /** * Boolean value of the state memory property. */ value: boolean; /** * Update the state memory property. * @param value - new boolean value to set */ setValue: (value: boolean) => void; /** * Triggers you have setup in the workflow for this state memory property. */ triggers: StateMemoryTrigger[]; } /** * The object representing action property in your component properties. */ interface Action { /** * The label of the element used to trigger the action (eg. button text). */ label: string; /** * Optional URL to navigate to when the action is triggered. * When provided no special handling is done, you need to handle the navigation yourself using a link or similar. */ url?: string; /** * Optional flag to open the URL in a new tab. * When provided no special handling is done, you need to pass this to the element that will handle the navigation. */ openInNew?: boolean; /** * Function to call when the action is triggered. * Currently supports only transition to a specified exit node. */ callAction?: () => Promise; } /** * The object representing block state of the selected block in the workflow. * The properties of this object are the same as the properties of the block. */ type BlockState = any> = ComponentProps; type ActiveBlockBase = { /** * Unique identifier of the block. Useful as a stable `key` during rendering. * * Note: each workflow version assigns different ids to each block, so this value changes on workflow publish. */ id: string; /** * Discriminant that identifies the block variant. Use this to narrow the type and access type-safe `props`. * * - `"component"` — a standalone workflow block * - `"tour-component"` — a single step within a tour * - `"survey"` — a survey block */ type: T; /** * The key of the registered UI component used to render this block. * Must match a key registered in `FlowsProvider` (React) or `init` (JS). */ component: string; /** * Props to pass to the component. The exact shape depends on the block `type`: * * - `"component"` → `ComponentProps` * - `"tour-component"` → `TourComponentProps` — includes `continue`, `previous?`, and `cancel` * - `"survey"` → `SurveyComponentProps` — includes `survey`, `complete`, and `cancel` */ props: P; }; /** * An `ActiveBlock` representing a standalone workflow component block. * * Narrow to this type by checking `block.type === "component"`. */ type ComponentActiveBlock = ActiveBlockBase<"component", ComponentProps>>; /** * An `ActiveBlock` representing a single step within a tour. * * Narrow to this type by checking `block.type === "tour-component"`. */ type TourComponentActiveBlock = ActiveBlockBase<"tour-component", TourComponentProps>> & { /** * Unique identifier of the parent tour block this step belongs to. Useful as a stable `key` during rendering. * * Prefer this over `id` when rendering tour steps — reusing the same key across steps lets the browser * reuse the DOM element rather than unmounting and remounting it between individual steps. * * Note: each workflow version assigns different ids to each block, so this value changes on workflow publish. */ tourBlockId?: string; }; /** * An `ActiveBlock` representing a survey block. * * Narrow to this type by checking `block.type === "survey"`. */ type SurveyActiveBlock = ActiveBlockBase<"survey", SurveyComponentProps>>; /** * A block that is currently active and ready to render. * * Use `block.type` to narrow to a specific variant and access type-safe `props`: * * ```ts * if (block.type === "tour-component") { * // props is TourComponentProps — includes continue, previous?, cancel * block.props.continue(); * } * ``` * * @see {@link ComponentActiveBlock} for `"component"` blocks * @see {@link TourComponentActiveBlock} for `"tour-component"` blocks * @see {@link SurveyActiveBlock} for `"survey"` blocks */ type ActiveBlock = ComponentActiveBlock | TourComponentActiveBlock | SurveyActiveBlock; type CustomFetch = typeof globalThis.fetch; type LanguageOption = "disabled" | "automatic" | Locale; /** * Full list of supported locales coming from the browser `navigator.language`. Source: [https://www.localeplanet.com/icu/](https://www.localeplanet.com/icu/). */ type Locale = "af" | "af-NA" | "af-ZA" | "agq" | "agq-CM" | "ak" | "ak-GH" | "am" | "am-ET" | "ar" | "ar-001" | "ar-AE" | "ar-BH" | "ar-DJ" | "ar-DZ" | "ar-EG" | "ar-EH" | "ar-ER" | "ar-IL" | "ar-IQ" | "ar-JO" | "ar-KM" | "ar-KW" | "ar-LB" | "ar-LY" | "ar-MA" | "ar-MR" | "ar-OM" | "ar-PS" | "ar-QA" | "ar-SA" | "ar-SD" | "ar-SO" | "ar-SS" | "ar-SY" | "ar-TD" | "ar-TN" | "ar-YE" | "as" | "as-IN" | "asa" | "asa-TZ" | "ast" | "ast-ES" | "az" | "az-Cyrl" | "az-Cyrl-AZ" | "az-Latn" | "az-Latn-AZ" | "bas" | "bas-CM" | "be" | "be-BY" | "bem" | "bem-ZM" | "bez" | "bez-TZ" | "bg" | "bg-BG" | "bm" | "bm-ML" | "bn" | "bn-BD" | "bn-IN" | "bo" | "bo-CN" | "bo-IN" | "br" | "br-FR" | "brx" | "brx-IN" | "bs" | "bs-Cyrl" | "bs-Cyrl-BA" | "bs-Latn" | "bs-Latn-BA" | "ca" | "ca-AD" | "ca-ES" | "ca-FR" | "ca-IT" | "ccp" | "ccp-BD" | "ccp-IN" | "ce" | "ce-RU" | "cgg" | "cgg-UG" | "chr" | "chr-US" | "ckb" | "ckb-IQ" | "ckb-IR" | "cs" | "cs-CZ" | "cy" | "cy-GB" | "da" | "da-DK" | "da-GL" | "dav" | "dav-KE" | "de" | "de-AT" | "de-BE" | "de-CH" | "de-DE" | "de-IT" | "de-LI" | "de-LU" | "dje" | "dje-NE" | "dsb" | "dsb-DE" | "dua" | "dua-CM" | "dyo" | "dyo-SN" | "dz" | "dz-BT" | "ebu" | "ebu-KE" | "ee" | "ee-GH" | "ee-TG" | "el" | "el-CY" | "el-GR" | "en" | "en-001" | "en-150" | "en-AG" | "en-AI" | "en-AS" | "en-AT" | "en-AU" | "en-BB" | "en-BE" | "en-BI" | "en-BM" | "en-BS" | "en-BW" | "en-BZ" | "en-CA" | "en-CC" | "en-CH" | "en-CK" | "en-CM" | "en-CX" | "en-CY" | "en-DE" | "en-DG" | "en-DK" | "en-DM" | "en-ER" | "en-FI" | "en-FJ" | "en-FK" | "en-FM" | "en-GB" | "en-GD" | "en-GG" | "en-GH" | "en-GI" | "en-GM" | "en-GU" | "en-GY" | "en-HK" | "en-IE" | "en-IL" | "en-IM" | "en-IN" | "en-IO" | "en-JE" | "en-JM" | "en-KE" | "en-KI" | "en-KN" | "en-KY" | "en-LC" | "en-LR" | "en-LS" | "en-MG" | "en-MH" | "en-MO" | "en-MP" | "en-MS" | "en-MT" | "en-MU" | "en-MW" | "en-MY" | "en-NA" | "en-NF" | "en-NG" | "en-NL" | "en-NR" | "en-NU" | "en-NZ" | "en-PG" | "en-PH" | "en-PK" | "en-PN" | "en-PR" | "en-PW" | "en-RW" | "en-SB" | "en-SC" | "en-SD" | "en-SE" | "en-SG" | "en-SH" | "en-SI" | "en-SL" | "en-SS" | "en-SX" | "en-SZ" | "en-TC" | "en-TK" | "en-TO" | "en-TT" | "en-TV" | "en-TZ" | "en-UG" | "en-UM" | "en-US" | "en-US-POSIX" | "en-VC" | "en-VG" | "en-VI" | "en-VU" | "en-WS" | "en-ZA" | "en-ZM" | "en-ZW" | "eo" | "es" | "es-419" | "es-AR" | "es-BO" | "es-BR" | "es-BZ" | "es-CL" | "es-CO" | "es-CR" | "es-CU" | "es-DO" | "es-EA" | "es-EC" | "es-ES" | "es-GQ" | "es-GT" | "es-HN" | "es-IC" | "es-MX" | "es-NI" | "es-PA" | "es-PE" | "es-PH" | "es-PR" | "es-PY" | "es-SV" | "es-US" | "es-UY" | "es-VE" | "et" | "et-EE" | "eu" | "eu-ES" | "ewo" | "ewo-CM" | "fa" | "fa-AF" | "fa-IR" | "ff" | "ff-CM" | "ff-GN" | "ff-MR" | "ff-SN" | "fi" | "fi-FI" | "fil" | "fil-PH" | "fo" | "fo-DK" | "fo-FO" | "fr" | "fr-BE" | "fr-BF" | "fr-BI" | "fr-BJ" | "fr-BL" | "fr-CA" | "fr-CD" | "fr-CF" | "fr-CG" | "fr-CH" | "fr-CI" | "fr-CM" | "fr-DJ" | "fr-DZ" | "fr-FR" | "fr-GA" | "fr-GF" | "fr-GN" | "fr-GP" | "fr-GQ" | "fr-HT" | "fr-KM" | "fr-LU" | "fr-MA" | "fr-MC" | "fr-MF" | "fr-MG" | "fr-ML" | "fr-MQ" | "fr-MR" | "fr-MU" | "fr-NC" | "fr-NE" | "fr-PF" | "fr-PM" | "fr-RE" | "fr-RW" | "fr-SC" | "fr-SN" | "fr-SY" | "fr-TD" | "fr-TG" | "fr-TN" | "fr-VU" | "fr-WF" | "fr-YT" | "fur" | "fur-IT" | "fy" | "fy-NL" | "ga" | "ga-IE" | "gd" | "gd-GB" | "gl" | "gl-ES" | "gsw" | "gsw-CH" | "gsw-FR" | "gsw-LI" | "gu" | "gu-IN" | "guz" | "guz-KE" | "gv" | "gv-IM" | "ha" | "ha-GH" | "ha-NE" | "ha-NG" | "haw" | "haw-US" | "he" | "he-IL" | "hi" | "hi-IN" | "hr" | "hr-BA" | "hr-HR" | "hsb" | "hsb-DE" | "hu" | "hu-HU" | "hy" | "hy-AM" | "id" | "id-ID" | "ig" | "ig-NG" | "ii" | "ii-CN" | "is" | "is-IS" | "it" | "it-CH" | "it-IT" | "it-SM" | "it-VA" | "ja" | "ja-JP" | "jgo" | "jgo-CM" | "jmc" | "jmc-TZ" | "ka" | "ka-GE" | "kab" | "kab-DZ" | "kam" | "kam-KE" | "kde" | "kde-TZ" | "kea" | "kea-CV" | "khq" | "khq-ML" | "ki" | "ki-KE" | "kk" | "kk-KZ" | "kkj" | "kkj-CM" | "kl" | "kl-GL" | "kln" | "kln-KE" | "km" | "km-KH" | "kn" | "kn-IN" | "ko" | "ko-KP" | "ko-KR" | "kok" | "kok-IN" | "ks" | "ks-IN" | "ksb" | "ksb-TZ" | "ksf" | "ksf-CM" | "ksh" | "ksh-DE" | "kw" | "kw-GB" | "ky" | "ky-KG" | "lag" | "lag-TZ" | "lb" | "lb-LU" | "lg" | "lg-UG" | "lkt" | "lkt-US" | "ln" | "ln-AO" | "ln-CD" | "ln-CF" | "ln-CG" | "lo" | "lo-LA" | "lrc" | "lrc-IQ" | "lrc-IR" | "lt" | "lt-LT" | "lu" | "lu-CD" | "luo" | "luo-KE" | "luy" | "luy-KE" | "lv" | "lv-LV" | "mas" | "mas-KE" | "mas-TZ" | "mer" | "mer-KE" | "mfe" | "mfe-MU" | "mg" | "mg-MG" | "mgh" | "mgh-MZ" | "mgo" | "mgo-CM" | "mk" | "mk-MK" | "ml" | "ml-IN" | "mn" | "mn-MN" | "mr" | "mr-IN" | "ms" | "ms-BN" | "ms-MY" | "ms-SG" | "mt" | "mt-MT" | "mua" | "mua-CM" | "my" | "my-MM" | "mzn" | "mzn-IR" | "naq" | "naq-NA" | "nb" | "nb-NO" | "nb-SJ" | "nd" | "nd-ZW" | "nds" | "nds-DE" | "nds-NL" | "ne" | "ne-IN" | "ne-NP" | "nl" | "nl-AW" | "nl-BE" | "nl-BQ" | "nl-CW" | "nl-NL" | "nl-SR" | "nl-SX" | "nmg" | "nmg-CM" | "nn" | "nn-NO" | "nnh" | "nnh-CM" | "nus" | "nus-SS" | "nyn" | "nyn-UG" | "om" | "om-ET" | "om-KE" | "or" | "or-IN" | "os" | "os-GE" | "os-RU" | "pa" | "pa-Arab" | "pa-Arab-PK" | "pa-Guru" | "pa-Guru-IN" | "pl" | "pl-PL" | "ps" | "ps-AF" | "pt" | "pt-AO" | "pt-BR" | "pt-CH" | "pt-CV" | "pt-GQ" | "pt-GW" | "pt-LU" | "pt-MO" | "pt-MZ" | "pt-PT" | "pt-ST" | "pt-TL" | "qu" | "qu-BO" | "qu-EC" | "qu-PE" | "rm" | "rm-CH" | "rn" | "rn-BI" | "ro" | "ro-MD" | "ro-RO" | "rof" | "rof-TZ" | "ru" | "ru-BY" | "ru-KG" | "ru-KZ" | "ru-MD" | "ru-RU" | "ru-UA" | "rw" | "rw-RW" | "rwk" | "rwk-TZ" | "sah" | "sah-RU" | "saq" | "saq-KE" | "sbp" | "sbp-TZ" | "se" | "se-FI" | "se-NO" | "se-SE" | "seh" | "seh-MZ" | "ses" | "ses-ML" | "sg" | "sg-CF" | "shi" | "shi-Latn" | "shi-Latn-MA" | "shi-Tfng" | "shi-Tfng-MA" | "si" | "si-LK" | "sk" | "sk-SK" | "sl" | "sl-SI" | "smn" | "smn-FI" | "sn" | "sn-ZW" | "so" | "so-DJ" | "so-ET" | "so-KE" | "so-SO" | "sq" | "sq-AL" | "sq-MK" | "sq-XK" | "sr" | "sr-Cyrl" | "sr-Cyrl-BA" | "sr-Cyrl-ME" | "sr-Cyrl-RS" | "sr-Cyrl-XK" | "sr-Latn" | "sr-Latn-BA" | "sr-Latn-ME" | "sr-Latn-RS" | "sr-Latn-XK" | "sv" | "sv-AX" | "sv-FI" | "sv-SE" | "sw" | "sw-CD" | "sw-KE" | "sw-TZ" | "sw-UG" | "ta" | "ta-IN" | "ta-LK" | "ta-MY" | "ta-SG" | "te" | "te-IN" | "teo" | "teo-KE" | "teo-UG" | "tg" | "tg-TJ" | "th" | "th-TH" | "ti" | "ti-ER" | "ti-ET" | "to" | "to-TO" | "tr" | "tr-CY" | "tr-TR" | "tt" | "tt-RU" | "twq" | "twq-NE" | "tzm" | "tzm-MA" | "ug" | "ug-CN" | "uk" | "uk-UA" | "ur" | "ur-IN" | "ur-PK" | "uz" | "uz-Arab" | "uz-Arab-AF" | "uz-Cyrl" | "uz-Cyrl-UZ" | "uz-Latn" | "uz-Latn-UZ" | "vai" | "vai-Latn" | "vai-Latn-LR" | "vai-Vaii" | "vai-Vaii-LR" | "vi" | "vi-VN" | "vun" | "vun-TZ" | "wae" | "wae-CH" | "wo" | "wo-SN" | "xog" | "xog-UG" | "yav" | "yav-CM" | "yi" | "yi-001" | "yo" | "yo-BJ" | "yo-NG" | "yue" | "yue-Hans" | "yue-Hans-CN" | "yue-Hant" | "yue-Hant-HK" | "zgh" | "zgh-MA" | "zh" | "zh-Hans" | "zh-Hans-CN" | "zh-Hans-HK" | "zh-Hans-MO" | "zh-Hans-SG" | "zh-Hant" | "zh-Hant-HK" | "zh-Hant-MO" | "zh-Hant-TW" | "zu" | "zu-ZA"; interface LinkComponentProps { children?: ReactNode; href: string; className?: string; onClick?: () => void; } type LinkComponentType = FC; type UserProperties = Record; type WorkflowStatus = "enabled" | "launchpad-enabled"; type WorkflowFrequency = "once" | "every-time"; type WorkflowUserState = "not-started" | "in-progress" | "completed" | "stopped"; interface Workflow { /** * UUID of the workflow. You can find it in the Flows app in the workflow detail by opening the three dot menu. */ id: string; /** * How the workflow is currently enabled in Flows. Can be either: * - `enabled`: The workflow is published and active. * - `launchpad-enabled`: The workflow is published, active, and inside an active launchpad group. */ workflow_status: WorkflowStatus; /** * How often the workflow can be shown to the user. Can be either: * - `once`: The workflow can only be entered once. * - `every-time`: The workflow can be entered every time. */ frequency: WorkflowFrequency; /** * The user's current state in the workflow. Can be either: * - `not-started`: The user has not entered the workflow. * - `in-progress`: The user is currently in the workflow. * - `completed`: The user has completed the workflow. * - `stopped`: The user has been stopped the workflow (e.g., by a workflow migration). */ user_state: WorkflowUserState; /** * ISO string of when the user entered the workflow. */ entered_at?: string; /** * ISO string of when the user exited the workflow. */ exited_at?: string; } interface WorkflowsResponse { workflows: Workflow[]; } interface FlowsSlotProps { id: string; placeholder?: ReactNode; /** * Limit of how many blocks to render in this slot. Defaults to no limit. * * Useful when multiple blocks match the same slot. * * @default undefined */ limit?: number; } declare const FlowsSlot: FC; type Component = FC; type Components = Record; type TourComponent = FC; type TourComponents = Record; type SurveyComponent = FC; type SurveyComponents = Record; interface FlowsProviderProps { /** * Your organization ID. Find this in Settings \> General. */ organizationId: string; /** * The environment key. Find this in Settings \> Environments. */ environment: string; /** * Unique ID used to identify the user. * * If set to `null`, the SDK will be disabled and `children` will render while waiting for the `userId`. This is useful when loading the ID asynchronously. */ userId: string | null; /** * Object with custom [user properties](https://flows.sh/docs/users/properties). Values can be string, number, boolean, or date. * * When any of the property changes, the SDK will automatically refetch blocks to reflect the updated user properties. */ userProperties?: UserProperties; /** * Custom API URL useful when using proxy to send Flows requests through your own domain. */ apiUrl?: string; /** * Custom fetch implementation useful when you need to customize api requests with custom headers, credentials, etc. */ customFetch?: CustomFetch; /** * Components used for workflow blocks. */ components: Components; /** * Components used for tour blocks. */ tourComponents: TourComponents; /** * Components used for survey blocks. */ surveyComponents: SurveyComponents; /** * Language used to enable [localization](https://flows.sh/docs/localization). Based on the set language, the correct translation for the block data will be selected. * - `disabled` (default) - The user will be served content in the default language group of your organization. * - `automatic` - Automatically detect the user's language and use the matching language group. The language is determined by the `Navigator.language` property in the browser. * - Manual - A specific language string, e.g. `en-US`, `fr-FR`, etc. This will use the matching language group for the specified language. See [https://www.localeplanet.com/icu/](https://www.localeplanet.com/icu/) for a full list of supported languages. * @default "disabled" */ language?: LanguageOption; /** * Enables the debug panel. Can be also invoked by pressing `Cmd + Option + Shift + F` on Mac or `Ctrl + Alt + Shift + F` on Windows/Linux. * * Disabled by default. Defaults to `true` when running on `localhost`. * * Passing `false` here will NOT disable the shortcut. */ debug?: boolean; /** * Custom keyboard shortcut handler for opening the debug panel. * * By default, the debug panel opens with `Cmd + Option + Shift + F` on Mac or `Ctrl + Alt + Shift + F` on Windows/Linux. * * Use this function to customize the shortcut or disable it entirely. * * @param event - The `keydown` keyboard event to evaluate * @returns `true` to open the debug panel, `false` to ignore the shortcut * * @example * ```ts * // Disable debug panel shortcut * onDebugShortcut={() => false} * * // Use custom shortcut * onDebugShortcut={(e) => { * return e.ctrlKey && e.key === "c" * }} * ``` */ onDebugShortcut?: (event: KeyboardEvent) => boolean; /** * Custom Link component used for client-side navigation when using components from `@flows/react-components`. Otherwise each link click will result in a full page reload. * * Expects link component from your router, for example Link from "next/link". The LinkComponent should accept `href`, `className`, `onClick` and `children` props and render html `` element. * * The LinkComponent will be used for all URLs without domain and without "openInNew" (target="_blank"). * - `/about` - internal link, use LinkComponent * - `?search=test` - internal link, use LinkComponent * - `https://example.com` - external link, use standard `` element * - `/about` with `openInNew` - external link, use standard `` element with `target="_blank"` * * @example * ```tsx * import { Link } from "react-router"; * import { LinkComponentType } from "@flows/react"; * * // Adapt "react-router" Link to Flows LinkComponentType * const LinkComponent: LinkComponentType = ({ href, children, className, onClick }) => ( * * {children} * * ) * * // Pass the LinkComponent to FlowsProvider * * ``` */ LinkComponent?: LinkComponentType; children: ReactNode; } declare const FlowsProvider: FC; /** * Get all the currently displayed workflow and tour blocks that are not slottable. * @returns array of `ActiveBlock` objects */ declare const useCurrentFloatingBlocks: () => ActiveBlock[]; /** * Get all the currently displayed workflow and tour blocks for a specific slot. * @param slotId - the slot id to get the blocks for * @returns array of `ActiveBlock` objects */ declare const useCurrentSlotBlocks: (slotId: string) => ActiveBlock[]; /** * Returns all available workflows for the current user. Before calling this method, the `` component must be rendered. * @returns A promise resolving to a {@link WorkflowsResponse} object containing an array of enabled workflows. */ declare const fetchWorkflows: () => Promise; /** * Reset progress for all workflows for the current user in the current environment. */ declare const resetAllWorkflowsProgress: () => Promise; /** * Reset progress of one workflow for the current user in the current environment. * @param workflowId - UUID of the workflow to reset. You can find it in the Flows app in the workflow detail by opening the three dot menu in the top right corner. */ declare const resetWorkflowProgress: (workflowId: string) => Promise; /** * Start a workflow from a manual start block. The workflow will only start if: * - Workflow is published in the current environment * - Workflow has a manual start block with a matching block key * - The current user can access the workflow based on the frequency setting * - The current user matches the start block's user property conditions * @param blockKey - block key of the manual start block */ declare const startWorkflow: (blockKey: string) => Promise; interface Props { block: ActiveBlock; } /** * Renders a single `ActiveBlock` using the matching component from `components`, `tourComponents`, or `surveyComponents` registered in `FlowsProvider`. * * `ActiveBlock` can be obtained from `useCurrentFloatingBlocks` or `useCurrentSlotBlocks`. * * Useful for advanced block rendering implementations. */ declare const Block: FC; export { type Action, type ActiveBlock, Block, type BlockState, type ComponentActiveBlock, type ComponentProps, type CustomFetch, type EndScreenQuestion, type FlowsProperties, FlowsProvider, FlowsSlot, type FlowsSlotProps, type FreeformQuestion, type LanguageOption, type LinkComponentProps, type LinkComponentType, type LinkQuestion, type Locale, type MultipleChoiceQuestion, type RatingQuestion, type SingleChoiceQuestion, type StateMemory, type Survey, type SurveyActiveBlock, type SurveyComponentProps, type SurveyQuestion, type TourComponentActiveBlock, type TourComponentProps, type Workflow, type WorkflowFrequency, type WorkflowStatus, type WorkflowUserState, fetchWorkflows, resetAllWorkflowsProgress, resetWorkflowProgress, startWorkflow, useCurrentFloatingBlocks, useCurrentSlotBlocks };