@carbon/ibm-products-web-components
Version:
Carbon for IBM Products Web Components
169 lines (166 loc) • 6.22 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 page_header_actions_set_default$1 from "./page-header-actions-set.scss.js";
import { LitElement, html } from "lit";
import { property, query, state } from "lit/decorators.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 { repeat } from "lit/directives/repeat.js";
import "@carbon/web-components/es/components/overflow-menu/index.js";
import OverflowMenuVertical16 from "@carbon/icons/es/overflow-menu--vertical/16.js";
//#region src/components/page-header/page-header-actions-set/page-header-actions-set.ts
/**
* @license
*
* Copyright IBM Corp. 2025, 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.
*/
const blockClass = `c4p--page-header-actions-set`;
let CDSPageHeaderActionsSet = class CDSPageHeaderActionsSet extends LitElement {
constructor(..._args) {
super(..._args);
this.hiddenItems = [];
this.actionsData = [];
this.overflowAriaLabel = "More page actions";
this.isSetup = false;
this.lastContainerWidth = 0;
}
connectedCallback() {
super.connectedCallback();
this.style.visibility = "hidden";
}
firstUpdated() {
if (!this.container) return;
this.updateComplete.then(() => {
requestAnimationFrame(() => {
this.setupOverflowDetection();
this.isSetup = true;
this.style.visibility = "visible";
});
});
}
updated(changedProperties) {
if (this.isSetup && changedProperties.has("actionsData") && !changedProperties.has("hiddenItems")) this.updateComplete.then(() => {
requestAnimationFrame(() => this.setupOverflowDetection());
});
}
setupOverflowDetection() {
if (!this.itemsContainer) return;
this.resizeObserver?.disconnect();
const slot = this.shadowRoot?.querySelector("slot");
const checkOverflow = () => {
const slottedElements = slot?.assignedElements();
if (!slottedElements || slottedElements.length === 0) return;
const containerWidth = this.offsetWidth || this.itemsContainer.clientWidth;
const overflowMenuWidth = 48;
if (containerWidth === 0) return;
if (Math.abs(containerWidth - this.lastContainerWidth) < 5) return;
this.lastContainerWidth = containerWidth;
let totalWidth = 0;
for (let i = 0; i < slottedElements.length; i++) totalWidth += slottedElements[i].offsetWidth;
if (totalWidth <= containerWidth) {
slottedElements.forEach((el) => {
el.removeAttribute("data-hidden");
});
this.hiddenItems = [];
return;
}
totalWidth = 0;
let visibleCount = 0;
for (let i = 0; i < slottedElements.length; i++) {
const itemWidth = slottedElements[i].offsetWidth;
if (totalWidth + itemWidth + overflowMenuWidth <= containerWidth) {
totalWidth += itemWidth;
visibleCount = i + 1;
} else break;
}
slottedElements.forEach((el, index) => {
if (index >= visibleCount) el.setAttribute("data-hidden", "");
else el.removeAttribute("data-hidden");
});
this.hiddenItems = this.actionsData?.slice(visibleCount) || [];
};
checkOverflow();
this.resizeObserver = new ResizeObserver(() => {
if (this.resizeTimeout) clearTimeout(this.resizeTimeout);
this.resizeTimeout = window.setTimeout(() => {
checkOverflow();
}, 100);
});
this.resizeObserver.observe(this);
this.resizeObserver.observe(this.itemsContainer);
}
disconnectedCallback() {
super.disconnectedCallback();
this.resizeObserver?.disconnect();
if (this.resizeTimeout) clearTimeout(this.resizeTimeout);
}
handleOverflowItemClick(index) {
const button = ((this.shadowRoot?.querySelector("slot"))?.assignedElements())[this.actionsData.length - this.hiddenItems.length + index];
if (button) button.click();
}
render() {
return html`
<ul class="${blockClass}">
<li class="${blockClass}__items">
<slot></slot>
</li>
<li data-offset ?data-hidden=${this.hiddenItems.length === 0}>
<cds-overflow-menu
size="md"
close-on-activation
enter-delay-ms="0"
leave-delay-ms="0"
align="left"
data-floating-menu-container
aria-label="${this.overflowAriaLabel}"
>
${iconLoader(OverflowMenuVertical16, {
class: `${blockClass}__overflow-svg`,
slot: "icon"
})}
<span slot="tooltip-content">More actions</span>
<cds-overflow-menu-body flipped>
${repeat(this.hiddenItems ?? [], (_item, index) => index, (item, index) => html`
<cds-overflow-menu-item
@click="${() => this.handleOverflowItemClick(index)}"
>
${item.label}
</cds-overflow-menu-item>
`)}
</cds-overflow-menu-body>
</cds-overflow-menu>
</li>
</ul>
`;
}
static {
this.styles = page_header_actions_set_default$1;
}
};
__decorate([state()], CDSPageHeaderActionsSet.prototype, "hiddenItems", void 0);
__decorate([property({
type: Array,
attribute: "actions-data",
reflect: true
})], CDSPageHeaderActionsSet.prototype, "actionsData", void 0);
__decorate([property({
type: String,
attribute: "overflow-aria-label",
reflect: true
})], CDSPageHeaderActionsSet.prototype, "overflowAriaLabel", void 0);
__decorate([query(`.${blockClass}`)], CDSPageHeaderActionsSet.prototype, "container", void 0);
__decorate([query(`.${blockClass}__items`)], CDSPageHeaderActionsSet.prototype, "itemsContainer", void 0);
CDSPageHeaderActionsSet = __decorate([carbonElement(`c4p-page-header-actions-set`)], CDSPageHeaderActionsSet);
var page_header_actions_set_default = CDSPageHeaderActionsSet;
//#endregion
export { page_header_actions_set_default as default };
//# sourceMappingURL=page-header-actions-set.js.map