From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../aboutwelcome/content/aboutwelcome.bundle.js | 2678 ++++++++++++++++++++ 1 file changed, 2678 insertions(+) create mode 100644 browser/components/aboutwelcome/content/aboutwelcome.bundle.js (limited to 'browser/components/aboutwelcome/content/aboutwelcome.bundle.js') diff --git a/browser/components/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/aboutwelcome/content/aboutwelcome.bundle.js new file mode 100644 index 0000000000..cb4e9004f8 --- /dev/null +++ b/browser/components/aboutwelcome/content/aboutwelcome.bundle.js @@ -0,0 +1,2678 @@ +/*! + * + * NOTE: This file is generated by webpack from aboutwelcome.jsx + * using the npm bundle task. + * + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/***/ ((module) => { + +module.exports = React; + +/***/ }), +/* 2 */ +/***/ ((module) => { + +module.exports = ReactDOM; + +/***/ }), +/* 3 */ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "AboutWelcomeUtils": () => (/* binding */ AboutWelcomeUtils), +/* harmony export */ "DEFAULT_RTAMO_CONTENT": () => (/* binding */ DEFAULT_RTAMO_CONTENT) +/* harmony export */ }); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// If the container has a "page" data attribute, then this is +// a Spotlight modal or Feature Callout. Otherwise, this is +// about:welcome and we should return the current page. +const page = + document.querySelector( + "#multi-stage-message-root.onboardingContainer[data-page]" + )?.dataset.page || document.location.href; + +const AboutWelcomeUtils = { + handleUserAction(action) { + return window.AWSendToParent("SPECIAL_ACTION", action); + }, + sendImpressionTelemetry(messageId, context) { + window.AWSendEventTelemetry?.({ + event: "IMPRESSION", + event_context: { + ...context, + page, + }, + message_id: messageId, + }); + }, + sendActionTelemetry(messageId, elementId, eventName = "CLICK_BUTTON") { + const ping = { + event: eventName, + event_context: { + source: elementId, + page, + }, + message_id: messageId, + }; + window.AWSendEventTelemetry?.(ping); + }, + sendDismissTelemetry(messageId, elementId) { + // Don't send DISMISS telemetry in spotlight modals since they already send + // their own equivalent telemetry. + if (page !== "spotlight") { + this.sendActionTelemetry(messageId, elementId, "DISMISS"); + } + }, + async fetchFlowParams(metricsFlowUri) { + let flowParams; + try { + const response = await fetch(metricsFlowUri, { + credentials: "omit", + }); + if (response.status === 200) { + const { deviceId, flowId, flowBeginTime } = await response.json(); + flowParams = { deviceId, flowId, flowBeginTime }; + } else { + console.error("Non-200 response", response); + } + } catch (e) { + flowParams = null; + } + return flowParams; + }, + sendEvent(type, detail) { + document.dispatchEvent( + new CustomEvent(`AWPage:${type}`, { + bubbles: true, + detail, + }) + ); + }, + getLoadingStrategyFor(url) { + return url?.startsWith("http") ? "lazy" : "eager"; + }, +}; + +const DEFAULT_RTAMO_CONTENT = { + template: "return_to_amo", + utm_term: "rtamo", + content: { + position: "split", + title: { string_id: "mr1-return-to-amo-subtitle" }, + has_noodles: false, + subtitle: { + string_id: "mr1-return-to-amo-addon-title", + }, + backdrop: + "var(--mr-welcome-background-color) var(--mr-welcome-background-gradient)", + background: + "url('chrome://activity-stream/content/data/content/assets/mr-rtamo-background-image.svg') no-repeat center", + progress_bar: true, + primary_button: { + label: { string_id: "mr1-return-to-amo-add-extension-label" }, + source_id: "ADD_EXTENSION_BUTTON", + action: { + type: "INSTALL_ADDON_FROM_URL", + data: { url: null, telemetrySource: "rtamo" }, + }, + }, + secondary_button: { + label: { + string_id: "onboarding-not-now-button-label", + }, + source_id: "RTAMO_START_BROWSING_BUTTON", + action: { + type: "OPEN_AWESOME_BAR", + }, + }, + secondary_button_top: { + label: { + string_id: "mr1-onboarding-sign-in-button-label", + }, + source_id: "RTAMO_FXA_SIGNIN_BUTTON", + action: { + data: { + entrypoint: "activity-stream-firstrun", + where: "tab", + }, + type: "SHOW_FIREFOX_ACCOUNTS", + addFlowParams: true, + }, + }, + }, +}; + + +/***/ }), +/* 4 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "MultiStageAboutWelcome": () => (/* binding */ MultiStageAboutWelcome), +/* harmony export */ "SecondaryCTA": () => (/* binding */ SecondaryCTA), +/* harmony export */ "StepsIndicator": () => (/* binding */ StepsIndicator), +/* harmony export */ "ProgressBar": () => (/* binding */ ProgressBar), +/* harmony export */ "WelcomeScreen": () => (/* binding */ WelcomeScreen) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3); +/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6); +/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10); +/* harmony import */ var _SubmenuButton__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(15); +/* harmony import */ var _lib_addUtmParams_mjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + + + + + + +// Amount of milliseconds for all transitions to complete (including delays). +const TRANSITION_OUT_TIME = 1000; +const LANGUAGE_MISMATCH_SCREEN_ID = "AW_LANGUAGE_MISMATCH"; +const MultiStageAboutWelcome = props => { + let { + defaultScreens + } = props; + const didFilter = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(false); + const [didMount, setDidMount] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false); + const [screens, setScreens] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(defaultScreens); + const [index, setScreenIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(props.startScreen); + const [previousOrder, setPreviousOrder] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(props.startScreen - 1); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + (async () => { + // If we want to load index from history state, we don't want to send impression yet + if (!didMount) { + return; + } + // On about:welcome first load, screensVisited should be empty + let screensVisited = didFilter.current ? screens.slice(0, index) : []; + let upcomingScreens = defaultScreens.filter(s => !screensVisited.find(v => v.id === s.id)) + // Filter out Language Mismatch screen from upcoming + // screens if screens set from useLanguageSwitcher hook + // has filtered language screen + .filter(upcomingScreen => !(!screens.find(s => s.id === LANGUAGE_MISMATCH_SCREEN_ID) && upcomingScreen.id === LANGUAGE_MISMATCH_SCREEN_ID)); + let filteredScreens = screensVisited.concat((await window.AWEvaluateScreenTargeting(upcomingScreens)) ?? upcomingScreens); + + // Use existing screen for the filtered screen to carry over any modification + // e.g. if AW_LANGUAGE_MISMATCH exists, use it from existing screens + setScreens(filteredScreens.map(filtered => screens.find(s => s.id === filtered.id) ?? filtered)); + didFilter.current = true; + const screenInitials = filteredScreens.map(({ + id + }) => id?.split("_")[1]?.[0]).join(""); + // Send impression ping when respective screen first renders + filteredScreens.forEach((screen, order) => { + if (index === order) { + const messageId = `${props.message_id}_${order}_${screen.id}_${screenInitials}`; + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendImpressionTelemetry(messageId, { + screen_family: props.message_id, + screen_index: order, + screen_id: screen.id, + screen_initials: screenInitials + }); + window.AWAddScreenImpression?.(screen); + } + }); + + // Remember that a new screen has loaded for browser navigation + if (props.updateHistory && index > window.history.state) { + window.history.pushState(index, ""); + } + + // Remember the previous screen index so we can animate the transition + setPreviousOrder(index); + })(); + }, [index, didMount]); // eslint-disable-line react-hooks/exhaustive-deps + + const [flowParams, setFlowParams] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null); + const { + metricsFlowUri + } = props; + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + (async () => { + if (metricsFlowUri) { + setFlowParams(await _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.fetchFlowParams(metricsFlowUri)); + } + })(); + }, [metricsFlowUri]); + + // Allow "in" style to render to actually transition towards regular state, + // which also makes using browser back/forward navigation skip transitions. + const [transition, setTransition] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(props.transitions ? "in" : ""); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (transition === "in") { + requestAnimationFrame(() => requestAnimationFrame(() => setTransition(""))); + } + }, [transition]); + + // Transition to next screen, opening about:home on last screen button CTA + const handleTransition = () => { + // Only handle transitioning out from a screen once. + if (transition === "out") { + return; + } + + // Start transitioning things "out" immediately when moving forwards. + setTransition(props.transitions ? "out" : ""); + + // Actually move forwards after all transitions finish. + setTimeout(() => { + if (index < screens.length - 1) { + setTransition(props.transitions ? "in" : ""); + setScreenIndex(prevState => prevState + 1); + } else { + window.AWFinish(); + } + }, props.transitions ? TRANSITION_OUT_TIME : 0); + }; + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + // When about:welcome loads (on refresh or pressing back button + // from about:home), ensure history state usEffect runs before + // useEffect hook that send impression telemetry + setDidMount(true); + if (props.updateHistory) { + // Switch to the screen tracked in state (null for initial state) + // or last screen index if a user navigates by pressing back + // button from about:home + const handler = ({ + state + }) => { + if (transition === "out") { + return; + } + setTransition(props.transitions ? "out" : ""); + setTimeout(() => { + setTransition(props.transitions ? "in" : ""); + setScreenIndex(Math.min(state, screens.length - 1)); + }, props.transitions ? TRANSITION_OUT_TIME : 0); + }; + + // Handle page load, e.g., going back to about:welcome from about:home + const { + state + } = window.history; + if (state) { + setScreenIndex(Math.min(state, screens.length - 1)); + setPreviousOrder(Math.min(state, screens.length - 1)); + } + + // Watch for browser back/forward button navigation events + window.addEventListener("popstate", handler); + return () => window.removeEventListener("popstate", handler); + } + return false; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const [multiSelects, setMultiSelects] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({}); + + // Save the active multi select state for each screen as an object keyed by + // screen id. Each screen id has an array containing checkbox ids used in + // handleAction to update MULTI_ACTION data. This allows us to remember the + // state of each screen's multi select checkboxes when navigating back and + // forth between screens, while also allowing a message to have more than one + // multi select screen. + const [activeMultiSelects, setActiveMultiSelects] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({}); + + // Get the active theme so the rendering code can make it selected + // by default. + const [activeTheme, setActiveTheme] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null); + const [initialTheme, setInitialTheme] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + (async () => { + let theme = await window.AWGetSelectedTheme(); + setInitialTheme(theme); + setActiveTheme(theme); + })(); + }, []); + const { + negotiatedLanguage, + langPackInstallPhase, + languageFilteredScreens + } = (0,_LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__.useLanguageSwitcher)(props.appAndSystemLocaleInfo, screens, index, setScreenIndex); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + setScreens(languageFilteredScreens); + }, [languageFilteredScreens]); + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `outer-wrapper onboardingContainer proton transition-${transition}`, + style: props.backdrop ? { + background: props.backdrop + } : {} + }, screens.map((screen, order) => { + const isFirstScreen = screen === screens[0]; + const isLastScreen = screen === screens[screens.length - 1]; + const totalNumberOfScreens = screens.length; + const isSingleScreen = totalNumberOfScreens === 1; + const setActiveMultiSelect = valueOrFn => setActiveMultiSelects(prevState => ({ + ...prevState, + [screen.id]: typeof valueOrFn === "function" ? valueOrFn(prevState[screen.id]) : valueOrFn + })); + const setScreenMultiSelects = valueOrFn => setMultiSelects(prevState => ({ + ...prevState, + [screen.id]: typeof valueOrFn === "function" ? valueOrFn(prevState[screen.id]) : valueOrFn + })); + return index === order ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(WelcomeScreen, { + key: screen.id + order, + id: screen.id, + totalNumberOfScreens: totalNumberOfScreens, + isFirstScreen: isFirstScreen, + isLastScreen: isLastScreen, + isSingleScreen: isSingleScreen, + order: order, + previousOrder: previousOrder, + content: screen.content, + navigate: handleTransition, + messageId: `${props.message_id}_${order}_${screen.id}`, + UTMTerm: props.utm_term, + flowParams: flowParams, + activeTheme: activeTheme, + initialTheme: initialTheme, + setActiveTheme: setActiveTheme, + setInitialTheme: setInitialTheme, + screenMultiSelects: multiSelects[screen.id], + setScreenMultiSelects: setScreenMultiSelects, + activeMultiSelect: activeMultiSelects[screen.id], + setActiveMultiSelect: setActiveMultiSelect, + autoAdvance: screen.auto_advance, + negotiatedLanguage: negotiatedLanguage, + langPackInstallPhase: langPackInstallPhase, + forceHideStepsIndicator: screen.force_hide_steps_indicator, + ariaRole: props.ariaRole, + aboveButtonStepsIndicator: screen.above_button_steps_indicator + }) : null; + }))); +}; +const SecondaryCTA = props => { + const targetElement = props.position ? `secondary_button_${props.position}` : `secondary_button`; + let buttonStyling = props.content.secondary_button?.has_arrow_icon ? `secondary arrow-icon` : `secondary`; + const isPrimary = props.content.secondary_button?.style === "primary"; + const isTextLink = !["split", "callout"].includes(props.content.position) && props.content.tiles?.type !== "addons-picker" && !isPrimary; + const isSplitButton = props.content.submenu_button?.attached_to === targetElement; + let className = "secondary-cta"; + if (props.position) { + className += ` ${props.position}`; + } + if (isSplitButton) { + className += " split-button-container"; + } + const isDisabled = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(disabledValue => disabledValue === "hasActiveMultiSelect" ? !(props.activeMultiSelect?.length > 0) : disabledValue, [props.activeMultiSelect?.length]); + if (isTextLink) { + buttonStyling += " text-link"; + } + if (isPrimary) { + buttonStyling = props.content.secondary_button?.has_arrow_icon ? `primary arrow-icon` : `primary`; + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: className + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: props.content[targetElement].text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: props.content[targetElement].label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: buttonStyling, + value: targetElement, + disabled: isDisabled(props.content.secondary_button?.disabled), + onClick: props.handleAction + })), isSplitButton ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_SubmenuButton__WEBPACK_IMPORTED_MODULE_5__.SubmenuButton, { + content: props.content, + handleAction: props.handleAction + }) : null); +}; +const StepsIndicator = props => { + let steps = []; + for (let i = 0; i < props.totalNumberOfScreens; i++) { + let className = `${i === props.order ? "current" : ""} ${i < props.order ? "complete" : ""}`; + steps.push( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + key: i, + className: `indicator ${className}`, + role: "presentation" + })); + } + return steps; +}; +const ProgressBar = ({ + step, + previousStep, + totalNumberOfScreens +}) => { + const [progress, setProgress] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(previousStep / totalNumberOfScreens); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + // We don't need to hook any dependencies because any time the step changes, + // the screen's entire DOM tree will be re-rendered. + setProgress(step / totalNumberOfScreens); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "indicator", + role: "presentation", + style: { + "--progress-bar-progress": `${progress * 100}%` + } + }); +}; +class WelcomeScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { + constructor(props) { + super(props); + this.handleAction = this.handleAction.bind(this); + } + handleOpenURL(action, flowParams, UTMTerm) { + let { + type, + data + } = action; + if (type === "SHOW_FIREFOX_ACCOUNTS") { + let params = { + ..._lib_addUtmParams_mjs__WEBPACK_IMPORTED_MODULE_6__.BASE_PARAMS, + utm_term: `${UTMTerm}-screen` + }; + if (action.addFlowParams && flowParams) { + params = { + ...params, + ...flowParams + }; + } + data = { + ...data, + extraParams: params + }; + } else if (type === "OPEN_URL") { + let url = new URL(data.args); + (0,_lib_addUtmParams_mjs__WEBPACK_IMPORTED_MODULE_6__.addUtmParams)(url, `${UTMTerm}-screen`); + if (action.addFlowParams && flowParams) { + url.searchParams.append("device_id", flowParams.deviceId); + url.searchParams.append("flow_id", flowParams.flowId); + url.searchParams.append("flow_begin_time", flowParams.flowBeginTime); + } + data = { + ...data, + args: url.toString() + }; + } + return _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.handleUserAction({ + type, + data + }); + } + async handleAction(event) { + let { + props + } = this; + const value = event.currentTarget.value ?? event.currentTarget.getAttribute("value"); + const source = event.source || value; + let targetContent = props.content[value] || props.content.tiles || props.content.languageSwitcher; + if (value === "submenu_button" && event.action) { + targetContent = { + action: event.action + }; + } + if (!(targetContent && targetContent.action)) { + return; + } + // Send telemetry before waiting on actions + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, source, event.name); + + // Send additional telemetry if a messaging surface like feature callout is + // dismissed via the dismiss button. Other causes of dismissal will be + // handled separately by the messaging surface's own code. + if (value === "dismiss_button" && !event.name) { + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendDismissTelemetry(props.messageId, source); + } + let { + action + } = targetContent; + action = JSON.parse(JSON.stringify(action)); + if (action.collectSelect) { + this.setMultiSelectActions(action); + } + let actionResult; + if (["OPEN_URL", "SHOW_FIREFOX_ACCOUNTS"].includes(action.type)) { + actionResult = await this.handleOpenURL(action, props.flowParams, props.UTMTerm); + } else if (action.type) { + actionResult = await _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.handleUserAction(action); + if (action.type === "FXA_SIGNIN_FLOW") { + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, actionResult ? "sign_in" : "sign_in_cancel", "FXA_SIGNIN_FLOW"); + } + // Wait until migration closes to complete the action + const hasMigrate = a => a.type === "SHOW_MIGRATION_WIZARD" || a.type === "MULTI_ACTION" && a.data?.actions?.some(hasMigrate); + if (hasMigrate(action)) { + await window.AWWaitForMigrationClose(); + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, "migrate_close"); + } + } + + // A special tiles.action.theme value indicates we should use the event's value vs provided value. + if (action.theme) { + let themeToUse = action.theme === "" ? event.currentTarget.value : this.props.initialTheme || action.theme; + this.props.setActiveTheme(themeToUse); + window.AWSelectTheme(themeToUse); + } + + // If the action has persistActiveTheme: true, we set the initial theme to the currently active theme + // so that it can be reverted to in the event that the user navigates away from the screen + if (action.persistActiveTheme) { + this.props.setInitialTheme(this.props.activeTheme); + } + + // `navigate` and `dismiss` can be true/false/undefined, or they can be a + // string "actionResult" in which case we should use the actionResult + // (boolean resolved by handleUserAction) + const shouldDoBehavior = behavior => behavior === "actionResult" ? actionResult : behavior; + if (shouldDoBehavior(action.navigate)) { + props.navigate(); + } + if (shouldDoBehavior(action.dismiss)) { + window.AWFinish(); + } + } + setMultiSelectActions(action) { + let { + props + } = this; + // Populate MULTI_ACTION data actions property with selected checkbox + // actions from tiles data + if (action.type !== "MULTI_ACTION") { + console.error("collectSelect is only supported for MULTI_ACTION type actions"); + action.type = "MULTI_ACTION"; + } + if (!Array.isArray(action.data?.actions)) { + console.error("collectSelect is only supported for MULTI_ACTION type actions with an array of actions"); + action.data = { + actions: [] + }; + } + + // Prepend the multi-select actions to the CTA's actions array, but keep + // the actions in the same order they appear in. This way the CTA action + // can go last, after the multi-select actions are processed. For example, + // 1. checkbox action 1 + // 2. checkbox action 2 + // 3. radio action + // 4. CTA action (which perhaps depends on the radio action) + let multiSelectActions = []; + for (const checkbox of props.content?.tiles?.data ?? []) { + let checkboxAction; + if (props.activeMultiSelect?.includes(checkbox.id)) { + checkboxAction = checkbox.checkedAction ?? checkbox.action; + } else { + checkboxAction = checkbox.uncheckedAction; + } + if (checkboxAction) { + multiSelectActions.push(checkboxAction); + } + } + action.data.actions.unshift(...multiSelectActions); + + // Send telemetry with selected checkbox ids + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, props.activeMultiSelect, "SELECT_CHECKBOX"); + } + render() { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_3__.MultiStageProtonScreen, { + content: this.props.content, + id: this.props.id, + order: this.props.order, + previousOrder: this.props.previousOrder, + activeTheme: this.props.activeTheme, + screenMultiSelects: this.props.screenMultiSelects, + setScreenMultiSelects: this.props.setScreenMultiSelects, + activeMultiSelect: this.props.activeMultiSelect, + setActiveMultiSelect: this.props.setActiveMultiSelect, + totalNumberOfScreens: this.props.totalNumberOfScreens, + appAndSystemLocaleInfo: this.props.appAndSystemLocaleInfo, + negotiatedLanguage: this.props.negotiatedLanguage, + langPackInstallPhase: this.props.langPackInstallPhase, + handleAction: this.handleAction, + messageId: this.props.messageId, + isFirstScreen: this.props.isFirstScreen, + isLastScreen: this.props.isLastScreen, + isSingleScreen: this.props.isSingleScreen, + startsWithCorner: this.props.startsWithCorner, + autoAdvance: this.props.autoAdvance, + forceHideStepsIndicator: this.props.forceHideStepsIndicator, + ariaRole: this.props.ariaRole, + aboveButtonStepsIndicator: this.props.aboveButtonStepsIndicator + }); + } +} + +/***/ }), +/* 5 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "CONFIGURABLE_STYLES": () => (/* binding */ CONFIGURABLE_STYLES), +/* harmony export */ "Localized": () => (/* binding */ Localized) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +const CONFIGURABLE_STYLES = ["color", "fontSize", "fontWeight", "letterSpacing", "lineHeight", "marginBlock", "marginInline", "paddingBlock", "paddingInline", "whiteSpace"]; +const ZAP_SIZE_THRESHOLD = 160; + +/** + * Based on the .text prop, localizes an inner element if a string_id + * is provided, OR renders plain text, OR hides it if nothing is provided. + * Allows configuring of some styles including zap underline and color. + * + * Examples: + * + * Localized text + * ftl: + * title = Welcome + * jsx: + *

