@devcycle/react-client-sdk
Version:
The DevCycle React SDK used for feature management.
246 lines (228 loc) • 9.21 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
var jsClientSdk = require('@devcycle/js-client-sdk');
var hoistNonReactStatics = require('hoist-non-react-statics');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var hoistNonReactStatics__default = /*#__PURE__*/_interopDefaultLegacy(hoistNonReactStatics);
const context = react.createContext(undefined);
const { Provider, Consumer } = context;
const initializedContext = react.createContext({
isInitialized: false,
});
const debugContextDefaults = {
showConditionalBorders: false,
borderColor: '#ff6347',
};
const debugContext = react.createContext(debugContextDefaults);
const initializeDevCycleClient = (sdkKey, user = { isAnonymous: true }, options) => {
if (options === null || options === void 0 ? void 0 : options.deferInitialization) {
return jsClientSdk.initializeDevCycle(sdkKey, {
sdkPlatform: 'react',
...options,
deferInitialization: true, // make typescript happy
bootstrapConfig: undefined,
});
}
return jsClientSdk.initializeDevCycle(sdkKey, user, {
sdkPlatform: 'react',
...options,
});
};
/**
* @deprecated Use the `useIsDevCycleInitialized` hook to block rendering of your application
* until SDK initialization is complete
*/
async function asyncWithDVCProvider(config) {
const { user, options } = config;
let sdkKey;
if ('sdkKey' in config) {
sdkKey = config.sdkKey;
}
else {
sdkKey = config.envKey;
}
if (!sdkKey) {
throw new Error('You must provide a sdkKey to asyncWithDVCProvider');
}
const client = initializeDevCycleClient(sdkKey, user, options);
await client.onClientInitialized();
return ({ children }) => {
return jsxRuntime.jsx(Provider, { value: { client }, children: children });
};
}
const useDevCycleClient = () => {
const dvcContext = react.useContext(context);
if (dvcContext === undefined)
throw new Error('useDevCycleClient must be used within DevCycleProvider');
// enforce the variable and custom data types provided by the user. These are for type-checking only.
return dvcContext.client;
};
/**
* @deprecated use useDevCycleClient instead
*/
const useDVCClient = useDevCycleClient;
const useVariable = (key, defaultValue) => {
const dvcContext = react.useContext(context);
const [_, forceRerender] = react.useState({});
const forceRerenderCallback = react.useCallback(() => forceRerender({}), []);
if (dvcContext === undefined)
throw new Error('useVariable must be used within DevCycleProvider');
react.useEffect(() => {
dvcContext.client.subscribe(`variableUpdated:${key}`, forceRerenderCallback);
return () => {
dvcContext.client.unsubscribe(`variableUpdated:${key}`, forceRerenderCallback);
};
}, [dvcContext, key, forceRerenderCallback]);
return dvcContext.client.variable(key, defaultValue);
};
const useVariableValue = (key, defaultValue) => {
return useVariable(key, defaultValue).value;
};
function DevCycleProvider(props) {
var _a, _b;
const { config } = props;
const { user, options } = config;
const [isInitialized, setIsInitialized] = react.useState(false);
let sdkKey;
if ('sdkKey' in config) {
sdkKey = config.sdkKey;
}
else {
sdkKey = config.envKey;
}
if (!sdkKey) {
throw new Error('You must provide a sdkKey to DevCycleProvider');
}
const clientRef = react.useRef();
const [_, forceRerender] = react.useState({});
if (clientRef.current === undefined) {
clientRef.current = initializeDevCycleClient(sdkKey, user, {
...options,
});
}
react.useEffect(() => {
if (clientRef.current === undefined) {
clientRef.current = initializeDevCycleClient(sdkKey, user, {
...options,
});
// react doesn't know the effect changed the ref, make sure it re-renders
forceRerender({});
}
clientRef.current
.onClientInitialized()
.then(() => {
setIsInitialized(true);
})
.catch(() => {
// set to true to unblock app load
console.log('Error initializing DevCycle.');
setIsInitialized(true);
});
return () => {
var _a;
void ((_a = clientRef.current) === null || _a === void 0 ? void 0 : _a.close());
clientRef.current = undefined;
};
}, [sdkKey, user, options]);
const mergedDebugOptions = Object.assign({}, debugContextDefaults, (_b = (_a = props.config.options) === null || _a === void 0 ? void 0 : _a.reactDebug) !== null && _b !== void 0 ? _b : {});
return (jsxRuntime.jsx(Provider, { value: { client: clientRef.current }, children: jsxRuntime.jsx(initializedContext.Provider, { value: {
isInitialized: isInitialized || clientRef.current.isInitialized,
}, children: jsxRuntime.jsx(debugContext.Provider, { value: mergedDebugOptions, children: props.children }) }) }));
}
/**
* @deprecated Use DevCycleProvider instead
*/
const DVCProvider = DevCycleProvider;
function withDevCycleProvider(config) {
return function (WrappedComponent) {
const HoistedComponent = react.forwardRef((props, ref) => {
return (jsxRuntime.jsx(DevCycleProvider, { config: config, children: jsxRuntime.jsx(WrappedComponent, { ...props, ref: ref }) }));
});
hoistNonReactStatics__default["default"](HoistedComponent, WrappedComponent);
return HoistedComponent;
};
}
/**
* @deprecated Use withDevCycleProvider instead
*/
const withDVCProvider = withDevCycleProvider;
/**
*
* @deprecated Use the `useVariable` hook instead
*
*/
const useDVCVariable = (key, defaultValue) => {
return useVariable(key, defaultValue);
};
const useIsDevCycleInitialized = () => {
const context = react.useContext(initializedContext);
if (context === undefined)
throw new Error('useIsDevCycleInitialized must be used within DevCycleProvider');
return context.isInitialized;
};
/**
* @deprecated use useIsDevCycleInitialized instead
*/
const useIsDVCInitialized = useIsDevCycleInitialized;
const RenderIfEnabled = (props) => {
let targetValue;
let defaultValue;
if ('targetValue' in props) {
targetValue = props.targetValue;
defaultValue = props.defaultValue;
}
else {
targetValue = true;
defaultValue = false;
}
const variableValue = useVariableValue(props.variableKey, defaultValue);
const debugSettings = react.useContext(debugContext);
if (variableValue === targetValue) {
if (debugSettings.showConditionalBorders) {
return (jsxRuntime.jsxs("div", { style: {
border: `2px solid ${debugSettings.borderColor}`,
position: 'relative',
}, className: `devcycle-conditional-border devcycle-conditional-border-${props.variableKey}`, children: [jsxRuntime.jsxs("a", { style: {
position: 'absolute',
cursor: 'pointer',
right: '-2px',
top: '-2.5rem',
color: 'white',
fontSize: '1.5rem',
padding: '2px 5px',
backgroundColor: `${debugSettings.borderColor}`,
}, target: '_blank', href: `https://app.devcycle.com/r/variables/${props.variableKey}`, rel: "noreferrer", children: [props.variableKey, ": ", JSON.stringify(variableValue)] }), props.children] }));
}
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.children });
}
return null;
};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const SwapComponents = (OldComponent, NewComponent, variableKey) => {
const DevCycleConditionalComponent = (props) => {
const variableValue = useVariableValue(variableKey, false);
if (variableValue) {
return jsxRuntime.jsx(NewComponent, { ...props });
}
else {
return jsxRuntime.jsx(OldComponent, { ...props });
}
};
return DevCycleConditionalComponent;
};
exports.DVCProvider = DVCProvider;
exports.DevCycleProvider = DevCycleProvider;
exports.RenderIfEnabled = RenderIfEnabled;
exports.SwapComponents = SwapComponents;
exports.asyncWithDVCProvider = asyncWithDVCProvider;
exports.useDVCClient = useDVCClient;
exports.useDVCVariable = useDVCVariable;
exports.useDevCycleClient = useDevCycleClient;
exports.useIsDVCInitialized = useIsDVCInitialized;
exports.useIsDevCycleInitialized = useIsDevCycleInitialized;
exports.useVariable = useVariable;
exports.useVariableValue = useVariableValue;
exports.withDVCProvider = withDVCProvider;
exports.withDevCycleProvider = withDevCycleProvider;