summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/aboutwelcome
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /browser/components/newtab/aboutwelcome
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/newtab/aboutwelcome')
-rw-r--r--browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm339
-rw-r--r--browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm266
-rw-r--r--browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js2321
-rw-r--r--browser/components/newtab/aboutwelcome/content/aboutwelcome.css1644
-rw-r--r--browser/components/newtab/aboutwelcome/content/aboutwelcome.html49
-rw-r--r--browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm707
-rw-r--r--browser/components/newtab/aboutwelcome/lib/AboutWelcomeTelemetry.jsm242
7 files changed, 5568 insertions, 0 deletions
diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm
new file mode 100644
index 0000000000..eef6c75b37
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm
@@ -0,0 +1,339 @@
+/* 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/. */
+
+"use strict";
+
+const EXPORTED_SYMBOLS = ["AboutWelcomeChild"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs",
+ NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ AboutWelcomeDefaults:
+ "resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm",
+});
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ const { Logger } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/Logger.sys.mjs"
+ );
+ return new Logger("AboutWelcomeChild");
+});
+
+async function getSelectedTheme(child) {
+ let activeThemeId = await child.sendQuery("AWPage:GET_SELECTED_THEME");
+ return activeThemeId;
+}
+
+class AboutWelcomeChild extends JSWindowActorChild {
+ actorCreated() {
+ this.exportFunctions();
+ }
+
+ /**
+ * Send event that can be handled by the page
+ * @param {{type: string, data?: any}} action
+ */
+ sendToPage(action) {
+ lazy.log.debug(`Sending to page: ${action.type}`);
+ const win = this.document.defaultView;
+ const event = new win.CustomEvent("AboutWelcomeChromeToContent", {
+ detail: Cu.cloneInto(action, win),
+ });
+ win.dispatchEvent(event);
+ }
+
+ /**
+ * Export functions that can be called by page js
+ */
+ exportFunctions() {
+ let window = this.contentWindow;
+
+ Cu.exportFunction(this.AWAddScreenImpression.bind(this), window, {
+ defineAs: "AWAddScreenImpression",
+ });
+
+ Cu.exportFunction(this.AWGetFeatureConfig.bind(this), window, {
+ defineAs: "AWGetFeatureConfig",
+ });
+
+ Cu.exportFunction(this.AWGetFxAMetricsFlowURI.bind(this), window, {
+ defineAs: "AWGetFxAMetricsFlowURI",
+ });
+
+ Cu.exportFunction(this.AWGetSelectedTheme.bind(this), window, {
+ defineAs: "AWGetSelectedTheme",
+ });
+
+ Cu.exportFunction(this.AWSelectTheme.bind(this), window, {
+ defineAs: "AWSelectTheme",
+ });
+
+ Cu.exportFunction(this.AWEvaluateScreenTargeting.bind(this), window, {
+ defineAs: "AWEvaluateScreenTargeting",
+ });
+
+ Cu.exportFunction(this.AWSendEventTelemetry.bind(this), window, {
+ defineAs: "AWSendEventTelemetry",
+ });
+
+ Cu.exportFunction(this.AWSendToParent.bind(this), window, {
+ defineAs: "AWSendToParent",
+ });
+
+ Cu.exportFunction(this.AWWaitForMigrationClose.bind(this), window, {
+ defineAs: "AWWaitForMigrationClose",
+ });
+
+ Cu.exportFunction(this.AWFinish.bind(this), window, {
+ defineAs: "AWFinish",
+ });
+
+ Cu.exportFunction(this.AWEnsureLangPackInstalled.bind(this), window, {
+ defineAs: "AWEnsureLangPackInstalled",
+ });
+
+ Cu.exportFunction(
+ this.AWNegotiateLangPackForLanguageMismatch.bind(this),
+ window,
+ {
+ defineAs: "AWNegotiateLangPackForLanguageMismatch",
+ }
+ );
+
+ Cu.exportFunction(this.AWSetRequestedLocales.bind(this), window, {
+ defineAs: "AWSetRequestedLocales",
+ });
+
+ Cu.exportFunction(this.AWSendToDeviceEmailsSupported.bind(this), window, {
+ defineAs: "AWSendToDeviceEmailsSupported",
+ });
+
+ Cu.exportFunction(this.AWNewScreen.bind(this), window, {
+ defineAs: "AWNewScreen",
+ });
+ }
+
+ /**
+ * Wrap a promise so content can use Promise methods.
+ */
+ wrapPromise(promise) {
+ return new this.contentWindow.Promise((resolve, reject) =>
+ promise.then(resolve, reject)
+ );
+ }
+
+ /**
+ * Clones the result of the query into the content window.
+ */
+ sendQueryAndCloneForContent(...sendQueryArgs) {
+ return this.wrapPromise(
+ (async () => {
+ return Cu.cloneInto(
+ await this.sendQuery(...sendQueryArgs),
+ this.contentWindow
+ );
+ })()
+ );
+ }
+
+ AWSelectTheme(data) {
+ return this.wrapPromise(
+ this.sendQuery("AWPage:SELECT_THEME", data.toUpperCase())
+ );
+ }
+
+ AWEvaluateScreenTargeting(data) {
+ return this.sendQueryAndCloneForContent(
+ "AWPage:EVALUATE_SCREEN_TARGETING",
+ data
+ );
+ }
+
+ AWAddScreenImpression(screen) {
+ return this.wrapPromise(
+ this.sendQuery("AWPage:ADD_SCREEN_IMPRESSION", screen)
+ );
+ }
+
+ /**
+ * Send initial data to page including experiment information
+ */
+ async getAWContent() {
+ let attributionData = await this.sendQuery("AWPage:GET_ATTRIBUTION_DATA");
+
+ // Return to AMO gets returned early.
+ if (attributionData?.template) {
+ lazy.log.debug("Loading about:welcome with RTAMO attribution data");
+ return Cu.cloneInto(attributionData, this.contentWindow);
+ } else if (attributionData?.ua) {
+ lazy.log.debug("Loading about:welcome with UA attribution");
+ }
+
+ let experimentMetadata =
+ lazy.ExperimentAPI.getExperimentMetaData({
+ featureId: "aboutwelcome",
+ }) || {};
+
+ lazy.log.debug(
+ `Loading about:welcome with ${
+ experimentMetadata?.slug ?? "no"
+ } experiment`
+ );
+
+ let featureConfig = lazy.NimbusFeatures.aboutwelcome.getAllVariables();
+ featureConfig.needDefault = await this.sendQuery("AWPage:NEED_DEFAULT");
+ featureConfig.needPin = await this.sendQuery("AWPage:DOES_APP_NEED_PIN");
+ if (featureConfig.languageMismatchEnabled) {
+ featureConfig.appAndSystemLocaleInfo = await this.sendQuery(
+ "AWPage:GET_APP_AND_SYSTEM_LOCALE_INFO"
+ );
+ }
+
+ // FeatureConfig (from experiments) has higher precendence
+ // to defaults. But the `screens` property isn't defined we shouldn't
+ // override the default with `null`
+ let defaults = lazy.AboutWelcomeDefaults.getDefaults();
+
+ const content = await lazy.AboutWelcomeDefaults.prepareContentForReact({
+ ...attributionData,
+ ...experimentMetadata,
+ ...defaults,
+ ...featureConfig,
+ screens: featureConfig.screens ?? defaults.screens,
+ backdrop: featureConfig.backdrop ?? defaults.backdrop,
+ });
+
+ return Cu.cloneInto(content, this.contentWindow);
+ }
+
+ AWGetFeatureConfig() {
+ return this.wrapPromise(this.getAWContent());
+ }
+
+ AWGetFxAMetricsFlowURI() {
+ return this.wrapPromise(this.sendQuery("AWPage:FXA_METRICS_FLOW_URI"));
+ }
+
+ AWGetSelectedTheme() {
+ return this.wrapPromise(getSelectedTheme(this));
+ }
+
+ /**
+ * Send Event Telemetry
+ * @param {object} eventData
+ */
+ AWSendEventTelemetry(eventData) {
+ this.AWSendToParent("TELEMETRY_EVENT", {
+ ...eventData,
+ event_context: {
+ ...eventData.event_context,
+ },
+ });
+ }
+
+ /**
+ * Send message that can be handled by AboutWelcomeParent.jsm
+ * @param {string} type
+ * @param {any=} data
+ * @returns {Promise<unknown>}
+ */
+ AWSendToParent(type, data) {
+ return this.sendQueryAndCloneForContent(`AWPage:${type}`, data);
+ }
+
+ AWWaitForMigrationClose() {
+ return this.wrapPromise(this.sendQuery("AWPage:WAIT_FOR_MIGRATION_CLOSE"));
+ }
+
+ AWFinish() {
+ this.contentWindow.location.href = "about:home";
+ }
+
+ AWEnsureLangPackInstalled(negotiated, screenContent) {
+ const content = Cu.cloneInto(screenContent, {});
+ return this.wrapPromise(
+ this.sendQuery(
+ "AWPage:ENSURE_LANG_PACK_INSTALLED",
+ negotiated.langPack
+ ).then(() => {
+ const formatting = [];
+ const l10n = new Localization(
+ ["branding/brand.ftl", "browser/newtab/onboarding.ftl"],
+ false,
+ undefined,
+ // Use the system-ish then app then default locale.
+ [...negotiated.requestSystemLocales, "en-US"]
+ );
+
+ // Add the negotiated language name as args.
+ function addMessageArgsAndUseLangPack(obj) {
+ for (const value of Object.values(obj)) {
+ if (value?.string_id) {
+ value.args = {
+ ...value.args,
+ negotiatedLanguage: negotiated.langPackDisplayName,
+ };
+
+ // Expose fluent strings wanting lang pack as raw.
+ if (value.useLangPack) {
+ formatting.push(
+ l10n.formatValue(value.string_id, value.args).then(raw => {
+ delete value.string_id;
+ value.raw = raw;
+ })
+ );
+ }
+ }
+ }
+ }
+ addMessageArgsAndUseLangPack(content.languageSwitcher);
+ addMessageArgsAndUseLangPack(content);
+ return Promise.all(formatting).then(() =>
+ Cu.cloneInto(content, this.contentWindow)
+ );
+ })
+ );
+ }
+
+ AWSetRequestedLocales(requestSystemLocales) {
+ return this.sendQueryAndCloneForContent(
+ "AWPage:SET_REQUESTED_LOCALES",
+ requestSystemLocales
+ );
+ }
+
+ AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo) {
+ return this.sendQueryAndCloneForContent(
+ "AWPage:NEGOTIATE_LANGPACK",
+ appAndSystemLocaleInfo
+ );
+ }
+
+ AWSendToDeviceEmailsSupported() {
+ return this.wrapPromise(
+ this.sendQuery("AWPage:SEND_TO_DEVICE_EMAILS_SUPPORTED")
+ );
+ }
+
+ AWNewScreen(screenId) {
+ return this.wrapPromise(this.sendQuery("AWPage:NEW_SCREEN", screenId));
+ }
+
+ /**
+ * @param {{type: string, detail?: any}} event
+ * @override
+ */
+ handleEvent(event) {
+ lazy.log.debug(`Received page event ${event.type}`);
+ }
+}
diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm
new file mode 100644
index 0000000000..2c9ff90eb2
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm
@@ -0,0 +1,266 @@
+/* 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/. */
+
+"use strict";
+
+const EXPORTED_SYMBOLS = ["AboutWelcomeParent"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
+ BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
+ BuiltInThemes: "resource:///modules/BuiltInThemes.sys.mjs",
+ FxAccounts: "resource://gre/modules/FxAccounts.sys.mjs",
+ LangPackMatcher: "resource://gre/modules/LangPackMatcher.sys.mjs",
+ ShellService: "resource:///modules/ShellService.sys.mjs",
+ SpecialMessageActions:
+ "resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ AboutWelcomeTelemetry:
+ "resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm",
+ AboutWelcomeDefaults:
+ "resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm",
+ AWScreenUtils: "resource://activity-stream/lib/AWScreenUtils.jsm",
+});
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ const { Logger } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/Logger.sys.mjs"
+ );
+ return new Logger("AboutWelcomeParent");
+});
+
+XPCOMUtils.defineLazyGetter(
+ lazy,
+ "Telemetry",
+ () => new lazy.AboutWelcomeTelemetry()
+);
+
+const DID_SEE_ABOUT_WELCOME_PREF = "trailhead.firstrun.didSeeAboutWelcome";
+const AWTerminate = {
+ WINDOW_CLOSED: "welcome-window-closed",
+ TAB_CLOSED: "welcome-tab-closed",
+ APP_SHUT_DOWN: "app-shut-down",
+ ADDRESS_BAR_NAVIGATED: "address-bar-navigated",
+};
+const LIGHT_WEIGHT_THEMES = {
+ AUTOMATIC: "default-theme@mozilla.org",
+ DARK: "firefox-compact-dark@mozilla.org",
+ LIGHT: "firefox-compact-light@mozilla.org",
+ ALPENGLOW: "firefox-alpenglow@mozilla.org",
+ "PLAYMAKER-SOFT": "playmaker-soft-colorway@mozilla.org",
+ "PLAYMAKER-BALANCED": "playmaker-balanced-colorway@mozilla.org",
+ "PLAYMAKER-BOLD": "playmaker-bold-colorway@mozilla.org",
+ "EXPRESSIONIST-SOFT": "expressionist-soft-colorway@mozilla.org",
+ "EXPRESSIONIST-BALANCED": "expressionist-balanced-colorway@mozilla.org",
+ "EXPRESSIONIST-BOLD": "expressionist-bold-colorway@mozilla.org",
+ "VISIONARY-SOFT": "visionary-soft-colorway@mozilla.org",
+ "VISIONARY-BALANCED": "visionary-balanced-colorway@mozilla.org",
+ "VISIONARY-BOLD": "visionary-bold-colorway@mozilla.org",
+ "ACTIVIST-SOFT": "activist-soft-colorway@mozilla.org",
+ "ACTIVIST-BALANCED": "activist-balanced-colorway@mozilla.org",
+ "ACTIVIST-BOLD": "activist-bold-colorway@mozilla.org",
+ "DREAMER-SOFT": "dreamer-soft-colorway@mozilla.org",
+ "DREAMER-BALANCED": "dreamer-balanced-colorway@mozilla.org",
+ "DREAMER-BOLD": "dreamer-bold-colorway@mozilla.org",
+ "INNOVATOR-SOFT": "innovator-soft-colorway@mozilla.org",
+ "INNOVATOR-BALANCED": "innovator-balanced-colorway@mozilla.org",
+ "INNOVATOR-BOLD": "innovator-bold-colorway@mozilla.org",
+};
+
+class AboutWelcomeObserver {
+ constructor() {
+ Services.obs.addObserver(this, "quit-application");
+
+ this.win = Services.focus.activeWindow;
+ if (!this.win) {
+ return;
+ }
+
+ this.terminateReason = AWTerminate.ADDRESS_BAR_NAVIGATED;
+
+ this.onWindowClose = () => {
+ this.terminateReason = AWTerminate.WINDOW_CLOSED;
+ };
+
+ this.onTabClose = () => {
+ this.terminateReason = AWTerminate.TAB_CLOSED;
+ };
+
+ this.win.addEventListener("TabClose", this.onTabClose, { once: true });
+ this.win.addEventListener("unload", this.onWindowClose, { once: true });
+ }
+
+ observe(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case "quit-application":
+ this.terminateReason = AWTerminate.APP_SHUT_DOWN;
+ break;
+ }
+ }
+
+ // Added for testing
+ get AWTerminate() {
+ return AWTerminate;
+ }
+
+ stop() {
+ lazy.log.debug(`Terminate reason is ${this.terminateReason}`);
+ Services.obs.removeObserver(this, "quit-application");
+ if (!this.win) {
+ return;
+ }
+ this.win.removeEventListener("TabClose", this.onTabClose);
+ this.win.removeEventListener("unload", this.onWindowClose);
+ this.win = null;
+ }
+}
+
+class AboutWelcomeParent extends JSWindowActorParent {
+ constructor() {
+ super();
+ this.AboutWelcomeObserver = new AboutWelcomeObserver(this);
+ }
+
+ // Static methods that calls into ShellService to check
+ // if Firefox is pinned or already default
+ static doesAppNeedPin() {
+ return lazy.ShellService.doesAppNeedPin();
+ }
+
+ static isDefaultBrowser() {
+ return lazy.ShellService.isDefaultBrowser();
+ }
+
+ didDestroy() {
+ if (this.AboutWelcomeObserver) {
+ this.AboutWelcomeObserver.stop();
+ }
+ this.RegionHomeObserver?.stop();
+
+ lazy.Telemetry.sendTelemetry({
+ event: "SESSION_END",
+ event_context: {
+ reason: this.AboutWelcomeObserver.terminateReason,
+ page: "about:welcome",
+ },
+ message_id: this.AWMessageId,
+ });
+ }
+
+ /**
+ * Handle messages from AboutWelcomeChild.jsm
+ *
+ * @param {string} type
+ * @param {any=} data
+ * @param {Browser} the xul:browser rendering the page
+ */
+ async onContentMessage(type, data, browser) {
+ lazy.log.debug(`Received content event: ${type}`);
+ switch (type) {
+ case "AWPage:SET_WELCOME_MESSAGE_SEEN":
+ this.AWMessageId = data;
+ try {
+ Services.prefs.setBoolPref(DID_SEE_ABOUT_WELCOME_PREF, true);
+ } catch (e) {
+ lazy.log.debug(`Fails to set ${DID_SEE_ABOUT_WELCOME_PREF}.`);
+ }
+ break;
+ case "AWPage:SPECIAL_ACTION":
+ return lazy.SpecialMessageActions.handleAction(data, browser);
+ case "AWPage:FXA_METRICS_FLOW_URI":
+ return lazy.FxAccounts.config.promiseMetricsFlowURI("aboutwelcome");
+ case "AWPage:TELEMETRY_EVENT":
+ lazy.Telemetry.sendTelemetry(data);
+ break;
+ case "AWPage:GET_ATTRIBUTION_DATA":
+ let attributionData =
+ await lazy.AboutWelcomeDefaults.getAttributionContent();
+ return attributionData;
+ case "AWPage:SELECT_THEME":
+ await lazy.BuiltInThemes.ensureBuiltInThemes();
+ return lazy.AddonManager.getAddonByID(LIGHT_WEIGHT_THEMES[data]).then(
+ addon => addon.enable()
+ );
+ case "AWPage:GET_SELECTED_THEME":
+ let themes = await lazy.AddonManager.getAddonsByTypes(["theme"]);
+ let activeTheme = themes.find(addon => addon.isActive);
+ // Store the current theme ID so user can restore their previous theme.
+ if (activeTheme?.id) {
+ LIGHT_WEIGHT_THEMES.AUTOMATIC = activeTheme.id;
+ }
+ // convert this to the short form name that the front end code
+ // expects
+ let themeShortName = Object.keys(LIGHT_WEIGHT_THEMES).find(
+ key => LIGHT_WEIGHT_THEMES[key] === activeTheme?.id
+ );
+ return themeShortName?.toLowerCase();
+ case "AWPage:DOES_APP_NEED_PIN":
+ return AboutWelcomeParent.doesAppNeedPin();
+ case "AWPage:NEED_DEFAULT":
+ // Only need to set default if we're supposed to check and not default.
+ return (
+ Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser") &&
+ !AboutWelcomeParent.isDefaultBrowser()
+ );
+ case "AWPage:WAIT_FOR_MIGRATION_CLOSE":
+ // Support multiples types of migration: 1) content modal 2) old
+ // migration modal 3) standalone content modal
+ return new Promise(resolve => {
+ const topics = [
+ "MigrationWizard:Closed",
+ "MigrationWizard:Destroyed",
+ ];
+ const observer = () => {
+ topics.forEach(t => Services.obs.removeObserver(observer, t));
+ resolve();
+ };
+ topics.forEach(t => Services.obs.addObserver(observer, t));
+ });
+ case "AWPage:GET_APP_AND_SYSTEM_LOCALE_INFO":
+ return lazy.LangPackMatcher.getAppAndSystemLocaleInfo();
+ case "AWPage:EVALUATE_SCREEN_TARGETING":
+ return lazy.AWScreenUtils.evaluateTargetingAndRemoveScreens(data);
+ case "AWPage:ADD_SCREEN_IMPRESSION":
+ return lazy.AWScreenUtils.addScreenImpression(data);
+ case "AWPage:NEGOTIATE_LANGPACK":
+ return lazy.LangPackMatcher.negotiateLangPackForLanguageMismatch(data);
+ case "AWPage:ENSURE_LANG_PACK_INSTALLED":
+ return lazy.LangPackMatcher.ensureLangPackInstalled(data);
+ case "AWPage:SET_REQUESTED_LOCALES":
+ return lazy.LangPackMatcher.setRequestedAppLocales(data);
+ case "AWPage:SEND_TO_DEVICE_EMAILS_SUPPORTED": {
+ return lazy.BrowserUtils.sendToDeviceEmailsSupported();
+ }
+ default:
+ lazy.log.debug(`Unexpected event ${type} was not handled.`);
+ }
+
+ return undefined;
+ }
+
+ /**
+ * @param {{name: string, data?: any}} message
+ * @override
+ */
+ receiveMessage(message) {
+ const { name, data } = message;
+ let browser;
+
+ if (this.manager.rootFrameLoader) {
+ browser = this.manager.rootFrameLoader.ownerElement;
+ return this.onContentMessage(name, data, browser);
+ }
+
+ lazy.log.warn(`Not handling ${name} because the browser doesn't exist.`);
+ return null;
+ }
+}
diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
new file mode 100644
index 0000000000..fd52cc91e0
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
@@ -0,0 +1,2321 @@
+/*!
+ *
+ * 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_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 */ });
+var _document$querySelect;
+
+/* 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$querySelect = document.querySelector("#multi-stage-message-root.onboardingContainer[data-page]")) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.dataset.page) || document.location.href;
+const AboutWelcomeUtils = {
+ handleUserAction(action) {
+ return window.AWSendToParent("SPECIAL_ACTION", action);
+ },
+
+ sendImpressionTelemetry(messageId, context) {
+ var _window$AWSendEventTe, _window;
+
+ (_window$AWSendEventTe = (_window = window).AWSendEventTelemetry) === null || _window$AWSendEventTe === void 0 ? void 0 : _window$AWSendEventTe.call(_window, {
+ event: "IMPRESSION",
+ event_context: { ...context,
+ page
+ },
+ message_id: messageId
+ });
+ },
+
+ sendActionTelemetry(messageId, elementId, eventName = "CLICK_BUTTON") {
+ var _window$AWSendEventTe2, _window2;
+
+ const ping = {
+ event: eventName,
+ event_context: {
+ source: elementId,
+ page
+ },
+ message_id: messageId
+ };
+ (_window$AWSendEventTe2 = (_window2 = window).AWSendEventTelemetry) === null || _window$AWSendEventTe2 === void 0 ? void 0 : _window$AWSendEventTe2.call(_window2, 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
+ }));
+ }
+
+};
+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__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__(11);
+/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(17);
+/* 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
+ }) => {
+ var _id$split$;
+
+ return id === null || id === void 0 ? void 0 : (_id$split$ = id.split("_")[1]) === null || _id$split$ === void 0 ? void 0 : _id$split$[0];
+ }).join(""); // Send impression ping when respective screen first renders
+
+ filteredScreens.forEach((screen, order) => {
+ if (index === order) {
+ var _window$AWAddScreenIm, _window;
+
+ _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendImpressionTelemetry(`${props.message_id}_${order}_${screen.id}_${screenInitials}`);
+ (_window$AWAddScreenIm = (_window = window).AWAddScreenImpression) === null || _window$AWAddScreenIm === void 0 ? void 0 : _window$AWAddScreenIm.call(_window, 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__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
+ // Save the active multi select state containing array of checkbox ids
+ // used in handleAction to update MULTI_ACTION data
+
+ const [activeMultiSelect, setActiveMultiSelect] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null); // 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;
+ 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,
+ activeMultiSelect: activeMultiSelect,
+ setActiveMultiSelect: setActiveMultiSelect,
+ autoAdvance: screen.auto_advance,
+ negotiatedLanguage: negotiatedLanguage,
+ langPackInstallPhase: langPackInstallPhase
+ }) : null;
+ })));
+};
+const SecondaryCTA = props => {
+ var _props$content$second;
+
+ let targetElement = props.position ? `secondary_button_${props.position}` : `secondary_button`;
+ const buttonStyling = (_props$content$second = props.content.secondary_button) !== null && _props$content$second !== void 0 && _props$content$second.has_arrow_icon ? `secondary text-link arrow-icon` : `secondary text-link`;
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: props.position ? `secondary-cta ${props.position}` : "secondary-cta"
+ }, /*#__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,
+ onClick: props.handleAction
+ })));
+};
+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 = { ..._asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__.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,_asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__.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__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 (!(targetContent && targetContent.action)) {
+ return;
+ } // Send telemetry before waiting on actions
+
+
+ _lib_aboutwelcome_utils__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__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendDismissTelemetry(props.messageId, source);
+ }
+
+ let {
+ action
+ } = targetContent;
+
+ if (action.collectSelect) {
+ // Populate MULTI_ACTION data actions property with selected checkbox actions from tiles data
+ action.data = {
+ actions: []
+ };
+
+ for (const checkbox of ((_props$content = props.content) === null || _props$content === void 0 ? void 0 : (_props$content$tiles = _props$content.tiles) === null || _props$content$tiles === void 0 ? void 0 : _props$content$tiles.data) ?? []) {
+ var _props$content, _props$content$tiles;
+
+ let checkboxAction;
+
+ if (this.props.activeMultiSelect.includes(checkbox.id)) {
+ checkboxAction = checkbox.checkedAction ?? checkbox.action;
+ } else {
+ checkboxAction = checkbox.uncheckedAction;
+ }
+
+ if (checkboxAction) {
+ action.data.actions.push(checkboxAction);
+ }
+ } // Send telemetry with selected checkbox ids
+
+
+ _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(props.messageId, props.activeMultiSelect, "SELECT_CHECKBOX");
+ }
+
+ 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__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.handleUserAction(action);
+
+ if (action.type === "FXA_SIGNIN_FLOW") {
+ _lib_aboutwelcome_utils__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 => {
+ var _a$data, _a$data$actions;
+
+ return a.type === "SHOW_MIGRATION_WIZARD" || a.type === "MULTI_ACTION" && ((_a$data = a.data) === null || _a$data === void 0 ? void 0 : (_a$data$actions = _a$data.actions) === null || _a$data$actions === void 0 ? void 0 : _a$data$actions.some(hasMigrate));
+ };
+
+ if (hasMigrate(action)) {
+ await window.AWWaitForMigrationClose();
+ _lib_aboutwelcome_utils__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>" ? 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();
+ }
+ }
+
+ 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,
+ 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
+ });
+ }
+
+}
+
+/***/ }),
+/* 5 */
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* 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"];
+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:
+ * <Localized text={{string_id: "title"}}><h1 /></Localized>
+ * output:
+ * <h1 data-l10n-id="title">Welcome</h1>
+ *
+ * Unlocalized text
+ * jsx:
+ * <Localized text="Welcome"><h1 /></Localized>
+ * <Localized text={{raw: "Welcome"}}><h1 /></Localized>
+ * output:
+ * <h1>Welcome</h1>
+ */
+
+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 === null || current === void 0 ? void 0 : 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 === null || children === void 0 ? void 0 : 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 _MRColorways__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
+/* harmony import */ var _MobileDownloads__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
+/* harmony import */ var _MultiSelect__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
+/* harmony import */ var _Themes__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
+/* harmony import */ var _MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4);
+/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(11);
+/* harmony import */ var _CTAParagraph__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(12);
+/* harmony import */ var _HeroImage__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(13);
+/* harmony import */ var _OnboardingVideo__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(14);
+/* harmony import */ var _AdditionalCTA__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(15);
+/* harmony import */ var _EmbeddedMigrationWizard__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(16);
+/* 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,
+ 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
+ });
+};
+const ProtonScreenActionButtons = props => {
+ var _content$checkbox, _content$additional_b, _content$primary_butt, _content$primary_butt2;
+
+ const {
+ content,
+ addonName
+ } = props;
+ const defaultValue = (_content$checkbox = content.checkbox) === null || _content$checkbox === void 0 ? void 0 : _content$checkbox.defaultValue;
+ const [isChecked, setIsChecked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(defaultValue || false);
+
+ if (!content.primary_button && !content.secondary_button && !content.additional_button) {
+ return null;
+ }
+
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: `action-buttons ${content.additional_button ? "additional-cta-container" : ""}`,
+ flow: (_content$additional_b = content.additional_button) === null || _content$additional_b === void 0 ? void 0 : _content$additional_b.flow
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: (_content$primary_butt = content.primary_button) === null || _content$primary_butt === void 0 ? void 0 : _content$primary_butt.label
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
+ className: "primary" // 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: ((_content$primary_butt2 = content.primary_button) === null || _content$primary_butt2 === void 0 ? void 0 : _content$primary_butt2.disabled) === true,
+ 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
+ }) : null);
+};
+class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
+ componentDidMount() {
+ this.mainContentHeader.focus();
+ }
+
+ getScreenClassName(isFirstScreen, isLastScreen, includeNoodles, isVideoOnboarding) {
+ const screenClass = `screen-${this.props.order % 2 !== 0 ? 1 : 2}`;
+ if (isVideoOnboarding) return "with-video";
+ return `${isFirstScreen ? `dialog-initial` : ``} ${isLastScreen ? `dialog-last` : ``} ${includeNoodles ? `with-noodles` : ``} ${screenClass}`;
+ }
+
+ renderLogo({
+ imageURL = "chrome://branding/content/about-logo.svg",
+ darkModeImageURL,
+ reducedMotionImageURL,
+ darkModeReducedMotionImageURL,
+ alt = "",
+ height
+ }) {
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("picture", {
+ className: "logo-container"
+ }, 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("img", {
+ className: "brand-logo",
+ style: {
+ height
+ },
+ src: imageURL,
+ alt: alt,
+ 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 === "colorway" && content.tiles.colorways ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MRColorways__WEBPACK_IMPORTED_MODULE_2__.Colorways, {
+ content: content,
+ activeTheme: this.props.activeTheme,
+ 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,
+ activeMultiSelect: this.props.activeMultiSelect,
+ setActiveMultiSelect: this.props.setActiveMultiSelect,
+ handleAction: this.props.handleAction
+ }) : 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() {
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
+ className: "dismiss-button",
+ onClick: this.props.handleAction,
+ value: "dismiss_button",
+ "data-l10n-id": "spotlight-dialog-close-button"
+ });
+ }
+
+ 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": "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",
+ 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"
+ })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: content.help_text
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
+ className: "attrib-text"
+ }))));
+ }
+
+ render() {
+ var _content$tiles, _this$props$appAndSys, _this$props$messageId;
+
+ const {
+ autoAdvance,
+ content,
+ isRtamo,
+ isTheme,
+ isFirstScreen,
+ isLastScreen,
+ isSingleScreen
+ } = this.props;
+ const includeNoodles = content.has_noodles; // The default screen position is "center"
+
+ const isCenterPosition = content.position === "center" || !content.position;
+ const hideStepsIndicator = autoAdvance || (content === null || content === void 0 ? void 0 : content.video_container) || isSingleScreen;
+ 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 === null || content === void 0 ? void 0 : content.video_container) : "";
+ const isEmbeddedMigration = ((_content$tiles = content.tiles) === null || _content$tiles === void 0 ? void 0 : _content$tiles.type) === "migration-wizard";
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("main", {
+ className: `screen ${this.props.id || ""}
+ ${screenClassName} ${textColorClass}`,
+ role: "alertdialog",
+ 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" : ""}`,
+ 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, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: `main-content ${hideStepsIndicator ? "no-steps" : ""}`,
+ style: content.background && isCenterPosition ? {
+ background: content.background
+ } : {}
+ }, content.logo ? this.renderLogo(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,
+ role: "presentation",
+ alt: ""
+ })) : 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 ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: content.title
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", {
+ id: "mainContentHeader"
+ })) : 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$appAndSys = this.props.appAndSystemLocaleInfo) === null || _this$props$appAndSys === void 0 ? void 0 : _this$props$appAndSys.displayNames)
+ }),
+ "aria-flowto": (_this$props$messageId = this.props.messageId) !== null && _this$props$messageId !== void 0 && _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, this.renderContentTiles(), this.renderLanguageSwitcher(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ProtonScreenActionButtons, {
+ content: content,
+ addonName: this.props.addonName,
+ handleAction: this.props.handleAction
+ })), !hideStepsIndicator ? this.renderStepsIndicator() : null), content.dismiss_button ? this.renderDismissButton() : null));
+ }
+
+}
+
+/***/ }),
+/* 7 */
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "ColorwayDescription": () => (/* binding */ ColorwayDescription),
+/* harmony export */ "computeColorWay": () => (/* binding */ computeColorWay),
+/* harmony export */ "computeVariationIndex": () => (/* binding */ computeVariationIndex),
+/* harmony export */ "Colorways": () => (/* binding */ Colorways)
+/* 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 ColorwayDescription = props => {
+ const {
+ colorway
+ } = props;
+
+ if (!colorway) {
+ return null;
+ }
+
+ const {
+ label,
+ description
+ } = colorway;
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: description
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: "colorway-text",
+ "data-l10n-args": JSON.stringify({
+ colorwayName: label
+ })
+ }));
+}; // Return colorway as "default" for default theme variations Automatic, Light, Dark,
+// Alpenglow theme and legacy colorways which is not supported in Colorway picker.
+// For themes other then default, theme names exist in
+// format colorway-variationId inside LIGHT_WEIGHT_THEMES in AboutWelcomeParent
+
+function computeColorWay(themeName, systemVariations) {
+ return !themeName || themeName === "alpenglow" || systemVariations.includes(themeName) ? "default" : themeName.split("-")[0];
+} // Set variationIndex based off activetheme value e.g. 'light', 'expressionist-soft'
+
+function computeVariationIndex(themeName, systemVariations, variations, defaultVariationIndex) {
+ // Check if themeName is in systemVariations, if yes choose variationIndex by themeName
+ let index = systemVariations.findIndex(theme => theme === themeName);
+
+ if (index >= 0) {
+ return index;
+ } // If themeName is one of the colorways, select variation index from colorways
+
+
+ let variation = themeName === null || themeName === void 0 ? void 0 : themeName.split("-")[1];
+ index = variations.findIndex(element => element === variation);
+
+ if (index >= 0) {
+ return index;
+ }
+
+ return defaultVariationIndex;
+}
+function Colorways(props) {
+ let {
+ colorways,
+ darkVariation,
+ defaultVariationIndex,
+ systemVariations,
+ variations
+ } = props.content.tiles;
+ let hasReverted = false; // Active theme id from JSON e.g. "expressionist"
+
+ const activeId = computeColorWay(props.activeTheme, systemVariations);
+ const [colorwayId, setState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(activeId);
+ const [variationIndex, setVariationIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(defaultVariationIndex);
+
+ function revertToDefaultTheme() {
+ if (hasReverted) return; // Spoofing an event with current target value of "navigate_away"
+ // helps the handleAction method to read the colorways theme as "revert"
+ // which causes the initial theme to be activated.
+ // The "navigate_away" action is set in content in the colorways screen JSON config.
+ // Any value in the JSON for theme will work, provided it is not `<event>`.
+
+ const event = {
+ currentTarget: {
+ value: "navigate_away"
+ }
+ };
+ props.handleAction(event);
+ hasReverted = true;
+ } // Revert to default theme if the user navigates away from the page or spotlight modal
+ // before clicking on the primary button to officially set theme.
+
+
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
+ addEventListener("beforeunload", revertToDefaultTheme);
+ addEventListener("pagehide", revertToDefaultTheme);
+ return () => {
+ removeEventListener("beforeunload", revertToDefaultTheme);
+ removeEventListener("pagehide", revertToDefaultTheme);
+ };
+ }); // Update state any time activeTheme changes.
+
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
+ setState(computeColorWay(props.activeTheme, systemVariations));
+ setVariationIndex(computeVariationIndex(props.activeTheme, systemVariations, variations, defaultVariationIndex)); // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [props.activeTheme]); //select a random colorway
+
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
+ //We don't want the default theme to be selected
+ const randomIndex = Math.floor(Math.random() * (colorways.length - 1)) + 1;
+ const randomColorwayId = colorways[randomIndex].id; // Change the variation to be the dark variation if configured and dark.
+ // Additional colorway changes will remain dark while system is unchanged.
+
+ if (darkVariation !== undefined && window.matchMedia("(prefers-color-scheme: dark)").matches) {
+ variations[variationIndex] = variations[darkVariation];
+ }
+
+ const value = `${randomColorwayId}-${variations[variationIndex]}`;
+ props.handleAction({
+ currentTarget: {
+ value
+ }
+ }); // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ 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"
+ })), colorways.map(({
+ id,
+ label,
+ tooltip
+ }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ key: id + label,
+ text: typeof tooltip === "object" ? tooltip : {}
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
+ className: "theme",
+ title: label,
+ "data-l10n-args": JSON.stringify({
+ colorwayName: label
+ })
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: typeof tooltip === "object" ? tooltip : {}
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
+ className: "sr-only colorway label",
+ id: `${id}-label`,
+ "data-l10n-args": JSON.stringify({
+ colorwayName: tooltip
+ })
+ })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: typeof label === "object" ? label : {}
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", {
+ type: "radio",
+ "data-colorway": id,
+ name: "theme",
+ value: id === "default" ? systemVariations[variationIndex] : `${id}-${variations[variationIndex]}`,
+ checked: colorwayId === id,
+ className: "sr-only input",
+ onClick: props.handleAction,
+ "data-l10n-args": JSON.stringify({
+ colorwayName: label
+ }),
+ "aria-labelledby": `${id}-label`
+ })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: `icon colorway ${colorwayId === id ? "selected" : ""} ${id}`
+ })))))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ColorwayDescription, {
+ colorway: colorways.find(colorway => colorway.id === activeId)
+ }));
+}
+
+/***/ }),
+/* 8 */
+/***/ ((__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);
+/* 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
+ }) : 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);
+};
+
+/***/ }),
+/* 9 */
+/***/ ((__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 MultiSelect = props => {
+ let handleChange = event => {
+ if (event.currentTarget.checked) {
+ props.setActiveMultiSelect([...props.activeMultiSelect, event.currentTarget.value]);
+ } else {
+ props.setActiveMultiSelect(props.activeMultiSelect.filter(id => id !== event.currentTarget.value));
+ }
+ };
+
+ let {
+ data
+ } = props.content.tiles; // When screen renders for first time, update state
+ // with checkbox ids that has defaultvalue true
+
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
+ if (!props.activeMultiSelect) {
+ props.setActiveMultiSelect(data.map(item => item.defaultValue && item.id).filter(item => !!item));
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
+
+ }, []);
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ className: "multi-select-container"
+ }, props.content.tiles.data.map(({
+ label,
+ id
+ }) => {
+ var _props$activeMultiSel;
+
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
+ key: id + label,
+ className: "checkbox-container multi-select-item"
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", {
+ type: "checkbox",
+ id: id,
+ value: id,
+ checked: (_props$activeMultiSel = props.activeMultiSelect) === null || _props$activeMultiSel === void 0 ? void 0 : _props$activeMultiSel.includes(id),
+ onChange: handleChange
+ }), /*#__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
+ })));
+ }));
+};
+
+/***/ }),
+/* 10 */
+/***/ ((__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"
+ }))))))));
+};
+
+/***/ }),
+/* 11 */
+/***/ ((__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__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)(() => {
+ var _screen$content;
+
+ if (screen !== null && screen !== void 0 && (_screen$content = screen.content) !== null && _screen$content !== void 0 && _screen$content.languageSwitcher) {
+ for (const text of Object.values(screen.content.languageSwitcher)) {
+ if (text !== null && text !== void 0 && 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 === null || screen === void 0 ? void 0 : 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]);
+ 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 === null || appAndSystemLocaleInfo === void 0 ? void 0 : appAndSystemLocaleInfo.matchType) !== "language-mismatch" || (negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.langPack) === null)) {
+ if (screenIndex > languageMismatchScreenIndex) {
+ setScreenIndex(screenIndex - 1);
+ }
+
+ setLanguageFilteredScreens(screens.filter(s => s.id !== "AW_LANGUAGE_MISMATCH"));
+ } else {
+ setLanguageFilteredScreens(screens);
+ }
+ }, [screens, negotiatedLanguage]);
+ 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"
+ }
+ });
+ });
+ }
+ }, [isAwaitingLangpack, langPackInstallPhase]);
+ 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__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 === null || negotiatedLanguage === void 0 ? void 0 : 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 === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.appDisplayName))));
+}
+
+/***/ }),
+/* 12 */
+/***/ ((__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 !== null && content !== void 0 && 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));
+};
+
+/***/ }),
+/* 13 */
+/***/ ((__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__);
+/* 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,
+ alt: alt || "",
+ role: alt ? null : "presentation"
+ }));
+};
+
+/***/ }),
+/* 14 */
+/***/ ((__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
+ })));
+};
+
+/***/ }),
+/* 15 */
+/***/ ((__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);
+/* 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
+}) => {
+ var _content$additional_b, _content$additional_b4, _content$additional_b5;
+
+ let buttonStyle = "";
+
+ if (!((_content$additional_b = content.additional_button) !== null && _content$additional_b !== void 0 && _content$additional_b.style)) {
+ buttonStyle = "primary";
+ } else {
+ var _content$additional_b2, _content$additional_b3;
+
+ buttonStyle = ((_content$additional_b2 = content.additional_button) === null || _content$additional_b2 === void 0 ? void 0 : _content$additional_b2.style) === "link" ? "cta-link" : (_content$additional_b3 = content.additional_button) === null || _content$additional_b3 === void 0 ? void 0 : _content$additional_b3.style;
+ }
+
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
+ text: (_content$additional_b4 = content.additional_button) === null || _content$additional_b4 === void 0 ? void 0 : _content$additional_b4.label
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
+ className: `${buttonStyle} additional-cta`,
+ onClick: handleAction,
+ value: "additional_button",
+ disabled: ((_content$additional_b5 = content.additional_button) === null || _content$additional_b5 === void 0 ? void 0 : _content$additional_b5.disabled) === true
+ }));
+};
+
+/***/ }),
+/* 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 === null || current === void 0 ? void 0 : current.addEventListener("MigrationWizard:BeginMigration", handleBeginMigration);
+ current === null || current === void 0 ? void 0 : current.addEventListener("MigrationWizard:Close", handleClose);
+ return () => {
+ current === null || current === void 0 ? void 0 : current.removeEventListener("MigrationWizard:BeginMigration", handleBeginMigration);
+ current === null || current === void 0 ? void 0 : current.removeEventListener("MigrationWizard:Close", handleClose);
+ };
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
+
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("migration-wizard", {
+ "auto-request-state": "",
+ ref: ref
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("panel-list", null));
+};
+
+/***/ }),
+/* 17 */
+/***/ ((__unused_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;
+}
+
+/***/ }),
+/* 18 */
+/***/ ((__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__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
+/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
+/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
+/* 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__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 = { ..._asrouter_templates_FirstRun_addUtmParams__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__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.handleUserAction({
+ type,
+ data
+ });
+ _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__.AboutWelcomeUtils.sendActionTelemetry(message_id, source_id);
+ }
+
+ render() {
+ var _this$props$themeScre;
+
+ const {
+ content,
+ type
+ } = this.props;
+
+ if (!content) {
+ return null;
+ }
+
+ if (content !== null && content !== void 0 && 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$themeScre = this.props.themeScreenshots[0]) === null || _this$props$themeScre === void 0 ? void 0 : _this$props$themeScre.url : this.props.iconURL,
+ addonName: this.props.name,
+ handleAction: this.handleAction
+ }));
+ }
+
+}
+ReturnToAMO.defaultProps = _lib_aboutwelcome_utils__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__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__(18);
+function _extends() { _extends = Object.assign || 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() {
+ var _window$AWGetFxAMetri, _window;
+
+ this.setState({
+ metricsFlowUri: await ((_window$AWGetFxAMetri = (_window = window).AWGetFxAMetricsFlowURI) === null || _window$AWGetFxAMetri === void 0 ? void 0 : _window$AWGetFxAMetri.call(_window))
+ });
+ }
+
+ componentDidMount() {
+ if (!this.props.skipFxA) {
+ this.fetchFxAFlowUri();
+ } // Record impression with performance data after allowing the page to load
+
+
+ const recordImpression = domState => {
+ const {
+ domComplete,
+ domInteractive
+ } = performance.getEntriesByType("navigation").pop();
+ _lib_aboutwelcome_utils__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
+ });
+ }
+
+} // 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
diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.css b/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
new file mode 100644
index 0000000000..ba9c835693
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
@@ -0,0 +1,1644 @@
+/* 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/. */
+.onboardingContainer.featureCallout {
+ --fc-background: var(--fc-background-light, #FFF);
+ --fc-color: var(--fc-color-light, #15141A);
+ --fc-border: var(--fc-border-light, #CFCFD8);
+ --fc-accent-color: var(--fc-accent-color-light, #0061E0);
+ --fc-button-background: var(--fc-button-background-light, #F0F0F4);
+ --fc-button-color: var(--fc-button-color-light, #15141A);
+ --fc-button-border: var(--fc-button-border-light, transparent);
+ --fc-button-background-hover: var(--fc-button-background-hover-light, #E0E0E6);
+ --fc-button-color-hover: var(--fc-button-color-hover-light, #15141A);
+ --fc-button-border-hover: var(--fc-button-border-hover-light, transparent);
+ --fc-button-background-active: var(--fc-button-background-active-light, #CFCFD8);
+ --fc-button-color-active: var(--fc-button-color-active-light, #15141A);
+ --fc-button-border-active: var(--fc-button-border-active-light, transparent);
+ --fc-step-color: color-mix(in srgb, currentColor 50%, transparent);
+ position: absolute;
+ transition: opacity 0.5s ease;
+ z-index: 2147483645;
+ outline: none;
+ color: var(--fc-color);
+}
+@media (prefers-color-scheme: dark) {
+ .onboardingContainer.featureCallout {
+ --fc-background: var(--fc-background-dark, #42414D);
+ --fc-color: var(--fc-color-dark, #FBFBFE);
+ --fc-border: var(--fc-border-dark, #3A3944);
+ --fc-accent-color: var(--fc-accent-color-dark, #00DDFF);
+ --fc-button-background: var(--fc-button-background-dark, #2B2A33);
+ --fc-button-color: var(--fc-button-color-dark, #FBFBFE);
+ --fc-button-border: var(--fc-button-border-dark, transparent);
+ --fc-button-background-hover: var(--fc-button-background-hover-dark, #52525E);
+ --fc-button-color-hover: var(--fc-button-color-hover-dark, #FBFBFE);
+ --fc-button-border-hover: var(--fc-button-border-hover-dark, transparent);
+ --fc-button-background-active: var(--fc-button-background-active-dark, #5B5B66);
+ --fc-button-color-active: var(--fc-button-color-active-dark, #FBFBFE);
+ --fc-button-border-active: var(--fc-button-border-active-dark, transparent);
+ }
+}
+@media (prefers-contrast) {
+ .onboardingContainer.featureCallout {
+ --fc-background: var(--fc-background-hcm, -moz-dialog);
+ --fc-color: var(--fc-color-hcm, -moz-dialogtext);
+ --fc-border: var(--fc-border-hcm, -moz-dialogtext);
+ --fc-accent-color: var(--fc-accent-color-hcm, LinkText);
+ --fc-button-background: var(--fc-button-background-hcm, ButtonFace);
+ --fc-button-color: var(--fc-button-color-hcm, ButtonText);
+ --fc-button-border: var(--fc-button-border-hcm, ButtonText);
+ --fc-button-background-hover: var(--fc-button-background-hover-hcm, ButtonText);
+ --fc-button-color-hover: var(--fc-button-color-hover-hcm, ButtonFace);
+ --fc-button-border-hover: var(--fc-button-border-hover-hcm, ButtonText);
+ --fc-button-background-active: var(--fc-button-background-active-hcm, ButtonText);
+ --fc-button-color-active: var(--fc-button-color-active-hcm, ButtonFace);
+ --fc-button-border-active: var(--fc-button-border-active-hcm, ButtonText);
+ --fc-step-color: var(--fc-accent-color-hcm, LinkText);
+ }
+}
+@media (-moz-content-prefers-color-scheme: light) {
+ .onboardingContainer.featureCallout.simulateContent {
+ --fc-background: var(--fc-background-light, #FFF);
+ --fc-color: var(--fc-color-light, #15141A);
+ --fc-border: var(--fc-border-light, #CFCFD8);
+ --fc-accent-color: var(--fc-accent-color-light, #0061E0);
+ --fc-button-background: var(--fc-button-background-light, #F0F0F4);
+ --fc-button-color: var(--fc-button-color-light, #15141A);
+ --fc-button-border: var(--fc-button-border-light, transparent);
+ --fc-button-background-hover: var(--fc-button-background-hover-light, #E0E0E6);
+ --fc-button-color-hover: var(--fc-button-color-hover-light, #15141A);
+ --fc-button-border-hover: var(--fc-button-border-hover-light, transparent);
+ --fc-button-background-active: var(--fc-button-background-active-light, #CFCFD8);
+ --fc-button-color-active: var(--fc-button-color-active-light, #15141A);
+ --fc-button-border-active: var(--fc-button-border-active-light, transparent);
+ --fc-step-color: color-mix(in srgb, currentColor 50%, transparent);
+ }
+}
+@media (-moz-content-prefers-color-scheme: dark) {
+ .onboardingContainer.featureCallout.simulateContent {
+ --fc-background: var(--fc-background-dark, #42414D);
+ --fc-color: var(--fc-color-dark, #FBFBFE);
+ --fc-border: var(--fc-border-dark, #3A3944);
+ --fc-accent-color: var(--fc-accent-color-dark, #00DDFF);
+ --fc-button-background: var(--fc-button-background-dark, #2B2A33);
+ --fc-button-color: var(--fc-button-color-dark, #FBFBFE);
+ --fc-button-border: var(--fc-button-border-dark, transparent);
+ --fc-button-background-hover: var(--fc-button-background-hover-dark, #52525E);
+ --fc-button-color-hover: var(--fc-button-color-hover-dark, #FBFBFE);
+ --fc-button-border-hover: var(--fc-button-border-hover-dark, transparent);
+ --fc-button-background-active: var(--fc-button-background-active-dark, #5B5B66);
+ --fc-button-color-active: var(--fc-button-color-active-dark, #FBFBFE);
+ --fc-button-border-active: var(--fc-button-border-active-dark, transparent);
+ }
+}
+@media (prefers-contrast) {
+ .onboardingContainer.featureCallout.simulateContent {
+ --fc-background: var(--fc-background-hcm, -moz-dialog);
+ --fc-color: var(--fc-color-hcm, -moz-dialogtext);
+ --fc-border: var(--fc-border-hcm, -moz-dialogtext);
+ --fc-accent-color: var(--fc-accent-color-hcm, LinkText);
+ --fc-button-background: var(--fc-button-background-hcm, ButtonFace);
+ --fc-button-color: var(--fc-button-color-hcm, ButtonText);
+ --fc-button-border: var(--fc-button-border-hcm, ButtonText);
+ --fc-button-background-hover: var(--fc-button-background-hover-hcm, ButtonText);
+ --fc-button-color-hover: var(--fc-button-color-hover-hcm, ButtonFace);
+ --fc-button-border-hover: var(--fc-button-border-hover-hcm, ButtonText);
+ --fc-button-background-active: var(--fc-button-background-active-hcm, ButtonText);
+ --fc-button-color-active: var(--fc-button-color-active-hcm, ButtonFace);
+ --fc-button-border-active: var(--fc-button-border-active-hcm, ButtonText);
+ --fc-step-color: var(--fc-accent-color-hcm, LinkText);
+ }
+}
+.onboardingContainer.featureCallout.hidden {
+ opacity: 0;
+ pointer-events: none;
+}
+.onboardingContainer.featureCallout, .onboardingContainer.featureCallout .outer-wrapper {
+ height: auto;
+}
+.onboardingContainer.featureCallout .screen:dir(rtl) {
+ transform: none;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] {
+ height: fit-content;
+ min-height: unset;
+ overflow: visible;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .logo-container {
+ display: flex;
+ justify-content: center;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .logo-container .brand-logo {
+ margin: 30px 45px 0;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .logo-container .brand-logo:dir(rtl) {
+ transform: rotateY(180deg);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .welcome-text {
+ align-items: baseline;
+ text-align: start;
+ margin-inline: 30px;
+ padding: 20px 0 0;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .welcome-text h1,
+.onboardingContainer.featureCallout .screen[pos=callout] .welcome-text h2 {
+ font-size: 0.8em;
+ margin: 0;
+ color: inherit;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .welcome-text h1 {
+ font-weight: bold;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .welcome-text h2 {
+ margin-block: 10px;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-secondary {
+ display: none;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main {
+ height: fit-content;
+ width: fit-content;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content {
+ position: relative;
+ overflow: hidden;
+ border: 1px solid var(--fc-border);
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+ border-radius: 4px;
+ padding-top: 0;
+ padding-bottom: 26px;
+ width: 25em;
+ background-color: var(--fc-background);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content .steps {
+ height: auto;
+ position: absolute;
+ bottom: 42px;
+ margin: 0 30px;
+ padding-block: 0;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content .steps .indicator {
+ border: 4px solid var(--fc-step-color);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content .steps .indicator.current {
+ border-color: var(--fc-accent-color);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content .steps .indicator.current, .onboardingContainer.featureCallout .screen[pos=callout] .section-main .main-content .steps.progress-bar .indicator.complete {
+ border-color: var(--fc-accent-color);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .section-main .dismiss-button {
+ font-size: 1em;
+ top: 0;
+ margin-block: 15px 0;
+ margin-inline: 0 15px;
+ z-index: 2147483647;
+ background-color: var(--fc-background);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary,
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta .secondary {
+ padding: 4px 16px;
+ font-size: 0.8em;
+ height: 2em;
+ background-color: var(--fc-button-background);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary {
+ font-weight: bold;
+ float: inline-end;
+ margin-inline: 10px 30px;
+ padding: 4px 16px;
+ font-size: 0.8em;
+ line-height: 16px;
+ min-height: 32px;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta {
+ float: inline-end;
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary,
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta .secondary,
+.onboardingContainer.featureCallout .screen[pos=callout] .dismiss-button {
+ border-radius: 4px;
+ border: 1px solid var(--fc-button-border);
+ cursor: pointer;
+ color: var(--fc-button-color);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary:hover,
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta .secondary:hover,
+.onboardingContainer.featureCallout .screen[pos=callout] .dismiss-button:hover {
+ background-color: var(--fc-button-background-hover);
+ color: var(--fc-button-color-hover);
+ border: 1px solid var(--fc-button-border-hover);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary:hover:active,
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta .secondary:hover:active,
+.onboardingContainer.featureCallout .screen[pos=callout] .dismiss-button:hover:active {
+ background-color: var(--fc-button-background-active);
+ color: var(--fc-button-color-active);
+ border: 1px solid var(--fc-button-border-active);
+}
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .primary:focus-visible,
+.onboardingContainer.featureCallout .screen[pos=callout] .action-buttons .secondary-cta .secondary:focus-visible,
+.onboardingContainer.featureCallout .screen[pos=callout] .dismiss-button:focus-visible {
+ box-shadow: none;
+ outline: 2px solid var(--fc-accent-color);
+ outline-offset: 2px;
+}
+.onboardingContainer.featureCallout.callout-arrow::before, .onboardingContainer.featureCallout.callout-arrow::after {
+ content: "";
+ position: absolute;
+ width: 24px;
+ height: 24px;
+ transform: rotate(45deg);
+ transform-style: preserve-3d;
+}
+.onboardingContainer.featureCallout.callout-arrow::before {
+ z-index: 2147483647;
+ background-color: var(--fc-background);
+}
+.onboardingContainer.featureCallout.callout-arrow::after {
+ background: transparent;
+ outline: 1px solid var(--fc-border);
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+ z-index: -1;
+}
+.onboardingContainer.featureCallout.arrow-top::before, .onboardingContainer.featureCallout.arrow-top::after {
+ top: -11px;
+ inset-inline-start: calc(50% - 12px);
+}
+.onboardingContainer.featureCallout.arrow-bottom::before, .onboardingContainer.featureCallout.arrow-bottom::after {
+ bottom: -11px;
+ inset-inline-start: calc(50% - 12px);
+}
+.onboardingContainer.featureCallout.arrow-inline-end::before, .onboardingContainer.featureCallout.arrow-inline-end::after {
+ top: calc(50% - 12px);
+ inset-inline-end: -11px;
+}
+.onboardingContainer.featureCallout.arrow-inline-start::before, .onboardingContainer.featureCallout.arrow-inline-start::after {
+ top: calc(50% - 12px);
+ inset-inline-start: -11px;
+}
+.onboardingContainer.featureCallout.arrow-top-end::before, .onboardingContainer.featureCallout.arrow-top-end::after {
+ top: -11px;
+ inset-inline-end: 12px;
+}
+.onboardingContainer.featureCallout.arrow-top-start::before, .onboardingContainer.featureCallout.arrow-top-start::after {
+ top: -11px;
+ inset-inline-start: 12px;
+}
+.onboardingContainer.featureCallout.hidden-arrow::before, .onboardingContainer.featureCallout.hidden-arrow::after {
+ display: none;
+}
+.onboardingContainer.featureCallout:focus-visible .screen[pos=callout] .section-main .main-content {
+ outline: 2px solid var(--fc-accent-color);
+ border-color: transparent;
+}
+@media (prefers-contrast) {
+ .onboardingContainer.featureCallout:focus-visible .screen[pos=callout] .section-main .main-content {
+ border-color: var(--fc-background);
+ }
+}
+.onboardingContainer.featureCallout:focus-visible.callout-arrow::after {
+ outline: 2px solid var(--fc-accent-color);
+}
+
+html {
+ height: 100%;
+}
+
+.dummy {
+ background: var(--mr-welcome-background-color) var(--mr-welcome-background-gradient) var(--mr-secondary-position) var(--mr-screen-background-color);
+}
+
+:root[dialogroot] {
+ background-color: transparent;
+}
+:root[dialogroot] body {
+ padding: 0;
+}
+:root[dialogroot] .onboardingContainer {
+ height: 100%;
+ background-color: transparent;
+}
+:root[dialogroot] .onboardingContainer:dir(rtl) {
+ transform: unset;
+}
+:root[dialogroot] .onboardingContainer .logo-container {
+ pointer-events: none;
+}
+:root[dialogroot] .onboardingContainer .screen:dir(rtl) {
+ transform: unset;
+}
+
+.welcome-container .onboardingContainer {
+ min-height: 610px;
+ min-width: fit-content;
+}
+
+.onboardingContainer {
+ --grey-subtitle-1: #696977;
+ --mr-welcome-background-color: #F8F6F4;
+ --mr-screen-heading-color: var(--in-content-text-color);
+ --mr-welcome-background-gradient: linear-gradient(0deg, rgba(144, 89, 255, 20%) 0%, rgba(2, 144, 238, 20%) 100%);
+ --mr-screen-background-color: #F8F6F4;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Ubuntu, "Helvetica Neue", sans-serif;
+ font-size: 16px;
+ position: relative;
+ text-align: center;
+ height: 100vh;
+ --transition: 0.6s opacity, 0.6s scale, 0.6s rotate, 0.6s translate;
+}
+@media (prefers-color-scheme: dark) {
+ .onboardingContainer {
+ --grey-subtitle-1: #FFF;
+ --mr-welcome-background-color: #333336;
+ --mr-welcome-background-gradient: linear-gradient(0deg, rgba(144, 89, 255, 30%) 0%, rgba(2, 144, 238, 30%) 100%);
+ --mr-screen-background-color: #62697A;
+ }
+}
+@media (prefers-contrast) {
+ .onboardingContainer {
+ --mr-screen-background-color: buttontext;
+ --mr-screen-heading-color: buttonface;
+ background-color: var(--in-content-page-background);
+ }
+}
+@media (prefers-reduced-motion: no-preference) {
+ .onboardingContainer {
+ --translate: 30px;
+ --rotate: 20deg;
+ --scale: 0.4;
+ --progress-bar-transition: 0.6s translate;
+ }
+ .onboardingContainer:dir(rtl) {
+ --scale: -0.4 0.4;
+ }
+}
+@media (prefers-reduced-motion: reduce) {
+ .onboardingContainer {
+ --translate: 0;
+ --rotate: 0deg;
+ --scale: 1;
+ --progress-bar-transition: none;
+ }
+ .onboardingContainer:dir(rtl) {
+ --scale: -1 1;
+ }
+}
+.onboardingContainer:dir(rtl) {
+ transform: rotateY(180deg);
+}
+.onboardingContainer .section-main {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ width: 504px;
+ flex-shrink: 0;
+}
+.onboardingContainer .section-main:not(.embedded-migration) {
+ position: relative;
+}
+.onboardingContainer .main-content {
+ background-color: var(--in-content-page-background);
+ border-radius: 20px;
+ box-shadow: 0 2px 14px 0 rgba(0, 0, 0, 0.2);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ padding: 0;
+ transition: var(--transition);
+ z-index: 1;
+ box-sizing: border-box;
+}
+.onboardingContainer .main-content.no-steps {
+ padding-bottom: 48px;
+}
+.onboardingContainer .main-content .main-content-inner {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ justify-content: space-around;
+}
+.onboardingContainer .main-content .no-steps .main-content {
+ padding-bottom: 48px;
+}
+.onboardingContainer .main-content .no-steps .steps {
+ display: none;
+}
+.onboardingContainer .screen {
+ display: flex;
+ position: relative;
+ flex-flow: row nowrap;
+ height: 100%;
+ min-height: 500px;
+ overflow: hidden;
+ --in-content-link-color: var(--in-content-primary-button-background);
+ --in-content-link-color-hover: var(--in-content-primary-button-background-hover);
+ --in-content-link-color-active: var(--in-content-primary-button-background-active);
+ --in-content-link-color-visited: var(--in-content-link-color);
+}
+.onboardingContainer .screen.light-text {
+ --in-content-page-color: rgb(251, 251, 254);
+ --in-content-primary-button-text-color: rgb(43, 42, 51);
+ --in-content-primary-button-text-color-hover: rgb(43, 42, 51);
+ --in-content-primary-button-background: rgb(0, 221, 255);
+ --in-content-primary-button-background-hover: rgb(128, 235, 255);
+ --in-content-primary-button-background-active: rgb(170, 242, 255);
+ --checkbox-checked-bgcolor: var(--in-content-primary-button-background);
+ --in-content-button-text-color: var(--in-content-page-color);
+}
+.onboardingContainer .screen.dark-text {
+ --in-content-page-color: rgb(21, 20, 26);
+ --in-content-primary-button-text-color: rgb(251, 251, 254);
+ --in-content-primary-button-text-color-hover: rgb(251, 251, 254);
+ --in-content-primary-button-background: #0061E0;
+ --in-content-primary-button-background-hover: #0250BB;
+ --in-content-primary-button-background-active: #053E94;
+ --in-content-primary-button-border-color: transparent;
+ --in-content-primary-button-border-hover: transparent;
+ --checkbox-checked-bgcolor: var(--in-content-primary-button-background);
+ --in-content-button-text-color: var(--in-content-page-color);
+}
+.onboardingContainer .screen:dir(rtl) {
+ transform: rotateY(180deg);
+}
+.onboardingContainer .screen[pos=center] {
+ background-color: rgba(21, 20, 26, 0.5);
+ min-width: 504px;
+}
+.onboardingContainer .screen[pos=center].with-noodles {
+ min-width: 610px;
+ min-height: 610px;
+}
+.onboardingContainer .screen[pos=center].with-noodles .section-main {
+ height: 504px;
+}
+.onboardingContainer .screen[pos=center].with-video {
+ justify-content: center;
+ background: none;
+ align-items: center;
+}
+.onboardingContainer .screen[pos=center].with-video .section-main {
+ width: 800px;
+ height: 550px;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content {
+ background-color: var(--mr-welcome-background-color);
+ border-radius: 8px;
+ box-shadow: 0 2px 14px rgba(58, 57, 68, 0.2);
+ padding: 44px 85px 20px;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .welcome-text {
+ margin: 0;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .main-content-inner {
+ justify-content: space-between;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content h1,
+.onboardingContainer .screen[pos=center].with-video .main-content h2 {
+ align-self: start;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content h1 {
+ font-size: 24px;
+ line-height: 28.8px;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content h2 {
+ font-size: 15px;
+ line-height: 22px;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta {
+ justify-content: end;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta .arrow-icon {
+ -moz-context-properties: fill;
+ fill: currentColor;
+ text-decoration: none;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta .arrow-icon::after {
+ content: "";
+ padding-inline-end: 12px;
+ margin-inline-start: 4px;
+ background: url("chrome://browser/skin/forward.svg") no-repeat center/12px;
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta .arrow-icon:dir(rtl)::after {
+ background-image: url("chrome://browser/skin/back.svg");
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta .secondary {
+ background-color: var(--in-content-button-background) !important;
+ border: 1px solid var(--in-content-button-border-color);
+ line-height: 12px;
+ font-size: 0.72em;
+ font-weight: 600;
+ padding: 8px 16px;
+ text-decoration: none;
+ color: var(--in-content-button-text-color);
+}
+.onboardingContainer .screen[pos=center].with-video .main-content .secondary-cta .secondary:hover {
+ background-color: var(--in-content-button-background-hover) !important;
+ color: var(--in-content-button-text-color-hover);
+}
+.onboardingContainer .screen:not([pos=split]) .secondary-cta .secondary {
+ background: none;
+ color: var(--in-content-link-color);
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 20px;
+}
+.onboardingContainer .screen:not([pos=split]) .secondary-cta.top button {
+ color: #FFF;
+}
+.onboardingContainer .screen:not([pos=split]) .secondary-cta.top button:hover {
+ color: #E0E0E6;
+}
+.onboardingContainer .screen[pos=split] {
+ margin: auto;
+ min-height: 550px;
+}
+.onboardingContainer .screen[pos=split]::before {
+ content: "";
+ position: absolute;
+ box-shadow: 0 2px 14px 0 rgba(0, 0, 0, 0.2);
+ width: 800px;
+ height: 550px;
+ border-radius: 8px;
+ inset: 0;
+ margin: auto;
+ pointer-events: none;
+}
+.onboardingContainer .screen[pos=split] .section-secondary,
+.onboardingContainer .screen[pos=split] .section-main {
+ width: 400px;
+ height: 550px;
+}
+.onboardingContainer .screen[pos=split] .secondary-cta.top {
+ position: fixed;
+ padding-inline-end: 0;
+}
+.onboardingContainer .screen[pos=split] .secondary-cta.top button {
+ color: var(--in-content-page-color);
+}
+.onboardingContainer .screen[pos=split] .section-main {
+ flex-direction: row;
+ display: block;
+ margin: auto auto auto 0;
+}
+.onboardingContainer .screen[pos=split] .section-main:dir(rtl) {
+ margin: auto 0 auto auto;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content {
+ border-radius: 0 8px 8px 0;
+ overflow: hidden;
+ padding-inline: 35px 20px;
+ padding-block: 120px 0;
+ box-shadow: none;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content.no-steps {
+ padding-bottom: 48px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content:dir(rtl) {
+ border-radius: 8px 0 0 8px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .main-content-inner {
+ min-height: 330px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .main-content-inner .language-switcher-container .primary {
+ margin-bottom: 5px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons {
+ position: relative;
+ text-align: initial;
+ height: 100%;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .checkbox-container {
+ font-size: 13px;
+ margin-block: 1em;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .checkbox-container:not(.multi-select-item) {
+ transition: var(--transition);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .checkbox-container input,
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .checkbox-container label {
+ vertical-align: middle;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .additional-cta {
+ margin: 8px 0;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .additional-cta.cta-link {
+ background: none;
+ padding: 0;
+ font-weight: normal;
+ text-decoration: underline;
+ cursor: pointer;
+ color: var(--in-content-link-color);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .additional-cta.cta-link:hover {
+ text-decoration: none;
+ color: var(--in-content-link-color-hover);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .additional-cta.cta-link:active {
+ text-decoration: none;
+ color: var(--in-content-link-color-active);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .additional-cta.secondary:hover {
+ background-color: var(--in-content-button-background-hover);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons.additional-cta-container {
+ flex-wrap: nowrap;
+ align-items: start;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta {
+ position: absolute;
+ bottom: -30px;
+ inset-inline-end: 0;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta .secondary {
+ background-color: var(--in-content-button-background) !important;
+ border: 1px solid var(--in-content-button-border-color);
+ line-height: 12px;
+ font-size: 0.72em;
+ font-weight: 600;
+ padding: 8px 16px;
+ text-decoration: none;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta .secondary:hover {
+ background-color: var(--in-content-button-background-hover) !important;
+ color: var(--in-content-button-text-color-hover);
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta .arrow-icon {
+ -moz-context-properties: fill;
+ fill: currentColor;
+ text-decoration: none;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta .arrow-icon::after {
+ content: "";
+ padding-inline-end: 12px;
+ margin-inline-start: 4px;
+ background: url("chrome://browser/skin/forward.svg") no-repeat center/12px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta .arrow-icon:dir(rtl)::after {
+ background-image: url("chrome://browser/skin/back.svg");
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .logo-container {
+ text-align: start;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .brand-logo {
+ height: 25px;
+ margin-block: 0;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text {
+ margin-inline: 0 10px;
+ margin-block: 10px 35px;
+ text-align: initial;
+ align-items: initial;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text:empty {
+ margin: 0;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text h1 {
+ font-size: 24px;
+ line-height: 1.2;
+ width: 300px;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text h2 {
+ margin: 10px 0 0;
+ min-height: 1em;
+ font-size: 15px;
+ line-height: 1.5;
+}
+@media (prefers-contrast: no-preference) {
+ .onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text h2 {
+ color: #5B5B66;
+ }
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text h1,
+.onboardingContainer .screen[pos=split] .section-main .main-content .primary {
+ margin: 0;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .steps {
+ z-index: 1;
+}
+.onboardingContainer .screen[pos=split] .section-main .main-content .steps.progress-bar {
+ width: 400px;
+ margin-inline: -35px;
+}
+@media (prefers-contrast) {
+ .onboardingContainer .screen[pos=split] .section-main .main-content {
+ border: 1px solid var(--in-content-page-color);
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .steps.progress-bar {
+ border-top: 1px solid var(--in-content-page-color);
+ background-color: var(--in-content-page-background);
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .steps.progress-bar .indicator {
+ background-color: var(--in-content-accent-color);
+ }
+}
+.onboardingContainer .screen[pos=split] .section-secondary {
+ --mr-secondary-position: center center / auto 350px;
+ border-radius: 8px 0 0 8px;
+ margin: auto 0 auto auto;
+ display: flex;
+ align-items: center;
+ -moz-context-properties: fill, stroke, fill-opacity, stroke-opacity;
+ stroke: currentColor;
+}
+.onboardingContainer .screen[pos=split] .section-secondary:dir(rtl) {
+ border-radius: 0 8px 8px 0;
+ margin: auto auto auto 0;
+}
+.onboardingContainer .screen[pos=split] .section-secondary h1 {
+ color: var(--mr-screen-heading-color);
+ font-weight: 700;
+ font-size: 47px;
+ line-height: 110%;
+ max-width: 340px;
+ text-align: initial;
+ white-space: pre-wrap;
+ text-shadow: none;
+ margin-inline: 40px 0;
+}
+.onboardingContainer .screen[pos=split] .section-secondary .image-alt {
+ width: inherit;
+ height: inherit;
+}
+.onboardingContainer .screen[pos=split] .section-secondary .hero-image {
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ max-height: 100%;
+}
+.onboardingContainer .screen[pos=split] .section-secondary .hero-image img {
+ width: 100%;
+ max-width: 180px;
+ margin: 25px 0;
+ padding-bottom: 30px;
+}
+@media only screen and (max-width: 800px) {
+ .onboardingContainer .screen[pos=split] .section-secondary .hero-image img {
+ padding-bottom: unset;
+ }
+}
+.onboardingContainer .screen[pos=split] .tiles-theme-container {
+ margin-block: -20px auto;
+ align-items: initial;
+}
+.onboardingContainer .screen[pos=split] .tiles-theme-container .colorway-text {
+ text-align: initial;
+ transition: var(--transition);
+ font-size: 13px;
+ line-height: 1.5;
+ min-height: 4.5em;
+ margin-block: 10px 20px;
+}
+.onboardingContainer .screen[pos=split] .tiles-theme-container .theme {
+ min-width: 38px;
+}
+@media (prefers-contrast: no-preference) and (prefers-color-scheme: dark) {
+ .onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text h2 {
+ color: #CFCFD8;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary {
+ background-color: #2B2A33;
+ }
+}
+@media only screen and (min-width: 800px) {
+ .onboardingContainer .screen[pos=split] .tiles-theme-section {
+ margin-inline-start: -10px;
+ }
+}
+@media only screen and (max-width: 800px) {
+ .onboardingContainer .screen[pos=split] {
+ flex-direction: column;
+ min-height: 550px;
+ }
+ .onboardingContainer .screen[pos=split]::before {
+ width: 400px;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary,
+.onboardingContainer .screen[pos=split] .section-main {
+ width: 400px;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary {
+ --mr-secondary-background-position-y: top;
+ --mr-secondary-position: center var(--mr-secondary-background-position-y) / 75%;
+ border-radius: 8px 8px 0 0;
+ margin: auto auto 0;
+ height: 100px;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary .hero-image img {
+ margin: 6px 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary .message-text {
+ margin-inline: auto;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary h1 {
+ font-size: 35px;
+ text-align: center;
+ white-space: normal;
+ margin-inline: auto;
+ margin-block: 14px 6px;
+ }
+ .onboardingContainer .screen[pos=split] .section-secondary:dir(rtl) {
+ margin: auto auto 0;
+ border-radius: 8px 8px 0 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-main {
+ margin: 0 auto auto;
+ height: 450px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content {
+ border-radius: 0 0 8px 8px;
+ padding: 30px 0 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .main-content-inner {
+ align-items: center;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .logo-container {
+ text-align: center;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .logo-container .brand-logo {
+ min-height: 25px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .logo-container .brand-logo, .onboardingContainer .screen[pos=split] .section-main .main-content .logo-container .brand-logo:dir(rtl) {
+ background-position: center;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text {
+ align-items: center;
+ text-align: center;
+ margin-inline: 0;
+ padding-inline: 30px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text .spacer-bottom,
+.onboardingContainer .screen[pos=split] .section-main .main-content .welcome-text .spacer-top {
+ display: none;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons {
+ text-align: center;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .checkbox-container {
+ display: none;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .action-buttons .secondary-cta {
+ position: relative;
+ margin-block: 10px 0;
+ bottom: 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .primary,
+.onboardingContainer .screen[pos=split] .section-main .main-content .secondary {
+ min-width: 240px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .colorway-text {
+ text-align: center;
+ margin-inline: 30px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .steps {
+ padding-block: 0;
+ margin: 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .main-content .steps.progress-bar {
+ margin-inline: 0;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .additional-cta.cta-link {
+ align-self: center;
+ }
+ .onboardingContainer .screen[pos=split] .section-main .dismiss-button {
+ top: -100px;
+ }
+ .onboardingContainer .screen[pos=split] .section-main:dir(rtl) {
+ margin: 0 auto auto;
+ }
+ .onboardingContainer .screen[pos=split] .section-main:dir(rtl) .main-content {
+ border-radius: 0 0 8px 8px;
+ }
+}
+@media only screen and (max-height: 650px) and (min-width: 800px) and (max-width: 990px) {
+ .onboardingContainer .screen[pos=split] .section-main .secondary-cta.top {
+ display: none;
+ }
+}
+@media only screen and (max-height: 650px) and (max-width: 590px) {
+ .onboardingContainer .screen[pos=split] .section-main .secondary-cta.top {
+ position: absolute;
+ padding: 0;
+ top: 0;
+ inset-inline-end: 0;
+ }
+}
+.onboardingContainer .brand-logo {
+ margin-block: 60px 10px;
+ transition: var(--transition);
+ height: 80px;
+}
+.onboardingContainer .brand-logo.cta-top {
+ margin-top: 25px;
+}
+.onboardingContainer .brand-logo.hide {
+ visibility: hidden;
+ padding: unset;
+ margin-top: 50px;
+}
+.onboardingContainer .rtamo-theme-icon {
+ max-height: 30px;
+ border-radius: 2px;
+ margin-bottom: 10px;
+ margin-top: 24px;
+}
+.onboardingContainer .rtamo-icon {
+ text-align: start;
+}
+@media only screen and (max-width: 800px) {
+ .onboardingContainer .rtamo-icon {
+ text-align: center;
+ }
+}
+.onboardingContainer .text-link {
+ text-decoration: underline;
+ cursor: pointer;
+ color: var(--in-content-link-color);
+}
+.onboardingContainer .text-link:hover {
+ text-decoration: none;
+ color: var(--in-content-link-color-hover);
+}
+.onboardingContainer .text-link:active {
+ text-decoration: none;
+ color: var(--in-content-link-color-active);
+}
+.onboardingContainer .welcome-text {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ margin: 0.5em 1em;
+ transition: var(--transition);
+}
+.onboardingContainer .welcome-text h1,
+.onboardingContainer .welcome-text h2 {
+ color: var(--in-content-page-color);
+ line-height: 1.5;
+}
+.onboardingContainer .welcome-text h1 {
+ font-size: 24px;
+ font-weight: 600;
+ margin: 0 6px;
+ letter-spacing: -0.02em;
+ outline: none;
+}
+.onboardingContainer .welcome-text h2 {
+ font-size: 16px;
+ font-weight: normal;
+ margin: 10px 6px 0;
+ max-width: 750px;
+ letter-spacing: -0.01em;
+}
+.onboardingContainer .welcome-text.fancy h1 {
+ background-image: linear-gradient(90deg, #9059FF, #FF4AA2, #FF8C00, #FF4AA2, #9059FF);
+ background-clip: text;
+ background-size: 200%;
+}
+@media (prefers-contrast: no-preference) {
+ .onboardingContainer .welcome-text.fancy h1 {
+ color: transparent;
+ }
+}
+@media (prefers-color-scheme: dark) {
+ .onboardingContainer .welcome-text.fancy h1 {
+ background-image: linear-gradient(90deg, #C688FF, #FF84C0, #FFBD4F, #FF84C0, #C688FF);
+ }
+ .onboardingContainer .welcome-text.fancy h1::selection {
+ color: #FFF;
+ background-color: #696977;
+ }
+}
+.onboardingContainer .welcome-text.shine h1 {
+ animation: shine 50s linear infinite;
+ background-size: 400%;
+}
+@keyframes shine {
+ to {
+ background-position: 400%;
+ }
+}
+.onboardingContainer .welcome-text .cta-paragraph a {
+ margin: 0;
+ text-decoration: underline;
+ cursor: pointer;
+}
+.onboardingContainer .screen.light-text .welcome-text.fancy h1 {
+ background-image: linear-gradient(90deg, #C688FF, #FF84C0, #FFBD4F, #FF84C0, #C688FF);
+}
+.onboardingContainer .screen.dark-text .welcome-text.fancy h1 {
+ background-image: linear-gradient(90deg, #9059FF, #FF4AA2, #FF8C00, #FF4AA2, #9059FF);
+}
+.onboardingContainer .welcomeZap span {
+ position: relative;
+ z-index: 1;
+ white-space: nowrap;
+}
+.onboardingContainer .welcomeZap .zap::after {
+ display: block;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ content: "";
+ position: absolute;
+ top: calc(100% - 0.15em);
+ width: 100%;
+ height: 0.3em;
+ left: 0;
+ z-index: -1;
+ transform: scaleY(3);
+}
+.onboardingContainer .welcomeZap .zap.short::after {
+ background-image: url("chrome://activity-stream/content/data/content/assets/short-zap.svg");
+}
+.onboardingContainer .welcomeZap .zap.long::after {
+ background-image: url("chrome://activity-stream/content/data/content/assets/long-zap.svg");
+}
+.onboardingContainer .language-loader {
+ filter: invert(1);
+ margin-inline-end: 10px;
+ position: relative;
+ top: 3px;
+ width: 16px;
+ height: 16px;
+ margin-top: -6px;
+}
+@media (prefers-color-scheme: dark) {
+ .onboardingContainer .language-loader {
+ filter: invert(0);
+ }
+}
+.onboardingContainer .tiles-theme-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 10px auto;
+}
+.onboardingContainer .sr-only {
+ opacity: 0;
+ overflow: hidden;
+ position: absolute;
+}
+.onboardingContainer .sr-only.input {
+ height: 1px;
+ width: 1px;
+}
+.onboardingContainer .tiles-theme-section {
+ border: 0;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 5px;
+ justify-content: space-evenly;
+ margin-inline: 10px;
+ padding: 10px;
+ transition: var(--transition);
+}
+.onboardingContainer .tiles-theme-section:hover, .onboardingContainer .tiles-theme-section:active, .onboardingContainer .tiles-theme-section:focus-within {
+ border-radius: 8px;
+ outline: 2px solid var(--in-content-primary-button-background);
+}
+.onboardingContainer .tiles-theme-section .theme {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 0;
+ min-width: 50px;
+ width: 180px;
+ color: #000;
+ box-shadow: none;
+ border-radius: 4px;
+ cursor: pointer;
+ z-index: 0;
+}
+.onboardingContainer .tiles-theme-section .theme.colorway {
+ width: auto;
+}
+.onboardingContainer .tiles-theme-section .theme:focus, .onboardingContainer .tiles-theme-section .theme:active {
+ outline: initial;
+ outline-offset: initial;
+}
+.onboardingContainer .tiles-theme-section .theme .icon.colorway,
+.onboardingContainer .tiles-theme-section .theme .label.colorway {
+ width: 20px;
+ height: 20px;
+}
+.onboardingContainer .tiles-theme-section .theme .icon {
+ background-size: cover;
+ width: 40px;
+ height: 40px;
+ border-radius: 40px;
+ outline: 1px solid var(--in-content-border-color);
+ outline-offset: -0.5px;
+ z-index: -1;
+}
+.onboardingContainer .tiles-theme-section .theme .icon:dir(rtl) {
+ transform: scaleX(-1);
+}
+.onboardingContainer .tiles-theme-section .theme .icon:focus, .onboardingContainer .tiles-theme-section .theme .icon:active, .onboardingContainer .tiles-theme-section .theme .icon.selected {
+ outline: 2px solid var(--in-content-primary-button-background);
+ outline-offset: 2px;
+}
+.onboardingContainer .tiles-theme-section .theme .icon.light {
+ background-image: url("resource://builtin-themes/light/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.dark {
+ background-image: url("resource://builtin-themes/dark/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.alpenglow {
+ background-image: url("resource://builtin-themes/alpenglow/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.default, .onboardingContainer .tiles-theme-section .theme .icon.automatic {
+ background-image: url("resource://default-theme/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.default.colorway, .onboardingContainer .tiles-theme-section .theme .icon.automatic.colorway {
+ background-image: url("chrome://activity-stream/content/data/content/assets/default.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.playmaker {
+ background-image: url("resource://builtin-themes/colorways/2022playmaker/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.expressionist {
+ background-image: url("resource://builtin-themes/colorways/2022expressionist/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.visionary {
+ background-image: url("resource://builtin-themes/colorways/2022visionary/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.dreamer {
+ background-image: url("resource://builtin-themes/colorways/2022dreamer/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.innovator {
+ background-image: url("resource://builtin-themes/colorways/2022innovator/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .icon.activist {
+ background-image: url("resource://builtin-themes/colorways/2022activist/balanced/icon.svg");
+}
+.onboardingContainer .tiles-theme-section .theme .text {
+ display: flex;
+ color: var(--in-content-page-color);
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 20px;
+ margin-inline-start: 0;
+ margin-top: 9px;
+}
+.onboardingContainer .tiles-theme-section legend {
+ cursor: default;
+}
+.onboardingContainer .tiles-container {
+ margin: 10px auto;
+}
+.onboardingContainer .tiles-container.info {
+ padding: 6px 12px 12px;
+}
+.onboardingContainer .tiles-container.info:hover, .onboardingContainer .tiles-container.info:focus {
+ background-color: rgba(217, 217, 227, 0.3);
+ border-radius: 4px;
+}
+.onboardingContainer .tiles-delayed {
+ animation: fadein 0.4s;
+}
+.onboardingContainer .multi-select-container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ margin-block: -1em 1em;
+ color: #5B5B66;
+ font-weight: 400;
+ font-size: 14px;
+ text-align: initial;
+ transition: var(--transition);
+ z-index: 1;
+}
+.onboardingContainer .multi-select-container .checkbox-container {
+ display: flex;
+ margin-bottom: 16px;
+}
+@media (prefers-color-scheme: dark) {
+ .onboardingContainer .multi-select-container {
+ color: #CFCFD8;
+ }
+}
+@media only screen and (max-width: 800px) {
+ .onboardingContainer .multi-select-container {
+ padding: 0 30px;
+ }
+}
+.onboardingContainer .mobile-downloads .qr-code-image {
+ margin: 24px 0 10px;
+ width: 113px;
+ height: 113px;
+}
+.onboardingContainer .mobile-downloads .email-link {
+ font-size: 16px;
+ font-weight: 400;
+ background: none;
+ text-decoration: underline;
+ cursor: pointer;
+ color: var(--in-content-link-color);
+}
+.onboardingContainer .mobile-downloads .email-link:hover {
+ text-decoration: none;
+ color: var(--in-content-link-color-hover);
+}
+.onboardingContainer .mobile-downloads .email-link:active {
+ text-decoration: none;
+ color: var(--in-content-link-color-active);
+}
+.onboardingContainer .mobile-downloads .email-link:hover {
+ background: none;
+}
+.onboardingContainer .mobile-downloads .ios button {
+ background-image: url("chrome://app-marketplace-icons/locale/ios.svg");
+}
+.onboardingContainer .mobile-downloads .android button {
+ background-image: url("chrome://app-marketplace-icons/locale/android.png");
+}
+.onboardingContainer .mobile-download-buttons {
+ list-style: none;
+ padding: 10px 0;
+ margin: 0;
+}
+.onboardingContainer .mobile-download-buttons li {
+ display: inline-block;
+}
+.onboardingContainer .mobile-download-buttons li button {
+ display: inline-block;
+ height: 45px;
+ width: 152px;
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-position: center;
+ box-shadow: none;
+ border: 0;
+}
+.onboardingContainer .mobile-download-buttons li:not(:first-child) {
+ margin-inline: 5px 0;
+}
+.onboardingContainer .dismiss-button {
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ left: auto;
+ right: 0;
+ box-sizing: border-box;
+ padding: 0;
+ margin: 16px;
+ display: block;
+ float: inline-end;
+ background: url("chrome://global/skin/icons/close.svg") no-repeat center/16px;
+ height: 32px;
+ width: 32px;
+ align-self: end;
+ min-height: 32px;
+ min-width: 32px;
+ -moz-context-properties: fill;
+ fill: currentColor;
+ transition: var(--transition);
+}
+.onboardingContainer .dismiss-button:dir(rtl) {
+ left: 0;
+ right: auto;
+}
+@keyframes fadein {
+ from {
+ opacity: 0;
+ }
+}
+.onboardingContainer .secondary-cta {
+ display: flex;
+ align-items: end;
+ flex-direction: row;
+ justify-content: center;
+ font-size: 14px;
+ transition: var(--transition);
+}
+.onboardingContainer .secondary-cta.top {
+ justify-content: end;
+ padding-inline-end: min(150px, 500px - 70vh);
+ padding-top: 4px;
+ position: absolute;
+ top: 10px;
+ inset-inline-end: 20px;
+ z-index: 2;
+}
+.onboardingContainer .secondary-cta span {
+ color: var(--grey-subtitle-1);
+ margin: 0 4px;
+}
+.onboardingContainer .message-text,
+.onboardingContainer .attrib-text {
+ transition: var(--transition);
+}
+.onboardingContainer .helptext {
+ padding: 1em;
+ text-align: center;
+ color: var(--grey-subtitle-1);
+ font-size: 12px;
+ line-height: 18px;
+}
+.onboardingContainer .helptext.default {
+ align-self: center;
+ max-width: 40%;
+}
+.onboardingContainer .helptext span {
+ padding-inline-end: 4px;
+}
+.onboardingContainer .helptext-img {
+ height: 1.5em;
+ width: 1.5em;
+ margin-inline-end: 4px;
+ vertical-align: middle;
+}
+.onboardingContainer .helptext-img.end {
+ margin: 4px;
+}
+.onboardingContainer .helptext-img.footer {
+ vertical-align: bottom;
+}
+.onboardingContainer .steps {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ margin-top: 0;
+ padding-block: 16px 0;
+ transition: var(--transition);
+ z-index: -1;
+ height: 48px;
+ box-sizing: border-box;
+}
+.onboardingContainer .steps.has-helptext {
+ padding-bottom: 0;
+}
+.onboardingContainer .steps .indicator {
+ width: 0;
+ height: 0;
+ margin-inline-end: 4px;
+ margin-inline-start: 4px;
+ background: var(--grey-subtitle-1);
+ border-radius: 5px;
+ border: 3px solid var(--in-content-button-text-color);
+ opacity: 0.35;
+ box-sizing: inherit;
+}
+.onboardingContainer .steps .indicator.current {
+ opacity: 1;
+ border-color: var(--checkbox-checked-bgcolor);
+}
+.onboardingContainer .steps .indicator.current:last-of-type:first-of-type {
+ opacity: 0;
+}
+.onboardingContainer .steps.progress-bar {
+ height: 6px;
+ padding-block: 0;
+ margin-block: 42px 0;
+ background-color: color-mix(in srgb, var(--in-content-button-text-color) 25%, transparent);
+ justify-content: start;
+ opacity: 1;
+ transition: none;
+}
+.onboardingContainer .steps.progress-bar .indicator {
+ width: 100%;
+ height: 100%;
+ margin-inline: -1px;
+ background-color: var(--checkbox-checked-bgcolor);
+ border: 0;
+ border-radius: 0;
+ opacity: 1;
+ transition: var(--progress-bar-transition);
+ translate: calc(var(--progress-bar-progress, 0%) - 100%);
+}
+.onboardingContainer .steps.progress-bar .indicator:dir(rtl) {
+ translate: calc(var(--progress-bar-progress, 0%) * -1 + 100%);
+}
+.onboardingContainer .additional-cta-container[flow] {
+ display: flex;
+ flex-flow: column wrap;
+ align-items: center;
+}
+.onboardingContainer .additional-cta-container[flow][flow=row] {
+ flex-direction: row;
+ justify-content: center;
+}
+.onboardingContainer .additional-cta-container[flow][flow=row] .secondary-cta {
+ flex-basis: 100%;
+}
+.onboardingContainer .primary,
+.onboardingContainer .secondary,
+.onboardingContainer .additional-cta {
+ font-size: 13px;
+ line-height: 16px;
+ padding: 11px 15px;
+ transition: var(--transition);
+}
+.onboardingContainer .primary.rtamo,
+.onboardingContainer .secondary.rtamo,
+.onboardingContainer .additional-cta.rtamo {
+ margin-top: 24px;
+}
+.onboardingContainer .secondary {
+ background-color: var(--in-content-button-background);
+ color: var(--in-content-button-text-color);
+}
+.onboardingContainer .noodle {
+ display: block;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ position: absolute;
+ transition: var(--transition);
+}
+.onboardingContainer .noodle:dir(rtl) {
+ scale: -1 1;
+}
+.onboardingContainer .outline-L {
+ background-image: url("chrome://activity-stream/content/data/content/assets/noodle-outline-L.svg");
+}
+.onboardingContainer .solid-L {
+ background-image: url("chrome://activity-stream/content/data/content/assets/noodle-solid-L.svg");
+ -moz-context-properties: fill;
+ fill: var(--in-content-page-background);
+ display: none;
+}
+.onboardingContainer .purple-C {
+ background-image: url("chrome://activity-stream/content/data/content/assets/noodle-C.svg");
+ -moz-context-properties: fill;
+ fill: #E7258C;
+}
+.onboardingContainer .orange-L {
+ background-image: url("chrome://activity-stream/content/data/content/assets/noodle-solid-L.svg");
+ -moz-context-properties: fill;
+ fill: #FFA437;
+}
+.onboardingContainer .screen-1 .section-main {
+ z-index: 1;
+ margin: auto;
+}
+.onboardingContainer .screen-1 .outline-L {
+ width: 87px;
+ height: 80px;
+ transform: rotate(10deg) translate(-30%, 200%);
+ transition-delay: 0.4s;
+ z-index: 2;
+}
+.onboardingContainer .screen-1 .orange-L {
+ width: 550px;
+ height: 660px;
+ transform: rotate(-155deg) translate(11%, -18%);
+ transition-delay: 0.2s;
+}
+.onboardingContainer .screen-1 .purple-C {
+ width: 310px;
+ height: 260px;
+ transform: translate(-18%, -67%);
+}
+.onboardingContainer .screen-1 .yellow-circle {
+ width: 165px;
+ height: 165px;
+ border-radius: 50%;
+ transform: translate(230%, -5%);
+ background: #952BB9;
+ transition-delay: -0.2s;
+}
+.onboardingContainer .dialog-initial .brand-logo {
+ transition-delay: 0.6s;
+}
+.onboardingContainer .dialog-initial .welcome-text {
+ transition-delay: 0.8s;
+}
+.onboardingContainer .dialog-initial .tiles-theme-section,
+.onboardingContainer .dialog-initial .multi-select-container,
+.onboardingContainer .dialog-initial migration-wizard {
+ transition-delay: 0.9s;
+}
+.onboardingContainer .dialog-initial .primary,
+.onboardingContainer .dialog-initial .secondary,
+.onboardingContainer .dialog-initial .secondary-cta,
+.onboardingContainer .dialog-initial .steps,
+.onboardingContainer .dialog-initial .cta-link {
+ transition-delay: 1s;
+}
+.onboardingContainer .screen:not(.dialog-initial) .tiles-theme-section,
+.onboardingContainer .screen:not(.dialog-initial) .multi-select-container,
+.onboardingContainer .screen:not(.dialog-initial) .colorway-text {
+ transition-delay: 0.2s;
+}
+.onboardingContainer .screen:not(.dialog-initial) .primary,
+.onboardingContainer .screen:not(.dialog-initial) .secondary,
+.onboardingContainer .screen:not(.dialog-initial) .secondary-cta,
+.onboardingContainer .screen:not(.dialog-initial) .cta-link {
+ transition-delay: 0.4s;
+}
+.onboardingContainer .screen-2 .section-main {
+ z-index: 1;
+ margin: auto;
+}
+.onboardingContainer .screen-2 .outline-L {
+ width: 87px;
+ height: 80px;
+ transform: rotate(250deg) translate(-420%, 425%);
+ transition-delay: 0.2s;
+ z-index: 2;
+}
+.onboardingContainer .screen-2 .orange-L {
+ height: 800px;
+ width: 660px;
+ transform: rotate(35deg) translate(-10%, -7%);
+ transition-delay: -0.4s;
+}
+.onboardingContainer .screen-2 .purple-C {
+ width: 392px;
+ height: 394px;
+ transform: rotate(260deg) translate(-34%, -35%);
+ transition-delay: -0.2s;
+ fill: #952BB9;
+}
+.onboardingContainer .screen-2 .yellow-circle {
+ width: 165px;
+ height: 165px;
+ border-radius: 50%;
+ transform: translate(160%, 130%);
+ background: #E7258C;
+}
+.onboardingContainer.transition-in .noodle {
+ opacity: 0;
+ rotate: var(--rotate);
+ scale: var(--scale);
+}
+.onboardingContainer.transition-in .dialog-initial .main-content,
+.onboardingContainer.transition-in .dialog-initial .dismiss-button {
+ translate: 0 calc(-2 * var(--translate));
+}
+.onboardingContainer.transition-in .dialog-initial .brand-logo,
+.onboardingContainer.transition-in .dialog-initial .steps {
+ opacity: 0;
+ translate: 0 calc(-1 * var(--translate));
+}
+.onboardingContainer.transition-in .screen .welcome-text,
+.onboardingContainer.transition-in .screen .multi-select-container,
+.onboardingContainer.transition-in .screen .tiles-theme-section,
+.onboardingContainer.transition-in .screen .colorway-text,
+.onboardingContainer.transition-in .screen .primary,
+.onboardingContainer.transition-in .screen .checkbox-container:not(.multi-select-item),
+.onboardingContainer.transition-in .screen .secondary,
+.onboardingContainer.transition-in .screen .secondary-cta:not(.top),
+.onboardingContainer.transition-in .screen .cta-link,
+.onboardingContainer.transition-in .screen migration-wizard {
+ opacity: 0;
+ translate: 0 calc(-1 * var(--translate));
+}
+.onboardingContainer.transition-in .screen:not(.dialog-initial) .steps:not(.progress-bar) {
+ opacity: 0.2;
+}
+.onboardingContainer.transition-out .noodle {
+ opacity: 0;
+ rotate: var(--rotate);
+ scale: var(--scale);
+ transition-delay: 0.2s;
+}
+.onboardingContainer.transition-out .screen:not(.dialog-last) .main-content {
+ overflow: hidden;
+}
+.onboardingContainer.transition-out .screen:not(.dialog-last) .welcome-text,
+.onboardingContainer.transition-out .screen:not(.dialog-last) .multi-select-container {
+ opacity: 0;
+ translate: 0 var(--translate);
+ transition-delay: 0.1s;
+}
+.onboardingContainer.transition-out .screen:not(.dialog-last) .tiles-theme-section,
+.onboardingContainer.transition-out .screen:not(.dialog-last) .colorway-text,
+.onboardingContainer.transition-out .screen:not(.dialog-last) migration-wizard {
+ opacity: 0;
+ translate: 0 var(--translate);
+ transition-delay: 0.2s;
+}
+.onboardingContainer.transition-out .screen:not(.dialog-last) .primary,
+.onboardingContainer.transition-out .screen:not(.dialog-last) .checkbox-container:not(.multi-select-item),
+.onboardingContainer.transition-out .screen:not(.dialog-last) .secondary,
+.onboardingContainer.transition-out .screen:not(.dialog-last) .secondary-cta:not(.top),
+.onboardingContainer.transition-out .screen:not(.dialog-last) .cta-link {
+ opacity: 0;
+ translate: 0 var(--translate);
+ transition-delay: 0.3s;
+}
+.onboardingContainer.transition-out .screen:not(.dialog-last) .steps:not(.progress-bar) {
+ opacity: 0.2;
+ transition-delay: 0.5s;
+}
+.onboardingContainer.transition-out .dialog-last .noodle {
+ transition-delay: 0s;
+}
+.onboardingContainer.transition-out .dialog-last .main-content,
+.onboardingContainer.transition-out .dialog-last .dismiss-button {
+ opacity: 0;
+ translate: 0 calc(2 * var(--translate));
+ transition-delay: 0.4s;
+}
+.onboardingContainer migration-wizard {
+ width: unset;
+ transition: var(--transition);
+}
+.onboardingContainer migration-wizard::part(buttons) {
+ margin-top: 32px;
+ justify-content: flex-start;
+}
+.onboardingContainer migration-wizard::part(deck) {
+ font-size: 0.83em;
+}
diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.html b/browser/components/newtab/aboutwelcome/content/aboutwelcome.html
new file mode 100644
index 0000000000..a14b563057
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.html
@@ -0,0 +1,49 @@
+<!-- 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/. -->
+
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="color-scheme" content="light dark" />
+ <meta
+ http-equiv="Content-Security-Policy"
+ content="default-src 'none'; object-src 'none'; script-src resource: chrome:; media-src resource: chrome: https://assets.mozilla.net https://www.mozilla.org; connect-src https:; img-src https: data: blob: chrome:; style-src resource: chrome:;"
+ />
+ <title data-l10n-id="onboarding-welcome-header"></title>
+ <link
+ rel="icon"
+ type="image/png"
+ href="chrome://branding/content/icon32.png"
+ />
+ <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
+ <link
+ rel="stylesheet"
+ href="chrome://activity-stream/content/aboutwelcome/aboutwelcome.css"
+ />
+ <link rel="localization" href="branding/brand.ftl" />
+ <link rel="localization" href="browser/newtab/onboarding.ftl" />
+ <link rel="localization" href="browser/spotlight.ftl" />
+ <link rel="localization" href="browser/migrationWizard.ftl" />
+ <link rel="localization" href="toolkit/branding/accounts.ftl" />
+ <link rel="localization" href="toolkit/branding/brandings.ftl" />
+ </head>
+ <body>
+ <div
+ id="multi-stage-message-root"
+ class="welcome-container"
+ role="presentation"
+ ></div>
+ <script src="resource://activity-stream/vendor/react.js"></script>
+ <script src="resource://activity-stream/vendor/react-dom.js"></script>
+ <script src="chrome://browser/content/contentTheme.js"></script>
+ <script src="resource://activity-stream/aboutwelcome/aboutwelcome.bundle.js"></script>
+ <script src="chrome://global/content/elements/named-deck.js" async></script>
+ <script src="chrome://global/content/elements/panel-list.js" async></script>
+ <script
+ src="chrome://browser/content/migration/migration-wizard.mjs"
+ type="module"
+ ></script>
+ </body>
+</html>
diff --git a/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm
new file mode 100644
index 0000000000..0e17a0b3ae
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm
@@ -0,0 +1,707 @@
+/* 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/. */
+"use strict";
+
+const EXPORTED_SYMBOLS = ["AboutWelcomeDefaults"];
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ AddonRepository: "resource://gre/modules/addons/AddonRepository.sys.mjs",
+ AttributionCode: "resource:///modules/AttributionCode.sys.mjs",
+ BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ AWScreenUtils: "resource://activity-stream/lib/AWScreenUtils.jsm",
+});
+
+// Message to be updated based on finalized MR designs
+const MR_ABOUT_WELCOME_DEFAULT = {
+ id: "MR_WELCOME_DEFAULT",
+ template: "multistage",
+ // Allow tests to easily disable transitions.
+ transitions: Services.prefs.getBoolPref(
+ "browser.aboutwelcome.transitions",
+ true
+ ),
+ backdrop:
+ "var(--mr-welcome-background-color) var(--mr-welcome-background-gradient)",
+ screens: [
+ {
+ id: "AW_WELCOME_BACK",
+ targeting: "isDeviceMigration",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-100px",
+ image_alt_text: {
+ string_id: "onboarding-device-migration-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/device-migration.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "onboarding-device-migration-title",
+ },
+ subtitle: {
+ string_id: "onboarding-device-migration-subtitle",
+ },
+ primary_button: {
+ label: {
+ string_id: "onboarding-device-migration-primary-button-label",
+ },
+ action: {
+ type: "FXA_SIGNIN_FLOW",
+ navigate: "actionResult",
+ data: {
+ entrypoint: "fx-device-migration-onboarding",
+ extraParams: {
+ utm_content: "migration-onboarding",
+ utm_source: "fx-new-device-sync",
+ utm_medium: "firefox-desktop",
+ utm_campaign: "migration",
+ },
+ },
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ },
+ },
+ {
+ id: "AW_EASY_SETUP",
+ targeting:
+ "os.windowsBuildNumber >= 15063 && !isDefaultBrowser && !doesAppNeedPin",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-60px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-default-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-settodefault.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-set-default-title",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-set-default-subtitle",
+ },
+ tiles: {
+ type: "multiselect",
+ data: [
+ {
+ id: "checkbox-1",
+ defaultValue: true,
+ label: {
+ string_id:
+ "mr2022-onboarding-easy-setup-set-default-checkbox-label",
+ },
+ action: {
+ type: "SET_DEFAULT_BROWSER",
+ },
+ },
+ {
+ id: "checkbox-2",
+ defaultValue: true,
+ label: {
+ string_id: "mr2022-onboarding-easy-setup-import-checkbox-label",
+ },
+ action: {
+ type: "SHOW_MIGRATION_WIZARD",
+ data: {},
+ },
+ },
+ ],
+ },
+ primary_button: {
+ label: {
+ string_id: "mr2022-onboarding-easy-setup-primary-button-label",
+ },
+ action: {
+ type: "MULTI_ACTION",
+ collectSelect: true,
+ navigate: true,
+ data: {
+ actions: [],
+ },
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ secondary_button_top: {
+ label: {
+ string_id: "mr1-onboarding-sign-in-button-label",
+ },
+ action: {
+ data: {
+ entrypoint: "activity-stream-firstrun",
+ where: "tab",
+ },
+ type: "SHOW_FIREFOX_ACCOUNTS",
+ addFlowParams: true,
+ },
+ },
+ },
+ },
+ {
+ id: "AW_PIN_FIREFOX",
+ targeting:
+ "!(os.windowsBuildNumber >= 15063 && !isDefaultBrowser && !doesAppNeedPin)",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-155px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-pin-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-pintaskbar.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-welcome-pin-header",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-welcome-pin-subtitle",
+ },
+ primary_button: {
+ label: {
+ string_id: "mr2022-onboarding-pin-primary-button-label",
+ },
+ action: {
+ navigate: true,
+ type: "PIN_FIREFOX_TO_TASKBAR",
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ secondary_button_top: {
+ label: {
+ string_id: "mr1-onboarding-sign-in-button-label",
+ },
+ action: {
+ data: {
+ entrypoint: "activity-stream-firstrun",
+ where: "tab",
+ },
+ type: "SHOW_FIREFOX_ACCOUNTS",
+ addFlowParams: true,
+ },
+ },
+ },
+ },
+ {
+ id: "AW_LANGUAGE_MISMATCH",
+ content: {
+ position: "split",
+ background: "var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-live-language-text",
+ },
+ subtitle: {
+ string_id: "mr2022-language-mismatch-subtitle",
+ },
+ hero_text: {
+ string_id: "mr2022-onboarding-live-language-text",
+ useLangPack: true,
+ },
+ languageSwitcher: {
+ downloading: {
+ string_id: "onboarding-live-language-button-label-downloading",
+ },
+ cancel: {
+ string_id: "onboarding-live-language-secondary-cancel-download",
+ },
+ waiting: { string_id: "onboarding-live-language-waiting-button" },
+ skip: { string_id: "mr2022-onboarding-secondary-skip-button-label" },
+ action: {
+ navigate: true,
+ },
+ switch: {
+ string_id: "mr2022-onboarding-live-language-switch-to",
+ useLangPack: true,
+ },
+ continue: {
+ string_id: "mr2022-onboarding-live-language-continue-in",
+ },
+ },
+ },
+ },
+ {
+ id: "AW_SET_DEFAULT",
+ targeting:
+ "!(os.windowsBuildNumber >= 15063 && !isDefaultBrowser && !doesAppNeedPin)",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-60px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-default-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-settodefault.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-set-default-title",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-set-default-subtitle",
+ },
+ primary_button: {
+ label: {
+ string_id: "mr2022-onboarding-set-default-primary-button-label",
+ },
+ action: {
+ navigate: true,
+ type: "SET_DEFAULT_BROWSER",
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ },
+ },
+ {
+ id: "AW_IMPORT_SETTINGS",
+ targeting:
+ "!(os.windowsBuildNumber >= 15063 && !isDefaultBrowser && !doesAppNeedPin) && !useEmbeddedMigrationWizard",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-42px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-import-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-import.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-import-header",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-import-subtitle",
+ },
+ primary_button: {
+ label: {
+ string_id:
+ "mr2022-onboarding-import-primary-button-label-no-attribution",
+ },
+ action: {
+ type: "SHOW_MIGRATION_WIZARD",
+ data: {},
+ navigate: true,
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ },
+ },
+ {
+ id: "AW_IMPORT_SETTINGS_EMBEDDED",
+ targeting:
+ "!(os.windowsBuildNumber >= 15063 && !isDefaultBrowser && !doesAppNeedPin) && useEmbeddedMigrationWizard",
+ content: {
+ tiles: { type: "migration-wizard" },
+ position: "split",
+ split_narrow_bkg_position: "-42px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-import-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-import.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ migrate_start: {
+ action: {},
+ },
+ migrate_close: {
+ action: {
+ navigate: true,
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ },
+ },
+ {
+ id: "AW_MOBILE_DOWNLOAD",
+ // The mobile download screen should only be shown to users who
+ // are either not logged into FxA, or don't have any mobile devices syncing
+ targeting: "!isFxASignedIn || sync.mobileDevices == 0",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-160px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-mobile-download-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-mobilecrosspromo.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-mobile-download-title",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-mobile-download-subtitle",
+ },
+ hero_image: {
+ url: "chrome://activity-stream/content/data/content/assets/mobile-download-qr-new-user.svg",
+ },
+ cta_paragraph: {
+ text: {
+ string_id: "mr2022-onboarding-mobile-download-cta-text",
+ string_name: "download-label",
+ },
+ action: {
+ type: "OPEN_URL",
+ data: {
+ args: "https://www.mozilla.org/firefox/mobile/get-app/?utm_medium=firefox-desktop&utm_source=onboarding-modal&utm_campaign=mr2022&utm_content=new-global",
+ where: "tab",
+ },
+ },
+ },
+ secondary_button: {
+ label: {
+ string_id: "mr2022-onboarding-secondary-skip-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ has_arrow_icon: true,
+ },
+ },
+ },
+ {
+ id: "AW_GRATITUDE",
+ content: {
+ position: "split",
+ split_narrow_bkg_position: "-228px",
+ image_alt_text: {
+ string_id: "mr2022-onboarding-gratitude-image-alt",
+ },
+ background:
+ "url('chrome://activity-stream/content/data/content/assets/mr-gratitude.svg') var(--mr-secondary-position) no-repeat var(--mr-screen-background-color)",
+ progress_bar: true,
+ logo: {},
+ title: {
+ string_id: "mr2022-onboarding-gratitude-title",
+ },
+ subtitle: {
+ string_id: "mr2022-onboarding-gratitude-subtitle",
+ },
+ primary_button: {
+ label: {
+ string_id: "mr2-onboarding-start-browsing-button-label",
+ },
+ action: {
+ navigate: true,
+ },
+ },
+ },
+ },
+ ],
+};
+
+async function getAddonFromRepository(data) {
+ const [addonInfo] = await lazy.AddonRepository.getAddonsByIDs([data]);
+ if (addonInfo.sourceURI.scheme !== "https") {
+ return null;
+ }
+
+ return {
+ name: addonInfo.name,
+ url: addonInfo.sourceURI.spec,
+ iconURL: addonInfo.icons["64"] || addonInfo.icons["32"],
+ type: addonInfo.type,
+ screenshots: addonInfo.screenshots,
+ };
+}
+
+async function getAddonInfo(attrbObj) {
+ let { content, source } = attrbObj;
+ try {
+ if (!content || source !== "addons.mozilla.org") {
+ return null;
+ }
+ // Attribution data can be double encoded
+ while (content.includes("%")) {
+ try {
+ const result = decodeURIComponent(content);
+ if (result === content) {
+ break;
+ }
+ content = result;
+ } catch (e) {
+ break;
+ }
+ }
+ // return_to_amo embeds the addon id in the content
+ // param, prefixed with "rta:". Translating that
+ // happens in AddonRepository, however we can avoid
+ // an API call if we check up front here.
+ if (content.startsWith("rta:")) {
+ return await getAddonFromRepository(content);
+ }
+ } catch (e) {
+ console.error("Failed to get the latest add-on version for Return to AMO");
+ }
+ return null;
+}
+
+async function getAttributionContent() {
+ let attribution = await lazy.AttributionCode.getAttrDataAsync();
+ if (attribution?.source === "addons.mozilla.org") {
+ let addonInfo = await getAddonInfo(attribution);
+ if (addonInfo) {
+ return {
+ ...addonInfo,
+ template: "return_to_amo",
+ };
+ }
+ }
+ if (attribution?.ua) {
+ return {
+ ua: decodeURIComponent(attribution.ua),
+ };
+ }
+ return null;
+}
+
+// Return default multistage welcome content
+function getDefaults() {
+ return Cu.cloneInto(MR_ABOUT_WELCOME_DEFAULT, {});
+}
+
+let gSourceL10n = null;
+
+// Localize Firefox download source from user agent attribution to show inside
+// import primary button label such as 'Import from <localized browser name>'.
+// no firefox as import wizard doesn't show it
+const allowedUAs = ["chrome", "edge", "ie"];
+function getLocalizedUA(ua) {
+ if (!gSourceL10n) {
+ gSourceL10n = new Localization(["browser/migration.ftl"]);
+ }
+ if (allowedUAs.includes(ua)) {
+ return gSourceL10n.formatValue(`source-name-${ua.toLowerCase()}`);
+ }
+ return null;
+}
+
+// Function to evalute the appropriate string for the welcome screen button label
+function evaluateWelcomeScreenButtonLabel(removeDefault) {
+ return removeDefault
+ ? "mr2022-onboarding-get-started-primary-button-label"
+ : "mr2022-onboarding-set-default-primary-button-label";
+}
+
+function prepareMobileDownload(content) {
+ let mobileContent = content?.screens?.find(
+ screen => screen.id === "AW_MOBILE_DOWNLOAD"
+ )?.content;
+
+ if (!mobileContent) {
+ return content;
+ }
+ if (!lazy.BrowserUtils.sendToDeviceEmailsSupported()) {
+ // If send to device emails are not supported for a user's locale,
+ // remove the send to device link and update the screen text
+ delete mobileContent.cta_paragraph.action;
+ mobileContent.cta_paragraph.text = {
+ string_id: "mr2022-onboarding-no-mobile-download-cta-text",
+ };
+ }
+ // Update CN specific QRCode url
+ if (AppConstants.isChinaRepack()) {
+ mobileContent.hero_image.url = `${mobileContent.hero_image.url.slice(
+ 0,
+ mobileContent.hero_image.url.indexOf(".svg")
+ )}-cn.svg`;
+ }
+
+ return content;
+}
+
+async function prepareContentForReact(content) {
+ const { screens } = content;
+
+ if (content?.template === "return_to_amo") {
+ return content;
+ }
+
+ // Change content for Windows 7 because non-light themes aren't quite right.
+ if (AppConstants.isPlatformAndVersionAtMost("win", "6.1")) {
+ await lazy.AWScreenUtils.removeScreens(screens, screen =>
+ ["theme"].includes(screen.content?.tiles?.type)
+ );
+ }
+
+ // Set the primary import button source based on attribution.
+ if (content?.ua) {
+ // If available, add the browser source to action data
+ // and localized browser string args to primary button label
+ const { label, action } =
+ content?.screens?.find(
+ screen =>
+ screen?.content?.primary_button?.action?.type ===
+ "SHOW_MIGRATION_WIZARD"
+ )?.content?.primary_button ?? {};
+
+ if (action) {
+ action.data = { ...action.data, source: content.ua };
+ }
+
+ let browserStr = await getLocalizedUA(content.ua);
+
+ if (label?.string_id) {
+ label.string_id = browserStr
+ ? "mr1-onboarding-import-primary-button-label-attribution"
+ : "mr2022-onboarding-import-primary-button-label-no-attribution";
+
+ label.args = browserStr ? { previous: browserStr } : {};
+ }
+ }
+
+ // If already pinned, convert "pin" screen to "welcome" with desired action.
+ let removeDefault = !content.needDefault;
+ if (!content.needPin) {
+ const pinScreen = content.screens?.find(screen =>
+ screen.id?.startsWith("AW_PIN_FIREFOX")
+ );
+ if (pinScreen?.content) {
+ pinScreen.id = removeDefault ? "AW_GET_STARTED" : "AW_ONLY_DEFAULT";
+ pinScreen.content.title = {
+ string_id: "mr2022-onboarding-welcome-pin-header",
+ };
+
+ pinScreen.content.subtitle = {
+ string_id: removeDefault
+ ? "mr2022-onboarding-get-started-primary-subtitle"
+ : "mr2022-onboarding-set-default-only-subtitle",
+ };
+
+ pinScreen.content.primary_button = {
+ label: {
+ string_id: evaluateWelcomeScreenButtonLabel(removeDefault, content),
+ },
+ action: {
+ navigate: true,
+ },
+ };
+ // Get started content will navigate without action, so remove "Not now."
+ if (!removeDefault) {
+ // The "pin" screen will now handle "default" so remove other "default."
+ pinScreen.content.primary_button.action.type = "SET_DEFAULT_BROWSER";
+ removeDefault = true;
+ }
+ }
+ }
+ if (removeDefault) {
+ await lazy.AWScreenUtils.removeScreens(screens, screen =>
+ screen.id?.startsWith("AW_SET_DEFAULT")
+ );
+ }
+
+ // Remove Firefox Accounts related UI and prevent related metrics.
+ if (!Services.prefs.getBoolPref("identity.fxaccounts.enabled", false)) {
+ delete content.screens?.find(
+ screen =>
+ screen.content?.secondary_button_top?.action?.type ===
+ "SHOW_FIREFOX_ACCOUNTS"
+ )?.content.secondary_button_top;
+ content.skipFxA = true;
+ }
+
+ // Remove the English-only image caption.
+ if (Services.locale.appLocaleAsBCP47.split("-")[0] !== "en") {
+ delete content.screens?.find(
+ screen => screen.content?.help_text?.deleteIfNotEn
+ )?.content.help_text;
+ }
+
+ let shouldRemoveLanguageMismatchScreen = true;
+ if (content.languageMismatchEnabled) {
+ const screen = content?.screens?.find(s => s.id === "AW_LANGUAGE_MISMATCH");
+ if (screen && content.appAndSystemLocaleInfo.canLiveReload) {
+ // Add the display names for the OS and Firefox languages, like "American English".
+ function addMessageArgs(obj) {
+ for (const value of Object.values(obj)) {
+ if (value?.string_id) {
+ value.args = content.appAndSystemLocaleInfo.displayNames;
+ }
+ }
+ }
+
+ addMessageArgs(screen.content.languageSwitcher);
+ addMessageArgs(screen.content);
+ shouldRemoveLanguageMismatchScreen = false;
+ }
+ }
+
+ if (shouldRemoveLanguageMismatchScreen) {
+ await lazy.AWScreenUtils.removeScreens(
+ screens,
+ screen => screen.id === "AW_LANGUAGE_MISMATCH"
+ );
+ }
+
+ return prepareMobileDownload(content);
+}
+
+const AboutWelcomeDefaults = {
+ prepareContentForReact,
+ getDefaults,
+ getAttributionContent,
+};
diff --git a/browser/components/newtab/aboutwelcome/lib/AboutWelcomeTelemetry.jsm b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeTelemetry.jsm
new file mode 100644
index 0000000000..b8bdd44794
--- /dev/null
+++ b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeTelemetry.jsm
@@ -0,0 +1,242 @@
+/* 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/. */
+"use strict";
+
+const EXPORTED_SYMBOLS = ["AboutWelcomeTelemetry"];
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ AttributionCode: "resource:///modules/AttributionCode.sys.mjs",
+ ClientID: "resource://gre/modules/ClientID.sys.mjs",
+ TelemetrySession: "resource://gre/modules/TelemetrySession.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ PingCentre: "resource:///modules/PingCentre.jsm",
+});
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "structuredIngestionEndpointBase",
+ "browser.newtabpage.activity-stream.telemetry.structuredIngestion.endpoint",
+ ""
+);
+XPCOMUtils.defineLazyGetter(lazy, "telemetryClientId", () =>
+ lazy.ClientID.getClientID()
+);
+XPCOMUtils.defineLazyGetter(
+ lazy,
+ "browserSessionId",
+ () => lazy.TelemetrySession.getMetadata("").sessionId
+);
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ const { Logger } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/Logger.sys.mjs"
+ );
+ return new Logger("AboutWelcomeTelemetry");
+});
+
+const TELEMETRY_TOPIC = "about:welcome";
+const PING_TYPE = "onboarding";
+const PING_VERSION = "1";
+const STRUCTURED_INGESTION_NAMESPACE_MS = "messaging-system";
+
+class AboutWelcomeTelemetry {
+ constructor() {
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "telemetryEnabled",
+ "browser.newtabpage.activity-stream.telemetry",
+ false
+ );
+ }
+
+ /**
+ * Lazily initialize PingCentre for Activity Stream to send pings
+ */
+ get pingCentre() {
+ Object.defineProperty(this, "pingCentre", {
+ value: new lazy.PingCentre({ topic: TELEMETRY_TOPIC }),
+ });
+ return this.pingCentre;
+ }
+
+ _generateStructuredIngestionEndpoint() {
+ const uuid = Services.uuid.generateUUID().toString();
+ // Structured Ingestion does not support the UUID generated by Services.uuid,
+ // because it contains leading and trailing braces. Need to trim them first.
+ const docID = uuid.slice(1, -1);
+ const extension = `${STRUCTURED_INGESTION_NAMESPACE_MS}/${PING_TYPE}/${PING_VERSION}/${docID}`;
+ return `${lazy.structuredIngestionEndpointBase}/${extension}`;
+ }
+
+ /**
+ * Attach browser attribution data to a ping payload.
+ *
+ * It intentionally queries the *cached* attribution data other than calling
+ * `getAttrDataAsync()` in order to minimize the overhead here.
+ * For the same reason, we are not querying the attribution data from
+ * `TelemetryEnvironment.currentEnvironment.settings`.
+ *
+ * In practice, it's very likely that the attribution data is already read
+ * and cached at some point by `AboutWelcomeParent`, so it should be able to
+ * read the cached results for the most if not all of the pings.
+ */
+ _maybeAttachAttribution(ping) {
+ const attribution = lazy.AttributionCode.getCachedAttributionData();
+ if (attribution && Object.keys(attribution).length) {
+ ping.attribution = attribution;
+ }
+ return ping;
+ }
+
+ async _createPing(event) {
+ if (event.event_context && typeof event.event_context === "object") {
+ event.event_context = JSON.stringify(event.event_context);
+ }
+ let ping = {
+ ...event,
+ addon_version: Services.appinfo.appBuildID,
+ locale: Services.locale.appLocaleAsBCP47,
+ client_id: await lazy.telemetryClientId,
+ browser_session_id: lazy.browserSessionId,
+ };
+
+ return this._maybeAttachAttribution(ping);
+ }
+
+ /**
+ * Augment the provided event with some metadata and then send it
+ * to the messaging-system's onboarding endpoint.
+ *
+ * Is sometimes used by non-onboarding events.
+ *
+ * @param event - an object almost certainly from an onboarding flow (though
+ * there is a case where spotlight may use this, too)
+ * containing a nested structure of data for reporting as
+ * telemetry, as documented in
+ * https://firefox-source-docs.mozilla.org/browser/components/newtab/docs/v2-system-addon/data_events.html
+ * Does not have all of its data (`_createPing` will augment
+ * with ids and attribution if available).
+ */
+ async sendTelemetry(event) {
+ if (!this.telemetryEnabled) {
+ return;
+ }
+
+ const ping = await this._createPing(event);
+
+ try {
+ this.submitGleanPingForPing(ping);
+ } catch (e) {
+ // Though Glean APIs are forbidden to throw, it may be possible that a
+ // mismatch between the shape of `ping` and the defined metrics is not
+ // adequately handled.
+ Glean.messagingSystem.gleanPingForPingFailures.add(1);
+ }
+
+ this.pingCentre.sendStructuredIngestionPing(
+ ping,
+ this._generateStructuredIngestionEndpoint(),
+ STRUCTURED_INGESTION_NAMESPACE_MS
+ );
+ }
+
+ /**
+ * Tries to infer appropriate Glean metrics on the "messaging-system" ping,
+ * sets them, and submits a "messaging-system" ping.
+ *
+ * Does not check if telemetry is enabled.
+ * (Though Glean will check the global prefs).
+ *
+ * Note: This is a very unusual use of Glean that is specific to the use-
+ * cases of Messaging System. Please do not copy this pattern.
+ */
+ submitGleanPingForPing(ping) {
+ lazy.log.debug(`Submitting Glean ping for ${JSON.stringify(ping)}`);
+ // event.event_context is an object, but it may have been stringified.
+ let event_context = ping?.event_context;
+ if (typeof event_context === "string") {
+ try {
+ event_context = JSON.parse(event_context);
+ } catch (e) {
+ Glean.messagingSystem.eventContextParseError.add(1);
+ }
+ }
+
+ // We echo certain properties from event_context into their own metrics
+ // to aid analysis.
+ if (event_context?.reason) {
+ Glean.messagingSystem.eventReason.set(event_context.reason);
+ }
+ if (event_context?.page) {
+ Glean.messagingSystem.eventPage.set(event_context.page);
+ }
+ if (event_context?.source) {
+ Glean.messagingSystem.eventSource.set(event_context.source);
+ }
+
+ // The event_context is also provided as-is as stringified JSON.
+ if (event_context) {
+ Glean.messagingSystem.eventContext.set(JSON.stringify(event_context));
+ }
+
+ if ("attribution" in ping) {
+ for (const [key, value] of Object.entries(ping.attribution)) {
+ const camelKey = this._snakeToCamelCase(key);
+ try {
+ Glean.messagingSystemAttribution[camelKey].set(value);
+ } catch (e) {
+ // We here acknowledge that we don't know the full breadth of data
+ // being collected. Ideally AttributionCode will later centralize
+ // definition and reporting of attribution data and we can be rid of
+ // this fail-safe for collecting the names of unknown keys.
+ Glean.messagingSystemAttribution.unknownKeys[camelKey].add(1);
+ }
+ }
+ }
+
+ // List of keys handled above.
+ const handledKeys = ["event_context", "attribution"];
+
+ for (const [key, value] of Object.entries(ping)) {
+ if (handledKeys.includes(key)) {
+ continue;
+ }
+ const camelKey = this._snakeToCamelCase(key);
+ try {
+ // We here acknowledge that even known keys might have non-scalar
+ // values. We're pretty sure we handled them all with handledKeys,
+ // but we might not have.
+ // Ideally this can later be removed after running for a version or two
+ // with no values seen in messaging_system.invalid_nested_data
+ if (typeof value === "object") {
+ Glean.messagingSystem.invalidNestedData[camelKey].add(1);
+ } else {
+ Glean.messagingSystem[camelKey].set(value);
+ }
+ } catch (e) {
+ // We here acknowledge that we don't know the full breadth of data being
+ // collected. Ideally we will later gain that confidence and can remove
+ // this fail-safe for collecting the names of unknown keys.
+ Glean.messagingSystem.unknownKeys[camelKey].add(1);
+ // TODO(bug 1600008): For testing, also record the overall count.
+ Glean.messagingSystem.unknownKeyCount.add(1);
+ }
+ }
+
+ // With all the metrics set, now it's time to submit this ping.
+ GleanPings.messagingSystem.submit();
+ }
+
+ _snakeToCamelCase(s) {
+ return s.toString().replace(/_([a-z])/gi, (_str, group) => {
+ return group.toUpperCase();
+ });
+ }
+}