@flopflip/react-redux
Version:
A feature toggle wrapper to use LaunchDarkly with React Redux
427 lines (400 loc) • 13.3 kB
JavaScript
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