Skip to content

Instantly share code, notes, and snippets.

@at0g
Last active August 25, 2018 09:25
Show Gist options
  • Select an option

  • Save at0g/013dc05805f0fd21db5f15dd622e655a to your computer and use it in GitHub Desktop.

Select an option

Save at0g/013dc05805f0fd21db5f15dd622e655a to your computer and use it in GitHub Desktop.
Typing Fela
// @flow
// file: src/FelaComponent.js
import * as React from 'react'
import { createComponent } from 'react-fela'
// Our basic component props, without any fela guff.
type PropsType = {
children: React.Node,
color?: string
}
// Our style rules function, typed as such.
// passing PropsType ensures type checking against PropsType
const styleRules:StyleFn<PropsType> = ({ color = 'red' }) => ({
color: color,
display: 'block',
});
// The component that will be styled with fela.
// In the case of createComponent / createComponentWithProxy, a `className` prop is added by fela
// Note that `as` will probably not be set and setting a default during destructuring causes a flow error,
// hence the need to create the Component const inside the function body.
const MyComponent = ({ as, children, extend, ...props }: FelaInjectedProps<PropsType>) => {
const Component = as || 'div'
return (
<Component {...props}>
{children}
</Component>
)
};
// The "finished" component, with styles attached.
const StyledComponent: FelaComponent<PropsType> = createComponent(styleRules, MyComponent)
export default StyledComponent
// @flow
import * as React from 'react'
import { connect } from 'react-fela'
import ChildComponent from './FelaComponent'
type PropTypes = {
title: React.Node,
subTitle?: React.Node,
children: React.Node,
}
const styleRules:StyleFn<PropTypes> = ({ subTitle }) => ({
title: {
borderLeft: '1em solid papayawhip',
color: 'papayawhip',
textIndent: '20px',
...(() => {
if (subTitle) {
return {
marginBottom: 0,
}
}
return {}
})()
},
subTitle: {
backgroundColor: 'papayawhip',
color: 'rebeccapurple',
marginTop: 0
}
})
const MyComponent = ({ as, children, styles, subTitle, title }: FelaInjectedConnectProps<PropTypes>) => {
const Component = as || 'section'
return (
<Component>
<header>
<ChildComponent as="h1">{title}</ChildComponent>
{!!subTitle && (
<React.Fragment>
<hr key="hr" />
<ChildComponent as="h2" key="subTitle">{subTitle}</ChildComponent>
</React.Fragment>
)}
</header>
{children}
</Component>
)
}
const StyledComponent:FelaConnectComponent<PropTypes> = connect(styleRules)(MyComponent)
export default StyledComponent
// file: flow-typed/react-fela.js
// Ensure flow@~0.69.0 is installed due to an issue with later versions:
// @see: https://github.com/facebook/flow/issues/6284
import * as React from 'react'
/**
* The function that is called to generate the styles for this component.
* If a theme is being used, it is merged with the components props as a `theme` property.
* The merged props are provided as the first argument, and the fela renderer as the second.
*/
declare type StyleFn<PropsType> = (
props: FelaExpectedProps<PropsType> & { theme: {} },
renderer: {}
) => FelaRuleType
/**
* The props that are injected into a component that has been decorated by fela.
*/
declare type FelaInjectedProps<PropsType: {}> =
PropsType & {
as?: string | React.ComponentType<*>,
className: string,
extend: StyleFn<PropsType>
}
/**
* When using { connect }, the injected props are very similar to { createComponent* }, with the following differences:
* - instead of a single className, each key from the styleRules function will become a key in the styles prop, just
* like a css module.
* - a new rules prop is injected. Each key from the styleRules function will be a key in rules, the value being a
* function used to generate css rules. Useful when extending an internal component as the applicable rules can be
* further extended from the outside.
*/
declare type FelaInjectedConnectProps<PropsType: {}> =
$Diff<FelaInjectedProps<PropsType>, { className?: string }> & {
+rules: {
[key: string]: StyleFn<PropsType>
},
+styles: {
[key: string]: string
}
}
/**
* The return type of a component created with createComponent or createComponentWithProxy
*/
declare type FelaComponent<PropsType: {}> =
React.ComponentType<FelaExpectedProps<PropsType>>
declare type FelaConnectComponent<PropsType: {}> = React.ComponentType<FelaExpectedProps<PropsType>>
/**
* Basic style rule.
* example: { color: 'red', margin: 0 }
* example: {
* color: 'red',
* ':hover': {
* color: 'blue',
* ':after': { display: 'none' }
* }
* }
*/
type FelaRuleType = {
[key: string]: string
| number
| FelaRuleType
}
/**
* The outward props that expected to the component.
* Fela makes as, className and extend all optional props
* when creating the node
*/
declare type FelaExpectedProps<PropsType: {}> =
PropsType & {
as?: string | React.ComponentType<PropsType>,
className?: string,
extend?: StyleFn<PropsType>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment