+
diff --git a/packages/elements/src/item/__test__/item.test.js b/packages/elements/src/item/__test__/item.test.js
index fedc23e459..20914b85e5 100644
--- a/packages/elements/src/item/__test__/item.test.js
+++ b/packages/elements/src/item/__test__/item.test.js
@@ -1,4 +1,4 @@
-import { elementUpdated, expect, fixture, nextFrame } from '@refinitiv-ui/test-helpers';
+import { elementUpdated, expect, fixture } from '@refinitiv-ui/test-helpers';
// import element and theme
import '@refinitiv-ui/elements/item';
import '@refinitiv-ui/elemental-theme/light/ef-item';
@@ -17,6 +17,10 @@ const createFixture = (type = '') => {
return fixture('
Test Not Highlightable');
case 'is_truncated':
return fixture('
Super vary long string that need to be truncated by parent
');
+ case 'is_truncated_label':
+ return fixture('
');
+ case 'is_truncated_subLabel':
+ return fixture('
');
case 'with_icon':
return fixture('
With settings icon');
case 'with_empty_icon':
@@ -130,23 +134,27 @@ describe('item/Item', () => {
expect(el.highlightable).to.equal(false);
});
- it('Should truncate text', async () => {
+ it('Should truncate item text', async () => {
const div = await createFixture('is_truncated');
const el = div.querySelector('ef-item');
+ expect(el.isItemOverflown(), 'Should truncate text').to.equal(true);
+ });
- await elementUpdated(el);
- await nextFrame();
+ it('Should truncate label', async () => {
+ const div = await createFixture('is_truncated_label');
+ const el = div.querySelector('ef-item');
+ expect(el.isItemOverflown(), 'Should truncate text').to.equal(true);
+ });
- expect(el.isTruncated, 'Should truncate text').to.equal(true);
+ it('Should truncate subLabel', async () => {
+ const div = await createFixture('is_truncated_subLabel');
+ const el = div.querySelector('ef-item');
+ expect(el.isItemOverflown(), 'Should truncate text').to.equal(true);
});
- it('Should not truncate text', async () => {
+ it('Should not truncate item text', async () => {
const el = await createFixture();
-
- await elementUpdated(el);
- await nextFrame();
-
- expect(el.isTruncated, 'Should not truncate text').to.equal(false);
+ expect(el.isItemOverflown(), 'Should not truncate text').to.equal(false);
});
});
diff --git a/packages/elements/src/item/index.ts b/packages/elements/src/item/index.ts
index faa7de59ec..de340ed1a5 100644
--- a/packages/elements/src/item/index.ts
+++ b/packages/elements/src/item/index.ts
@@ -8,11 +8,12 @@ import {
} from '@refinitiv-ui/core';
import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js';
import { property } from '@refinitiv-ui/core/decorators/property.js';
-import { query } from '@refinitiv-ui/core/decorators/query.js';
import { VERSION } from '../version.js';
import '../icon/index.js';
import '../checkbox/index.js';
-
+import { registerOverflowTooltip } from '../tooltip/index.js';
+import { isElementOverflown } from '@refinitiv-ui/utils/element.js';
+import { createRef, ref, Ref } from '@refinitiv-ui/core/directives/ref.js';
import type { ItemType, ItemText, ItemHeader, ItemDivider, ItemData } from './helpers/types';
export type { ItemType, ItemText, ItemHeader, ItemDivider, ItemData };
@@ -126,10 +127,19 @@ export class Item extends ControlElement {
public for: string | null = null;
/**
- * Cache label element
+ * Reference to the label element
+ */
+ private labelRef: Ref
= createRef();
+
+ /**
+ * Reference to the subLabel element
+ */
+ private subLabelRef: Ref = createRef();
+
+ /**
+ * Reference to the slot element
*/
- @query('#label')
- private labelEl?: HTMLElement;
+ private slotRef: Ref = createRef();
/**
* True, if there is no slotted content
@@ -187,6 +197,16 @@ export class Item extends ControlElement {
}
}
+ /**
+ * Called after the component is first rendered
+ * @param changedProperties Properties which have changed
+ * @returns {void}
+ */
+ protected firstUpdated (changedProperties: PropertyValues): void {
+ super.firstUpdated(changedProperties);
+ registerOverflowTooltip(this, () => this.getItemContent(), () => this.isItemOverflown());
+ }
+
/**
* Invoked before update() to compute values needed during the update.
* @param changedProperties changed properties
@@ -204,6 +224,45 @@ export class Item extends ControlElement {
}
}
+
+ /**
+ * Get Item content
+ * @returns return item content from slot or label and sub-label
+ */
+ private getItemContent (): string {
+
+ if (this.isSlotEmpty) {
+ let text = '';
+ if (this.label) {
+ text += this.label;
+ }
+ if (this.subLabel) {
+ text += text ? ` (${this.subLabel})` : this.subLabel;
+ }
+ return text;
+ }
+ else {
+ return this.slotContent;
+ }
+ }
+
+ /**
+ * Get element overflown
+ * @param element Target element
+ * @returns return true if element is overflown.
+ */
+ private isItemElementOverflown (element?: HTMLElement): boolean {
+ return element ? isElementOverflown(element) : false;
+ }
+
+ /**
+ * Get item overflown
+ * @returns return true if an item is overflown.
+ */
+ private isItemOverflown (): boolean {
+ return this.isItemElementOverflown(this.labelRef.value) || this.isItemElementOverflown(this.subLabelRef.value);
+ }
+
/**
* Get icon template if icon attribute is defined
*/
@@ -215,14 +274,22 @@ export class Item extends ControlElement {
* Get subLabel template if it is defined and no slot content present
*/
private get subLabelTemplate (): TemplateResult | undefined {
- return this.subLabel && this.isSlotEmpty ? html`${this.subLabel}
` : undefined;
+ return html`${this.subLabel}
`;
}
/**
* Get label template if it is defined and no slot content present
*/
private get labelTemplate (): TemplateResult | undefined {
- return this.label && this.isSlotEmpty ? html`${this.label}` : undefined;
+ return html`${this.label}`;
+ }
+
+ /**
+ * Get slot content
+ */
+ private get slotContent (): string {
+ const nodes = this.slotRef.value?.assignedNodes() || [];
+ return nodes.map(node => node.textContent).join(' ').trim();
}
/**
@@ -251,15 +318,6 @@ export class Item extends ControlElement {
return !this.disabled && this.type !== 'header' && this.type !== 'divider';
}
- /**
- * Getter returning if the label is truncated
- * @prop {boolean} isTruncated
- * @returns whether element is truncated or not
- */
- public get isTruncated (): boolean {
- return !!(this.labelEl && (this.labelEl.offsetWidth < this.labelEl.scrollWidth));
- }
-
/**
* A `TemplateResult` that will be used
* to render the updated internal template.
@@ -272,10 +330,10 @@ export class Item extends ControlElement {
${this.multipleTemplate}