UNPKG

@flopflip/react-redux

Version:

A feature toggle wrapper to use LaunchDarkly with React Redux

427 lines (400 loc) 13.3 kB
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 import React from "react"; // src/use-feature-toggle.ts import { getIsFeatureEnabled, useAdapterContext } from "@flopflip/react"; import { useDebugValue } from "react"; import { useSelector } from "react-redux"; // src/ducks/flags.ts import { isNil } from "@flopflip/react"; import { createSlice } from "@reduxjs/toolkit"; // src/constants.ts var STATE_SLICE = "@flopflip"; // src/ducks/flags.ts var initialState = { memory: {} }; var flagsSlice = createSlice({ 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 (!isNil(flagValue)) { foundFlagVariation = flagValue; } } return foundFlagVariation; }; // src/use-feature-toggle.ts function useFeatureToggle(flagName, flagVariation = true) { const adapterContext = useAdapterContext(); const allFlags = useSelector(selectFlags()); const isFeatureEnabled = getIsFeatureEnabled( allFlags, adapterContext.adapterEffectIdentifiers, flagName, flagVariation ); useDebugValue({ 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__ */ React.createElement(ToggledComponent, __spreadValues({}, ownProps)); } if (UntoggledComponent) { return /* @__PURE__ */ React.createElement(UntoggledComponent, __spreadValues({}, ownProps)); } return null; } return WrappedToggledComponent; }; } // src/configure.tsx import { ConfigureAdapter, useAdapterSubscription } from "@flopflip/react"; import React2 from "react"; // src/use-update-flags.ts import { useCallback } from "react"; import { useDispatch } from "react-redux"; var useUpdateFlags = ({ adapterIdentifiers }) => { const dispatch = useDispatch(); return useCallback( (flagsChange) => dispatch(updateFlags(flagsChange, adapterIdentifiers)), [dispatch, adapterIdentifiers] ); }; // src/use-update-status.ts import { adapterIdentifiers as allAdapterIdentifiers } from "@flopflip/types"; import { useCallback as useCallback2 } from "react"; import { useDispatch as useDispatch2 } from "react-redux"; // src/ducks/status.ts import { selectAdapterConfigurationStatus } from "@flopflip/react"; import { createSlice as createSlice2 } from "@reduxjs/toolkit"; var initialState2 = {}; var statusSlice = createSlice2({ 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 selectAdapterConfigurationStatus(status, adapterIdentifiers); }; // src/use-update-status.ts var useUpdateStatus = () => { const dispatch = useDispatch2(); return useCallback2( (statusChange) => dispatch(updateStatus(statusChange, Object.keys(allAdapterIdentifiers))), [dispatch] ); }; // src/configure.tsx function Configure({ adapter, adapterArgs, children, defaultFlags = {}, shouldDeferAdapterConfiguration = false }) { const adapterIdentifiers = [adapter.id]; const handleUpdateFlags = useUpdateFlags({ adapterIdentifiers }); const handleUpdateStatus = useUpdateStatus(); useAdapterSubscription(adapter); return /* @__PURE__ */ React2.createElement( ConfigureAdapter, { adapter, adapterArgs, defaultFlags, shouldDeferAdapterConfiguration, onFlagsStateChange: handleUpdateFlags, onStatusStateChange: handleUpdateStatus }, children ); } Configure.displayName = "ConfigureFlopflip"; // src/ducks/index.ts import { combineReducers } from "@reduxjs/toolkit"; var flopflipReducer = combineReducers({ flags: reducer, status: reducer2 }); var createFlopflipReducer = (preloadedState = { memory: {} }) => combineReducers({ flags: createReducer(preloadedState), status: reducer2 }); // src/enhancer.ts import { adapterIdentifiers as allAdapterIdentifiers2 } from "@flopflip/types"; import { createAction } from "@reduxjs/toolkit"; var configureAdapter = createAction("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(allAdapterIdentifiers2)) ); } }); return store; }; } // src/inject-feature-toggle.tsx import { DEFAULT_FLAG_PROP_KEY, setDisplayName, wrapDisplayName } from "@flopflip/react"; import React3 from "react"; // src/use-flag-variations.ts import { getFlagVariation, useAdapterContext as useAdapterContext2 } from "@flopflip/react"; import { useSelector as useSelector2 } from "react-redux"; function useFlagVariations(flagNames) { const adapterContext = useAdapterContext2(); const allFlags = useSelector2(selectFlags()); const flagVariations = flagNames.map( (requestedVariation) => getFlagVariation( allFlags, adapterContext.adapterEffectIdentifiers, requestedVariation ) ); return flagVariations; } // src/inject-feature-toggle.tsx var injectFeatureToggle = (flagName, propKey = DEFAULT_FLAG_PROP_KEY) => (Component) => { function WrappedComponent(ownProps) { const [flagVariation] = useFlagVariations([flagName]); const props = __spreadProps(__spreadValues({}, ownProps), { [propKey]: flagVariation }); return /* @__PURE__ */ React3.createElement(Component, __spreadValues({}, props)); } setDisplayName(wrapDisplayName(WrappedComponent, "injectFeatureToggle")); return WrappedComponent; }; // src/inject-feature-toggles.tsx import { DEFAULT_FLAGS_PROP_KEY, setDisplayName as setDisplayName2, wrapDisplayName as wrapDisplayName2 } from "@flopflip/react"; import React4 from "react"; var injectFeatureToggles = (flagNames, propKey = 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__ */ React4.createElement(Component, __spreadValues({}, props)); } setDisplayName2(wrapDisplayName2(WrappedComponent, "injectFeatureToggles")); return WrappedComponent; }; // src/reconfigure.ts import { ReconfigureAdapter } from "@flopflip/react"; // src/toggle-feature.tsx import { ToggleFeature as SharedToggleFeature } from "@flopflip/react"; import React5 from "react"; function ToggleFeature(_a) { var _b = _a, { flag, variation } = _b, remainingProps = __objRest(_b, [ "flag", "variation" ]); const isFeatureEnabled = useFeatureToggle(flag, variation); return /* @__PURE__ */ React5.createElement( SharedToggleFeature, __spreadProps(__spreadValues({ flag, variation }, remainingProps), { isFeatureEnabled }) ); } ToggleFeature.displayName = "ToggleFeature"; // src/use-adapter-reconfiguration.ts import { useAdapterReconfiguration } from "@flopflip/react"; // src/use-adapter-status.ts import { useDebugValue as useDebugValue2 } from "react"; import { useSelector as useSelector3 } from "react-redux"; function useAdapterStatus({ adapterIdentifiers } = {}) { const adapterStatus = useSelector3(selectStatus({ adapterIdentifiers })); useDebugValue2({ adapterStatus }); return adapterStatus; } // src/use-all-feature-toggles.ts import { useAdapterContext as useAdapterContext3 } from "@flopflip/react"; import { useSelector as useSelector4 } from "react-redux"; function useAllFeatureToggles() { const adapterContext = useAdapterContext3(); const allFlags = useSelector4(selectFlags()); const reversedAdapterEffectIdentifiers = [ ...adapterContext.adapterEffectIdentifiers ].reverse(); return reversedAdapterEffectIdentifiers.reduce( (_allFlags, adapterIdentifier) => __spreadValues(__spreadValues({}, _allFlags), allFlags[adapterIdentifier]), {} ); } // src/use-feature-toggles.ts import { getIsFeatureEnabled as getIsFeatureEnabled2, useAdapterContext as useAdapterContext4 } from "@flopflip/react"; import { useSelector as useSelector5 } from "react-redux"; function useFeatureToggles(flags) { const allFlags = useSelector5(selectFlags()); const adapterContext = useAdapterContext4(); const requestedFlags = Object.entries(flags).reduce( (previousFlags, [flagName, flagVariation]) => { const isFeatureEnabled = getIsFeatureEnabled2( 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__"; export { Configure as ConfigureFlopFlip, STATE_SLICE as FLOPFLIP_STATE_SLICE, ReconfigureAdapter as ReconfigureFlopFlip, ToggleFeature, branchOnFeatureToggle, createFlopFlipEnhancer, createFlopflipReducer, flopflipReducer, injectFeatureToggle, injectFeatureToggles, selectFlag as selectFeatureFlag, selectFlags as selectFeatureFlags, useAdapterReconfiguration, useAdapterStatus, useAllFeatureToggles, useFeatureToggle, useFeatureToggles, useFlagVariation, useFlagVariations, version }; //# sourceMappingURL=index.js.map