Created
December 6, 2016 11:31
-
-
Save gcanti/f7ccecc3cd813ba12aeb2a95f5bb2560 to your computer and use it in GitHub Desktop.
Typed style POC
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
// @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" | |
} | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment