diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
index ce3f5c07e529..7e05929b0d3b 100644
--- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
+++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
@@ -9814,6 +9814,24 @@ Map {
"children": Object {
"type": "node",
},
+ "enableExperimentalFocusWrapWithoutSentinels": Object {
+ "type": "bool",
+ },
+ "enableTreeviewControllable": Object {
+ "type": "bool",
+ },
+ "enableUseControlledStateWithValue": Object {
+ "type": "bool",
+ },
+ "enableV12Overflowmenu": Object {
+ "type": "bool",
+ },
+ "enableV12TileDefaultIcons": Object {
+ "type": "bool",
+ },
+ "enableV12TileRadioIcons": Object {
+ "type": "bool",
+ },
"flags": Object {
"args": Array [
Object {
diff --git a/packages/react/src/components/FeatureFlags/__tests__/FeatureFlags-test.js b/packages/react/src/components/FeatureFlags/__tests__/FeatureFlags-test.js
index 0b423bc56490..cb95de54b7c2 100644
--- a/packages/react/src/components/FeatureFlags/__tests__/FeatureFlags-test.js
+++ b/packages/react/src/components/FeatureFlags/__tests__/FeatureFlags-test.js
@@ -71,6 +71,46 @@ describe('FeatureFlags', () => {
});
});
+ it('should provide access to the feature flags for a scope', () => {
+ const checkFlags = jest.fn();
+ const checkFlag = jest.fn();
+
+ function TestComponent() {
+ const featureFlags = useFeatureFlags();
+ const flag1 = useFeatureFlag('enable-v12-overflowmenu');
+ const flag2 = useFeatureFlag('enable-treeview-controllable');
+
+ checkFlags({
+ enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
+ enableTreeviewControllable: featureFlags.enabled(
+ 'enable-treeview-controllable'
+ ),
+ });
+
+ checkFlag({
+ enableV12Overflowmenu: flag1,
+ enableTreeviewControllable: flag2,
+ });
+
+ return null;
+ }
+
+ render(
+
+
+
+ );
+
+ expect(checkFlags).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: true,
+ enableTreeviewControllable: false,
+ });
+ expect(checkFlag).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: true,
+ enableTreeviewControllable: false,
+ });
+ });
+
it('should re-render when flags change', () => {
const checkFlags = jest.fn();
const checkFlag = jest.fn();
@@ -124,6 +164,94 @@ describe('FeatureFlags', () => {
});
});
+ it('should handle boolean props correctly when no flags object is provided', () => {
+ const checkFlags = jest.fn();
+ const checkFlag = jest.fn();
+
+ function TestComponent() {
+ const featureFlags = useFeatureFlags();
+ const enableV12Overflowmenu = useFeatureFlag('enable-v12-overflowmenu');
+ const enableTreeviewControllable = useFeatureFlag(
+ 'enable-treeview-controllable'
+ );
+
+ checkFlags({
+ enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
+ enableTreeviewControllable: featureFlags.enabled(
+ 'enable-treeview-controllable'
+ ),
+ });
+
+ checkFlag({
+ enableV12Overflowmenu,
+ enableTreeviewControllable,
+ });
+
+ return null;
+ }
+
+ render(
+
+
+
+ );
+
+ expect(checkFlags).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: true,
+ enableTreeviewControllable: false,
+ });
+ expect(checkFlag).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: true,
+ enableTreeviewControllable: false,
+ });
+ });
+
+ it('should handle boolean props and flags object with no overlapping keys', () => {
+ const checkFlags = jest.fn();
+ const checkFlag = jest.fn();
+
+ function TestComponent() {
+ const featureFlags = useFeatureFlags();
+ const enableV12Overflowmenu = useFeatureFlag('enable-v12-overflowmenu');
+ const enableExperimentalFocusWrapWithoutSentinels = useFeatureFlag(
+ 'enable-experimental-focus-wrap-without-sentinels'
+ );
+
+ checkFlags({
+ enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
+ enableExperimentalFocusWrapWithoutSentinels: featureFlags.enabled(
+ 'enable-experimental-focus-wrap-without-sentinels'
+ ),
+ });
+
+ checkFlag({
+ enableV12Overflowmenu,
+ enableExperimentalFocusWrapWithoutSentinels,
+ });
+
+ return null;
+ }
+
+ render(
+
+
+
+ );
+
+ expect(checkFlags).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: false,
+ enableExperimentalFocusWrapWithoutSentinels: true,
+ });
+ expect(checkFlag).toHaveBeenLastCalledWith({
+ enableV12Overflowmenu: false,
+ enableExperimentalFocusWrapWithoutSentinels: true,
+ });
+ });
+
it('should merge scopes and overwrite duplicate keys', () => {
GlobalFeatureFlags.add('global', true);
diff --git a/packages/react/src/components/FeatureFlags/index.js b/packages/react/src/components/FeatureFlags/index.js
index f8b00c764b4a..f5054e69343f 100644
--- a/packages/react/src/components/FeatureFlags/index.js
+++ b/packages/react/src/components/FeatureFlags/index.js
@@ -29,17 +29,37 @@ const FeatureFlagContext = createContext(GlobalFeatureFlags);
* 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 = {} }) {
+function FeatureFlags({
+ children,
+ flags = {},
+ enableUseControlledStateWithValue,
+ enableV12TileDefaultIcons,
+ enableV12TileRadioIcons,
+ enableV12Overflowmenu,
+ enableTreeviewControllable,
+ enableExperimentalFocusWrapWithoutSentinels,
+}) {
const parentScope = useContext(FeatureFlagContext);
const [prevParentScope, setPrevParentScope] = useState(parentScope);
+
+ const combinedFlags = {
+ 'enable-use-controlled-state-with-value': enableUseControlledStateWithValue,
+ 'enable-v12-tile-default-icons': enableV12TileDefaultIcons,
+ 'enable-v12-tile-radio-icons': enableV12TileRadioIcons,
+ 'enable-v12-overflowmenu': enableV12Overflowmenu,
+ 'enable-treeview-controllable': enableTreeviewControllable,
+ 'enable-experimental-focus-wrap-without-sentinels':
+ enableExperimentalFocusWrapWithoutSentinels,
+ ...flags,
+ };
const [scope, updateScope] = useState(() => {
- const scope = createScope(flags);
+ const scope = createScope(combinedFlags);
scope.mergeWithScope(parentScope);
return scope;
});
if (parentScope !== prevParentScope) {
- const scope = createScope(flags);
+ const scope = createScope(combinedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
setPrevParentScope(parentScope);
@@ -48,7 +68,7 @@ function FeatureFlags({ children, flags = {} }) {
// We use a custom hook to detect if any of the keys or their values change
// for flags that are passed in. If they have changed, then we re-create the
// FeatureFlagScope using the new flags
- useChangedValue(flags, isEqual, (changedFlags) => {
+ useChangedValue(combinedFlags, isEqual, (changedFlags) => {
const scope = createScope(changedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
@@ -68,6 +88,12 @@ FeatureFlags.propTypes = {
* Provide the feature flags to enabled or disabled in the current React tree
*/
flags: PropTypes.objectOf(PropTypes.bool),
+ enableUseControlledStateWithValue: PropTypes.bool,
+ enableV12TileDefaultIcons: PropTypes.bool,
+ enableV12TileRadioIcons: PropTypes.bool,
+ enableV12Overflowmenu: PropTypes.bool,
+ enableTreeviewControllable: PropTypes.bool,
+ enableExperimentalFocusWrapWithoutSentinels: PropTypes.bool,
};
/**