Skip to content

Commit fdb3f04

Browse files
2nikhiltomtay1orjonesheloiseluikennylam
authored
feat(FileUploader): add enhanced callbacks with feature flag (#20005)
* feat(FileUploader): add enhanced callbacks with feature flag * fix: use crypto.getRandomValues * test: adds test * chore: snapshots * refactor: fix import --------- Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com> Co-authored-by: kennylam <909118+kennylam@users.noreply.github.com>
1 parent 936bbf7 commit fdb3f04

File tree

9 files changed

+601
-53
lines changed

9 files changed

+601
-53
lines changed

packages/feature-flags/feature-flags.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,9 @@ feature-flags:
5858
description: >
5959
Enable a reduced spacing between the toggle control and its label
6060
enabled: false
61+
- name: enable-enhanced-file-uploader
62+
description: >
63+
Enable enhanced functionality for the FileUploader component, including
64+
richer callback data and expanded trigger events for onChange and
65+
onDelete.
66+
enabled: false

packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3470,6 +3470,9 @@ Map {
34703470
"enableDialogElement": {
34713471
"type": "bool",
34723472
},
3473+
"enableEnhancedFileUploader": {
3474+
"type": "bool",
3475+
},
34733476
"enableExperimentalFocusWrapWithoutSentinels": {
34743477
"type": "bool",
34753478
},
@@ -3565,7 +3568,9 @@ Map {
35653568
"args": [
35663569
[
35673570
"sm",
3571+
"small",
35683572
"md",
3573+
"field",
35693574
"lg",
35703575
],
35713576
],
@@ -10426,6 +10431,9 @@ Map {
1042610431
"enableDialogElement": {
1042710432
"type": "bool",
1042810433
},
10434+
"enableEnhancedFileUploader": {
10435+
"type": "bool",
10436+
},
1042910437
"enableExperimentalFocusWrapWithoutSentinels": {
1043010438
"type": "bool",
1043110439
},

packages/react/src/components/FeatureFlags/__tests__/FeatureFlags-test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,5 +633,58 @@ describe('FeatureFlags', () => {
633633
enableV12DynamicFloatingStyles: true,
634634
});
635635
});
636+
it('enable-enhanced-file-uploader - enableEnhancedFileUploader', () => {
637+
const checkFlags = jest.fn();
638+
const checkFlag = jest.fn();
639+
640+
function TestComponent() {
641+
const featureFlags = useFeatureFlags();
642+
const enableEnhancedFileUploader = useFeatureFlag(
643+
'enable-enhanced-file-uploader'
644+
);
645+
646+
checkFlags({
647+
enableEnhancedFileUploader: featureFlags.enabled(
648+
'enable-enhanced-file-uploader'
649+
),
650+
});
651+
652+
checkFlag({
653+
enableEnhancedFileUploader,
654+
});
655+
656+
return null;
657+
}
658+
659+
// Render the default
660+
const { rerender } = render(
661+
<FeatureFlags>
662+
<TestComponent />
663+
</FeatureFlags>
664+
);
665+
666+
// Ensure the default value is as defined and as expected
667+
expect(checkFlags).toHaveBeenLastCalledWith({
668+
enableEnhancedFileUploader: false,
669+
});
670+
expect(checkFlag).toHaveBeenLastCalledWith({
671+
enableEnhancedFileUploader: false,
672+
});
673+
674+
// Enable the flag
675+
rerender(
676+
<FeatureFlags enableEnhancedFileUploader>
677+
<TestComponent />
678+
</FeatureFlags>
679+
);
680+
681+
// Ensure that when enabled, this flag is true and does not error
682+
expect(checkFlags).toHaveBeenLastCalledWith({
683+
enableEnhancedFileUploader: true,
684+
});
685+
expect(checkFlag).toHaveBeenLastCalledWith({
686+
enableEnhancedFileUploader: true,
687+
});
688+
});
636689
});
637690
});

