Skip to content

Commit

Permalink
feat: add basic flow types for css and styled tags
Browse files Browse the repository at this point in the history
Now the result of the `css` tag will always be of the type string, and the result of the `styled.x` or `styled(x)` tag will be `React.ComponentType`. If the `styled(x)` tag wraps another component, the type of the props will also include the type from that component.

Limitations:

- It's not possible to type-check the interpolations currently. I have added annotations for them, but they don't work.
- It doesn't handle `defaultProps` property on the styled component, will look into it in future.
- The type annotations for tags (e.g. - `styled.div`) are broad, but React DOM [doesn't seem to type it either](https://github.com/facebook/flow/blob/master/lib/react-dom.js#L406).
  • Loading branch information
satya164 committed Oct 15, 2018
1 parent b5c37ec commit e0666be
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/core/css.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* @flow */

function css() {
throw new Error(
'Using the "css" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.'
);
}

module.exports = css;

/* ::
declare module.exports: (string[], Array<string | number | {}>) => string;
*/
40 changes: 30 additions & 10 deletions src/react/styled.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
/* @flow */

const React = require('react'); // eslint-disable-line import/no-extraneous-dependencies

function styled(tag) {
return options => {
/* ::
type Options = {
name: string,
class: string,
vars?: { [string]: [string | number | ((props: *) => string | number), string | void] }
}
*/

function styled(tag /* : React.ComponentType<*> | string */) {
return (options /* : Options */) => {
if (process.env.NODE_ENV !== 'production') {
if (Array.isArray(options)) {
// We received a strings array since it's used as a tag
Expand All @@ -11,20 +21,23 @@ function styled(tag) {
}
}

/* $FlowFixMe: Flow doesn't know about forwardRef */
const Result = React.forwardRef((props, ref) => {
const { as: component, ...rest } = props;
const { as: component = tag, ...rest } = props;
const next = Object.assign(rest, {
ref,
className: props.className
? `${options.class} ${props.className}`
: options.class,
});

if (options.vars) {
const { vars } = options;

if (vars) {
const style = {};

Object.keys(options.vars).forEach(name => {
const [value, unit = ''] = options.vars[name];
Object.keys(vars).forEach(name => {
const [value, unit = ''] = vars[name];
style[`--${name}`] = `${
typeof value === 'function' ? value(props) : value
}${unit}`;
Expand All @@ -40,10 +53,6 @@ function styled(tag) {
Result.className = options.class;
Result.extends = tag;

Result.defaultProps = {
as: tag,
};

return Result;
};
}
Expand All @@ -57,3 +66,14 @@ if (process.env.NODE_ENV !== 'production') {
} else {
module.exports = styled;
}

/* ::
type StyledComponent<T> = React.ComponentType<T & { as?: React$ElementType }>;
type StyledTag<T> = (string[], Array<string | number | {} | (T => string | number)>) => StyledComponent<T>;
declare module.exports: {|
<T>(T): StyledTag<React.ElementConfig<T>>,
[string]: StyledTag<{ children?: React.Node, [key: string]: any }>,
|};
*/

0 comments on commit e0666be

Please sign in to comment.