Created
December 6, 2016 11:31
-
-
Save gcanti/f7ccecc3cd813ba12aeb2a95f5bb2560 to your computer and use it in GitHub Desktop.
Revisions
-
gcanti created this gist
Dec 6, 2016 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,102 @@ // @flow // // library agnostic types and helpers // // keep private class Unit<A> {} class IsMedia {} export type Px = string & Unit<'pixel'>; export type Percentage = string & Unit<'percentage'>; export type Media = string & IsMedia; export const px = (x: number): Px => ((`${x}px`: any): Px) export const percentage = (x: number): Percentage => ((`${x}%`: any): Percentage) // other unit factories here... export const media = (options: { minHeight?: Px }): Media => { const constraints = [] if (options.minHeight) { constraints.push(`minHeight: ${options.minHeight}`) } // other constraints here... return ((`@media (${constraints.join(' and ')})`: any): Media) } // the official $Exact doesn't play well with Pseudo type type Exact<A> = A & $Shape<A>; export type Own = Exact<{ fontSize?: Px, lineHeight?: Px | number // other rules here... }>; export type Pseudo = Exact<{ ':hover'?: Own // other pseudos here... }>; // I need an array here because computed properties are bugged // https://github.com/facebook/flow/issues/2928 // when fixed we could define type Medias = { [key: Media]: Exact<{ style?: Own, pseudo?: Pseudo }> } export type Medias = Array<[Media, Exact<{ style?: Own, pseudo?: Pseudo }>]>; // // adapter example // // this function is library specific, one for styled-components, one for fela, etc... // and returns a library specific domain model, perhaps a string or an // internal representation for styled-components, an object for fela, etc... function css(style: Own, pseudos: Pseudo, medias: Medias) { return Object.assign({}, style, pseudos, getMedias(medias)) } function getMedias(medias?: Medias): ?Object { if (medias) { const o = {} medias.forEach(([m, s]) => o[m] = s) return o } return null } // // usage // const style = css({ fontSize: px(30) // fontSize: 'a' // <= error // fontSize: 30 // <= error // fontsize: 1 / <= error }, { ':hover': { fontSize: px(50) } }, [ [media({ minHeight: px(300) }), { style: { fontSize: px(60) } }] ]) console.log(JSON.stringify(style, null, 2)) /* Output: { "fontSize": "30px", ":hover": { "fontSize": "50px" }, "@media (minHeight: 300px)": { "fontSize": "60px" } } */