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 @@ +
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.
+ * 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
+ *
+ * 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.
+ *
+ * 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.
+ * ui5-wizard-step
as slotted element within the ui5-wizard
ui5-wizard-step
as slotted element within the ui5-wizard
.
+ *
+ * <ui5-dialog style="height: 80%">
+ * <ui5-wizard></ui5-wizard>
+ * </ui5-dialog>
+ *
+ * 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.
+ * ui5-wizard-step
,
+ * and show/hide it when certain fields are filled or user defined criteria is met.
+ *
+ * import @ui5/webcomponents-fiori/dist/Wizard.js";
(includes 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