mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[SharedUX] Replace Sass with Emotion, Round 1 (#199885)
## Summary Part of https://github.com/elastic/kibana-team/issues/1082 Selects certain Sass files to replace with styles declared with Emotion. This PR does not include any changes that would be noticeable by end-users. It changes the internals to use a different technology for styling components. ~~Some `className` attributes have been kept, because they are referenced in JS and tests.~~ Update: all classNames that are no longer needed for styling purposes have been removed. * If the className was needed for tests, it has been replaced with a test-subj. * If the className was used as a selector in production code, it has been replaced with alternative JS. ## References 1. https://emotion.sh/docs/globals 2. https://emotion.sh/docs/best-practices 3. https://github.com/elastic/eui/discussions/6828#discussioncomment-10825360 --------- Co-authored-by: Jatin Kathuria <jatin.kathuria@elastic.co>
This commit is contained in:
parent
16817cc44d
commit
d86896bac0
14 changed files with 222 additions and 135 deletions
|
@ -1,31 +1,62 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`kbnLoadingIndicator is hidden by default 1`] = `
|
exports[`kbnLoadingIndicator is hidden by default 1`] = `
|
||||||
<EuiIcon
|
<Fragment>
|
||||||
aria-label="Elastic Logo"
|
<EmotionGlobal
|
||||||
className="chrHeaderLogo__cluster"
|
styles={
|
||||||
data-test-subj="globalLoadingIndicator-hidden"
|
Object {
|
||||||
size="l"
|
".euiHeaderSectionItem .euiButtonEmpty__text": Object {
|
||||||
type="logoElastic"
|
"display": "flex",
|
||||||
/>
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EuiIcon
|
||||||
|
aria-label="Elastic Logo"
|
||||||
|
data-test-subj="globalLoadingIndicator-hidden"
|
||||||
|
size="l"
|
||||||
|
type="logoElastic"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`kbnLoadingIndicator is visible when loadingCount is > 0 1`] = `
|
exports[`kbnLoadingIndicator is visible when loadingCount is > 0 1`] = `
|
||||||
<EuiIcon
|
<Fragment>
|
||||||
aria-label="Elastic Logo"
|
<EmotionGlobal
|
||||||
className="chrHeaderLogo__cluster"
|
styles={
|
||||||
data-test-subj="globalLoadingIndicator-hidden"
|
Object {
|
||||||
size="l"
|
".euiHeaderSectionItem .euiButtonEmpty__text": Object {
|
||||||
type="logoElastic"
|
"display": "flex",
|
||||||
/>
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EuiIcon
|
||||||
|
aria-label="Elastic Logo"
|
||||||
|
data-test-subj="globalLoadingIndicator-hidden"
|
||||||
|
size="l"
|
||||||
|
type="logoElastic"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`kbnLoadingIndicator shows logo image when customLogo is set 1`] = `
|
exports[`kbnLoadingIndicator shows logo image when customLogo is set 1`] = `
|
||||||
<EuiImage
|
<Fragment>
|
||||||
alt="logo"
|
<EmotionGlobal
|
||||||
aria-label="User logo"
|
styles={
|
||||||
data-test-subj="globalLoadingIndicator-hidden"
|
Object {
|
||||||
size={24}
|
".euiHeaderSectionItem .euiButtonEmpty__text": Object {
|
||||||
src="customLogo"
|
"display": "flex",
|
||||||
/>
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<EuiImage
|
||||||
|
alt="logo"
|
||||||
|
aria-label="User logo"
|
||||||
|
data-test-subj="globalLoadingIndicator-hidden"
|
||||||
|
size={24}
|
||||||
|
src="customLogo"
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -168,7 +168,7 @@ Array [
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
aria-label="Recently viewed links"
|
aria-label="Recently viewed links"
|
||||||
class="euiListGroup kbnCollapsibleNav__recentsListGroup emotion-euiListGroup-none"
|
class="euiListGroup emotion-EuiListGroup"
|
||||||
style="max-inline-size: none;"
|
style="max-inline-size: none;"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
|
@ -218,10 +218,10 @@ Array [
|
||||||
class="euiHorizontalRule emotion-euiHorizontalRule-full"
|
class="euiHorizontalRule emotion-euiHorizontalRule-full"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="euiFlexItem kbnCollapsibleNav__solutions emotion-euiFlexItem-grow-1"
|
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-euiCollapsibleNavGroup-isCollapsible-none"
|
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-EuiCollapsibleNavGroup"
|
||||||
data-test-subj="collapsibleNavGroup-kibana"
|
data-test-subj="collapsibleNavGroup-kibana"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -230,7 +230,7 @@ Array [
|
||||||
<button
|
<button
|
||||||
aria-controls="generated-id"
|
aria-controls="generated-id"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
class="euiAccordion__button kbnCollapsibleNav__solutionGroupButton emotion-euiAccordion__button"
|
class="euiAccordion__button euiCollapsibleNavGroup__heading emotion-euiAccordion__button"
|
||||||
id="generated-id"
|
id="generated-id"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
@ -351,7 +351,7 @@ Array [
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-euiCollapsibleNavGroup-isCollapsible-none"
|
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-EuiCollapsibleNavGroup"
|
||||||
data-test-subj="collapsibleNavGroup-observability"
|
data-test-subj="collapsibleNavGroup-observability"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -360,7 +360,7 @@ Array [
|
||||||
<button
|
<button
|
||||||
aria-controls="generated-id"
|
aria-controls="generated-id"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
class="euiAccordion__button kbnCollapsibleNav__solutionGroupButton emotion-euiAccordion__button"
|
class="euiAccordion__button euiCollapsibleNavGroup__heading emotion-euiAccordion__button"
|
||||||
id="generated-id"
|
id="generated-id"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
@ -464,7 +464,7 @@ Array [
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-euiCollapsibleNavGroup-isCollapsible-none"
|
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-EuiCollapsibleNavGroup"
|
||||||
data-test-subj="collapsibleNavGroup-securitySolution"
|
data-test-subj="collapsibleNavGroup-securitySolution"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -473,7 +473,7 @@ Array [
|
||||||
<button
|
<button
|
||||||
aria-controls="generated-id"
|
aria-controls="generated-id"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
class="euiAccordion__button kbnCollapsibleNav__solutionGroupButton emotion-euiAccordion__button"
|
class="euiAccordion__button euiCollapsibleNavGroup__heading emotion-euiAccordion__button"
|
||||||
id="generated-id"
|
id="generated-id"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
@ -560,7 +560,7 @@ Array [
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-euiCollapsibleNavGroup-isCollapsible-none"
|
class="euiAccordion euiAccordion-isOpen euiCollapsibleNavGroup emotion-euiAccordion-EuiCollapsibleNavGroup"
|
||||||
data-test-subj="collapsibleNavGroup-management"
|
data-test-subj="collapsibleNavGroup-management"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -569,7 +569,7 @@ Array [
|
||||||
<button
|
<button
|
||||||
aria-controls="generated-id"
|
aria-controls="generated-id"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
class="euiAccordion__button kbnCollapsibleNav__solutionGroupButton emotion-euiAccordion__button"
|
class="euiAccordion__button euiCollapsibleNavGroup__heading emotion-euiAccordion__button"
|
||||||
id="generated-id"
|
id="generated-id"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
@ -858,7 +858,15 @@ exports[`CollapsibleNav renders the default nav 1`] = `
|
||||||
<EuiCollapsibleNav
|
<EuiCollapsibleNav
|
||||||
aria-label="Primary"
|
aria-label="Primary"
|
||||||
button={<button />}
|
button={<button />}
|
||||||
className="kbnCollapsibleNav"
|
css={
|
||||||
|
Object {
|
||||||
|
"map": undefined,
|
||||||
|
"name": "1pvcuvk",
|
||||||
|
"next": undefined,
|
||||||
|
"styles": "@media (max-height: 240px){overflow-y:auto;}",
|
||||||
|
"toString": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
data-test-subj="collapsibleNav"
|
data-test-subj="collapsibleNav"
|
||||||
id="collapsibe-nav"
|
id="collapsibe-nav"
|
||||||
isOpen={false}
|
isOpen={false}
|
||||||
|
@ -1045,7 +1053,15 @@ exports[`CollapsibleNav renders the default nav 2`] = `
|
||||||
<EuiCollapsibleNav
|
<EuiCollapsibleNav
|
||||||
aria-label="Primary"
|
aria-label="Primary"
|
||||||
button={<button />}
|
button={<button />}
|
||||||
className="kbnCollapsibleNav"
|
css={
|
||||||
|
Object {
|
||||||
|
"map": undefined,
|
||||||
|
"name": "1pvcuvk",
|
||||||
|
"next": undefined,
|
||||||
|
"styles": "@media (max-height: 240px){overflow-y:auto;}",
|
||||||
|
"toString": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
data-test-subj="collapsibleNav"
|
data-test-subj="collapsibleNav"
|
||||||
id="collapsibe-nav"
|
id="collapsibe-nav"
|
||||||
isOpen={false}
|
isOpen={false}
|
||||||
|
|
|
@ -56,12 +56,11 @@ Array [
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-label="Elastic home"
|
aria-label="Elastic home"
|
||||||
class="chrHeaderLogo"
|
css="You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)."
|
||||||
data-test-subj="logo"
|
data-test-subj="logo"
|
||||||
href="/"
|
href="/"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="chrHeaderLogo__cluster"
|
|
||||||
data-euiicon-type="logoElastic"
|
data-euiicon-type="logoElastic"
|
||||||
data-test-subj="globalLoadingIndicator-hidden"
|
data-test-subj="globalLoadingIndicator-hidden"
|
||||||
>
|
>
|
||||||
|
@ -70,7 +69,8 @@ Array [
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-labelledby="elasticMark"
|
aria-labelledby="elasticMark"
|
||||||
class="chrHeaderLogo__mark"
|
css="You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)."
|
||||||
|
data-test-subj="logoMark"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="19"
|
height="19"
|
||||||
width="64"
|
width="64"
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
$screenHeightBreakpoint: $euiSize * 15;
|
|
||||||
|
|
||||||
.kbnCollapsibleNav {
|
|
||||||
@media (max-height: $screenHeightBreakpoint) {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.kbnCollapsibleNav__recentsListGroup {
|
|
||||||
max-height: $euiSize * 10;
|
|
||||||
margin-right: -$euiSizeS;
|
|
||||||
@include euiYScroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kbnCollapsibleNav__solutions {
|
|
||||||
@include euiYScroll;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows the solutions nav group to be viewed on
|
|
||||||
* very small screen sizes and when the browser Zoom is high
|
|
||||||
*/
|
|
||||||
@media (max-height: $screenHeightBreakpoint) {
|
|
||||||
flex: 1 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Increase the hit area of the link (anchor)
|
|
||||||
* 2. Only show the text underline when hovering on the text/anchor portion
|
|
||||||
*/
|
|
||||||
|
|
||||||
.kbnCollapsibleNav__solutionGroupButton {
|
|
||||||
display: block; /* 1 */
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: none; /* 2 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.kbnCollapsibleNav__solutionGroupLink {
|
|
||||||
display: block; /* 1 */
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline; /* 2 */
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './collapsible_nav.scss';
|
|
||||||
import {
|
import {
|
||||||
EuiThemeProvider,
|
EuiThemeProvider,
|
||||||
EuiCollapsibleNav,
|
EuiCollapsibleNav,
|
||||||
|
@ -18,6 +17,7 @@ import {
|
||||||
EuiListGroupItem,
|
EuiListGroupItem,
|
||||||
EuiCollapsibleNavProps,
|
EuiCollapsibleNavProps,
|
||||||
EuiButton,
|
EuiButton,
|
||||||
|
useEuiTheme,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { groupBy, sortBy } from 'lodash';
|
import { groupBy, sortBy } from 'lodash';
|
||||||
|
@ -36,6 +36,7 @@ import {
|
||||||
createEuiButtonItem,
|
createEuiButtonItem,
|
||||||
createOverviewLink,
|
createOverviewLink,
|
||||||
} from './nav_link';
|
} from './nav_link';
|
||||||
|
import { getCollapsibleNavStyles } from './get_collapsible_nav_styles';
|
||||||
|
|
||||||
function getAllCategories(allCategorizedLinks: Record<string, ChromeNavLink[]>) {
|
function getAllCategories(allCategorizedLinks: Record<string, ChromeNavLink[]>) {
|
||||||
const allCategories = {} as Record<string, AppCategory | undefined>;
|
const allCategories = {} as Record<string, AppCategory | undefined>;
|
||||||
|
@ -149,6 +150,7 @@ export function CollapsibleNav({
|
||||||
...(needsIcon && { basePath }),
|
...(needsIcon && { basePath }),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const styles = getCollapsibleNavStyles(useEuiTheme());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiCollapsibleNav
|
<EuiCollapsibleNav
|
||||||
|
@ -162,7 +164,7 @@ export function CollapsibleNav({
|
||||||
button={button}
|
button={button}
|
||||||
ownFocus={false}
|
ownFocus={false}
|
||||||
size={248}
|
size={248}
|
||||||
className="kbnCollapsibleNav"
|
css={styles.navCss}
|
||||||
>
|
>
|
||||||
{customNavLink && (
|
{customNavLink && (
|
||||||
<>
|
<>
|
||||||
|
@ -275,14 +277,14 @@ export function CollapsibleNav({
|
||||||
color="subdued"
|
color="subdued"
|
||||||
gutterSize="none"
|
gutterSize="none"
|
||||||
size="s"
|
size="s"
|
||||||
className="kbnCollapsibleNav__recentsListGroup"
|
css={styles.navRecentsListGroupCss}
|
||||||
/>
|
/>
|
||||||
</EuiCollapsibleNavGroup>
|
</EuiCollapsibleNavGroup>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<EuiHorizontalRule margin="none" />
|
<EuiHorizontalRule margin="none" />
|
||||||
|
|
||||||
<EuiFlexItem className="kbnCollapsibleNav__solutions">
|
<EuiFlexItem css={styles.navSolutions}>
|
||||||
{/* Kibana, Observability, Security, and Management sections */}
|
{/* Kibana, Observability, Security, and Management sections */}
|
||||||
{orderedCategories.map((categoryName) => {
|
{orderedCategories.map((categoryName) => {
|
||||||
const category = categoryDictionary[categoryName]!;
|
const category = categoryDictionary[categoryName]!;
|
||||||
|
@ -294,11 +296,12 @@ export function CollapsibleNav({
|
||||||
iconType={category.euiIconType}
|
iconType={category.euiIconType}
|
||||||
iconSize="m"
|
iconSize="m"
|
||||||
buttonElement={overviewLink ? 'div' : 'button'}
|
buttonElement={overviewLink ? 'div' : 'button'}
|
||||||
buttonClassName="kbnCollapsibleNav__solutionGroupButton"
|
css={styles.navSolutionGroupButton}
|
||||||
title={
|
title={
|
||||||
overviewLink ? (
|
overviewLink ? (
|
||||||
<a
|
<a
|
||||||
className="eui-textInheritColor kbnCollapsibleNav__solutionGroupLink"
|
className="eui-textInheritColor"
|
||||||
|
css={styles.navSolutionGroupLink}
|
||||||
{...createOverviewLink({
|
{...createOverviewLink({
|
||||||
link: overviewLink,
|
link: overviewLink,
|
||||||
navigateToUrl,
|
navigateToUrl,
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the "Elastic License
|
||||||
|
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||||
|
* Public License v 1"; you may not use this file except in compliance with, at
|
||||||
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||||
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { UseEuiTheme, euiYScroll, mathWithUnits } from '@elastic/eui';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
export const getCollapsibleNavStyles = (euiThemeContext: UseEuiTheme) => {
|
||||||
|
const { euiTheme } = euiThemeContext;
|
||||||
|
const screenHeightBreakpoint = mathWithUnits(euiTheme.size.base, (x) => x * 15);
|
||||||
|
const _euiYScroll = euiYScroll(euiThemeContext);
|
||||||
|
|
||||||
|
const navCss = css({
|
||||||
|
[`@media (max-height: ${screenHeightBreakpoint})`]: {
|
||||||
|
overflowY: 'auto',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const navRecentsListGroupCss = [
|
||||||
|
css({
|
||||||
|
maxHeight: `calc(${euiTheme.size.base} * 10)`,
|
||||||
|
marginRight: `-${euiTheme.size.s}`,
|
||||||
|
}),
|
||||||
|
_euiYScroll,
|
||||||
|
];
|
||||||
|
|
||||||
|
const navSolutions = [
|
||||||
|
_euiYScroll,
|
||||||
|
css({
|
||||||
|
/**
|
||||||
|
* Allows the solutions nav group to be viewed on
|
||||||
|
* very small screen sizes and when the browser Zoom is high
|
||||||
|
*/
|
||||||
|
[`@media (max-height: ${screenHeightBreakpoint})`]: {
|
||||||
|
flex: '1 0 auto',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Increase the hit area of the link (anchor)
|
||||||
|
* 2. Only show the text underline when hovering on the text/anchor portion
|
||||||
|
*/
|
||||||
|
const navSolutionGroupButton = css({
|
||||||
|
display: 'block' /* 1 */,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'none' /* 2 */,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const navSolutionGroupLink = css({
|
||||||
|
display: 'block' /* 1 */,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'underline' /* 2 */,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
navCss,
|
||||||
|
navRecentsListGroupCss,
|
||||||
|
navSolutions,
|
||||||
|
navSolutionGroupButton,
|
||||||
|
navSolutionGroupLink,
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,11 +0,0 @@
|
||||||
.chrHeaderLogo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: $euiSizeXXL;
|
|
||||||
padding-inline: $euiSizeS;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chrHeaderLogo__mark {
|
|
||||||
margin-left: $euiSizeS;
|
|
||||||
fill: $euiColorGhost;
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './header_logo.scss';
|
import { css } from '@emotion/react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useObservable from 'react-use/lib/useObservable';
|
import useObservable from 'react-use/lib/useObservable';
|
||||||
|
@ -16,6 +16,7 @@ import Url from 'url';
|
||||||
import { CustomBranding } from '@kbn/core-custom-branding-common';
|
import { CustomBranding } from '@kbn/core-custom-branding-common';
|
||||||
import type { HttpStart } from '@kbn/core-http-browser';
|
import type { HttpStart } from '@kbn/core-http-browser';
|
||||||
import type { ChromeNavLink } from '@kbn/core-chrome-browser';
|
import type { ChromeNavLink } from '@kbn/core-chrome-browser';
|
||||||
|
import { useEuiTheme } from '@elastic/eui';
|
||||||
import { ElasticMark } from './elastic_mark';
|
import { ElasticMark } from './elastic_mark';
|
||||||
import { LoadingIndicator } from '../loading_indicator';
|
import { LoadingIndicator } from '../loading_indicator';
|
||||||
|
|
||||||
|
@ -83,14 +84,29 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeaderLogo({ href, navigateToApp, loadingCount$, ...observables }: Props) {
|
export function HeaderLogo({ href, navigateToApp, loadingCount$, ...observables }: Props) {
|
||||||
|
const { euiTheme } = useEuiTheme();
|
||||||
const forceNavigation = useObservable(observables.forceNavigation$, false);
|
const forceNavigation = useObservable(observables.forceNavigation$, false);
|
||||||
const navLinks = useObservable(observables.navLinks$, []);
|
const navLinks = useObservable(observables.navLinks$, []);
|
||||||
const customBranding = useObservable(observables.customBranding$, {});
|
const customBranding = useObservable(observables.customBranding$, {});
|
||||||
const { customizedLogo, logo } = customBranding;
|
const { customizedLogo, logo } = customBranding;
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
logoCss: css({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: euiTheme.size.xxl,
|
||||||
|
paddingInline: euiTheme.size.s,
|
||||||
|
}),
|
||||||
|
logoMarkCss: css({
|
||||||
|
marginLeft: euiTheme.size.s,
|
||||||
|
fill: euiTheme.colors.ghost,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
onClick={(e) => onClick(e, forceNavigation, navLinks, navigateToApp)}
|
onClick={(e) => onClick(e, forceNavigation, navLinks, navigateToApp)}
|
||||||
className="chrHeaderLogo"
|
css={styles.logoCss}
|
||||||
href={href}
|
href={href}
|
||||||
data-test-subj="logo"
|
data-test-subj="logo"
|
||||||
aria-label={i18n.translate('core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel', {
|
aria-label={i18n.translate('core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel', {
|
||||||
|
@ -101,12 +117,13 @@ export function HeaderLogo({ href, navigateToApp, loadingCount$, ...observables
|
||||||
{customizedLogo ? (
|
{customizedLogo ? (
|
||||||
<img
|
<img
|
||||||
src={customizedLogo}
|
src={customizedLogo}
|
||||||
className="chrHeaderLogo__mark"
|
data-test-subj="logoMark"
|
||||||
|
css={styles.logoMarkCss}
|
||||||
style={{ maxWidth: '200px', maxHeight: '84px' }}
|
style={{ maxWidth: '200px', maxHeight: '84px' }}
|
||||||
alt="custom mark"
|
alt="custom mark"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ElasticMark className="chrHeaderLogo__mark" aria-hidden={true} />
|
<ElasticMark data-test-subj="logoMark" css={styles.logoMarkCss} aria-hidden={true} />
|
||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
.kbnLoadingIndicator-hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
animation-play-state: paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
.euiHeaderSectionItem .euiButtonEmpty__text {
|
|
||||||
// stop global header buttons from jumping during loading state
|
|
||||||
display: flex;
|
|
||||||
}
|
|
|
@ -16,7 +16,9 @@ import { LoadingIndicator } from './loading_indicator';
|
||||||
describe('kbnLoadingIndicator', () => {
|
describe('kbnLoadingIndicator', () => {
|
||||||
it('is hidden by default', () => {
|
it('is hidden by default', () => {
|
||||||
const wrapper = shallow(<LoadingIndicator loadingCount$={new BehaviorSubject(0)} />);
|
const wrapper = shallow(<LoadingIndicator loadingCount$={new BehaviorSubject(0)} />);
|
||||||
expect(wrapper.prop('data-test-subj')).toBe('globalLoadingIndicator-hidden');
|
expect(
|
||||||
|
wrapper.findWhere((node) => node.prop('data-test-subj') === 'globalLoadingIndicator-hidden')
|
||||||
|
).toHaveLength(1);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Global, css } from '@emotion/react';
|
||||||
import { EuiLoadingSpinner, EuiProgress, EuiIcon, EuiImage } from '@elastic/eui';
|
import { EuiLoadingSpinner, EuiProgress, EuiIcon, EuiImage } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -14,8 +15,6 @@ import classNames from 'classnames';
|
||||||
import type { Subscription } from 'rxjs';
|
import type { Subscription } from 'rxjs';
|
||||||
import type { HttpStart } from '@kbn/core-http-browser';
|
import type { HttpStart } from '@kbn/core-http-browser';
|
||||||
|
|
||||||
import './loading_indicator.scss';
|
|
||||||
|
|
||||||
export interface LoadingIndicatorProps {
|
export interface LoadingIndicatorProps {
|
||||||
loadingCount$: ReturnType<HttpStart['getLoadingCount$']>;
|
loadingCount$: ReturnType<HttpStart['getLoadingCount$']>;
|
||||||
showAsBar?: boolean;
|
showAsBar?: boolean;
|
||||||
|
@ -60,6 +59,12 @@ export class LoadingIndicator extends React.Component<LoadingIndicatorProps, { v
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const className = classNames(!this.state.visible && 'kbnLoadingIndicator-hidden');
|
const className = classNames(!this.state.visible && 'kbnLoadingIndicator-hidden');
|
||||||
|
const indicatorHiddenCss = !this.state.visible
|
||||||
|
? css({
|
||||||
|
visibility: 'hidden',
|
||||||
|
animationPlayState: 'paused',
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const testSubj = this.state.visible
|
const testSubj = this.state.visible
|
||||||
? 'globalLoadingIndicator'
|
? 'globalLoadingIndicator'
|
||||||
|
@ -84,7 +89,6 @@ export class LoadingIndicator extends React.Component<LoadingIndicatorProps, { v
|
||||||
type={'logoElastic'}
|
type={'logoElastic'}
|
||||||
size="l"
|
size="l"
|
||||||
data-test-subj={testSubj}
|
data-test-subj={testSubj}
|
||||||
className="chrHeaderLogo__cluster"
|
|
||||||
aria-label={i18n.translate('core.ui.chrome.headerGlobalNav.logoAriaLabel', {
|
aria-label={i18n.translate('core.ui.chrome.headerGlobalNav.logoAriaLabel', {
|
||||||
defaultMessage: 'Elastic Logo',
|
defaultMessage: 'Elastic Logo',
|
||||||
})}
|
})}
|
||||||
|
@ -102,18 +106,31 @@ export class LoadingIndicator extends React.Component<LoadingIndicatorProps, { v
|
||||||
logoImage
|
logoImage
|
||||||
);
|
);
|
||||||
|
|
||||||
return !this.props.showAsBar ? (
|
return (
|
||||||
logo
|
<>
|
||||||
) : (
|
<Global
|
||||||
<EuiProgress
|
styles={{
|
||||||
className={className}
|
'.euiHeaderSectionItem .euiButtonEmpty__text': {
|
||||||
data-test-subj={testSubj}
|
// stop global header buttons from jumping during loading state
|
||||||
max={this.props.maxAmount}
|
display: 'flex',
|
||||||
value={this.props.valueAmount}
|
},
|
||||||
position="fixed"
|
}}
|
||||||
color="accent"
|
/>
|
||||||
size="xs"
|
{!this.props.showAsBar ? (
|
||||||
/>
|
logo
|
||||||
|
) : (
|
||||||
|
<EuiProgress
|
||||||
|
className={className}
|
||||||
|
css={indicatorHiddenCss}
|
||||||
|
data-test-subj={testSubj}
|
||||||
|
max={this.props.maxAmount}
|
||||||
|
value={this.props.valueAmount}
|
||||||
|
position="fixed"
|
||||||
|
color="accent"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
.chrHeaderLogo__mark {
|
|
||||||
margin-left: $euiSizeS;
|
|
||||||
fill: $euiColorGhost;
|
|
||||||
}
|
|
|
@ -184,7 +184,7 @@ export const focusUtilityBarAction = (containerElement: HTMLElement | null) => {
|
||||||
* Resets keyboard focus on the page
|
* Resets keyboard focus on the page
|
||||||
*/
|
*/
|
||||||
export const resetKeyboardFocus = () => {
|
export const resetKeyboardFocus = () => {
|
||||||
document.querySelector<HTMLAnchorElement>('header.headerGlobalNav a.chrHeaderLogo')?.focus();
|
document.body.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OperatorHandler {
|
interface OperatorHandler {
|
||||||
|
|
|
@ -91,8 +91,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
require.resolve('./acme_text.png')
|
require.resolve('./acme_text.png')
|
||||||
);
|
);
|
||||||
await goToSettings();
|
await goToSettings();
|
||||||
const logo = await testSubjects.find('logo');
|
const img = await testSubjects.find('logoMark');
|
||||||
const img = await logo.findByCssSelector('.chrHeaderLogo__mark');
|
|
||||||
const imgSrc = (await img.getAttribute('src')) ?? '';
|
const imgSrc = (await img.getAttribute('src')) ?? '';
|
||||||
expect(imgSrc.startsWith('data:image/png')).to.be(true);
|
expect(imgSrc.startsWith('data:image/png')).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue