Skip to content

Commit 898525b

Browse files
david0xdFrederikBolding
authored andcommitted
feat(snaps): Add background color prop to Snaps UI Container component (#29095)
This PR adds `backgroundColor` property to Container component. Background colors that can be used are predefined as: default and alternative. This PR deliberately disables the `backgroundColor` feature for containers used within Transaction Insights pages (Snaps). [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29095?quickstart=1) Fixes: MetaMask/snaps#2906 Related Snaps PR: MetaMask/snaps#2950 1. Try installing and using a Snap with confirmation window or home page, with `Container` in its content with `backgroundColor` defined (e.g. `<Container backgroundColor="default">`). 2. Try the same thing on transaction insights Snaps and confirm that the colors are not changing there. 3. Confirm that the colors are as expected on all pages. Some source code used for testing: - Source code used for confirmation content: ```typescript export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { switch (request.method) { case 'hello': return snap.request({ method: 'snap_dialog', params: { content: ( <Container backgroundColor="default"> <Box> <Section> <Row label="From"> <Address address="0x1234567890123456789012345678901234567890" /> </Row> <Row label="To" variant="warning" tooltip="This address has been deemed dangerous." > <Address address="0x0000000000000000000000000000000000000000" /> </Row> </Section> <Form name="form"> <Box direction="horizontal"> <Field label="baz"> <Input name="baz" placeholder="Enter something..." /> </Field> <Field label="foo"> <Selector title="bar" name="test"> <SelectorOption value="one"> <Card title="test" value="test" /> </SelectorOption> </Selector> </Field> </Box> <Field label="something_else"> <Selector title="bar" name="test2"> <SelectorOption value="one"> <Card title="test" value="test" /> </SelectorOption> </Selector> </Field> <Box direction="horizontal"> <Field label="baz2"> <Input name="baz2" placeholder="Enter something..." /> </Field> <Field label="foo3"> <Input name="foo3" placeholder="Enter something..." /> </Field> </Box> <Box direction="horizontal"> <Field label="Example Dropdown"> <Dropdown name="example-dropdown"> <Option value="option1">Option 1</Option> <Option value="option2">Option 2</Option> <Option value="option3">Option 3</Option> </Dropdown> </Field> <Field label="Example RadioGroup"> <RadioGroup name="example-radiogroup"> <Radio value="option1">Option 1</Radio> <Radio value="option2">Option 2</Radio> <Radio value="option3">Option 3</Radio> </RadioGroup> </Field> </Box> <Field label="Example Dropdown full width"> <Dropdown name="example-dropdown-full"> <Option value="option1">Option 1</Option> <Option value="option2">Option 2</Option> <Option value="option3">Option 3</Option> </Dropdown> </Field> <Field label="Example RadioGroup full width"> <RadioGroup name="example-radiogroup-full"> <Radio value="option11">Option 11</Radio> <Radio value="option22">Option 22</Radio> <Radio value="option33">Option 33</Radio> </RadioGroup> </Field> <Field label="foo4"> <Input name="foo4" placeholder="Enter something..." /> </Field> <Box direction="horizontal"> <Field label="baz3"> <Input name="baz3" placeholder="Enter something..." /> </Field> </Box> <Box direction="horizontal"> <Field label="Example Checkbox"> <Checkbox name="example-checkbox" label="Checkbox" /> </Field> <Field label="Example Selector"> <Selector name="example-selector" title="Choose an option" value="option1" > <SelectorOption value="option1"> <Card title="Option 1" value="option1" /> </SelectorOption> <SelectorOption value="option2"> <Card title="Option 2" value="option2" /> </SelectorOption> <SelectorOption value="option3"> <Card title="Option 3" value="option3" /> </SelectorOption> </Selector> </Field> </Box> <Field label="Example FileInput 2"> <FileInput name="file-input-2" /> </Field> <Field label="Example Checkbox Full field"> <Checkbox name="example-checkbox-full" label="Checkbox" /> </Field> <Box direction="horizontal"> <Field label="baz4"> <Input name="baz4" placeholder="Enter something..." /> </Field> <Field label="Example FileInput"> <FileInput name="file-input-1" /> </Field> </Box> <Box direction="horizontal"> <Field label="baz5"> <Input name="baz5" placeholder="Enter something..." /> </Field> <Field label="FileInput Compact"> <FileInput name="file-input-3" compact={true} /> </Field> </Box> <Field label="FileInput Compact 2 full"> <FileInput name="file-input-4" compact={true} /> </Field> </Form> </Box> </Container> ), }, }); default: throw new Error('Method not found.'); } }; ``` Note: Changing container colors was not possible before. ![Screenshot 2024-12-11 at 14 06 34](https://github.com/user-attachments/assets/aa7fbeb9-37ab-48f9-9613-2a76fb64960b) ![Screenshot 2024-12-11 at 14 06 59](https://github.com/user-attachments/assets/a06b620a-5755-4297-96a5-676bafb60638) ![Screenshot 2025-01-13 at 13 34 54](https://github.com/user-attachments/assets/28486134-b5cf-42c9-ac83-eada133a00ad) ![Screenshot 2025-01-13 at 13 38 00](https://github.com/user-attachments/assets/8ecd5169-a49e-4ba0-9cc2-baa3a92a2d75) ![Screenshot 2025-01-13 at 13 38 32](https://github.com/user-attachments/assets/c674aa5c-0b52-42a7-a58a-b894dcddeb58) ![Screenshot 2025-01-13 at 13 41 11](https://github.com/user-attachments/assets/a1b5ca36-e833-40a2-84c7-06e31af57d8b) ![Screenshot 2025-01-13 at 13 43 54](https://github.com/user-attachments/assets/cf5436e1-6626-4641-933d-5a02d031bb65) ![Screenshot 2025-01-13 at 13 44 25](https://github.com/user-attachments/assets/f598d930-ebee-473a-aea8-5132ec60114c) - [ ] 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. - [ ] 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 1844e67 commit 898525b

File tree

11 files changed

+45
-9
lines changed

11 files changed

+45
-9
lines changed

ui/components/app/snaps/insight-warnings/insight-warnings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export default function InsightWarnings({
8585
isCollapsable
8686
isCollapsed={warningState[snapId]}
8787
boxProps={{ marginBottom: idx === lastWarningIdx ? 0 : 4 }}
88+
contentBackgroundColor={BackgroundColor.backgroundDefault}
8889
/>
8990
);
9091
})}

