export const UploadGeneSet = withProps(({ CreateButton }) => ({ CreateSetButton: withProps(() => ({ CreateButton: CreateButton || CreateExploreGeneSetButton, idMap: geneMap, idKey: 'gene_id', mainField: 'genes.gene_id', }))(CreateSetButton), inputProps: { type: 'gene', placeholder: 'e.g. ENSG00000155657, TTN, 7273, HGNC:12403, 188840, Q8WZ42', helpText: ( <div> <div style={{ maxWidth: '50rem', whiteSpace: 'initial' }}> - Gene identifier accepted:{' '} {Object.values(GENE_ID_FIELD_DISPLAY).join(', ')} </div> - Delimiters between gene identifiers: comma, space, tab or 1 gene identifier per line<br /> <FileFormats /> </div> ), }, MappingTable: GeneMappingTable, validateHits: geneValidateHits, idMap: geneMap, heading: 'Upload Gene Set', validatingMessage: ( <span> <SpinnerIcon /> validating genes </span> ), }))(Base);
export const UploadSsmSet = withProps(({ CreateButton }) => ({ CreateSetButton: withProps(() => ({ CreateButton: CreateButton || CreateExploreSsmSetButton, idMap: ssmMap, idKey: 'ssm_id', mainField: 'ssms.ssm_id', }))(CreateSetButton), inputProps: { displayType: 'mutation', placeholder: 'e.g. chr3:g.179234297A>G, 92b75ae1-8d4d-52c2-8658-9c981eef0e57', helpText: ( <div> <div style={{ maxWidth: '50rem', whiteSpace: 'initial' }}> - Mutation identifier accepted:{' '} {Object.values(SSM_ID_FIELD_DISPLAY).join(', ')} </div> - Delimiters between mutation identifiers: comma, space, tab or 1 mutation identifier per line<br /> <FileFormats /> </div> ), }, MappingTable: SsmMappingTable, validateHits: ssmValidateHits, idMap: ssmMap, heading: 'Upload Mutation Set', validatingMessage: ( <span> <SpinnerIcon /> validating mutations </span> ), }))(Base);
export const UploadCaseSet = withProps(({ CreateButton }) => ({ CreateSetButton: withProps(() => ({ CreateButton: CreateButton || CreateRepositoryCaseSetButton, idMap: caseMap, idKey: 'case_id', mainField: 'cases.case_id', }))(CreateSetButton), inputProps: { type: 'case', placeholder: 'e.g. TCGA-DD-AAVP, TCGA-DD-AAVP-10A-01D-A40U-10, 0004d251-3f70-4395-b175-c94c2f5b1b81', helpText: ( <div> <div style={{ maxWidth: '50rem', whiteSpace: 'initial' }}> - Case identifier accepted:{' '} {Object.values(CASE_ID_FIELD_DISPLAY).join(', ')} </div> - Delimiters between case identifiers: comma, space, tab or 1 case identifier per line<br /> <FileFormats /> </div> ), }, MappingTable: CaseMappingTable, validateHits: caseValidateHits, idMap: caseMap, heading: 'Upload Case Set', validatingMessage: ( <span> <SpinnerIcon /> validating cases </span> ), }))(Base);
export default function createSimpleDialog(props) { return compose( withDialog({ isDraggable: true, width: 400, ...props.dialogProps }), reduxForm({ form: props.formName }), withProps(props) )(SimpleGenericDialogForm); }
const withReduxForm = (initialState, mapProps = defaultMapProps) => { const hoc = compose( withProps((props) => ({ ...props, ...mapProps(props) })), reduxForm(initialState) ) if (process.env.NODE_ENV !== 'production') { return (BaseComponent) => setDisplayName(wrapDisplayName(BaseComponent, 'withReduxForm'))(hoc(BaseComponent)) } return hoc }
it('renames a single prop', () => { const spy = createSpy() const StringConcat = compose( withProps({ so: 123, la: 456 }), renameProp('so', 'do'), spy )('div') expect(StringConcat.displayName).to.equal( 'withProps(renameProp(spy(div)))' ) renderIntoDocument(<StringConcat />) expect(spy.getProps()).to.eql({ do: 123, la: 456 }) })
export default mapThemeToCss => { let refs = 0; let sheet = null; let cache = null; const attach = (nextState, force = false) => { if (isEqual(nextState, cache)) return; cache = nextState; if (force || !sheet) sheet = jss.createStyleSheet(nextState); sheet.attach(); }; const ref = (nextState) => { if (refs === 0) attach(nextState); refs++; return sheet; }; const deref = () => { refs--; if (refs === 0) { sheet.detach(); cache = null; } }; return compose( lifecycle({ componentWillMount() { const nextState = mapThemeToCss(this.props.theme); ref(nextState); }, componentWillReceiveProps(nextProps) { if (!isEqual(this.props.theme, nextProps.theme)) { attach(mapThemeToCss(nextProps.theme), true); } }, componentWillUnmount() { deref(); } }), withProps(() => ({ sheet })) ); };
// sets a fetching flag on the state tree. actions.request() // dispatch a promise to be unpacked by redux-promise to send the result to // the reducer to update the state tree with the route times actions.routeTimeFetch(axios.get(`/fetch/times/${routeNumber}/${direction}/${stopID}`)) .then(function fulfilled () { actions.requestSuccess() }) } // Looking at the source code for lifecycle it does not look like this is // optional.... function teardown () { return null } const goHome = curry(function goHome (push, event) { event.preventDefault() return push('/') }) // wrapping the component in a Higher Order Component (HCO) export default compose( pure, withProps({ goHome }), lifecycle( setup, teardown ), )(RouteTimesWrapper)
import React from 'react'; import { compose, withProps } from 'recompose'; import { connect } from 'react-redux'; import { get } from 'lodash'; import { removeFilesFromCart, addAllFilesInCart } from '@ncigdc/dux/cart'; import Button from '@ncigdc/uikit/Button'; import ShoppingCartIcon from '@ncigdc/theme/icons/ShoppingCart'; import { SpinnerIcon } from '../../theme/icons/index'; export default compose( connect(state => ({ cartFiles: state.cart.files })), withProps(props => { return { files: get(props, 'filesViewer.repository.files.hits.edges', []).map( x => x.node, ), }; }), )(({ dispatch, cartFiles, style, loading, files, ...props }) => { const hasFilesToAdd = files.filter( f => !cartFiles.some(cf => cf.file_id === f.file_id), ).length; const cartOperation = hasFilesToAdd ? addAllFilesInCart : removeFilesFromCart; return ( <Button style={style} className="test-cart-file-toggle" onClick={() => !loading && dispatch(cartOperation(files))} leftIcon={loading ? <SpinnerIcon /> : <ShoppingCartIcon />}
(eA: string) } { // $ExpectError hello nor any nor number (hello: number) } </div>; const enhacer: HOC<*, EnhancedCompProps> = compose( withPropsOnChange(["eA"], ({ eA }) => ({ hello: `${eA}` })), withProps(props => ({ hello: (props.hello: string), eA: (props.eA: number), // $ExpectError hello nor any nor number helloErr: (props.hello: number), // $ExpectError eA nor any nor string eAErr: (props.eA: string) })), withProps(props => ({ // $ExpectError property not found err: props.iMNotExists })) ); const enhacerFn: HOC<*, EnhancedCompProps> = compose( withPropsOnChange( (props, nextProps) => { (props.eA: number); (nextProps.eA: number); // $ExpectError eA nor any nor string
import { Map } from 'immutable'; import { compose, withProps, setPropTypes } from 'recompose'; import { withModels } from 'ui/utils/hocs'; import SiteUserOrgItem from 'ui/containers/SiteUsers/SiteUserOrgItem'; const enhance = compose( setPropTypes({ user: PropTypes.instanceOf(Map).isRequired }), withProps(({ user }) => { const schema = 'organisation'; const organisations = user .get('organisations') .map(org => new Map({ $oid: org })); const filter = new Map({ _id: new Map({ $in: organisations }) }); return { schema, filter }; }), withModels ); const render = ({ models, user }) => { const orgsItems = models .map(org => <SiteUserOrgItem org={org} user={user} />) .valueSeq(); return <ul>{orgsItems}</ul>; };
import { unsubscribe } from '/imports/api/discussions/methods'; import renderUnsubscribePage from '../helpers/withState'; const enhancer = compose( lifecycle({ componentDidMount() { const { documentId, documentType } = this.props; unsubscribe.call({ documentId, documentType }, handleMethodResult((error) => this.props.setState({ error, loading: false }) )); }, }), withProps({ children: ( <h3>You've successfully unsubscribed from this discussion's notifications</h3> ), }), ); const Notifications = renderUnsubscribePage(enhancer); Notifications.propTypes = { documentId: PropTypes.string.isRequired, documentType: PropTypes.string.isRequired, }; export default Notifications;
); }; TextAreaArgInput.propTypes = { updateValue: PropTypes.func.isRequired, value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, confirm: PropTypes.string, commit: PropTypes.func.isRequired, renderError: PropTypes.func, argId: PropTypes.string.isRequired, }; const EnhancedTextAreaArgInput = compose( withProps(({ onValueChange, typeInstance, argValue }) => ({ confirm: get(typeInstance, 'options.confirm'), commit: onValueChange, value: argValue, })), createStatefulPropHoc('value') )(TextAreaArgInput); EnhancedTextAreaArgInput.propTypes = { argValue: PropTypes.any.isRequired, onValueChange: PropTypes.func.isRequired, typeInstance: PropTypes.object.isRequired, renderError: PropTypes.func.isRequired, }; export const textarea = () => ({ name: 'textarea', displayName: 'Textarea',
type EnhancedCompProps = { eA: 1 } const Comp = ({ eA }) => <div> {(eA: number)} { // $ExpectError eA nor any nor string (eA: string) } </div> const enhacer: HOC<*, EnhancedCompProps> = compose( withContext({}, props => { // $ExpectError eA nor any nor string ;(props.eA: string) return {} }), withProps(props => ({ eA: (props.eA: number), // $ExpectError eA nor any nor string eAErr: (props.eA: string), })), withProps(props => ({ // $ExpectError property not found err: props.iMNotExists, })) ) const EnhancedComponent = enhacer(Comp)
await loadBrowserRegistries(types, basePath); // set app state to ready dispatch(appReady()); } catch (e) { dispatch(appError(e)); } }, setAppError: payload => dispatch(appError(payload)), }); const mergeProps = (stateProps, dispatchProps, ownProps) => { return { ...ownProps, ...stateProps, ...dispatchProps, setAppReady: dispatchProps.setAppReady(stateProps.basePath), }; }; export const App = compose( connect( mapStateToProps, mapDispatchToProps, mergeProps ), withProps(() => ({ onRouteChange: trackRouteChange, })) )(Component);
export default (schemaDefinition) => { const schema = new SimpleSchema(schemaDefinition); return withProps({ schema, }); };
import React, { PropTypes } from 'react'; import { compose, withProps, setPropTypes } from 'recompose'; import ConfirmModal from 'ui/components/Modal/ConfirmModal'; const enhanceConfirmModal = compose( setPropTypes({ target: PropTypes.string.isRequired, }), withProps(({ target }) => ({ title: 'Confirm delete', message: ( <span> This will delete the {target} <b>permanently</b>. Are you sure? </span> ) })), ); export default enhanceConfirmModal(ConfirmModal);
const getTypeFromMime = (mime) => { const match = TYPES.find(([matcher]) => matcher.test(mime)); if (!match) { return null; } return match[1]; }; const mapDispatchToProps = dispatch => ({ importAsset: bindActionCreators(assetActions.importAsset, dispatch), }); const autoFileDrop = compose( withProps(({ type }) => { if (!type) { return null; } const accepts = ACCEPTS[type]; return { accepts }; }), connect(null, mapDispatchToProps), withHandlers({ onDrop: ({ importAsset, onDrop }) => (acceptedFiles) => { acceptedFiles.forEach((file) => { const type = getTypeFromMime(file.type); importAsset(file, type) .then(({ id }) => { onDrop(id); }); });
{!disabled && <div className="form-group"> <button className="btn btn-primary pull-right" onClick={handleImportPersonas}> Import Personas </button> </div> } </div> ); }; export default compose( withProps(({ model }) => ({ schema, id: model.get('_id') })), withModel, connect( (state, { schema: connectSchema, id }) => ({ model: modelsSchemaIdSelector(connectSchema, id, { deep: true })(state) }), { importPersonas } ), disabledState, handlers )( ConfigureUploadComponent );
const { data } = template || { data: undefined }; const { heading: templateHeading } = data || { heading: undefined }; if (templateHeading) { this.heading = templateHeading; } else { this.heading = { defaultValue: "Address Book", i18nKey: "accountsUI.addressBook" }; } } onData(null, { addressBook, countries, heading: this.heading, initMode, regionsByCountry }); } registerComponent("AddressBook", AddressBook, [ composeWithTracker(composer), withProps(handlers) ]); export default compose( composeWithTracker(composer), withProps(handlers) )(AddressBook);
import {compose, withProps, withPropsOnChange, withState} from 'recompose'; import {withDefaultProps} from './'; import {sanitizeDate, withImmutableProps} from '../utils'; import enhanceHeader from '../Header/withMultipleDates'; import format from 'date-fns/format'; import parse from 'date-fns/parse'; // Enhance Day component to display selected state based on an array of selected dates export const enhanceDay = withPropsOnChange(['selected'], props => ({ isSelected: props.selected.indexOf(props.date) !== -1, })); // Enhance year component const enhanceYears = withProps(({displayDate}) => ({ selected: displayDate ? parse(displayDate) : null, })); // Enhancer to handle selecting and displaying multiple dates export const withMultipleDates = compose( withDefaultProps, withState('scrollDate', 'setScrollDate', getInitialDate), withState('displayDate', 'setDisplayDate', getInitialDate), withImmutableProps(({ DayComponent, HeaderComponent, YearsComponent, }) => ({ DayComponent: enhanceDay(DayComponent), HeaderComponent: enhanceHeader(HeaderComponent), YearsComponent: enhanceYears(YearsComponent), })),
export const withSearch = passedInState => { // prefix props to avoid collisions with existing props for component being enhanced const defaultState = { results: [], query: '', isLoading: false, isInSearchMode: false, fileHistoryResult: [], }; // prevent results that come back out-of-order from being displayed let timeOfMostRecentRequest = 0; return compose( withState('state', 'setState', _.defaults(passedInState, defaultState)), withRouter, withProps(({ setState }) => ({ handleResults: async (results, timeOfRequest, query) => { if (timeOfMostRecentRequest === timeOfRequest) { if (query && !results.length && isUUID(query)) { const history = await fetchFileHistory(query); if (history && history.length) { return setState(s => ({ ...s, fileHistoryResult: history, results: [], isLoading: false, })); } } setState(s => ({ ...s, results, fileHistoryResult: [], isLoading: false, })); } }, })), withHandlers({ setQuery: ({ setState }) => q => { setState(s => ({ ...s, query: q.trim() })); }, reset: ({ setState }) => () => { setState(s => ({ ...s, query: '', isInSearchMode: false, isLoading: false, })); }, fetchResults: ({ handleResults }) => (query, timeOfRequest) => { return throttledInvoker(() => fetchApi( `/quick_search?query=${window.encodeURIComponent(query)}&size=5`, { headers: { 'Content-Type': 'application/json', }, }, ).then(response => { let hits = []; if (response && response.data) { hits = response.data.query.hits; } return handleResults(hits, timeOfRequest, query); }), ); }, }), withHandlers({ selectItem: ({ push, reset }) => (item: ISearchHit) => { push(extractFilePath(item)); setTimeout(reset, 100); }, }), withPropsOnChange( (props, nextProps) => props.state.query !== nextProps.state.query, ({ state: { query, results, fileHistoryResult }, setState, fetchResults, }) => { timeOfMostRecentRequest = new Date().getTime(); if (query) { setState(s => ({ ...s, isLoading: true })); fetchResults(query, timeOfMostRecentRequest); } else if ( (results && results.length) || (fileHistoryResult && fileHistoryResult.length) ) { setState(s => ({ ...s, results: [], fileHistoryResult: [] })); } else { setState(s => ({ ...s, isLoading: false })); } }, ), ); };
onClick={addShareable}> New shareable link </button> </div> <ModelList schema="dashboardSharing" isLoading={false} hasMore={false} models={model.get('shareable', new List())} fetchMore={() => {}} ModelForm={ModelForm} ModelListItem={ModelListItemWithoutModel} parentModel={model} updateModel={updateModel} buttons={[(openLinkButton({ parentModel: model })), (deleteButton({ parentModel: model }))]} getDescription={mod => mod.get('title')} noItemsDisplay="No shared links - click 'New shareable link' to share your dashboard" /> <hr /> </div> ); export default compose( withProps(({ id }) => ({ id, schema })), withModel, withStyles(styles), dashboardSharingHandlers )(DashboardSharingComponent);
import { withProps, compose } from 'recompose'; import { queryStringToQuery, modelQueryStringSelector } from 'ui/redux/modules/search'; import { withModels, withModel } from 'ui/utils/hocs'; import { addModel } from 'ui/redux/modules/models'; import { routeNodeSelector } from 'redux-router5'; import ModelList from 'ui/containers/ModelList'; import SearchBox from 'ui/containers/SearchBox'; import PersonaView from './PersonaView'; const schema = 'persona'; const PersonaList = compose( withProps({ schema, sort: fromJS({ _id: -1 }) }), withModels, withModel )(ModelList); class PersonaManage extends Component { static propTypes = { addModel: PropTypes.func, personaId: PropTypes.string // optional }; constructor(props) { super(props); this.state = { openModal: null,
shouldComponentUpdate(nextProps) { return this.props._id === nextProps.at || (this.props.at === this.props._id && !nextProps.at) || (this.props.at === this.props._id && nextProps.at !== this.props._id) || !this.props.isMergedWithPreviousMessage && nextProps.isMergedWithPreviousMessage; }, componentDidMount() { if (this.props.isSelected) { invoke(this.props, 'scrollToSelectedMessage', this); } }, }), withHandlers({ onMessageAvatarClick: openUserDetails, onMessageContentsClick: deselect, onMessageTimeClick: select, onMessageDelete: remove, }), withProps(transsoc({ isAuthor, userAvatar: withUser(getAvatar), userFirstName: withUser(getFirstName), userFullNameOrEmail: withUser(getFullNameOrEmail), pathToMessage: getMessagePath, time: getMessageTime, contents: getMessageContents, pathToMessageToCopy: getPathToMessageToCopy, className: getClassName, })) )(Message);
cursor: pointer; padding-left: 2px; &:hover { color: #0275d8 } & > div { margin-right: 8px; } `; const enhance = compose( withStateToggle(false, 'isOpen', 'togglePopover'), withProps(({ fill, id }) => ({ iconProps: { size: Timeline.LIST_ICON_SIZE, inline: true, id: `item-${id}`, fill, }, })), ); const TimelineListItem = ({ label, date, userName, symbol, isOpen, iconProps, togglePopover, renderPopover, }) => (
import { compose, mapProps, withProps } from "recompose"; import type { HOC } from "recompose"; type EnhancedCompProps = { eA: 1 }; const Comp = ({ a }) => <div> {(a: string)} { // $ExpectError (a: number) } </div>; const enhacer: HOC<*, EnhancedCompProps> = compose( mapProps(p => ({ a: "1" })), // If you need to to detect erros after a mapProps HOC // you need to explicitly set Types for all HOCs below // seems like this https://github.com/facebook/flow/issues/4342 issue withProps(props => ({ a: (props.a: string), // $ExpectError but not e: Math.round(props.a) })) ); enhacer(Comp);
import PropTypes from 'prop-types'; import React from 'react'; import { compose, withProps } from 'recompose'; import Form from '/imports/ui/react/forms/components/Form'; import ReviewAnnualDate from '../AnnualDate'; import { getFormProps } from '../helpers'; const enhance = compose(withProps(props => getFormProps(props))); const ReviewAnnualDateForm = enhance(props => ( <Form autosave initialFormData={props.initialFormData} onFormChange={props.onAnnualDateChanged} > <ReviewAnnualDate fieldName={props.fieldNames.annualDate} /> </Form> )); ReviewAnnualDateForm.propTypes = { data: PropTypes.object, documentKey: PropTypes.string, onAnnualDateChanged: PropTypes.func, }; export default ReviewAnnualDateForm;
import { connect } from 'react-redux'; import MessagesList from '../../components/MessagesList'; import { compose, withProps } from 'recompose'; import { transformMessages } from './helpers.js'; import { transsoc, pickFromDiscussion } from '/imports/api/helpers.js'; export default compose( connect(pickFromDiscussion(['at'])), withProps(transsoc({ messages: transformMessages, })) )(MessagesList);