mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
## Summary
This PR adds resize support to the Discover field list sidebar, which is
persisted to a user's local storage similar to the resizable chart
height.
Additionally it migrates the resizable layout code from Unified
Histogram to a new package called `kbn-resizable-layout` so it can be
shared between Discover and Unified Histogram, as well as act as a new
platform component that other teams can consume to create their own
resizable layouts.

Resolves #9531.
### Checklist
- [ ] ~Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)~
- [ ]
~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials~
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] ~Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))~
- [ ] ~If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
### For maintainers
- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
161 lines
5.2 KiB
TypeScript
161 lines
5.2 KiB
TypeScript
/*
|
|
* 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 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 or the Server
|
|
* Side Public License, v 1.
|
|
*/
|
|
|
|
import { CoreThemeProvider } from '@kbn/core-theme-browser-internal';
|
|
import type { AppMountParameters } from '@kbn/core/public';
|
|
import { I18nProvider } from '@kbn/i18n-react';
|
|
import React, { ReactNode, useState } from 'react';
|
|
import ReactDOM from 'react-dom';
|
|
import { useIsWithinBreakpoints } from '@elastic/eui';
|
|
import { css } from '@emotion/react';
|
|
import {
|
|
ResizableLayout,
|
|
ResizableLayoutDirection,
|
|
ResizableLayoutMode,
|
|
} from '@kbn/resizable-layout';
|
|
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
|
|
|
|
const ResizableSection = ({
|
|
direction,
|
|
initialFixedPanelSize,
|
|
minFixedPanelSize,
|
|
minFlexPanelSize,
|
|
fixedPanelColor,
|
|
flexPanelColor,
|
|
fixedPanelContent,
|
|
flexPanelContent,
|
|
}: {
|
|
direction: ResizableLayoutDirection;
|
|
initialFixedPanelSize: number;
|
|
minFixedPanelSize: number;
|
|
minFlexPanelSize: number;
|
|
fixedPanelColor: string;
|
|
flexPanelColor: string;
|
|
fixedPanelContent: ReactNode;
|
|
flexPanelContent: ReactNode;
|
|
}) => {
|
|
const [fixedPanelSize, setFixedPanelSize] = useState(initialFixedPanelSize);
|
|
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
|
const [fixedPanelNode] = useState(() =>
|
|
createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } })
|
|
);
|
|
const [flexPanelNode] = useState(() =>
|
|
createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } })
|
|
);
|
|
|
|
const isMobile = useIsWithinBreakpoints(['xs', 's']);
|
|
const layoutMode = isMobile ? ResizableLayoutMode.Static : ResizableLayoutMode.Resizable;
|
|
const layoutDirection = isMobile ? ResizableLayoutDirection.Vertical : direction;
|
|
|
|
const fullWidthAndHeightCss = css`
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
`;
|
|
const panelBaseCss = css`
|
|
${fullWidthAndHeightCss}
|
|
padding: 20px;
|
|
font-size: 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
`;
|
|
const fixedPanelCss = css`
|
|
${panelBaseCss}
|
|
background-color: ${fixedPanelColor};
|
|
`;
|
|
const flexPanelCss = css`
|
|
${panelBaseCss}
|
|
background-color: ${flexPanelColor};
|
|
`;
|
|
|
|
return (
|
|
<div ref={setContainer} css={fullWidthAndHeightCss}>
|
|
<InPortal node={fixedPanelNode}>
|
|
<div css={fixedPanelCss}>{fixedPanelContent}</div>
|
|
</InPortal>
|
|
<InPortal node={flexPanelNode}>
|
|
<div css={flexPanelCss}>{flexPanelContent}</div>
|
|
</InPortal>
|
|
<ResizableLayout
|
|
mode={layoutMode}
|
|
direction={layoutDirection}
|
|
container={container}
|
|
fixedPanelSize={fixedPanelSize}
|
|
minFixedPanelSize={minFixedPanelSize}
|
|
minFlexPanelSize={minFlexPanelSize}
|
|
fixedPanel={<OutPortal node={fixedPanelNode} />}
|
|
flexPanel={<OutPortal node={flexPanelNode} />}
|
|
onFixedPanelSizeChange={setFixedPanelSize}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const renderApp = ({ element, theme$ }: AppMountParameters) => {
|
|
ReactDOM.render(
|
|
<I18nProvider>
|
|
<CoreThemeProvider theme$={theme$}>
|
|
<div
|
|
css={css`
|
|
height: calc(100vh - var(--euiFixedHeadersOffset, 0));
|
|
`}
|
|
>
|
|
<ResizableSection
|
|
direction={ResizableLayoutDirection.Horizontal}
|
|
initialFixedPanelSize={500}
|
|
minFixedPanelSize={300}
|
|
minFlexPanelSize={500}
|
|
fixedPanelColor="#16E0BD"
|
|
flexPanelColor="#89A6FB"
|
|
fixedPanelContent={
|
|
<ResizableSection
|
|
direction={ResizableLayoutDirection.Vertical}
|
|
initialFixedPanelSize={200}
|
|
minFixedPanelSize={100}
|
|
minFlexPanelSize={200}
|
|
fixedPanelColor="#E3655B"
|
|
flexPanelColor="#FDCA40"
|
|
fixedPanelContent="Sidebar Header"
|
|
flexPanelContent="Sidebar Body"
|
|
/>
|
|
}
|
|
flexPanelContent={
|
|
<ResizableSection
|
|
direction={ResizableLayoutDirection.Vertical}
|
|
initialFixedPanelSize={300}
|
|
minFixedPanelSize={200}
|
|
minFlexPanelSize={300}
|
|
fixedPanelColor="#FFA0AC"
|
|
flexPanelColor="#F6F740"
|
|
fixedPanelContent="Main Body Header"
|
|
flexPanelContent={
|
|
<ResizableSection
|
|
direction={ResizableLayoutDirection.Horizontal}
|
|
initialFixedPanelSize={400}
|
|
minFixedPanelSize={200}
|
|
minFlexPanelSize={200}
|
|
fixedPanelColor="#78C3FB"
|
|
flexPanelColor="#EF709D"
|
|
fixedPanelContent="Main Body Left"
|
|
flexPanelContent="Main Body Right"
|
|
/>
|
|
}
|
|
/>
|
|
}
|
|
/>
|
|
</div>
|
|
</CoreThemeProvider>
|
|
</I18nProvider>,
|
|
element
|
|
);
|
|
|
|
return () => {
|
|
ReactDOM.unmountComponentAtNode(element);
|
|
};
|
|
};
|