Files
webstudio/apps/builder/app/shared/theme/theme.ts
T
Ivan Starkov d243fbc2fb Fix error in dev mode (#1408)
## Description

Fixes Error in dev mode on every start or reload

```
react-dom.development.js:67 Warning: Prop `className` did not match. Server: "null" Client: "t-doScVt"
    at html
    at Root (http://localhost:3000/build/_shared/chunk-TNFZIIN2.js:36:22)
 ```

It works because of bug, now without bug it shows
https://github.com/webstudio-is/webstudio-builder/pull/1408

I would comment usetEffect for now



## Steps for reproduction

Run localy, see Error has gone

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why", not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login: 5de6)
- [ ] updated [test cases](https://github.com/webstudio-is/webstudio-builder/blob/main/apps/builder/docs/test-cases.md) document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
2023-04-10 19:43:34 +04:00

112 lines
2.8 KiB
TypeScript

import { useLoaderData } from "@remix-run/react";
import { isFeatureEnabled } from "@webstudio-is/feature-flags";
import { darkTheme } from "@webstudio-is/design-system";
import { restThemePath } from "~/shared/router-utils";
import type { ColorScheme, ThemeSetting } from "./types";
import { useState } from "react";
// User selected theme setting.
let setting: ThemeSetting = isFeatureEnabled("dark") ? "system" : "light";
// Current systeme theme.
let system: ColorScheme;
/**
* Subscribes color scheme change event and rerenders
*/
const subscribeSystemTheme = () => {
if (typeof matchMedia === "undefined") {
return;
}
const query = matchMedia("(prefers-color-scheme: light)");
const queryColorScheme = (query: MediaQueryList | MediaQueryListEvent) =>
query.matches ? "light" : "dark";
system = queryColorScheme(query);
query.addEventListener("change", (queryEvent) => {
system = queryColorScheme(queryEvent);
renderThemeProps();
});
};
subscribeSystemTheme();
const fallbackTheme = "light";
/**
* Logic we use to decide depending on user setting which color scheme to use.
*/
const getColorScheme = (): ColorScheme => {
if (setting === "system") {
return system || fallbackTheme;
}
return setting || fallbackTheme;
};
/**
* When switching theme we need to apply the class/style manually.
*/
const renderThemeProps = () => {
const theme = getColorScheme();
const root = document.documentElement;
theme === "dark"
? root.classList.add(darkTheme.className)
: root.classList.remove(darkTheme.className);
root.style.colorScheme = theme;
root.dataset.theme = theme;
};
/**
* Apply immediately and set the cookie on the server.
*/
export const setThemeSetting = (nextSetting: ThemeSetting) => {
setting = nextSetting;
renderThemeProps();
fetch(restThemePath({ setting }));
};
/**
* Returns the class and style to applied to some root node serverside and during hydration.
*/
export const useThemeProps = () => {
const data = useLoaderData();
if (data.theme.setting) {
setting = data.theme.setting;
}
if (data.theme.system) {
system = data.theme.system;
}
const [themeProps] = useState<{
className: string | undefined;
style: { colorScheme: ColorScheme };
"data-theme": ColorScheme;
}>({
className: undefined,
style: { colorScheme: "light" },
"data-theme": "light",
});
/*
// @todo uncomment when we will decide to use theme
useEffect(() => {
const theme = getColorScheme();
setThemeProps(() => ({
className: theme === "dark" ? darkTheme.className : undefined,
style: { colorScheme: theme },
"data-theme": theme,
}));
}, []);
*/
return themeProps;
};
/**
* Currently selected by user theme setting.
*/
export const getThemeSetting = (): ThemeSetting => {
return setting;
};