ui/components/app/snaps/snap-home-page/snap-home-renderer.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ export const SnapHomeRenderer = ({ snapId }) => {
9393
isLoading={loading}
9494
useDelineator={false}
9595
useFooter
96-
contentBackgroundColor={BackgroundColor.backgroundAlternative}
9796
/>
9897
);
9998
};

ui/components/app/snaps/snap-insight/snap-insight.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useSelector, useDispatch } from 'react-redux';
66
import { Text } from '../../../component-library';
77
import {
88
AlignItems,
9+
BackgroundColor,
910
FLEX_DIRECTION,
1011
JustifyContent,
1112
TextAlign,
@@ -69,6 +70,7 @@ export const SnapInsight = ({ snapId, data }) => {
6970
interfaceId={interfaceId}
7071
delineatorType={DelineatorType.Insights}
7172
isLoading={isLoading}
73+
contentBackgroundColor={BackgroundColor.backgroundDefault}
7274
/>
7375
) : (
7476
<Text

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BoxElement, JSXElement } from '@metamask/snaps-sdk/jsx';
1+
import { ContainerElement, JSXElement } from '@metamask/snaps-sdk/jsx';
22
import { getJsxChildren } from '@metamask/snaps-utils';
33
import { mapToTemplate } from '../utils';
44
import {
@@ -8,7 +8,7 @@ import {
88
import { UIComponentFactory } from './types';
99
import { DEFAULT_FOOTER } from './footer';
1010

11-
export const container: UIComponentFactory<BoxElement> = ({
11+
export const container: UIComponentFactory<ContainerElement> = ({
1212
element,
1313
useFooter,
1414
onCancel,

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@ import { box } from './box';
88

99
export const section: UIComponentFactory<SectionElement> = ({
1010
element,
11+
contentBackgroundColor,
1112
...params
1213
}) => {
1314
const { children, props } = box({
1415
element,
1516
...params,
1617
} as unknown as UIComponentParams<BoxElement>);
18+
19+
// Reverse colors to improve visibility on certain backgrounds
20+
const backgroundColor =
21+
contentBackgroundColor === BackgroundColor.backgroundDefault
22+
? BackgroundColor.backgroundAlternative
23+
: BackgroundColor.backgroundDefault;
24+
1725
return {
1826
element: 'Box',
1927
children,
@@ -22,7 +30,7 @@ export const section: UIComponentFactory<SectionElement> = ({
2230
className: 'snap-ui-renderer__section',
2331
padding: 4,
2432
gap: 2,
25-
backgroundColor: BackgroundColor.backgroundDefault,
33+
backgroundColor,
2634
borderRadius: BorderRadius.LG,
2735
},
2836
};

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type UIComponentParams<T extends JSXElement> = {
1313
placeholder?: string;
1414
};
1515
t: (key: string) => string;
16+
contentBackgroundColor: string | undefined;
1617
};
1718

1819
export type UIComponent = {

ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ import { SnapInterfaceContextProvider } from '../../../../contexts/snaps';
1414
import PulseLoader from '../../../ui/pulse-loader';
1515
import {
1616
AlignItems,
17+
BackgroundColor,
1718
BlockSize,
1819
Display,
1920
JustifyContent,
2021
} from '../../../../helpers/constants/design-system';
2122
import { useI18nContext } from '../../../../hooks/useI18nContext';
22-
import { mapToTemplate } from './utils';
23+
import { mapToExtensionCompatibleColor, mapToTemplate } from './utils';
2324

2425
// Component that maps Snaps UI JSON format to MetaMask Template Renderer format
2526
const SnapUIRendererComponent = ({
@@ -69,6 +70,11 @@ const SnapUIRendererComponent = ({
6970
[inputValue, onInputChange, placeholder, isPrompt],
7071
);
7172

73+
const backgroundColor =
74+
contentBackgroundColor ??
75+
mapToExtensionCompatibleColor(content?.props?.backgroundColor) ??
76+
BackgroundColor.backgroundAlternative;
77+
7278
const sections = useMemo(
7379
() =>
7480
content &&
@@ -79,8 +85,9 @@ const SnapUIRendererComponent = ({
7985
useFooter,
8086
promptLegacyProps,
8187
t,
88+
contentBackgroundColor: backgroundColor,
8289
}),
83-
[content, onCancel, useFooter, promptLegacyProps, t],
90+
[content, onCancel, useFooter, promptLegacyProps, t, backgroundColor],
8491
);
8592

8693
if (isLoading || !content) {
@@ -134,7 +141,7 @@ const SnapUIRendererComponent = ({
134141
<Box
135142
className="snap-ui-renderer__content"
136143
height={BlockSize.Full}
137-
backgroundColor={contentBackgroundColor}
144+
backgroundColor={backgroundColor}
138145
style={{
139146
overflowY: 'auto',
140147
marginBottom: useFooter && hasFooter ? '80px' : '0',

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { sha256 } from '@noble/hashes/sha256';
55
import { NonEmptyArray, bytesToHex, remove0x } from '@metamask/utils';
66
import { unescape as unescapeEntities } from 'he';
77
import { ChangeEvent as ReactChangeEvent } from 'react';
8+
import { BackgroundColor } from '../../../../helpers/constants/design-system';
89
import { COMPONENT_MAPPING } from './components';
910
import { UIComponent } from './components/types';
1011

@@ -20,6 +21,7 @@ export type MapToTemplateParams = {
2021
placeholder?: string;
2122
};
2223
t?: (key: string) => string;
24+
contentBackgroundColor?: string | undefined;
2325
};
2426

2527
/**
@@ -140,3 +142,17 @@ export const FIELD_ELEMENT_TYPES = [
140142
export const getPrimaryChildElementIndex = (children: JSXElement[]) => {
141143
return children.findIndex((c) => FIELD_ELEMENT_TYPES.includes(c.type));
142144
};
145+
146+
/**
147+
* Map Snap custom color to extension compatible color.
148+
*
149+
* @param color - Snap custom color.
150+
* @returns String, representing color from design system.
151+
*/
152+
export const mapToExtensionCompatibleColor = (color: string) => {
153+
const backgroundColorMapping: { [key: string]: string | undefined } = {
154+
default: BackgroundColor.backgroundAlternative, // For Snaps, the default background color is the Alternative
155+
alternative: BackgroundColor.backgroundDefault,
156+
};
157+
return color ? backgroundColorMapping[color] : undefined;
158+
};

ui/components/app/snaps/snap-ui-selector/index.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.snap-ui-renderer {
22
&__selector {
33
width: 100%;
4+
border: 1px solid var(--color-border-muted);
45

56
& > span:first-child {
67
width: 100%;
@@ -12,6 +13,7 @@
1213

1314
&:hover {
1415
background-color: var(--color-background-alternative-hover);
16+
border-color: var(--color-border-default);
1517
}
1618
}
1719

ui/pages/confirmations/components/confirm/snaps/snaps-section/snap-insight.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TextColor,
88
TextVariant,
99
FontWeight,
10+
BackgroundColor,
1011
} from '../../../../../../helpers/constants/design-system';
1112
import { useI18nContext } from '../../../../../../hooks/useI18nContext';
1213
import { getSnapMetadata } from '../../../../../../selectors';
@@ -75,6 +76,7 @@ export const SnapInsight: React.FunctionComponent<SnapInsightProps> = ({
7576
interfaceId={interfaceId}
7677
isLoading={loading}
7778
useDelineator={false}
79+
contentBackgroundColor={BackgroundColor.backgroundDefault}
7880
/>
7981
</Delineator>
8082
);

0 commit comments

Comments
 (0)