kibana/examples/resizable_layout_examples/public/application.tsx
Davis McPhee 3e1865513d
[Discover] Add resize support to the Discover field list sidebar (#167066)
## 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.


![resize](71b9a0ae-1795-43c8-acb0-e75fe46e2a8a)

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>
2023-09-27 21:52:25 -03:00

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);
};
};