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

feat(ui5-timeline-item): introduce state property #10277

Merged
merged 15 commits into from
Jan 20, 2025
55 changes: 55 additions & 0 deletions packages/fiori/cypress/specs/Timeline.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { html } from "lit";
import "../../src/Timeline.js";
import "../../src/TimelineItem.js";
import "@ui5/webcomponents-icons/dist/accept.js";
import "@ui5/webcomponents-icons/dist/message-information.js";
import "@ui5/webcomponents-icons/dist/decline.js";
import "@ui5/webcomponents-icons/dist/message-warning.js";

describe("Accessibility", () => {
beforeEach(() => {
cy.mount(html`
<ui5-timeline id="test-timeline">
<ui5-timeline-group-item group-name="Build">
<ui5-timeline-item
id="item1"
title="Compile"
subtitle="Testing suite A"
icon="sap-icon://accept"
name="Testing suite A"
status="Positive"
>
Compilation succeeded.
</ui5-timeline-item>
<ui5-timeline-item
id="item2"
title="Lint"
subtitle="Testing suite B"
icon="sap-icon://message-information"
name="Testing suite B"
>
Lint completed with minor issues.
</ui5-timeline-item>
</ui5-timeline-group-item>
</ui5-timeline>
`);

cy.get("#test-timeline").as("timeline");
});

it("item with status attribute has aria-description, item without status does not", () => {
cy.get(`ui5-timeline-item[status="Positive"]`).each($itemWithStatus => {
cy.wrap($itemWithStatus)
.shadow()
.find(".ui5-tli-bubble")
.should("have.attr", "aria-description");
});

cy.get(`ui5-timeline-item:not([status="Positive"])`).each($itemWithoutStatus => {
cy.wrap($itemWithoutStatus)
.shadow()
.find(".ui5-tli-bubble")
.should("not.have.attr", "aria-description");
});
});
});
5 changes: 4 additions & 1 deletion packages/fiori/src/TimelineGroupItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import ToggleButton from "@ui5/webcomponents/dist/ToggleButton.js";
import TimelineLayout from "./types/TimelineLayout.js";
import TimelineItem from "./TimelineItem.js";
import type { ITimelineItem } from "./Timeline.js";

import "@ui5/webcomponents-icons/dist/slim-arrow-left.js";
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-up.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
import TimelineGroupItemTemplate from "./generated/templates/TimelineGroupItemTemplate.lit.js";

