jss-theme
TypeScript icon, indicating that this package has built-in type declarations

1.1.3 • Public • Published

JSS Theme

npm version GitHub license Size Downloads

Framework agnostic theming solution inspired by React MUI theming solution in order to implement something like that for Angular projects.

Demo & docs

Demo and docs could be found here.

Example in sandbox could be found here.

IMPORTANT

Since 1.0.0 is shipped as separate package providing only general API for working w/ Themes.

There are other packages:

Notes

Include necessary typescript typings.

Init

initJss(options?: JssOptions | boolean) => void

First of all call this method first to init JSS with default preset and optional custom options.

If provided true value - will be called with jss-default-preset. If false - without any preset. If options - just with provided options.

Returns created Jss instance so there are abilities to add plugins etc.

This method is just alias for next piece of code:

import jss from 'jss';
import preset from 'jss-preset-default';

jss.setup(preset());
// or
const options = { ... };
jss.setup(options);

General usage

// theme.ts

import { createDefaultTheme, Theme } from 'jss-theme';

createDefaultTheme({ spacing: 8, color: '#ff0000' }); // Work w/ default Theme instance

export const MyTheme = new Theme({ spacing: 12, color: '#f2f2f2' }); // Or create own Theme instance

...

// app.component.ts

import { Component, OnInit, DoCheck } from '@angular/core';
import { makeStyles, useStyles, JssClasses, JssTheme, isEqualTheme, getTheme, updateTheme } from 'jss-theme';

import { MyTheme } from '../path/to/theme.ts'

const styles = makeStyles((theme) => ({ //  MyTheme.makeStyles((theme) => ({ ... }))
  App: { margin: theme.spacing },
}));

@Component({
  template: `
    <div [class]="classes.App">Jss styled div with margins</div>
    <button (click)="handleUpdateTheme()">Update theme</button>
  `,
})
class App implements OnInit, DoCheck {
  public classes: JssClasses = { };
  private _cachedTheme: JssTheme;

  public ngOnInit(): void {
    this._cachedTheme = getTheme();
    // OR: this._cachedTheme = MyTheme.getTheme();
    // OR: this._cachedTheme = getTheme(MyTheme);

    this.classes = useStyles(styles);
    // OR: this.classes = MyTheme.useStyles(styles);
    // OR: this.classes = useStyles(styles, null, MyTheme);
  }

  public DoCheck(): void {
    if (!isEqualTheme(this._cachedTheme)) {
      // OR: if (!MyTheme.isEqualTheme(this._cachedTheme)) {...}
      // OR: if (!isEqualTheme(this._cachedTheme, MyTheme)) {...}

      this._cachedTheme = getTheme();
      // OR: this._cachedTheme = MyTheme.getTheme();
      // OR: this._cachedTheme = getTheme(MyTheme);

      this.classes = useStyles(styles);
      // OR: this.classes = MyTheme.useStyles(styles);
      // OR: this.classes = useStyles(styles, null, MyTheme);
    }
  }

  public handleUpdateTheme(): void {
    updateTheme({ spacing: 12 });
    // OR: MyTheme.updateTheme({ spacing: 12 });
    // OR: updateTheme({ spacing: 12 }, null, null, MyTheme);
  }
}

...

ThemeProvider, UseStyles and createJssStyledComponent

ThemeProvider

Since version 1.1.1 jss-theme package provides ThemeProvider class, which internally depends on rxjs package.

// themeProvider.ts
import { ThemeProvider, Theme } from 'jss-theme';

interface ITheme {
  spacing: number;
  color: string;
}

const theme = new Theme<ITheme>({ spacing: 8, color: '#cc00cc' });
export const themeProvider = new ThemeProvider(theme); // or const themeProvider = new ThemeProvider<ITheme>({ spacing: 8, color: '#cc00cc' });

Then in another component

// component.ts
import { themeProvider } from './path/to/themeProvider';

const styles = themeProvider.makeStyles((theme) => ({ TestClass: { color: theme.color } }));

class Component {
  public classes = themeProvider.useStyles(this, styles);
}
// component2.ts
import { themeProvider } from './path/to/themeProvider';

class Component {
  public someMethod(): void {
    themeProvider.updateTheme({ color: '#1c1c1c' });
  }
}

note for Angular users. If using OnPush change detection strategy it would be useful to inject ChangeDetectorRef into component. ThemeProvider will in such way use it to markForCheck component.

UseStyles

Decorator for class property. It adds to class property a getter to receive correct classes.

