Skip to content

Commit

Permalink
Add media query support
Browse files Browse the repository at this point in the history
  • Loading branch information
hennessyevan committed Apr 29, 2019
1 parent 2ecbe93 commit 49e0f10
Show file tree
Hide file tree
Showing 44 changed files with 811 additions and 1,041 deletions.
7 changes: 5 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"presets": ["@babel/env", "@babel/react"],
"plugins": ["@babel/plugin-proposal-class-properties"]
"presets": ["@babel/env", "@babel/react"],
"plugins": [
"@babel/plugin-proposal-class-properties",
["emotion", { "autoLabel": false }]
]
}
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"singleQuote": true
"singleQuote": true,
"semi": false
}
1 change: 1 addition & 0 deletions .storybook/addons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@storybook/addon-viewport/register'
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"dependencies": {
"@emotion/core": "^10.0.10",
"@emotion/hash": "^0.7.1",
"facepaint": "^1.2.1",
"inline-style-prefixer": "^5.0.1",
"prop-types": "^15.6.0"
},
Expand All @@ -44,6 +45,7 @@
"@babel/preset-env": "^7.4.4",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.4.4",
"@storybook/addon-viewport": "^5.0.11",
"@storybook/react": "^5.0.0",
"@storybook/storybook-deployer": "^2.2.0",
"@types/enzyme": "^3.1.15",
Expand All @@ -57,6 +59,7 @@
"awesome-typescript-loader": "^5.2.1",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.4",
"babel-plugin-emotion": "^10.0.9",
"csstype": "^2.6.0",
"emotion-jsxstyle": "^1.2.0",
"enzyme": "^3.4.1",
Expand Down
16 changes: 11 additions & 5 deletions src/box-types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {ReactNode, Component} from 'react'
import * as CSS from 'csstype'
import { BoxSizingProperty, Properties } from 'csstype'
import { Component, ReactNode } from 'react'

type UIBoxProp = string | number | boolean | null | undefined
export type CSSProps = CSS.StandardProperties<number | string | boolean>
export type Falsey<T> = { [P in keyof T]?: T[P] | T[P][] | false | null }
interface BoxPropsAugmented
extends Falsey<
Properties<string | number | boolean | string[] | number[] | boolean[]>
> {}

interface BoxPropsBase extends CSSProps {
interface BoxPropsBase extends BoxPropsAugmented {
is?: string | React.ComponentClass | React.FunctionComponent

className?: string

breakpoints?: string[]

marginX?: UIBoxProp

marginY?: UIBoxProp
Expand All @@ -29,7 +35,7 @@ interface BoxPropsBase extends CSSProps {
}

export type BoxProps = BoxPropsBase & {
boxSizing?: CSS.BoxSizingProperty | UIBoxProp;
boxSizing?: BoxSizingProperty | UIBoxProp
}

export type Box = Component<BoxProps>
54 changes: 34 additions & 20 deletions src/box.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,54 @@
import { css as ecss } from '@emotion/core';
import * as React from 'react';
import { BoxProps } from './box-types';
import enhanceProps from './enhance-props';
import { ClassNames } from '@emotion/core'
import facepaint from 'facepaint'
import * as React from 'react'
import { BoxProps } from './box-types'
import enhanceProps from './enhance-props'
import { MediaQueryConsumer } from './media-query-context'

class Box extends React.Component<BoxProps, {}> {
static defaultProps = {
css: null,
innerRef: null,
is: 'div',
boxSizing: 'border-box'
};
}

ref = React.createRef();
ref = React.createRef()

render() {
const { is = 'div', css, innerRef, children, ...props } = this.props;
const { is = 'div', css, innerRef, children, ...props } = this.props
// Convert the CSS props to class names (and inject the styles)
const { className, enhancedProps: parsedProps } = enhanceProps(props);

// Add glamor class
if (css) {
parsedProps.className = `${className} ${ecss(css).toString()}`;
} else {
parsedProps.className = className;
}
const { className, enhancedProps: parsedProps, mqCSS } = enhanceProps(props)

if (innerRef) {
parsedProps.ref = (node: React.ReactNode) => {
innerRef(node);
};
innerRef(node)
}

parsedProps.ref = this.ref;
parsedProps.ref = this.ref
}

return React.createElement(is, parsedProps, children);
if (Object.keys(mqCSS).length > 0) {
const mergedCSS = { ...css, ...mqCSS }
// Add emotion class
return React.createElement(
MediaQueryConsumer,
null,
(breakpoints: string[]) => {
const mq = facepaint(breakpoints)

return React.createElement(ClassNames, null, ({ css: ecss, cx }) =>
React.createElement(
is,
{ className: cx(className, ecss(mq(mergedCSS))), ...parsedProps },
children
)
)
}
)
}
return React.createElement(is, parsedProps, children)
}
}

export default Box;
export default Box
39 changes: 23 additions & 16 deletions src/cache.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
export type CacheValue = string | number | boolean | object;
let cache = new Map<string, CacheValue>();
export type CacheValue = string | number | boolean | object
let cache = new Map<string, CacheValue>()

