add ariaLabel
This commit is contained in:
@@ -19,6 +19,7 @@ export function QueryOptionGroup({ title, children, collapsedInfo }: Props) {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Collapse
|
||||
ariaLabel={title}
|
||||
className={styles.collapse}
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleOpen}
|
||||
|
||||
@@ -70,7 +70,7 @@ export const WithCustomLabel: StoryFn<typeof Collapse> = (args) => {
|
||||
}}
|
||||
label={
|
||||
<Stack flex={1} alignItems="center" justifyContent="space-between">
|
||||
Collapse panel
|
||||
My title
|
||||
<Stack alignItems="center">
|
||||
<IconButton
|
||||
onClick={(event) => {
|
||||
@@ -83,6 +83,7 @@ export const WithCustomLabel: StoryFn<typeof Collapse> = (args) => {
|
||||
</Stack>
|
||||
</Stack>
|
||||
}
|
||||
ariaLabel="My title"
|
||||
>
|
||||
<p>{args.children}</p>
|
||||
</Collapse>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useId, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
import { type PropsWithChildren, useId, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
@@ -92,11 +91,9 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
}),
|
||||
});
|
||||
|
||||
export interface Props {
|
||||
interface BaseProps {
|
||||
/** Expand or collapse te content */
|
||||
isOpen?: boolean;
|
||||
/** Element or text for the Collapse header */
|
||||
label: React.ReactNode;
|
||||
/** Indicates loading state of the content */
|
||||
loading?: boolean;
|
||||
/** Callback for the toggle functionality */
|
||||
@@ -107,7 +104,20 @@ export interface Props {
|
||||
collapsible?: boolean;
|
||||
}
|
||||
|
||||
export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.PropsWithChildren<Props>) => {
|
||||
interface PropsWithStringLabel extends BaseProps {
|
||||
label: string;
|
||||
ariaLabel?: never;
|
||||
}
|
||||
|
||||
interface PropsWithCustomLabel extends BaseProps {
|
||||
label: JSX.Element;
|
||||
/** aria-label for the Collapse header. Required if passing a custom element as the label */
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
export type Props = PropsWithStringLabel | PropsWithCustomLabel;
|
||||
|
||||
export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: PropsWithChildren<Props>) => {
|
||||
const [open, setOpen] = useState(isOpen);
|
||||
return (
|
||||
<Collapse
|
||||
@@ -123,9 +133,19 @@ export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.Pr
|
||||
);
|
||||
};
|
||||
|
||||
export const Collapse = ({ isOpen, label, loading, onToggle, className, children }: React.PropsWithChildren<Props>) => {
|
||||
export const Collapse = ({
|
||||
ariaLabel,
|
||||
isOpen,
|
||||
label,
|
||||
loading,
|
||||
onToggle,
|
||||
className,
|
||||
children,
|
||||
}: PropsWithChildren<Props>) => {
|
||||
const style = useStyles2(getStyles);
|
||||
const labelId = useId();
|
||||
const contentId = useId();
|
||||
const buttonLabel =
|
||||
ariaLabel ?? (typeof label === 'string' ? label : t('grafana-ui.collapse.aria-label-default', 'Toggle collapse'));
|
||||
|
||||
const onClickToggle = () => {
|
||||
if (onToggle) {
|
||||
@@ -141,21 +161,16 @@ export const Collapse = ({ isOpen, label, loading, onToggle, className, children
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||
<div className={style.header} onClick={onClickToggle}>
|
||||
<IconButton
|
||||
aria-describedby={labelId}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={contentId}
|
||||
className={style.button}
|
||||
aria-label={
|
||||
isOpen
|
||||
? t('grafana-ui.collapse.aria-label-collapse', 'Collapse panel')
|
||||
: t('grafana-ui.collapse.aria-label-expand', 'Expand panel')
|
||||
}
|
||||
aria-label={buttonLabel}
|
||||
name={isOpen ? 'angle-down' : 'angle-right'}
|
||||
/>
|
||||
<div id={labelId} className={style.headerLabel}>
|
||||
{label}
|
||||
</div>
|
||||
<div className={style.headerLabel}>{label}</div>
|
||||
</div>
|
||||
{isOpen && (
|
||||
<div className={style.collapseBody}>
|
||||
<div className={style.collapseBody} id={contentId}>
|
||||
<div className={loaderClass} />
|
||||
<div className={style.bodyContentWrapper}>{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -171,6 +171,7 @@ export const CorrelationHelper = ({ exploreId, correlations }: Props) => {
|
||||
})}
|
||||
</pre>
|
||||
<Collapse
|
||||
ariaLabel={t('explore.correlation-helper.label-description-header', 'Label / Description')}
|
||||
isOpen={isLabelDescOpen}
|
||||
onToggle={() => {
|
||||
setIsLabelDescOpen(!isLabelDescOpen);
|
||||
@@ -200,6 +201,7 @@ export const CorrelationHelper = ({ exploreId, correlations }: Props) => {
|
||||
</Field>
|
||||
</Collapse>
|
||||
<Collapse
|
||||
ariaLabel={t('explore.correlation-helper.transformations', 'Transformations')}
|
||||
isOpen={isTransformOpen}
|
||||
onToggle={() => {
|
||||
setIsTransformOpen(!isTransformOpen);
|
||||
|
||||
@@ -308,7 +308,7 @@ class LogsContainer extends PureComponent<LogsContainerProps, LogsContainerState
|
||||
|
||||
return (
|
||||
<>
|
||||
<LogsCrossFadeTransition visible={!isLive}>
|
||||
<LogsCrossFadeTransition visible={isLive}>
|
||||
<PanelChrome title={t('explore.logs-container.label-logs', 'Logs')}>
|
||||
<LiveTailControls exploreId={exploreId}>
|
||||
{(controls) => (
|
||||
@@ -326,7 +326,7 @@ class LogsContainer extends PureComponent<LogsContainerProps, LogsContainerState
|
||||
</LiveTailControls>
|
||||
</PanelChrome>
|
||||
</LogsCrossFadeTransition>
|
||||
<LogsCrossFadeTransition visible={isLive}>
|
||||
<LogsCrossFadeTransition visible={!isLive}>
|
||||
<Logs
|
||||
exploreId={exploreId}
|
||||
datasourceType={this.props.datasourceInstance?.type}
|
||||
|
||||
@@ -145,6 +145,7 @@ export function LogsSamplePanel(props: Props) {
|
||||
|
||||
return queryResponse?.state !== LoadingState.NotStarted ? (
|
||||
<Collapse
|
||||
ariaLabel={t('explore.logs-sample-panel.label', 'Logs sample')}
|
||||
label={
|
||||
<div>
|
||||
<Trans i18nKey="explore.logs-sample-panel.label">Logs sample</Trans>
|
||||
|
||||
+6
-1
@@ -151,7 +151,12 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Collapse label={collapseLabel} isOpen={showSpanFilters} onToggle={setShowSpanFilters}>
|
||||
<Collapse
|
||||
ariaLabel={t('explore.span-filters.label-collapse', 'Span Filters')}
|
||||
label={collapseLabel}
|
||||
isOpen={showSpanFilters}
|
||||
onToggle={setShowSpanFilters}
|
||||
>
|
||||
<InlineFieldRow className={styles.flexContainer}>
|
||||
<InlineField label={t('explore.span-filters.label-service-name', 'Service name')} labelWidth={16}>
|
||||
<Stack gap={0.5}>
|
||||
|
||||
@@ -2,9 +2,9 @@ import { css } from '@emotion/css';
|
||||
import { isString } from 'lodash';
|
||||
import { FeatureLike } from 'ol/Feature';
|
||||
import { useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { DataFrame, FieldType, getFieldDisplayName, GrafanaTheme2 } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Collapse, TabContent, useStyles2 } from '@grafana/ui';
|
||||
import { GeomapLayerHover } from 'app/plugins/panel/geomap/event';
|
||||
import { renderValue } from 'app/plugins/panel/geomap/utils/uiUtils';
|
||||
@@ -37,6 +37,9 @@ export const DataHoverRows = ({ layers, activeTabIndex }: Props) => {
|
||||
|
||||
return shouldDisplayCollapse ? (
|
||||
<Collapse
|
||||
ariaLabel={t('visualization.data-hover-rows.aria-label-collapse', 'Match: {{number}}', {
|
||||
number: idx + 1,
|
||||
})}
|
||||
key={key}
|
||||
label={generateLabel(feature, idx)}
|
||||
isOpen={rowMap.get(key)}
|
||||
@@ -59,7 +62,7 @@ export const DataHoverRows = ({ layers, activeTabIndex }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const generateLabel = (feature: FeatureLike, idx: number): string | React.ReactNode => {
|
||||
export const generateLabel = (feature: FeatureLike, idx: number) => {
|
||||
const names = ['Name', 'name', 'Title', 'ID', 'id'];
|
||||
let props = feature.getProperties();
|
||||
let first = '';
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ export function QueryOptionGroup({ title, children, collapsedInfo }: Props) {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Collapse
|
||||
ariaLabel={title}
|
||||
className={styles.collapse}
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleOpen}
|
||||
|
||||
@@ -296,6 +296,7 @@ export function LokiContextUi(props: LokiContextUiProps) {
|
||||
</div>
|
||||
|
||||
<Collapse
|
||||
ariaLabel={queryExpr}
|
||||
isOpen={isOpen}
|
||||
onToggle={() => {
|
||||
window.localStorage.setItem(IS_LOKI_LOG_CONTEXT_UI_OPEN, (!isOpen).toString());
|
||||
|
||||
+1
@@ -24,6 +24,7 @@ export function QueryOptionGroup({ title, children, collapsedInfo, queryStats, o
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Collapse
|
||||
ariaLabel={title}
|
||||
className={styles.collapse}
|
||||
isOpen={propsIsOpen ?? isOpen}
|
||||
onToggle={onToggle ?? toggleOpen}
|
||||
|
||||
Reference in New Issue
Block a user