UNPKG

@flopflip/react-redux

Version:

A feature toggle wrapper to use LaunchDarkly with React Redux

427 lines (336 loc) 12.9 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; // src/branch-on-feature-toggle.tsx var _react = require('react'); var _react2 = _interopRequireDefault(_react); // src/use-feature-toggle.ts var _react3 = require('@flopflip/react'); var _reactredux = require('react-redux'); // src/ducks/flags.ts var _toolkit = require('@reduxjs/toolkit'); // src/constants.ts var STATE_SLICE = "@flopflip"; // src/ducks/flags.ts var initialState = { memory: {} }; var flagsSlice = _toolkit.createSlice.call(void 0, { name: "flags", initialState, reducers: { updateFlags: { reducer(state, action) { if (action.payload.id) { state[action.payload.id] = __spreadValues(__spreadValues({}, state[action.payload.id]), action.payload.flags); return; } for (const adapterId of action.payload.adapterIdentifiers) { state[adapterId] = __spreadValues(__spreadValues({}, state[adapterId]), action.payload.flags); } }, prepare(flagsChange, adapterIdentifiers) { return { payload: __spreadProps(__spreadValues({}, flagsChange), { adapterIdentifiers }) }; } } } }); var { updateFlags } = flagsSlice.actions; var reducer = flagsSlice.reducer; var createReducer = (preloadedState = initialState) => { return (state = preloadedState, action) => reducer(state, action); }; var selectFlags = () => (state) => { var _a; return (_a = state[STATE_SLICE].flags) != null ? _a : {}; }; var selectFlag = (flagName, adapterIdentifiers) => (state) => { var _a; const allFlags = selectFlags()(state); let foundFlagVariation = false; for (const adapterId of adapterIdentifiers) { const flagValue = (_a = allFlags[adapterId]) == null ? void 0 : _a[flagName]; if (!_react3.isNil.call(void 0, flagValue)) { foundFlagVariation = flagValue; } } return foundFlagVariation; }; // src/use-feature-toggle.ts function useFeatureToggle(flagName, flagVariation = true) { const adapterContext = _react3.useAdapterContext.call(void 0, ); const allFlags = _reactredux.useSelector.call(void 0, selectFlags()); const isFeatureEnabled = _react3.getIsFeatureEnabled.call(void 0, allFlags, adapterContext.adapterEffectIdentifiers, flagName, flagVariation ); _react.useDebugValue.call(void 0, { flagName, flagVariation, isEnabled: isFeatureEnabled }); return isFeatureEnabled; } // src/branch-on-feature-toggle.tsx function branchOnFeatureToggle({ flag: flagName, variation: flagVariation }, UntoggledComponent) { return (ToggledComponent) => { function WrappedToggledComponent(ownProps) { const isFeatureEnabled = useFeatureToggle(flagName, flagVariation); if (isFeatureEnabled) { return /* @__PURE__ */ _react2.default.createElement(ToggledComponent, __spreadValues({}, ownProps)); } if (UntoggledComponent) { return /* @__PURE__ */ _react2.default.createElement(UntoggledComponent, __spreadValues({}, ownProps)); } return null; } return WrappedToggledComponent; }; } // src/configure.tsx // src/use-update-flags.ts var useUpdateFlags = ({ adapterIdentifiers }) => { const dispatch = _reactredux.useDispatch.call(void 0, ); return _react.useCallback.call(void 0, (flagsChange) => dispatch(updateFlags(flagsChange, adapterIdentifiers)), [dispatch, adapterIdentifiers] ); }; // src/use-update-status.ts var _types = require('@flopflip/types'); // src/ducks/status.ts var initialState2 = {}; var statusSlice = _toolkit.createSlice.call(void 0, { name: "status", initialState: initialState2, reducers: { updateStatus: { reducer(state, action) { if (action.payload.id) { state[action.payload.id] = __spreadValues(__spreadValues({}, state[action.payload.id]), action.payload.status); return; } for (const adapterInterfaceIdentifier of action.payload.adapterIdentifiers) { state[adapterInterfaceIdentifier] = __spreadValues(__spreadValues({}, state[adapterInterfaceIdentifier]), action.payload.status); } }, prepare(statusChange, adapterIdentifiers) { return { payload: __spreadProps(__spreadValues({}, statusChange), { adapterIdentifiers }) }; } } } }); var { updateStatus } = statusSlice.actions; var reducer2 = statusSlice.reducer; var selectStatus = ({ adapterIdentifiers } = {}) => (state) => { const { status } = state[STATE_SLICE]; return _react3.selectAdapterConfigurationStatus.call(void 0, status, adapterIdentifiers); }; // src/use-update-status.ts var useUpdateStatus = () => { const dispatch = _reactredux.useDispatch.call(void 0, ); return _react.useCallback.call(void 0, (statusChange) => dispatch(updateStatus(statusChange, Object.keys(_types.adapterIdentifiers))), [dispatch] ); }; // src/configure.tsx function Configure({ adapter, adapterArgs, children, defaultFlags = {}, shouldDeferAdapterConfiguration = false }) { const adapterIdentifiers = [adapter.id]; const handleUpdateFlags = useUpdateFlags({ adapterIdentifiers }); const handleUpdateStatus = useUpdateStatus(); _react3.useAdapterSubscription.call(void 0, adapter); return /* @__PURE__ */ _react2.default.createElement( _react3.ConfigureAdapter, { adapter, adapterArgs, defaultFlags, shouldDeferAdapterConfiguration, onFlagsStateChange: handleUpdateFlags, onStatusStateChange: handleUpdateStatus }, children ); } Configure.displayName = "ConfigureFlopflip"; // src/ducks/index.ts var flopflipReducer = _toolkit.combineReducers.call(void 0, { flags: reducer, status: reducer2 }); var createFlopflipReducer = (preloadedState = { memory: {} }) => _toolkit.combineReducers.call(void 0, { flags: createReducer(preloadedState), status: reducer2 }); // src/enhancer.ts var configureAdapter = _toolkit.createAction.call(void 0, "flopflip/configureAdapter"); function createFlopFlipEnhancer(adapter, adapterArgs) { return (next) => (...args) => { const store = next(...args); store.dispatch(configureAdapter({ adapter, adapterArgs })); adapter.configure(adapterArgs, { onFlagsStateChange: (flagsChange) => { store.dispatch(updateFlags(flagsChange, [adapter.id])); }, onStatusStateChange: (statusChange) => { store.dispatch( updateStatus(statusChange, Object.keys(_types.adapterIdentifiers)) ); } }); return store; }; } // src/inject-feature-toggle.tsx // src/use-flag-variations.ts function useFlagVariations(flagNames) { const adapterContext = _react3.useAdapterContext.call(void 0, ); const allFlags = _reactredux.useSelector.call(void 0, selectFlags()); const flagVariations = flagNames.map( (requestedVariation) => _react3.getFlagVariation.call(void 0, allFlags, adapterContext.adapterEffectIdentifiers, requestedVariation ) ); return flagVariations; } // src/inject-feature-toggle.tsx var injectFeatureToggle = (flagName, propKey = _react3.DEFAULT_FLAG_PROP_KEY) => (Component) => { function WrappedComponent(ownProps) { const [flagVariation] = useFlagVariations([flagName]); const props = __spreadProps(__spreadValues({}, ownProps), { [propKey]: flagVariation }); return /* @__PURE__ */ _react2.default.createElement(Component, __spreadValues({}, props)); } _react3.setDisplayName.call(void 0, _react3.wrapDisplayName.call(void 0, WrappedComponent, "injectFeatureToggle")); return WrappedComponent; }; // src/inject-feature-toggles.tsx var injectFeatureToggles = (flagNames, propKey = _react3.DEFAULT_FLAGS_PROP_KEY) => (Component) => { function WrappedComponent(ownProps) { const flagVariations = useFlagVariations(flagNames); const flags = Object.fromEntries( flagNames.map((flagName, indexOfFlagName) => [ flagName, flagVariations[indexOfFlagName] ]) ); const props = __spreadProps(__spreadValues({}, ownProps), { [propKey]: flags }); return /* @__PURE__ */ _react2.default.createElement(Component, __spreadValues({}, props)); } _react3.setDisplayName.call(void 0, _react3.wrapDisplayName.call(void 0, WrappedComponent, "injectFeatureToggles")); return WrappedComponent; }; // src/reconfigure.ts // src/toggle-feature.tsx function ToggleFeature(_a) { var _b = _a, { flag, variation } = _b, remainingProps = __objRest(_b, [ "flag", "variation" ]); const isFeatureEnabled = useFeatureToggle(flag, variation); return /* @__PURE__ */ _react2.default.createElement( _react3.ToggleFeature, __spreadProps(__spreadValues({ flag, variation }, remainingProps), { isFeatureEnabled }) ); } ToggleFeature.displayName = "ToggleFeature"; // src/use-adapter-reconfiguration.ts // src/use-adapter-status.ts function useAdapterStatus({ adapterIdentifiers } = {}) { const adapterStatus = _reactredux.useSelector.call(void 0, selectStatus({ adapterIdentifiers })); _react.useDebugValue.call(void 0, { adapterStatus }); return adapterStatus; } // src/use-all-feature-toggles.ts function useAllFeatureToggles() { const adapterContext = _react3.useAdapterContext.call(void 0, ); const allFlags = _reactredux.useSelector.call(void 0, selectFlags()); const reversedAdapterEffectIdentifiers = [ ...adapterContext.adapterEffectIdentifiers ].reverse(); return reversedAdapterEffectIdentifiers.reduce( (_allFlags, adapterIdentifier) => __spreadValues(__spreadValues({}, _allFlags), allFlags[adapterIdentifier]), {} ); } // src/use-feature-toggles.ts function useFeatureToggles(flags) { const allFlags = _reactredux.useSelector.call(void 0, selectFlags()); const adapterContext = _react3.useAdapterContext.call(void 0, ); const requestedFlags = Object.entries(flags).reduce( (previousFlags, [flagName, flagVariation]) => { const isFeatureEnabled = _react3.getIsFeatureEnabled.call(void 0, allFlags, adapterContext.adapterEffectIdentifiers, flagName, flagVariation ); previousFlags.push(isFeatureEnabled); return previousFlags; }, [] ); return requestedFlags; } // src/use-flag-variation.ts function useFlagVariation(flagName) { const [flagVariation] = useFlagVariations([flagName]); return flagVariation; } // src/index.ts var version = "__@FLOPFLIP/VERSION_OF_RELEASE__"; exports.ConfigureFlopFlip = Configure; exports.FLOPFLIP_STATE_SLICE = STATE_SLICE; exports.ReconfigureFlopFlip = _react3.ReconfigureAdapter; exports.ToggleFeature = ToggleFeature; exports.branchOnFeatureToggle = branchOnFeatureToggle; exports.createFlopFlipEnhancer = createFlopFlipEnhancer; exports.createFlopflipReducer = createFlopflipReducer; exports.flopflipReducer = flopflipReducer; exports.injectFeatureToggle = injectFeatureToggle; exports.injectFeatureToggles = injectFeatureToggles; exports.selectFeatureFlag = selectFlag; exports.selectFeatureFlags = selectFlags; exports.useAdapterReconfiguration = _react3.useAdapterReconfiguration; exports.useAdapterStatus = useAdapterStatus; exports.useAllFeatureToggles = useAllFeatureToggles; exports.useFeatureToggle = useFeatureToggle; exports.useFeatureToggles = useFeatureToggles; exports.useFlagVariation = useFlagVariation; exports.useFlagVariations = useFlagVariations; exports.version = version; //# sourceMappingURL=index.cjs.map