@carbon/ibm-products
Version:
Carbon for IBM Products
149 lines (147 loc) • 5.75 kB
JavaScript
/**
* Copyright IBM Corp. 2020, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const require_runtime = require("../../_virtual/_rolldown/runtime.js");
const require_props_helper = require("../../global/js/utils/props-helper.js");
let react = require("react");
react = require_runtime.__toESM(react);
let prop_types = require("prop-types");
prop_types = require_runtime.__toESM(prop_types);
let _carbon_feature_flags = require("@carbon/feature-flags");
//#region src/components/FeatureFlags/index.tsx
/**
* Copyright IBM Corp. 2024, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
_carbon_feature_flags.FeatureFlags.merge({
"default-portal-target-body": true,
"enable-datagrid-useInlineEdit": false,
"enable-datagrid-useEditableCell": false,
"enable-datagrid-useCustomizeColumns": false,
"ExampleComponent.secondaryIcon": false,
"ExampleComponent.useExample": false,
"enable-test-flag-a": false,
"enable-test-flag-b": true,
enableSidepanelResizer: false
});
/**
* Our FeatureFlagContext is used alongside the FeatureFlags component to enable
* or disable feature flags in a given React tree
*/
const FeatureFlagContext = (0, react.createContext)(_carbon_feature_flags.FeatureFlags);
/**
* Supports an object of feature flag values with the `flags` prop, merging them
* along with the current `FeatureFlagContext` to provide consumers to check if
* a feature flag is enabled or disabled in a given React tree
*/
function FeatureFlags({ children, flags = {}, defaultPortalTargetBody = true, enableDatagridUseInlineEdit = false, enableDatagridUseEditableCell = false, enableDatagridUseCustomizeColumns = false, enableSidepanelResizer = false, enableTestFlagA = false, enableTestFlagB = false }) {
const parentScope = (0, react.useContext)(FeatureFlagContext);
const [prevParentScope, setPrevParentScope] = (0, react.useState)(parentScope);
const combinedFlags = {
"default-portal-target-body": defaultPortalTargetBody,
"enable-datagrid-useInlineEdit": enableDatagridUseInlineEdit,
"enable-datagrid-useEditableCell": enableDatagridUseEditableCell,
"enable-datagrid-useCustomizeColumns": enableDatagridUseCustomizeColumns,
enableSidepanelResizer,
"enable-test-flag-a": enableTestFlagA,
"enable-test-flag-b": enableTestFlagB,
...flags
};
const [scope, updateScope] = (0, react.useState)(() => {
const scope = (0, _carbon_feature_flags.createScope)(combinedFlags);
scope.mergeWithScope(parentScope);
return scope;
});
if (parentScope !== prevParentScope) {
const scope = (0, _carbon_feature_flags.createScope)(combinedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
setPrevParentScope(parentScope);
}
useChangedValue(combinedFlags, isEqual, (changedFlags) => {
const scope = (0, _carbon_feature_flags.createScope)(changedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
});
return /* @__PURE__ */ react.default.createElement(FeatureFlagContext.Provider, { value: scope }, children);
}
FeatureFlags.propTypes = {
children: prop_types.default.node,
/**
* Provide the feature flags to enabled or disabled in the current React tree
*/
defaultPortalTargetBody: prop_types.default.bool,
enableDatagridUseCustomizeColumns: prop_types.default.bool,
enableDatagridUseEditableCell: prop_types.default.bool,
enableDatagridUseInlineEdit: prop_types.default.bool,
enableSidepanelResizer: prop_types.default.bool,
enableTestFlagA: prop_types.default.bool,
enableTestFlagB: prop_types.default.bool,
flags: require_props_helper.deprecateProp(prop_types.default.objectOf(prop_types.default.bool), "The `flags` prop for `FeatureFlag` has been deprecated. Please pass the flags directly as props in camelCase")
};
/**
* This hook will store previous versions of the given `value` and compare the
* current value to the previous one using the `compare` function. If the
* compare function returns true, then the given `callback` is invoked in an
* effect.
*
* @param {any} value
* @param {Function} compare
* @param {Function} callback
*/
function useChangedValue(value, compare, callback) {
const initialRender = (0, react.useRef)(false);
const savedCallback = (0, react.useRef)(callback);
const [prevValue, setPrevValue] = (0, react.useState)(value);
if (!compare(prevValue, value)) setPrevValue(value);
(0, react.useEffect)(() => {
savedCallback.current = callback;
});
(0, react.useEffect)(() => {
if (initialRender.current) savedCallback.current(prevValue);
}, [prevValue]);
(0, react.useEffect)(() => {
initialRender.current = true;
}, []);
}
/**
* Access whether a given flag is enabled or disabled in a given
* FeatureFlagContext
*
* @returns {boolean}
*/
function useFeatureFlag(flag) {
return (0, react.useContext)(FeatureFlagContext).enabled(flag);
}
/**
* Access all feature flag information for the given FeatureFlagContext
*
* @returns {FeatureFlagScope}
*/
function useFeatureFlags() {
return (0, react.useContext)(FeatureFlagContext);
}
/**
* Compare two objects and determine if they are equal. This is a shallow
* comparison since the objects we are comparing are objects with boolean flags
* from the flags prop in the `FeatureFlags` component
*
* @param {object} a
* @param {object} b
* @returns {boolean}
*/
function isEqual(a, b) {
if (a === b) return true;
for (const key of Object.keys(a)) if (a[key] !== b[key]) return false;
for (const key of Object.keys(b)) if (b[key] !== a[key]) return false;
return true;
}
//#endregion
exports.FeatureFlags = FeatureFlags;
exports.useFeatureFlag = useFeatureFlag;
exports.useFeatureFlags = useFeatureFlags;