-
Notifications
You must be signed in to change notification settings - Fork 360
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add VerticalNavigation, Masthead, Item, and related components
- Loading branch information
Showing
29 changed files
with
3,572 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ node_modules | |
npm-debug.log | ||
dist | ||
.out | ||
.DS_Store | ||
|
||
# IDEs and editors | ||
/.idea | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { nullValues, bindMethods, selectKeys, filterKeys } from './helpers'; | ||
|
||
/* | ||
controlled(stateTypes, defaults)(WrappedComponent) | ||
This Higher Order Component provides the controlled component pattern on a prop-by-prop basis. | ||
It's a nice way for components to implement internal state so they "just work" out of the box, | ||
but also give users the option of lifting some or all of that state up into their application. | ||
controlled() takes arguments as an object with three options: | ||
* types - an object of PropTypes for the state that will be contained here | ||
* defaults - an optional object with default values for stateTypes | ||
* persist - an optional array of names from stateTypes which will be persisted to sessionStorage | ||
The WrappedComponent will be rendered with special props: | ||
* setControlledState - a reference to this state wrapper's this.setState. | ||
* Props for all the stateTypes, from this.props if present or from this.state otherwise. | ||
* All other props passed to the controlled component HoC. | ||
The idea is that the values in stateTypes could be stored in state, or passed in via props. | ||
The WrappedComponent doesn't have to care which is being used, and can manage the state | ||
contained here. When present, props are used instead. If you provide these special props, | ||
be sure to also provide corresponding callbacks/handlers to keep them updated. | ||
If you are using the persist option, you can optionally pass a sessionKey prop to the component | ||
to ensure multiple instances of the component store their data separately. If you don't pass | ||
a sessionKey, a stringified list of the persisted keys will be used (not unique to the instance). | ||
*/ | ||
const controlled = ({ types, defaults = {}, persist }) => WrappedComponent => { | ||
class ControlledComponent extends React.Component { | ||
constructor() { | ||
super(); | ||
this.state = { ...nullValues(types), ...defaults }; | ||
bindMethods(this, [ | ||
'sessionKey', | ||
'savePersistent', | ||
'loadPersistent', | ||
'setControlledState' | ||
]); | ||
} | ||
|
||
componentDidMount() { | ||
this.loadPersistent(); | ||
window && | ||
window.addEventListener && | ||
window.addEventListener('beforeunload', this.savePersistent); | ||
} | ||
|
||
componentWillUnmount() { | ||
this.savePersistent(); | ||
window && | ||
window.removeEventListener && | ||
window.removeEventListener('beforeunload', this.savePersistent); | ||
} | ||
|
||
sessionKey() { | ||
return this.props.sessionKey || JSON.stringify(persist); | ||
} | ||
|
||
savePersistent() { | ||
if (persist && persist.length > 0) { | ||
const toPersist = selectKeys(this.state, persist); | ||
window && | ||
window.sessionStorage && | ||
window.sessionStorage.setItem( | ||
this.sessionKey(), | ||
JSON.stringify(toPersist) | ||
); | ||
} | ||
} | ||
|
||
loadPersistent() { | ||
if (persist && persist.length > 0) { | ||
const fromPersisted = | ||
window && | ||
window.sessionStorage && | ||
window.sessionStorage.getItem(this.sessionKey()); | ||
fromPersisted && this.setState(JSON.parse(fromPersisted)); | ||
} | ||
} | ||
|
||
setControlledState(updater) { | ||
this.setState(updater); | ||
} | ||
|
||
render() { | ||
const controlledStateProps = filterKeys( | ||
this.props, | ||
key => types.hasOwnProperty(key) && this.props[key] !== null | ||
); | ||
const otherProps = filterKeys( | ||
this.props, | ||
key => !types.hasOwnProperty(key) | ||
); | ||
return ( | ||
<WrappedComponent | ||
setControlledState={this.setControlledState} | ||
{...this.state} | ||
{...controlledStateProps} | ||
{...otherProps} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
ControlledComponent.displayName = WrappedComponent.displayName; | ||
ControlledComponent.propTypes = { | ||
...WrappedComponent.propTypes, | ||
...types, | ||
sessionKey: PropTypes.string | ||
}; | ||
|
||
ControlledComponent.defaultProps = { | ||
...WrappedComponent.defaultProps | ||
}; | ||
|
||
return ControlledComponent; // TODO use recompose withState or withStateHandlers here instead of component state above | ||
}; | ||
|
||
export default controlled; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,38 @@ | ||
import React from 'react'; | ||
|
||
export const bindMethods = (context, methods) => { | ||
methods.forEach(method => { | ||
context[method] = context[method].bind(context); | ||
}); | ||
}; | ||
|
||
// Returns a subset of the given object including only the given keys, with values optionally replaced by a fn. | ||
export const selectKeys = (obj, keys, fn = val => val) => | ||
keys.reduce((values, key) => ({ ...values, [key]: fn(obj[key]) }), {}); | ||
|
||
// Returns a subset of the given object with a validator function applied to its keys. | ||
export const filterKeys = (obj, validator) => | ||
selectKeys(obj, Object.keys(obj).filter(validator)); | ||
|
||
export const childrenToArray = children => | ||
children && | ||
React.Children.count(children) > 0 && | ||
React.Children.toArray(children); | ||
|
||
export const filterChildren = (children, validator) => { | ||
const array = childrenToArray(children); | ||
return array && array.filter(validator); | ||
}; | ||
|
||
export const findChild = (children, validator) => { | ||
const array = childrenToArray(children); | ||
return array && array.find(validator); | ||
}; | ||
|
||
export const propsChanged = (propNames, oldProps, newProps) => | ||
propNames.some(propName => oldProps[propName] !== newProps[propName]); | ||
|
||
// Returns an object with the same keys as the given one, but all null values. | ||
export const nullValues = obj => selectKeys(obj, Object.keys(obj), () => null); | ||
|
||
export const noop = Function.prototype; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,19 @@ | ||
import 'patternfly/dist/js/patternfly-settings'; | ||
import 'patternfly/dist/js/patternfly-settings-charts'; | ||
import Break from 'breakjs'; | ||
|
||
const patternfly = window.patternfly; | ||
const c3ChartDefaults = patternfly.c3ChartDefaults(); | ||
|
||
export { patternfly, c3ChartDefaults }; | ||
const mockLayout = { | ||
is: layout => layout === 'desktop', | ||
addChangeListener: () => {}, | ||
removeChangeListener: () => {} | ||
}; | ||
|
||
const layout = | ||
process.env.NODE_ENV === 'test' | ||
? mockLayout | ||
: Break({ mobile: 0, ...patternfly.pfBreakpoints }); | ||
|
||
export { patternfly, c3ChartDefaults, layout }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { Navbar as default } from 'react-bootstrap'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default as Navbar } from './Navbar'; |
Oops, something went wrong.