UNPKG

@carbon/ibm-products-web-components

Version:

Carbon for IBM Products Web Components

259 lines (255 loc) • 10.5 kB
/** * Copyright IBM Corp. 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { __decorate } from 'tslib'; import { nothing, html } from 'lit'; import { property, state } from 'lit/decorators.js'; import { prefix } from '../../globals/settings.js'; import HostListenerMixin from '@carbon/web-components/es/globals/mixins/host-listener.js'; import { carbonElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js'; import '@carbon/web-components/es/components/button/index.js'; import styles from './interstitial-screen-footer.scss.js'; import { interstitialDetailsSignal } from './interstitial-screen-context.js'; import { SignalWatcher } from '@lit-labs/signals'; import '@carbon/web-components/es/components/inline-loading/inline-loading.js'; import { CDSModalFooter } from '@carbon/web-components/es/index.js'; import ArrowRight from '@carbon/web-components/es/icons/arrow--right/16.js'; /** * @license * * Copyright IBM Corp. 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const blockClass = `${prefix}--interstitial-screen`; /** * interstitial-screen-footer for footer section * @element c4p-interstitial-screen-footer * @fires c4p-on-action - The name of the custom event fired just before the action. You can use this event to perform any async/sync validation. * if you pass async-action = true, the component will wait for an external listener (e.g., a form validation or confirmation modal) to resolve the proceed() * callback before continuing. When asyncAction is true, you must listen for the eventOnBeforeAction event and call the proceed() function * (either synchronously or with a promise) to allow navigation. */ let CDSInterstitialScreenFooter = class CDSInterstitialScreenFooter extends SignalWatcher(HostListenerMixin(CDSModalFooter)) { constructor() { super(...arguments); /** * The label for the Next button. */ this.nextButtonLabel = 'Next'; /** * The label for the Previous button. */ this.previousButtonLabel = 'Back'; /** * The label for the skip button. */ this.skipButtonLabel = 'Skip'; /** * The label for the start button. */ this.startButtonLabel = 'Get Started'; this.slot = 'footer'; this.handleSkip = () => this.handleAction('skip'); this.handleStart = () => this.handleAction('start'); this.handleClickNext = () => this.handleAction('next'); this.handleClickPrev = () => this.handleAction('back'); this.handleAction = async (actionType) => { var _a; this.loadingAction = actionType; const { currentStep, stepDetails } = interstitialDetailsSignal.get(); const stepCount = stepDetails.length; let resolvePromise; const proceedPromise = new Promise((resolve) => { resolvePromise = resolve; }); const customEvent = new CustomEvent(this.constructor.eventOnBeforeAction, { bubbles: true, composed: true, cancelable: true, detail: { step: currentStep, stepCount: stepCount, proceed: (allow) => { Promise.resolve(allow).then(resolvePromise); }, }, }); const eventNotCanceled = this.dispatchEvent(customEvent); if (!eventNotCanceled) { return; } const canProceed = this.asyncAction ? await proceedPromise : true; this.loadingAction = ''; if (canProceed) { const { carouselAPI } = interstitialDetailsSignal.get(); if (actionType == 'next') { carouselAPI.next(); } else if (actionType === 'back') { carouselAPI.prev(); } else { (_a = this._handleUserInitiatedClose) === null || _a === void 0 ? void 0 : _a.call(this, actionType); } } }; } updated(_changedProperties) { if (_changedProperties.size === 0) { // This logic ensures the start/next button receives focus when focus is lost from the "next" or "back" buttons // during step navigation—particularly when those buttons are not rendered. this.updateComplete.then(() => { const { stepDetails, currentStep } = interstitialDetailsSignal.get(); const isMultiStep = Array.isArray(stepDetails) && stepDetails.length > 0; const lastStepIndex = (stepDetails === null || stepDetails === void 0 ? void 0 : stepDetails.length) - 1; if (!isMultiStep) { return; } const focusButton = (selector) => { var _a; const btn = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(selector); btn === null || btn === void 0 ? void 0 : btn.focus(); }; if (currentStep === lastStepIndex) { focusButton(`.${prefix}--interstitial-screen--start-btn`); } else if (currentStep === 0) { focusButton(`.${prefix}--interstitial-screen--next-btn`); } }); } } _handleUserInitiatedClose(triggeredBy) { const init = { bubbles: true, cancelable: true, composed: true, detail: { triggeredBy, }, }; this.dispatchEvent(new CustomEvent(this.constructor.eventRequestClose, init)); } render() { const { stepDetails, currentStep, disableActions } = interstitialDetailsSignal.get(); const { start, next, back, skip } = disableActions; const isMulti = (stepDetails === null || stepDetails === void 0 ? void 0 : stepDetails.length) > 0; const progStepCeil = (stepDetails === null || stepDetails === void 0 ? void 0 : stepDetails.length) - 1; return html `<slot> <div class="${blockClass}--footer"> ${isMulti ? html ` <cds-button class="${blockClass}--skip-btn" kind="ghost" size="lg" title="${this.skipButtonLabel}" @click="${this.handleSkip}" ?disabled="${skip}" > ${this.skipButtonLabel} </cds-button> ` : ''} <div class="${blockClass}--footer-controls"> ${isMulti && currentStep > 0 ? html ` <cds-button class="${blockClass}--prev-btn" kind="secondary" size="lg" title="${this.previousButtonLabel}" ?disabled="${back}" @click="${this.handleClickPrev}" > ${this.previousButtonLabel} ${this.loadingAction === 'back' ? html ` <cds-inline-loading slot="icon" aria-live="off"> </cds-inline-loading>` : nothing} </cds-button> ` : nothing} ${isMulti && currentStep < progStepCeil ? html ` <cds-button class="${blockClass}--next-btn" kind="primary" size="lg" title="${this.nextButtonLabel}" ?disabled="${next}" @click="${this.handleClickNext}" > ${this.nextButtonLabel} ${this.loadingAction === 'next' ? html ` <cds-inline-loading slot="icon" aria-live="off"> </cds-inline-loading>` : html ` ${ArrowRight({ slot: 'icon' })}`} </cds-button> ` : nothing} ${(isMulti && currentStep === progStepCeil) || !isMulti ? html ` <cds-button class="${blockClass}--start-btn" kind="primary" size="lg" title="${this.startButtonLabel}" ?disabled="${start}" @click="${this.handleStart}" > ${this.startButtonLabel} ${this.loadingAction === 'start' ? html ` <cds-inline-loading slot="icon" aria-live="off"> </cds-inline-loading>` : nothing} </cds-button> ` : nothing} </div> </div> </slot>`; } static get eventRequestClose() { return `${prefix}-request-close`; } /** * The name of the custom event fired just before the action. */ static get eventOnBeforeAction() { return `${prefix}-on-action`; } }; CDSInterstitialScreenFooter.styles = styles; __decorate([ property({ reflect: true }) ], CDSInterstitialScreenFooter.prototype, "nextButtonLabel", void 0); __decorate([ property({ reflect: true }) ], CDSInterstitialScreenFooter.prototype, "previousButtonLabel", void 0); __decorate([ property({ reflect: true }) ], CDSInterstitialScreenFooter.prototype, "skipButtonLabel", void 0); __decorate([ property({ reflect: true }) ], CDSInterstitialScreenFooter.prototype, "startButtonLabel", void 0); __decorate([ property({ reflect: true }) ], CDSInterstitialScreenFooter.prototype, "slot", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'async-action' }) ], CDSInterstitialScreenFooter.prototype, "asyncAction", void 0); __decorate([ state() ], CDSInterstitialScreenFooter.prototype, "loadingAction", void 0); CDSInterstitialScreenFooter = __decorate([ carbonElement(`${prefix}-interstitial-screen-footer`) ], CDSInterstitialScreenFooter); var CDSInterstitialScreenFooter$1 = CDSInterstitialScreenFooter; export { CDSInterstitialScreenFooter$1 as default }; //# sourceMappingURL=interstitial-screen-footer.js.map