@carbon/ibm-products-web-components
Version:
Carbon for IBM Products Web Components
205 lines (203 loc) • 8.99 kB
JavaScript
/**
* Copyright IBM Corp. 2020, 2026
*
* 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 "../../globals/settings.js";
import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
import "../action-set/index.js";
import { registerFocusableContainers } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
import { interstitialDetailsSignal } from "./interstitial-screen-context.js";
import interstitial_screen_footer_default$1 from "./interstitial-screen-footer.scss.js";
import { html, nothing } from "lit";
import { property, state } from "lit/decorators.js";
import '@carbon/web-components/es-custom/components/button/index.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 { iconLoader } from "@carbon/web-components/es/globals/internal/icon-loader.js";
import { SignalWatcher } from "@lit-labs/signals";
import '@carbon/web-components/es-custom/components/inline-loading/inline-loading.js';
import CDSModalFooter from "@carbon/web-components/es/components/modal/modal-footer";
import ArrowRight from "@carbon/icons/es/arrow--right/16.js";
//#region src/components/interstitial-screen/interstitial-screen-footer.ts
/**
* @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 = `c4p--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(..._args) {
super(..._args);
this.nextButtonLabel = "Next";
this.previousButtonLabel = "Back";
this.skipButtonLabel = "Skip";
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) => {
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,
proceed: (allow) => {
Promise.resolve(allow).then(resolvePromise);
}
}
});
if (!this.dispatchEvent(customEvent)) 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 this._handleUserInitiatedClose?.(actionType);
}
};
}
firstUpdated(_changedProperties) {
registerFocusableContainers(this.childNodes.length > 0 ? this : this.shadowRoot);
}
updated(_changedProperties) {
if (_changedProperties.size === 0) this.updateComplete.then(() => {
const { stepDetails, currentStep } = interstitialDetailsSignal.get();
const isMultiStep = Array.isArray(stepDetails) && stepDetails.length > 0;
const lastStepIndex = stepDetails?.length - 1;
if (!isMultiStep) return;
const focusButton = (selector) => {
(this.shadowRoot?.querySelector(selector))?.focus();
};
if (currentStep === lastStepIndex) focusButton(`.c4p--interstitial-screen--start-btn`);
else if (currentStep === 0) focusButton(`.c4p--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?.length > 0;
const progStepCeil = stepDetails?.length - 1;
return html`<slot>
<div class="${blockClass}--footer">
<c4p-action-set size="xl">
${isMulti ? html`
<cds-custom-button
class="${blockClass}--skip-btn"
kind="ghost"
size="xl"
title="${this.skipButtonLabel}"
@click="${this.handleSkip}"
?disabled="${skip}"
>
${this.skipButtonLabel}
</cds-custom-button>
` : ""}
${isMulti && currentStep > 0 ? html`
<cds-custom-button
class="${blockClass}--prev-btn"
kind="secondary"
size="xl"
title="${this.previousButtonLabel}"
?disabled="${back}"
@click="${this.handleClickPrev}"
>
${this.previousButtonLabel}
${this.loadingAction === "back" ? html` <cds-custom-inline-loading slot="icon" aria-live="off">
</cds-custom-inline-loading>` : nothing}
</cds-custom-button>
` : nothing}
${isMulti && currentStep < progStepCeil ? html`
<cds-custom-button
class="${blockClass}--next-btn"
kind="primary"
size="xl"
title="${this.nextButtonLabel}"
?disabled="${next}"
@click="${this.handleClickNext}"
>
${this.nextButtonLabel}
${this.loadingAction === "next" ? html` <cds-custom-inline-loading slot="icon" aria-live="off">
</cds-custom-inline-loading>` : html`${iconLoader(ArrowRight, { slot: "icon" })}`}
</cds-custom-button>
` : nothing}
${isMulti && currentStep === progStepCeil || !isMulti ? html`
<cds-custom-button
class="${blockClass}--start-btn"
kind="primary"
size="xl"
title="${this.startButtonLabel}"
?disabled="${start}"
@click="${this.handleStart}"
>
${this.startButtonLabel}
${this.loadingAction === "start" ? html` <cds-custom-inline-loading slot="icon" aria-live="off">
</cds-custom-inline-loading>` : html`${iconLoader(ArrowRight, { slot: "icon" })}`}
</cds-custom-button>
` : nothing}
</c4p-action-set>
</div>
</slot>`;
}
static {
this.styles = interstitial_screen_footer_default$1;
}
static get eventRequestClose() {
return `c4p-request-close`;
}
/**
* The name of the custom event fired just before the action.
*/
static get eventOnBeforeAction() {
return `c4p-on-action`;
}
};
__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(`c4p-interstitial-screen-footer`)], CDSInterstitialScreenFooter);
var interstitial_screen_footer_default = CDSInterstitialScreenFooter;
//#endregion
export { interstitial_screen_footer_default as default };
//# sourceMappingURL=interstitial-screen-footer.js.map