@@ -319,10 +398,15 @@ exports[`EuiSteps renders steps with titleSize 1`] = `
-
+ >
+
+ Step 3 is incomplete
+
+
diff --git a/src/components/steps/__snapshots__/steps_horizontal.test.tsx.snap b/src/components/steps/__snapshots__/steps_horizontal.test.tsx.snap
index 596f37dac60..3aeb863b89c 100644
--- a/src/components/steps/__snapshots__/steps_horizontal.test.tsx.snap
+++ b/src/components/steps/__snapshots__/steps_horizontal.test.tsx.snap
@@ -1,111 +1,119 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EuiStepsHorizontal is rendered 1`] = `
-
-
-
- Step
-
-
-
-
- Completed Step 1
-
-
-
+
+
+
+ Completed Step 1
+
+
+
+
-
- Step
-
-
- 2
-
-
- Selected Step 2
-
-
-
+
+ Step 2
+
+
+ 2
+
+
+
+ Selected Step 2
+
+
+
+
-
- Step
-
-
- 3
-
-
- Incomplete Step 3
-
-
-
+
+ Step 3 is incomplete
+
+
+ 3
+
+
+
+ Incomplete Step 3
+
+
+
+
-
- Step
-
-
- 4
-
-
- Disabled Step 4
-
-
-
+
+
+ Step 4 is disabled
+
+
+ 4
+
+
+
+ Disabled Step 4
+
+
+
+
`;
diff --git a/src/components/steps/_steps_horizontal.scss b/src/components/steps/_steps_horizontal.scss
index 85e0bcbddfe..88e15494a84 100644
--- a/src/components/steps/_steps_horizontal.scss
+++ b/src/components/steps/_steps_horizontal.scss
@@ -13,14 +13,22 @@
.euiStepsHorizontal {
display: flex;
align-items: stretch;
- flex-grow: 1;
background: transparentize($euiColorLightestShade, .5);
}
-// Button containing item
-.euiStepHorizontal {
+.euiStepHorizontal__item {
flex-grow: 1; /* 2 */
flex-basis: 0%; /* 2 */
+
+ // Remove the respective lines if the first or last child
+ &:first-of-type > .euiStepHorizontal::before,
+ &:last-of-type > .euiStepHorizontal::after {
+ display: none;
+ }
+}
+
+// Button containing item
+.euiStepHorizontal {
padding: $euiSizeL $euiSize $euiSize;
display: flex; /* 3 */
flex-direction: column; /* 3 */
@@ -28,6 +36,7 @@
justify-content: flex-start; /* 3 */
cursor: pointer;
position: relative;
+ width: 100%;
// focus & hover state
&:focus:not(.euiStepHorizontal-isDisabled),
@@ -69,15 +78,6 @@
&::after {
right: 0;
}
-
- // Remove the respective lines if the first or last child
- &:first-of-type::before {
- display: none;
- }
-
- &:last-of-type::after {
- display: none;
- }
}
.euiStepHorizontal__number {
@@ -91,7 +91,6 @@
margin-top: $euiSizeS;
font-weight: $euiFontWeightRegular;
text-align: center;
- max-width: 100%; // IE Fix for wrapping text
.euiStepHorizontal-isDisabled & {
color: $euiColorDarkShade;
@@ -123,8 +122,8 @@
// reduce top padding and shift lines
padding-top: $euiSize;
- &:before,
- &:after {
+ &::before,
+ &::after {
top: $euiSize + $euiStepNumberSize / 2;
}
}
diff --git a/src/components/steps/step.tsx b/src/components/steps/step.tsx
index 055249b506e..69bc68913bc 100644
--- a/src/components/steps/step.tsx
+++ b/src/components/steps/step.tsx
@@ -17,16 +17,16 @@
* under the License.
*/
-import React, { FunctionComponent, HTMLAttributes, ReactNode } from 'react';
-import { CommonProps } from '../common';
-
import classNames from 'classnames';
-
+import React, {
+ createElement,
+ FunctionComponent,
+ HTMLAttributes,
+ ReactNode,
+} from 'react';
+import { CommonProps } from '../common';
import { EuiTitle, EuiTitleProps, EuiTitleSize } from '../title';
-
-import { EuiStepStatus, EuiStepNumber } from './step_number';
-
-import { EuiI18n } from '../i18n';
+import { EuiStepNumber, EuiStepStatus } from './step_number';
export interface EuiStepInterface {
/**
@@ -80,27 +80,15 @@ export const EuiStep: FunctionComponent
= ({
return (
- {
- if (status === 'incomplete') return 'Incomplete Step';
- return 'Step';
- }}
- values={{ status }}>
- {(ariaLabel: string) => (
-
- )}
-
-
+
- {React.createElement(headingElement, null, title)}
+ {createElement(headingElement, null, title)}
diff --git a/src/components/steps/step_horizontal.tsx b/src/components/steps/step_horizontal.tsx
index 668d4f48b0f..831c604702e 100644
--- a/src/components/steps/step_horizontal.tsx
+++ b/src/components/steps/step_horizontal.tsx
@@ -17,22 +17,23 @@
* under the License.
*/
+import classNames from 'classnames';
import React, {
FunctionComponent,
- HTMLAttributes,
+ MouseEvent as ReactMouseEvent,
MouseEventHandler,
} from 'react';
import { CommonProps } from '../common';
-import classNames from 'classnames';
-
-import { EuiI18n } from '../i18n';
-import { EuiScreenReaderOnly, EuiKeyboardAccessible } from '../accessibility';
-
-import { EuiStepStatus, EuiStepNumber } from './step_number';
+import { EuiStepNumber, EuiStepStatus } from './step_number';
+import {
+ useI18nCompleteStep,
+ useI18nDisabledStep,
+ useI18nIncompleteStep,
+ useI18nStep,
+ useI18nWarningStep,
+} from './step_strings';
-export interface EuiStepHorizontalProps
- extends CommonProps,
- HTMLAttributes
{
+export interface EuiStepHorizontalProps extends CommonProps {
/**
* Is the current step
*/
@@ -41,7 +42,7 @@ export interface EuiStepHorizontalProps
* Is a previous step that has been completed
*/
isComplete?: boolean;
- onClick: MouseEventHandler;
+ onClick: MouseEventHandler;
disabled?: boolean;
/**
* The number of the step in the list of steps
@@ -66,6 +67,12 @@ export const EuiStepHorizontal: FunctionComponent = ({
status,
...rest
}) => {
+ const buttonTitle = useI18nStep({ number: step, title });
+ const completeTitle = useI18nCompleteStep({ number: step, title });
+ const disabledTitle = useI18nDisabledStep({ number: step, title });
+ const incompleteTitle = useI18nIncompleteStep({ number: step, title });
+ const warningTitle = useI18nWarningStep({ number: step, title });
+
const classes = classNames('euiStepHorizontal', className, {
'euiStepHorizontal-isSelected': isSelected,
'euiStepHorizontal-isComplete': isComplete,
@@ -73,70 +80,37 @@ export const EuiStepHorizontal: FunctionComponent = ({
'euiStepHorizontal-isDisabled': disabled,
});
- if (disabled) {
- status = 'disabled';
- } else if (isComplete) {
- status = 'complete';
- } else if (isSelected) {
- status = status;
- } else if (!status) {
- status = 'incomplete';
- }
+ if (disabled) status = 'disabled';
+ else if (isComplete) status = 'complete';
+ else if (isSelected) status = status;
+ else if (!status) status = 'incomplete';
+
+ let stepTitle = buttonTitle;
+ if (status === 'disabled') stepTitle = disabledTitle;
+ if (status === 'complete') stepTitle = completeTitle;
+ if (status === 'incomplete') stepTitle = incompleteTitle;
+ if (status === 'warning') stepTitle = warningTitle;
- const onStepClick = (event: React.MouseEvent) => {
- if (disabled) return;
- onClick(event);
+ const onStepClick = (
+ event: ReactMouseEvent
+ ) => {
+ if (!disabled) onClick(event);
};
return (
- ) => {
- let titleAppendix = '';
- if (disabled) {
- titleAppendix = ' is disabled';
- } else if (isComplete) {
- titleAppendix = ' is complete';
- }
-
- return `Step ${step}: ${title}${titleAppendix}`;
- }}
- values={{ step, title, disabled, isComplete }}>
- {(buttonTitle: string) => (
-
-
-
-
-
-
-
-
-
+
+
- {title}
-
-
- )}
-
+ {title}
+
);
};
diff --git a/src/components/steps/step_number.tsx b/src/components/steps/step_number.tsx
index 2df7a717a1f..10b393ffbca 100644
--- a/src/components/steps/step_number.tsx
+++ b/src/components/steps/step_number.tsx
@@ -17,15 +17,20 @@
* under the License.
*/
-import React, { FunctionComponent, HTMLAttributes } from 'react';
import classNames from 'classnames';
-
+import React, { FunctionComponent, HTMLAttributes } from 'react';
+import { EuiScreenReaderOnly } from '../accessibility';
+import { CommonProps, keysOf } from '../common';
import { EuiIcon } from '../icon';
-
import { EuiStepProps } from './step';
-
-import { EuiI18n } from '../i18n';
-import { CommonProps, keysOf } from '../common';
+import {
+ useI18nCompleteStep,
+ useI18nDisabledStep,
+ useI18nErrorsStep,
+ useI18nIncompleteStep,
+ useI18nStep,
+ useI18nWarningStep,
+} from './step_strings';
const statusToClassNameMap = {
complete: 'euiStepNumber--complete',
@@ -70,64 +75,66 @@ export const EuiStepNumber: FunctionComponent = ({
titleSize,
...rest
}) => {
+ const stepAriaLabel = useI18nStep({ number });
+ const completeAriaLabel = useI18nCompleteStep({ number });
+ const warningAriaLabel = useI18nWarningStep({ number });
+ const errorsAriaLabel = useI18nErrorsStep({ number });
+ const incompleteAriaLabel = useI18nIncompleteStep({ number });
+ const disabledAriaLabel = useI18nDisabledStep({ number });
+
const classes = classNames(
'euiStepNumber',
status ? statusToClassNameMap[status] : undefined,
- {
- 'euiStepNumber-isHollow': isHollow,
- },
+ { 'euiStepNumber-isHollow': isHollow },
className
);
const iconSize = titleSize === 'xs' ? 's' : 'm';
+ let screenReaderText = stepAriaLabel;
+ if (status === 'incomplete') screenReaderText = incompleteAriaLabel;
+ else if (status === 'disabled') screenReaderText = disabledAriaLabel;
+
+ let numberOrIcon = (
+ <>
+
+ {screenReaderText}
+
+ {!isHollow && {number} }
+ >
+ );
- let numberOrIcon;
if (status === 'complete') {
numberOrIcon = (
-
- {(isComplete: string) => (
-
- )}
-
+
);
} else if (status === 'warning') {
numberOrIcon = (
-
- {(hasWarnings: string) => (
-
- )}
-
+
);
} else if (status === 'danger') {
numberOrIcon = (
-
- {(hasErrors: string) => (
-
- )}
-
+
);
- } else if (!isHollow) {
- numberOrIcon = number;
}
return (
-
+
{numberOrIcon}
-
+
);
};
diff --git a/src/components/steps/step_strings.tsx b/src/components/steps/step_strings.tsx
new file mode 100644
index 00000000000..3eff1b41581
--- /dev/null
+++ b/src/components/steps/step_strings.tsx
@@ -0,0 +1,132 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { useEuiI18n } from '../i18n';
+
+type Props = { number?: number; title?: string };
+
+export const useI18nStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n('euiStepStrings.step', 'Step {number}: {title}', {
+ number,
+ title,
+ });
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleStep',
+ 'Step {number}',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
+
+export const useI18nCompleteStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n(
+ 'euiStepStrings.complete',
+ 'Step {number}: {title} is complete',
+ {
+ number,
+ title,
+ }
+ );
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleComplete',
+ 'Step {number} is complete',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
+
+export const useI18nWarningStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n(
+ 'euiStepStrings.warning',
+ 'Step {number}: {title} has warnings',
+ {
+ number,
+ title,
+ }
+ );
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleWarning',
+ 'Step {number} has warnings',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
+
+export const useI18nErrorsStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n(
+ 'euiStepStrings.errors',
+ 'Step {number}: {title} has errors',
+ {
+ number,
+ title,
+ }
+ );
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleErrors',
+ 'Step {number} has errors',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
+
+export const useI18nIncompleteStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n(
+ 'euiStepStrings.incomplete',
+ 'Step {number}: {title} is incomplete',
+ {
+ number,
+ title,
+ }
+ );
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleIncomplete',
+ 'Step {number} is incomplete',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
+
+export const useI18nDisabledStep = ({ number, title }: Props): string => {
+ const string = useEuiI18n(
+ 'euiStepStrings.disabled',
+ 'Step {number}: {title} is disabled',
+ {
+ number,
+ title,
+ }
+ );
+
+ const simpleString = useEuiI18n(
+ 'euiStepStrings.simpleDisabled',
+ 'Step {number} is disabled',
+ { number }
+ );
+
+ return title ? string : simpleString;
+};
diff --git a/src/components/steps/steps_horizontal.tsx b/src/components/steps/steps_horizontal.tsx
index 9dc3c782288..8a58512bdcc 100644
--- a/src/components/steps/steps_horizontal.tsx
+++ b/src/components/steps/steps_horizontal.tsx
@@ -17,27 +17,16 @@
* under the License.
*/
-import React, { FunctionComponent, HTMLAttributes } from 'react';
-import { CommonProps } from '../common';
import classNames from 'classnames';
+import React, { FunctionComponent } from 'react';
+import { CommonProps } from '../common';
+import { EuiStepHorizontal, EuiStepHorizontalProps } from './step_horizontal';
-import { EuiStepHorizontalProps, EuiStepHorizontal } from './step_horizontal';
-
-type ContainedEuiStepHorizontalProps = Omit;
-
-export interface EuiStepsHorizontalProps
- extends CommonProps,
- HTMLAttributes {
+export interface EuiStepsHorizontalProps extends CommonProps {
/**
* An array of `EuiStepHorizontal` objects excluding the `step` prop
*/
- steps: ContainedEuiStepHorizontalProps[];
-}
-
-function renderHorizontalSteps(steps: ContainedEuiStepHorizontalProps[]) {
- return steps.map((step, index) => {
- return ;
- });
+ steps: Array>;
}
export const EuiStepsHorizontal: FunctionComponent = ({
@@ -48,8 +37,18 @@ export const EuiStepsHorizontal: FunctionComponent = ({
const classes = classNames('euiStepsHorizontal', className);
return (
-
- {renderHorizontalSteps(steps)}
-
+
+ {steps.map((stepProps, index) => {
+ const isCurrent = stepProps.isSelected
+ ? { 'aria-current': 'step' as const }
+ : {};
+
+ return (
+
+
+
+ );
+ })}
+
);
};