Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Dashboard] [Controls] Make floating actions keyboard accessible #152155

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ export const StaticByReferenceExample = ({
</EuiText>
<EuiSpacer size="m" />
<EuiPanel
className="eui-scrollBar"
hasBorder={true}
// By specifying the height of the EuiPanel, we make it so that the dashboard height is
// By specifying the height + overflow of the EuiPanel, we make it so that the dashboard height is
// constrained to the container - so, the dashboard is rendered with a vertical scrollbar
css={css`
height: 600px;
overflow-y: auto;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the Dashboard viewport is no longer constrained to the height of its parent container, we need the container (in this case, the EuiPanel) to be responsible for handling the overflow.

Mar-02-2023 09-56-09

`}
>
<DashboardContainerRenderer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,28 +214,25 @@ export const ControlFrame = ({
);

return (
<>
<FloatingActions
className={classNames('controlFrameFloatingActions', {
'controlFrameFloatingActions--twoLine': usingTwoLineLayout,
'controlFrameFloatingActions--oneLine': !usingTwoLineLayout,
})}
usingTwoLineLayout={usingTwoLineLayout}
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
actions={floatingActions}
isEnabled={embeddable && enableActions}
<FloatingActions
className={classNames({
'controlFrameFloatingActions--twoLine': usingTwoLineLayout,
'controlFrameFloatingActions--oneLine': !usingTwoLineLayout,
})}
actions={floatingActions}
isEnabled={embeddable && enableActions}
>
<EuiFormRow
data-test-subj="control-frame-title"
fullWidth
label={
usingTwoLineLayout
? title || ControlGroupStrings.emptyState.getTwoLineLoadingTitle()
: undefined
}
>
<EuiFormRow
data-test-subj="control-frame-title"
fullWidth
label={
usingTwoLineLayout
? title || ControlGroupStrings.emptyState.getTwoLineLoadingTitle()
: undefined
}
>
{form}
</EuiFormRow>
</FloatingActions>
</>
{form}
</EuiFormRow>
</FloatingActions>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ $controlMinWidth: $euiSize * 14;
box-shadow: 0 0 0 1px $euiColorLightShade;
}

&--twoLine {
top: (-$euiSizeXS) !important;
}

&--fatalError {
padding: $euiSizeXS;
border-radius: $euiBorderRadius;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
flex-direction: column;
}

.dashboardViewportWrapper {
display: flex;
flex: 1;
flex-direction: column;
}

.dshUnsavedListingItem {
margin-top: $euiSizeM;
}
Expand Down
30 changes: 24 additions & 6 deletions src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ViewMode } from '@kbn/embeddable-plugin/public';
import { useExecutionContext } from '@kbn/kibana-react-plugin/public';
import { createKbnUrlStateStorage, withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public';

import { css } from '@emotion/react';
import {
DashboardAppNoDataPage,
isDashboardAppInNoDataState,
Expand Down Expand Up @@ -53,6 +54,12 @@ export function DashboardApp({
history,
}: DashboardAppProps) {
const [showNoDataPage, setShowNoDataPage] = useState<boolean>(false);
/**
* This state keeps track of the height of the top navigation bar so that padding at the
* top of the viewport can be adjusted dynamically.
*/
const [topNavHeight, setTopNavHeight] = useState(0);

useMount(() => {
(async () => setShowNoDataPage(await isDashboardAppInNoDataState()))();
});
Expand Down Expand Up @@ -192,16 +199,27 @@ export function DashboardApp({
<>
{DashboardReduxWrapper && (
<DashboardReduxWrapper>
<DashboardTopNav redirectTo={redirectTo} embedSettings={embedSettings} />
<DashboardTopNav
onHeightChange={setTopNavHeight}
redirectTo={redirectTo}
embedSettings={embedSettings}
/>
</DashboardReduxWrapper>
)}

{getLegacyConflictWarning?.()}
<DashboardContainerRenderer
savedObjectId={savedDashboardId}
getCreationOptions={getCreationOptions}
onDashboardContainerLoaded={(container) => setDashboardContainer(container)}
/>
<div
className="dashboardViewportWrapper"
css={css`
padding-top: ${topNavHeight}px;
`}
>
<DashboardContainerRenderer
savedObjectId={savedDashboardId}
getCreationOptions={getCreationOptions}
onDashboardContainerLoaded={(container) => setDashboardContainer(container)}
/>
</div>
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.dashboardTopNav {
position: fixed;
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
z-index: $euiZLevel2;
background: $euiPageBackgroundColor;
width: 100%;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { ViewMode } from '@kbn/embeddable-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';

import { EuiHorizontalRule } from '@elastic/eui';
import { EuiHorizontalRule, useResizeObserver } from '@elastic/eui';
import {
getDashboardTitle,
leaveConfirmStrings,
Expand All @@ -33,14 +33,20 @@ import { useDashboardMountContext } from '../hooks/dashboard_mount_context';
import { getFullEditPath, LEGACY_DASHBOARD_APP_ID } from '../../dashboard_constants';
import { useDashboardContainerContext } from '../../dashboard_container/dashboard_container_context';

import './_dashboard_top_nav.scss';
export interface DashboardTopNavProps {
embedSettings?: DashboardEmbedSettings;
redirectTo: DashboardRedirect;
onHeightChange: (height: number) => void;
}

const LabsFlyout = withSuspense(LazyLabsFlyout, null);

export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavProps) {
export function DashboardTopNav({
embedSettings,
redirectTo,
onHeightChange,
}: DashboardTopNavProps) {
const [isChromeVisible, setIsChromeVisible] = useState(false);
const [isLabsShown, setIsLabsShown] = useState(false);

Expand Down Expand Up @@ -116,6 +122,16 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr
if (!embedSettings) setChromeVisibility(viewMode !== ViewMode.PRINT);
}, [embedSettings, setChromeVisibility, viewMode]);

/**
* Keep track of the height of the top nav bar as it changes so that the padding at the top of the
* dashboard viewport can be adjusted dynamically as it changes
*/
const resizeRef = useRef<HTMLDivElement>(null);
const dimensions = useResizeObserver(resizeRef.current);
useEffect(() => {
onHeightChange(dimensions.height);
}, [dimensions, onHeightChange]);

/**
* populate recently accessed, and set is chrome visible.
*/
Expand Down Expand Up @@ -214,7 +230,7 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr
});

return (
<>
<div ref={resizeRef} className={'dashboardTopNav'}>
<h1
id="dashboardTitle"
className="euiScreenReaderOnly"
Expand Down Expand Up @@ -267,6 +283,6 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr
) : null}
{viewMode === ViewMode.EDIT ? <DashboardEditingToolbar /> : null}
<EuiHorizontalRule margin="none" />
</>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import classNames from 'classnames';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import useObservable from 'react-use/lib/useObservable';

import { EuiLoadingElastic, EuiLoadingSpinner, useEuiOverflowScroll } from '@elastic/eui';
import { css } from '@emotion/react';
import { EuiLoadingElastic, EuiLoadingSpinner } from '@elastic/eui';

import {
DashboardContainerFactory,
Expand Down Expand Up @@ -109,19 +108,13 @@ export const DashboardContainerRenderer = ({
{ 'dashboardViewport--loading': loading }
);

const viewportStyles = css`
${useEuiOverflowScroll('y', false)}
`;

const loadingSpinner = showPlainSpinner ? (
<EuiLoadingSpinner size="xxl" />
) : (
<EuiLoadingElastic size="xxl" />
);
return (
<div className={viewportClasses} css={viewportStyles}>
{loading ? loadingSpinner : <div ref={dashboardRoot} />}
</div>
<div className={viewportClasses}>{loading ? loadingSpinner : <div ref={dashboardRoot} />}</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.presentationUtil__floatingActionsWrapper {
position: relative;

.presentationUtil__floatingActions {
opacity: 0;
visibility: hidden;
// slower transition on hover leave in case the user accidentally stops hover
transition: visibility .3s, opacity .3s;

position: absolute;
right: $euiSizeXS;
top: (-$euiSizeL);
z-index: $euiZLevel9; // the highest possible z-level
}

&:hover, &:focus-within {
.presentationUtil__floatingActions {
opacity: 1;
visibility: visible;
transition: visibility .1s, opacity .1s;
}
}
}