Last active
October 13, 2016 21:24
-
-
Save basarat/d92e8a099434415f8c7da8a9f045a5d4 to your computer and use it in GitHub Desktop.
My thin wrapper around `free-style`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @module Maintains a single stylesheet and keeps it in sync with requested styles | |
*/ | |
import * as FreeStyle from "free-style"; | |
import * as React from "react"; | |
/** Just for autocomplete convinience */ | |
export interface CSSProperties extends React.CSSProperties { | |
'&:hover'?: CSSProperties; | |
'&:active'?: CSSProperties; | |
'&:disabled'?: CSSProperties; | |
'&:focus'?: CSSProperties; | |
} | |
/** | |
* Only calls cb all sync operations settle | |
*/ | |
const {afterAllSync} = new class { | |
pending: any; | |
afterAllSync = (cb) => { | |
if (this.pending) clearTimeout(this.pending); | |
this.pending = setTimeout(cb); | |
} | |
} | |
/** | |
* We have a single stylesheet that we update as components register themselves | |
*/ | |
const freeStyle = FreeStyle.create(); | |
const singletonStyle = typeof window === 'undefined' ? { innerHTML: '' } : document.createElement('style'); | |
if (typeof document !== 'undefined') document.head.appendChild(singletonStyle as any); | |
const styleUpdated = () => afterAllSync(() => { | |
singletonStyle.innerHTML = freeStyle.getStyles(); | |
}); | |
/** | |
* Allows use to use the stylesheet in a node.js environment | |
*/ | |
export const getRawStyles = () => freeStyle.getStyles(); | |
/** | |
* Takes CSSProperties and return a generated className you can use on your component | |
*/ | |
export function style(...objects: CSSProperties[]) { | |
const object = extend(...objects); | |
const className = freeStyle.registerStyle(object); | |
styleUpdated(); | |
return className; | |
} | |
/** | |
* Takes Keyframes and returns a generated animation name | |
*/ | |
export function keyframes(frames: { | |
[key /** stuff like `from`, `to` or `10%` etc*/: string]: CSSProperties | |
}) { | |
const animationName = freeStyle.registerKeyframes(frames); | |
styleUpdated(); | |
return animationName; | |
} | |
/** | |
* Merges various styles into a single style object. | |
* Note: if two objects have the same property the last one wins | |
*/ | |
export function extend(...objects: CSSProperties[]): CSSProperties{ | |
/** The final result we will return */ | |
const result: CSSProperties = {}; | |
for (const object of objects) { | |
for (const key in object) { | |
if ( | |
// Some psuedo state or media query | |
(key.indexOf('&:') === 0 || key.indexOf('@media') === 0) | |
// And we already have something for this key | |
&& result[key] | |
) { | |
// Then extend in the final result | |
result[key] = extend(result[key], object); | |
} | |
// Otherwise just copy to output | |
else { | |
result[key] = object[key]; | |
} | |
} | |
} | |
return result; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is effectively my stylesheet | |
namespace ButtonStyles { | |
// Reusable variables | |
const color = 'red'; | |
const buttonStyles = { | |
color, | |
background: 'grey', | |
}; | |
// Classes! | |
export const buttonClass = fstyle.style(buttonStyles); | |
} | |
// Component | |
// May or may not be react! | |
const Button = ()=> <button className={ButtonStyles.buttonClass}/> | |
// Server side | |
const css = fstyle.getRawStyes(); | |
// ^ render this `css` in a style tag at will. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment