UNPKG

@talend/react-cmf

Version:

A framework built on top of best react libraries

395 lines (388 loc) 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = cmfConnect; exports.getComponentId = getComponentId; exports.getComponentName = getComponentName; exports.getDispatchToProps = getDispatchToProps; exports.getMergeProps = getMergeProps; exports.getStateToProps = getStateToProps; var _propTypes = _interopRequireDefault(require("prop-types")); var _react = require("react"); var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-statics")); var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes")); var _reactRedux = require("react-redux"); var _utils = require("@talend/utils"); var _actions = _interopRequireDefault(require("./actions")); var _actionCreator = _interopRequireDefault(require("./actionCreator")); var _component = _interopRequireDefault(require("./component")); var _constant = _interopRequireDefault(require("./constant")); var _expression = _interopRequireDefault(require("./expression")); var _onEvent = _interopRequireDefault(require("./onEvent")); var _componentState = require("./componentState"); var _settings = require("./settings"); var _omit = _interopRequireDefault(require("./omit")); var _RegistryProvider = require("./RegistryProvider"); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /** * This module connect your component in the CMF environment. * @module react-cmf/lib/cmfConnect * @example import { cmfConnect } from '@talend/react-cmf'; function MyComponent(props) { const onClick = (event) => { props.dispatchActionCreator('myaction', event, { props: props }); }; return <button onClick={onClick}>Edit {props.foo.name}</button>; } function mapStateToProps(state) { return { foo: state.cmf.collection.get('foo', { name: 'world' }), }; } export default cmfConnect({ mapStateToProps, }); */ function getComponentName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; } function getComponentId(componentId, props) { if (typeof componentId === 'function') { return componentId(props) || 'default'; } else if (typeof componentId === 'string') { return componentId; } else if (props.componentId) { return props.componentId; } return 'default'; } function getStateToProps({ defaultProps, componentId, ownProps, state, mapStateToProps, WrappedComponent }) { const props = { ...defaultProps }; const cmfProps = (0, _componentState.getStateProps)(state, getComponentName(WrappedComponent), getComponentId(componentId, ownProps)); _extends(props, cmfProps); const viewProps = (0, _settings.mapStateToViewProps)(state, ownProps, getComponentName(WrappedComponent), getComponentId(componentId, ownProps)); _extends(props, viewProps); let userProps = {}; if (mapStateToProps) { userProps = mapStateToProps(state, { ...ownProps, ...props }, cmfProps); } _extends(props, userProps); _extends(props, _expression.default.mapStateToProps(state, { ...ownProps, ...props })); return props; } function getDispatchToProps({ defaultState, dispatch, componentId, mapDispatchToProps, ownProps, WrappedComponent }) { const cmfProps = (0, _componentState.getStateAccessors)(dispatch, getComponentName(WrappedComponent), getComponentId(componentId, ownProps), defaultState); cmfProps.dispatch = dispatch; cmfProps.getComponent = _component.default.get; cmfProps.dispatchActionCreator = (actionId, event, data, context) => { dispatch(_actionCreator.default.get(context, actionId)(event, data, context)); }; let userProps = {}; if (mapDispatchToProps) { if (process.env.NODE_ENV === 'development') { // eslint-disable-next-line no-console console.warn(`DEPRECATION WARNING: mapDispatchToProps will be removed from cmfConnect. Please use the injectedProps dispatchActionCreator or dispatch`); } userProps = mapDispatchToProps(dispatch, ownProps, cmfProps); } return { ...cmfProps, ...userProps }; } /** * Internal: you should not have to use this * return the merged props which cleanup expression props * call mergeProps if exists after the cleanup * @param {object} options { mergeProps, stateProps, dispatchProps, ownProps } */ function getMergeProps({ mergeProps, stateProps, dispatchProps, ownProps }) { if (mergeProps) { return mergeProps(_expression.default.mergeProps(stateProps), _expression.default.mergeProps(dispatchProps), _expression.default.mergeProps(ownProps)); } return { ..._expression.default.mergeProps(ownProps), ..._expression.default.mergeProps(dispatchProps), ..._expression.default.mergeProps(stateProps) }; } /** * this function wrap your component to inject CMF props * @example * The following props are injected: * - props.state * - props.setState * - props.initState (you should never have to call it your self) * - dispatch(action) * - dispatchActionCreator(id, event, data, [context]) * * support for the following props * - initialState (called by props.initState) * - didMountActionCreator (id or array of id) * - willUnMountActionCreator (id or array of id) * - componentId (or will use uuid) * - keepComponentState (boolean, overrides the keepComponentState defined in container) * - didMountActionCreator (string called as action creator in didMount) * - view (string to inject the settings as props with ref support) * - whateverExpression (will inject `whatever` props and will remove it) * @example * options has the following shape: { componentId, // string or function(props) to compute the id in the store defaultState, // the default state when the component is mount keepComponent, // boolean, when the component is unmount, to keep it's state in redux store mapStateToProps, // function(state, ownProps) that should return the props (same as redux) mapDispatchToProps, // same as redux connect arg, you should use dispatchActionCreator instead mergeProps, // same as redux connect } * @param {object} options Option objects to configure the redux connect * @return {ReactComponent} */ function cmfConnect({ componentId, defaultState, defaultProps, keepComponentState, mapStateToProps, mapDispatchToProps, mergeProps, omitCMFProps = true, withComponentRegistry = false, withDispatch = false, withDispatchActionCreator = false, withComponentId = false, ...rest } = {}) { const propsToOmit = []; if (omitCMFProps) { if (!defaultState) { propsToOmit.push(..._constant.default.INJECTED_STATE_PROPS); } if (!withComponentRegistry) { propsToOmit.push('getComponent'); } if (!withComponentId) { propsToOmit.push('componentId'); } if (!withDispatch) { propsToOmit.push('dispatch'); } if (!withDispatchActionCreator) { propsToOmit.push('dispatchActionCreator'); } } let displayNameWarning = true; return function wrapWithCMF(WrappedComponent) { if (!WrappedComponent.displayName && displayNameWarning) { displayNameWarning = false; // eslint-disable-next-line no-console console.warn(`${WrappedComponent.name} has no displayName. Please read https://jira.talendforge.org/browse/TUI-302`); } function getState(state, id = 'default') { return state.cmf.components.getIn([getComponentName(WrappedComponent), id], defaultState); } function getSetStateAction(state, id, type) { return { type: type || `${getComponentName(WrappedComponent)}.setState`, cmf: { componentState: _actions.default.components.mergeState(getComponentName(WrappedComponent), id, state) } }; } function CMFContainer(props, ref) { const [instanceId] = (0, _react.useState)((0, _utils.randomUUID)()); const registry = (0, _react.useContext)(_RegistryProvider.RegistryContext); const store = (0, _reactRedux.useStore)(); function dispatchActionCreator(actionCreatorId, event, data, extraContext) { const extendedContext = { registry, store, ...extraContext }; props.dispatchActionCreator(actionCreatorId, event, data, extendedContext); } (0, _react.useEffect)(() => { (0, _componentState.initState)(props); if (props.saga) { dispatchActionCreator('cmf.saga.start', { type: 'DID_MOUNT', componentId: instanceId }, { ...props, // DEPRECATED componentId: getComponentId(componentId, props) }); } if (props.didMountActionCreator) { dispatchActionCreator(props.didMountActionCreator, null, props); } return () => { if (props.willUnmountActionCreator) { dispatchActionCreator(props.willUnmountActionCreator, null, props); } // if the props.keepComponentState is present we have to stick to it if (props.keepComponentState === false || props.keepComponentState === undefined && !keepComponentState) { props.deleteState(props.initialState); } if (props.saga) { dispatchActionCreator('cmf.saga.stop', { type: 'WILL_UNMOUNT', componentId: instanceId }, props); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); function getOnEventProps() { return Object.keys(props).reduce((acc, key) => { // TODO check how to replace the this _onEvent.default.addOnEventSupport(_onEvent.default.DISPATCH, { props }, acc, key); _onEvent.default.addOnEventSupport(_onEvent.default.ACTION_CREATOR, { props }, acc, key); _onEvent.default.addOnEventSupport(_onEvent.default.SETSTATE, { props }, acc, key); return acc; }, { toOmit: [], dispatchActionCreator }); } if (props.renderIf === false) { return null; } const { toOmit, spreadCMFState, ...handlers } = getOnEventProps(); // remove all internal props already used by the container delete handlers.dispatchActionCreator; toOmit.push(..._constant.default.CMF_PROPS, ...propsToOmit); if (props.omitRouterProps) { toOmit.push('omitRouterProps', ..._constant.default.INJECTED_ROUTER_PROPS); } let spreadedState = {}; if ((spreadCMFState || props.spreadCMFState) && props.state) { spreadedState = props.state.toJS(); } const newProps = { ...(0, _omit.default)(props, toOmit), ...handlers, ...spreadedState }; if (newProps.dispatchActionCreator && toOmit.indexOf('dispatchActionCreator') === -1) { // override to inject CMFContainer context newProps.dispatchActionCreator = dispatchActionCreator; } if (!newProps.state && defaultState && toOmit.indexOf('state') === -1) { newProps.state = defaultState; } if (rest.forwardRef) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(WrappedComponent, { ...newProps, ref: ref }); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(WrappedComponent, { ...newProps }); } let CMFWithRef = (0, _hoistNonReactStatics.default)(CMFContainer, WrappedComponent); CMFContainer.displayName = `CMF(${getComponentName(WrappedComponent)})`; CMFContainer.propTypes = { ...cmfConnect.propTypes }; CMFContainer.WrappedComponent = WrappedComponent; CMFContainer.getState = getState; // eslint-disable-next-line @typescript-eslint/default-param-last CMFContainer.setStateAction = function setStateAction(state, id = 'default', type) { if (typeof state !== 'function') { return getSetStateAction(state, id, type); } return (_, getReduxState) => getSetStateAction(state(getState(getReduxState(), id)), id, type); }; if (rest.forwardRef) { CMFWithRef = /*#__PURE__*/(0, _react.forwardRef)(CMFWithRef); CMFWithRef.displayName = `ForwardRef(${CMFContainer.displayName})`; CMFWithRef.WrappedComponent = CMFContainer.WrappedComponent; CMFWithRef.getState = CMFContainer.getState; CMFWithRef.setStateAction = CMFContainer.setStateAction; } const Connected = (0, _reactRedux.connect)((state, ownProps) => getStateToProps({ componentId, defaultProps, defaultState, ownProps, state, mapStateToProps, WrappedComponent }), (dispatch, ownProps) => getDispatchToProps({ defaultState, dispatch, componentId, mapDispatchToProps, ownProps, WrappedComponent }), (stateProps, dispatchProps, ownProps) => getMergeProps({ mergeProps, stateProps, dispatchProps, ownProps }), { ...rest })(CMFWithRef); Connected.CMFContainer = CMFContainer; return Connected; }; } cmfConnect.INJECTED_PROPS = _constant.default.INJECTED_PROPS; cmfConnect.INJECTED_STATE_PROPS = _constant.default.INJECTED_STATE_PROPS; cmfConnect.INJECTED_ROUTER_PROPS = _constant.default.INJECTED_ROUTER_PROPS; cmfConnect.ALL_INJECTED_PROPS = _constant.default.INJECTED_PROPS.concat(['getComponent', 'componentId']); cmfConnect.omit = _omit.default; cmfConnect.omitAllProps = props => cmfConnect.omit(props, cmfConnect.ALL_INJECTED_PROPS); cmfConnect.propTypes = { state: _reactImmutableProptypes.default.map, initialState: _propTypes.default.oneOfType([_reactImmutableProptypes.default.map, _propTypes.default.object]), getComponent: _propTypes.default.func, setState: _propTypes.default.func, initState: _propTypes.default.func, dispatchActionCreator: _propTypes.default.func, dispatch: _propTypes.default.func }; //# sourceMappingURL=cmfConnect.js.map