void DevMenuManager::CreateAndShowUI()

in vnext/Microsoft.ReactNative/Views/DevMenu.cpp [98:300]


void DevMenuManager::CreateAndShowUI() noexcept {
  if (!Mso::React::ReactOptions::UseDeveloperSupport(m_context->Properties()))
    return;

  winrt::Microsoft::ReactNative::DevMenuControl devMenu{};

  devMenu.RemoteDebugText().Text(
      Mso::React::ReactOptions::UseWebDebugger(m_context->Properties()) ? L"Disable Remote JS Debugging"
                                                                        : L"Enable Remote JS Debugging");
  devMenu.RemoteDebugDesc().Text(
      L"When enabled runs the JS remotely in VSCode or Chrome based on what you attach to the packager.  This means that the JS may run with a different JS engine than it runs in on in the real application, in addition synchronous native module calls, and JSI native modules will not work.");

  devMenu.FastRefreshText().Text(
      Mso::React::ReactOptions::UseFastRefresh(m_context->Properties()) ? L"Disable Fast Refresh"
                                                                        : L"Enable Fast Refresh");
  if (Mso::React::ReactOptions::JsiEngine(m_context->Properties()) == Mso::React::JSIEngine::Hermes) {
    devMenu.SamplingProfilerText().Text(
        !Microsoft::ReactNative::HermesSamplingProfiler::IsStarted() ? L"Start Hermes sampling profiler"
                                                                     : L"Stop and copy trace path to clipboard");
    devMenu.SamplingProfilerIcon().Glyph(
        !Microsoft::ReactNative::HermesSamplingProfiler::IsStarted() ? L"\ue1e5" : L"\ue15b");

    std::ostringstream os;
    if (Microsoft::ReactNative::HermesSamplingProfiler::IsStarted()) {
      os << "Hermes Sampling profiler is running.. !";
    } else {
      os << "Click to start.";
    }

    auto lastTraceFilePath = Microsoft::ReactNative::HermesSamplingProfiler::GetLastTraceFilePath();
    if (!lastTraceFilePath.empty()) {
      os << std::endl
         << "Samples from last invocation are stored at " << lastTraceFilePath.c_str()
         << "  (path copied to clipboard).";
      os << std::endl << "Navigate to \"edge:\\tracing\" and load the trace file.";
    }

    devMenu.SamplingProfilerDescText().Text(winrt::to_hstring(os.str()));
  }

  devMenu.DirectDebugText().Text(
      Mso::React::ReactOptions::UseDirectDebugger(m_context->Properties()) ? L"Disable Direct Debugging"
                                                                           : L"Enable Direct Debugging");
  devMenu.DirectDebugDesc().Text(
      L"If using Chakra, this will allow Visual Studio to be attached directly to the application using \"Script Debugging\" to debug the JS running directly in this app.\nIf using V8/Hermes, this will enable standard JS debugging tools such as VSCode to attach to the application.");

  devMenu.BreakOnNextLineText().Text(
      Mso::React::ReactOptions::DebuggerBreakOnNextLine(m_context->Properties()) ? L"Disable Break on First Line"
                                                                                 : L"Enable Break on First Line");

  m_reloadJSRevoker = devMenu.Reload().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          DevSettings::Reload(React::ReactPropertyBag(strongThis->m_context->Properties()));
        }
      });

  m_remoteDebugJSRevoker = devMenu.RemoteDebug().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          Mso::React::ReactOptions::SetUseWebDebugger(
              strongThis->m_context->Properties(),
              !Mso::React::ReactOptions::UseWebDebugger(strongThis->m_context->Properties()));
          DevSettings::Reload(React::ReactPropertyBag(strongThis->m_context->Properties()));
        }
      });

  m_directDebuggingRevoker = devMenu.DirectDebug().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          Mso::React::ReactOptions::SetUseDirectDebugger(
              strongThis->m_context->Properties(),
              !Mso::React::ReactOptions::UseDirectDebugger(strongThis->m_context->Properties()));
          DevSettings::Reload(React::ReactPropertyBag(strongThis->m_context->Properties()));
        }
      });

  m_breakOnNextLineRevoker = devMenu.BreakOnNextLine().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          Mso::React::ReactOptions::SetDebuggerBreakOnNextLine(
              strongThis->m_context->Properties(),
              !Mso::React::ReactOptions::DebuggerBreakOnNextLine(strongThis->m_context->Properties()));
          DevSettings::Reload(React::ReactPropertyBag(strongThis->m_context->Properties()));
        }
      });

  m_fastRefreshRevoker = devMenu.FastRefresh().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          Mso::React::ReactOptions::SetUseFastRefresh(
              strongThis->m_context->Properties(),
              !Mso::React::ReactOptions::UseFastRefresh(strongThis->m_context->Properties()));
          DevSettings::Reload(React::ReactPropertyBag(strongThis->m_context->Properties()));
        }
      });

  if (Mso::React::ReactOptions::JsiEngine(m_context->Properties()) == Mso::React::JSIEngine::Hermes) {
    m_samplingProfilerRevoker = devMenu.SamplingProfiler().Click(
        winrt::auto_revoke,
        [wkThis = weak_from_this()](
            auto & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept -> winrt::fire_and_forget {
          if (auto strongThis = wkThis.lock()) {
            strongThis->Hide();
            if (!Microsoft::ReactNative::HermesSamplingProfiler::IsStarted()) {
              Microsoft::ReactNative::HermesSamplingProfiler::Start();
            } else {
              auto traceFilePath = co_await Microsoft::ReactNative::HermesSamplingProfiler::Stop();
              auto uiDispatcher =
                  React::implementation::ReactDispatcher::GetUIDispatcher(strongThis->m_context->Properties());
              uiDispatcher.Post([traceFilePath]() {
                DataTransfer::DataPackage data;
                data.SetText(winrt::to_hstring(traceFilePath));
                DataTransfer::Clipboard::SetContentWithOptions(data, nullptr);
              });
            }
          }
        });
  } else {
    devMenu.SamplingProfiler().Visibility(xaml::Visibility::Collapsed);
  }

  m_toggleInspectorRevoker = devMenu.Inspector().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          DevSettings::ToggleElementInspector(*(strongThis->m_context));
        }
      });

  m_configBundlerRevoker = devMenu.ConfigBundler().Click(
      winrt::auto_revoke,
      [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
          React::ReactPropertyBag(strongThis->m_context->Properties()).Get(ConfigureBundlerProperty())();
        }
      });
  // Only show Configure Bundler when connected to a bundler
  devMenu.ConfigBundler().Visibility(
      (Mso::React::ReactOptions::UseFastRefresh(m_context->Properties()) ||
       Mso::React::ReactOptions::UseWebDebugger(m_context->Properties()))
          ? xaml::Visibility::Visible
          : xaml::Visibility::Collapsed);

  m_cancelRevoker = devMenu.Cancel().Click(
      winrt::auto_revoke, [wkThis = weak_from_this()](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) {
        if (auto strongThis = wkThis.lock()) {
          strongThis->Hide();
        }
      });

  m_flyout = xaml::Controls::Flyout{};
  m_flyout.Content(devMenu);
  if (Is19H1OrHigher()) {
    // ShouldConstrainToRootBounds added in 19H1
    m_flyout.ShouldConstrainToRootBounds(false);
  }

  xaml::UIElement root{nullptr};
  auto xamlRoot = React::XamlUIService::GetXamlRoot(m_context->Properties());
  if (xamlRoot) {
    m_flyout.XamlRoot(xamlRoot);
    root = xamlRoot.Content();
  } else {
    auto window = xaml::Window::Current();
    root = window.Content();
  }

  m_flyout.LightDismissOverlayMode(xaml::Controls::LightDismissOverlayMode::On);
  devMenu.XYFocusKeyboardNavigation(xaml::Input::XYFocusKeyboardNavigationMode::Enabled);

  auto style = xaml::Style(winrt::xaml_typename<xaml::Controls::FlyoutPresenter>());
  style.Setters().Append(xaml::Setter(
      xaml::Controls::ScrollViewer::HorizontalScrollBarVisibilityProperty(),
      winrt::box_value(xaml::Controls::ScrollBarVisibility::Disabled)));
  style.Setters().Append(xaml::Setter(
      xaml::Controls::ScrollViewer::VerticalScrollBarVisibilityProperty(),
      winrt::box_value(xaml::Controls::ScrollBarVisibility::Disabled)));
  style.Setters().Append(xaml::Setter(
      xaml::Controls::ScrollViewer::HorizontalScrollModeProperty(),
      winrt::box_value(xaml::Controls::ScrollMode::Disabled)));
  style.Setters().Append(xaml::Setter(
      xaml::Controls::ScrollViewer::VerticalScrollModeProperty(),
      winrt::box_value(xaml::Controls::ScrollMode::Disabled)));

  m_flyout.FlyoutPresenterStyle(style);
  m_flyout.ShowAt(root.as<xaml::FrameworkElement>());

  // Notify instance that dev menu is shown -- This is used to trigger a connection to dev tools
  m_context->CallJSFunction("RCTNativeAppEventEmitter", "emit", folly::dynamic::array("RCTDevMenuShown"));
}