packages/react/src/components/FeatureFlags/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface FeatureFlagsProps {
3131
enableExperimentalFocusWrapWithoutSentinels?: boolean;
3232
enableDialogElement?: boolean;
3333
enableV12DynamicFloatingStyles?: boolean;
34+
enableEnhancedFileUploader?: boolean;
3435
}
3536
/**
3637
* Our FeatureFlagContext is used alongside the FeatureFlags component to enable
@@ -53,6 +54,7 @@ function FeatureFlags({
5354
enableExperimentalFocusWrapWithoutSentinels = false,
5455
enableDialogElement = false,
5556
enableV12DynamicFloatingStyles = false,
57+
enableEnhancedFileUploader = false,
5658
}: FeatureFlagsProps): JSX.Element {
5759
const parentScope = useContext(FeatureFlagContext);
5860
const [prevParentScope, setPrevParentScope] = useState(parentScope);
@@ -66,6 +68,7 @@ function FeatureFlags({
6668
enableExperimentalFocusWrapWithoutSentinels,
6769
'enable-dialog-element': enableDialogElement,
6870
'enable-v12-dynamic-floating-styles': enableV12DynamicFloatingStyles,
71+
'enable-enhanced-file-uploader': enableEnhancedFileUploader,
6972
...flags,
7073
};
7174
const [scope, updateScope] = useState(() => {
@@ -116,6 +119,7 @@ FeatureFlags.propTypes = {
116119
enableExperimentalFocusWrapWithoutSentinels: PropTypes.bool,
117120
enableDialogElement: PropTypes.bool,
118121
enableV12DynamicFloatingStyles: PropTypes.bool,
122+
enableEnhancedFileUploader: PropTypes.bool,
119123
};
120124

121125
/**

packages/react/src/components/FeatureFlags/overview.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ in the Carbon monorepo.
5656
| `enable-v12-structured-list-visible-icons` | Enable icon components within StructuredList to always be visible | `false` | || [enable-v12-structured-list-visible-icons](https://github.com/carbon-design-system/carbon/tree/main/packages/upgrade#enable-v12-structured-list-visible-icons) |
5757
| `enable-v12-dynamic-floating-styles` | Enable dynamic setting of floating styles for components like Popover, Tooltip, etc. | `false` || | No - App level |
5858
| `enable-v12-toggle-reduced-label-spacing` | Enable a reduced spacing between the toggle control and its label | `false` | || No - Style only |
59+
| `enable-enhanced-file-uploader` | Enable enhanced FileUploader callbacks with richer data and expanded triggers. | `false` || | No - Config only |
5960

6061

6162
## Turning on feature flags in Javascript/react
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Meta } from '@storybook/addon-docs/blocks';
2+
3+
<Meta title="Components/FileUploader/Feature Flag" name="Flag details" />
4+
5+
# Enhanced FileUploader Callbacks
6+
7+
The `enable-enhanced-file-uploader` flag enables enhanced functionality for the
8+
FileUploader component, including richer callback data and expanded trigger
9+
events for `onChange` and `onDelete`.
10+
11+
When this flag is enabled, the `onChange` callback is consistently triggered for
12+
all file list modifications (additions, deletions, programmatic clears), and both
13+
`onChange` and `onDelete` events are augmented with detailed file information
14+
like `deletedFile`, `addedFiles`, and `currentFiles` on `event.target`.
15+
16+
## Enable enhanced FileUploader callbacks
17+
18+
```js
19+
<FeatureFlags enableEnhancedFileUploader={true}>
20+
<FileUploader
21+
multiple
22+
filenameStatus="edit"
23+
onChange={(evt) => console.log('onChange', evt.target.action, evt.target.currentFiles)}
24+
onDelete={(evt) => console.log('onDelete', evt.target.deletedFile)}
25+
/>
26+
</FeatureFlags>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Copyright IBM Corp. 2016, 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React from 'react';
9+
import { FileUploader } from '../FileUploader';
10+
import { WithFeatureFlags } from '../../../.storybook/templates/WithFeatureFlags';
11+
12+
export default {
13+
title: 'Components/FileUploader/Feature Flag',
14+
component: FileUploader,
15+
tags: ['!autodocs'],
16+
decorators: [
17+
(Story) => (
18+
<WithFeatureFlags
19+
flags={{
20+
'enable-enhanced-file-uploader': true,
21+
}}>
22+
<Story />
23+
</WithFeatureFlags>
24+
),
25+
],
26+
};
27+
28+
export const EnhancedCallbacks = (args) => {
29+
const handleChange = (event, data) => {
30+
console.log(' Action:', event.target.action);
31+
32+
if (event.target.addedFiles) {
33+
console.log(
34+
' Added Files:',
35+
event.target.addedFiles.map((f) => ({ name: f.name, uuid: f.uuid }))
36+
);
37+
}
38+
39+
if (event.target.deletedFile) {
40+
console.log(' Deleted File:', {
41+
name: event.target.deletedFile.name,
42+
uuid: event.target.deletedFile.uuid,
43+
});
44+
}
45+
46+
if (event.target.clearedFiles) {
47+
console.log(
48+
' Cleared Files:',
49+
event.target.clearedFiles.map((f) => ({ name: f.name, uuid: f.uuid }))
50+
);
51+
}
52+
53+
console.log(
54+
' Current Files:',
55+
event.target.currentFiles?.map((f) => ({ name: f.name, uuid: f.uuid })) ||
56+
[]
57+
);
58+
};
59+
60+
const handleDelete = (event, data) => {
61+
console.log(' Deleted File Object:', event.target.deletedFile);
62+
console.log(' Deleted File Name:', event.target.deletedFile?.name);
63+
console.log(
64+
' Remaining Files:',
65+
event.target.remainingFiles?.map((f) => ({
66+
name: f.name,
67+
uuid: f.uuid,
68+
})) || []
69+
);
70+
};
71+
72+
return (
73+
<div>
74+
<FileUploader
75+
labelTitle="Enhanced FileUploader Demo"
76+
labelDescription="Open browser console to see detailed callback data when adding/removing files"
77+
buttonLabel="Add file(s)"
78+
buttonKind="primary"
79+
filenameStatus="edit"
80+
multiple={true}
81+
onChange={handleChange}
82+
onDelete={handleDelete}
83+
iconDescription="Remove uploaded file"
84+
{...args}
85+
/>
86+
</div>
87+
);
88+
};
89+
90+
EnhancedCallbacks.args = {
91+
disabled: false,
92+
};
93+
94+
EnhancedCallbacks.argTypes = {
95+
disabled: {
96+
control: {
97+
type: 'boolean',
98+
},
99+
},
100+
};

0 commit comments

Comments
 (0)