Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[react-jss] Add flow typings #818

Merged
merged 27 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b4b0523
First commit
gomesalexandre Aug 7, 2018
e008910
Fixes on createHOC and injectSheet
gomesalexandre Aug 8, 2018
bd5348a
More fixes on createHOC and injectSheet
gomesalexandre Aug 8, 2018
887652f
Better flow typings on createHOC
gomesalexandre Aug 10, 2018
3954fc5
Moved types/index.js just to types.js and added InnerProps and OuterP…
Aug 11, 2018
a7cca18
Simplified typings of injectSheet.js
Aug 11, 2018
b379272
Updated and fixed some typings in createHOC.js
Aug 11, 2018
b1fb062
Removed unnecessary types in ns.js
Aug 12, 2018
1d69fce
Added flow flag to some untyped files
Aug 12, 2018
0c07422
Exporting StyleSheetFactoryOptions now instead of StyleSheetOptions
Aug 12, 2018
386f2e5
Fix typing of getDisplayName
Aug 12, 2018
839e1ae
Added Context Type and updated Options to use StyleSheetFactoryOption…
Aug 12, 2018
fccbbf0
Moved types/index.js just to types.js and added
Aug 12, 2018
5f1c1e8
Improved Context Type
Aug 12, 2018
d867aa2
Updated createHoc to use Context type
Aug 12, 2018
539c3ed
Improved typing of the Theming option
Aug 12, 2018
bacb6bd
Formatted code with prettier
Aug 12, 2018
2b86b8d
Updated size snapshot and lockfile
Aug 12, 2018
ecdf147
Make options in injectSheet optional an default it to an empty object
Aug 12, 2018
4c16374
Fixed types of the JssProvider props
Aug 12, 2018
3ad6097
Remove semi eslint rule
Aug 12, 2018
1a803f9
Removed unnecessary types
Aug 14, 2018
44d7dd5
Remove unnecessary check
Aug 14, 2018
9da04d3
Updated a if statement and fixed removing dynamic sheet from global r…
Aug 14, 2018
3d7d984
Fixed naming of some type names to always start with an uppercase char
Aug 15, 2018
fcd4345
Renamed generic types of createHOC
Aug 15, 2018
629d9f5
Merge branch 'master' into react-jss-flow-typings
Aug 15, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,548 changes: 2,774 additions & 2,774 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/jss/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {JssOptions} from './types'
* Export types for better typing inside plugins and integrations.
*/
export type {
StyleSheetOptions,
StyleSheetFactoryOptions,
JssValue,
JssOptions,
JssStyle,
Expand Down
28 changes: 14 additions & 14 deletions packages/react-jss/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"dist/react-jss.js": {
"bundled": 236824,
"minified": 65331,
"gzipped": 17972
"bundled": 237551,
"minified": 65553,
"gzipped": 18041
},
"dist/react-jss.min.js": {
"bundled": 201522,
"minified": 55978,
"gzipped": 15787
"bundled": 202242,
"minified": 56196,
"gzipped": 15853
},
"dist/react-jss.cjs.js": {
"bundled": 17646,
"minified": 7319,
"gzipped": 2579
"bundled": 18288,
"minified": 7484,
"gzipped": 2645
},
"dist/react-jss.esm.js": {
"bundled": 17160,
"minified": 6889,
"gzipped": 2485,
"bundled": 17802,
"minified": 7054,
"gzipped": 2548,
"treeshaked": {
"rollup": {
"code": 1908,
"code": 2057,
"import_statements": 214
},
"webpack": {
"code": 3079
"code": 3228
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions packages/react-jss/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 22 additions & 4 deletions packages/react-jss/src/JssProvider.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import {Component, Children} from 'react'
// @flow
import {Component, Children, type Element, type ElementType} from 'react'
import PropTypes from 'prop-types'
import type {Jss, generateClassName as GenerateClassNameType, SheetsRegistry} from 'jss'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why mapping from lower case to capital?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh, I think we need to rename it to upper case in the core package in the first place

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once it starts uppercase you don't need to add Type suffix either

import {createGenerateClassNameDefault} from './jss'
import * as ns from './ns'
import contextTypes from './contextTypes'
import propTypes from './propTypes'
import type {Context} from './types'

export default class JssProvider extends Component {
type Props = {
jss?: Jss,
registry?: SheetsRegistry,
generateClassName?: GenerateClassNameType,
classNamePrefix?: string,
disableStylesGeneration?: boolean,
children: Element<ElementType>
}

export default class JssProvider extends Component<Props> {
static propTypes = {
...propTypes,
generateClassName: PropTypes.func,
Expand All @@ -22,7 +34,7 @@ export default class JssProvider extends Component {
// 1. Check if there is a value passed over props.
// 2. If value was passed, we set it on the child context.
// 3. If value was not passed, we proxy parent context (default context behaviour).
getChildContext() {
getChildContext(): Context {
const {
registry,
classNamePrefix,
Expand All @@ -31,7 +43,7 @@ export default class JssProvider extends Component {
disableStylesGeneration
} = this.props
const sheetOptions = this.context[ns.sheetOptions] || {}
const context = {[ns.sheetOptions]: sheetOptions}
const context: Context = {[ns.sheetOptions]: sheetOptions}

if (registry) {
context[ns.sheetsRegistry] = registry
Expand Down Expand Up @@ -73,6 +85,12 @@ export default class JssProvider extends Component {
return context
}

registry: SheetsRegistry

managers: {}

generateClassName: GenerateClassNameType

render() {
return Children.only(this.props.children)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/react-jss/src/compose.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @flow
import type {Classes} from 'jss'
/**
* Adds `composes` property to each top level rule
* in order to have a composed class name for dynamic style sheets.
Expand All @@ -21,7 +23,7 @@
* @param {Object} styles dynamic styles object without static properties
* @return {Object|null}
*/
export default (staticClasses, dynamicClasses) => {
export default (staticClasses: Classes, dynamicClasses: Classes) => {
const combinedClasses = {...staticClasses}

for (const name in dynamicClasses) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-jss/src/contextTypes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @flow
import PropTypes from 'prop-types'
import * as ns from './ns'
import propTypes from './propTypes'
Expand Down
72 changes: 53 additions & 19 deletions packages/react-jss/src/createHoc.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import React, {Component} from 'react'
// @flow
import React, {Component, type ComponentType} from 'react'
import PropTypes from 'prop-types'
import defaultTheming from 'theming'
import type {StyleSheet} from 'jss'
import jss, {getDynamicStyles, SheetsManager} from './jss'
import compose from './compose'
import getDisplayName from './getDisplayName'
import * as ns from './ns'
import contextTypes from './contextTypes'
import type {
Options,
Theme,
StylesOrThemer,
InnerProps,
OuterProps,
Context,
SubscriptionId
} from './types'

const env = process.env.NODE_ENV

Expand All @@ -32,7 +43,18 @@ const dynamicStylesNs = Math.random()
*
*/

const getStyles = (stylesOrCreator, theme) => {
type InjectedProps = {
classes?: {},
theme?: Theme,
sheet?: {}
}
type State = {
theme: Theme,
dynamicSheet?: StyleSheet,
classes: {}
}

const getStyles = (stylesOrCreator: StylesOrThemer, theme: Theme) => {
if (typeof stylesOrCreator !== 'function') {
return stylesOrCreator
}
Expand All @@ -57,60 +79,68 @@ let managersCounter = 0
/**
* Wrap a Component into a JSS Container Component.
*
* IProps: Props of the InnerComponent.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InnerProps would be probably a better name, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already using InnerProps though, that's why I had to name it IProps 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets find a better convention, maybe InnerPropsType?

* OProps: The Outer props the HOC accepts.
*
* @param {Object|Function} stylesOrCreator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove those jsdoc comments now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do some cleanup in another PR. Have some small fixes etc. in mind

* @param {Component} InnerComponent
* @param {Object} [options]
* @return {Component}
*/
export default (stylesOrCreator, InnerComponent, options = {}) => {
export default function createHOC<
IProps: InnerProps,
C: ComponentType<IProps>,
OProps: OuterProps<IProps, C>
>(stylesOrCreator: StylesOrThemer, InnerComponent: C, options: Options): ComponentType<OProps> {
const isThemingEnabled = typeof stylesOrCreator === 'function'
const {theming = defaultTheming, inject, jss: optionsJss, ...sheetOptions} = options
const injectMap = inject ? toMap(inject) : defaultInjectProps
const {themeListener} = theming
const displayName = getDisplayName(InnerComponent)
const defaultClassNamePrefix = env === 'production' ? undefined : `${displayName}-`
const defaultClassNamePrefix = env === 'production' ? '' : `${displayName}-`
const noTheme = {}
const managerId = managersCounter++
const manager = new SheetsManager()
const defaultProps = {...InnerComponent.defaultProps}
// $FlowFixMe defaultProps are not defined in React$Component
const defaultProps: InjectedProps = {...InnerComponent.defaultProps}
delete defaultProps.classes

class Jss extends Component {
class Jss extends Component<OProps, State> {
static displayName = `Jss(${displayName})`
static InnerComponent = InnerComponent
static contextTypes = {
...contextTypes,
...(isThemingEnabled && themeListener.contextTypes)
...(isThemingEnabled ? themeListener.contextTypes : {})
}
static propTypes = {
innerRef: PropTypes.func
}
static defaultProps = defaultProps

constructor(props, context) {
constructor(props: OProps, context: Context) {
super(props, context)
const theme = isThemingEnabled ? themeListener.initial(context) : noTheme

this.state = this.createState({theme}, props)
this.state = this.createState({theme, classes: {}}, props)
}

componentWillMount() {
this.manage(this.state)
}

componentDidMount() {
if (isThemingEnabled) {
if (themeListener && isThemingEnabled) {
this.unsubscribeId = themeListener.subscribe(this.context, this.setTheme)
}
}

componentWillReceiveProps(nextProps, nextContext) {
componentWillReceiveProps(nextProps: OProps, nextContext: Context) {
this.context = nextContext
const {dynamicSheet} = this.state
if (dynamicSheet) dynamicSheet.update(nextProps)
}

componentWillUpdate(nextProps, nextState) {
componentWillUpdate(nextProps: OProps, nextState: State) {
if (isThemingEnabled && this.state.theme !== nextState.theme) {
const newState = this.createState(nextState, nextProps)
this.manage(newState)
Expand All @@ -119,15 +149,15 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {
}
}

componentDidUpdate(prevProps, prevState) {
componentDidUpdate(prevProps: OProps, prevState: State) {
// We remove previous dynamicSheet only after new one was created to avoid FOUC.
if (prevState.dynamicSheet !== this.state.dynamicSheet && prevState.dynamicSheet) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& prevState.dynamicSheet should not be removed!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same diff reason, fixed

this.jss.removeStyleSheet(prevState.dynamicSheet)
}
}

componentWillUnmount() {
if (this.unsubscribeId) {
if (themeListener && this.unsubscribeId) {
themeListener.unsubscribe(this.context, this.unsubscribeId)
}

Expand All @@ -137,9 +167,11 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {
}
}

setTheme = theme => this.setState({theme})
setTheme = (theme: Theme) => this.setState({theme})
unsubscribeId: SubscriptionId
context: Context

createState({theme, dynamicSheet}, {classes: userClasses}) {
createState({theme, dynamicSheet}: State, {classes: userClasses}): State {
const contextSheetOptions = this.context[ns.sheetOptions]
if (contextSheetOptions && contextSheetOptions.disableStylesGeneration) {
return {theme, dynamicSheet, classes: {}}
Expand All @@ -161,9 +193,11 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {
classNamePrefix
})
this.manager.add(theme, staticSheet)
// $FlowFixMe Cannot add random fields to instance of class StyleSheet
staticSheet[dynamicStylesNs] = getDynamicStyles(styles)
}

// $FlowFixMe Cannot access random fields on instance of class StyleSheet
const dynamicStyles = staticSheet[dynamicStylesNs]

if (dynamicStyles) {
Expand All @@ -176,6 +210,7 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {
})
}

// $FlowFixMe InnerComponent can be class or stateless, the latter doesn't have a defaultProps property
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may have defaultProps property same way as class based

Copy link
Member

@HenriBeck HenriBeck Aug 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah but flow doesn't have defaultProps typed on the class nor the functional component https://github.com/facebook/flow/blob/master/lib/react.js#L99

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird, we should look for an issue there for explanation or raise one .... really weird

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explanation is in the comment above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol ... my day is over :)

const defaultClasses = InnerComponent.defaultProps
? InnerComponent.defaultProps.classes
: undefined
Expand All @@ -194,7 +229,7 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {
return {theme, dynamicSheet, classes}
}

manage({theme, dynamicSheet}) {
manage({theme, dynamicSheet}: State) {
const contextSheetOptions = this.context[ns.sheetOptions]
if (contextSheetOptions && contextSheetOptions.disableStylesGeneration) {
return
Expand Down Expand Up @@ -231,8 +266,7 @@ export default (stylesOrCreator, InnerComponent, options = {}) => {

render() {
const {theme, dynamicSheet, classes} = this.state
const {innerRef, ...props} = this.props

const {innerRef, ...props}: OProps = this.props
const sheet = dynamicSheet || this.manager.get(theme)

if (injectMap.sheet && !props.sheet) props.sheet = sheet
Expand Down
6 changes: 5 additions & 1 deletion packages/react-jss/src/getDisplayName.js
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export default Component => Component.displayName || Component.name || 'Component'
// @flow
import type {ComponentType} from 'react'

export default <P>(Component: ComponentType<P>) =>
Component.displayName || Component.name || 'Component'
1 change: 1 addition & 0 deletions packages/react-jss/src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @flow
export {ThemeProvider, withTheme, createTheming} from 'theming'
export {default as JssProvider} from './JssProvider'
export {
Expand Down
Loading