export function get(property: string, value: CacheValue) {
return cache.get(property + value);
export function get(
property: string,
value: CacheValue
): CacheValue | undefined {
return cache.get(property + value)
}

export function set(property: string, value: CacheValue, className: string) {
export function set(
property: string,
value: CacheValue,
className: string
): void {
if (process.env.NODE_ENV !== 'production') {
const valueType = typeof value;
const valueType = typeof value
if (
valueType !== 'boolean' &&
valueType !== 'number' &&
valueType !== 'string'
) {
const encodedValue = JSON.stringify(value);
const encodedValue = JSON.stringify(value)
throw new TypeError(
`al- aluminum-box: invalid cache value “${encodedValue}”. Only booleans, numbers and strings are supported.`
);
)
}
}

cache.set(property + value, className);
cache.set(property + value, className)
}

export function entries() {
return [...cache];
export function entries(): [string, CacheValue][] {
return [...cache]
}

type CacheEntry = [string, CacheValue];
export function hydrate(newEntries: CacheEntry[]) {
cache = new Map<string, CacheValue>([...cache, ...newEntries]);
type CacheEntry = [string, CacheValue]
export function hydrate(newEntries: CacheEntry[]): void {
cache = new Map<string, CacheValue>([...cache, ...newEntries])
}

export function clear() {
cache.clear();
export function clear(): void {
cache.clear()
}
19 changes: 14 additions & 5 deletions src/enhance-props.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import {propEnhancers} from './enhancers'
import expandAliases from './expand-aliases'
import { BoxProps } from './box-types'
import * as cache from './cache'
import { propEnhancers } from './enhancers'
import expandAliases from './expand-aliases'
import * as styles from './styles'
import {BoxProps} from './box-types'

interface EnhancedPropsResult {
mqCSS: Partial<BoxProps>
className: string
enhancedProps: Partial<BoxProps>
}
/**
* Converts the CSS props to class names and inserts the styles.
*/
export default function enhanceProps(rawProps: Partial<BoxProps>): EnhancedPropsResult {
export default function enhanceProps(
rawProps: Partial<BoxProps>
): EnhancedPropsResult {
const propsMap = expandAliases(rawProps)
const enhancedProps = {}
const mqCSS = {}
let className = rawProps.className || ''

for (const [propName, propValue] of propsMap) {
if (Array.isArray(propValue)) {
mqCSS[propName] = propValue
continue
}

const cachedClassName = cache.get(propName, propValue)
if (cachedClassName) {
className = `${className} ${cachedClassName}`
Expand Down Expand Up @@ -50,5 +59,5 @@ export default function enhanceProps(rawProps: Partial<BoxProps>): EnhancedProps

className = className.trim()

return {className, enhancedProps}
return { className, enhancedProps, mqCSS }
}
54 changes: 29 additions & 25 deletions src/enhancers/background.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as PropTypes from 'prop-types'
import getCss from '../get-css'
import {PropEncharValueType as ValueType} from './types'
import * as PropTypes from 'prop-types';
import getCss, { GetCSS } from '../get-css';
import { PropEncharValueType as ValueType } from './types';

export const propTypes = {
background: PropTypes.string,
Expand All @@ -12,70 +12,74 @@ export const propTypes = {
backgroundPosition: PropTypes.string,
backgroundRepeat: PropTypes.string,
backgroundSize: PropTypes.string
}
};

export const propAliases = {}
export const propAliases = {};

export const propValidators = {}
export const propValidators = {};

const background = {
className: 'bg',
cssName: 'background',
jsName: 'background',
isPrefixed: true,
complexValue: true
}
};
const backgroundColor = {
className: 'bg-clr',
cssName: 'background-color',
jsName: 'backgroundColor'
}
};
const backgroundImage = {
className: 'bg-img',
cssName: 'background-image',
jsName: 'backgroundImage',
isPrefixed: true,
complexValue: true
}
};
const backgroundPosition = {
className: 'bg-pos',
cssName: 'background-position',
jsName: 'backgroundPosition'
}
};
const backgroundSize = {
className: 'bg-siz',
cssName: 'background-size',
jsName: 'backgroundSize'
}
};
const backgroundOrigin = {
className: 'bg-orgn',
cssName: 'background-origin',
jsName: 'backgroundOrigin'
}
};
const backgroundRepeat = {
className: 'bg-rpt',
cssName: 'background-repeat',
jsName: 'backgroundRepeat'
}
};
const backgroundClip = {
className: 'bg-clp',
cssName: 'background-clip',
jsName: 'backgroundClip'
}
};
const backgroundBlendMode = {
className: 'bg-blnd-md',
cssName: 'background-blend-mode',
jsName: 'backgroundBlendMode'
}
};

export const propEnhancers = {
background: (value: ValueType) => getCss(background, value),
backgroundBlendMode: (value: ValueType) => getCss(backgroundBlendMode, value),
backgroundClip: (value: ValueType) => getCss(backgroundClip, value),
backgroundColor: (value: ValueType) => getCss(backgroundColor, value),
backgroundImage: (value: ValueType) => getCss(backgroundImage, value),
backgroundOrigin: (value: ValueType) => getCss(backgroundOrigin, value),
backgroundPosition: (value: ValueType) => getCss(backgroundPosition, value),
backgroundRepeat: (value: ValueType) => getCss(backgroundRepeat, value),
backgroundSize: (value: ValueType) => getCss(backgroundSize, value)
}
background: (value: ValueType): GetCSS => getCss(background, value),
backgroundBlendMode: (value: ValueType): GetCSS =>
getCss(backgroundBlendMode, value),
backgroundClip: (value: ValueType): GetCSS => getCss(backgroundClip, value),
backgroundColor: (value: ValueType): GetCSS => getCss(backgroundColor, value),
backgroundImage: (value: ValueType): GetCSS => getCss(backgroundImage, value),
backgroundOrigin: (value: ValueType): GetCSS =>
getCss(backgroundOrigin, value),
backgroundPosition: (value: ValueType): GetCSS =>
getCss(backgroundPosition, value),
backgroundRepeat: (value: ValueType): GetCSS =>
getCss(backgroundRepeat, value),
backgroundSize: (value: ValueType): GetCSS => getCss(backgroundSize, value)
};
Loading

0 comments on commit 49e0f10

Please sign in to comment.