// Styles
Expand Down
4 changes: 2 additions & 2 deletions packages/fiori/src/TimelineItem.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<div class="{{classes.indicator}}">
<div class="ui5-tli-icon-outer">
{{#if icon}}
<ui5-icon class="ui5-tli-icon" name="{{icon}}"></ui5-icon>
<ui5-icon class="ui5-tli-icon" name="{{icon}}" mode="Decorative"></ui5-icon>
{{else}}
<div class="ui5-tli-dummy-icon-container"></div>
{{/if}}
</div>
</div>
{{#unless hideBubble}}
<div class="ui5-tli-bubble" tabindex="{{forcedTabIndex}}" data-sap-focus-ref>
<div class="ui5-tli-bubble" tabindex="{{forcedTabIndex}}" data-sap-focus-ref aria-description={{timelineItemStatusText}}>
<div class="ui5-tli-title">
{{#if name}}
{{> name}}
Expand Down
37 changes: 37 additions & 0 deletions packages/fiori/src/TimelineItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement
import event from "@ui5/webcomponents-base/dist/decorators/event.js";
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
import Icon from "@ui5/webcomponents/dist/Icon.js";
import Link from "@ui5/webcomponents/dist/Link.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type { ITimelineItem } from "./Timeline.js";
import type TimelineItemStatus from "./types/TimelineItemStatus.js";
import TimelineItemTemplate from "./generated/templates/TimelineItemTemplate.lit.js";
import TimelineLayout from "./types/TimelineLayout.js";

import {
TIMELINE_ITEM_INFORMATION_STATUS_TEXT,
TIMELINE_ITEM_POSITIVE_STATUS_TEXT,
TIMELINE_ITEM_NEGATIVE_STATUS_TEXT,
TIMELINE_ITEM_CRITICAL_STATUS_TEXT,
} from "./generated/i18n/i18n-defaults.js";

// Styles
import TimelineItemCss from "./generated/themes/TimelineItem.css.js";

Expand Down Expand Up @@ -91,6 +103,15 @@ class TimelineItem extends UI5Element implements ITimelineItem {
@property()
subtitleText?: string;

/**
* Defines the status of the icon displayed in the `ui5-timeline-item`.
* @default "None"
* @public
* @since 2.5.0
*/
@property()
status: `${TimelineItemStatus}` = "None";

/**
* Defines the content of the `ui5-timeline-item`.
* @public
Expand Down Expand Up @@ -154,6 +175,9 @@ class TimelineItem extends UI5Element implements ITimelineItem {
@property({ type: Number })
positionInGroup?: number;

@i18n("@ui5/webcomponents")
static i18nBundle: I18nBundle;

constructor() {
super();
}
Expand All @@ -169,6 +193,19 @@ class TimelineItem extends UI5Element implements ITimelineItem {
this.shadowRoot!.querySelector<Link>("[ui5-link]")?.focus();
}

static typeTextMappings(): Record<string, I18nText> {
return {
"Information": TIMELINE_ITEM_INFORMATION_STATUS_TEXT,
"Positive": TIMELINE_ITEM_POSITIVE_STATUS_TEXT,
"Negative": TIMELINE_ITEM_NEGATIVE_STATUS_TEXT,
"Critical": TIMELINE_ITEM_CRITICAL_STATUS_TEXT,
};
}

get timelineItemStatusText() {
return this.status !== "None" ? TimelineItem.i18nBundle.getText(TimelineItem.typeTextMappings()[this.status]) : undefined;
}

get classes() {
return {
indicator: {
Expand Down
6 changes: 6 additions & 0 deletions packages/fiori/src/i18n/messagebundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ NOTIFICATION_LIST_GROUP_EXPANDED=Expanded
#XACT: ARIA announcement for timeline label
TIMELINE_ARIA_LABEL=Timeline

#XACT: ARIA announcement for the TimelineItem status
TIMELINE_ITEM_INFORMATION_STATUS_TEXT=Status Information
TIMELINE_ITEM_POSITIVE_STATUS_TEXT=Status Positive
TIMELINE_ITEM_NEGATIVE_STATUS_TEXT=Status Negative
TIMELINE_ITEM_CRITICAL_STATUS_TEXT=Status Critical

#XBUT: Button text for cancel button in the UploadCollectionItem
UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT=Cancel

Expand Down
16 changes: 16 additions & 0 deletions packages/fiori/src/themes/TimelineItem.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@
inset-inline-start: 50%;
}

:host([status="Positive"]) .ui5-tli-icon {
color: var(--sapPositiveElementColor);
}

:host([status="Negative"]) .ui5-tli-icon {
color: var(--sapNegativeElementColor);
}

:host([status="Critical"]) .ui5-tli-icon {
color: var(--sapCriticalElementColor);
}

:host([status="Information"]) .ui5-tli-icon {
color: var(--sapInformativeElementColor);
}

:host(:not([icon])[layout="Vertical"]) .ui5-tli-indicator::before {
inset-block-start: 1.75rem;
}
Expand Down
37 changes: 37 additions & 0 deletions packages/fiori/src/types/TimelineItemStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Different statuses of a timeline item.
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
* @public
*/
enum TimelineItemStatus {
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
/**
* Default type (no special styling).
* @public
*/
None = "None",

/**
* Represents an informational status, typically used to display neutral information.
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
* @public
*/
Information = "Information",

/**
* Represents a positive or successful status, indicating that an operation is completed.
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
* @public
*/
Positive = "Positive",

/**
* Represents a critical status, used to indicate that attention is required.
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
* @public
*/
Critical = "Critical",

/**
* Represents a negative status, indicating that an operation failed or there is an issue.
hinzzx marked this conversation as resolved.
Show resolved Hide resolved
* @public
*/
Negative = "Negative",
}

export default TimelineItemStatus;
27 changes: 27 additions & 0 deletions packages/fiori/test/pages/Timeline.html
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,33 @@ <h2>Advanced Timeline - Horizontal With Groups and Diverse Components</h2>
</ui5-timeline>
</div>
</section>

<section style="width: 100%;">
<h2>Timeline with Various Timeline Item Statuses</h2>
<div style="width: 50%; margin: 1rem;">
<ui5-timeline id="test-timeline">
<ui5-timeline-group-item group-name="Build">
<ui5-timeline-item title="Compile" subtitle="Testing suite A" icon="sap-icon://accept" name="Testing suite A" status="Positive">
Compilation succeeded.
</ui5-timeline-item>
<ui5-timeline-item title="Lint" subtitle="Testing suite B" icon="sap-icon://message-information" name="Testing suite B" status="Information">
Lint completed with minor issues.
</ui5-timeline-item>
</ui5-timeline-group-item>
<ui5-timeline-group-item group-name="Test">
<ui5-timeline-item title="Unit Test" subtitle="Testing suite C" icon="sap-icon://decline" name="Testing suite C" status="Negative">
Unit tests failed.
</ui5-timeline-item>
<ui5-timeline-item title="Integration Test" subtitle="Testing suite D" icon="sap-icon://message-warning" name="Testing suite D" status="Critical">
Integration tests have warnings.
</ui5-timeline-item>
<ui5-timeline-item title="E2E Test" subtitle="Testing suite E" icon="sap-icon://accept" name="Testing suite E" status="Positive">
End-to-end tests passed.
</ui5-timeline-item>
</ui5-timeline-group-item>
</ui5-timeline>
</div>
</section>
</div>

<script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Basic from "../../../_samples/fiori/Timeline/Basic/Basic.md";
import Horizontal from "../../../_samples/fiori/Timeline/Horizontal/Horizontal.md";
import InCard from "../../../_samples/fiori/Timeline/InCard/InCard.md";
import WithGroups from "../../../_samples/fiori/Timeline/WithGroups/WithGroups.md";
import WithStatus from "../../../_samples/fiori/Timeline/WithStatus/WithStatus.md";

<%COMPONENT_OVERVIEW%>

Expand All @@ -15,6 +16,9 @@ import WithGroups from "../../../_samples/fiori/Timeline/WithGroups/WithGroups.m
### Horizontal layout
<Horizontal />

### Timeline with Status

<WithStatus />

### Timeline in Card

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ import "@ui5/webcomponents-fiori/dist/TimelineItem.js";
import "@ui5/webcomponents/dist/Avatar.js";
import "@ui5/webcomponents/dist/Label.js";
import "@ui5/webcomponents-icons/dist/phone.js";
import "@ui5/webcomponents-icons/dist/calendar.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-left.js";
import "@ui5/webcomponents-icons/dist/calendar.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import html from '!!raw-loader!./sample.html';
import js from '!!raw-loader!./main.js';

<Editor html={html} js={js} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import "@ui5/webcomponents/dist/Label.js";

import "@ui5/webcomponents-fiori/dist/Timeline.js";
import "@ui5/webcomponents-fiori/dist/TimelineItem.js";

import "@ui5/webcomponents-icons/dist/message-information.js";
import "@ui5/webcomponents-icons/dist/decline.js";
import "@ui5/webcomponents-icons/dist/message-warning.js";
import "@ui5/webcomponents-icons/dist/accept.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!-- playground-fold -->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample</title>
</head>

<body style="background-color: var(--sapBackgroundColor); padding: 2rem;">
<!-- playground-fold-end -->

<ui5-timeline id="test-timeline">
<ui5-timeline-group-item group-name="Build">
<ui5-timeline-item title="Compile" subtitle="Testing suite A" icon="sap-icon://accept" name="Testing suite A" status="Positive">
Compilation succeeded.
</ui5-timeline-item>
<ui5-timeline-item title="Lint" subtitle="Testing suite B" icon="sap-icon://message-information" name="Testing suite B" status="Information">
Lint completed with minor issues.
</ui5-timeline-item>
</ui5-timeline-group-item>
<ui5-timeline-group-item group-name="Test">
<ui5-timeline-item title="Unit Test" subtitle="Testing suite C" icon="sap-icon://decline" name="Testing suite C" status="Negative">
Unit tests failed.
</ui5-timeline-item>
<ui5-timeline-item title="Integration Test" subtitle="Testing suite D" icon="sap-icon://message-warning" name="Testing suite D" status="Critical">
Integration tests have warnings.
</ui5-timeline-item>
<ui5-timeline-item title="E2E Test" subtitle="Testing suite E" icon="sap-icon://accept" name="Testing suite E" status="Positive">
End-to-end tests passed.
</ui5-timeline-item>
</ui5-timeline-group-item>
</ui5-timeline>
<!-- playground-fold -->
<script type="module" src="main.js"></script>
</body>

</html>
<!-- playground-fold-end -->
Loading