primer-react
Version:
Primer react components
164 lines (145 loc) • 3.81 kB
JavaScript
import React from 'react'
import {style} from 'styled-system'
import system from 'system-components/emotion'
import {default as defaultTheme} from './theme'
export {system as default}
export const COMMON = ['color', 'space']
export const TYPOGRAPHY = COMMON.concat(
// typography props
'fontFamily',
'fontSize',
'fontWeight',
'lineHeight'
)
export const LAYOUT = COMMON.concat(
// layout props
'borders',
'borderColor',
'borderRadius',
'boxShadow',
'display',
'size',
'width',
'height',
'minWidth',
'minHeight',
'maxWidth',
'maxHeight',
'verticalAlign'
)
export const POSITION = [
// position props
'position',
'zIndex',
'top',
'right',
'bottom',
'left'
]
export const FLEX_CONTAINER = LAYOUT.concat(
// flex container props (display: flex)
'alignContent',
'alignItems',
'flexWrap',
'flex',
'flexBasis',
'flexDirection',
'justifyContent',
'order'
)
export const FLEX_ITEM = LAYOUT.concat(
// flex container child props
'justifySelf',
'alignSelf'
)
/**
* Defensively determine whether a component function or class is a "system
* component" by checking its `systemComponent` flag or whether its
* `defaultProps.blacklist` is an array.
*/
export function isSystemComponent(Component) {
return (
Component.systemComponent === true || (Component.defaultProps && Array.isArray(Component.defaultProps.blacklist))
)
}
/**
* Create a "system component" with the named props from styled-system.
* The Component (first) argument can either be a React component (a function
* or a class) or an object representing default props. To pass a custom
* component with other default props, set the object's `is` key to the
* component:
*
* ```js
* const Wrapped = withSystemProps({is: Component, m: 2})
* ```
*
* which is the equivalent of:
*
* ```js
* const Wrapped = withSystemProps(Component)
* Wrapped.defaultProps = {
* m: 2
* }
* ```
*/
export function withSystemProps(Component, props = COMMON) {
if (isSystemComponent(Component)) {
throw new Error(`${Component.name} is already a system component; can't call withSystemProps() on it`)
}
const component = typeof Component === 'object' ? Component : {is: Component}
if (typeof component.is === 'function') {
component.is = guardDoubleRender(component.is)
}
const Wrapped = system(component, ...props)
Wrapped.displayName = Component.displayName
Object.assign(Wrapped.propTypes, Component.propTypes)
// Set what system props we use on this component
Wrapped.systemProps = props
Wrapped.systemComponent = true
// Copy over non-system keys from components
// eg. Tooltip.js => Tooltip.directions Tooltip.alignments
for (const key of Object.keys(Component)) {
if (!Wrapped.hasOwnProperty(key)) {
Wrapped[key] = Component[key]
}
}
return withDefaultTheme(Wrapped)
}
/**
* Set the component's defaultProps.theme to our theme, and returns the
* component.
*/
export function withDefaultTheme(Component, theme = defaultTheme) {
if (Component.defaultProps) {
Component.defaultProps.theme = theme
} else {
Component.defaultProps = {theme}
}
return Component
}
/**
* Remove the named keys from a component's propTypes object (if present), and
* return the component.
*/
export function withoutPropTypes(Component, props) {
for (const prop of props) {
delete Component.propTypes[prop]
}
return Component
}
export const listStyle = style({
prop: 'listStyle',
cssProperty: 'list-style',
key: 'listStyles'
})
function guardDoubleRender(Component) {
function render(props) {
const {is, ...rest} = props
if (is === Component || is === render) {
return <Component {...rest} />
} else {
return <Component {...props} />
}
}
return render
}