+ * output: + *

Welcome

+ * + * Unlocalized text + * jsx: + *

+ *

+ * output: + *

Welcome

+ */ + +const Localized = ({ + text, + children +}) => { + // Dynamically determine the size of the zap style. + const zapRef = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + const { + current + } = zapRef; + if (current) { + requestAnimationFrame(() => current?.classList.replace("short", current.getBoundingClientRect().width > ZAP_SIZE_THRESHOLD ? "long" : "short")); + } + }); + + // Skip rendering of children with no text. + if (!text) { + return null; + } + + // Allow augmenting existing child container properties. + const props = { + children: [], + className: "", + style: {}, + ...children?.props + }; + // Support nested Localized by starting with their children. + const textNodes = Array.isArray(props.children) ? props.children : [props.children]; + + // Pick desired fluent or raw/plain text to render. + if (text.string_id) { + // Set the key so React knows not to reuse when switching to plain text. + props.key = text.string_id; + props["data-l10n-id"] = text.string_id; + if (text.args) { + props["data-l10n-args"] = JSON.stringify(text.args); + } + } else if (text.raw) { + textNodes.push(text.raw); + } else if (typeof text === "string") { + textNodes.push(text); + } + + // Add zap style and content in a way that allows fluent to insert too. + if (text.zap) { + props.className += " welcomeZap"; + textNodes.push( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { + className: "short zap", + "data-l10n-name": "zap", + ref: zapRef + }, text.zap)); + } + if (text.aria_label) { + props["aria-label"] = text.aria_label; + } + + // Apply certain configurable styles. + CONFIGURABLE_STYLES.forEach(style => { + if (text[style] !== undefined) { + props.style[style] = text[style]; + } + }); + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().cloneElement( + // Provide a default container for the text if necessary. + children ?? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null), props, + // Conditionally pass in as void elements can't accept empty array. + textNodes.length ? textNodes : null); +}; + +/***/ }), +/* 6 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "MultiStageProtonScreen": () => (/* binding */ MultiStageProtonScreen), +/* harmony export */ "ProtonScreenActionButtons": () => (/* binding */ ProtonScreenActionButtons), +/* harmony export */ "ProtonScreen": () => (/* binding */ ProtonScreen) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3); +/* harmony import */ var _MobileDownloads__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7); +/* harmony import */ var _MultiSelect__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8); +/* harmony import */ var _Themes__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9); +/* harmony import */ var _MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4); +/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(10); +/* harmony import */ var _CTAParagraph__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(11); +/* harmony import */ var _HeroImage__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(12); +/* harmony import */ var _OnboardingVideo__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(13); +/* harmony import */ var _AdditionalCTA__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(14); +/* harmony import */ var _EmbeddedMigrationWizard__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(16); +/* harmony import */ var _AddonsPicker__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(17); +/* harmony import */ var _LinkParagraph__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(18); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + + + + + + + + + + + + + +const MultiStageProtonScreen = props => { + const { + autoAdvance, + handleAction, + order + } = props; + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (autoAdvance) { + const timer = setTimeout(() => { + handleAction({ + currentTarget: { + value: autoAdvance + }, + name: "AUTO_ADVANCE" + }); + }, 20000); + return () => clearTimeout(timer); + } + return () => {}; + }, [autoAdvance, handleAction, order]); + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ProtonScreen, { + content: props.content, + id: props.id, + order: props.order, + activeTheme: props.activeTheme, + screenMultiSelects: props.screenMultiSelects, + setScreenMultiSelects: props.setScreenMultiSelects, + activeMultiSelect: props.activeMultiSelect, + setActiveMultiSelect: props.setActiveMultiSelect, + totalNumberOfScreens: props.totalNumberOfScreens, + handleAction: props.handleAction, + isFirstScreen: props.isFirstScreen, + isLastScreen: props.isLastScreen, + isSingleScreen: props.isSingleScreen, + previousOrder: props.previousOrder, + autoAdvance: props.autoAdvance, + isRtamo: props.isRtamo, + addonName: props.addonName, + isTheme: props.isTheme, + iconURL: props.iconURL, + messageId: props.messageId, + negotiatedLanguage: props.negotiatedLanguage, + langPackInstallPhase: props.langPackInstallPhase, + forceHideStepsIndicator: props.forceHideStepsIndicator, + ariaRole: props.ariaRole, + aboveButtonStepsIndicator: props.aboveButtonStepsIndicator + }); +}; +const ProtonScreenActionButtons = props => { + const { + content, + addonName, + activeMultiSelect + } = props; + const defaultValue = content.checkbox?.defaultValue; + const [isChecked, setIsChecked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(defaultValue || false); + const buttonRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); + const shouldFocusButton = content?.primary_button?.should_focus_button; + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (shouldFocusButton) { + buttonRef.current?.focus(); + } + }, [shouldFocusButton]); + if (!content.primary_button && !content.secondary_button && !content.additional_button) { + return null; + } + + // If we have a multi-select screen, we want to disable the primary button + // until the user has selected at least one item. + const isPrimaryDisabled = primaryDisabledValue => primaryDisabledValue === "hasActiveMultiSelect" ? !(activeMultiSelect?.length > 0) : primaryDisabledValue; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `action-buttons ${content.additional_button ? "additional-cta-container" : ""}`, + flow: content.additional_button?.flow, + alignment: content.additional_button?.alignment + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.primary_button?.label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + ref: buttonRef, + className: `${content.primary_button?.style ?? "primary"}${content.primary_button?.has_arrow_icon ? " arrow-icon" : ""}` + // Whether or not the checkbox is checked determines which action + // should be handled. By setting value here, we indicate to + // this.handleAction() where in the content tree it should take + // the action to execute from. + , + value: isChecked ? "checkbox" : "primary_button", + disabled: isPrimaryDisabled(content.primary_button?.disabled), + onClick: props.handleAction, + "data-l10n-args": addonName ? JSON.stringify({ + "addon-name": addonName + }) : "" + })), content.additional_button ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_AdditionalCTA__WEBPACK_IMPORTED_MODULE_11__.AdditionalCTA, { + content: content, + handleAction: props.handleAction + }) : null, content.checkbox ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "checkbox-container" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { + type: "checkbox", + id: "action-checkbox", + checked: isChecked, + onChange: () => { + setIsChecked(!isChecked); + } + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.checkbox.label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { + htmlFor: "action-checkbox" + }))) : null, content.secondary_button ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__.SecondaryCTA, { + content: content, + handleAction: props.handleAction, + activeMultiSelect: activeMultiSelect + }) : null); +}; +class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { + componentDidMount() { + this.mainContentHeader.focus(); + } + getScreenClassName(isFirstScreen, isLastScreen, includeNoodles, isVideoOnboarding, isAddonsPicker) { + const screenClass = `screen-${this.props.order % 2 !== 0 ? 1 : 2}`; + if (isVideoOnboarding) { + return "with-video"; + } + if (isAddonsPicker) { + return "addons-picker"; + } + return `${isFirstScreen ? `dialog-initial` : ``} ${isLastScreen ? `dialog-last` : ``} ${includeNoodles ? `with-noodles` : ``} ${screenClass}`; + } + renderTitle({ + title, + title_logo + }) { + if (title_logo) { + const { + alignment, + ...rest + } = title_logo; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "inline-icon-container", + alignment: alignment ?? "center" + }, this.renderPicture({ + ...rest + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: title + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", { + id: "mainContentHeader" + }))); + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: title + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", { + id: "mainContentHeader" + })); + } + renderPicture({ + imageURL = "chrome://branding/content/about-logo.svg", + darkModeImageURL, + reducedMotionImageURL, + darkModeReducedMotionImageURL, + alt = "", + width, + height, + marginBlock, + marginInline, + className = "logo-container" + }) { + function getLoadingStrategy() { + for (let url of [imageURL, darkModeImageURL, reducedMotionImageURL, darkModeReducedMotionImageURL]) { + if (_lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.getLoadingStrategyFor(url) === "lazy") { + return "lazy"; + } + } + return "eager"; + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("picture", { + className: className, + style: { + marginInline, + marginBlock + } + }, darkModeReducedMotionImageURL ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("source", { + srcSet: darkModeReducedMotionImageURL, + media: "(prefers-color-scheme: dark) and (prefers-reduced-motion: reduce)" + }) : null, darkModeImageURL ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("source", { + srcSet: darkModeImageURL, + media: "(prefers-color-scheme: dark)" + }) : null, reducedMotionImageURL ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("source", { + srcSet: reducedMotionImageURL, + media: "(prefers-reduced-motion: reduce)" + }) : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: alt + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "sr-only logo-alt" + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + className: "brand-logo", + style: { + height, + width + }, + src: imageURL, + alt: "", + loading: getLoadingStrategy(), + role: alt ? null : "presentation" + })); + } + renderContentTiles() { + const { + content + } = this.props; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, content.tiles && content.tiles.type === "addons-picker" && content.tiles.data ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_AddonsPicker__WEBPACK_IMPORTED_MODULE_13__.AddonsPicker, { + content: content, + message_id: this.props.messageId, + handleAction: this.props.handleAction + }) : null, content.tiles && content.tiles.type === "theme" && content.tiles.data ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_Themes__WEBPACK_IMPORTED_MODULE_5__.Themes, { + content: content, + activeTheme: this.props.activeTheme, + handleAction: this.props.handleAction + }) : null, content.tiles && content.tiles.type === "mobile_downloads" && content.tiles.data ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MobileDownloads__WEBPACK_IMPORTED_MODULE_3__.MobileDownloads, { + data: content.tiles.data, + handleAction: this.props.handleAction + }) : null, content.tiles && content.tiles.type === "multiselect" && content.tiles.data ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiSelect__WEBPACK_IMPORTED_MODULE_4__.MultiSelect, { + content: content, + screenMultiSelects: this.props.screenMultiSelects, + setScreenMultiSelects: this.props.setScreenMultiSelects, + activeMultiSelect: this.props.activeMultiSelect, + setActiveMultiSelect: this.props.setActiveMultiSelect + }) : null, content.tiles && content.tiles.type === "migration-wizard" ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_EmbeddedMigrationWizard__WEBPACK_IMPORTED_MODULE_12__.EmbeddedMigrationWizard, { + handleAction: this.props.handleAction + }) : null); + } + renderNoodles() { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "noodle orange-L" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "noodle purple-C" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "noodle solid-L" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "noodle outline-L" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "noodle yellow-circle" + })); + } + renderLanguageSwitcher() { + return this.props.content.languageSwitcher ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_LanguageSwitcher__WEBPACK_IMPORTED_MODULE_7__.LanguageSwitcher, { + content: this.props.content, + handleAction: this.props.handleAction, + negotiatedLanguage: this.props.negotiatedLanguage, + langPackInstallPhase: this.props.langPackInstallPhase, + messageId: this.props.messageId + }) : null; + } + renderDismissButton() { + const { + size, + marginBlock, + marginInline, + label + } = this.props.content.dismiss_button; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "dismiss-button", + onClick: this.props.handleAction, + value: "dismiss_button", + "data-l10n-id": label?.string_id || "spotlight-dialog-close-button", + "button-size": size, + style: { + marginBlock, + marginInline + } + }); + } + renderStepsIndicator() { + const currentStep = (this.props.order ?? 0) + 1; + const previousStep = (this.props.previousOrder ?? -1) + 1; + const { + content, + totalNumberOfScreens: total + } = this.props; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + id: "steps", + className: `steps${content.progress_bar ? " progress-bar" : ""}`, + "data-l10n-id": content.steps_indicator?.string_id || "onboarding-welcome-steps-indicator-label", + "data-l10n-args": JSON.stringify({ + current: currentStep, + total: total ?? 0 + }), + "data-l10n-attrs": "aria-label", + role: "progressbar", + "aria-valuenow": currentStep, + "aria-valuemin": 1, + "aria-valuemax": total + }, content.progress_bar ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__.ProgressBar, { + step: currentStep, + previousStep: previousStep, + totalNumberOfScreens: total + }) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__.StepsIndicator, { + order: this.props.order, + totalNumberOfScreens: total + })); + } + renderSecondarySection(content) { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `section-secondary ${content.hide_secondary_section ? "with-secondary-section-hidden" : ""}`, + style: content.background ? { + background: content.background, + "--mr-secondary-background-position-y": content.split_narrow_bkg_position + } : {} + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.image_alt_text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "sr-only image-alt", + role: "img" + })), content.hero_image ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_HeroImage__WEBPACK_IMPORTED_MODULE_9__.HeroImage, { + url: content.hero_image.url + }) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "message-text" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "spacer-top" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.hero_text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "spacer-bottom" + })))); + } + renderOrderedContent(content) { + const elements = []; + for (const item of content) { + switch (item.type) { + case "text": + elements.push( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_LinkParagraph__WEBPACK_IMPORTED_MODULE_14__.LinkParagraph, { + text_content: item, + handleAction: this.props.handleAction + })); + break; + case "image": + elements.push(this.renderPicture({ + imageURL: item.url, + darkModeImageURL: item.darkModeImageURL, + height: item.height, + width: item.width, + alt: item.alt_text, + marginInline: item.marginInline, + className: "inline-image" + })); + } + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, elements); + } + render() { + const { + autoAdvance, + content, + isRtamo, + isTheme, + isFirstScreen, + isLastScreen, + isSingleScreen, + forceHideStepsIndicator, + ariaRole, + aboveButtonStepsIndicator + } = this.props; + const includeNoodles = content.has_noodles; + // The default screen position is "center" + const isCenterPosition = content.position === "center" || !content.position; + const hideStepsIndicator = autoAdvance || content?.video_container || isSingleScreen || forceHideStepsIndicator; + const textColorClass = content.text_color ? `${content.text_color}-text` : ""; + // Assign proton screen style 'screen-1' or 'screen-2' to centered screens + // by checking if screen order is even or odd. + const screenClassName = isCenterPosition ? this.getScreenClassName(isFirstScreen, isLastScreen, includeNoodles, content?.video_container, content.tiles?.type === "addons-picker") : ""; + const isEmbeddedMigration = content.tiles?.type === "migration-wizard"; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("main", { + className: `screen ${this.props.id || ""} + ${screenClassName} ${textColorClass}`, + role: ariaRole ?? "alertdialog", + layout: content.layout, + pos: content.position || "center", + tabIndex: "-1", + "aria-labelledby": "mainContentHeader", + ref: input => { + this.mainContentHeader = input; + } + }, isCenterPosition ? null : this.renderSecondarySection(content), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `section-main ${isEmbeddedMigration ? "embedded-migration" : ""}`, + "hide-secondary-section": content.hide_secondary_section ? String(content.hide_secondary_section) : null, + role: "document" + }, content.secondary_button_top ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__.SecondaryCTA, { + content: content, + handleAction: this.props.handleAction, + position: "top" + }) : null, includeNoodles ? this.renderNoodles() : null, content.dismiss_button ? this.renderDismissButton() : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `main-content ${hideStepsIndicator ? "no-steps" : ""}`, + style: { + background: content.background && isCenterPosition ? content.background : null, + width: content.width && content.position !== "split" ? content.width : null + } + }, content.logo ? this.renderPicture(content.logo) : null, isRtamo ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "rtamo-icon" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + className: `${isTheme ? "rtamo-theme-icon" : "brand-logo"}`, + src: this.props.iconURL, + loading: _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.getLoadingStrategyFor(this.props.iconURL), + alt: "", + role: "presentation" + })) : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "main-content-inner" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `welcome-text ${content.title_style || ""}` + }, content.title ? this.renderTitle(content) : null, content.subtitle ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.subtitle + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", { + "data-l10n-args": JSON.stringify({ + "addon-name": this.props.addonName, + ...this.props.appAndSystemLocaleInfo?.displayNames + }), + "aria-flowto": this.props.messageId?.includes("FEATURE_TOUR") ? "steps" : "" + })) : null, content.cta_paragraph ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_CTAParagraph__WEBPACK_IMPORTED_MODULE_8__.CTAParagraph, { + content: content.cta_paragraph, + handleAction: this.props.handleAction + }) : null), content.video_container ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_OnboardingVideo__WEBPACK_IMPORTED_MODULE_10__.OnboardingVideo, { + content: content.video_container, + handleAction: this.props.handleAction + }) : null, content.above_button_content ? this.renderOrderedContent(content.above_button_content) : null, this.renderContentTiles(), this.renderLanguageSwitcher(), !hideStepsIndicator && aboveButtonStepsIndicator ? this.renderStepsIndicator() : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ProtonScreenActionButtons, { + content: content, + addonName: this.props.addonName, + handleAction: this.props.handleAction, + activeMultiSelect: this.props.activeMultiSelect + })), !hideStepsIndicator && !aboveButtonStepsIndicator ? this.renderStepsIndicator() : null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.info_text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { + className: "info-text" + }))); + } +} + +/***/ }), +/* 7 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "MarketplaceButtons": () => (/* binding */ MarketplaceButtons), +/* harmony export */ "MobileDownloads": () => (/* binding */ MobileDownloads) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + +const MarketplaceButtons = props => { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { + className: "mobile-download-buttons" + }, props.buttons.includes("ios") ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { + className: "ios" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + "data-l10n-id": "spotlight-ios-marketplace-button", + value: "ios", + onClick: props.handleAction + })) : null, props.buttons.includes("android") ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { + className: "android" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + "data-l10n-id": "spotlight-android-marketplace-button", + value: "android", + onClick: props.handleAction + })) : null); +}; +const MobileDownloads = props => { + const { + QR_code: QRCode + } = props.data; + const showEmailLink = props.data.email && window.AWSendToDeviceEmailsSupported(); + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "mobile-downloads" + }, QRCode ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + "data-l10n-id": QRCode.alt_text.string_id ? QRCode.alt_text.string_id : null, + className: "qr-code-image", + alt: typeof QRCode.alt_text === "string" ? QRCode.alt_text : "", + src: QRCode.image_url, + loading: _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.getLoadingStrategyFor(QRCode.image_url) + }) : null, showEmailLink ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: props.data.email.link_text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "email-link", + value: "email_link", + onClick: props.handleAction + }))) : null, props.data.marketplace_buttons ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(MarketplaceButtons, { + buttons: props.data.marketplace_buttons, + handleAction: props.handleAction + }) : null); +}; + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "MultiSelect": () => (/* binding */ MultiSelect) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const MULTI_SELECT_STYLES = [..._MSLocalized__WEBPACK_IMPORTED_MODULE_1__.CONFIGURABLE_STYLES, "flexDirection", "flexWrap", "flexFlow", "flexGrow", "flexShrink", "justifyContent", "alignItems", "gap"]; +const MULTI_SELECT_ICON_STYLES = [..._MSLocalized__WEBPACK_IMPORTED_MODULE_1__.CONFIGURABLE_STYLES, "width", "height", "background", "backgroundColor", "backgroundImage", "backgroundSize", "backgroundPosition", "backgroundRepeat", "backgroundOrigin", "backgroundClip", "border", "borderRadius", "appearance", "fill", "stroke", "outline", "outlineOffset", "boxShadow"]; +function getValidStyle(style, validStyles, allowVars) { + if (!style) { + return null; + } + return Object.keys(style).filter(key => validStyles.includes(key) || allowVars && key.startsWith("--")).reduce((obj, key) => { + obj[key] = style[key]; + return obj; + }, {}); +} +const MultiSelect = ({ + content, + screenMultiSelects, + setScreenMultiSelects, + activeMultiSelect, + setActiveMultiSelect +}) => { + const { + data + } = content.tiles; + const refs = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)({}); + const handleChange = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => { + const newActiveMultiSelect = []; + Object.keys(refs.current).forEach(key => { + if (refs.current[key]?.checked) { + newActiveMultiSelect.push(key); + } + }); + setActiveMultiSelect(newActiveMultiSelect); + }, [setActiveMultiSelect]); + const items = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => { + function getOrderedIds() { + if (screenMultiSelects) { + return screenMultiSelects; + } + let orderedIds = data.map(item => ({ + id: item.id, + rank: item.randomize ? Math.random() : NaN + })).sort((a, b) => b.rank - a.rank).map(({ + id + }) => id); + setScreenMultiSelects(orderedIds); + return orderedIds; + } + return getOrderedIds().map(id => data.find(item => item.id === id)); + }, [] // eslint-disable-line react-hooks/exhaustive-deps + ); + const containerStyle = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => getValidStyle(content.tiles.style, MULTI_SELECT_STYLES, true), [content.tiles.style]); + + // When screen renders for first time, update state + // with checkbox ids that has defaultvalue true + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (!activeMultiSelect) { + let newActiveMultiSelect = []; + items.forEach(({ + id, + defaultValue + }) => { + if (defaultValue && id) { + newActiveMultiSelect.push(id); + } + }); + setActiveMultiSelect(newActiveMultiSelect); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "multi-select-container", + style: containerStyle, + role: items.some(({ + type, + group + }) => type === "radio" && group) ? "radiogroup" : "group", + "aria-labelledby": "multi-stage-multi-select-label" + }, content.tiles.label ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.tiles.label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", { + id: "multi-stage-multi-select-label" + })) : null, items.map(({ + id, + label, + icon, + type = "checkbox", + group, + style + }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + key: id + label, + className: "checkbox-container multi-select-item", + style: getValidStyle(style, MULTI_SELECT_STYLES) + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { + type: type // checkbox or radio + , + id: id, + value: id, + name: group, + checked: activeMultiSelect?.includes(id), + style: getValidStyle(icon?.style, MULTI_SELECT_ICON_STYLES), + onChange: handleChange, + ref: el => refs.current[id] = el + }), label ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { + htmlFor: id + })) : null))); +}; + +/***/ }), +/* 9 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Themes": () => (/* binding */ Themes) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const Themes = props => { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "tiles-theme-container" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("fieldset", { + className: "tiles-theme-section" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: props.content.subtitle + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("legend", { + className: "sr-only" + })), props.content.tiles.data.map(({ + theme, + label, + tooltip, + description + }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + key: theme + label, + text: typeof tooltip === "object" ? tooltip : {} + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { + className: "theme", + title: theme + label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: typeof description === "object" ? description : {} + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { + type: "radio", + value: theme, + name: "theme", + checked: theme === props.activeTheme, + className: "sr-only input", + onClick: props.handleAction + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: `icon ${theme === props.activeTheme ? " selected" : ""} ${theme}` + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "text" + })))))))); +}; + +/***/ }), +/* 10 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "useLanguageSwitcher": () => (/* binding */ useLanguageSwitcher), +/* harmony export */ "LanguageSwitcher": () => (/* binding */ LanguageSwitcher) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + + +/** + * The language switcher implements a hook that should be placed at a higher level + * than the actual language switcher component, as it needs to preemptively fetch + * and install langpacks for the user if there is a language mismatch screen. + */ +function useLanguageSwitcher(appAndSystemLocaleInfo, screens, screenIndex, setScreenIndex) { + const languageMismatchScreenIndex = screens.findIndex(({ + id + }) => id === "AW_LANGUAGE_MISMATCH"); + const screen = screens[languageMismatchScreenIndex]; + + // Ensure fluent messages have the negotiatedLanguage args set, as they are rendered + // before the negotiatedLanguage is known. If the arg isn't present then Firefox will + // crash in development mode. + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (screen?.content?.languageSwitcher) { + for (const text of Object.values(screen.content.languageSwitcher)) { + if (text?.args && text.args.negotiatedLanguage === undefined) { + text.args.negotiatedLanguage = ""; + } + } + } + }, [screen]); + + // If there is a mismatch, then Firefox can negotiate a better langpack to offer + // the user. + const [negotiatedLanguage, setNegotiatedLanguage] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(function getNegotiatedLanguage() { + if (!appAndSystemLocaleInfo) { + return; + } + if (appAndSystemLocaleInfo.matchType !== "language-mismatch") { + // There is no language mismatch, so there is no need to negotiate a langpack. + return; + } + (async () => { + const { + langPack, + langPackDisplayName + } = await window.AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo); + if (langPack) { + setNegotiatedLanguage({ + langPackDisplayName, + appDisplayName: appAndSystemLocaleInfo.displayNames.appLanguage, + langPack, + requestSystemLocales: [langPack.target_locale, appAndSystemLocaleInfo.appLocaleRaw], + originalAppLocales: [appAndSystemLocaleInfo.appLocaleRaw] + }); + } else { + setNegotiatedLanguage({ + langPackDisplayName: null, + appDisplayName: null, + langPack: null, + requestSystemLocales: null + }); + } + })(); + }, [appAndSystemLocaleInfo]); + + /** + * @type { + * "before-installation" + * | "installing" + * | "installed" + * | "installation-error" + * | "none-available" + * } + */ + const [langPackInstallPhase, setLangPackInstallPhase] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)("before-installation"); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(function ensureLangPackInstalled() { + if (!negotiatedLanguage) { + // There are no negotiated languages to download yet. + return; + } + setLangPackInstallPhase("installing"); + window.AWEnsureLangPackInstalled(negotiatedLanguage, screen?.content).then(content => { + // Update screen content with strings that might have changed. + screen.content = content; + setLangPackInstallPhase("installed"); + }, error => { + console.error(error); + setLangPackInstallPhase("installation-error"); + }); + }, [negotiatedLanguage, screen]); + const [languageFilteredScreens, setLanguageFilteredScreens] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(screens); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(function filterScreen() { + // Remove the language screen if it exists (already removed for no live + // reload) and we either don't-need-to or can't switch. + if (screen && (appAndSystemLocaleInfo?.matchType !== "language-mismatch" || negotiatedLanguage?.langPack === null)) { + if (screenIndex > languageMismatchScreenIndex) { + setScreenIndex(screenIndex - 1); + } + setLanguageFilteredScreens(screens.filter(s => s.id !== "AW_LANGUAGE_MISMATCH")); + } else { + setLanguageFilteredScreens(screens); + } + }, + // Removing screenIndex as a dependency as it's causing infinite re-renders (1873019) + // eslint-disable-next-line react-hooks/exhaustive-deps + [appAndSystemLocaleInfo?.matchType, languageMismatchScreenIndex, negotiatedLanguage, screen, screens, setScreenIndex]); + return { + negotiatedLanguage, + langPackInstallPhase, + languageFilteredScreens + }; +} + +/** + * The language switcher is a separate component as it needs to perform some asynchronous + * network actions such as retrieving the list of langpacks available, and downloading + * a new langpack. On a fast connection, this won't be noticeable, but on slow or unreliable + * internet this may fail for a user. + */ +function LanguageSwitcher(props) { + const { + content, + handleAction, + negotiatedLanguage, + langPackInstallPhase, + messageId + } = props; + const [isAwaitingLangpack, setIsAwaitingLangpack] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false); + + // Determine the status of the langpack installation. + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + if (isAwaitingLangpack && langPackInstallPhase !== "installing") { + window.AWSetRequestedLocales(negotiatedLanguage.requestSystemLocales); + requestAnimationFrame(() => { + handleAction( + // Simulate the click event. + { + currentTarget: { + value: "download_complete" + } + }); + }); + } + }, [handleAction, isAwaitingLangpack, langPackInstallPhase, negotiatedLanguage?.requestSystemLocales]); + let showWaitingScreen = false; + let showPreloadingScreen = false; + let showReadyScreen = false; + if (isAwaitingLangpack && langPackInstallPhase !== "installed") { + showWaitingScreen = true; + } else if (langPackInstallPhase === "before-installation") { + showPreloadingScreen = true; + } else { + showReadyScreen = true; + } + + // Use {display: "none"} rather than if statements to prevent layout thrashing with + // the localized text elements rendering as blank, then filling in the text. + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "action-buttons language-switcher-container" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + style: { + display: showPreloadingScreen ? "block" : "none" + } + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "primary", + value: "primary_button", + disabled: true, + type: "button" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + className: "language-loader", + src: "chrome://browser/skin/tabbrowser/tab-connecting.png", + alt: "" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.waiting + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "secondary-cta" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.skip + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + value: "decline_waiting", + type: "button", + className: "secondary text-link arrow-icon", + onClick: handleAction + })))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + style: { + display: showWaitingScreen ? "block" : "none" + } + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "primary", + value: "primary_button", + disabled: true, + type: "button" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + className: "language-loader", + src: "chrome://browser/skin/tabbrowser/tab-connecting.png", + alt: "" + }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.downloading + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "secondary-cta" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.cancel + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + type: "button", + className: "secondary text-link", + onClick: () => { + setIsAwaitingLangpack(false); + handleAction({ + currentTarget: { + value: "cancel_waiting" + } + }); + } + })))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + style: { + display: showReadyScreen ? "block" : "none" + } + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "primary", + value: "primary_button", + onClick: () => { + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(messageId, "download_langpack"); + setIsAwaitingLangpack(true); + } + }, content.languageSwitcher.switch ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.switch + }) : + // This is the localized name from the Intl.DisplayNames API. + negotiatedLanguage?.langPackDisplayName)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + type: "button", + className: "primary", + value: "decline", + onClick: event => { + window.AWSetRequestedLocales(negotiatedLanguage.originalAppLocales); + handleAction(event); + } + }, content.languageSwitcher.continue ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.languageSwitcher.continue + }) : + // This is the localized name from the Intl.DisplayNames API. + negotiatedLanguage?.appDisplayName)))); +} + +/***/ }), +/* 11 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "CTAParagraph": () => (/* binding */ CTAParagraph) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const CTAParagraph = props => { + const { + content, + handleAction + } = props; + if (!content?.text) { + return null; + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", { + className: "cta-paragraph" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.text + }, content.text.string_name && typeof handleAction === "function" ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { + "data-l10n-id": content.text.string_id, + onClick: handleAction, + onKeyUp: event => ["Enter", " "].includes(event.key) ? handleAction(event) : null, + value: "cta_paragraph", + role: "button", + tabIndex: "0" + }, " ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { + role: "button", + tabIndex: "0", + "data-l10n-name": content.text.string_name + }, " ")) : null)); +}; + +/***/ }), +/* 12 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "HeroImage": () => (/* binding */ HeroImage) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const HeroImage = props => { + const { + height, + url, + alt + } = props; + if (!url) { + return null; + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "hero-image" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + style: height ? { + height + } : null, + src: url, + loading: _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.getLoadingStrategyFor(url), + alt: alt || "", + role: alt ? null : "presentation" + })); +}; + +/***/ }), +/* 13 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "OnboardingVideo": () => (/* binding */ OnboardingVideo) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +const OnboardingVideo = props => { + const vidUrl = props.content.video_url; + const autoplay = props.content.autoPlay; + const handleVideoAction = event => { + props.handleAction({ + currentTarget: { + value: event + } + }); + }; + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { + // eslint-disable-line jsx-a11y/media-has-caption + controls: true, + autoPlay: autoplay, + src: vidUrl, + width: "604px", + height: "340px", + onPlay: () => handleVideoAction("video_start"), + onEnded: () => handleVideoAction("video_end") + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("source", { + src: vidUrl + }))); +}; + +/***/ }), +/* 14 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "AdditionalCTA": () => (/* binding */ AdditionalCTA) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _SubmenuButton__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(15); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + +const AdditionalCTA = ({ + content, + handleAction +}) => { + let buttonStyle = ""; + const isSplitButton = content.submenu_button?.attached_to === "additional_button"; + let className = "additional-cta-box"; + if (isSplitButton) { + className += " split-button-container"; + } + if (!content.additional_button?.style) { + buttonStyle = "primary"; + } else { + buttonStyle = content.additional_button?.style === "link" ? "cta-link" : content.additional_button?.style; + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: className + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.additional_button?.label + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: `${buttonStyle} additional-cta`, + onClick: handleAction, + value: "additional_button", + disabled: content.additional_button?.disabled === true + })), isSplitButton ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_SubmenuButton__WEBPACK_IMPORTED_MODULE_2__.SubmenuButton, { + content: content, + handleAction: handleAction + }) : null); +}; + +/***/ }), +/* 15 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "SubmenuButton": () => (/* binding */ SubmenuButton) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const SubmenuButton = props => { + return document.createXULElement ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SubmenuButtonInner, props) : null; +}; +function translateMenuitem(item, element) { + let { + label + } = item; + if (!label) { + return; + } + if (label.raw) { + element.setAttribute("label", label.raw); + } + if (label.access_key) { + element.setAttribute("accesskey", label.access_key); + } + if (label.aria_label) { + element.setAttribute("aria-label", label.aria_label); + } + if (label.tooltip_text) { + element.setAttribute("tooltiptext", label.tooltip_text); + } + if (label.string_id) { + element.setAttribute("data-l10n-id", label.string_id); + if (label.args) { + element.setAttribute("data-l10n-args", JSON.stringify(label.args)); + } + } +} +function addMenuitems(items, popup) { + for (let item of items) { + switch (item.type) { + case "separator": + popup.appendChild(document.createXULElement("menuseparator")); + break; + case "menu": + let menu = document.createXULElement("menu"); + menu.className = "fxms-multi-stage-menu"; + translateMenuitem(item, menu); + if (item.id) { + menu.value = item.id; + } + if (item.icon) { + menu.classList.add("menu-iconic"); + menu.setAttribute("image", item.icon); + } + popup.appendChild(menu); + let submenuPopup = document.createXULElement("menupopup"); + menu.appendChild(submenuPopup); + addMenuitems(item.submenu, submenuPopup); + break; + case "action": + let menuitem = document.createXULElement("menuitem"); + translateMenuitem(item, menuitem); + menuitem.config = item; + if (item.id) { + menuitem.value = item.id; + } + if (item.icon) { + menuitem.classList.add("menuitem-iconic"); + menuitem.setAttribute("image", item.icon); + } + popup.appendChild(menuitem); + break; + } + } +} +const SubmenuButtonInner = ({ + content, + handleAction +}) => { + const ref = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); + const isPrimary = content.submenu_button?.style === "primary"; + const onCommand = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(event => { + let { + config + } = event.target; + let mockEvent = { + currentTarget: ref.current, + source: config.id, + name: "command", + action: config.action + }; + handleAction(mockEvent); + }, [handleAction]); + const onClick = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => { + let button = ref.current; + let submenu = button?.querySelector(".fxms-multi-stage-submenu"); + if (submenu && !button.hasAttribute("open")) { + submenu.openPopup(button, { + position: "after_end" + }); + } + }, []); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + let button = ref.current; + if (!button || button.querySelector(".fxms-multi-stage-submenu")) { + return null; + } + let menupopup = document.createXULElement("menupopup"); + menupopup.className = "fxms-multi-stage-submenu"; + addMenuitems(content.submenu_button.submenu, menupopup); + button.appendChild(menupopup); + let stylesheet; + if (!document.head.querySelector(`link[href="chrome://global/content/widgets.css"], link[href="chrome://global/skin/global.css"]`)) { + stylesheet = document.createElement("link"); + stylesheet.rel = "stylesheet"; + stylesheet.href = "chrome://global/content/widgets.css"; + document.head.appendChild(stylesheet); + } + if (!menupopup.listenersRegistered) { + menupopup.addEventListener("command", onCommand); + menupopup.addEventListener("popupshowing", event => { + if (event.target === menupopup && event.target.anchorNode) { + event.target.anchorNode.toggleAttribute("open", true); + } + }); + menupopup.addEventListener("popuphiding", event => { + if (event.target === menupopup && event.target.anchorNode) { + event.target.anchorNode.toggleAttribute("open", false); + } + }); + menupopup.listenersRegistered = true; + } + return () => { + menupopup?.remove(); + stylesheet?.remove(); + }; + }, [onCommand]); // eslint-disable-line react-hooks/exhaustive-deps + + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: content.submenu_button.label ?? {} + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: `submenu-button ${isPrimary ? "primary" : "secondary"}`, + value: "submenu_button", + onClick: onClick, + ref: ref + })); +}; + +/***/ }), +/* 16 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "EmbeddedMigrationWizard": () => (/* binding */ EmbeddedMigrationWizard) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +const EmbeddedMigrationWizard = ({ + handleAction +}) => { + const ref = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(); + (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { + const handleBeginMigration = () => { + handleAction({ + currentTarget: { + value: "migrate_start" + }, + source: "primary_button" + }); + }; + const handleClose = () => { + handleAction({ + currentTarget: { + value: "migrate_close" + } + }); + }; + const { + current + } = ref; + current?.addEventListener("MigrationWizard:BeginMigration", handleBeginMigration); + current?.addEventListener("MigrationWizard:Close", handleClose); + return () => { + current?.removeEventListener("MigrationWizard:BeginMigration", handleBeginMigration); + current?.removeEventListener("MigrationWizard:Close", handleClose); + }; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("migration-wizard", { + "force-show-import-all": "false", + "auto-request-state": "", + ref: ref + }); +}; + +/***/ }), +/* 17 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Loader": () => (/* binding */ Loader), +/* harmony export */ "InstallButton": () => (/* binding */ InstallButton), +/* harmony export */ "AddonsPicker": () => (/* binding */ AddonsPicker) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + +const Loader = () => { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + className: "primary" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "loaderContainer" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { + className: "loader" + }))); +}; +const InstallButton = props => { + const [installing, setInstalling] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false); + const [installComplete, setInstallComplete] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false); + let buttonLabel = installComplete ? "Installed" : "Add to Firefox"; + function onClick(event) { + props.handleAction(event); + // Replace the label with the spinner + setInstalling(true); + window.AWEnsureAddonInstalled(props.addonId).then(value => { + if (value === "complete") { + // Set the label to "Installed" + setInstallComplete(true); + } + // Whether the addon installs or not, we want to remove the spinner + setInstalling(false); + }); + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "install-button-wrapper" + }, installing ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(Loader, null) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__.Localized, { + text: buttonLabel + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { + id: props.name, + value: props.index, + onClick: onClick, + disabled: installComplete, + className: "primary" + }))); +}; +const AddonsPicker = props => { + const { + content + } = props; + if (!content) { + return null; + } + function handleAction(event) { + const { + message_id + } = props; + let { + action, + source_id + } = content.tiles.data[event.currentTarget.value]; + let { + type, + data + } = action; + if (type === "INSTALL_ADDON_FROM_URL") { + if (!data) { + return; + } + } + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.handleUserAction({ + type, + data + }); + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.sendActionTelemetry(message_id, source_id); + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "addons-picker-container" + }, content.tiles.data.map(({ + id, + name, + type, + description, + icon + }, index) => name ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + key: id, + className: "addon-container" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "rtamo-icon" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { + className: `${type === "theme" ? "rtamo-theme-icon" : "brand-logo"}`, + src: icon, + role: "presentation", + alt: "" + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "addon-details" + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__.Localized, { + text: name + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "addon-title" + })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__.Localized, { + text: description + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "addon-description" + }))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(InstallButton, { + key: id, + addonId: id, + name: name, + handleAction: handleAction, + index: index + })) : null)); +}; + +/***/ }), +/* 18 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "LinkParagraph": () => (/* binding */ LinkParagraph) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + +const LinkParagraph = props => { + const { + text_content, + handleAction + } = props; + const handleParagraphAction = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(event => { + if (event.target.closest("a")) { + handleAction({ + ...event, + currentTarget: event.target + }); + } + }, [handleAction]); + const onKeyPress = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(event => { + if (event.key === "Enter" && !event.repeat) { + handleParagraphAction(event); + } + }, [handleParagraphAction]); + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, { + text: text_content.text + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", { + className: text_content.font_styles === "legal" ? "legal-paragraph" : "link-paragraph", + onClick: handleParagraphAction, + value: "link_paragraph", + onKeyPress: onKeyPress + }, text_content.link_keys?.map(link => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { + key: link, + value: link, + role: "link", + className: "text-link", + "data-l10n-name": link + // must pass in tabIndex when no href is provided + , + tabIndex: "0" + }, " ")))); +}; + +/***/ }), +/* 19 */ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "BASE_PARAMS": () => (/* binding */ BASE_PARAMS), +/* harmony export */ "addUtmParams": () => (/* binding */ addUtmParams) +/* harmony export */ }); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * BASE_PARAMS keys/values can be modified from outside this file + */ +const BASE_PARAMS = { + utm_source: "activity-stream", + utm_campaign: "firstrun", + utm_medium: "referral", +}; + +/** + * Takes in a url as a string or URL object and returns a URL object with the + * utm_* parameters added to it. If a URL object is passed in, the paraemeters + * are added to it (the return value can be ignored in that case as it's the + * same object). + */ +function addUtmParams(url, utmTerm) { + let returnUrl = url; + if (typeof returnUrl === "string") { + returnUrl = new URL(url); + } + for (let [key, value] of Object.entries(BASE_PARAMS)) { + if (!returnUrl.searchParams.has(key)) { + returnUrl.searchParams.append(key, value); + } + } + returnUrl.searchParams.append("utm_term", utmTerm); + return returnUrl; +} + + +/***/ }), +/* 20 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "ReturnToAMO": () => (/* binding */ ReturnToAMO) +/* harmony export */ }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3); +/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6); +/* harmony import */ var _lib_addUtmParams_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(19); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + + +class ReturnToAMO extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { + constructor(props) { + super(props); + this.fetchFlowParams = this.fetchFlowParams.bind(this); + this.handleAction = this.handleAction.bind(this); + } + async fetchFlowParams() { + if (this.props.metricsFlowUri) { + this.setState({ + flowParams: await _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.fetchFlowParams(this.props.metricsFlowUri) + }); + } + } + componentDidUpdate() { + this.fetchFlowParams(); + } + handleAction(event) { + const { + content, + message_id, + url, + utm_term + } = this.props; + let { + action, + source_id + } = content[event.currentTarget.value]; + let { + type, + data + } = action; + if (type === "INSTALL_ADDON_FROM_URL") { + if (!data) { + return; + } + // Set add-on url in action.data.url property from JSON + data = { + ...data, + url + }; + } else if (type === "SHOW_FIREFOX_ACCOUNTS") { + let params = { + ..._lib_addUtmParams_mjs__WEBPACK_IMPORTED_MODULE_3__.BASE_PARAMS, + utm_term: `aboutwelcome-${utm_term}-screen` + }; + if (action.addFlowParams && this.state.flowParams) { + params = { + ...params, + ...this.state.flowParams + }; + } + data = { + ...data, + extraParams: params + }; + } + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.handleUserAction({ + type, + data + }); + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.sendActionTelemetry(message_id, source_id); + } + render() { + const { + content, + type + } = this.props; + if (!content) { + return null; + } + if (content?.primary_button.label) { + content.primary_button.label.string_id = type.includes("theme") ? "return-to-amo-add-theme-label" : "mr1-return-to-amo-add-extension-label"; + } + + // For experiments, when needed below rendered UI allows settings hard coded strings + // directly inside JSON except for ReturnToAMOText which picks add-on name and icon from fluent string + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { + className: "outer-wrapper onboardingContainer proton", + style: content.backdrop ? { + background: content.backdrop + } : {} + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__.MultiStageProtonScreen, { + content: content, + isRtamo: true, + isTheme: type.includes("theme"), + id: this.props.message_id, + order: this.props.order || 0, + totalNumberOfScreens: 1, + isSingleScreen: true, + autoAdvance: this.props.auto_advance, + iconURL: type.includes("theme") ? this.props.themeScreenshots[0]?.url : this.props.iconURL, + addonName: this.props.name, + handleAction: this.handleAction + })); + } +} +ReturnToAMO.defaultProps = _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_RTAMO_CONTENT; + +/***/ }) +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); +/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3); +/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4); +/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + + + + +class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { + constructor(props) { + super(props); + this.state = { + metricsFlowUri: null + }; + this.fetchFxAFlowUri = this.fetchFxAFlowUri.bind(this); + } + async fetchFxAFlowUri() { + this.setState({ + metricsFlowUri: await window.AWGetFxAMetricsFlowURI?.() + }); + } + componentDidMount() { + if (!this.props.skipFxA) { + this.fetchFxAFlowUri(); + } + if (document.location.href === "about:welcome") { + // Record impression with performance data after allowing the page to load + const recordImpression = domState => { + const { + domComplete, + domInteractive + } = performance.getEntriesByType("navigation").pop(); + _lib_aboutwelcome_utils_mjs__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendImpressionTelemetry(this.props.messageId, { + domComplete, + domInteractive, + mountStart: performance.getEntriesByName("mount").pop().startTime, + domState, + source: this.props.UTMTerm + }); + }; + if (document.readyState === "complete") { + // Page might have already triggered a load event because it waited for async data, + // e.g., attribution, so the dom load timing could be of a empty content + // with domState in telemetry captured as 'complete' + recordImpression(document.readyState); + } else { + window.addEventListener("load", () => recordImpression("load"), { + once: true + }); + } + + // Captures user has seen about:welcome by setting + // firstrun.didSeeAboutWelcome pref to true and capturing welcome UI unique messageId + window.AWSendToParent("SET_WELCOME_MESSAGE_SEEN", this.props.messageId); + } + } + render() { + const { + props + } = this; + if (props.template === "return_to_amo") { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__.ReturnToAMO, { + message_id: props.messageId, + type: props.type, + name: props.name, + url: props.url, + iconURL: props.iconURL, + themeScreenshots: props.screenshots, + metricsFlowUri: this.state.metricsFlowUri + }); + } + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__.MultiStageAboutWelcome, { + message_id: props.messageId, + defaultScreens: props.screens, + updateHistory: !props.disableHistoryUpdates, + metricsFlowUri: this.state.metricsFlowUri, + utm_term: props.UTMTerm, + transitions: props.transitions, + backdrop: props.backdrop, + startScreen: props.startScreen || 0, + appAndSystemLocaleInfo: props.appAndSystemLocaleInfo, + ariaRole: props.aria_role + }); + } +} + +// Computes messageId and UTMTerm info used in telemetry +function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) { + let messageId = welcomeContent.template === "return_to_amo" ? `RTAMO_DEFAULT_WELCOME_${welcomeContent.type.toUpperCase()}` : "DEFAULT_ID"; + let UTMTerm = "aboutwelcome-default"; + if (welcomeContent.id) { + messageId = welcomeContent.id.toUpperCase(); + } + if (experimentId && branchId) { + UTMTerm = `aboutwelcome-${experimentId}-${branchId}`.toLowerCase(); + } + return { + messageId, + UTMTerm + }; +} +async function retrieveRenderContent() { + // Feature config includes RTAMO attribution data if exists + // else below data in order specified + // user prefs + // experiment data + // defaults + let featureConfig = await window.AWGetFeatureConfig(); + let { + messageId, + UTMTerm + } = ComputeTelemetryInfo(featureConfig, featureConfig.slug, featureConfig.branch && featureConfig.branch.slug); + return { + featureConfig, + messageId, + UTMTerm + }; +} +async function mount() { + let { + featureConfig: aboutWelcomeProps, + messageId, + UTMTerm + } = await retrieveRenderContent(); + react_dom__WEBPACK_IMPORTED_MODULE_1___default().render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(AboutWelcome, _extends({ + messageId: messageId, + UTMTerm: UTMTerm + }, aboutWelcomeProps)), document.getElementById("multi-stage-message-root")); +} +performance.mark("mount"); +mount(); +})(); + +/******/ })() +; \ No newline at end of file -- cgit v1.2.3