Create @kbn/css-utils
package (#223933)
## 🧵 Summary
This PR introduces a few structural and cleanup improvements:
1. Moves core Emotion CSS helpers (`useMemoizedStyles` renamed as
`useMemoCss`, `kbnFullBodyHeightCss`, `kbnFullScreenBgCss`) from
`core/public` to a new package: `@kbn/css-utils`.
2. Removes a significant portion of legacy SCSS from the core plugin.
3. Replaces scss mixin with emotion `kbnFullScreenBgCss` across Kibana
(we have scss and emotion version, but emotion version wasn't widely
used yet).
4. As a result of (3), some plugin tests were migrated to React Testing
Library. This was necessary because Emotion-generated snapshots in
Enzyme were difficult to read and maintain when moving to emotion.
### Considerations
I initially tried to add the package to the [shared-deps
bundle](8e15517ddd
),
but couldn’t get the SVG imports for `kbnFullScreenBgCss` to work
correctly in that setup.
As a workaround, I opted to import the helpers directly from their
source files.
An alternative approach could be to convert the used SVGs into React
components and use those within the shared package. Or explore something
like a static package and try to somehow wire in that in the webpack
internal compilers, but it doesn't seem to be worth the effort at the
moment.
### 💡 Motivation
- These utils don’t need to live in Core and are now decoupled to
improve performance and flexibility.
- Importing from `core/public` (even just for a small hook) was adding
noticeable overhead to test runs:
- ~1–2s delay on first Jest execution
- ~200ms added on subsequent runs
- Occasional CI timeouts due to deep import graph
### 👥 Ownership
I assigned this package to sharedux team. Thank you!
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1
.github/CODEOWNERS
vendored
|
@ -438,6 +438,7 @@ src/platform/packages/shared/kbn-config-schema @elastic/kibana-core
|
|||
src/platform/packages/shared/kbn-content-management-utils @elastic/kibana-data-discovery
|
||||
src/platform/packages/shared/kbn-crypto @elastic/kibana-security
|
||||
src/platform/packages/shared/kbn-crypto-browser @elastic/kibana-core
|
||||
src/platform/packages/shared/kbn-css-utils @elastic/appex-sharedux
|
||||
src/platform/packages/shared/kbn-custom-icons @elastic/obs-ux-logs-team
|
||||
src/platform/packages/shared/kbn-cypress-config @elastic/kibana-operations
|
||||
src/platform/packages/shared/kbn-data-grid-in-table-search @elastic/kibana-data-discovery
|
||||
|
|
|
@ -439,6 +439,7 @@
|
|||
"@kbn/cross-cluster-replication-plugin": "link:x-pack/platform/plugins/private/cross_cluster_replication",
|
||||
"@kbn/crypto": "link:src/platform/packages/shared/kbn-crypto",
|
||||
"@kbn/crypto-browser": "link:src/platform/packages/shared/kbn-crypto-browser",
|
||||
"@kbn/css-utils": "link:src/platform/packages/shared/kbn-css-utils",
|
||||
"@kbn/custom-branding-plugin": "link:x-pack/platform/plugins/private/custom_branding",
|
||||
"@kbn/custom-icons": "link:src/platform/packages/shared/kbn-custom-icons",
|
||||
"@kbn/custom-integrations": "link:x-pack/solutions/observability/packages/kbn-custom-integrations",
|
||||
|
|
|
@ -288,10 +288,6 @@ export function getWebpackConfig(
|
|||
extensions: ['.js', '.ts', '.tsx', '.json'],
|
||||
mainFields: ['browser', 'module', 'main'],
|
||||
alias: {
|
||||
core_app_image_assets: Path.resolve(
|
||||
worker.repoRoot,
|
||||
'src/core/public/styles/core_app/images'
|
||||
),
|
||||
vega: Path.resolve(worker.repoRoot, 'node_modules/vega/build-es5/vega.js'),
|
||||
'react-dom$': 'react-dom/profiling',
|
||||
'scheduler/tracing': 'scheduler/tracing-profiling',
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
// This file replaces scss core/public/_mixins.scss
|
||||
|
||||
import { css, keyframes } from '@emotion/react';
|
||||
import { COLOR_MODES_STANDARD, UseEuiTheme, euiCanAnimate, useEuiTheme } from '@elastic/eui';
|
||||
import { useMemo } from 'react';
|
||||
import { CSSInterpolation } from '@emotion/serialize';
|
||||
import bg_top_branded from './styles/core_app/images/bg_top_branded.svg';
|
||||
import bg_top_branded_dark from './styles/core_app/images/bg_top_branded_dark.svg';
|
||||
import bg_bottom_branded from './styles/core_app/images/bg_bottom_branded.svg';
|
||||
import bg_bottom_branded_dark from './styles/core_app/images/bg_bottom_branded_dark.svg';
|
||||
|
||||
// The `--kbnAppHeadersOffset` CSS variable is automatically updated by
|
||||
// styles/rendering/_base.scss, based on whether the Kibana chrome has a
|
||||
// header banner, app menu, and is visible or hidden
|
||||
export const kibanaFullBodyHeightCss = (additionalOffset = '0px') =>
|
||||
css({
|
||||
height: `calc(100vh - var(--kbnAppHeadersOffset, var(--euiFixedHeadersOffset, 0)) - ${additionalOffset})`,
|
||||
});
|
||||
|
||||
export const fullScreenGraphicsMixinStyles = (euiZLevel: number, euiTheme: UseEuiTheme) => {
|
||||
const lightOrDarkTheme = (lightSvg: any, darkSvg: any) => {
|
||||
return euiTheme.colorMode === COLOR_MODES_STANDARD.light ? lightSvg : darkSvg;
|
||||
};
|
||||
const fullScreenGraphicsFadeIn = keyframes`
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
return css({
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: euiZLevel + 1000,
|
||||
background: 'inherit',
|
||||
backgroundColor: euiTheme.euiTheme.colors.backgroundBasePlain,
|
||||
opacity: 0,
|
||||
overflow: 'auto',
|
||||
[euiCanAnimate]: {
|
||||
animation: `${fullScreenGraphicsFadeIn} ${euiTheme.euiTheme.animation.extraSlow} ${euiTheme.euiTheme.animation.resistance} 0s forwards`,
|
||||
},
|
||||
'.kbnBody--hasHeaderBanner &': {
|
||||
top: 'var(--kbnHeaderBannerHeight)',
|
||||
},
|
||||
'&::before': {
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1,
|
||||
width: '400px',
|
||||
height: '400px',
|
||||
content: `url(${lightOrDarkTheme(bg_top_branded, bg_top_branded_dark)})`,
|
||||
},
|
||||
'&::after': {
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
zIndex: 1,
|
||||
width: '400px',
|
||||
height: '400px',
|
||||
content: `url(${lightOrDarkTheme(bg_bottom_branded, bg_bottom_branded_dark)})`,
|
||||
},
|
||||
[`@media (max-width: ${euiTheme.euiTheme.breakpoint.l}px)`]: {
|
||||
'&::before, &::after': {
|
||||
content: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export type EmotionStyles = Record<
|
||||
string,
|
||||
CSSInterpolation | ((theme: UseEuiTheme) => CSSInterpolation)
|
||||
>;
|
||||
|
||||
type StaticEmotionStyles = Record<string, CSSInterpolation>;
|
||||
|
||||
/**
|
||||
* Custom hook to reduce boilerplate when working with Emotion styles that may depend on
|
||||
* the EUI theme.
|
||||
*
|
||||
* Accepts a map of styles where each entry is either a static Emotion style (via `css`)
|
||||
* or a function that returns styles based on the current `euiTheme`.
|
||||
*
|
||||
* It returns a memoized version of the style map with all values resolved to static
|
||||
* Emotion styles, allowing components to use a clean and unified object for styling.
|
||||
*
|
||||
* This helps simplify component code by centralizing theme-aware style logic.
|
||||
*
|
||||
* Example usage:
|
||||
* const componentStyles = {
|
||||
* container: css({ overflow: hidden }),
|
||||
* leftPane: ({ euiTheme }) => css({ paddingTop: euiTheme.size.m }),
|
||||
* }
|
||||
* const styles = useMemoizedStyles(componentStyles);
|
||||
*/
|
||||
export const useMemoizedStyles = (styleMap: EmotionStyles) => {
|
||||
const euiThemeContext = useEuiTheme();
|
||||
const outputStyles = useMemo(() => {
|
||||
return Object.entries(styleMap).reduce<StaticEmotionStyles>((acc, [key, value]) => {
|
||||
acc[key] = typeof value === 'function' ? value(euiThemeContext) : value;
|
||||
return acc;
|
||||
}, {});
|
||||
}, [euiThemeContext, styleMap]);
|
||||
return outputStyles;
|
||||
};
|
|
@ -310,10 +310,3 @@ export type { CoreSetup, CoreStart, StartServicesAccessor } from '@kbn/core-life
|
|||
export type { CoreSystem } from '@kbn/core-root-browser-internal';
|
||||
|
||||
export { __kbnBootstrap__ } from '@kbn/core-root-browser-internal';
|
||||
|
||||
export {
|
||||
kibanaFullBodyHeightCss,
|
||||
fullScreenGraphicsMixinStyles,
|
||||
useMemoizedStyles,
|
||||
type EmotionStyles,
|
||||
} from './css_utils';
|
||||
|
|
|
@ -4,6 +4,4 @@
|
|||
|
||||
@import '@elastic/eui-theme-borealis/src/theme_dark.scss';
|
||||
|
||||
@import './mixins';
|
||||
|
||||
$kbnThemeVersion: 'borealisdark';
|
|
@ -4,6 +4,4 @@
|
|||
|
||||
@import '@elastic/eui-theme-borealis/src/theme_light.scss';
|
||||
|
||||
@import './mixins';
|
||||
|
||||
$kbnThemeVersion: 'borealislight';
|
|
@ -5,6 +5,4 @@
|
|||
@import '@elastic/eui/src/themes/amsterdam/colors_dark';
|
||||
@import '@elastic/eui/src/themes/amsterdam/globals';
|
||||
|
||||
@import './mixins';
|
||||
|
||||
$kbnThemeVersion: 'v8dark';
|
||||
|
|
|
@ -5,6 +5,4 @@
|
|||
@import '@elastic/eui/src/themes/amsterdam/colors_light';
|
||||
@import '@elastic/eui/src/themes/amsterdam/globals';
|
||||
|
||||
@import './mixins';
|
||||
|
||||
$kbnThemeVersion: 'v8light';
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
@mixin flexParent($grow: 1, $shrink: 1, $basis: auto, $direction: column) {
|
||||
flex: $grow $shrink $basis;
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
|
||||
> * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin kibanaCircleLogo() {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@mixin kibanaFullScreenGraphics($euiZLevel: $euiZLevel9) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: $euiZLevel + 1000;
|
||||
background: inherit;
|
||||
background-color: $euiPageBackgroundColor;
|
||||
opacity: 0;
|
||||
overflow: auto;
|
||||
animation: kibanaFullScreenGraphics_FadeIn $euiAnimSpeedExtraSlow $euiAnimSlightResistance 0s forwards;
|
||||
|
||||
@at-root {
|
||||
.kbnBody--hasHeaderBanner & {
|
||||
top: var(--kbnHeaderBannerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
content: url(lightOrDarkTheme('~core_app_image_assets/bg_top_branded.svg', '~core_app_image_assets/bg_top_branded_dark.svg'));
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
content: url(lightOrDarkTheme('~core_app_image_assets/bg_bottom_branded.svg', '~core_app_image_assets/bg_bottom_branded_dark.svg'));
|
||||
}
|
||||
|
||||
@keyframes kibanaFullScreenGraphics_FadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: map-get($euiBreakpoints, 'l')) {
|
||||
&::before, &::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 115 KiB |
|
@ -118,7 +118,7 @@ export class ImportResolver {
|
|||
}
|
||||
|
||||
// these are special webpack-aliases only used in storybooks, ignore them
|
||||
if (req === 'core_styles' || req === 'core_app_image_assets') {
|
||||
if (req === 'core_styles') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,12 +95,6 @@ describe('#resolve()', () => {
|
|||
}
|
||||
`);
|
||||
|
||||
expect(resolver.resolve('core_app_image_assets', FIXTURES_DIR)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"type": "ignore",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(resolver.resolve('@elastic/eui/src/components/foo', FIXTURES_DIR))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
|
18
src/platform/packages/shared/kbn-css-utils/README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# @kbn/css-utils
|
||||
|
||||
Shared Emotion-based CSS utilities for use across Kibana.
|
||||
|
||||
This package includes reusable styling helpers designed to support styling with Emotion.
|
||||
|
||||
## ✨ Included Utilities
|
||||
|
||||
- `useMemoCss`: React hook to memoize Emotion styles.
|
||||
- `kbnFullBodyHeightCss`: Utility for full-body-height layout styling.
|
||||
- `kbnFullScreenBgCss`: Full-screen graphics styling helper, used in various login page.
|
||||
|
||||
## 📌 Usage
|
||||
|
||||
To prevent unnecessary chunk size bloat, always import directly from specific helper files:
|
||||
|
||||
```ts
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
14
src/platform/packages/shared/kbn-css-utils/jest.config.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../../..',
|
||||
roots: ['<rootDir>/src/platform/packages/shared/kbn-css-utils'],
|
||||
};
|
9
src/platform/packages/shared/kbn-css-utils/kibana.jsonc
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/css-utils",
|
||||
"owner": [
|
||||
"@elastic/appex-sharedux",
|
||||
],
|
||||
"group": "platform",
|
||||
"visibility": "shared"
|
||||
}
|
7
src/platform/packages/shared/kbn-css-utils/package.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@kbn/css-utils",
|
||||
"version": "1.0.0",
|
||||
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0",
|
||||
"private": true,
|
||||
"sideEffects": false
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
// This file replaces scss core/public/_mixins.scss
|
||||
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
// The `--kbnAppHeadersOffset` CSS variable is automatically updated by
|
||||
// styles/rendering/_base.scss, based on whether the Kibana chrome has a
|
||||
// header banner, app menu, and is visible or hidden
|
||||
export const kbnFullBodyHeightCss = (additionalOffset = '0px') =>
|
||||
css({
|
||||
height: `calc(100vh - var(--kbnAppHeadersOffset, var(--euiFixedHeadersOffset, 0)) - ${additionalOffset})`,
|
||||
});
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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".
|
||||
*/
|
||||
|
||||
// This file replaces scss core/public/_mixins.scss
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { css, keyframes } from '@emotion/react';
|
||||
import { COLOR_MODES_STANDARD, UseEuiTheme, euiCanAnimate, useEuiTheme } from '@elastic/eui';
|
||||
import bg_top_branded from './images/bg_top_branded.svg';
|
||||
import bg_top_branded_dark from './images/bg_top_branded_dark.svg';
|
||||
import bg_bottom_branded from './images/bg_bottom_branded.svg';
|
||||
import bg_bottom_branded_dark from './images/bg_bottom_branded_dark.svg';
|
||||
|
||||
export const kbnFullScreenBgCss = ({ euiTheme, colorMode }: UseEuiTheme) => {
|
||||
const lightOrDarkTheme = (lightSvg: string, darkSvg: any) => {
|
||||
return colorMode === COLOR_MODES_STANDARD.light ? lightSvg : darkSvg;
|
||||
};
|
||||
const fullScreenGraphicsFadeIn = keyframes`
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
return css({
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: Number(euiTheme.levels.navigation) + 1000,
|
||||
background: 'inherit',
|
||||
backgroundColor: euiTheme.colors.backgroundBasePlain,
|
||||
opacity: 0,
|
||||
overflow: 'auto',
|
||||
[euiCanAnimate]: {
|
||||
animation: `${fullScreenGraphicsFadeIn} ${euiTheme.animation.extraSlow} ${euiTheme.animation.resistance} 0s forwards`,
|
||||
},
|
||||
'.kbnBody--hasHeaderBanner &': {
|
||||
top: 'var(--kbnHeaderBannerHeight)',
|
||||
},
|
||||
'&::before, &::after': {
|
||||
position: 'fixed',
|
||||
zIndex: 1,
|
||||
width: '400px',
|
||||
height: '400px',
|
||||
content: `url(${lightOrDarkTheme(bg_top_branded, bg_top_branded_dark)})`,
|
||||
[`@media (max-width: ${euiTheme.breakpoint.l}px)`]: {
|
||||
content: 'none',
|
||||
},
|
||||
},
|
||||
'&::before': {
|
||||
top: 0,
|
||||
left: 0,
|
||||
content: `url(${lightOrDarkTheme(bg_top_branded, bg_top_branded_dark)})`,
|
||||
},
|
||||
'&::after': {
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
content: `url(${lightOrDarkTheme(bg_bottom_branded, bg_bottom_branded_dark)})`,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useKbnFullScreenBgCss = () => {
|
||||
const euiTheme = useEuiTheme();
|
||||
const styles = useMemo(() => kbnFullScreenBgCss(euiTheme), [euiTheme]);
|
||||
return styles;
|
||||
};
|
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 116 KiB |
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
import { CSSInterpolation } from '@emotion/css';
|
||||
import { UseEuiTheme, useEuiTheme } from '@elastic/eui';
|
||||
|
||||
export type EmotionStyles = Record<
|
||||
string,
|
||||
CSSInterpolation | ((theme: UseEuiTheme) => CSSInterpolation)
|
||||
>;
|
||||
|
||||
type StaticEmotionStyles = Record<string, CSSInterpolation>;
|
||||
|
||||
/**
|
||||
* Custom hook to reduce boilerplate when working with Emotion styles that may depend on
|
||||
* the EUI theme.
|
||||
*
|
||||
* Accepts a map of styles where each entry is either a static Emotion style (via `css`)
|
||||
* or a function that returns styles based on the current `euiTheme`.
|
||||
*
|
||||
* It returns a memoized version of the style map with all values resolved to static
|
||||
* Emotion styles, allowing components to use a clean and unified object for styling.
|
||||
*
|
||||
* This helps simplify component code by centralizing theme-aware style logic.
|
||||
*
|
||||
* Example usage:
|
||||
* const componentStyles = {
|
||||
* container: css({ overflow: hidden }),
|
||||
* leftPane: ({ euiTheme }) => css({ paddingTop: euiTheme.size.m }),
|
||||
* }
|
||||
* const styles = useMemoCss(componentStyles);
|
||||
*/
|
||||
export const useMemoCss = (styleMap: EmotionStyles) => {
|
||||
const euiThemeContext = useEuiTheme();
|
||||
const outputStyles = useMemo(() => {
|
||||
return Object.entries(styleMap).reduce<StaticEmotionStyles>((acc, [key, value]) => {
|
||||
acc[key] = typeof value === 'function' ? value(euiThemeContext) : value;
|
||||
return acc;
|
||||
}, {});
|
||||
}, [euiThemeContext, styleMap]);
|
||||
return outputStyles;
|
||||
};
|
20
src/platform/packages/shared/kbn-css-utils/tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": "../../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"react",
|
||||
"@kbn/ambient-ui-types",
|
||||
],
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
],
|
||||
"kbn_references": [
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
]
|
||||
}
|
|
@ -53,7 +53,6 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
|
|||
extensions: ['.js', '.mjs', '.ts', '.tsx', '.json', '.mdx'],
|
||||
mainFields: ['browser', 'main'],
|
||||
alias: {
|
||||
core_app_image_assets: resolve(REPO_ROOT, 'src/core/public/styles/core_app/images'),
|
||||
core_styles: resolve(REPO_ROOT, 'src/core/public/index.scss'),
|
||||
vega: resolve(REPO_ROOT, 'node_modules/vega/build-es5/vega.js'),
|
||||
},
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
.interactiveSetup {
|
||||
@include kibanaFullScreenGraphics;
|
||||
}
|
||||
|
||||
.interactiveSetup__header {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
|
@ -11,7 +7,7 @@
|
|||
.interactiveSetup__logo {
|
||||
margin-bottom: $euiSizeXL;
|
||||
|
||||
@include kibanaCircleLogo;
|
||||
display: inline-block;
|
||||
@include euiBottomShadowMedium;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import type { FunctionComponent } from 'react';
|
|||
import React, { useState } from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
import { useKbnFullScreenBgCss } from '@kbn/css-utils/public/full_screen_bg_css';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { ClusterAddressForm } from './cluster_address_form';
|
||||
|
@ -38,6 +39,8 @@ export const App: FunctionComponent<AppProps> = ({ onSuccess }) => {
|
|||
[http]
|
||||
);
|
||||
|
||||
const kbnFullScreenBgCss = useKbnFullScreenBgCss();
|
||||
|
||||
if (state.loading) {
|
||||
return null;
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ export const App: FunctionComponent<AppProps> = ({ onSuccess }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="interactiveSetup">
|
||||
<div css={kbnFullScreenBgCss}>
|
||||
<header className="interactiveSetup__header eui-textCenter">
|
||||
<EuiSpacer size="xxl" />
|
||||
<span className="interactiveSetup__logo">
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"@kbn/core-preboot-server",
|
||||
"@kbn/security-hardening",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
// LAYOUT
|
||||
//
|
||||
|
||||
@mixin flexParent($grow: 1, $shrink: 1, $basis: auto, $direction: column) {
|
||||
flex: $grow $shrink $basis;
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
|
||||
> * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.visEditorSidebar {
|
||||
height: 100%;
|
||||
padding-left: $euiSizeS;
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { DEFAULT_CONTROL_GROW } from '../../../common';
|
||||
|
@ -46,7 +46,7 @@ export const ControlClone = ({
|
|||
);
|
||||
const isTwoLine = labelPosition === 'twoLine';
|
||||
|
||||
const styles = useMemoizedStyles(controlCloneStyles);
|
||||
const styles = useMemoCss(controlCloneStyles);
|
||||
|
||||
return (
|
||||
<EuiFlexItem
|
||||
|
|
|
@ -15,7 +15,7 @@ import { Markdown } from '@kbn/shared-ux-markdown';
|
|||
import { useErrorTextStyle } from '@kbn/react-hooks';
|
||||
import { css } from '@emotion/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
interface ControlErrorProps {
|
||||
error: Error | string;
|
||||
|
@ -51,7 +51,7 @@ export const ControlError = ({ error }: ControlErrorProps) => {
|
|||
const errorTextStyle = useErrorTextStyle();
|
||||
const [isPopoverOpen, setPopoverOpen] = useState(false);
|
||||
const errorMessage = error instanceof Error ? error.message : error || defaultMessage;
|
||||
const styles = useMemoizedStyles(controlErrorStyles);
|
||||
const styles = useMemoCss(controlErrorStyles);
|
||||
|
||||
const popoverButton = (
|
||||
<EuiButtonEmpty
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
apiPublishesViewMode,
|
||||
useBatchedOptionalPublishingSubjects,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import classNames from 'classnames';
|
||||
import { FloatingActions } from './floating_actions';
|
||||
import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '../../../common';
|
||||
|
@ -104,7 +104,7 @@ export const ControlPanel = <ApiType extends DefaultControlApi = DefaultControlA
|
|||
const insertBefore = isOver && (index ?? -1) < (activeIndex ?? -1);
|
||||
const insertAfter = isOver && (index ?? -1) > (activeIndex ?? -1);
|
||||
|
||||
const styles = useMemoizedStyles(controlPanelStyles);
|
||||
const styles = useMemoCss(controlPanelStyles);
|
||||
|
||||
return (
|
||||
<EuiFlexItem
|
||||
|
|
|
@ -17,7 +17,7 @@ import { Subscription, switchMap } from 'rxjs';
|
|||
import { ViewMode, apiHasUniqueId } from '@kbn/presentation-publishing';
|
||||
import { Action } from '@kbn/ui-actions-plugin/public';
|
||||
import { AnyApiAction } from '@kbn/presentation-panel-plugin/public/panel_actions/types';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { uiActionsService } from '../../services/kibana_services';
|
||||
import { CONTROL_HOVER_TRIGGER, controlHoverTrigger } from '../../actions/controls_hover_trigger';
|
||||
|
||||
|
@ -119,7 +119,7 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
|
|||
};
|
||||
}, [api, viewMode, disabledActions]);
|
||||
|
||||
const styles = useMemoizedStyles(floatingActionsStyles);
|
||||
const styles = useMemoCss(floatingActionsStyles);
|
||||
|
||||
return (
|
||||
<div css={styles.wrapper}>
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { isCompressed } from '../../../../control_group/utils/is_compressed';
|
||||
import { OptionsListSelection } from '../../../../../common/options_list/options_list_selections';
|
||||
import { MIN_POPOVER_WIDTH } from '../../../constants';
|
||||
|
@ -121,7 +121,7 @@ export const OptionsListControl = ({
|
|||
);
|
||||
|
||||
const delimiter = useMemo(() => OptionsListStrings.control.getSeparator(field?.type), [field]);
|
||||
const styles = useMemoizedStyles(optionListControlStyles);
|
||||
const styles = useMemoCss(optionListControlStyles);
|
||||
|
||||
const { hasSelections, selectionDisplayNode, selectedOptionsCount } = useMemo(() => {
|
||||
return {
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
useStateFromPublishingSubject,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { getCompatibleSearchTechniques } from '../../../../../common/options_list/suggestions_searching';
|
||||
import { useOptionsListContext } from '../options_list_context_provider';
|
||||
import { OptionsListPopoverSortingButton } from './options_list_popover_sorting_button';
|
||||
|
@ -89,7 +89,7 @@ export const OptionsListPopoverActionBar = ({
|
|||
[searchTechnique, compatibleSearchTechniques]
|
||||
);
|
||||
|
||||
const styles = useMemoizedStyles(optionsListPopoverStyles);
|
||||
const styles = useMemoCss(optionsListPopoverStyles);
|
||||
|
||||
return (
|
||||
<div className="optionsList__actions" css={styles.actions}>
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
} from '@kbn/presentation-publishing';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { useOptionsListContext } from '../options_list_context_provider';
|
||||
import { OptionsListStrings } from '../options_list_strings';
|
||||
|
||||
|
@ -39,7 +39,7 @@ const optionsListPopoverInvalidSelectionsStyles = {
|
|||
|
||||
export const OptionsListPopoverInvalidSelections = () => {
|
||||
const { componentApi } = useOptionsListContext();
|
||||
const styles = useMemoizedStyles(optionsListPopoverInvalidSelectionsStyles);
|
||||
const styles = useMemoCss(optionsListPopoverInvalidSelectionsStyles);
|
||||
|
||||
const [invalidSelections, fieldFormatter] = useBatchedPublishingSubjects(
|
||||
componentApi.invalidSelections$,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { EuiSelectableOption } from '@elastic/eui/src/components/selectable/sele
|
|||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { OptionsListSuggestions } from '../../../../../common/options_list/types';
|
||||
import { OptionsListSelection } from '../../../../../common/options_list/options_list_selections';
|
||||
import { MAX_OPTIONS_LIST_REQUEST_SIZE } from '../constants';
|
||||
|
@ -36,7 +36,7 @@ export const OptionsListPopoverSuggestions = ({
|
|||
} = useOptionsListContext();
|
||||
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const styles = useMemoizedStyles(optionListPopoverSuggestionsStyles);
|
||||
const styles = useMemoCss(optionListPopoverSuggestionsStyles);
|
||||
|
||||
const [
|
||||
sort,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
import React from 'react';
|
||||
import { EuiText, UseEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
interface Props {
|
||||
onClick: () => void;
|
||||
|
@ -52,7 +52,7 @@ const timeSliderStyles = {
|
|||
};
|
||||
|
||||
export function TimeSliderPopoverButton(props: Props) {
|
||||
const styles = useMemoizedStyles(timeSliderStyles);
|
||||
const styles = useMemoCss(timeSliderStyles);
|
||||
return (
|
||||
<button
|
||||
className="eui-textTruncate"
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
"@kbn/std",
|
||||
"@kbn/react-hooks",
|
||||
"@kbn/esql-types",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
|
||||
import { ViewMode } from '@kbn/presentation-publishing';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import type { DashboardAttributes } from '../../server/content_management';
|
||||
import {
|
||||
DASHBOARD_PANELS_UNSAVED_ID,
|
||||
|
@ -77,7 +77,7 @@ const DashboardUnsavedItem = ({
|
|||
onOpenClick: () => void;
|
||||
onDiscardClick: () => void;
|
||||
}) => {
|
||||
const styles = useMemoizedStyles(unsavedItemStyles);
|
||||
const styles = useMemoCss(unsavedItemStyles);
|
||||
return (
|
||||
<div css={styles.item}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="none" css={styles.heading} responsive={false}>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { GridLayout, GridPanelData, GridSectionData, type GridLayoutData } from
|
|||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import classNames from 'classnames';
|
||||
import { default as React, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { DASHBOARD_GRID_COLUMN_COUNT } from '../../../common/content_management/constants';
|
||||
import { GridData } from '../../../common/content_management/v2/types';
|
||||
import { areLayoutsEqual } from '../../dashboard_api/are_layouts_equal';
|
||||
|
@ -167,7 +167,7 @@ export const DashboardGrid = ({
|
|||
[appFixedViewport, dashboardContainerRef, dashboardInternalApi.layout$]
|
||||
);
|
||||
|
||||
const styles = useMemoizedStyles(dashboardGridStyles);
|
||||
const styles = useMemoCss(dashboardGridStyles);
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
|
||||
import { EuiLoadingChart, UseEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { EmbeddableRenderer } from '@kbn/embeddable-plugin/public';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import classNames from 'classnames';
|
||||
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { DashboardPanelState } from '../../../common';
|
||||
import { useDashboardApi } from '../../dashboard_api/use_dashboard_api';
|
||||
import { useDashboardInternalApi } from '../../dashboard_api/use_dashboard_internal_api';
|
||||
|
@ -106,7 +106,7 @@ export const Item = React.forwardRef<HTMLDivElement, Props>(
|
|||
|
||||
const dashboardContainerTopOffset = dashboardContainerRef?.current?.offsetTop || 0;
|
||||
const globalNavTopOffset = appFixedViewport?.offsetTop || 0;
|
||||
const styles = useMemoizedStyles(dashboardGridItemStyles);
|
||||
const styles = useMemoCss(dashboardGridItemStyles);
|
||||
|
||||
const renderedEmbeddable = useMemo(() => {
|
||||
const panelProps = {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { ExitFullScreenButton } from '@kbn/shared-ux-button-exit-full-screen';
|
|||
import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common';
|
||||
import { ControlGroupApi } from '@kbn/controls-plugin/public';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { CONTROL_GROUP_EMBEDDABLE_ID } from '../../dashboard_api/control_group_manager';
|
||||
import { useDashboardApi } from '../../dashboard_api/use_dashboard_api';
|
||||
import { useDashboardInternalApi } from '../../dashboard_api/use_dashboard_internal_api';
|
||||
|
@ -103,7 +103,7 @@ export const DashboardViewport = ({
|
|||
}, [dashboard]);
|
||||
*/
|
||||
|
||||
const styles = useMemoizedStyles(dashboardViewportStyles);
|
||||
const styles = useMemoCss(dashboardViewportStyles);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -24,7 +24,7 @@ import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
|
|||
|
||||
import useMountedState from 'react-use/lib/useMountedState';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api';
|
||||
import { coreServices } from '../../../services/kibana_services';
|
||||
import { getDashboardCapabilities } from '../../../utils/get_dashboard_capabilities';
|
||||
|
@ -43,7 +43,7 @@ export function DashboardEmptyScreen() {
|
|||
const viewMode = useStateFromPublishingSubject(dashboardApi.viewMode$);
|
||||
const isEditMode = viewMode === 'edit';
|
||||
|
||||
const styles = useMemoizedStyles(emptyScreenStyles);
|
||||
const styles = useMemoCss(emptyScreenStyles);
|
||||
|
||||
// TODO replace these SVGs with versions from EuiIllustration as soon as it becomes available.
|
||||
const imageUrl = coreServices.http.basePath.prepend(
|
||||
|
|
|
@ -21,7 +21,8 @@ import {
|
|||
UseEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { MountPoint, useMemoizedStyles } from '@kbn/core/public';
|
||||
import { MountPoint } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { Query } from '@kbn/es-query';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { getManagedContentBadge } from '@kbn/managed-content-badge';
|
||||
|
@ -114,7 +115,7 @@ export function InternalDashboardTopNav({
|
|||
return getDashboardTitle(title, viewMode, !lastSavedId);
|
||||
}, [title, viewMode, lastSavedId]);
|
||||
|
||||
const styles = useMemoizedStyles(topNavStyles);
|
||||
const styles = useMemoCss(topNavStyles);
|
||||
|
||||
/**
|
||||
* focus on the top header when title or view mode is changed
|
||||
|
|
|
@ -85,7 +85,8 @@
|
|||
"@kbn/esql-types",
|
||||
"@kbn/saved-objects-tagging-plugin",
|
||||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/std"
|
||||
"@kbn/std",
|
||||
"@kbn/css-utils"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import type { UseColumnsProps } from '@kbn/unified-data-table';
|
|||
import { popularizeField, useColumns } from '@kbn/unified-data-table';
|
||||
import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
|
||||
import type { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
|
||||
import { kibanaFullBodyHeightCss } from '@kbn/core/public';
|
||||
import { kbnFullBodyHeightCss } from '@kbn/css-utils/public/full_body_height_css';
|
||||
import { ContextErrorMessage } from './components/context_error_message';
|
||||
import { LoadingStatus } from './services/context_query_state';
|
||||
import type { AppState, GlobalState } from './services/context_state';
|
||||
|
@ -331,5 +331,5 @@ const styles = {
|
|||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
}),
|
||||
docsPage: kibanaFullBodyHeightCss('54px'), // 54px is the action bar height
|
||||
docsPage: kbnFullBodyHeightCss('54px'), // 54px is the action bar height
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ import { popularizeField, useColumns } from '@kbn/unified-data-table';
|
|||
import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
|
||||
import { kibanaFullBodyHeightCss } from '@kbn/core/public';
|
||||
import { kbnFullBodyHeightCss } from '@kbn/css-utils/public/full_body_height_css';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { useSavedSearchInitial } from '../../state_management/discover_state_provider';
|
||||
import type { DiscoverStateContainer } from '../../state_management/discover_state';
|
||||
|
@ -378,7 +378,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
|
|||
background-color: ${pageBackgroundColor};
|
||||
|
||||
${useEuiBreakpoint(['m', 'l', 'xl'])} {
|
||||
${kibanaFullBodyHeightCss(TABS_ENABLED ? '32px' : undefined)}
|
||||
${kbnFullBodyHeightCss(TABS_ENABLED ? '32px' : undefined)}
|
||||
}
|
||||
`}
|
||||
>
|
||||
|
|
|
@ -106,7 +106,8 @@
|
|||
"@kbn/unified-tabs",
|
||||
"@kbn/unified-histogram",
|
||||
"@kbn/alerts-ui-shared",
|
||||
"@kbn/core-pricing-browser-mocks"
|
||||
"@kbn/core-pricing-browser-mocks",
|
||||
"@kbn/css-utils"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -24,12 +24,11 @@ import {
|
|||
UseEuiTheme,
|
||||
useEuiShadow,
|
||||
mathWithUnits,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { css } from '@emotion/react';
|
||||
import { fullScreenGraphicsMixinStyles } from '@kbn/core/public';
|
||||
import { useKbnFullScreenBgCss } from '@kbn/css-utils/public/full_screen_bg_css';
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
import { SampleDataCard } from './sample_data';
|
||||
|
@ -44,7 +43,8 @@ interface WelcomeProps {
|
|||
export const Welcome: React.FC<WelcomeProps> = ({ urlBasePath, onSkip }: WelcomeProps) => {
|
||||
const services = getServices();
|
||||
const euiShadowM = useEuiShadow('m');
|
||||
const theme = useEuiTheme();
|
||||
|
||||
const kbnFullScreenBgCss = useKbnFullScreenBgCss();
|
||||
|
||||
const redirectToAddData = () => {
|
||||
services.application.navigateToApp('integrations', { path: '/browse' });
|
||||
|
@ -80,13 +80,7 @@ export const Welcome: React.FC<WelcomeProps> = ({ urlBasePath, onSkip }: Welcome
|
|||
|
||||
return (
|
||||
<EuiPortal>
|
||||
<div
|
||||
data-test-subj="homeWelcomeInterstitial"
|
||||
css={[
|
||||
styles,
|
||||
fullScreenGraphicsMixinStyles(Number(theme.euiTheme.levels.navigation), theme),
|
||||
]}
|
||||
>
|
||||
<div data-test-subj="homeWelcomeInterstitial" css={[styles, kbnFullScreenBgCss]}>
|
||||
<header className="homeWelcome__header">
|
||||
<div className="homeWelcome__content eui-textCenter">
|
||||
<EuiSpacer size="xl" />
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"@kbn/core-http-browser",
|
||||
"@kbn/deeplinks-observability",
|
||||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { DataTableRecord } from '@kbn/discover-utils/types';
|
||||
import { ElasticRequestState } from '@kbn/unified-doc-viewer';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { useEsDocSearch } from '../../hooks';
|
||||
import { getHeight, DEFAULT_MARGIN_BOTTOM } from './get_height';
|
||||
import { JSONCodeEditorCommonMemoized } from '../json_code_editor';
|
||||
|
@ -51,7 +51,7 @@ export const DocViewerSource = ({
|
|||
decreaseAvailableHeightBy,
|
||||
onRefresh,
|
||||
}: SourceViewerProps) => {
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
|
||||
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor>();
|
||||
const [editorHeight, setEditorHeight] = useState<number>();
|
||||
|
|
|
@ -38,7 +38,7 @@ import {
|
|||
canPrependTimeFieldColumn,
|
||||
} from '@kbn/discover-utils';
|
||||
import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
import { getUnifiedDocViewerServices } from '../../plugin';
|
||||
import {
|
||||
|
@ -136,7 +136,7 @@ export const DocViewerTable = ({
|
|||
onAddColumn,
|
||||
onRemoveColumn,
|
||||
}: DocViewRenderProps) => {
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
|
||||
const isEsqlMode = Array.isArray(textBasedHits);
|
||||
const [containerRef, setContainerRef] = useState<HTMLDivElement | null>(null);
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
import React, { Fragment, useCallback, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { IgnoredReason } from '@kbn/discover-utils';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
export const DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT = 110;
|
||||
|
||||
|
@ -111,7 +111,7 @@ export const TableFieldValue = ({
|
|||
isDetails,
|
||||
isHighlighted,
|
||||
}: TableFieldValueProps) => {
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
|
||||
const truncationHeight = DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT;
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
"@kbn/embeddable-plugin",
|
||||
"@kbn/apm-types-shared",
|
||||
"@kbn/object-utils",
|
||||
"@kbn/es-query"
|
||||
"@kbn/es-query",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
@mixin flexParent($grow: 1, $shrink: 1, $basis: auto, $direction: column) {
|
||||
flex: $grow $shrink $basis;
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
|
||||
> * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.visEditor {
|
||||
height: 100%;
|
||||
@include flexParent();
|
||||
|
|
|
@ -716,6 +716,8 @@
|
|||
"@kbn/crypto/*": ["src/platform/packages/shared/kbn-crypto/*"],
|
||||
"@kbn/crypto-browser": ["src/platform/packages/shared/kbn-crypto-browser"],
|
||||
"@kbn/crypto-browser/*": ["src/platform/packages/shared/kbn-crypto-browser/*"],
|
||||
"@kbn/css-utils": ["src/platform/packages/shared/kbn-css-utils"],
|
||||
"@kbn/css-utils/*": ["src/platform/packages/shared/kbn-css-utils/*"],
|
||||
"@kbn/custom-branding-plugin": ["x-pack/platform/plugins/private/custom_branding"],
|
||||
"@kbn/custom-branding-plugin/*": ["x-pack/platform/plugins/private/custom_branding/*"],
|
||||
"@kbn/custom-icons": ["src/platform/packages/shared/kbn-custom-icons"],
|
||||
|
|
|
@ -35,7 +35,6 @@ module.exports = {
|
|||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
core_app_image_assets: path.resolve(KIBANA_ROOT, 'src/core/public/styles/core_app/images'),
|
||||
[require.resolve('@elastic/eui/es/components/drag_and_drop')]: false,
|
||||
},
|
||||
extensions: ['.js', '.json', '.ts', '.tsx', '.scss'],
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { kibanaFullBodyHeightCss, useMemoizedStyles } from '@kbn/core/public';
|
||||
import { kbnFullBodyHeightCss } from '@kbn/css-utils/public/full_body_height_css';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiTitle, UseEuiTheme } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { formatRequestPayload, formatJson } from '../lib/format';
|
||||
|
@ -41,7 +42,7 @@ const mainStyles = {
|
|||
// (they're both the same height, hence the x2)
|
||||
const bodyOffset = `(${bottomBarHeight} * 2)`;
|
||||
|
||||
return kibanaFullBodyHeightCss(bodyOffset);
|
||||
return kbnFullBodyHeightCss(bodyOffset);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -53,7 +54,7 @@ export const Main: React.FunctionComponent = () => {
|
|||
links,
|
||||
} = useAppContext();
|
||||
|
||||
const styles = useMemoizedStyles(mainStyles);
|
||||
const styles = useMemoCss(mainStyles);
|
||||
const [isRequestFlyoutOpen, setRequestFlyoutOpen] = useState(false);
|
||||
const { inProgress, response, submit } = useSubmitCode(http);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { Response } from '../../types';
|
||||
import { OutputTab } from './output_tab';
|
||||
import { ParametersTab } from './parameters_tab';
|
||||
|
@ -49,7 +49,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export const OutputPane: FunctionComponent<Props> = ({ isLoading, response }) => {
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
const outputTabLabel = (
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"@kbn/code-editor",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/scout",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { UseEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { getColorPalette, getLinearGradient } from '../../../color_palettes';
|
||||
|
||||
interface Props {
|
||||
|
@ -29,7 +29,7 @@ const componentStyles = {
|
|||
};
|
||||
export const ColorGradient = ({ colorPaletteId }: Props) => {
|
||||
const palette = getColorPalette(colorPaletteId);
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
return palette.length ? (
|
||||
<div css={styles.mapColorGradientStyles} style={{ background: getLinearGradient(palette) }} />
|
||||
) : null;
|
||||
|
|
|
@ -11,7 +11,7 @@ import { EuiSpacer, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiFormRow } from
|
|||
import { removeRow, isColorInvalid } from './color_stops_utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { MbValidatedColorPicker } from './mb_validated_color_picker';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { mapColorStopsStyles } from '../map_color_stops.styles';
|
||||
|
||||
export const ColorStops = ({
|
||||
|
@ -23,7 +23,7 @@ export const ColorStops = ({
|
|||
addNewRow,
|
||||
swatches,
|
||||
}) => {
|
||||
const styles = useMemoizedStyles(mapColorStopsStyles);
|
||||
const styles = useMemoCss(mapColorStopsStyles);
|
||||
function getStopInput(stop, index) {
|
||||
const onStopChange = (newStopValue) => {
|
||||
const newColorStops = _.cloneDeep(colorStops);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React, { ReactElement } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiText, UseEuiTheme } from '@elastic/eui';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { VECTOR_STYLES } from '../../../../../../common/constants';
|
||||
import { VectorIcon } from './vector_icon';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export function Category({
|
|||
symbolId,
|
||||
svg,
|
||||
}: Props) {
|
||||
const styles = useMemoizedStyles(categoryStyles);
|
||||
const styles = useMemoCss(categoryStyles);
|
||||
|
||||
function renderIcon() {
|
||||
if (styleName === VECTOR_STYLES.LABEL_COLOR) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { EuiText, UseEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { StyleError } from './style_error';
|
||||
import {
|
||||
DynamicStyleProperty,
|
||||
|
@ -51,7 +51,7 @@ export function VectorStyleLegend({
|
|||
}: Props) {
|
||||
const legendRows = [];
|
||||
|
||||
const cssStyles = useMemoizedStyles(vectorStyleLegendStyles);
|
||||
const cssStyles = useMemoCss(vectorStyleLegendStyles);
|
||||
|
||||
for (let i = 0; i < styles.length; i++) {
|
||||
const styleMetaDataRequest = styles[i].isDynamic()
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { css } from '@emotion/react';
|
||||
import { UseEuiTheme } from '@elastic/eui';
|
||||
import type { EmotionStyles } from '@kbn/core/public';
|
||||
import type { EmotionStyles } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
export const mapColorStopsStyles: EmotionStyles = {
|
||||
mapColorStops: ({ euiTheme }: UseEuiTheme) =>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { IconSelect } from './icon_select';
|
|||
import { StopInput } from '../stop_input';
|
||||
import { getMakiSymbol, PREFERRED_ICONS, SYMBOL_OPTIONS } from '../../symbol_utils';
|
||||
import { mapColorStopsStyles } from '../map_color_stops.styles';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
function isDuplicateStop(targetStop, iconStops) {
|
||||
const stops = iconStops.filter(({ stop }) => {
|
||||
|
@ -53,7 +53,7 @@ export function IconStops({
|
|||
onCustomIconsChange,
|
||||
customIcons,
|
||||
}) {
|
||||
const styles = useMemoizedStyles(mapColorStopsStyles);
|
||||
const styles = useMemoCss(mapColorStopsStyles);
|
||||
return iconStops
|
||||
.map(({ stop, icon, iconSource }, index) => {
|
||||
const iconInfo =
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { UseEuiTheme } from '@elastic/eui';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { SymbolIcon } from '../legend/symbol_icon';
|
||||
import { getIsDarkMode } from '../../../../../kibana_services';
|
||||
|
||||
|
@ -18,7 +18,7 @@ const prependButtonStyles = {
|
|||
};
|
||||
|
||||
export const PrependButton = ({ value, svg }: { value: string; svg: string }) => {
|
||||
const styles = useMemoizedStyles(prependButtonStyles);
|
||||
const styles = useMemoCss(prependButtonStyles);
|
||||
return (
|
||||
<SymbolIcon
|
||||
key={value}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { ActionExecutionContext, Action } from '@kbn/ui-actions-plugin/public';
|
|||
import { Observable } from 'rxjs';
|
||||
import { ExitFullScreenButton } from '@kbn/shared-ux-button-exit-full-screen';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { MBMap } from '../mb_map';
|
||||
import { RightSideControls } from '../right_side_controls';
|
||||
import { Timeslider } from '../timeslider';
|
||||
|
@ -269,7 +269,7 @@ const FlyoutPanelWrapper = ({ flyoutDisplay }: { flyoutDisplay: FLYOUT_STATE })
|
|||
flyoutPanel = <MapSettingsPanel />;
|
||||
}
|
||||
const isVisible = !!flyoutPanel;
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
return (
|
||||
<EuiFlexItem
|
||||
css={[styles.flyoutPanelWrapperStyles, isVisible && styles.flyoutVisibleStyles]}
|
||||
|
|
|
@ -38,13 +38,6 @@ exports[`isFullScreen 1`] = `
|
|||
"_insertTag": [Function],
|
||||
"before": null,
|
||||
"container": <head>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
>
|
||||
|
||||
.css-721pd1-floatTopRight{position:absolute;top:-8px;right:-8px;}
|
||||
</style>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
|
@ -147,13 +140,6 @@ exports[`render 1`] = `
|
|||
"_insertTag": [Function],
|
||||
"before": null,
|
||||
"container": <head>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
>
|
||||
|
||||
.css-721pd1-floatTopRight{position:absolute;top:-8px;right:-8px;}
|
||||
</style>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
|
|
|
@ -10,7 +10,7 @@ import React, { useEffect, useState, useCallback } from 'react';
|
|||
import { UseEuiTheme } from '@elastic/eui';
|
||||
import type { Map as MapboxMap } from '@kbn/mapbox-gl';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
|
||||
const MAX_WIDTH = 110;
|
||||
|
||||
|
@ -59,7 +59,7 @@ const componentStyles = {
|
|||
export const ScaleControl: React.FC<Props> = ({ isFullScreen, mbMap }) => {
|
||||
const [label, setLabel] = useState('');
|
||||
const [width, setWidth] = useState(0);
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
const onUpdate = useCallback(() => {
|
||||
const container = mbMap.getContainer();
|
||||
const centerHeight = container.clientHeight / 2;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import _ from 'lodash';
|
||||
import React, { Component, CSSProperties, RefObject, ReactNode } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { useMemoizedStyles } from '@kbn/core/public';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiLoadingSpinner,
|
||||
|
@ -386,7 +386,7 @@ interface MapFeatureTooltipRowProps {
|
|||
}
|
||||
|
||||
export const MapFeatureTooltipRow = ({ children, className }: MapFeatureTooltipRowProps) => {
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
return (
|
||||
<tr css={styles.mapFeatureTooltipRowStyles} className={className}>
|
||||
{children}
|
||||
|
|
|
@ -14,8 +14,8 @@ import {
|
|||
AppMountParameters,
|
||||
KibanaExecutionContext,
|
||||
ScopedHistory,
|
||||
kibanaFullBodyHeightCss,
|
||||
} from '@kbn/core/public';
|
||||
import { kbnFullBodyHeightCss } from '@kbn/css-utils/public/full_body_height_css';
|
||||
import { Adapters } from '@kbn/inspector-plugin/public';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { type Filter, FilterStateStore, type Query, type TimeRange } from '@kbn/es-query';
|
||||
|
@ -71,7 +71,7 @@ const styles = {
|
|||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
kibanaFullBodyHeightCss(),
|
||||
kbnFullBodyHeightCss(),
|
||||
]),
|
||||
fullScreen: css({
|
||||
height: '100vh !important',
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
"@kbn/react-hooks",
|
||||
"@kbn/scout",
|
||||
"@kbn/react-kibana-mount",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -17,8 +17,8 @@ import {
|
|||
EuiPanel,
|
||||
UseEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { kibanaFullBodyHeightCss, useMemoizedStyles } from '@kbn/core/public';
|
||||
import { kbnFullBodyHeightCss } from '@kbn/css-utils/public/full_body_height_css';
|
||||
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
SearchProfilerTabs,
|
||||
|
@ -41,7 +41,7 @@ const componentStyles = {
|
|||
overflow: 'hidden',
|
||||
flexShrink: 1,
|
||||
}, // adding dev tool top bar to the body offset
|
||||
kibanaFullBodyHeightCss(`(${euiTheme.size.base} * 3)`),
|
||||
kbnFullBodyHeightCss(`(${euiTheme.size.base} * 3)`),
|
||||
]),
|
||||
};
|
||||
|
||||
|
@ -103,7 +103,7 @@ export const App = () => {
|
|||
return null;
|
||||
};
|
||||
|
||||
const styles = useMemoizedStyles(componentStyles);
|
||||
const styles = useMemoCss(componentStyles);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/code-editor",
|
||||
"@kbn/monaco",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AuthenticationStatePage renders 1`] = `
|
||||
<div
|
||||
className="secAuthenticationStatePage "
|
||||
>
|
||||
<header
|
||||
className="secAuthenticationStatePage__header"
|
||||
>
|
||||
<div
|
||||
className="secAuthenticationStatePage__content eui-textCenter"
|
||||
>
|
||||
<EuiSpacer
|
||||
size="xxl"
|
||||
/>
|
||||
<span
|
||||
className="secAuthenticationStatePage__logo"
|
||||
>
|
||||
<EuiIcon
|
||||
size="xxl"
|
||||
type="logoElastic"
|
||||
/>
|
||||
</span>
|
||||
<EuiTitle
|
||||
className="secAuthenticationStatePage__title"
|
||||
size="l"
|
||||
>
|
||||
<h1>
|
||||
foo
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="xl"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div
|
||||
className="secAuthenticationStatePage__content eui-textCenter"
|
||||
>
|
||||
<span>
|
||||
hello world
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -1,7 +1,3 @@
|
|||
.secAuthenticationStatePage {
|
||||
@include kibanaFullScreenGraphics;
|
||||
}
|
||||
|
||||
.secAuthenticationStatePage__header {
|
||||
position: relative;
|
||||
padding: $euiSizeXL;
|
||||
|
@ -11,7 +7,7 @@
|
|||
.secAuthenticationStatePage__logo {
|
||||
margin-bottom: $euiSizeXL;
|
||||
|
||||
@include kibanaCircleLogo;
|
||||
display: inline-block;
|
||||
@include euiBottomShadowMedium;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,30 +5,53 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { shallowWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { renderWithI18n } from '@kbn/test-jest-helpers';
|
||||
|
||||
import { AuthenticationStatePage } from './authentication_state_page';
|
||||
|
||||
describe('AuthenticationStatePage', () => {
|
||||
it('renders', () => {
|
||||
expect(
|
||||
shallowWithIntl(
|
||||
<AuthenticationStatePage title={'foo'}>
|
||||
<span>hello world</span>
|
||||
</AuthenticationStatePage>
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
it('renders the title, child content, and layout elements correctly', () => {
|
||||
const { container } = renderWithI18n(
|
||||
<AuthenticationStatePage title="foo">
|
||||
<span>hello world</span>
|
||||
</AuthenticationStatePage>
|
||||
);
|
||||
|
||||
// Page wrapper with expected class
|
||||
const wrapper = container.querySelector('.secAuthenticationStatePage');
|
||||
expect(wrapper).toBeInTheDocument();
|
||||
|
||||
// Header section
|
||||
const header = container.querySelector('.secAuthenticationStatePage__header');
|
||||
expect(header).toBeInTheDocument();
|
||||
|
||||
// Title in <h1>
|
||||
const title = screen.getByRole('heading', { level: 1, name: 'foo' });
|
||||
expect(title).toBeInTheDocument();
|
||||
|
||||
// Child content
|
||||
expect(screen.getByText('hello world')).toBeInTheDocument();
|
||||
|
||||
// Icon wrapper with logo class
|
||||
const logoWrapper = container.querySelector('.secAuthenticationStatePage__logo');
|
||||
expect(logoWrapper).toBeInTheDocument();
|
||||
|
||||
// Check the EuiIcon is rendered with correct type
|
||||
const icon = logoWrapper?.querySelector('[data-euiicon-type="logoElastic"]');
|
||||
expect(icon).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with custom CSS class', () => {
|
||||
const { container } = renderWithI18n(
|
||||
<AuthenticationStatePage className="customClassName" title={'foo'}>
|
||||
<span>hello world</span>
|
||||
</AuthenticationStatePage>
|
||||
);
|
||||
expect(
|
||||
shallowWithIntl(
|
||||
<AuthenticationStatePage className="customClassName" title={'foo'}>
|
||||
<span>hello world</span>
|
||||
</AuthenticationStatePage>
|
||||
).exists('.secAuthenticationStatePage.customClassName')
|
||||
).toBe(true);
|
||||
container.querySelector('.secAuthenticationStatePage.customClassName')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,30 +11,36 @@ import { EuiIcon, EuiImage, EuiSpacer, EuiTitle } from '@elastic/eui';
|
|||
import type { FC, PropsWithChildren } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useKbnFullScreenBgCss } from '@kbn/css-utils/public/full_screen_bg_css';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
title: React.ReactNode;
|
||||
logo?: string;
|
||||
}
|
||||
|
||||
export const AuthenticationStatePage: FC<PropsWithChildren<Props>> = (props) => (
|
||||
<div className={`secAuthenticationStatePage ${props.className || ''}`}>
|
||||
<header className="secAuthenticationStatePage__header">
|
||||
<div className="secAuthenticationStatePage__content eui-textCenter">
|
||||
<EuiSpacer size="xxl" />
|
||||
<span className="secAuthenticationStatePage__logo">
|
||||
{props.logo ? (
|
||||
<EuiImage src={props.logo} size={40} alt={'logo'} />
|
||||
) : (
|
||||
<EuiIcon type="logoElastic" size="xxl" />
|
||||
)}
|
||||
</span>
|
||||
<EuiTitle size="l" className="secAuthenticationStatePage__title">
|
||||
<h1>{props.title}</h1>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="xl" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="secAuthenticationStatePage__content eui-textCenter">{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
export const AuthenticationStatePage: FC<PropsWithChildren<Props>> = (props) => {
|
||||
const kbnFullScreenBgCss = useKbnFullScreenBgCss();
|
||||
|
||||
return (
|
||||
<div className={`secAuthenticationStatePage ${props.className || ''}`} css={kbnFullScreenBgCss}>
|
||||
<header className="secAuthenticationStatePage__header">
|
||||
<div className="secAuthenticationStatePage__content eui-textCenter">
|
||||
<EuiSpacer size="xxl" />
|
||||
<span className="secAuthenticationStatePage__logo">
|
||||
{props.logo ? (
|
||||
<EuiImage src={props.logo} size={40} alt={'logo'} />
|
||||
) : (
|
||||
<EuiIcon type="logoElastic" size="xxl" />
|
||||
)}
|
||||
</span>
|
||||
<EuiTitle size="l" className="secAuthenticationStatePage__title">
|
||||
<h1>{props.title}</h1>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="xl" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="secAuthenticationStatePage__content eui-textCenter">{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -293,170 +293,369 @@ exports[`LoginPage enabled form state renders as expected when loginHelp is set
|
|||
`;
|
||||
|
||||
exports[`LoginPage page renders as expected 1`] = `
|
||||
<div
|
||||
className="loginWelcome login-form"
|
||||
>
|
||||
<header
|
||||
className="loginWelcome__header"
|
||||
>
|
||||
<div
|
||||
className="loginWelcome__content eui-textCenter"
|
||||
>
|
||||
<span
|
||||
className="loginWelcome__logo"
|
||||
style={Object {}}
|
||||
>
|
||||
<EuiIcon
|
||||
size="xxl"
|
||||
type="logoElastic"
|
||||
/>
|
||||
</span>
|
||||
<EuiTitle
|
||||
className="loginWelcome__title"
|
||||
data-test-subj="loginWelcomeTitle"
|
||||
size="m"
|
||||
>
|
||||
<h1>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Welcome to Elastic"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
</header>
|
||||
<div>
|
||||
<div
|
||||
className="loginWelcome__content loginWelcome-body"
|
||||
class="loginWelcome login-form css-1gj8l3e-kbnFullScreenBgCss"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
gutterSize="l"
|
||||
<header
|
||||
class="loginWelcome__header"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<LoginForm
|
||||
http={
|
||||
Object {
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"get": [MockFunction],
|
||||
}
|
||||
}
|
||||
loginAssistanceMessage=""
|
||||
notifications={
|
||||
Object {
|
||||
"showErrorDialog": [MockFunction],
|
||||
"toasts": Object {
|
||||
"add": [MockFunction],
|
||||
"addDanger": [MockFunction],
|
||||
"addError": [MockFunction],
|
||||
"addInfo": [MockFunction],
|
||||
"addSuccess": [MockFunction],
|
||||
"addWarning": [MockFunction],
|
||||
"get$": [MockFunction],
|
||||
"remove": [MockFunction],
|
||||
},
|
||||
}
|
||||
}
|
||||
selector={
|
||||
Object {
|
||||
"enabled": false,
|
||||
"providers": Array [
|
||||
Object {
|
||||
"name": "basic1",
|
||||
"type": "basic",
|
||||
"usesLoginForm": true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<div
|
||||
class="loginWelcome__content eui-textCenter"
|
||||
>
|
||||
<span
|
||||
class="loginWelcome__logo"
|
||||
>
|
||||
<span
|
||||
data-euiicon-type="logoElastic"
|
||||
/>
|
||||
</span>
|
||||
<h1
|
||||
class="euiTitle loginWelcome__title emotion-euiTitle-m"
|
||||
data-test-subj="loginWelcomeTitle"
|
||||
>
|
||||
Welcome to Elastic
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div
|
||||
class="loginWelcome__content loginWelcome-body"
|
||||
>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<div
|
||||
class="euiPanel euiPanel--transparent euiPanel--paddingMedium emotion-euiPanel-grow-m-m-transparent"
|
||||
data-test-subj="loginForm"
|
||||
>
|
||||
<form>
|
||||
<div
|
||||
class="euiFormRow euiFormRow--hasLabel emotion-euiFormRow"
|
||||
id="generated-id-row"
|
||||
>
|
||||
<div
|
||||
class="euiFormRow__labelWrapper"
|
||||
>
|
||||
<label
|
||||
aria-invalid="false"
|
||||
class="euiFormLabel euiFormRow__label euiFormLabel-isFocused emotion-euiFormLabel-focused"
|
||||
for="generated-id"
|
||||
id="generated-id-label"
|
||||
>
|
||||
Username
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow__fieldWrapper"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout emotion-euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
autocomplete="off"
|
||||
class="euiFieldText emotion-euiFieldText"
|
||||
data-test-subj="loginUsername"
|
||||
id="generated-id"
|
||||
name="username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow euiFormRow--hasLabel emotion-euiFormRow"
|
||||
id="generated-id-row"
|
||||
>
|
||||
<div
|
||||
class="euiFormRow__labelWrapper"
|
||||
>
|
||||
<label
|
||||
aria-invalid="false"
|
||||
class="euiFormLabel euiFormRow__label emotion-euiFormLabel"
|
||||
for="generated-id"
|
||||
id="generated-id-label"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow__fieldWrapper"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout euiFormControlLayout--group emotion-euiFormControlLayout-group"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper-inGroup-appendOnly"
|
||||
style="--euiFormControlLeftIconsCount: 1;"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayoutIcons emotion-euiFormControlLayoutIcons-absolute-left"
|
||||
>
|
||||
<span
|
||||
class="euiFormControlLayoutCustomIcon emotion-euiFormControlLayoutCustomIcon"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="euiFormControlLayoutCustomIcon__icon"
|
||||
data-euiicon-type="lock"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
aria-required="true"
|
||||
autocomplete="off"
|
||||
class="euiFieldPassword emotion-euiFieldPassword-inGroup-withToggle"
|
||||
data-test-subj="loginPassword"
|
||||
id="generated-id"
|
||||
name="password"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormControlLayout__append emotion-euiFormControlLayout__side-append"
|
||||
>
|
||||
<button
|
||||
aria-label="Show password as plain text. Note: this will visually expose your password on the screen."
|
||||
class="euiButtonIcon emotion-euiButtonIcon-xs-empty-primary"
|
||||
title="Show password as plain text. Note: this will visually expose your password on the screen."
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="euiButtonIcon__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="eye"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="euiSpacer euiSpacer--l emotion-euiSpacer-l"
|
||||
/>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-s-flexStart-center-row"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<button
|
||||
class="euiButton emotion-euiButtonDisplay-m-fullWidth-defaultMinWidth-fill-primary"
|
||||
data-test-subj="loginSubmit"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="emotion-euiButtonDisplayContent"
|
||||
>
|
||||
Log in
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`LoginPage page renders with custom branding 1`] = `
|
||||
<div
|
||||
className="loginWelcome login-form"
|
||||
>
|
||||
<header
|
||||
className="loginWelcome__header"
|
||||
>
|
||||
<div
|
||||
className="loginWelcome__content eui-textCenter"
|
||||
>
|
||||
<span
|
||||
className="loginWelcome__logo"
|
||||
style={
|
||||
Object {
|
||||
"padding": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<EuiImage
|
||||
alt="logo"
|
||||
size={40}
|
||||
src="logo"
|
||||
/>
|
||||
</span>
|
||||
<EuiTitle
|
||||
className="loginWelcome__title"
|
||||
data-test-subj="loginWelcomeTitle"
|
||||
size="m"
|
||||
>
|
||||
<h1>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Welcome to Elastic"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
</header>
|
||||
<div>
|
||||
<div
|
||||
className="loginWelcome__content loginWelcome-body"
|
||||
class="loginWelcome login-form css-1gj8l3e-kbnFullScreenBgCss"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
gutterSize="l"
|
||||
<header
|
||||
class="loginWelcome__header"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<LoginForm
|
||||
http={
|
||||
Object {
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"get": [MockFunction],
|
||||
}
|
||||
}
|
||||
loginAssistanceMessage=""
|
||||
notifications={
|
||||
Object {
|
||||
"showErrorDialog": [MockFunction],
|
||||
"toasts": Object {
|
||||
"add": [MockFunction],
|
||||
"addDanger": [MockFunction],
|
||||
"addError": [MockFunction],
|
||||
"addInfo": [MockFunction],
|
||||
"addSuccess": [MockFunction],
|
||||
"addWarning": [MockFunction],
|
||||
"get$": [MockFunction],
|
||||
"remove": [MockFunction],
|
||||
},
|
||||
}
|
||||
}
|
||||
selector={
|
||||
Object {
|
||||
"enabled": false,
|
||||
"providers": Array [
|
||||
Object {
|
||||
"name": "basic1",
|
||||
"type": "basic",
|
||||
"usesLoginForm": true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<div
|
||||
class="loginWelcome__content eui-textCenter"
|
||||
>
|
||||
<span
|
||||
class="loginWelcome__logo"
|
||||
style="padding: 0px;"
|
||||
>
|
||||
<figure
|
||||
class="euiImageWrapper emotion-euiImageWrapper"
|
||||
>
|
||||
<img
|
||||
alt="logo"
|
||||
class="euiImage emotion-euiImage-customSize"
|
||||
src="logo"
|
||||
style="max-width: 40px; max-height: 40px;"
|
||||
/>
|
||||
</figure>
|
||||
</span>
|
||||
<h1
|
||||
class="euiTitle loginWelcome__title emotion-euiTitle-m"
|
||||
data-test-subj="loginWelcomeTitle"
|
||||
>
|
||||
Welcome to Elastic
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div
|
||||
class="loginWelcome__content loginWelcome-body"
|
||||
>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<div
|
||||
class="euiPanel euiPanel--transparent euiPanel--paddingMedium emotion-euiPanel-grow-m-m-transparent"
|
||||
data-test-subj="loginForm"
|
||||
>
|
||||
<form>
|
||||
<div
|
||||
class="euiFormRow euiFormRow--hasLabel emotion-euiFormRow"
|
||||
id="generated-id-row"
|
||||
>
|
||||
<div
|
||||
class="euiFormRow__labelWrapper"
|
||||
>
|
||||
<label
|
||||
aria-invalid="false"
|
||||
class="euiFormLabel euiFormRow__label euiFormLabel-isFocused emotion-euiFormLabel-focused"
|
||||
for="generated-id"
|
||||
id="generated-id-label"
|
||||
>
|
||||
Username
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow__fieldWrapper"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout emotion-euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
autocomplete="off"
|
||||
class="euiFieldText emotion-euiFieldText"
|
||||
data-test-subj="loginUsername"
|
||||
id="generated-id"
|
||||
name="username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow euiFormRow--hasLabel emotion-euiFormRow"
|
||||
id="generated-id-row"
|
||||
>
|
||||
<div
|
||||
class="euiFormRow__labelWrapper"
|
||||
>
|
||||
<label
|
||||
aria-invalid="false"
|
||||
class="euiFormLabel euiFormRow__label emotion-euiFormLabel"
|
||||
for="generated-id"
|
||||
id="generated-id-label"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormRow__fieldWrapper"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout euiFormControlLayout--group emotion-euiFormControlLayout-group"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper-inGroup-appendOnly"
|
||||
style="--euiFormControlLeftIconsCount: 1;"
|
||||
>
|
||||
<div
|
||||
class="euiFormControlLayoutIcons emotion-euiFormControlLayoutIcons-absolute-left"
|
||||
>
|
||||
<span
|
||||
class="euiFormControlLayoutCustomIcon emotion-euiFormControlLayoutCustomIcon"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="euiFormControlLayoutCustomIcon__icon"
|
||||
data-euiicon-type="lock"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
aria-required="true"
|
||||
autocomplete="off"
|
||||
class="euiFieldPassword emotion-euiFieldPassword-inGroup-withToggle"
|
||||
data-test-subj="loginPassword"
|
||||
id="generated-id"
|
||||
name="password"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="euiFormControlLayout__append emotion-euiFormControlLayout__side-append"
|
||||
>
|
||||
<button
|
||||
aria-label="Show password as plain text. Note: this will visually expose your password on the screen."
|
||||
class="euiButtonIcon emotion-euiButtonIcon-xs-empty-primary"
|
||||
title="Show password as plain text. Note: this will visually expose your password on the screen."
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="euiButtonIcon__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="eye"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="euiSpacer euiSpacer--l emotion-euiSpacer-l"
|
||||
/>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-s-flexStart-center-row"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<button
|
||||
class="euiButton emotion-euiButtonDisplay-m-fullWidth-defaultMinWidth-fill-primary"
|
||||
data-test-subj="loginSubmit"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="emotion-euiButtonDisplayContent"
|
||||
>
|
||||
Log in
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
.loginWelcome {
|
||||
@include kibanaFullScreenGraphics;
|
||||
}
|
||||
|
||||
.loginWelcome__header {
|
||||
margin-top: calc($euiSizeXXL * 3);
|
||||
position: relative;
|
||||
|
@ -11,8 +7,7 @@
|
|||
|
||||
.loginWelcome__logo {
|
||||
margin-bottom: $euiSizeXL;
|
||||
|
||||
@include kibanaCircleLogo;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.loginWelcome__content {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { EuiFlexItem, EuiThemeProvider } from '@elastic/eui';
|
||||
import { act } from '@testing-library/react';
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
@ -13,7 +13,7 @@ import { of } from 'rxjs';
|
|||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks';
|
||||
import { nextTick } from '@kbn/test-jest-helpers';
|
||||
import { nextTick, renderWithI18n } from '@kbn/test-jest-helpers';
|
||||
|
||||
import { DisabledLoginForm, LoginForm, LoginFormMessageType } from './components';
|
||||
import { LoginPage } from './login_page';
|
||||
|
@ -61,23 +61,23 @@ describe('LoginPage', () => {
|
|||
customBrandingMock.customBranding$ = of({});
|
||||
httpMock.get.mockResolvedValue(createLoginState());
|
||||
|
||||
const wrapper = shallow(
|
||||
const { container } = renderWithI18n(
|
||||
<LoginPage
|
||||
http={httpMock}
|
||||
customBranding={customBrandingMock}
|
||||
notifications={coreStartMock.notifications}
|
||||
fatalErrors={coreStartMock.fatalErrors}
|
||||
loginAssistanceMessage=""
|
||||
/>
|
||||
/>,
|
||||
{ wrapper: EuiThemeProvider }
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
resetHttpMock(); // so the calls don't show in the BasicLoginForm snapshot
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders with custom branding', async () => {
|
||||
|
@ -85,23 +85,23 @@ describe('LoginPage', () => {
|
|||
customBrandingMock.customBranding$ = of({ logo: 'logo' });
|
||||
httpMock.get.mockResolvedValue(createLoginState());
|
||||
|
||||
const wrapper = shallow(
|
||||
const { container } = renderWithI18n(
|
||||
<LoginPage
|
||||
http={httpMock}
|
||||
customBranding={customBrandingMock}
|
||||
notifications={coreStartMock.notifications}
|
||||
fatalErrors={coreStartMock.fatalErrors}
|
||||
loginAssistanceMessage=""
|
||||
/>
|
||||
/>,
|
||||
{ wrapper: EuiThemeProvider }
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
resetHttpMock(); // so the calls don't show in the BasicLoginForm snapshot
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import type {
|
|||
NotificationsStart,
|
||||
} from '@kbn/core/public';
|
||||
import type { CustomBranding } from '@kbn/core-custom-branding-common';
|
||||
import { kbnFullScreenBgCss } from '@kbn/css-utils/public/full_screen_bg_css';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
|
@ -154,7 +155,7 @@ export class LoginPage extends Component<Props, State> {
|
|||
// custom logo needs to be centered
|
||||
const logoStyle = customLogo ? { padding: 0 } : {};
|
||||
return (
|
||||
<div className="loginWelcome login-form">
|
||||
<div className="loginWelcome login-form" css={kbnFullScreenBgCss}>
|
||||
<header className="loginWelcome__header">
|
||||
<div className={contentHeaderClasses}>
|
||||
<span className="loginWelcome__logo" style={logoStyle}>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`OverwrittenSessionPage renders as expected 1`] = `
|
||||
<div
|
||||
class="secAuthenticationStatePage "
|
||||
class="secAuthenticationStatePage css-1vgeo0r-kbnFullScreenBgCss"
|
||||
>
|
||||
<header
|
||||
class="secAuthenticationStatePage__header"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"public/**/*",
|
||||
"server/**/*",
|
||||
"__mocks__/**/*",
|
||||
"../../../../../typings/emotion.d.ts"
|
||||
"../../../../../typings/**/*",
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/cloud-plugin",
|
||||
|
@ -93,6 +93,7 @@
|
|||
"@kbn/core-http-server-utils",
|
||||
"@kbn/core-user-profile-browser-mocks",
|
||||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/css-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -5,12 +5,7 @@ exports[`it renders with custom logo 1`] = `
|
|||
css="unknown styles"
|
||||
data-test-subj="kibanaSpaceSelector"
|
||||
>
|
||||
<EuiPortal>
|
||||
<div
|
||||
className="spcSelectorBackground spcSelectorBackground__nonMixinAttributes"
|
||||
role="presentation"
|
||||
/>
|
||||
</EuiPortal>
|
||||
<Memo(BackgroundPortal) />
|
||||
<_EuiPageSection
|
||||
color="transparent"
|
||||
paddingSize="xl"
|
||||
|
@ -65,12 +60,7 @@ exports[`it renders without crashing 1`] = `
|
|||
css="unknown styles"
|
||||
data-test-subj="kibanaSpaceSelector"
|
||||
>
|
||||
<EuiPortal>
|
||||
<div
|
||||
className="spcSelectorBackground spcSelectorBackground__nonMixinAttributes"
|
||||
role="presentation"
|
||||
/>
|
||||
</EuiPortal>
|
||||
<Memo(BackgroundPortal) />
|
||||
<_EuiPageSection
|
||||
color="transparent"
|
||||
paddingSize="xl"
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
.spcSelectorBackground {
|
||||
@include kibanaFullScreenGraphics;
|
||||
}
|
||||
|
||||
.spcSelectorBackground__nonMixinAttributes {
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
|
|
|
@ -25,6 +25,7 @@ import type { Observable, Subscription } from 'rxjs';
|
|||
|
||||
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import type { CustomBranding } from '@kbn/core-custom-branding-common';
|
||||
import { useKbnFullScreenBgCss } from '@kbn/css-utils/public/full_screen_bg_css';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { KibanaSolutionAvatar } from '@kbn/shared-ux-avatar-solution';
|
||||
|
@ -130,14 +131,7 @@ export class SpaceSelector extends Component<Props, State> {
|
|||
`}
|
||||
data-test-subj="kibanaSpaceSelector"
|
||||
>
|
||||
{/* Portal the fixed background graphic so it doesn't affect page positioning or overlap on top of global banners */}
|
||||
<EuiPortal>
|
||||
<div
|
||||
className="spcSelectorBackground spcSelectorBackground__nonMixinAttributes"
|
||||
role="presentation"
|
||||
/>
|
||||
</EuiPortal>
|
||||
|
||||
<BackgroundPortal />
|
||||
<KibanaPageTemplate.Section color="transparent" paddingSize="xl">
|
||||
<EuiText textAlign="center" size="s">
|
||||
<EuiSpacer size="xxl" />
|
||||
|
@ -278,3 +272,17 @@ export const renderSpaceSelectorApp = (
|
|||
ReactDOM.render(services.rendering.addContext(<SpaceSelector {...props} />), element);
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
||||
|
||||
// portal the fixed background graphic so it doesn't affect page positioning or overlap on top of global banners
|
||||
const BackgroundPortal = React.memo(function BackgroundPortal() {
|
||||
const kbnFullScreenBgCss = useKbnFullScreenBgCss();
|
||||
return (
|
||||
<EuiPortal>
|
||||
<div
|
||||
className="spcSelectorBackground spcSelectorBackground__nonMixinAttributes"
|
||||
css={kbnFullScreenBgCss}
|
||||
role="presentation"
|
||||
/>
|
||||
</EuiPortal>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
"@kbn/core-chrome-browser",
|
||||
"@kbn/core-lifecycle-server",
|
||||
"@kbn/core-user-profile-browser-mocks",
|
||||
"@kbn/spaces-utils"
|
||||
"@kbn/spaces-utils",
|
||||
"@kbn/css-utils"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -5203,6 +5203,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/css-utils@link:src/platform/packages/shared/kbn-css-utils":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/custom-branding-plugin@link:x-pack/platform/plugins/private/custom_branding":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|