diff --git a/docs/Public Module Imports.md b/docs/Public Module Imports.md index 000b8c4286dc..d96a78d4f588 100644 --- a/docs/Public Module Imports.md +++ b/docs/Public Module Imports.md @@ -31,8 +31,8 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | Carousel | `ui5-carousel` | `import "@ui5/webcomponents/dist/Carousel.js";` | | Checkbox | `ui5-checkbox` | `import "@ui5/webcomponents/dist/CheckBox.js";` | | ComboBox | `ui5-combobox` | `import "@ui5/webcomponents/dist/ComboBox.js";` | -| ComboBox Item | `ui5-cb-item` | comes with `ui5-combobox` | -| Date Picker | `ui5-date-picker` | `import "@ui5/webcomponents/dist/DatePicker.js";` | +| ComboBox Item | `ui5-cb-item` | comes with `ui5-combobox` | +| Date Picker | `ui5-date-picker` | `import "@ui5/webcomponents/dist/DatePicker.js";` | | Dialog | `ui5-dialog` | `import "@ui5/webcomponents/dist/Dialog.js";` | | File Uploader | `ui5-file-uploader` | `import "@ui5/webcomponents/dist/FileUploader.js";` | | Icon | `ui5-icon` | `import "@ui5/webcomponents/dist/Icon.js";` | @@ -45,13 +45,13 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | List - Group Header Item | `ui5-li-groupheader` | `import "@ui5/webcomponents/dist/GroupHeaderListItem.js";` | | Message Strip | `ui5-messagestrip` | `import "@ui5/webcomponents/dist/MessageStrip.js";` | | Multi ComboBox | `ui5-multi-combobox` | `import "@ui5/webcomponents/dist/MultiComboBox.js";` | -| Multi ComboBox Item | `ui5-mcb-item` | comes with `ui5-multi-combobox` | +| Multi ComboBox Item | `ui5-mcb-item` | comes with `ui5-multi-combobox` | | Panel | `ui5-panel` | `import "@ui5/webcomponents/dist/Panel.js";` | | Popover | `ui5-popover` | `import "@ui5/webcomponents/dist/Popover.js";` | | Radio Button | `ui5-radiobutton` | `import "@ui5/webcomponents/dist/RadioButton.js";` | | Responsive Popover | `ui5-responsive-popover`| `import "@ui5/webcomponents/dist/ResponsivePopover.js";`| | Select | `ui5-select` | `import "@ui5/webcomponents/dist/Select.js";` | -| Select Option | `ui5-option` | comes with `ui5-select ` | +| Select Option | `ui5-option` | comes with `ui5-select ` | | Segmented Button | `ui5-segmentedbutton`|`import "@ui5/webcomponents/dist/SegmentedButton.js";` | | Suggestion Item | `ui5-suggestion-item`|`import "@ui5/webcomponents/dist/SuggestionItem.js";` | | Switch | `ui5-switch` | `import "@ui5/webcomponents/dist/Switch.js";` | @@ -63,9 +63,9 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | Table Row | `ui5-table-row` | `import "@ui5/webcomponents/dist/TableRow.js";` | | Table Cell | `ui5-table-cell` | `import "@ui5/webcomponents/dist/TableCell.js";` | | Textarea | `ui5-textarea` | `import "@ui5/webcomponents/dist/TextArea.js";` | -| TimePicker | `ui5-time-picker` | `import "@ui5/webcomponents/dist/TimePicker.js";` | +| TimePicker | `ui5-time-picker` | `import "@ui5/webcomponents/dist/TimePicker.js";` | | Timeline | `ui5-timeline` | `import "@ui5/webcomponents/dist/Timeline.js";` | -| Timeline Item | `ui5-timeline-item` | comes with `ui5-timeline` | +| Timeline Item | `ui5-timeline-item` | comes with `ui5-timeline` | | Title | `ui5-title` | `import "@ui5/webcomponents/dist/Title.js";` | | Toast | `ui5-toast` | `import "@ui5/webcomponents/dist/Toast.js";` | | Toggle Button | `ui5-togglebutton` | `import "@ui5/webcomponents/dist/ToggleButton.js";` | @@ -147,6 +147,8 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | Notification Overflow Action | `ui5-notification-overflow-action` | `import "@ui5/webcomponents-fiori/dist/NotificationOverflowAction.js";`| | Upload Collection | `ui5-upload-collection` | `import "@ui5/webcomponents-fiori/dist/UploadCollection.js";` | | Upload Collection Item | `ui5-upload-collection-item` | `import "@ui5/webcomponents-fiori/dist/UploadCollectionItem.js";` | +| Wizard | `ui5-wizard` | `import "@ui5/webcomponents-fiori/dist/Wizard.js";` | +| Wizard Step | `ui5-wizard-step` | comes with `ui5-wizard` | ### 2. Assets diff --git a/packages/fiori/bundle.esm.js b/packages/fiori/bundle.esm.js index 6ffe5d349002..cdd601fa5e8f 100644 --- a/packages/fiori/bundle.esm.js +++ b/packages/fiori/bundle.esm.js @@ -20,5 +20,6 @@ import UploadCollectionItem from "./dist/UploadCollectionItem.js"; import NotificationListItem from "./dist/NotificationListItem.js" import NotificationListGroupItem from "./dist/NotificationListGroupItem.js"; import NotificationOverflowAction from "./dist/NotificationOverflowAction.js"; +import Wizard from "./dist/Wizard.js"; export default testAssets; diff --git a/packages/fiori/src/Wizard.hbs b/packages/fiori/src/Wizard.hbs new file mode 100644 index 000000000000..7a80338cc0e2 --- /dev/null +++ b/packages/fiori/src/Wizard.hbs @@ -0,0 +1,41 @@ +
+ + +
+ {{#each _steps}} +
+ +
+ {{/each}} +
+
\ No newline at end of file diff --git a/packages/fiori/src/Wizard.js b/packages/fiori/src/Wizard.js new file mode 100644 index 000000000000..6c4174c85e92 --- /dev/null +++ b/packages/fiori/src/Wizard.js @@ -0,0 +1,702 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; +import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; +import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js"; +import Float from "@ui5/webcomponents-base/dist/types/Float.js"; +import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import { isPhone } from "@ui5/webcomponents-base/dist/Device.js"; + +// Texts +import { + WIZARD_NAV_STEP_DEFAULT_HEADING, + WIZARD_NAV_ARIA_ROLE_DESCRIPTION, +} from "./generated/i18n/i18n-defaults.js"; + +// Step in header and content +import WizardTab from "./WizardTab.js"; +import WizardStep from "./WizardStep.js"; + +// Template and Styles +import WizardTemplate from "./generated/templates/WizardTemplate.lit.js"; +import WizardCss from "./generated/themes/Wizard.css.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-wizard", + managedSlots: true, + properties: /** @lends sap.ui.webcomponents.fiori.Wizard.prototype */ { + /** + * Defines the aria-label text of the ui5-wizard. + * + * @type {String} + * @defaultvalue undefined + * @private + */ + ariaLabel: { + type: String, + defaultValue: undefined, + }, + + /** + * Defines the width of the ui5-wizard. + * @private + */ + width: { + type: Float, + }, + }, + slots: /** @lends sap.ui.webcomponents.fiori.Wizard.prototype */ { + /** + * Defines the steps. + *

+ * Note: Use the available ui5-wizard-step component. + * + * @type {HTMLElement[]} + * @public + * @slot + */ + "default": { + propertyName: "steps", + type: HTMLElement, + "individualSlots": true, + listenFor: { include: ["*"] }, + }, + }, + events: /** @lends sap.ui.webcomponents.fiori.Wizard.prototype */ { + /** + * Fired when the step selection is changed by user interaction - either with scrolling, + * or by clicking on the steps within the component header. + * + * @event sap.ui.webcomponents.fiori.Wizard#selection-change + * @param {HTMLElement} selectedStep the newly selected step + * @param {HTMLElement} previouslySelectedStep the previously selected step + * @public + */ + "selection-change": { + detail: { + selectedStep: { type: HTMLElement }, + previouslySelectedStep: { type: HTMLElement }, + }, + }, + }, +}; + +/** + * @class + * + *

Overview

+ * + * The ui5-wizard helps users complete a complex task by dividing it into sections and guiding the user through it. + * It has two main areas - a navigation area at the top showing the step sequence and a content area below it. + * + *

Structure

+ *

Navigation area

+ * The top most area of the ui5-wizard is occupied by the navigation area. + * It shows the sequence of steps, where the recommended number of steps is between 3 and 8 steps. + * + * + * Note: If no selected step is defined, the first step will be auto selected. + *
+ * Note: If multiple selected steps are defined, the last step will be selected. + * + *

Content

+ * The content occupies the main part of the page. It can hold any type of HTML elements. + * It's defined by using the ui5-wizard-step as slotted element within the ui5-wizard. + * + *

Scrolling

+ * The component handles user scrolling by selecting the closest step, based on the current scroll position + * and scrolls to particular place, when the user clicks on the step within the navigation area. + *

+ * + * Important: In order the component's scrolling behaviour to work, it has to be limited from the outside parent element in terms of height. + * The component or its parent has to be given percentage or absolute height. Otherwise, the component will be scrolled out with the entire page. + *

+ * For example: + *

+ * <ui5-dialog style="height: 80%">
+ * <ui5-wizard></ui5-wizard>
+ * </ui5-dialog> + * + *

Moving to next step

+ * The ui5-wizard-step provides the necessary API and it's up to the user of the component to use it to move to the next step. + * You have to set its selected property (and remove the disabled one if set) to true. + * And, the ui5-wizard will automatically scroll to the content of the newly selected step. + *

+ * + * The Fiori 3 guidelines recommends having a "nextStep" button in the content area. + * You can place a button, or any other type of element to trigger step change, inside the ui5-wizard-step, + * and show/hide it when certain fields are filled or user defined criteria is met. + * + *

Usage

+ *

When to use:

+ * When the user has to accomplish a long set of tasks. + *

When not to use:

+ * When the task has less than 3 steps. + * + *

Responsive Behavior

+ * On small widths the step's heading, subheading and separators in the navigation area + * will start truncate and shrink and from particular point they will hide to free as much space as possible. + * + *

ES6 Module Import

+ * import @ui5/webcomponents-fiori/dist/Wizard.js"; (includes ) + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.fiori.Wizard + * @extends UI5Element + * @tagname ui5-wizard + * @since 1.0.0-rc.10 + * @appenddocs WizardStep + * @public + */ +class Wizard extends UI5Element { + constructor() { + super(); + + // Stores the scroll offsets of the steps, + // e.g. the steps' starting point. + this.stepScrollOffsets = []; + + // Keeps track of the selected step index. + this.selectedStepIndex = 0; + + // Indicates that selection will be changed + // due to user click. + this.selectionRequestedByClick = false; + + // Indicates that selection will be changed + // due to user scroll. + this.selectionRequestedByScroll = false; + + this.initItemNavigation(); + + this._onResize = this.onResize.bind(this); + + this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + } + + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get styles() { + return WizardCss; + } + + static get template() { + return WizardTemplate; + } + + static get dependencies() { + return [WizardTab, WizardStep]; + } + + static async onDefine() { + await fetchI18nBundle("@ui5/webcomponents-fiori"); + } + + static get PHONE_BREAKPOINT() { + return 559; + } + + static get SCROLL_DEBOUNCE_RATE() { + return 25; + } + + static get CONTENT_TOP_OFFSET() { + return 80; + } + + onEnterDOM() { + ResizeHandler.register(this, this._onResize); + } + + onExitDOM() { + ResizeHandler.deregister(this, this._onResize); + } + + onBeforeRendering() { + this.syncSelection(); + } + + onAfterRendering() { + this.storeStepScrollOffsets(); + this.scrollToSelectedStep(); + } + + /** + * Normalizes the step selection as follows: + * (1) If there is no selected step - the first step is going to be selected. + * (2) If the selected steps are more than one - the last step is going to be selected. + * (3) If the selected step is also disabled - log a warning. + * @private + */ + syncSelection() { + if (this.stepsCount === 0) { + return; + } + + // If no selected steps -> select the first step. + if (this.selectedStepsCount === 0) { + this.selectFirstStep(); + console.warn("Selecting the first step: no selected step is defined."); // eslint-disable-line + } + + // If there are multiple selected steps -> keep the last selected one. + if (this.selectedStepsCount > 1) { + this.selectLastSelectedStep(); + console.warn(`Selecting the last step defined as selected: multiple selected steps are defined.`); // eslint-disable-line + } + + // If the selected step is defined as disabled - log warning. + if (this.selectedStep && this.selectedStep.disabled) { + console.warn("The selected step is disabled: you need to enable it in order to interact with the step."); // eslint-disable-line + } + + // Place for improvement: If the selected step is not the first, enable all the prior steps + this.selectedStepIndex = this.getSelectedStepIndex(); + } + + /** + * Selects the first step. + * @private + */ + selectFirstStep() { + this.deselectAll(); + this.slottedSteps[0].selected = true; + this.slottedSteps[0].disabled = false; + } + + /** + * Selects the last step from multiple selected ones. + * @private + */ + selectLastSelectedStep() { + const lastSelectedStep = this.lastSelectedStep; + + if (lastSelectedStep) { + this.deselectAll(); + lastSelectedStep.selected = true; + lastSelectedStep.disabled = false; + } + } + + /** + * Deselects all steps. + * @private + */ + deselectAll() { + this.slottedSteps.forEach(step => { + step.selected = false; + }); + } + + /** + * Stores the scroll offsets of the steps, + * e.g. the steps' starting point. + * + * Note: the disabled ones has negative offsets. + * @private + */ + storeStepScrollOffsets() { + this.stepScrollOffsets = this.slottedSteps.map(step => { + const contentItem = this.getStepWrapperByRefId(step._id); + return contentItem.offsetTop + contentItem.offsetHeight - Wizard.CONTENT_TOP_OFFSET; + }); + } + + /** + * Handles user click on steps' tabs within the header. + * Note: the handler is bound in the template. + * @param {Event} event + * @private + */ + onSelectionChangeRequested(event) { + this.selectionRequestedByClick = true; + this.changeSelectionByStepClick(event.target); + } + + /** + * Handles user scrolling with debouncing. + * Note: the handler is bound in the template. + * @param {Event} event + * @private + */ + onScroll(event) { + if (this.selectionRequestedByClick) { + this.selectionRequestedByClick = false; + return; + } + + this.debounce(this.changeSelectionByScroll.bind(this, event.target.scrollTop), Wizard.SCROLL_DEBOUNCE_RATE); + } + + /** + * Handles when a step in the header is focused in order to update the ItemNavigation. + * Note: the handler is bound in the template. + * @param {Event} event + * @private + */ + onStepInHeaderFocused(event) { + this._itemNavigation.update(event.target); + } + + /** + * Handles component resize to: + * (1) trigger scroll scrollOffset reCalculation and syncSelection + * (2) hide steps' separators and texts to free more space on small sizes + * @private + */ + onResize() { + this.width = this.getBoundingClientRect().width; + } + + /** + * Called upon onScroll. + * Selects the closest step, based on the user scroll position. + * @param {Integer} scrollPos the current scroll position + * @private + */ + changeSelectionByScroll(scrollPos) { + const newlySelectedIndex = this.getClosestStepIndexByScrollPos(scrollPos); + + // Skip if already selected - stop. + if (this.selectedStepIndex === newlySelectedIndex) { + return; + } + + // If the calculated index is in range, + // change selection and fire "selection-change". + if (newlySelectedIndex >= 0 && newlySelectedIndex <= this.stepsCount - 1) { + const stepToSelect = this.slottedSteps[newlySelectedIndex]; + this.switchSelectionFromOldToNewStep(this.selectedStep, stepToSelect, newlySelectedIndex); + this.selectionRequestedByScroll = true; + } + } + + /** + * Called upon onSelectionChangeRequested. + * Selects the external step (ui5-wizard-step), + * based on the clicked step in the header (ui5-wizard-tab). + * @param {HTMLElement} stepInHeader the step equivalent in the header + * @private + */ + changeSelectionByStepClick(stepInHeader) { + const stepRefId = stepInHeader.getAttribute("data-ui5-content-ref-id"); + const selectedStep = this.selectedStep; + const stepToSelect = this.getStepByRefId(stepRefId); + + // If the currently selected (active) step is clicked, + // just scroll to its starting point and stop. + if (selectedStep === stepToSelect) { + this.scrollToContentItem(this.selectedStepIndex); + return; + } + + // Change selection and fire "selection-change". + const newlySelectedIndex = this.slottedSteps.indexOf(stepToSelect); + this.switchSelectionFromOldToNewStep(selectedStep, stepToSelect, newlySelectedIndex); + } + + get _stepsInHeader() { + return this.getStepsInfo(); + } + + get _steps() { + const lastEnabledStepIndex = this.getLastEnabledStepIndex(); + + return this.steps.map((step, idx) => { + step.stretch = idx === lastEnabledStepIndex; + return step; + }); + } + + get stepsCount() { + return this.slottedSteps.length; + } + + get selectedStep() { + if (this.selectedStepsCount) { + return this.selectedSteps[0]; + } + + return null; + } + + get lastSelectedStep() { + if (this.selectedStepsCount) { + return this.selectedSteps[this.selectedStepsCount - 1]; + } + + return null; + } + + get selectedSteps() { + return this.slottedSteps.filter(step => step.selected); + } + + get enabledSteps() { + return this.slottedSteps.filter(step => !step.disabled); + } + + get selectedStepsCount() { + return this.selectedSteps.length; + } + + get slottedSteps() { + return this.getSlottedNodes("steps"); + } + + get contentDOM() { + return this.shadowRoot.querySelector(`.ui5-wiz-content`); + } + + get stepsInHeaderDOM() { + return Array.from(this.shadowRoot.querySelectorAll("[ui5-wizard-tab]")); + } + + get enabledStepsInHeaderDOM() { + return this.stepsInHeaderDOM.filter(step => !step.disabled); + } + + get phoneMode() { + if (isPhone()) { + return true; + } + + return this.width <= Wizard.PHONE_BREAKPOINT; + } + + get navAriaRoleDescription() { + return this.i18nBundle.getText(WIZARD_NAV_ARIA_ROLE_DESCRIPTION); + } + + get navStepDefaultHeading() { + return this.i18nBundle.getText(WIZARD_NAV_STEP_DEFAULT_HEADING); + } + + get ariaLabelText() { + return this.ariaLabel || this.i18nBundle.getText(WIZARD_NAV_ARIA_ROLE_DESCRIPTION); + } + + /** + * Returns an array of data objects, based on the user defined steps + * to later build the steps (tabs) within the header. + * @returns {Array} + * @private + */ + getStepsInfo() { + const lastEnabledStepIndex = this.getLastEnabledStepIndex(); + const stepsCount = this.stepsCount; + + return this.steps.map((step, idx) => { + const pos = idx + 1; + + // Hide separator if: + // (1) its size is under the phone breakpoint + // (2) it's the last step and it's not a branching one + const hideSeparator = this.phoneMode || ((idx === stepsCount - 1) && !step.branching); + + // Calculate the step's aria-roledectioption: "1. heading" or "Step 1". + const roleDescription = step.heading ? `${pos}. ${step.heading}` : `${this.navStepDefaultHeading} ${pos}`; + + return { + icon: step.icon, + heading: this.phoneMode ? "" : step.heading, + subheading: this.phoneMode ? "" : step.subheading, + number: pos, + selected: step.selected, + disabled: step.disabled, + hideSeparator, + activeSeparator: (idx < lastEnabledStepIndex) && !step.disabled, + branchingSeparator: step.branching, + pos, + size: stepsCount, + roleDescription, + ariaLabel: getEffectiveAriaLabelText(step), + refStepId: step._id, + tabIndex: this.selectedStepIndex === idx ? "0" : "-1", + }; + }); + } + + /** + * Returns the index of the selected step. + * @returns {Integer} + * @private + */ + getSelectedStepIndex() { + if (this.selectedStep) { + return this.slottedSteps.indexOf(this.selectedStep); + } + return 0; + } + + /** + * Returns the index of the last enabled step. + * @returns {Integer} + * @private + */ + getLastEnabledStepIndex() { + let lastEnabledStepIndex = 0; + + this.slottedSteps.forEach((step, idx) => { + if (!step.disabled) { + lastEnabledStepIndex = idx; + } + }); + + return lastEnabledStepIndex; + } + + getStepByRefId(refId) { + return this.slottedSteps.find(step => step._id === refId); + } + + getStepWrapperByRefId(refId) { + return this.shadowRoot.querySelector(`[data-ui5-content-item-ref-id=${refId}]`); + } + + /** + * Scrolls to the content of the selected step + * and it is used in onAfteRendering. + * @private + */ + scrollToSelectedStep() { + if (!this.selectionRequestedByScroll) { + this.scrollToContentItem(this.selectedStepIndex); + } + this.selectionRequestedByScroll = false; + } + + /** + * Scrolls to the content item within the ui5-wizard shadowDOM + * by given step index. + * + * @private + * @param {Integer} stepIndex the index of a step + */ + scrollToContentItem(stepIndex) { + this.contentDOM.scrollTop = this.getClosestScrollPosByStepIndex(stepIndex); + } + + /** + * Returns to closest scroll position for the given step index. + * by given step index. + * + * @private + * @param {Integer} stepIndex the index of a step + */ + getClosestScrollPosByStepIndex(stepIndex) { + if (stepIndex === 0) { + return 0; + } + + // It's possible to have [enabled - 0, disabled - 1, enabled - 2, disabled - 3] step definition and similar. + // Consider selection of the third step at index 2, the wizard should scroll where the previous step ends, + // but in this case the 2nd step is disabled, so we have to fallback to the first possible step. + for (let closestStepIndex = stepIndex - 1; closestStepIndex >= 0; closestStepIndex--) { + if (this.stepScrollOffsets[closestStepIndex] > 0) { + return this.stepScrollOffsets[closestStepIndex]; + } + } + + return 0; + } + + /** + * Returns the closest step index by given scroll position. + * + * @param {Integer} scrollPos scroll position + * @returns {Integer} closestStepIndex the closest step index + * @private + */ + getClosestStepIndexByScrollPos(scrollPos) { + for (let closestStepIndex = 0; closestStepIndex <= this.stepScrollOffsets.length - 1; closestStepIndex++) { + const stepOffset = this.stepScrollOffsets[closestStepIndex]; + + if (stepOffset > 0 && scrollPos < stepOffset) { + return closestStepIndex; + } + } + + return 0; + } + + /** + * Switches the selection from the old step to the newly selected step. + * + * @param {HTMLElement} selectedStep the old step + * @param {HTMLElement} stepToSelect the step to be selected + * @param {Integer} selectedStepIndex the index of the newly selected step + * @private + */ + switchSelectionFromOldToNewStep(selectedStep, stepToSelect, selectedStepIndex) { + if (selectedStep && stepToSelect) { + selectedStep.selected = false; + stepToSelect.selected = true; + + this.fireEvent("selection-change", { + selectedStep: stepToSelect, + previouslySelectedStep: selectedStep, + }); + + this.selectedStepIndex = selectedStepIndex; + } + } + + /** + * Initializes the ItemNavigation + * that controls the navigation between the steps in the navigation header. + * @private + */ + initItemNavigation() { + this._itemNavigation = new ItemNavigation(this, { + navigationMode: NavigationMode.Horizontal, + }); + + this._itemNavigation.getItemsCallback = () => this.enabledStepsInHeaderDOM; + } + + /** + * Delays function execution by given threshold - used to delay the scroll event handling. + * @private + */ + debounce(fn, delay) { + clearTimeout(this.debounceInterval); + this.debounceInterval = setTimeout(() => { + this.debounceInterval = null; + fn(); + }, delay); + } + + /** + * Sorter method for sorting an array in ascending order. + * @private + */ + sortAscending(a, b) { + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } +} + +Wizard.define(); + +export default Wizard; diff --git a/packages/fiori/src/WizardStep.js b/packages/fiori/src/WizardStep.js new file mode 100644 index 000000000000..6d4ef59ecf79 --- /dev/null +++ b/packages/fiori/src/WizardStep.js @@ -0,0 +1,164 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-wizard-step", + properties: /** @lends sap.ui.webcomponents.fiori.WizardStep.prototype */ { + /** + * Defines the heading of the step. + *

+ * + * Note: the text is displayed in the ui5-wizard navigation header. + *
+ * Note: the text will hide on small sizes (about 559 px). + * @type {String} + * @defaultvalue "" + * @public + */ + heading: { + type: String, + }, + + /** + * Defines the subheading of the step. + *

+ * + * Note: the text is displayed in the ui5-wizard navigation header. + *
+ * Note: the text will hide on small sizes (about 559 px). + * @type {String} + * @defaultvalue "" + * @public + */ + subheading: { + type: String, + }, + + /** + * Defines the icon of the step. + *

+ * + * Note: the icon is displayed in the ui5-wizard navigation header. + *

+ * + * The SAP-icons font provides numerous options. + * See all the available icons in the Icon Explorer. + * @type {String} + * @defaultvalue "" + * @public + */ + icon: { + type: String, + }, + + /** + * Defines if the step is disabled. When disabled the step is displayed, + * but the user can't select the step by clicking or navigate to it with scrolling. + *

+ * + * Note: Step can't be selected and disabled at the same time. + * In this case the selected property would take precedence. + * + * @type {boolean} + * @defaultvalue false + * @public + */ + disabled: { + type: Boolean, + }, + + /** + * Defines the step's selected state - the step that is currently active. + *

+ * + * Note: Step can't be selected and disabled at the same time. + * In this case the selected property would take precedence. + * + * @type {boolean} + * @defaultvalue false + * @public + */ + selected: { + type: Boolean, + }, + + /** + * When branching is enabled a dashed line would be displayed after the step, + * meant to indicate that the next step is not yet known and depends on user choice in the current step. + *

+ * + * Note: It is recommended to use branching on the last known step + * and later add new steps when it becomes clear how the wizard flow should continue. + * + * @type {boolean} + * @defaultvalue false + * @public + */ + branching: { + type: Boolean, + }, + + /** + * Defines the aria-label of the step. + * @type {boolean} + * @defaultvalue "" + * @private + */ + ariaLabel: { + type: String, + }, + + /** + * Defines the aria-labelledby of the step. + * @type {boolean} + * @defaultvalue "" + * @private + */ + ariaLabelledby: { + type: String, + }, + }, + slots: /** @lends sap.ui.webcomponents.fiori.WizardStep.prototype */ { + }, + events: /** @lends sap.ui.webcomponents.fiori.WizardStep.prototype */ { + }, +}; + +/** + * @class + * + *

Overview

+ * + * A component that represents a logical step as part of the ui5-wizard. + * It is meant to aggregate arbitrary HTML elements that forms the content of a single step. + * + *

Structure

+ *
    + *
  • Each wizard step has arbitrary content
  • + *
  • Each wizard step might have texts - defined by the heading and subheading properties
  • + *
  • Each wizard step might have an icon - defined by the icon property
  • + *
  • Each wizard step might display a number in place of the icon, when it's missing
  • + *
+ * + *

Usage

+ * The ui5-wizard-step component should be used only as slot of the ui5-wizard component + * and should not be used standalone. + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.fiori.WizardStep + * @extends UI5Element + * @tagname ui5-wizard-step + * @public + */ +class WizardStep extends UI5Element { + static get metadata() { + return metadata; + } +} + +WizardStep.define(); + +export default WizardStep; diff --git a/packages/fiori/src/WizardTab.hbs b/packages/fiori/src/WizardTab.hbs new file mode 100644 index 000000000000..0a9959411319 --- /dev/null +++ b/packages/fiori/src/WizardTab.hbs @@ -0,0 +1,34 @@ +
+
+
+ {{#if icon}} + + {{else}} + {{number}} + {{/if}} +
+ {{#if hasTexts}} +
+
{{heading}}
+
{{subheading}}
+
+ {{/if}} +
+ + {{#unless hideSeparator}} +
+ {{/unless}} +
\ No newline at end of file diff --git a/packages/fiori/src/WizardTab.js b/packages/fiori/src/WizardTab.js new file mode 100644 index 000000000000..f3686a56d4ea --- /dev/null +++ b/packages/fiori/src/WizardTab.js @@ -0,0 +1,291 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; +import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; +import Icon from "@ui5/webcomponents/dist/Icon.js"; + +import WizardTabTemplate from "./generated/templates/WizardTabTemplate.lit.js"; +import WizardTabCss from "./generated/themes/WizardTab.css.js"; + +const metadata = { + tag: "ui5-wizard-tab", + properties: /** @lends sap.ui.webcomponents.fiori.WizardTab.prototype */ { + /** + * Defines the icon of the step. + * @type {String} + * @defaultvalue "" + * @private + */ + icon: { + type: String, + }, + + /** + * Defines the heading of the step. + * @type {String} + * @defaultvalue "" + * @private + */ + heading: { + type: String, + }, + + /** + * Defines the subheading of the step. + * @type {String} + * @defaultvalue "" + * @private + */ + subheading: { + type: String, + }, + + /** + * Defines the number that will be displayed in place of the icon, when it's missing. + * @type {String} + * @defaultvalue "" + * @private + */ + number: { + type: String, + }, + + /** + * Defines if the step is disabled - the step is not responding to user interaction. + * @type {boolean} + * @defaultvalue false + * @private + */ + disabled: { + type: Boolean, + }, + + /** + * Defines if the step is selected
. + *

+ * + * @type {boolean} + * @defaultvalue false + * @private + */ + selected: { + type: Boolean, + }, + + /** + * Defines if the step's separator is hidden or not. + * @type {boolean} + * @defaultvalue false + * @private + */ + hideSeparator: { + type: Boolean, + }, + + /** + * Defines if the step's separator is active or not. + * @type {boolean} + * @defaultvalue false + * @private + */ + activeSeparator: { + type: Boolean, + }, + + /** + * Defines if the step's separator is dashed or not. + * @type {boolean} + * @defaultvalue false + * @private + */ + branchingSeparator: { + type: Boolean, + }, + + /** + * Defines the role of the step. + * @type {boolean} + * @defaultvalue listitem + * @private + */ + role: { + type: String, + defaultValue: "listitem", + }, + + /** + * Defines the aria-roledescription of the step. + * @type {boolean} + * @defaultvalue "" + * @private + */ + ariaRoledescription: { + type: String, + }, + + /** + * Defines the aria-label of the step. + * @type {boolean} + * @defaultvalue undefined + * @private + */ + ariaLabel: { + type: String, + defaultValue: undefined, + }, + + /** + * Defines the aria-labelledby of the step. + * @type {boolean} + * @defaultvalue undefined + * @private + */ + ariaLabelledby: { + type: String, + defaultValue: undefined, + }, + + /** + * Defines the aria-setsize of the step. + * @type {boolean} + * @defaultvalue undefined + * @private + */ + ariaSetsize: { + type: Integer, + }, + + /** + * Defines the aria-posinset of the step. + * @type {boolean} + * @defaultvalue undefined + * @private + */ + ariaPosinset: { + type: Integer, + }, + + /** + * Defines the tabindex of the step. + * @type {String} + * @defaultvalue -1 + * @private + */ + _tabIndex: { + type: String, + defaultValue: "-1", + }, + }, + slots: /** @lends sap.ui.webcomponents.fiori.WizardTab.prototype */ { + }, + events: /** @lends sap.ui.webcomponents.fiori.WizardTab.prototype */ { + /** + * Fired when clicking on none disabled step. + * + * @event sap.ui.webcomponents.fiori.WizardTab#selection-change-requested + * @private + */ + "selection-change-requested": {}, + }, +}; + +/** + * @class + * + *

Overview

+ * Private component, used internally by the ui5-wizard + * to represent a "step" in the navigation header of the ui5-wizard. + * + *

Usage

+ * + * For the ui5-wizard-tap + *

ES6 Module Import

+ * + * import @ui5/webcomponents/dist/WizardTab.js"; (imported with ) + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.fiori.WizardTab + * @extends UI5Element + * @tagname ui5-wizard-tab + * @private + */ +class WizardTab extends UI5Element { + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get styles() { + return WizardTabCss; + } + + static get template() { + return WizardTabTemplate; + } + + static get dependencies() { + return [Icon]; + } + + _onclick() { + if (!this.disabled) { + this.fireEvent("selection-change-requested"); + } + } + + _onkeydown(event) { + if (this.disabled) { + return; + } + + if (isSpace(event)) { + event.preventDefault(); + } + + if (isEnter(event)) { + this.fireEvent("selection-change-requested"); + } + } + + _onkeyup(event) { + if (this.disabled) { + return; + } + + if (isSpace(event)) { + this.fireEvent("selection-change-requested"); + } + } + + _onfocusin() { + if (this.disabled) { + return; + } + + this.fireEvent("focused"); + } + + get tabIndex() { + return this.disabled ? undefined : this._tabIndex; + } + + get ariaCurrent() { + return this.selected ? "step" : undefined; + } + + get ariaDisabled() { + return this.disabled ? "true" : undefined; + } + + get hasTexts() { + return this.heading || this.subheading; + } +} + +WizardTab.define(); + +export default WizardTab; diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties index 8361b9c02d6d..58a5fd5bb98a 100644 --- a/packages/fiori/src/i18n/messagebundle.properties +++ b/packages/fiori/src/i18n/messagebundle.properties @@ -109,4 +109,10 @@ SHELLBAR_PRODUCTS = Products SHELLBAR_SEARCH = Search #XACT: ARIA announcement for the more button -SHELLBAR_OVERFLOW = More \ No newline at end of file +SHELLBAR_OVERFLOW = More + +#XACT: ARIA announcement for roledescription attribute of Wizard navigation header +WIZARD_NAV_ARIA_ROLE_DESCRIPTION = Wizard + +#XACT: WizardProgressNavigator predefined text for step +WIZARD_NAV_STEP_DEFAULT_HEADING=Step \ No newline at end of file diff --git a/packages/fiori/src/themes/Wizard.css b/packages/fiori/src/themes/Wizard.css new file mode 100644 index 000000000000..baec6b05e3a2 --- /dev/null +++ b/packages/fiori/src/themes/Wizard.css @@ -0,0 +1,64 @@ +:host(:not([hidden])) { + display: block; + height: 100%; + width: 100%; + overflow: auto; +} + +.ui5-wiz-root { + height: 100%; + width: 100%; + position: relative; +} + +.ui5-wiz-nav { + position: absolute; + display: flex; + align-items: center; + z-index: 1; + height: 4rem; + width: 100%; + padding: 1rem; + background: var(--sapObjectHeader_Background); + font-size: var(--sapFontMediumSize); + box-shadow: inset 0 -0.125rem var(--sapObjectHeader_BorderColor); + box-sizing: border-box; + user-select: none; + outline: none; +} + +.ui5-wiz-nav-list { + display: flex; + align-items: center; + flex-direction: row; + width: 100%; + margin: 0; + padding: 0; +} + +.ui5-wiz-nav-list > * { + flex-grow: 1; +} + +.ui5-wiz-content { + position: relative; + padding: 5rem 1rem 1rem 1rem; + overflow: auto; + height: calc(100% - 4rem); + box-sizing: border-box; +} + +.ui5-wiz-content-item { + display: block; + box-sizing: border-box; + padding-bottom: 2rem; +} + +.ui5-wiz-content-item[hidden] { + display: none; +} + +.ui5-wiz-content-item[stretch] { + /* Add 2rem to ensure there is enough scroll height to reach the last step */ + min-height: calc(100% + 2rem); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/WizardTab.css b/packages/fiori/src/themes/WizardTab.css new file mode 100644 index 000000000000..5f06e9fe9198 --- /dev/null +++ b/packages/fiori/src/themes/WizardTab.css @@ -0,0 +1,139 @@ +:host(:not([hidden])) { + display: inline-block; + /* Well known worakround to allow shrinking inside flex containers + * and shrinking is needed so the texts trucnate properly. + */ + min-width: 1px; +} + +/* Selected (active) step */ +:host([selected]:not([disabled])) .ui5-wiz-step-icon-circle { + background: var(--_ui5_wiz_tab_selected_bg); +} + +:host([selected]:not([disabled])) .ui5-wiz-step-icon-circle::after { + content: ""; + position: absolute; + border-bottom: 0.25rem solid var(--_ui5_wiz_tab_selection_line); + border-top-left-radius: 0.1875rem; + border-top-right-radius: 0.1875rem; + left: 0; + right: 0; + bottom: -1rem; +} + +:host([selected]:not([disabled])) .ui5-wiz-step-icon { + color: var(--sapList_Active_TextColor); +} + +:host([selected]:not([disabled])) .ui5-wiz-step-number { + color: var(--sapList_Active_TextColor); +} + +/* Disabled step */ +:host([disabled]) .ui5-wiz-step-icon-circle { + border-color: var(--sapList_BorderColor); + background: var(--sapObjectHeader_Background); +} + +:host([disabled]) .ui5-wiz-step-icon { + color: var(--sapContent_LabelColor); +} + +:host([disabled]) .ui5-wiz-step-number { + color: var(--sapContent_LabelColor); +} + +.ui5-wiz-step-root { + display: flex; + align-items: center; + flex-direction: row; + padding: 0 .5rem; + font-size: var(--sapFontSize); + font-family: var(--sapFontFamily); + outline: none; +} + +.ui5-wiz-step-main { + display: flex; + align-items: center; + flex-direction: row; + min-width: 2rem; +} + +:host(:not([disabled])) .ui5-wiz-step-main { + cursor: pointer; +} + +.ui5-wiz-step-root:focus .ui5-wiz-step-main { + outline: var(--_ui5_wiz_tab_focus_outline); +} + +/* Icon */ +.ui5-wiz-step-icon-circle { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + min-width: 2rem; + height: 2rem; + background: var(--sapObjectHeader_Background); + border: var(--_ui5_wiz_tab_border); + border-radius: 50%; + pointer-events: none; +} + +.ui5-wiz-step-icon { + width: 1rem; + height: 1rem; + color: var(--_ui5_wiz_tab_icon_color); + pointer-events: none; +} + +/* Texts when no icon set */ +.ui5-wiz-step-number { + color: var(--_ui5_wiz_tab_icon_color); +} + +/* Heading and Subheading */ +.ui5-wiz-step-texts { + display: flex; + flex-direction: column; + padding: 0 .5rem; +} + +.ui5-wiz-step-heading, +.ui5-wiz-step-subheading { + color: var(--sapContent_LabelColor); + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.ui5-wiz-step-subheading { + font-size: var(--sapFontSmallSize); +} + +/* Separator */ +.ui5-wiz-step-hr { + display: inline-block; + border-bottom-color: var(--sapList_BorderColor); + border-bottom-width: 1px; + border-bottom-style: solid; + height: 1px; + flex-grow: 1; +} + +:host([active-separator]) .ui5-wiz-step-hr { + border-bottom-color: var(--_ui5_wiz_tab_active_separator_color) +} + +:host([branching-separator]) .ui5-wiz-step-hr { + border-bottom-style: dashed; +} + +/* Workaround for IE to make the focus outline visible */ +ui5-wizard-tab .ui5-wiz-step-main { + pointer-events: none; +} \ No newline at end of file diff --git a/packages/fiori/src/themes/base/WizardTab-parameters.css b/packages/fiori/src/themes/base/WizardTab-parameters.css new file mode 100644 index 000000000000..6d350ad9fe83 --- /dev/null +++ b/packages/fiori/src/themes/base/WizardTab-parameters.css @@ -0,0 +1,8 @@ +:root { + --_ui5_wiz_tab_focus_outline: 1px dotted var(--sapContent_FocusColor); + --_ui5_wiz_tab_selected_bg: var(--sapSelectedColor); + --_ui5_wiz_tab_border: 1px solid var(--sapSelectedColor); + --_ui5_wiz_tab_selection_line: var(--sapSelectedColor); + --_ui5_wiz_tab_icon_color: var(--sapSelectedColor); + --_ui5_wiz_tab_active_separator_color: var(--sapSelectedColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize/parameters-bundle.css b/packages/fiori/src/themes/sap_belize/parameters-bundle.css index c8fd179b1929..7bfa8734bb4e 100644 --- a/packages/fiori/src/themes/sap_belize/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize/parameters-bundle.css @@ -1,3 +1,4 @@ @import "../base/FlexibleColumnLayout-parameters.css"; @import "../base/ProductSwitchItem-parameters.css"; -@import "../base/UploadCollection-parameters.css"; \ No newline at end of file +@import "../base/UploadCollection-parameters.css"; +@import "../base/WizardTab-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/WizardTab-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/WizardTab-parameters.css new file mode 100644 index 000000000000..d0fb81f4dfc6 --- /dev/null +++ b/packages/fiori/src/themes/sap_belize_hcb/WizardTab-parameters.css @@ -0,0 +1,9 @@ +@import "../base/WizardTab-parameters.css"; + +:root { + --_ui5_wiz_tab_focus_outline: 0.125rem dotted var(--sapContent_FocusColor); + --_ui5_wiz_tab_selection_line: var(--sapTextColor); + --_ui5_wiz_tab_border: 1px solid var(--sapTextColor); + --_ui5_wiz_tab_icon_color: var(--sapTextColor); + --_ui5_wiz_tab_active_separator_color: var(--sapTextColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css index 6babe5296a03..7267d1281af3 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css @@ -1,3 +1,4 @@ @import "./FlexibleColumnLayout-parameters.css"; @import "./ProductSwitchItem-parameters.css"; -@import "./UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; +@import "./WizardTab-parameters.css"; diff --git a/packages/fiori/src/themes/sap_belize_hcw/WizardTab-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/WizardTab-parameters.css new file mode 100644 index 000000000000..ac97f70ae210 --- /dev/null +++ b/packages/fiori/src/themes/sap_belize_hcw/WizardTab-parameters.css @@ -0,0 +1,8 @@ +@import "../base/WizardTab-parameters.css"; + +:root { + --_ui5_wiz_tab_focus_outline: 0.125rem dotted var(--sapContent_FocusColor); + --_ui5_wiz_tab_selection_line: var(--sapTextColor); + --_ui5_wiz_tab_border: 1px solid var(--sapTextColor); + --_ui5_wiz_tab_icon_color: var(--sapTextColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css index 6babe5296a03..7267d1281af3 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css @@ -1,3 +1,4 @@ @import "./FlexibleColumnLayout-parameters.css"; @import "./ProductSwitchItem-parameters.css"; -@import "./UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; +@import "./WizardTab-parameters.css"; diff --git a/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css index c8fd179b1929..66ad60845cb6 100644 --- a/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css @@ -1,3 +1,4 @@ @import "../base/FlexibleColumnLayout-parameters.css"; @import "../base/ProductSwitchItem-parameters.css"; -@import "../base/UploadCollection-parameters.css"; \ No newline at end of file +@import "../base/UploadCollection-parameters.css"; +@import "../base/WizardTab-parameters.css"; diff --git a/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css index f51cd989bb52..6a36e1cbf4a8 100644 --- a/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css @@ -1,3 +1,4 @@ @import "./FlexibleColumnLayout-parameters.css"; @import "../base/ProductSwitchItem-parameters.css"; -@import "../base/UploadCollection-parameters.css"; \ No newline at end of file +@import "../base/UploadCollection-parameters.css"; +@import "../base/WizardTab-parameters.css"; diff --git a/packages/fiori/src/themes/sap_fiori_3_hcb/WizardTab-parameters.css b/packages/fiori/src/themes/sap_fiori_3_hcb/WizardTab-parameters.css new file mode 100644 index 000000000000..d0fb81f4dfc6 --- /dev/null +++ b/packages/fiori/src/themes/sap_fiori_3_hcb/WizardTab-parameters.css @@ -0,0 +1,9 @@ +@import "../base/WizardTab-parameters.css"; + +:root { + --_ui5_wiz_tab_focus_outline: 0.125rem dotted var(--sapContent_FocusColor); + --_ui5_wiz_tab_selection_line: var(--sapTextColor); + --_ui5_wiz_tab_border: 1px solid var(--sapTextColor); + --_ui5_wiz_tab_icon_color: var(--sapTextColor); + --_ui5_wiz_tab_active_separator_color: var(--sapTextColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_fiori_3_hcb/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3_hcb/parameters-bundle.css index 97855c33e4b4..5e32744b2a8c 100644 --- a/packages/fiori/src/themes/sap_fiori_3_hcb/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3_hcb/parameters-bundle.css @@ -1,2 +1,3 @@ @import "./ProductSwitchItem-parameters.css"; -@import "./UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; +@import "./WizardTab-parameters.css"; diff --git a/packages/fiori/src/themes/sap_fiori_3_hcw/WizardTab-parameters.css b/packages/fiori/src/themes/sap_fiori_3_hcw/WizardTab-parameters.css new file mode 100644 index 000000000000..ac97f70ae210 --- /dev/null +++ b/packages/fiori/src/themes/sap_fiori_3_hcw/WizardTab-parameters.css @@ -0,0 +1,8 @@ +@import "../base/WizardTab-parameters.css"; + +:root { + --_ui5_wiz_tab_focus_outline: 0.125rem dotted var(--sapContent_FocusColor); + --_ui5_wiz_tab_selection_line: var(--sapTextColor); + --_ui5_wiz_tab_border: 1px solid var(--sapTextColor); + --_ui5_wiz_tab_icon_color: var(--sapTextColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_fiori_3_hcw/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3_hcw/parameters-bundle.css index 97855c33e4b4..5e32744b2a8c 100644 --- a/packages/fiori/src/themes/sap_fiori_3_hcw/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3_hcw/parameters-bundle.css @@ -1,2 +1,3 @@ @import "./ProductSwitchItem-parameters.css"; -@import "./UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; +@import "./WizardTab-parameters.css"; diff --git a/packages/fiori/test/pages/FCL.html b/packages/fiori/test/pages/FCL.html index 7b54bbd7754c..e5daec9fdb2e 100644 --- a/packages/fiori/test/pages/FCL.html +++ b/packages/fiori/test/pages/FCL.html @@ -82,20 +82,133 @@ -
-
- Column 2 -
- - Hello worild! - Hello worild! - Hello worild! - Hello worild! - Hello worild! - Hello worild! - Hello worild! - Hello worild! - +
+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + + Open Wizard Dialog +
+ + Step 2 +
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Largr + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ + Finalize +
+
@@ -615,7 +728,7 @@ }); expandMidColumn.addEventListener("click", function(e) { - const tb = e.target; + var tb = e.target; if (tb.pressed) { tb.icon = "exit-full-screen"; fcl6.layout = "MidColumnFullScreen"; @@ -632,7 +745,7 @@ }); expandEndColumn.addEventListener("click", function(e) { - const tb = e.target; + var tb = e.target; if (tb.pressed) { tb.icon = "exit-full-screen"; @@ -783,6 +896,59 @@ fullscreenEndColumn.addEventListener("click", function (e) { fclApp.layout = nextLayout("col3fullscreen"); }); + + // Wizard + var wiz = document.getElementById("wiz"); + + wiz.addEventListener("selection-change", function () { + console.log(event.detail.selectedStep); + }); + + sw.addEventListener("change", function () { + toStep3.removeAttribute("hidden"); + }); + + sb.addEventListener("selection-change", function () { + toStep4.removeAttribute("hidden"); + }); + + toStep2.addEventListener("click", function () { + deselectAll(); + setStep(1); + toStep2.setAttribute("hidden", true); + }); + + toStep3.addEventListener("click", function () { + deselectAll(wiz); + setStep(2); + toStep3.setAttribute("hidden", true); + }); + + toStep4.addEventListener("click", function () { + deselectAll(wiz); + setStep(3); + toStep4.setAttribute("hidden", true); + }); + + finalize.addEventListener("click", function () { + alert("Finalize") + }); + + function deselectAll() { + Array.from(wiz.children).forEach(function(step) { + step.selected = false; + }); + } + + function setStep(idx) { + const step = getStep(idx); + step.selected = true; + step.disabled = false; + } + + function getStep(idx) { + return Array.from(wiz.children)[idx]; + } diff --git a/packages/fiori/test/pages/Wizard.html b/packages/fiori/test/pages/Wizard.html new file mode 100644 index 000000000000..09b900831b2e --- /dev/null +++ b/packages/fiori/test/pages/Wizard.html @@ -0,0 +1,788 @@ + + + + + + + + Wizard + + + + + + + + + + + + + +

Wizard

+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + + Open Wizard Dialog +
+ + Step 2 +
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Large + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ + Finalize +
+
+ +

Wizard non-standard

+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + + Open Wizard Dialog +
+
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Large + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ +
+ + +
+ 5. Final
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ +
+
+ +

Wizard non-standard 2

+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + + Open Wizard Dialog +
+
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Large + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ +
+
+ +

Wizard non-standard 3

+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + +
+
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Large + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ +
+
+ + + + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + +
+ + Step 2 +
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Largr + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ + Finalize +
+
+
+ + + + diff --git a/packages/fiori/test/pages/Wizard_test.html b/packages/fiori/test/pages/Wizard_test.html new file mode 100644 index 000000000000..357ae20b9ff4 --- /dev/null +++ b/packages/fiori/test/pages/Wizard_test.html @@ -0,0 +1,204 @@ + + + + + + + + Wizard Test Page + + + + + + + + + + +
+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + + + +
+ + Step 2 +
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + Step 3 +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Largr + +
+
+
+ + Step 4 +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ + Finalize +
+
+
+ + + + diff --git a/packages/fiori/test/samples/Wizard.sample.html b/packages/fiori/test/samples/Wizard.sample.html new file mode 100644 index 000000000000..d5e8b922954b --- /dev/null +++ b/packages/fiori/test/samples/Wizard.sample.html @@ -0,0 +1,287 @@ +
+

Wizard

+
+ +
+
+ +
@ui5/webcomponents-fiori
+ +
<ui5-wizard>
+ + + + +
+

Wizard

+ +
+ + +
+ 1. Product Type
+ + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ + Sed fermentum, mi et tristique ullamcorper, sapien sapien faucibus sem, quis pretium nibh lorem malesuada diam. Nulla quis arcu aliquet, feugiat massa semper, volutpat diam. Nam vitae ante posuere, molestie neque sit amet, dapibus velit. Maecenas eleifend tempor lorem. Mauris vitae elementum mi, sed eleifend ligula. Nulla tempor vulputate dolor, nec dignissim quam convallis ut. Praesent vitae commodo felis, ut iaculis felis. Fusce quis eleifend sapien, eget facilisis nibh. Suspendisse est velit, scelerisque ut commodo eget, dignissim quis metus. Cras faucibus consequat gravida. Curabitur vitae quam felis. Phasellus ac leo eleifend, commodo tortor et, varius quam. Aliquam erat volutpat. + +
+ + Step 2 +
+ + +
+ 2. Product Information
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + +
+
+ Name + +
+ +
+ Weight + +
+ +
+ Manifacturer + + Apple + Samsung + Huawei + +
+ +
+ 5 years guarantee included + +
+
+
+ + +
+ + +
+ 3. Options
+ + + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Manifacture date + +
+ +
+ Availability + + In stock + In depot + Damaged + Out of stock + +
+ +
+ Size + + Small + Medium + Large + +
+
+
+ + +
+ + +
+ 4. Pricing
+ + Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien + + + The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with. +
+ +
+
+ Price + +
+ +
+ Quantity + +
+ +
+ Vat included + +
+
+
+ + Finalize +
+
+
+ + + +

+<ui5-wizard id="wiz">
+	<ui5-wizard-step icon="product" heading="Product type" selected>
+		<ui5-title>1. Product Type</ui5-title>
+
+		<!-- Move to step 2 -->
+		<ui5-button id="toStep2">Step 2</ui5-button>
+	</ui5-wizard-step>
+
+	<ui5-wizard-step icon="hint" heading="Product Information" disabled>
+		<ui5-title>2. Product Information</ui5-title>
+
+		<div>
+			<ui5-label>5 years guarantee included</ui5-label>
+			<ui5-switch id="sw"></ui5-switch>
+		</div>
+
+		<!-- Move to step 3 -->
+		<ui5-button id="toStep3" hidden>Step 3</ui5-button>
+	</ui5-wizard-step>
+
+	<ui5-wizard-step icon="action-settings" heading="Options" disabled>
+		<ui5-title>3. Options</ui5-title><br>
+
+		<ui5-segmentedbutton id="sb">
+			<ui5-togglebutton icon="employee" pressed>Small</ui5-togglebutton>
+			<ui5-togglebutton>Medium</ui5-togglebutton>
+			<ui5-togglebutton>Large</ui5-togglebutton>
+		</ui5-segmentedbutton>
+
+		<!-- Move to step 4 -->
+		<ui5-button id="toStep4" hidden>Step 4</ui5-button>
+	</ui5-wizard-step>
+
+	<ui5-wizard-step icon="lead" heading="Pricing" disabled>
+		<ui5-title>4. Pricing</ui5-title><br>
+		<ui5-button id="finalize">Finalize</ui5-button>
+	</ui5-wizard-step>
+</ui5-wizard>
+
+<script>
+	// The code shows how the users can manipulte the ui5-wizard-step API (selected and disabled)
+	// to go through the wizard steps.
+	const moveToStep = idx => {
+		const step = getStep(idx); // where "step" is an instance of ui5-wizard-step
+		step.selected = true;
+		step.disabled = false;
+	}
+	const getStep = idx => {
+		return Array.from(wizard.children)[idx];
+	}
+	const deselectAllSteps = () => {
+		Array.from(wizard.children).forEach(function(step) {
+			step.selected = false;
+		});
+	}
+
+	// Move to Step 2
+	toStep2.addEventListener("click", function () {
+		deselectAllSteps();
+		moveToStep(1);
+	});
+
+	// Move to Step 3
+	toStep3.addEventListener("click", function () {
+		deselectAllSteps();
+		moveToStep(2);
+	});
+
+	// Show the "step to 3" button after "validation"
+	sw.addEventListener("change", function () {
+		toStep3.removeAttribute("hidden");
+	});
+</script>
+	
+
+ + diff --git a/packages/fiori/test/specs/Wizard.spec.js b/packages/fiori/test/specs/Wizard.spec.js new file mode 100644 index 000000000000..ba66c8f145a3 --- /dev/null +++ b/packages/fiori/test/specs/Wizard.spec.js @@ -0,0 +1,155 @@ +const assert = require("chai").assert; + +describe("Wizard general interaction", () => { + browser.url("http://localhost:8081/test-resources/pages/Wizard_test.html"); + + it("test initial selection", () => { + const wiz = browser.$("#wizTest"); + const step1 = browser.$("#st1"); + const step1InHeader = wiz.shadow$(`[data-ui5-index="1"]`); + + // assert - that first step in the content and in the header are properly selected + assert.strictEqual(step1.getAttribute("selected"), "true", + "First step in the content is selected."); + assert.strictEqual(step1InHeader.getAttribute("selected"), "true", + "First step in the header is selected."); + }); + + it("move to next step by API", () => { + const wiz = browser.$("#wizTest"); + const btnToStep2 = browser.$("#toStep2"); + const step1 = browser.$("#st1"); + const step2 = browser.$("#st2"); + const step1InHeader = wiz.shadow$(`[data-ui5-index="1"]`); + const step2InHeader = wiz.shadow$(`[data-ui5-index="2"]`); + + // act - the click handler calls the API + btnToStep2.click(); + + // assert - that first step in the content and in the header are not selected + assert.strictEqual(step1.getAttribute("selected"), null, + "First step in the content is not selected."); + assert.strictEqual(step1InHeader.getAttribute("selected"), null, + "First step in the header not is selected."); + + // assert - that second step in the content and in the header are properly selected + assert.strictEqual(step2.getAttribute("selected"), "true", + "Second step in the content is selected."); + assert.strictEqual(step2InHeader.getAttribute("selected"), + "true", "Second step in the header is selected."); + assert.strictEqual(step2.getAttribute("disabled"), null, + "Second step is enabled."); + assert.strictEqual(step2InHeader.getAttribute("disabled"), null, + "Second step in header is enabled."); + }); + + it("move to next step by click", () => { + const wiz = browser.$("#wizTest"); + const step1 = browser.$("#st1"); + const step2 = browser.$("#st2"); + const step1InHeader = wiz.shadow$(`[data-ui5-index="1"]`); + const step2InHeader = wiz.shadow$(`[data-ui5-index="2"]`); + const inpSelectionChangeCounter = browser.$("#inpSelectionChangeCounter"); + + // act - click on the first step in the header + step1InHeader.click(); + + // assert - that first step in the content and in the header are selected + assert.strictEqual(step1.getAttribute("selected"), "true", + "First step in the content is not selected."); + assert.strictEqual(step1InHeader.getAttribute("selected"), "true", + "First step in the header not is selected."); + assert.strictEqual(step1.getAttribute("disabled"), null, + "First step is enabled."); + assert.strictEqual(step1InHeader.getAttribute("disabled"), null, + "First step in header is enabled."); + + // assert - that second step in the content and in the header are not selected + assert.strictEqual(step2.getAttribute("selected"), null, + "Second step in the content is not selected."); + assert.strictEqual(step2InHeader.getAttribute("selected"), null, + "Second step in the header is not selected."); + + // assert - selection-change fired once + assert.strictEqual(inpSelectionChangeCounter.getProperty("value"), "1", + "Event selection-change fired once."); + }); + + it("move to next step by SPACE/ENTER", () => { + const wiz = browser.$("#wizTest"); + const step1 = browser.$("#st1"); + const step2 = browser.$("#st2"); + const step1InHeader = wiz.shadow$(`[data-ui5-index="1"]`); + const step2InHeader = wiz.shadow$(`[data-ui5-index="2"]`); + const inpSelectionChangeCounter = browser.$("#inpSelectionChangeCounter"); + + // act - bring the focus to the first step in the header + // act - use keyboard to move to step2 + step1InHeader.click(); + step1InHeader.keys("ArrowRight"); + step2InHeader.keys("Space"); + + // assert - that first step in the content and in the header are not selected + assert.strictEqual(step1.getAttribute("selected"), null, "First step in the content is not selected."); + assert.strictEqual(step1InHeader.getAttribute("selected"), null, "First step in the header not is selected."); + + // assert - that second step in the content and in the header are properly selected + assert.strictEqual(step2.getAttribute("selected"), "true", + "Second step in the content is selected."); + assert.strictEqual(step2InHeader.getAttribute("selected"), "true", + "Second step in the header is selected."); + assert.strictEqual(step2.getAttribute("disabled"), null, + "Second step is enabled."); + assert.strictEqual(step2InHeader.getAttribute("disabled"), null, + "Second step in header is enabled."); + + // assert - selection-change second time + assert.strictEqual(inpSelectionChangeCounter.getProperty("value"), "2", "Event selection-change fired 2nd time."); + + // act - use keyboard to move back to step1 + step2InHeader.keys("ArrowLeft"); + step1InHeader.keys("Enter"); + + // assert - that first step in the content and in the header are selected + assert.strictEqual(step1.getAttribute("selected"), "true", + "First step in the content is not selected."); + assert.strictEqual(step1InHeader.getAttribute("selected"), "true", + "First step in the header not is selected."); + assert.strictEqual(step1.getAttribute("disabled"), null, + "First step is enabled."); + assert.strictEqual(step1InHeader.getAttribute("disabled"), null, + "First step in header is enabled."); + + // assert - that second step in the content and in the header are not selected + assert.strictEqual(step2.getAttribute("selected"), null, + "Second step in the content is not selected."); + assert.strictEqual(step2InHeader.getAttribute("selected"), null, + "Second step in the header is not selected."); + + // assert - selection-change second time + assert.strictEqual(inpSelectionChangeCounter.getProperty("value"), "3", + "Event selection-change fired 3rd time."); + }); + + it("move to next step by scroll", () => { + const wiz = browser.$("#wizTest"); + const step2 = browser.$("#st2"); + const step2InHeader = wiz.shadow$(`[data-ui5-index="2"]`); + const inpSelectionChangeCounter = browser.$("#inpSelectionChangeCounter"); + + // act - scroll the 2nd step into view + // Note: scrollIntoView works in Chrome, but if we start executing the test on every browser, + // this test should be reworked. + step2.scrollIntoView(); + browser.pause(500); + + // assert - that second step in the content and in the header are properly selected + assert.strictEqual(step2.getAttribute("selected"), "true", "Second step in the content is selected."); + assert.strictEqual(step2InHeader.getAttribute("selected"), "true", "Second step in the header is selected."); + assert.strictEqual(step2.getAttribute("disabled"), null, "Second step is enabled."); + assert.strictEqual(step2InHeader.getAttribute("disabled"), null, "Second step in header is enabled."); + + assert.strictEqual(inpSelectionChangeCounter.getProperty("value"), "4", + "Event selection-change fired 4rd time due to scrolling."); + }); +}); \ No newline at end of file diff --git a/packages/playground/Gemfile.lock b/packages/playground/Gemfile.lock index b07b4ca3cef0..e952777daeb0 100644 --- a/packages/playground/Gemfile.lock +++ b/packages/playground/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - UI5-Web-Components-Playground (1.0.0.pre.rc.8) + UI5-Web-Components-Playground (1.0.0.pre.rc.9) jekyll (~> 3.8.5) jekyll-seo-tag (~> 2.0) rake (~> 12.3.1) @@ -17,9 +17,7 @@ GEM eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) eventmachine (1.2.7) - eventmachine (1.2.7-x64-mingw32) ffi (1.11.1) - ffi (1.11.1-x64-mingw32) forwardable-extended (2.6.0) http_parser.rb (0.6.0) i18n (0.9.5) diff --git a/packages/playground/build-scripts/samples-prepare.js b/packages/playground/build-scripts/samples-prepare.js index 89695d5fc329..9b307adfa3d6 100644 --- a/packages/playground/build-scripts/samples-prepare.js +++ b/packages/playground/build-scripts/samples-prepare.js @@ -12,7 +12,8 @@ const components = []; // Add new components here const newComponents = [ - "MultiInput" + "MultiInput", + "Wizard", ]; packages.forEach(package => {