diff --git a/packages/fiori/cypress/specs/Timeline.cy.ts b/packages/fiori/cypress/specs/Timeline.cy.ts index b2c84ed3efa8..6b2e717c776d 100644 --- a/packages/fiori/cypress/specs/Timeline.cy.ts +++ b/packages/fiori/cypress/specs/Timeline.cy.ts @@ -1,10 +1,250 @@ 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"; +import "../../src/TimelineGroupItem.js"; + +const sample = html` + + + + + MR SOF02 2.43 + + + Online meeting + + + +`; + +const sampleWithSingleItem = html` + + + +`; + +const groupSample = html` + + + Morning event + + + Good morning + + + 20.02.2017 11:30 + + + + 20.02.2017 11:30 + + + + + + + + + + + +`; + +describe("Timeline general interaction", () => { + it("should fire name-click event on a normal item name", () => { + cy.mount(sample); + + cy.get("[ui5-timeline]") + .as("timeline") + .then($item => { + $item.get(0).addEventListener("name-click", cy.stub().as("clicked")); + }); + + cy.get("ui5-timeline-item") + .shadow() + .find("ui5-link") + .click(); + + cy.get("@clicked").should("have.been.calledOnce"); + }); + + it("setting accessible-name applied on the host element is reflected on the ul tag", () => { + cy.mount(sample); + cy.get("[ui5-timeline]") + .shadow() + .find("ul") + .should("have.attr", "aria-label", "Timeline vertical"); + }); + + it("Item within Timeline Item is rendered", () => { + cy.mount(sampleWithSingleItem); + cy.get("[ui5-timeline]") + .find("#testTimelineItem") + .shadow() + .find(".ui5-tli-bubble") + .find(".ui5-tli-desc") + .should("exist"); + }); +}); + +describe("Timeline with group items interactions", () => { + it("Group items are rendered", () => { + cy.mount(groupSample); + + cy.get("[ui5-timeline]") + .find("[ui5-timeline-group-item][group-name='Events']") + .as("groupItem"); + + cy.get("@groupItem") + .eq(0) + .find("ui5-timeline-item") + .should("have.length", 4); + }); + + it("Group items are collapsed on button click", () => { + cy.mount(groupSample); + + cy.get("[ui5-timeline]") + .find("[ui5-timeline-group-item][group-name='Events']") + .as("currentGroup"); + + cy.get("@currentGroup") + .eq(0) + .shadow() + .find("[ui5-toggle-button]") + .as("currentGroupButton"); + + cy.get("@currentGroupButton") + .realClick(); + + cy.realPress("Tab"); + + cy.get("[ui5-timeline]") + .find("[ui5-timeline-group-item][group-name='Meetings']") + .as("nextGroup"); + + cy.get("@nextGroup") + .eq(0) + .shadow() + .find("[ui5-toggle-button]") + .should("be.focused"); + }); + + it("Group items are navigable", () => { + cy.mount(groupSample); + + cy.get("[ui5-timeline]") + .find("[ui5-timeline-group-item][group-name='Events']") + .eq(0) + .as("currentGroup"); + + cy.realPress("Tab"); + cy.realPress("ArrowDown"); + cy.realPress("ArrowDown"); + cy.realPress("ArrowDown"); + cy.realPress("ArrowUp"); + + cy.get("@currentGroup") + .find("ui5-timeline-item") + .eq(1) + .should("be.focused"); + }); + + it("Group can be collapsed/expanded using keyboard", () => { + cy.mount(groupSample); + + cy.get("[ui5-timeline]") + .find("[ui5-timeline-group-item][group-name='Events']") + .as("currentGroup"); + + cy.get("@currentGroup") + .eq(0) + .shadow() + .find("[ui5-toggle-button]") + .as("currentGroupButton"); + + cy.get("@currentGroupButton") + .realClick(); + + cy.realPress("Enter"); + + cy.get("@currentGroup") + .eq(0) + .should("not.have.attr", "collapsed"); + + cy.realPress("Space"); + + cy.get("@currentGroup") + .eq(0) + .should("have.attr", "collapsed"); + }); +}); + +describe("Timeline with growing mode", () => { + it("tests 'loadMore' event fired upon infinite scroll", () => { // 8 + cy.mount(html` +
+ + + + + + + +
`); + + cy.get("[ui5-timeline]") + .as("timeline"); + + cy.get("@timeline") + .then(timeline => { + timeline.get(0).addEventListener("ui5-load-more", cy.stub().as("loadMore")); + }); + + cy.get("#scroll-container") + .scrollTo("bottom", { duration: 100 }); + + cy.get("@loadMore") + .should("have.been.calledOnce"); + }); + + it("Arrow down and up navigation between last item and growing button", () => { + cy.mount(html` + + + + + + `); + + cy.get("[ui5-timeline]") + .as("timeline"); + + cy.get("@timeline") + .find("ui5-timeline-item") + .last() + .click(); + + cy.get("@timeline") + .find("ui5-timeline-item") + .last() + .should("be.focused"); + + cy.realPress("Tab"); + + cy.get("@timeline") + .shadow() + .find("[id$='growing-btn']") + .should("be.focused"); + + cy.realPress("Tab"); + + cy.get("@timeline") + .find("ui5-timeline-item") + .first() + .should("be.focused"); + }); +}); describe("Accessibility", () => { beforeEach(() => { diff --git a/packages/fiori/src/Timeline.ts b/packages/fiori/src/Timeline.ts index 28d9a324048e..1c91071baf82 100644 --- a/packages/fiori/src/Timeline.ts +++ b/packages/fiori/src/Timeline.ts @@ -5,22 +5,30 @@ import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; import { isTabNext, isTabPrevious, + isSpace, + isEnter, } from "@ui5/webcomponents-base/dist/Keys.js"; import type { ITabbable } from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import type ToggleButton from "@ui5/webcomponents/dist/ToggleButton.js"; +import "./TimelineItem.js"; import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js"; import { TIMELINE_ARIA_LABEL } from "./generated/i18n/i18n-defaults.js"; import TimelineTemplate from "./TimelineTemplate.js"; -import "./TimelineItem.js"; -import "./TimelineGroupItem.js"; - +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; +import debounce from "@ui5/webcomponents-base/dist/util/debounce.js"; +import query from "@ui5/webcomponents-base/dist/decorators/query.js"; +import process from "@ui5/webcomponents-icons/dist/process.js"; +import drillDown from "@ui5/webcomponents-icons/dist/drill-down.js"; // Styles import TimelineCss from "./generated/themes/Timeline.css.js"; import TimelineLayout from "./types/TimelineLayout.js"; +// Mode +import TimelineGrowingMode from "./types/TimelineGrowingMode.js"; /** * Interface for components that may be slotted inside `ui5-timeline` as items @@ -43,6 +51,7 @@ interface ITimelineItem extends UI5Element, ITabbable { const SHORT_LINE_WIDTH = "ShortLineWidth"; const LARGE_LINE_WIDTH = "LargeLineWidth"; +const GROWING_WITH_SCROLL_DEBOUNCE_RATE = 250; // ms /** * @class @@ -66,7 +75,22 @@ const LARGE_LINE_WIDTH = "LargeLineWidth"; styles: TimelineCss, template: TimelineTemplate, }) + +/** + * Fired when the user presses the `More` button or scrolls to the Timeline's end. + * + * **Note:** The event will be fired if `growing` is set to `Button` or `Scroll`. + * @public + * @since 2.7.0 + */ +@event("load-more", { + bubbles: true, +}) + class Timeline extends UI5Element { + eventDetails!: { + "load-more": void, + } /** * Defines the items orientation. * @default "Vertical" @@ -85,6 +109,50 @@ class Timeline extends UI5Element { @property() accessibleName?: string; + /** + * Defines if the component should display a loading indicator over the Timeline. + * + * @default false + * @since 2.7.0 + * @public + */ + @property({ type: Boolean }) + loading = false; + + /** + * Defines the delay in milliseconds, after which the loading indicator will show up for this component. + * @default 1000 + * @public + */ + @property({ type: Number }) + loadingDelay = 1000; + + /** + * Defines whether the Timeline will have growing capability either by pressing a "More" button, + * or via user scroll. In both cases a `load-more` event is fired. + * + * Available options: + * + * `Button` - Displays a button at the end of the Timeline, which when pressed triggers the `load-more` event. + * + * `Scroll` -Triggers the `load-more` event when the user scrolls to the end of the Timeline. + * + * `None` (default) - The growing functionality is off. + * + * @default "None" + * @since 2.7.0 + * @public + */ + @property() + growing: `${TimelineGrowingMode}` = "None"; + + /** + * Defines the active state of the `More` button. + * @private + */ + @property({ type: Boolean }) + _loadMoreActive = false; + /** * Determines the content of the `ui5-timeline`. * @public @@ -92,16 +160,22 @@ class Timeline extends UI5Element { @slot({ type: HTMLElement, individualSlots: true, "default": true }) items!: Array; + @query(".ui5-timeline-end-marker") + timelineEndMarker!: HTMLElement; + @i18n("@ui5/webcomponents-fiori") static i18nBundle: I18nBundle; _itemNavigation: ItemNavigation; + growingIntersectionObserver?: IntersectionObserver | null; + timeLineEndObserved = false; + initialIntersection = true; constructor() { super(); this._itemNavigation = new ItemNavigation(this, { - getItemsCallback: () => this._navigatableItems, + getItemsCallback: () => this._navigableItems, }); } @@ -111,6 +185,101 @@ class Timeline extends UI5Element { : Timeline.i18nBundle.getText(TIMELINE_ARIA_LABEL); } + get showBusyIndicatorOverlay() { + return !this.growsWithButton && this.loading; + } + + get growsOnScroll(): boolean { + return this.growing === TimelineGrowingMode.Scroll; + } + + get growingButtonIcon() { + return this.layout === TimelineLayout.Horizontal ? process : drillDown; + } + + get growsWithButton(): boolean { + return this.growing === TimelineGrowingMode.Button; + } + + onAfterRendering() { + if (this.growsOnScroll) { + this.observeTimelineEnd(); + } else if (this.timeLineEndObserved) { + this.unobserveTimelineEnd(); + } + + this.growingIntersectionObserver = this.getIntersectionObserver(); + } + + onExitDOM() { + this.unobserveTimelineEnd(); + } + + async observeTimelineEnd() { + if (!this.timeLineEndObserved) { + await renderFinished(); + this.getIntersectionObserver().observe(this.timelineEndMarker); + this.timeLineEndObserved = true; + } + } + + unobserveTimelineEnd() { + if (this.growingIntersectionObserver) { + this.growingIntersectionObserver.disconnect(); + this.growingIntersectionObserver = null; + this.timeLineEndObserved = false; + } + } + + getIntersectionObserver(): IntersectionObserver { + if (!this.growingIntersectionObserver) { + this.growingIntersectionObserver = new IntersectionObserver(this.onIntersection.bind(this), { + root: null, + threshold: 1.0, + }); + } + + return this.growingIntersectionObserver; + } + + onIntersection(entries: Array) { + if (this.initialIntersection) { + this.initialIntersection = false; + return; + } + + if (entries.some(entry => entry.isIntersecting)) { + debounce(this.loadMore.bind(this), GROWING_WITH_SCROLL_DEBOUNCE_RATE); + } + } + + loadMore() { + this.fireDecoratorEvent("load-more"); + } + + _onLoadMoreKeydown(e: KeyboardEvent) { + if (isSpace(e)) { + e.preventDefault(); + this._loadMoreActive = true; + } + + if (isEnter(e)) { + this._onLoadMoreClick(); + this._loadMoreActive = true; + } + } + + _onLoadMoreKeyup(e: KeyboardEvent) { + if (isSpace(e)) { + this._onLoadMoreClick(); + } + this._loadMoreActive = false; + } + + _onLoadMoreClick() { + this.fireDecoratorEvent("load-more"); + } + _onfocusin(e: FocusEvent) { let target = e.target as ITimelineItem | ToggleButton; @@ -188,8 +357,8 @@ class Timeline extends UI5Element { updatedTarget = target.shadowRoot!.querySelector("[ui5-toggle-button]")!; } - const nextTargetIndex = isNext ? this._navigatableItems.indexOf(updatedTarget) + 1 : this._navigatableItems.indexOf(updatedTarget) - 1; - const nextTarget = this._navigatableItems[nextTargetIndex]; + const nextTargetIndex = isNext ? this._navigableItems.indexOf(updatedTarget) + 1 : this._navigableItems.indexOf(updatedTarget) - 1; + const nextTarget = this._navigableItems[nextTargetIndex]; if (!nextTarget) { return; @@ -202,7 +371,7 @@ class Timeline extends UI5Element { } } - get _navigatableItems() { + get _navigableItems() { const navigatableItems: Array = []; if (!this.items.length) { diff --git a/packages/fiori/src/TimelineItem.ts b/packages/fiori/src/TimelineItem.ts index df4f8162ed24..89596151e12b 100644 --- a/packages/fiori/src/TimelineItem.ts +++ b/packages/fiori/src/TimelineItem.ts @@ -11,6 +11,7 @@ import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type { ITimelineItem } from "./Timeline.js"; import type ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; import TimelineItemTemplate from "./TimelineItemTemplate.js"; +// Styles import type TimelineLayout from "./types/TimelineLayout.js"; import { @@ -20,7 +21,6 @@ import { TIMELINE_ITEM_CRITICAL_STATE_TEXT, } from "./generated/i18n/i18n-defaults.js"; -// Styles import TimelineItemCss from "./generated/themes/TimelineItem.css.js"; /** diff --git a/packages/fiori/src/TimelineTemplate.tsx b/packages/fiori/src/TimelineTemplate.tsx index 6550273dc5c8..d2b6685432e0 100644 --- a/packages/fiori/src/TimelineTemplate.tsx +++ b/packages/fiori/src/TimelineTemplate.tsx @@ -1,20 +1,67 @@ +import Button from "@ui5/webcomponents/dist/Button.js"; import type Timeline from "./Timeline.js"; +import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js"; export default function TimelineTemplate(this: Timeline) { return (
+ onKeyDown={this._onkeydown} + > + +
-
-
    - {this.items.map(item => -
  • - -
  • - )} -
+
    + {this.items.map(item => +
  • + +
  • + )} + { this.growsWithButton && moreRow.call(this) } + { this.growsOnScroll && endRow.call(this) } +
+
+ +
+ ); +} + +function moreRow(this: Timeline) { + return ( +
  • +
    +
    + {this.loading && + + + } +
  • + ); +} + +function endRow(this: Timeline) { + return ( + ); } diff --git a/packages/fiori/src/themes/Timeline.css b/packages/fiori/src/themes/Timeline.css index 757a68c70f71..0e12bb56bec1 100644 --- a/packages/fiori/src/themes/Timeline.css +++ b/packages/fiori/src/themes/Timeline.css @@ -14,6 +14,25 @@ padding: 0; } +:host([layout="Horizontal"]) .ui5-timeline-list-item.ui5-timeline-list-growing { + display: flex; + flex-direction: column; + justify-content: center; + margin-inline-start: 0.625rem; + align-items: center; + min-width: 3.375rem; +} +:host([layout="Vertical"]) .ui5-timeline-list-item.ui5-timeline-list-growing { + display: flex; + flex-direction: row-reverse; + justify-content: center; + align-items: center; +} + +:host([layout="Horizontal"]) .ui5-timeline-end-marker { + margin: -0.625rem; +} + :host([layout="Vertical"]) .ui5-timeline-list { display: flex; flex-direction: column; @@ -44,4 +63,28 @@ overflow: auto; /* The padding values of the parent container are added to the size of scroll container */ width: calc(100% + var(--_ui5_timeline_scroll_container_offset)); +} + +:host([loading]) .ui5-timeline-growing-button-busy-indicator:not([_is-busy]) { + display: none; +} + +.ui5-timeline-root, +.ui5-timeline-busy-indicator { + width: 100%; + height: 100%; + position: relative; + box-sizing: border-box; + padding-inline-end: 0; +} + +:host([layout="Vertical"]) .ui5-timeline-scroll-container { + overflow: auto; + height: 100%; + width: 100%; +} + +:host([growing="Scroll"]) .ui5-timeline-end-marker { + /* Ensure the list-end-marker has a block property to always be stretched and "visible" on the screen */ + display: inline-block; } \ No newline at end of file diff --git a/packages/fiori/src/types/TimelineGrowingMode.ts b/packages/fiori/src/types/TimelineGrowingMode.ts new file mode 100644 index 000000000000..ff9d8358bad5 --- /dev/null +++ b/packages/fiori/src/types/TimelineGrowingMode.ts @@ -0,0 +1,22 @@ +enum TimelineGrowingMode { + /** + * Event `load-more` is fired + * upon pressing a "More" button at the end. + * @public + */ + Button = "Button", + + /** + * Event `load-more` is fired upon scroll. + * @public + */ + Scroll = "Scroll", + + /** + * The growing feature is not enabled. + * @public + */ + None = "None", +} + +export default TimelineGrowingMode; diff --git a/packages/fiori/test/pages/Timeline.html b/packages/fiori/test/pages/Timeline.html index 527b9a4bea50..6b84273bec3a 100644 --- a/packages/fiori/test/pages/Timeline.html +++ b/packages/fiori/test/pages/Timeline.html @@ -14,278 +14,353 @@ -
    -

    ui5-timeline

    -
    +
    +

    ui5-timeline

    +
    -
    -
    -

    Timeline within Card Vertical

    -
    - - - - - - - - MR SOF02 2.43 - - - Online meeting - - - -
    -

    Timeline within Card Horizontal

    -
    - - - - - - - - MR SOF02 2.43 - - - Online meeting - - - +
    +
    +

    Timeline within Card Vertical

    +
    + + + + + + + + MR SOF02 2.43 + + + Online meeting + + + +
    +

    Timeline within Card Horizontal

    +
    + + + + + + + + MR SOF02 2.43 + + + Online meeting + + + +
    -
    -
    -

    Result

    - -
    -
    + -
    -

    Basic Timeline - Vertical

    +
    +

    Basic Timeline - Vertical

    - - + + MR SOF02 2.43 - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + -
    +
    -
    -

    Basic Timeline - Horizontal

    +
    +

    Basic Timeline - Horizontal

    - - + + MR SOF02 2.43 - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting - + Online meeting -
    +
    + +
    -
    +
    +

    Basic Timeline - Vertical With groups

    +
    + + + + Morning event + + + Good morning + + + 20.02.2017 11:30 + -
    -

    Basic Timeline - Vertical With groups

    -
    - + + + 20.02.2017 11:30 + + + + + + + + + + + + +
    +
    - - - Morning event - +
    +

    Basic Timeline - Vertical

    +
    + + Good morning - - 20.02.2017 11:30 - - - - - - - 20.02.2017 11:30 - - - - - - - - - - - - -
    -
    - -
    -

    Basic Timeline - Vertical

    -
    - - - - Good morning - - - 20.02.2017 11:30 - - 20.02.2017 11:30 - - - - - - -
    -
    + + 20.02.2017 11:30 + + 20.02.2017 11:30 + + + + + +
    +
    +
    -
    -

    Basic Timeline - Horizontal With Groups

    -
    - - - - - - - - 20.02.2017 11:30 - - - - - - - - -
    -
    +
    +

    Basic Timeline - Horizontal With Groups

    +
    + + + + + + + + 20.02.2017 11:30 + + + + + + + + +
    +
    -
    -

    Basic Timeline - Horizontal

    -
    - - Test item - Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad sequi magnam nam sed numquam. - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad sequi magnam nam sed numquam. - Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad sequi magnam nam sed numquam. - - 20.02.2017 11:30 - - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad sequi magnam nam sed numquam. - Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad sequi magnam nam sed numquam. - - -
    -
    +
    +

    Basic Timeline - Horizontal

    +
    + + Test item + Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad + sequi magnam nam sed numquam. + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad + sequi magnam nam sed numquam. + Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad + sequi magnam nam sed numquam. + + 20.02.2017 11:30 + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad + sequi magnam nam sed numquam. + Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad + sequi magnam nam sed numquam. + + +
    +
    -
    -

    Advanced Timeline - Horizontal With Groups and Diverse Components

    -
    - - - -
    Discussion about upcoming projects
    - Meeting Link -
    - - Important -
    Topics: UI5 Basics, Advanced Concepts
    - Workshop Details -
    - - -
    Speaker: Sarah Kerrigan
    - Join Webinar -
    -
    - - - - - - - -
    Quarterly planning session
    -
    - - -
    Reviewing the budget for Q1
    -
    - - -
    Manager: John Smith
    - -
    -
    - - - High Priority -
    Task progress update
    -
    - - Deadline -
    Upload final project documents
    - Submit -
    - - - - - - -
    Review project deliverables
    -
    -
    -
    -
    -
    +
    +

    Advanced Timeline - Horizontal With Groups and Diverse Components

    +
    + + + +
    Discussion about upcoming projects
    + Meeting Link +
    + + Important +
    Topics: UI5 Basics, Advanced Concepts
    + Workshop Details +
    + + +
    Speaker: Sarah Kerrigan
    + Join Webinar +
    +
    + + + + + + + +
    Quarterly planning session
    +
    + + +
    Reviewing the budget for Q1
    +
    + + +
    Manager: John Smith
    + +
    +
    + + + High Priority +
    Task progress update
    +
    + + Deadline +
    Upload final project documents
    + Submit +
    + + + + + + +
    Review project deliverables
    +
    +
    +
    +
    +

    Timeline with Various Timeline Item States

    @@ -313,14 +388,7 @@

    Timeline with Various Timeline Item States

    -
    - - +
    + \ No newline at end of file diff --git a/packages/fiori/test/pages/TimelineGrowing_Button.html b/packages/fiori/test/pages/TimelineGrowing_Button.html new file mode 100644 index 000000000000..c285d4c35103 --- /dev/null +++ b/packages/fiori/test/pages/TimelineGrowing_Button.html @@ -0,0 +1,139 @@ + + + + + + + Timeline + + + + + + + + + +
    +

    Timeline growing "Button"

    +
    + +
    +

    Timeline - Vertical

    +
    + + + + MR SOF02 2.43 + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + +
    + +

    Timeline - Horizontal

    +
    + + + + MR SOF02 2.43 + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + +
    +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/packages/fiori/test/pages/TimelineGrowing_Scroll.html b/packages/fiori/test/pages/TimelineGrowing_Scroll.html new file mode 100644 index 000000000000..bd19e8e74a62 --- /dev/null +++ b/packages/fiori/test/pages/TimelineGrowing_Scroll.html @@ -0,0 +1,139 @@ + + + + + + + Timeline + + + + + + + + + +
    +

    Timeline growing "Scroll"

    +
    + +
    +

    Timeline - Vertical

    +
    + + + + MR SOF02 2.43 + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + +
    + +

    Timeline - Horizontal

    +
    + + + + MR SOF02 2.43 + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + + Online meeting + + +
    +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/packages/fiori/test/pages/styles/TimelineGrowing_Button.css b/packages/fiori/test/pages/styles/TimelineGrowing_Button.css new file mode 100644 index 000000000000..b709ae8f2e5d --- /dev/null +++ b/packages/fiori/test/pages/styles/TimelineGrowing_Button.css @@ -0,0 +1,20 @@ +.timeline_auto { + padding-inline-start: 2rem; +} + +.header { + display: flex; + justify-content: center; +} + +.timeline-vertical-container { + max-height: 25rem; + overflow: auto; + margin-bottom: 5rem; + display: flex; +} + +.timeline-horizontal-container { + max-width: 50%; + overflow: auto; +} diff --git a/packages/fiori/test/pages/styles/TimelineGrowing_Scroll.css b/packages/fiori/test/pages/styles/TimelineGrowing_Scroll.css new file mode 100644 index 000000000000..4c93bc206c4e --- /dev/null +++ b/packages/fiori/test/pages/styles/TimelineGrowing_Scroll.css @@ -0,0 +1,21 @@ +.timeline_auto { + padding-inline-start: 2rem; +} + +.header { + display: flex; + justify-content: center; +} + +.timeline-vertical-container { + max-height: 25rem; + overflow: auto; + margin-bottom: 5rem; + display: flex; +} + +.timeline-horizontal-container { + max-width: 50%; + overflow: auto; +} + diff --git a/packages/fiori/test/specs/Timeline.spec.js b/packages/fiori/test/specs/Timeline.spec.js deleted file mode 100644 index 28bb92da2a3c..000000000000 --- a/packages/fiori/test/specs/Timeline.spec.js +++ /dev/null @@ -1,88 +0,0 @@ -import { assert } from "chai"; - -describe("Timeline general interaction", () => { - before(async () => { - await browser.url(`test/pages/Timeline.html`); - }); - - it("should fire name-click event on a normal item name", async () => { - const timelineItemName = await browser.$("ui5-timeline-item").shadow$("ui5-link"); - const result = await browser.$("#result"); - - await timelineItemName.click(); - assert.strictEqual(await result.getText(), "Stanislava Baltova", "Click event is fired"); - }); - - it("setting accessible-name applied on the host element is reflected on the ul tag", async () => { - const timeline = await browser.$("#timelineAccName"); - - assert.strictEqual(await timeline.shadow$("ul").getAttribute("aria-label"), "Timeline vertical", "Attribute is reflected"); - }); - - it("Item within Timeline Item is rendered", async () => { - const timeline = await browser.$("#testTimeline"); - const timelineItem = await timeline.$("#testTimelineItem").shadow$("ui5-tli-desc"); - - assert.ok(timelineItem, "Item within Timeline Item is rendered"); - }) -}); - -describe("Timeline with group items interactions", () => { - before(async () => { - await browser.url(`test/pages/Timeline.html`); - }); - - it("Group items are rendered", async () => { - const timeline = await browser.$("#verticalWithGrps"); - const groupItem = await timeline.$$("ui5-timeline-group-item[group-name='Events']"); - const groupItemsLength = await groupItem[0].$$("ui5-timeline-item").length; - - - assert.strictEqual(groupItemsLength, 4, "Group items are rendered"); - }) - - it("Group items are collapsed on button click", async () => { - const timeline = await browser.$("#verticalWithGrps"); - const groupItem = await timeline.$$("ui5-timeline-group-item[group-name='Events']"); - const groupItemButton = await groupItem[0].shadow$("ui5-toggle-button"); - - await groupItemButton.click(); - - await browser.keys("Tab"); - - const nextGroupItem = await timeline.$$("ui5-timeline-group-item[group-name='Meetings']"); - const nextGroupItemButton = nextGroupItem[0].shadow$("ui5-toggle-button"); - - assert.ok(nextGroupItemButton.matches(":focus"), "Items are hidden on group collapse"); - }) - - it("Group items are navigatable", async () => { - const timeline = await browser.$("#verticalWithGrps"); - const groupItem = await timeline.$$("ui5-timeline-group-item[group-name='Events']"); - - await browser.keys("Tab"); - await browser.keys("ArrowDown"); - await browser.keys("ArrowDown"); - await browser.keys("ArrowUp"); - - const secondItemInGroup = await groupItem[0].$$("ui5-timeline-item"); - - assert.ok(secondItemInGroup[1].matches(":focus"), "Group items are navigatable with tab and arrow keys"); - }) - - it("Group can be collapsed/expanded using keyboard", async () => { - const timeline = await browser.$("#verticalWithGrps"); - const groupItem = await timeline.$$("ui5-timeline-group-item[group-name='Meetings']"); - const groupItemButton = await groupItem[0].shadow$("ui5-toggle-button"); - - await groupItemButton.click(); - await browser.keys("Enter"); - - assert.strictEqual(await groupItem[0].hasAttribute("collapsed"), false, "Group can be expanded with keyboard"); - - await browser.keys("Space"); - - assert.strictEqual(await groupItem[0].hasAttribute("collapsed"), true, "Group can be collapsed with keyboard"); - } - ); -}) diff --git a/packages/website/docs/_components_pages/fiori/Timeline/Timeline.mdx b/packages/website/docs/_components_pages/fiori/Timeline/Timeline.mdx index 41c634e87294..b9f6544b7bbb 100644 --- a/packages/website/docs/_components_pages/fiori/Timeline/Timeline.mdx +++ b/packages/website/docs/_components_pages/fiori/Timeline/Timeline.mdx @@ -3,6 +3,7 @@ import Horizontal from "../../../_samples/fiori/Timeline/Horizontal/Horizontal.m import InCard from "../../../_samples/fiori/Timeline/InCard/InCard.md"; import WithGroups from "../../../_samples/fiori/Timeline/WithGroups/WithGroups.md"; import WithState from "../../../_samples/fiori/Timeline/WithState/WithState.md"; +import WithGrowing from "../../../_samples/fiori/Timeline/WithGrowing/WithGrowing.md"; <%COMPONENT_OVERVIEW%> @@ -26,4 +27,8 @@ import WithState from "../../../_samples/fiori/Timeline/WithState/WithState.md"; ### Timeline with Groups - \ No newline at end of file + + +### Timeline with Growing + + \ No newline at end of file diff --git a/packages/website/docs/_samples/fiori/Timeline/WithGrowing/WithGrowing.md b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/WithGrowing.md new file mode 100644 index 000000000000..17798ecc59ab --- /dev/null +++ b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/WithGrowing.md @@ -0,0 +1,4 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; + + diff --git a/packages/website/docs/_samples/fiori/Timeline/WithGrowing/main.js b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/main.js new file mode 100644 index 000000000000..3213a2205147 --- /dev/null +++ b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/main.js @@ -0,0 +1,35 @@ +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/phone.js"; +import "@ui5/webcomponents-icons/dist/calendar.js"; + +let itemsLoaded = 0; +const itemToLoad = 5; +const growingTimeline = document.querySelector("#growingTimeline"); +const timelineItemTemplate = (index) => { + var timelineItem = document.createElement("ui5-timeline-item"); + timelineItem.titleText = "title text"; + timelineItem.subtitleText = "the subtitle tex goes here " + index; + timelineItem.icon = "calendar"; + return timelineItem; +} + + +const insertItems = (timeline) => { + for (var i = itemsLoaded; i < itemsLoaded + itemToLoad; i++) { + timeline.appendChild(timelineItemTemplate(i)); + } + itemsLoaded+= itemToLoad; +} + +growingTimeline.addEventListener("load-more", (e) => { + growingTimeline.loading = true; + + setTimeout(() => { + insertItems(growingTimeline); + growingTimeline.loading = false; + }, 1500); +}); \ No newline at end of file diff --git a/packages/website/docs/_samples/fiori/Timeline/WithGrowing/sample.html b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/sample.html new file mode 100644 index 000000000000..77fc3f287e74 --- /dev/null +++ b/packages/website/docs/_samples/fiori/Timeline/WithGrowing/sample.html @@ -0,0 +1,32 @@ + + + + + + + + Sample + + + + +
    + + + + + + MR SOF02 2.43 + + + + Online meeting + + +
    + + + + + +