solid-styled-components icon indicating copy to clipboard operation
solid-styled-components copied to clipboard

ThemeProvider does not accept theme change over createContext

Open tghpereira opened this issue 3 years ago • 0 comments

Issue Description

Expected Behavior

Change props theme in styled of the "solid-styled-components" via createSignal or createContext.

Actual Behavior

When receiving context or signal, styled of the ThemeProvider doesn't seem to notice the change in state.

Erros Presented

Solid did not show errors in console or browser

Steps to Reproduce

  1. Start a new solid project
 npx degit solidjs/templates/ts my-app
  1. Add solid-styled-components to your project
yarn add solid-styled-components
  1. Create a light and a dark theme in src/styles/theme/index.ts.
export interface ITheme{
    colors: {
        background: {
            index: string;
            header: string;
        }
        fonts: {
            title: string;
            subTitle: string;
            text: string;
        },
        book: {
            index: string;
            green: string;
            red: string;
            orange: string;
            blue: string;
            cyan: string;
        },
        border:{
            header: string;
        }
    },
    
    fonts: {
        weight:{
            light: number;
            regular: number;
            medium: number;
            bold: number;
            black: number;
        },
        family: {
            title: string;
        }
    },
}
const darkTheme: ITheme = {
    colors:{
        background: {
            index: "#12131A",
            header: "#1E1E1E",
        },
        fonts: {
            title: "#FFFFFF",
            subTitle: "hsl(225, 20%, 60%)",
            text: "hsl(225, 20%, 60%)",
        },
        book: {
            index: "#2C2C2C",
            green: '#2ED47A',
            red: "#e83f58",
            orange: "#ff872c",
            blue: "#1182D9",
            cyan: "#6FB6F6",
        },
        border:{
            header: "#121212"
        }
    },
    fonts: {
        weight: {
            light: 300,
            regular: 400,
            medium: 500,
            bold: 700,
            black: 900,
        },
        family: {
            title: "Roboto",
        }
    },
};
const lightTheme: ITheme = {
    colors:{
        background: {
            index: "#FFFFFF",
            header: "#FFFFFF",
        },
        fonts: {
            title: "#1E1E1E",
            subTitle: "hsl(225, 20%, 60%)",
            text: "rgba(0, 0, 0, 0.6)",
        },
        book: {
            index: "hsl(225, 20%, 96%)",
            green: '#2ED47A',
            red: "#e83f58",
            orange: "#ff872c",
            blue: "#1182D9",
            cyan: "#6FB6F6",
        },
        border:{
            header: "hsl(225, 20%, 96%)"
        }
    },
    fonts: {
        weight: {
            light: 300,
            regular: 400,
            medium: 500,
            bold: 700,
            black: 900,
        },
        family: {
            title: "Roboto",
        }
    },
};

export const themes = {
    light: lightTheme,
    dark: darkTheme,
}
export type TThemeName = keyof typeof themes;
export type TThemeType = typeof themes.light | typeof themes.dark;
  1. Extend definitions using declaration merge in a src/@types/styled.d.ts.
import "solid-styled-components";
import { TThemeType } from "../styles/theme";

declare module "solid-styled-components" {
  export interface DefaultTheme extends TThemeType {}
}
  1. Create a context of your app theme in src/contexts/theme/index.tsx
import {
  createContext,
  useContext,
  ParentComponent,
  createSignal,
} from "solid-js";

import { themes } from "../../styles/theme";
import { TThemeName, TThemeType } from "../../styles/theme";

export type ThemeContextState = {
  theme: () => TThemeType;
};

export type ThemeContextValue = [
  state: ThemeContextState,
  actions: {
    toggleTheme: (selectTheme: TThemeName) => void;
    themeName: () => TThemeName;
  }
];

const AppThemeContext = createContext<ThemeContextValue>([
  {
    theme: () => themes["dark"],
  },
  {
    toggleTheme: () => undefined,
    themeName: () => "dark",
  },
]);

export const AppThemeProvider: ParentComponent = (props) => {
  const [modeTheme, setModeTheme] = createSignal<TThemeName>("dark");

  const toggleTheme = (mode: TThemeName) => {
    setModeTheme(mode);
  };

  const themeName = () => {
    return modeTheme();
  };

  const theme = () => {
    return themes[modeTheme()];
  };

  return (
    <AppThemeContext.Provider value={[{ theme }, { toggleTheme, themeName }]}>
      {props.children}
    </AppThemeContext.Provider>
  );
};

export const useTheme = () => useContext(AppThemeContext);

  1. Create global Styles in src/styles/global/index.tsx.
import { createGlobalStyles } from "solid-styled-components";

export const GlobalStyles = () => {
  const Styles = createGlobalStyles`
    * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    }
    html, body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    }
  `;
  return <Styles />;
};
  1. Create a Container component using the styled from "solid-styled-components" in src/components/Container/index.tsx.
import type { Component, JSXElement } from "solid-js";
import { styled } from "solid-styled-components";

const Content = styled("div")`
    width: 100vw;
    height: 100vh;
    background-color: ${({ theme }) => theme?.colors.background.index};
`;

interface IProps {
  children: JSXElement;
}

export const Container: Component<IProps> = ({ children }) => {
  return <Content>{children}</Content>;
};

  1. Add ThemeProvider of "solid style components", add GlobalStyles and its Container component, create a button using inline style in your App component..
import type { Component } from "solid-js";
import { ThemeProvider } from "solid-styled-components";
import { Container } from "./components/Container";
import { useTheme } from "./contexts/theme";
import { GlobalStyles } from "./styles/theme/global";

const App: Component = () => {
  const [{ theme }, { toggleTheme, themeName }] = useTheme();

  return (
    <ThemeProvider theme={theme()}>
      <Container>
        <button
          style={{
            padding: "10px",
            background: theme().colors.background.header,
            color: "red",
          }}
          onClick={() =>
            themeName() === "dark" ? toggleTheme("light") : toggleTheme("dark")
          }
        >
          {themeName()} - {JSON.stringify(theme(), null, 2)}
        </button>
      </Container>
      <GlobalStyles />
    </ThemeProvider>
  );
};

export default App;

  1. Import AppThemeProvider in index.tsx
import { render } from "solid-js/web";

import App from "./App";
import { AppThemeProvider } from "./contexts/theme";

render(
  () => (
    <AppThemeProvider>
      <App />
    </AppThemeProvider>
  ),
  document.getElementById("root") as HTMLElement
);

Notice that the style button in lina gets the theme change, but the component Container created by styled from "solid-styled-components" doesn't seem to notice the change of ThemeProvider props.

My Environment

Dependency Version
Operating System windows
Node.js version 16.15.1
Typescript version 4.8.2
Vite version 3.0.9
Vite Plugin Solid version 2.3.0
Solidjs version 1.5.1
Solidjs Styled Components version 0.28.5

Are you willing to resolve this issue by submitting a Pull Request?

  • ✖️ Yes, I have the time, and I know how to start.
  • ✖️ Yes, I have the time, but I don't know how to start. I would need guidance.
  • ✖️ No, I don’t have the time, but I can support (using donations) development.
  • ✖️ No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.
  • ✅ I don't know how to solve this bug, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

tghpereira avatar Oct 15 '22 17:10 tghpereira