pankod/refine

View on GitHub
packages/live-previews/src/scope/mui.tsx

Summary

Maintainability
A
35 mins
Test Coverage
import React from "react";
import parseHtml from "html-react-parser";
import type { RefineProps } from "@refinedev/core";
import { RefineCommonScope } from "./common";
import type * as RefineMuiTypes from "@refinedev/mui";
import * as MuiMaterialStyles from "@mui/material/styles";

import * as EmotionReact from "@emotion/react";
import * as EmotionStyled from "@emotion/styled";
import * as MuiLab from "@mui/lab";
import * as MuiMaterial from "@mui/material";
import * as MuiXDataGrid from "@mui/x-data-grid";
import * as ReactHookForm from "react-hook-form";

import * as RefineMui from "@refinedev/mui";

const { CssBaseline, GlobalStyles } = MuiMaterial;

import LightModeOutlined from "@mui/icons-material/LightModeOutlined";
import DarkModeOutlined from "@mui/icons-material/DarkModeOutlined";
import ArrowRight from "@mui/icons-material/ArrowRight";
import Camera from "@mui/icons-material/Camera";
import ListOutlined from "@mui/icons-material/ListOutlined";
import Logout from "@mui/icons-material/Logout";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import ChevronLeft from "@mui/icons-material/ChevronLeft";
import ChevronRight from "@mui/icons-material/ChevronRight";
import MenuRounded from "@mui/icons-material/MenuRounded";
import Menu from "@mui/icons-material/Menu";
import Dashboard from "@mui/icons-material/Dashboard";
import Check from "@mui/icons-material/Check";
import Close from "@mui/icons-material/Close";

import axios from "axios";

const SIMPLE_REST_API_URL = "https://api.fake-rest.refine.dev";

const RefineMuiDemo: React.FC<
  Partial<RefineProps> & {
    initialRoutes?: string[];
  }
> = ({ initialRoutes, ...rest }) => {
  if (initialRoutes) {
    RefineCommonScope.setInitialRoutes(initialRoutes);
  }

  return (
    <ThemeProvider theme={RefineMui.LightTheme}>
      <CssBaseline />
      <GlobalStyles styles={{ html: { WebkitFontSmoothing: "auto" } }} />
      <RefineMui.RefineSnackbarProvider>
        <RefineCommonScope.RefineCore.Refine
          legacyRouterProvider={
            RefineCommonScope.LegacyRefineReactRouterV6.default
          }
          dataProvider={RefineCommonScope.RefineSimpleRest.default(
            SIMPLE_REST_API_URL,
          )}
          notificationProvider={RefineMui.notificationProvider}
          Layout={RefineMui.Layout}
          Sider={() => null}
          catchAll={<RefineMui.ErrorComponent />}
          options={{
            disableTelemetry: true,
            reactQuery: {
              devtoolConfig: false,
            },
          }}
          {...rest}
        />
      </RefineMui.RefineSnackbarProvider>
    </ThemeProvider>
  );
};

const ThemedTitleV2 = ({
  collapsed,
  wrapperStyles,
  text: textFromProps,
  icon: iconFromProps,
}: RefineMuiTypes.RefineLayoutThemedTitleProps) => {
  const [svgContent, setSvgContent] = React.useState<string | undefined>(
    window.__refineIconSVGContent || undefined,
  );
  const [title, setTitle] = React.useState<string | undefined>(
    window.__refineTitleContent || undefined,
  );

  React.useEffect(() => {
    if (typeof window !== "undefined") {
      const messageListener = (event: MessageEvent) => {
        if (event.data.type === "UPDATE_DYNAMIC_VALUES") {
          if (event.data.payload?.title) {
            setTitle(event.data.payload?.title);

            if (typeof window !== "undefined") {
              window.__refineTitleContent = event.data.payload?.title;
            }
          }

          if (event.data.payload?.icon) {
            try {
              axios
                .get(`/assets/icons/${event.data.payload.icon}`)
                .then((res) => {
                  const content = res.data
                    .replace(/fill\=\"white\"/g, `fill="currentColor"`)
                    .replace(/stroke\=\"white\"/g, `stroke="currentColor"`);

                  setSvgContent(content);

                  if (typeof window !== "undefined") {
                    window.__refineIconSVGContent = content;
                  }
                });
            } catch (error) {
              console.error(error);
            }
          }
        }
      };

      window.addEventListener("message", messageListener);

      return () => {
        window.removeEventListener("message", messageListener);
      };
    }

    return () => undefined;
  }, []);

  return (
    <RefineMui.ThemedTitleV2
      collapsed={collapsed}
      wrapperStyles={wrapperStyles}
      text={title || textFromProps}
      icon={svgContent ? parseHtml(svgContent) : iconFromProps}
    />
  );
};

const ThemeProvider = ({
  children,
  theme,
}: {
  children?: React.ReactNode;
  theme?: { palette?: { mode?: "light" | "dark" } };
}) => {
  const [themeFromWindow, setThemeFromWindow] = React.useState<
    undefined | string
  >(undefined);

  React.useEffect(() => {
    if (typeof window !== "undefined") {
      const messageListener = (event: MessageEvent) => {
        if (event.data.type === "UPDATE_DYNAMIC_VALUES") {
          if (event.data.payload?.theme) {
            setThemeFromWindow(event.data.payload.theme);
          }
        }
      };

      window.addEventListener("message", messageListener);

      return () => {
        window.removeEventListener("message", messageListener);
      };
    }

    return () => undefined;
  }, []);

  const isLightPalette = theme?.palette?.mode === "light";

  const RefineThemeFromWindow = React.useMemo(() => {
    if (themeFromWindow && themeFromWindow in RefineMui.RefineThemes) {
      if (isLightPalette) {
        return RefineMui.RefineThemes[
          themeFromWindow as keyof typeof RefineMui.RefineThemes
        ];
      }
      return RefineMui.RefineThemes[
        `${themeFromWindow}Dark` as keyof typeof RefineMui.RefineThemes
      ];
    }

    return undefined;
  }, [themeFromWindow, isLightPalette]);

  return (
    <MuiMaterialStyles.ThemeProvider
      theme={(RefineThemeFromWindow as any) ?? theme}
    >
      {children}
    </MuiMaterialStyles.ThemeProvider>
  );
};

const MuiScope = {
  // ...RefineCommonScope,
  RefineMuiDemo,
  RefineMui: {
    ...RefineMui,
    ThemedTitleV2,
  },
  EmotionReact,
  EmotionStyled,
  MuiLab,
  MuiMaterial,
  MuiXDataGrid,
  MuiMaterialStyles: {
    ...MuiMaterialStyles,
    ThemeProvider,
  },
  ReactHookForm,
  MuiIconsMaterial: {
    Close,
    Check,
    LightModeOutlined,
    DarkModeOutlined,
    ArrowRight,
    Camera,
    ListOutlined,
    Logout,
    ExpandLess,
    ExpandMore,
    ChevronLeft,
    ChevronRight,
    MenuRounded,
    Menu,
    Dashboard,
  },
};

export default MuiScope;