@flopflip/react-broadcast
Version:
A feature toggle wrapper to use LaunchDarkly with React
458 lines (376 loc) • 14.1 kB
JavaScript
;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');
// src/use-flags-context.ts
// src/flags-context.ts
var _types = require('@flopflip/types');
var createIntialFlagsContext = (adapterIdentifiers2, initialFlags) => Object.fromEntries(
Object.values(adapterIdentifiers2).map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
initialFlags
])
);
var FlagsContext = _react.createContext.call(void 0,
createIntialFlagsContext(_types.adapterIdentifiers, {})
);
// src/use-flags-context.ts
var useFlagsContext = () => _react.useContext.call(void 0, FlagsContext);
// src/use-feature-toggle.ts
function useFeatureToggle(flagName, flagVariation = true) {
const adapterContext = _react3.useAdapterContext.call(void 0, );
const flagsContext = useFlagsContext();
const isFeatureEnabled = _react3.getIsFeatureEnabled.call(void 0,
flagsContext,
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
var _shim = require('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 = _shim.useSyncExternalStore.call(void 0,
store.subscribe,
() => store.getSnapshot().flags,
() => store.getSnapshot().flags
);
const updateFlags = _react.useCallback.call(void 0,
(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 = _shim.useSyncExternalStore.call(void 0,
store.subscribe,
() => store.getSnapshot().status,
() => store.getSnapshot().status
);
const setStatus = _react.useCallback.call(void 0,
(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 = _react.useMemo.call(void 0, () => [adapter.id], [adapter.id]);
const [flags, updateFlags] = useFlagsState({ adapterIdentifiers: adapterIdentifiers2 });
const [status, updateStatus] = useStatusState({ adapterIdentifiers: adapterIdentifiers2 });
const getHasAdapterSubscriptionStatus = _react3.useAdapterSubscription.call(void 0, adapter);
const handleUpdateFlags = _react.useCallback.call(void 0,
(flagsChange) => {
if (getHasAdapterSubscriptionStatus(_types.AdapterSubscriptionStatus.Unsubscribed)) {
return;
}
updateFlags(flagsChange);
},
[updateFlags, getHasAdapterSubscriptionStatus]
);
const handleUpdateStatus = _react.useCallback.call(void 0,
(statusChange) => {
if (getHasAdapterSubscriptionStatus(_types.AdapterSubscriptionStatus.Unsubscribed)) {
return;
}
updateStatus(statusChange);
},
[updateStatus, getHasAdapterSubscriptionStatus]
);
return /* @__PURE__ */ _react2.default.createElement(FlagsContext.Provider, { value: flags }, /* @__PURE__ */ _react2.default.createElement(
_react3.ConfigureAdapter,
{
adapter,
adapterArgs,
adapterStatus: status,
defaultFlags,
shouldDeferAdapterConfiguration,
onFlagsStateChange: handleUpdateFlags,
onStatusStateChange: handleUpdateStatus
},
children
));
}
Configure.displayName = "ConfigureFlopflip";
// src/inject-feature-toggle.tsx
// src/use-flag-variations.ts
function useFlagVariations(flagNames) {
const adapterContext = _react3.useAdapterContext.call(void 0, );
const flagsContext = useFlagsContext();
const flagVariations = flagNames.map(
(requestedVariation) => _react3.getFlagVariation.call(void 0,
flagsContext,
adapterContext.adapterEffectIdentifiers,
requestedVariation
)
);
return flagVariations;
}
// src/inject-feature-toggle.tsx
function injectFeatureToggle(flagName, propKey = _react3.DEFAULT_FLAG_PROP_KEY) {
return (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
function injectFeatureToggles(flagNames, propKey = _react3.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__ */ _react2.default.createElement(Component, __spreadValues({}, props));
}
_react3.setDisplayName.call(void 0, _react3.wrapDisplayName.call(void 0, WrappedComponent, "injectFeatureToggles"));
return WrappedComponent;
};
}
// src/reconfigure.ts
// src/test-provider.tsx
var defaultProps = {
adapterIdentifiers: ["test"],
status: __spreadValues({}, Object.fromEntries(
Object.values(_types.adapterIdentifiers).map((adapterInterfaceIdentifier) => [
adapterInterfaceIdentifier,
{
subscriptionStatus: _types.AdapterSubscriptionStatus.Subscribed,
configurationStatus: _types.AdapterConfigurationStatus.Configured
}
])
))
};
function TestProvider({
adapterIdentifiers: adapterIdentifiers2 = defaultProps.adapterIdentifiers,
reconfigure,
flags,
children,
status = defaultProps.status
}) {
const adapterContextValue = _react3.createAdapterContext.call(void 0,
adapterIdentifiers2,
reconfigure,
status
);
const flagsContextValue = createIntialFlagsContext(
// @ts-expect-error Can not remember. Sorry to myself.
adapterIdentifiers2,
flags
);
return /* @__PURE__ */ _react2.default.createElement(_react3.AdapterContext.Provider, { value: adapterContextValue }, /* @__PURE__ */ _react2.default.createElement(FlagsContext.Provider, { value: flagsContextValue }, children));
}
TestProvider.displayName = "TestProviderFlopFlip";
// 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: adapterIdentifiers2 } = {}) {
const { status } = _react3.useAdapterContext.call(void 0, );
const adapterStatus = _react3.selectAdapterConfigurationStatus.call(void 0,
status,
adapterIdentifiers2
);
_react.useDebugValue.call(void 0, { adapterStatus });
return adapterStatus;
}
// src/use-all-feature-toggles.ts
function useAllFeatureToggles() {
const adapterContext = _react3.useAdapterContext.call(void 0, );
const flagsContext = useFlagsContext();
const reversedAdapterEffectIdentifiers = [
...adapterContext.adapterEffectIdentifiers
].reverse();
return reversedAdapterEffectIdentifiers.reduce(
(_allFlags, adapterIdentifier) => __spreadValues(__spreadValues({}, _allFlags), flagsContext[adapterIdentifier]),
{}
);
}
// src/use-feature-toggles.ts
function useFeatureToggles(flags) {
const adapterContext = _react3.useAdapterContext.call(void 0, );
const flagsContext = useFlagsContext();
const requestedFlags = Object.entries(flags).reduce(
(previousFlags, [flagName, flagVariation]) => {
const isFeatureEnabled = _react3.getIsFeatureEnabled.call(void 0,
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__";
exports.ConfigureFlopFlip = Configure; exports.ReconfigureFlopFlip = _react3.ReconfigureAdapter; exports.TestProviderFlopFlip = TestProvider; exports.ToggleFeature = ToggleFeature; exports.branchOnFeatureToggle = branchOnFeatureToggle; exports.injectFeatureToggle = injectFeatureToggle; exports.injectFeatureToggles = injectFeatureToggles; 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