Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Emotion] Nested EuiThemeProviders now render a wrapper setting the correct inherited text color #6775

Merged
merged 12 commits into from
May 17, 2023
Merged
1 change: 0 additions & 1 deletion src-docs/src/views/app_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const AppView = ({ children, currentRoute }) => {
{`${hash ? '— ' : ''}${currentRoute.name} — Elastic UI Framework`}
</EuiScreenReaderLive>
<EuiSkipLink
color="ghost"
destinationId="start-of-content"
position="fixed"
overrideLinkBehavior
Expand Down
30 changes: 12 additions & 18 deletions src-docs/src/views/theme/color_mode/color_mode_example.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import { Link } from 'react-router-dom';

import { GuideSectionTypes } from '../../../components';

Expand Down Expand Up @@ -42,25 +41,20 @@ export const ColorModeExample = {
the current color mode.
</p>
<p>
When nesting or overriding <strong>EuiThemeProvider</strong> bear in
mind that the{' '}
<Link to="/display/text">
<strong>EuiText</strong>
</Link>{' '}
inherits the color that is set in the global styles or a parent
component. This is why you should change the color of{' '}
<strong>EuiText</strong> to <EuiCode>{'"default"'}</EuiCode> when
you want it to correctly adapt to the <EuiCode>colorMode</EuiCode>{' '}
of the nested <strong>EuiThemeProvider</strong>.
When nesting or overriding <strong>EuiThemeProvider</strong>, a
wrapping <EuiCode>{'<span>'}</EuiCode> element that sets the correct
default text color (normally set at the global{' '}
<EuiCode>{'<body>'}</EuiCode> level) will be rendered. You can
customize the display of this wrapping element by passing{' '}
<EuiCode>wrapperProps</EuiCode>.
</p>
<p>
<Link to="/display/icons">
<strong>EuiIcon</strong>
</Link>{' '}
behaves similarly. By default, it gets the color of its parent
component. Thus, you can override the color to{' '}
<EuiCode>{'"text"'}</EuiCode> or wrap it in a{' '}
<strong>EuiText</strong> to inherit its color.
Alternatively, if a wrapper will significantly impact the DOM
layout/flow of your content, and if your child is a single React
component, you may pass{' '}
<EuiCode>{'wrapperProps={{ cloneElement: true }}'}</EuiCode> to
avoid rendering an extra wrapper and to clone the correct color
classes onto your child content.
</p>
</>
),
Expand Down
180 changes: 157 additions & 23 deletions src-docs/src/views/theme/color_mode/inverse.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,181 @@
import React from 'react';
import React, { useState, FC } from 'react';
import {
EuiThemeProvider,
useEuiTheme,
EuiIcon,
EuiSpacer,
EuiText,
EuiThemeProvider,
EuiCode,
EuiPanel,
EuiFlexGroup,
EuiFlexItem,
EuiButton,
EuiPopover,
EuiModal,
EuiModalHeader,
EuiModalHeaderTitle,
EuiModalBody,
EuiModalFooter,
EuiFlyout,
EuiFlyoutHeader,
EuiTitle,
EuiFlyoutBody,
} from '../../../../../src';

export default () => {
return (
<>
<EuiThemeProvider colorMode="light">
<EuiPanel>
<EuiText color="default">
<p>
<EuiIcon type="faceHappy" /> The colors of this panel will always
be in <strong>light</strong> mode
</p>
</EuiText>
</EuiPanel>
<ThemedChildren />
</EuiThemeProvider>
<EuiSpacer />

<EuiThemeProvider colorMode="dark">
<EuiPanel>
<EuiText color="default">
<p>
<EuiIcon type="faceHappy" /> The colors of this panel will always
be in <strong>dark</strong> mode
</p>
</EuiText>
</EuiPanel>
<ThemedChildren />
</EuiThemeProvider>
<EuiSpacer />

<EuiThemeProvider colorMode="inverse">
<EuiPanel>
<EuiText color="default">
<ThemedChildren>
<EuiSpacer size="m" />
<EuiText>
<p>
<EuiIcon type="faceHappy" /> The colors of this panel are the
opposite (<strong>inverse</strong>) of the current color mode
This panel is in <strong>inverse</strong> mode (the opposite of
the global color mode), and renders a 3rd level nested theme
provider that inverses color mode yet again.
</p>
</EuiText>
</EuiPanel>
<EuiSpacer size="m" />

<EuiThemeProvider
colorMode="inverse"
wrapperProps={{ cloneElement: true }}
>
<ThemedChildren>
<EuiText>
<p>
This panel demonstrates the <EuiCode>cloneElement</EuiCode>{' '}
property.
</p>
</EuiText>
</ThemedChildren>
</EuiThemeProvider>
</ThemedChildren>
</EuiThemeProvider>
</>
);
};

const ThemedChildren: FC = ({ children, ...rest }) => {
const { colorMode: _colorMode } = useEuiTheme();
const colorMode = _colorMode.toLowerCase();
return (
<EuiPanel {...rest}>
<EuiFlexGroup gutterSize="m">
<EuiFlexItem>
<EuiText>
<p>
<EuiIcon type="faceHappy" /> The colors of this panel and its
portalled content are in <strong>{colorMode}</strong> mode.
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Popover>
This popover should render in <strong>{colorMode}</strong> mode.
</Popover>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Modal>
This modal should render in <strong>{colorMode}</strong> mode.
</Modal>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Flyout>
This flyout should render in <strong>{colorMode}</strong> mode.
</Flyout>
</EuiFlexItem>
</EuiFlexGroup>
{children}
</EuiPanel>
);
};

const Popover: FC = ({ children }) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
return (
<EuiPopover
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
button={
<EuiButton
onClick={() => setIsPopoverOpen((isOpen) => !isOpen)}
fullWidth
size="s"
>
Open popover
</EuiButton>
}
display="block"
>
{children}
</EuiPopover>
);
};

const Modal: FC = ({ children }) => {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<>
<EuiButton onClick={() => setIsModalOpen(true)} size="s">
Open modal
</EuiButton>
{isModalOpen && (
<EuiModal onClose={() => setIsModalOpen(false)}>
<EuiModalHeader>
<EuiModalHeaderTitle>Modal title</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiText>
<p>{children}</p>
</EuiText>
</EuiModalBody>
<EuiModalFooter>
<EuiButton onClick={() => setIsModalOpen(false)} fill>
Close
</EuiButton>
</EuiModalFooter>
</EuiModal>
)}
</>
);
};

const Flyout: FC = ({ children }) => {
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
return (
<>
<EuiButton onClick={() => setIsFlyoutOpen(true)} size="s">
Open flyout
</EuiButton>
{isFlyoutOpen && (
<EuiFlyout
ownFocus
onClose={() => setIsFlyoutOpen(false)}
aria-labelledby="flyoutTitle"
>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<h2 id="flyoutTitle">Flyout title</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiText>
<p>{children}</p>
</EuiText>
</EuiFlyoutBody>
</EuiFlyout>
)}
</>
);
};
1 change: 0 additions & 1 deletion src-docs/src/views/theme/color_mode/inverse_complex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const Box: FunctionComponent<{ children: ReactNode }> = ({ children }) => {
css={{
background: euiTheme.colors.lightShade,
padding: euiTheme.size.xl,
color: euiTheme.colors.text,
}}
>
<p>{children}</p>
Expand Down
48 changes: 0 additions & 48 deletions src-docs/src/views/theme/inverse.tsx

This file was deleted.

Loading