Mantle Single Stylesheet Migration Guide
@ngrok/mantle/mantle.css holds the light theme and the dark theme. @ngrok/mantle/mantle-dark.css is gone, with MantleStyleSheets, mantleStyleSheetUrls, and the types MantleStyleSheetsProps and MantleThemeCssUrls. invert-theme islands, the dark: and light: variants, ThemeProvider, and PreventWrongThemeFlashScript work as before.
TL;DR: Delete every import of @ngrok/mantle/mantle-dark.css, every <MantleStyleSheets />, and every mantleStyleSheetUrls call. In a non-React <head>, delete the mantle-dark-styles <link>. Nothing replaces them.
Codemod
From a mantle checkout:
In a project that installs @ngrok/mantle:
The rules apply steps 1 and 2:
- They delete each
<MantleStyleSheets />that is a direct child of a JSX element. - They delete each
constwhose value is amantleStyleSheetUrlscall, when only a deleted<MantleStyleSheets />reads it. - They delete each JavaScript import of
@ngrok/mantle/mantle-dark.css, with or without?url, when only deleted code reads its name. - They delete the
MantleStyleSheets,mantleStyleSheetUrls,MantleStyleSheetsProps, andMantleThemeCssUrlsimports from@ngrok/mantle/themewhen only deleted code reads them, and they delete an import statement that holds nothing else.
Code that other code still reads stays: an exported const, a <MantleStyleSheets /> inside an expression such as {show && …}, a type annotation, and a mantle-dark.css URL in a preload list. The removed export then makes the type checker or the bundler name that code for manual work. The rules read a part through its import from @ngrok/mantle/theme, under its own name or an alias. A function that binds the part's name to a parameter or a local shadows the import, so the rules leave that function alone.
Steps 3 and 4 stay manual, because a CSS @import and an HTML template are not syntax a rule can read. The codemod is safe to run twice. Pass --dry-run to print the rewrites first, and run your formatter after the rewrite.
You are an agent migrating a codebase. Do this:
- Find every
MantleStyleSheetselement and everymantleStyleSheetUrlscall from@ngrok/mantle/theme, under its own name or an alias. Delete each one, theconstthat holds the call, and the imports. Delete theMantleStyleSheetsPropsandMantleThemeCssUrlstypes, or replace them with your own. KeepPreventWrongThemeFlashScriptin<head>; it did not change. - Find every JavaScript import of
@ngrok/mantle/mantle-dark.css, usuallyimport darkCssUrl from "@ngrok/mantle/mantle-dark.css?url". Delete it and every use of its name, such as aLinkpreload header in a server entry. The type checker does not report a stale?urlimport, because a*?urlmodule declaration types it. The bundler fails on it. - Find every CSS
@import "@ngrok/mantle/mantle-dark.css";. Delete it.@import "@ngrok/mantle/mantle.css";holds both themes. - In a
<head>that a non-React server writes, such as a Go template, delete<link id="mantle-dark-styles" rel="stylesheet" href="…/mantle-dark.css" />. Keep the inline theme script. - After editing, run the project's formatter, linter, type checker, tests, and production build.
Why one stylesheet? Every page loaded
mantle-dark.css, because aninvert-themeisland on a light page paints in dark. The second sheet saved no request, and it made every app wire a?urlimport and a component into<head>.
Before → after
The root stylesheets
An aliased import
A server entry that preloads the stylesheet
A CSS entry point
A non-React head
Edge cases & gotchas
- A theme class that disagrees with
data-applied-theme. The dark rules now come before the light rules inmantle.css. When the<html>theme class anddata-applied-themedisagree, the light rule wins. Before, the stylesheet order decided.ThemeProviderandPreventWrongThemeFlashScriptkeep the two in step, so only a page whose writers get differentforceThemevalues sees this.
How to verify
- Run
rg "mantle-dark|MantleStyleSheets|mantleStyleSheetUrls|MantleThemeCssUrls"across the repo. Expect no results. - Load a page in light, in dark, and with an
invert-themeisland. The page must look as before, and the browser must load nomantle-darkstylesheet. - Run the project's formatter, linter, type checker, tests, and production build.