UNPKG

@devcycle/react-client-sdk

Version:

The DevCycle React SDK used for feature management.

246 lines (228 loc) 9.21 kB
'use strict'; 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;