// component.ts
import { makeStyles, UseStyles, JssClasses } from 'jss-theme';

const styles = makeStyles((theme) => ({ TestClass: { color: theme.color } }));

class Component {
  @UseStyles(styles)
  public classes: JssClasses;
}

createJssStyledComponent

Function to create component w/ injected themeProvider.

// JssStyledComponent.ts
import { createJssStyledComponent } from 'jss-theme';
import { themeProvider } from './path/to/themeProvider';

export const JssStyledComponent = createJssStyledComponent(themeProvider);
// component.ts
import { themeProvider } from './path/to/themeProvider';
import { JssStyledComponent } from './path/to/JssStyledComponent';

const styles = themeProvider.makeStyles((theme) => ({ TestClass: { color: theme.color } }));

class Component extends JssStyledComponent {
  constructor() {
    super(styles);
    console.log(this.classes);
  }
}

note for Angular users. It would be better and more optimized ot use UseStyles combining w/ OnPush change detection strategy.

Detailed usage for custom Theme (multiple Themes)

new Theme(themeConfig?, options?, replacer?)

Creates new theme, which could be used in components. Constructor gets 3 arguments: theme config for new Theme instance and optional default options for creating new stylesheets and replacer for compiled styles. Each Theme instance has following methods:

  • getTheme() => JssTheme Returns current theme value;
  • updateDefaultOptions(options) => void Updates default options for creating new stylesheets
  • updateDefaultReplacer(replacer) => void Updates default replacer for theme styles. This one is concerned with Jss compiler errors during parsing some pseudo-classes (:first-child, :first-of-type)
  • isEqualTheme(theme) => boolean Check whether provided theme options equals to that used by Theme instance
  • hasStylesInCache(styles) => boolean Checks if provided styles are cached. Necessary for checking for theme dependent styles updates;
  • rewriteTheme(themeConfig?, options?, replacer?) => JssTheme Totally rewrite current theme options with provided new (no merge here). Optional params as for constructor
  • updateTheme(themeConfig, options?, replacer?) => Classes Updates theme with new values. Optionally could be provided jss sheet options. Optional params as for constructor
  • useStyles(styles, options?) => Classes Gets styles, compiles them, attaches to DOM and returns related classNames
  • makeStyles(styles) => JssStyles Helper for providing correct type definitions and intellisense while creating styles
import { Theme } from 'jss-theme';

const SomeTheme = new Theme({ spacing: 8 });
// or
const SomeTheme = new Theme();
SomeTheme.rewriteTheme({ spacing: 8 });

// Methods
const theme = SomeTheme.getTheme();
SomeTheme.updateDefaultOptions({ ... });
SomeTheme.updateDefaultReplacer(replacer);
SomeTheme.isEqualTheme(theme);
const styles = SomeTheme.makeStyles((theme) => ({
	calssName: { margin: theme.spacing }
}))
SomeTheme.hasStylesInCache(styles);
const classes = SomeTheme.useStyles(styles);
SomeTheme.updateTheme({ spacing: 1 });

Detailed usage for default Theme. (This are shortcut functions for Theme instance methods)

createDefaultTheme(themeConfig?, options?, replacer?) => DefaultTheme

This function should be called before any other methods in order to use them on default theme instance.

Second optional argument provides default options for creating new stylesheets. Third optional argument provides default replacer for compiled styles.

If no first param provided - creates and returns Default Theme instance with default (Material Design) theme config. If provided first param - creates default Theme instance with provided config.

import { createDefaultTheme, getTheme } from 'jss-theme';

createDefaultTheme({ spacing: 8 });

console.log(getTheme().spacing === 8);

getDefaultTheme() => DefaultThemeInstance

Returns Default (precreated) Theme instance, which ships with package.

setDefaultTheme(Theme) => void

Sets provided Theme instance as default so all shortcuts functions now will be used upon this Theme instance. Shortcut functions could be used as well as Theme instance methods.

import { makeStyles, useStyles, createTheme, Theme, setDefaultTheme } from 'jss-theme';

// This will be called on default Theme, which is included in package
createTheme({ spacing: 1 });
const styles = makeStyles((theme) => ({
	className: {
		margin: theme.spacing * 2,
	},
}));
const classes = useStyles(styles);

// Create custom Theme and set it as default
const SomeCustomTheme = new Theme({ customProp: 'top' });
setDefaultTheme(SomeCustomTheme);

// Now shortcut function calls will be executed on SomeCustomTheme
const styles = makeStyles((theme) => ({
	className: {
		position: theme.customProp,
	},
}));
const classes = useStyles(styles);

