solidjs / solid-styled-components

A 1kb Styled Components library for Solid
MIT License
280 stars 26 forks source link

ThemeProvider does not accept theme change over createContext #39

Closed tghpereira closed 1 year ago

tghpereira commented 1 year ago

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
  2. Add solid-styled-components to your project
    yarn add solid-styled-components
  3. 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;

4. Extend definitions using declaration merge in a src/@types/styled.d.ts.
```typescript
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([ { theme: () => themes["dark"], }, { toggleTheme: () => undefined, themeName: () => "dark", }, ]);

export const AppThemeProvider: ParentComponent = (props) => { const [modeTheme, setModeTheme] = createSignal("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);

6. Create global Styles in src/styles/global/index.tsx.
```typescript
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 = ({ children }) => { return {children}; };


8. Add ThemeProvider of "solid style components", add GlobalStyles and its Container component, create a button using inline style in your App component..
```typescript
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( () => (

), 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

<!--
  Please add any other relevant dependencies to this table at the end.
  For example: Electron, React Native, or NestJS.
-->

| 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.
bonfantefilippo commented 1 year ago

Try to use createStore instead of createSignal on context