npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@iamstarkov/theming-w-listener

v1.0.3

Published

Unified CSSinJS theming solution for React

Downloads

13

Readme

theming

Greenkeeper badge

NPM version Build Coveralls Status Dependency Status

Unified CSSinJS theming solution for React

  • ThemeProvider allows you to pass, update, merge and augment theme through context down react tree.
  • withTheme allows you to receive theme and its updates in your components as a theme prop.
  • createTheming allows you to integrate theming into your CSSinJS library with custom channel (if you need custom one).
  • Advanced usage: themeListener allows you to add theming support in your components.

See Motivation for details.

Table of Contents

Install

npm install --save theming
# or
yarn add theming

Usage

In your components

Note: this component i will use later to show what theme you will get

import React from 'react';
import { withTheme } from 'theming';

const DemoBox = props => {
  console.log(props.theme);
  return (<div />);
}

export default withTheme(DemoBox);

In your app

import React from 'react';
import { ThemeProvider } from 'theming';
import DemoBox from './components/DemoBox'

const theme = {
  color: 'black',
  background: 'white',
};

const App = () => (
  <ThemeProvider theme={theme}>
    <DemoBox /> {/* { color: 'black', background: 'white' } */}
  </ThemeProvider>
)

export default App;

Playground demo

Be our guest, play with theming in this webpackbin: https://www.webpackbin.com/bins/-Km8TglfWP84oYhDquT1

theming playground demo

Motivation

These components are enabling seamless theming for your react applications. And as far as you dont want to pass theme object to each and every component. Thats why you want to use context. But as far context feature is experimental API and it is likely to break in future releases of React you don't want to use it directly. Here theming comes to play.

If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.

If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
Context, React documentation

Regarding isolation your use of context to a small area and small areas_ in particular our very own react prophet Dan Abramov have a thing to say:

Should I use React unstable “context” feature?

Dan Abramov @dan_abramov on Twitter

So you are fine to use context for theming. theming package provides everything you need to do that:

  • ThemeProvider allows you to pass and update theme through context down react tree.
  • withTheme allows you to receive theme and its updates in your components as a theme prop.
  • createTheming allows you to integrate theming into your CSSinJS library with custom channel (if you need custom one).

API

channel

Theming package by default uses this string as a name of the field in context (hence contextTypes and childContextTypes). If you want to build your own components on top of theming, it might be a good idea to not rely on hard coded value, but instead import this value from the package.

import { channel } from 'theming';

console.log(channel); '__THEMING__';

ThemeProvider

React High-Order component, which passes theme object down the react tree by context.

import { ThemeProvider } from 'theming';
const theme = { /*…*/ };

<ThemeProvider theme={theme}>
  <App />
</ThemeProvider>

props

props.theme

Required
Type: Object, Function

If its Object and its root ThemeProvider then its intact and being passed down the react tree.

const theme = { themed: true };

<ThemeProvider theme={theme}>
  <DemoBox /> {/* { themed: true } */}
</ThemeProvider>

If its Object and its nested ThemeProvider then its being merged with theme from parent ThemeProvider and passed down to the react tree.

const theme = { themed: true };
const patch = { merged: true };

<ThemeProvider theme={theme}>
  <ThemeProvider theme={patch}>
    <DemoBox /> {/* { themed: true, merged: true } */}
  </ThemeProvider>
</ThemeProvider>

If its Function and its nested ThemeProvider then its being applied to the theme from parent ThemeProvider. if result is an Object it will be passed down to the react tree, throws otherwise.

const theme = { themed: true };
const augment = outerTheme =>
  Object.assign({}, outerTheme, { augmented: true });

<ThemeProvider theme={theme}>
  <ThemeProvider theme={augment}>
    <DemoBox /> {/* { themed: true, augmented: true } */}
  </ThemeProvider>
</ThemeProvider>
props.children

Required
Type: PropTypes.element

ThemeProvider uses React.Children.only in render, which returns the only child in children. Throws otherwise.

withTheme(component)

React High-Order component, which maps context to theme prop.

component

Required
Type: PropTypes.element

You need to have ThemeProvider with a theme somewhere upper the react tree, after that wrap your component in withTheme and your component will get theme as a prop. withTheme will handle initial theme object as well as theme updates.

PS. It doesnt break if you have PureComponent somewhere in between your ThemeProvider and withTheme (i have tests for that).

Usage with Component:

import React from 'react';
import { withTheme } from 'theming';

const DemoBox = props => {
  console.log(props.theme);
  return (<div />);
}

export default withTheme(DemoBox);

In the app:

import React from 'react';
import { ThemeProvider } from 'theming';
import DemoBox from './components/DemoBox'

const theme = {
  color: 'black',
  background: 'white',
};

const App = () => (
  <ThemeProvider theme={theme}>
    <DemoBox /> {/* { color: 'black', background: 'white' } */}
  </ThemeProvider>
)

export default App;

themeListener

Advanced helper to hook theming in any Component.

import { themeListener } from 'theming';

function CustomWithTheme(Component) {
  return class CustomWithTheme extends React.Component {
    static contextTypes = themeListener.contextTypes;
    constructor(props) {
      super(props);
      this.state = { theme: {} };
      this.setTheme = theme => this.setState({ theme });
    }
    componentWillMount() {
      this.setTheme(themeListener.initial(this.context))
    }
    componentDidMount() {
      this.unsubscribe = themeListener.subscribe(this.context, this.setTheme);
    }
    componentWillUnmount() {
      this.unsubscribe();
    }
    render() {
      const { theme } = this.state;
      return <Component theme={theme} {...this.props} />;
    }
  }
}

themeListener is an Object with following fields:

  • themeListener.contextTypes
    • type: Object
    • meant to be added your component's contextTypes:
      static contextTypes = themeListener.contextTypes;
      // or
      static contextTypes = Object.assign({}, themeListener.contextTypes, {
        /* your Component's contextTypes */
      });
  • themeListener.initial
    • type: Function
    • takes a single context Object, where context is this.context from your component
    • meant to be used in componentWillMount
    • throws an error if your component will be used outside ThemeProvider
    • example:
      constructor(props) {
        super(props);
      }
      componentWillMount() {
        this.setState({ theme: themeListener.initial(this.context) });
      }
  • themeListener.subscribe
    • type: Function
    • takes 2 arguments:
      • context Object, where context is this.context from your component
      • callback Function, which in turn will be invoked with theme update Object, every time theme is updated in ThemeProvider
    • meant to be used in componentDidMount
    • returns unsubscribe Function, which you should invoke in componentWillUnmount
    • example:
      constructor(props) {
        super(props);
      }
      componentDidMount() {
        this.unsubscribe = themeListener.subscribe(theme => this.setState({ theme }));
      }
      componentWillUnmount() {
        this.unsubscribe();
      }

createTheming(customChannel)

Function to create ThemeProvider and withTheme with custom context channel.

customChannel

Type: String
Default: __THEMING__
Result: Object { channel, withTheme, ThemeProvider. themeListener }

withTheme, ThemeProvider and themeListener are the same as default ones, but with overwritten context channel.

channel is customChannel to track what is context channel.

import { createTheming } from 'theming';

const theming = createTheming('__styled-components__');

const { channel, withTheme, ThemeProvider } = theming;

export default {
  channel,
  withTheme,
  ThemeProvider,
};

Credits

License

MIT © Vladimir Starkov