@flopflip/react-broadcast
Version:
A feature toggle wrapper to use LaunchDarkly with React
458 lines (435 loc) • 14.4 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";
// src/use-flags-context.ts
import { useContext } from "react";
// src/flags-context.ts
import {
adapterIdentifiers as allAdapterIdentifiers
} from "@flopflip/types";
import { createContext } from "react";
var createIntialFlagsContext = (adapterIdentifiers2, initialFlags) => Object.fromEntries(
Object.values(adapterIdentifiers2).map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
initialFlags
])
);
var FlagsContext = createContext(
createIntialFlagsContext(allAdapterIdentifiers, {})
);
// src/use-flags-context.ts
var useFlagsContext = () => useContext(FlagsContext);
// src/use-feature-toggle.ts
function useFeatureToggle(flagName, flagVariation = true) {
const adapterContext = useAdapterContext();
const flagsContext = useFlagsContext();
const isFeatureEnabled = getIsFeatureEnabled(
flagsContext,
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 {
AdapterSubscriptionStatus
} from "@flopflip/types";
import React2, { useCallback, useMemo } from "react";
import { useSyncExternalStore } from "use-sync-external-store/shim";
// src/store.ts
function createStore(initialState) {
let state = initialState;
const getSnapshot = () => state;
const listeners = /* @__PURE__ */ new Set();
function setState(fn) {
state = fn(state);
for (const listener of listeners) {
listener();
}
}
function subscribe(listener) {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
}
return { getSnapshot, setState, subscribe };
}
// src/configure.tsx
var store = createStore({
status: {},
flags: {}
});
var useFlagsState = ({
adapterIdentifiers: adapterIdentifiers2
}) => {
const flags = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().flags,
() => store.getSnapshot().flags
);
const updateFlags = useCallback(
(flagsChange) => {
store.setState((prevState) => {
let nextState;
if (flagsChange.id) {
nextState = __spreadProps(__spreadValues({}, prevState), {
flags: __spreadProps(__spreadValues({}, prevState.flags), {
[flagsChange.id]: __spreadValues(__spreadValues({}, prevState.flags[flagsChange.id]), flagsChange.flags)
})
});
return nextState;
}
nextState = __spreadProps(__spreadValues({}, prevState), {
flags: __spreadValues(__spreadValues({}, prevState.flags), Object.fromEntries(
adapterIdentifiers2.map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
__spreadValues(__spreadValues({}, prevState.flags[adapterInterfaceIdentifier]), flagsChange.flags)
])
))
});
return nextState;
});
},
[adapterIdentifiers2]
);
return [flags, updateFlags];
};
var useStatusState = ({
adapterIdentifiers: adapterIdentifiers2
}) => {
const status = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().status,
() => store.getSnapshot().status
);
const setStatus = useCallback(
(statusChange) => {
store.setState((prevState) => {
let nextState;
if (statusChange.id) {
nextState = __spreadProps(__spreadValues({}, prevState), {
status: __spreadProps(__spreadValues({}, prevState.status), {
[statusChange.id]: __spreadValues(__spreadValues({}, prevState.status[statusChange.id]), statusChange.status)
})
});
return nextState;
}
nextState = __spreadProps(__spreadValues({}, prevState), {
status: __spreadValues(__spreadValues({}, prevState.status), Object.fromEntries(
adapterIdentifiers2.map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
__spreadValues(__spreadValues({}, prevState.status[adapterInterfaceIdentifier]), statusChange.status)
])
))
});
return nextState;
});
},
[adapterIdentifiers2]
);
return [status, setStatus];
};
function Configure({
children,
shouldDeferAdapterConfiguration = false,
defaultFlags = {},
adapter,
adapterArgs
}) {
const adapterIdentifiers2 = useMemo(() => [adapter.id], [adapter.id]);
const [flags, updateFlags] = useFlagsState({ adapterIdentifiers: adapterIdentifiers2 });
const [status, updateStatus] = useStatusState({ adapterIdentifiers: adapterIdentifiers2 });
const getHasAdapterSubscriptionStatus = useAdapterSubscription(adapter);
const handleUpdateFlags = useCallback(
(flagsChange) => {
if (getHasAdapterSubscriptionStatus(AdapterSubscriptionStatus.Unsubscribed)) {
return;
}
updateFlags(flagsChange);
},
[updateFlags, getHasAdapterSubscriptionStatus]
);
const handleUpdateStatus = useCallback(
(statusChange) => {
if (getHasAdapterSubscriptionStatus(AdapterSubscriptionStatus.Unsubscribed)) {
return;
}
updateStatus(statusChange);
},
[updateStatus, getHasAdapterSubscriptionStatus]
);
return /* @__PURE__ */ React2.createElement(FlagsContext.Provider, { value: flags }, /* @__PURE__ */ React2.createElement(
ConfigureAdapter,
{
adapter,
adapterArgs,
adapterStatus: status,
defaultFlags,
shouldDeferAdapterConfiguration,
onFlagsStateChange: handleUpdateFlags,
onStatusStateChange: handleUpdateStatus
},
children
));
}
Configure.displayName = "ConfigureFlopflip";
// 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";
function useFlagVariations(flagNames) {
const adapterContext = useAdapterContext2();
const flagsContext = useFlagsContext();
const flagVariations = flagNames.map(
(requestedVariation) => getFlagVariation(
flagsContext,
adapterContext.adapterEffectIdentifiers,
requestedVariation
)
);
return flagVariations;
}
// src/inject-feature-toggle.tsx
function injectFeatureToggle(flagName, propKey = DEFAULT_FLAG_PROP_KEY) {
return (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";
function injectFeatureToggles(flagNames, propKey = DEFAULT_FLAGS_PROP_KEY) {
return (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/test-provider.tsx
import { AdapterContext, createAdapterContext } from "@flopflip/react";
import {
AdapterConfigurationStatus,
AdapterSubscriptionStatus as AdapterSubscriptionStatus2,
adapterIdentifiers
} from "@flopflip/types";
import React5 from "react";
var defaultProps = {
adapterIdentifiers: ["test"],
status: __spreadValues({}, Object.fromEntries(
Object.values(adapterIdentifiers).map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
{
subscriptionStatus: AdapterSubscriptionStatus2.Subscribed,
configurationStatus: AdapterConfigurationStatus.Configured
}
])
))
};
function TestProvider({
adapterIdentifiers: adapterIdentifiers2 = defaultProps.adapterIdentifiers,
reconfigure,
flags,
children,
status = defaultProps.status
}) {
const adapterContextValue = createAdapterContext(
adapterIdentifiers2,
reconfigure,
status
);
const flagsContextValue = createIntialFlagsContext(
// @ts-expect-error Can not remember. Sorry to myself.
adapterIdentifiers2,
flags
);
return /* @__PURE__ */ React5.createElement(AdapterContext.Provider, { value: adapterContextValue }, /* @__PURE__ */ React5.createElement(FlagsContext.Provider, { value: flagsContextValue }, children));
}
TestProvider.displayName = "TestProviderFlopFlip";
// src/toggle-feature.tsx
import {
ToggleFeature as SharedToggleFeature
} from "@flopflip/react";
import React6 from "react";
function ToggleFeature(_a) {
var _b = _a, {
flag,
variation
} = _b, remainingProps = __objRest(_b, [
"flag",
"variation"
]);
const isFeatureEnabled = useFeatureToggle(flag, variation);
return /* @__PURE__ */ React6.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 {
selectAdapterConfigurationStatus,
useAdapterContext as useAdapterContext3
} from "@flopflip/react";
import { useDebugValue as useDebugValue2 } from "react";
function useAdapterStatus({ adapterIdentifiers: adapterIdentifiers2 } = {}) {
const { status } = useAdapterContext3();
const adapterStatus = selectAdapterConfigurationStatus(
status,
adapterIdentifiers2
);
useDebugValue2({ adapterStatus });
return adapterStatus;
}
// src/use-all-feature-toggles.ts
import { useAdapterContext as useAdapterContext4 } from "@flopflip/react";
function useAllFeatureToggles() {
const adapterContext = useAdapterContext4();
const flagsContext = useFlagsContext();
const reversedAdapterEffectIdentifiers = [
...adapterContext.adapterEffectIdentifiers
].reverse();
return reversedAdapterEffectIdentifiers.reduce(
(_allFlags, adapterIdentifier) => __spreadValues(__spreadValues({}, _allFlags), flagsContext[adapterIdentifier]),
{}
);
}
// src/use-feature-toggles.ts
import { getIsFeatureEnabled as getIsFeatureEnabled2, useAdapterContext as useAdapterContext5 } from "@flopflip/react";
function useFeatureToggles(flags) {
const adapterContext = useAdapterContext5();
const flagsContext = useFlagsContext();
const requestedFlags = Object.entries(flags).reduce(
(previousFlags, [flagName, flagVariation]) => {
const isFeatureEnabled = getIsFeatureEnabled2(
flagsContext,
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,
ReconfigureAdapter as ReconfigureFlopFlip,
TestProvider as TestProviderFlopFlip,
ToggleFeature,
branchOnFeatureToggle,
injectFeatureToggle,
injectFeatureToggles,
useAdapterReconfiguration,
useAdapterStatus,
useAllFeatureToggles,
useFeatureToggle,
useFeatureToggles,
useFlagVariation,
useFlagVariations,
version
};
//# sourceMappingURL=index.js.map