Skip to content

Commit 7aac0a3

Browse files
authored
feat(snaps):Add disabled state for Snap UI interactive components (#29896)
## **Description** This PR integrates new Snaps UI feature for disabling interactive UI components. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29896?quickstart=1) ## **Related issues** Fixes: #29669 ## **Related Pull Requests** MetaMask/snaps#3030 ## **Manual testing steps** 1. Make new Snap with custom UI using interactive UI components specified in the task linked under "related issues". 2. Add flag `disabled={true}` to these components. 3. Check that components with `disabled` flag are not clickable and their styling is different (opacity 0.5). ## **Screenshots/Recordings** ### **Before** `disabled` state was not available before, nothing to show here. ### **After** ![Screenshot 2025-01-24 at 16 35 56](https://github.com/user-attachments/assets/b7f55722-9865-4ec6-8069-6dfb2c13b354) https://github.com/user-attachments/assets/5c8a0404-a7d6-49f1-8e8d-041daaa3b09b ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
1 parent d53d2a3 commit 7aac0a3

File tree

16 files changed

+91
-9
lines changed

16 files changed

+91
-9
lines changed

ui/components/app/snaps/snap-ui-checkbox/snap-ui-checkbox.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type SnapUICheckboxProps = {
2222
label?: string;
2323
error?: string;
2424
form?: string;
25+
disabled?: boolean;
2526
};
2627

2728
export const SnapUICheckbox: FunctionComponent<SnapUICheckboxProps> = ({
@@ -31,6 +32,7 @@ export const SnapUICheckbox: FunctionComponent<SnapUICheckboxProps> = ({
3132
label,
3233
error,
3334
form,
35+
disabled,
3436
...props
3537
}) => {
3638
const { handleInputChange, getValue } = useSnapInterfaceContext();
@@ -65,6 +67,7 @@ export const SnapUICheckbox: FunctionComponent<SnapUICheckboxProps> = ({
6567
value={value}
6668
onLabel={label}
6769
offLabel={label}
70+
disabled={disabled}
6871
{...props}
6972
/>
7073
) : (
@@ -75,6 +78,7 @@ export const SnapUICheckbox: FunctionComponent<SnapUICheckboxProps> = ({
7578
inputProps={{
7679
borderColor: BorderColor.borderMuted,
7780
}}
81+
isDisabled={disabled}
7882
{...props}
7983
/>
8084
)}

ui/components/app/snaps/snap-ui-dropdown/snap-ui-dropdown.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ export type SnapUIDropdownProps = {
1919
error?: string;
2020
options: { name: string; value: string }[];
2121
form?: string;
22+
disabled?: boolean;
2223
};
2324

2425
export const SnapUIDropdown: FunctionComponent<SnapUIDropdownProps> = ({
2526
name,
2627
label,
2728
error,
2829
form,
30+
disabled,
2931
...props
3032
}) => {
3133
const { handleInputChange, getValue } = useSnapInterfaceContext();
@@ -61,6 +63,7 @@ export const SnapUIDropdown: FunctionComponent<SnapUIDropdownProps> = ({
6163
style={{
6264
border: '1px solid var(--color-border-muted)',
6365
}}
66+
disabled={disabled}
6467
{...props}
6568
/>
6669
{error && (

ui/components/app/snaps/snap-ui-file-input/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
&__file-input {
33
&__drop-zone {
44
background-color: var(--color-background-alternative);
5+
cursor: pointer;
56

67
.mm-icon,
78
.mm-text {

ui/components/app/snaps/snap-ui-file-input/snap-ui-file-input.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export type SnapUIFileInputProps = {
4242
compact?: boolean;
4343
error?: boolean;
4444
helpText?: string;
45+
disabled?: boolean;
4546
};
4647

4748
/**
@@ -65,6 +66,7 @@ export type SnapUIFileInputProps = {
6566
* has an error, the help text is displayed in red.
6667
* @param props.helpText - The help text of the file input, which is displayed
6768
* below the file input field.
69+
* @param props.disabled - Whether the file input is disabled.
6870
* @returns A file input element.
6971
*/
7072
export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
@@ -75,6 +77,7 @@ export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
7577
compact,
7678
error,
7779
helpText,
80+
disabled,
7881
}) => {
7982
const t = useI18nContext();
8083
const { handleFileChange } = useSnapInterfaceContext();
@@ -126,6 +129,7 @@ export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
126129
onChange={handleChange}
127130
accept={accept?.join(',')}
128131
hidden={true}
132+
disabled={disabled}
129133
/>
130134
</>
131135
);
@@ -167,6 +171,7 @@ export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
167171
borderRadius={BorderRadius.MD}
168172
onClick={handleClick}
169173
ariaLabel={t('uploadFile')}
174+
disabled={disabled}
170175
/>
171176
{footer}
172177
</Box>
@@ -183,7 +188,10 @@ export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
183188
>
184189
{header}
185190
<Box
186-
className="snap-ui-renderer__file-input__drop-zone"
191+
className={classnames('snap-ui-renderer__file-input__drop-zone', {
192+
'snap-ui-snap-ui-renderer__file-input__drop-zone--disabled':
193+
disabled === true,
194+
})}
187195
display={Display.Flex}
188196
flexDirection={FlexDirection.Row}
189197
justifyContent={JustifyContent.center}
@@ -197,7 +205,6 @@ export const SnapUIFileInput: FunctionComponent<SnapUIFileInputProps> = ({
197205
borderWidth={1}
198206
borderRadius={BorderRadius.MD}
199207
style={{
200-
cursor: 'pointer',
201208
backgroundColor: active
202209
? 'var(--color-background-default-hover)'
203210
: 'var(--color-background-default)',

ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type SnapUIInputProps = {
1717

1818
export const SnapUIInput: FunctionComponent<
1919
SnapUIInputProps & FormTextFieldProps<'div'>
20-
> = ({ name, form, label, ...props }) => {
20+
> = ({ name, form, label, disabled, ...props }) => {
2121
const { handleInputChange, getValue, focusedInput, setCurrentFocusedInput } =
2222
useSnapInterfaceContext();
2323

@@ -63,6 +63,7 @@ export const SnapUIInput: FunctionComponent<
6363
value={value}
6464
onChange={handleChange}
6565
label={label}
66+
disabled={disabled}
6667
{...props}
6768
/>
6869
);

ui/components/app/snaps/snap-ui-radio-group/snap-ui-radio-group.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,27 @@ import {
1515
Text,
1616
} from '../../../component-library';
1717

18-
export type SnapUIRadioOption = { value: string; name: string };
18+
export type SnapUIRadioOption = {
19+
value: string;
20+
name: string;
21+
disabled: boolean;
22+
};
1923

2024
export type SnapUIRadioGroupProps = {
2125
name: string;
2226
label?: string;
2327
error?: string;
2428
options: SnapUIRadioOption[];
2529
form?: string;
30+
disabled?: boolean;
2631
};
2732

2833
export const SnapUIRadioGroup: FunctionComponent<SnapUIRadioGroupProps> = ({
2934
name,
3035
label,
3136
error,
3237
form,
38+
disabled,
3339
...props
3440
}) => {
3541
const { handleInputChange, getValue } = useSnapInterfaceContext();
@@ -61,8 +67,13 @@ export const SnapUIRadioGroup: FunctionComponent<SnapUIRadioGroupProps> = ({
6167
checked={value === option.value}
6268
onChange={() => handleChange(option.value)}
6369
style={{ margin: '0' }} // radio buttons have default margins that need to be stripped to ensure proper centering
70+
disabled={disabled || option.disabled}
6471
/>
6572
<Text
73+
className={classnames({
74+
'snap-ui-renderer__radio-label--disabled':
75+
disabled || option.disabled,
76+
})}
6677
as="label"
6778
htmlFor={option.name}
6879
variant={TextVariant.bodyMd}

ui/components/app/snaps/snap-ui-renderer/components/checkbox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const checkbox: UIComponentFactory<CheckboxElement> = ({
1111
name: element.props.name,
1212
label: element.props.label,
1313
variant: element.props.variant,
14+
disabled: element.props.disabled,
1415
form,
1516
},
1617
});

ui/components/app/snaps/snap-ui-renderer/components/dropdown.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ export const dropdown: UIComponentFactory<DropdownElement> = ({
1212
const options = children.map((child) => ({
1313
value: child.props.value,
1414
name: child.props.children,
15+
disabled: child.props.disabled,
1516
}));
1617

1718
return {
1819
element: 'SnapUIDropdown',
1920
props: {
2021
id: element.props.name,
2122
name: element.props.name,
23+
disabled: element.props.disabled,
2224
form,
2325
options,
2426
},

ui/components/app/snaps/snap-ui-renderer/components/field.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const field: UIComponentFactory<FieldElement> = ({
4040
form,
4141
error: element.props.error !== undefined,
4242
helpText: element.props.error,
43+
disabled: child.props.disabled,
4344
},
4445
};
4546
}
@@ -85,6 +86,7 @@ export const field: UIComponentFactory<FieldElement> = ({
8586
form,
8687
error: element.props.error !== undefined,
8788
helpText: element.props.error,
89+
disabled: child.props.disabled,
8890
},
8991
propComponents: {
9092
startAccessory: leftAccessoryMapped && {
@@ -119,6 +121,7 @@ export const field: UIComponentFactory<FieldElement> = ({
119121
name: dropdown.props.name,
120122
form,
121123
error: element.props.error,
124+
disabled: child.props.disabled,
122125
},
123126
};
124127
}
@@ -137,6 +140,7 @@ export const field: UIComponentFactory<FieldElement> = ({
137140
name: radioGroup.props.name,
138141
form,
139142
error: element.props.error,
143+
disabled: child.props.disabled,
140144
},
141145
};
142146
}
@@ -153,6 +157,7 @@ export const field: UIComponentFactory<FieldElement> = ({
153157
fieldLabel: element.props.label,
154158
form,
155159
error: element.props.error,
160+
disabled: child.props.disabled,
156161
},
157162
};
158163
}
@@ -171,6 +176,7 @@ export const field: UIComponentFactory<FieldElement> = ({
171176
label: element.props.label,
172177
form,
173178
error: element.props.error,
179+
disabled: child.props.disabled,
174180
},
175181
};
176182
}

ui/components/app/snaps/snap-ui-renderer/components/file-input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const fileInput: UIComponentFactory<FileInputElement> = ({
1111
name: element.props.name,
1212
accept: element.props.accept,
1313
compact: element.props.compact,
14+
disabled: element.props.disabled,
1415
form,
1516
},
1617
});

0 commit comments

Comments
 (0)