rewriteTheme(themeConfig, options?, replacer?, theme?) => JssTheme

This will create initial default theme. This method could be called only once upon each Theme instance.

Second and third params similar to createDefaultTheme();

Last optional argument could be used to call this method on specific Theme instance:

import { createTheme, JssTheme, Theme } from 'jss-theme';

const themeConfig: JssTheme = {
	spacing: 10,
};

const SomeTheme = new Theme();

createTheme(themeConfig, null, SomeTheme); // Specific Theme
createTheme(themeConfig); // Default Theme

getTheme(theme?) => void

Gets current theme.

Optional argument could be used to call this method on specific Theme instance:

import { getTheme, Theme } from 'jss-theme';

const SomeTheme = new Theme({ spacing: 1 });

const theme = getTheme(SomeTheme) // Custom theme
const theme = getTheme() // Default theme

makeStyles(styles) => JssStyles

This is just helper function which provides correct type definitions and intellisense either calling with theme function or styles object.

import { makeStyles } from 'jss-theme';

const styles = makeStyles({
	className1: {
		display: 'flex',
		marginTop: 10,
	},
});
// or
const styles = makeStyles((theme) => ({
	className1: {
		display: 'flex',
		marginTop: theme.spacing * 2,
	},
}));

useStyles(styles, options?, theme?) => Classes

This one should be called with styles object or theme function (which could be written manually or via makeStyles method) and returns classes object, which could be used in components.

Second optional argument provides default options for creating new stylesheets.

Last optional argument could be used to call this method on specific Theme instance:

Example with Angular component:

import { Component, OnInit } from '@angular/core';
import { makeStyles, useStyles, Classes, Theme } from 'jss-theme';

@Component({
	template: `<div [class]="classes.className1">Jss styled div</div>`,
	...
})
export class SomeComponent implements OnInit {
	public classes: Classes = {};

	public ngOnInit(): void {
		const SomeTheme = new Theme({ spacing: 1 });
		const styles = makeStyles({
			className1: {
				display: 'flex',
				marginTop: 10,
			},
		});

		this.classes = useStyles(styles, null, SomeTheme); // Specific Theme
		this.classes = useStyles(styles); // Default Theme		
	}
}

updateTheme(themeConfig, options?, replacer?, theme?) => JssTheme

This method updates current theme. After theme was updated, it will detach (remove from DOM) all theme dependent stylesheets, so if using this method in component with theme dependent styles it is IMPORTANT to provide styles for creating new sheet.

Second and third params similar to createDefaultTheme();

Last optional argument could be used to call this method on specific Theme instance:

import { makeStyles, updateTheme, Theme } from 'jss-theme';

const SomeTheme = new Theme({ spacing: 1 });

...

this.classes = updateTheme({ spacing: 10 }, SomeTheme); // Specific Theme
this.classes = updateTheme({ spacing: 10 }); // Default Theme

updateDefaultOptions(options, theme?) => void

Updates default options for creating new stylesheets.

Last optional argument could be used to call this method on specific Theme instance:

import { updateDefaultOptions, Theme } from 'jss-theme';

const SomeTheme = new Theme({ spacing: 1 });

updateDefaultOptions({ ... }, SomeTheme) // Custom theme
updateDefaultOptions({ ... }) // Default theme

updateDefaultReplacer(replacer, theme?) => void

Updates default replacer for theme styles.

Last optional argument could be used to call this method on specific Theme instance:

import { updateDefaultReplacer, Theme } from 'jss-theme';

const SomeTheme = new Theme({ spacing: 1 });

// const replacer = { pattern: RegExp | string, value: string };
// or
// const replacer = [
// 	  { pattern: RegExp | string, value: string },
//	  { pattern: RegExp | string, value: string },
//	  ...
// ];

const replacer = { pattern: ':first-child', value: ':nth-child(2)' };

updateDefaultReplacer(replacer, SomeTheme) // Custom theme
updateDefaultReplacer(replacer) // Default theme

isEqualTheme(themeConfig, theme?) and hasStylesInCache(themeConfig, theme?)

Similar to Theme instance methods.

Last optional argument could be used to call this method on specific Theme instance

License

This project is licensed under the terms of the MIT license.

Dependencies (4)

Dev Dependencies (24)

Package Sidebar

Install

npm i jss-theme

Weekly Downloads

24

Version

1.1.3

License

MIT

Unpacked Size

585 kB

Total Files

5

Last publish

Collaborators

  • mopc