UNPKG

@carbon/ibm-products-web-components

Version:
221 lines (219 loc) 7.41 kB
/** * 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 truncated_text_default$1 from "./truncated-text.scss.js"; import { classMap } from "lit/directives/class-map.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 { styleMap } from "lit/directives/style-map.js"; import '@carbon/web-components/es-custom/components/tooltip/index.js'; import '@carbon/web-components/es-custom/components/button/button.js'; import '@carbon/web-components/es-custom/components/link/index.js'; //#region src/components/truncated-text/truncated-text.ts /** * @license * * Copyright IBM Corp. 2025, 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 componentName = "truncated-text"; const blockClass = `c4p--${componentName}`; const elementName = `c4p-${componentName}`; let CDSTruncatedText = class CDSTruncatedText extends LitElement { constructor(..._args) { super(..._args); this.align = "top"; this.autoalign = false; this.collapseLabel = ""; this.expandLabel = ""; this.id = ""; this.lines = 0; this.type = "tooltip"; this.value = ""; this._isOverflowing = false; this._isExpanded = false; this._maxHeight = "none"; this._lineHeight = 0; this._isLayered = false; } static { this.styles = truncated_text_default$1; } connectedCallback() { super.connectedCallback(); this._isLayered = !!this.closest(`cds-custom-layer`); this.type = this.type || "tooltip"; } disconnectedCallback() { this._resizeObserver?.disconnect(); super.disconnectedCallback(); } firstUpdated() { requestAnimationFrame(() => { const computedStyle = getComputedStyle(this._textElement); this._lineHeight = parseFloat(computedStyle.lineHeight); this._setupResizeObserver(); }); } updated(changed) { if (changed.has("lines") || changed.has("value")) { this._updateOverflowStatus(); this._updateMaxHeight(); } } _updateMaxHeight() { if (this.type !== "expand") return; requestAnimationFrame(() => { if (!this._textElement) return; this._maxHeight = this.lines > 0 && !this._isExpanded ? `${this.lines * this._lineHeight}px` : `${this._textElement.scrollHeight}px`; }); } _setupResizeObserver() { if (!this._textElement) return; if (this._resizeObserver) this._resizeObserver.disconnect(); this._resizeObserver = new ResizeObserver(() => { this._updateOverflowStatus(); }); this._resizeObserver.observe(this); } _updateOverflowStatus() { if (!this._textElement || this.lines <= 0) return; this._updateMaxHeight(); const { scrollHeight, clientHeight } = this._textElement; const isOverflowing = scrollHeight > clientHeight + this._lineHeight / 2; if (isOverflowing !== this._isOverflowing) this._isOverflowing = isOverflowing; } _handleKeydown(evt) { const { key } = evt; if (key === "Enter" || key === " ") this._toggleExpansion(); } _toggleExpansion() { this._isExpanded = !this._isExpanded; this._updateMaxHeight(); this._textElement?.classList.add(`${blockClass}_transition`); const onTransitionEnd = () => { this._textElement?.querySelector("button")?.focus(); this._textElement?.removeEventListener("transitionend", onTransitionEnd); }; this._textElement?.addEventListener("transitionend", onTransitionEnd); /** * currently you cannot animate line-clamping * you can however animate max-height * this removes the clamping and then quickly adds it so you can see the ellipsis */ if (this._isExpanded === false) { this._textElement?.classList.add(`${blockClass}_content--closing`); setTimeout(() => { this._textElement?.classList.remove(`${blockClass}_content--closing`); }, 100); } } _renderToggleButton() { const className = classMap({ [`${blockClass}_button-collapse`]: this._isExpanded, [`${blockClass}_button-expand`]: !this._isExpanded, [`${blockClass}_button-layered`]: this._isLayered, [`${blockClass}_button-hide`]: !this._isOverflowing && !this._isExpanded }); const label = this._isExpanded ? this.collapseLabel : this.expandLabel; return html` <span aria-controls=${this.id} aria-expanded=${this._isExpanded} class=${className} @click=${this._toggleExpansion} @keydown=${this._handleKeydown} role="button" tabIndex="0" > ${label} </span> `; } render() { const contentStyle = { ["--line-clamp"]: this._isExpanded ? "none" : this.lines, ["max-block-size"]: this.type === "expand" ? this._maxHeight : "none" }; const valueBody = html` <div id=${this.id} class="${blockClass}_content" style=${styleMap(contentStyle)} > ${this.value} </div> `; const tooltipVariant = this._isOverflowing ? html` <cds-custom-tooltip align=${this.align} autoalign=${this.autoalign} enter-delay-ms="0" leave-delay-ms="0" > <button type="button" class="${blockClass}_tooltip-trigger" aria-label=${this.value} > ${valueBody} </button> <cds-custom-tooltip-content>${this.value}</cds-custom-tooltip-content> </cds-custom-tooltip> ` : valueBody; const expandVariant = html`${valueBody} ${this._renderToggleButton()}`; return this.type === "tooltip" && this._isOverflowing ? tooltipVariant : expandVariant; } }; __decorate([property({ reflect: true, type: String })], CDSTruncatedText.prototype, "align", void 0); __decorate([property({ type: Boolean, reflect: true })], CDSTruncatedText.prototype, "autoalign", void 0); __decorate([property({ attribute: "collapse-label", type: String, reflect: true })], CDSTruncatedText.prototype, "collapseLabel", void 0); __decorate([property({ attribute: "expand-label", type: String, reflect: true })], CDSTruncatedText.prototype, "expandLabel", void 0); __decorate([property({ type: String, reflect: true })], CDSTruncatedText.prototype, "id", void 0); __decorate([property({ type: Number, reflect: true })], CDSTruncatedText.prototype, "lines", void 0); __decorate([property({ type: String, reflect: true })], CDSTruncatedText.prototype, "type", void 0); __decorate([property({ type: String, attribute: "value", reflect: true })], CDSTruncatedText.prototype, "value", void 0); __decorate([state()], CDSTruncatedText.prototype, "_isOverflowing", void 0); __decorate([state()], CDSTruncatedText.prototype, "_isExpanded", void 0); __decorate([state()], CDSTruncatedText.prototype, "_maxHeight", void 0); __decorate([query(`.${blockClass}_content`)], CDSTruncatedText.prototype, "_textElement", void 0); CDSTruncatedText = __decorate([carbonElement(elementName)], CDSTruncatedText); var truncated_text_default = CDSTruncatedText; //#endregion export { CDSTruncatedText, blockClass, truncated_text_default as default }; //# sourceMappingURL=truncated-text.js.map