diff --git a/.changeset/lemon-pants-act.md b/.changeset/lemon-pants-act.md new file mode 100644 index 0000000000..afc24a616b --- /dev/null +++ b/.changeset/lemon-pants-act.md @@ -0,0 +1,5 @@ +--- +"@siemens/ix": patch +--- + +fix(core/tree): handle text overflow gracefully diff --git a/packages/core/component-doc.json b/packages/core/component-doc.json index 8147aa03b4..f2c59fc719 100644 --- a/packages/core/component-doc.json +++ b/packages/core/component-doc.json @@ -16216,6 +16216,7 @@ "reflectToAttr": false, "docs": "Tree model", "docsTags": [], + "default": "{}", "values": [ { "type": "{ [x: string]: TreeItem; }" @@ -16264,7 +16265,7 @@ "type": "(index: number, data: T, dataList: T[], context: TreeContext, update: (callback: UpdateCallback) => void) => HTMLElement" } ], - "optional": false, + "optional": true, "required": false }, { @@ -16286,7 +16287,7 @@ } ], "optional": false, - "required": false + "required": true } ], "methods": [], @@ -16414,7 +16415,7 @@ "type": "TreeItemContext" } ], - "optional": false, + "optional": true, "required": false }, { @@ -16430,6 +16431,7 @@ "reflectToAttr": false, "docs": "Has tree item children", "docsTags": [], + "default": "false", "values": [ { "type": "boolean" @@ -16456,7 +16458,7 @@ "type": "string" } ], - "optional": false, + "optional": true, "required": false } ], diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index 485d8fbb64..84da58ff1a 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -2291,7 +2291,7 @@ export namespace Components { /** * Render function of tree items */ - "renderItem": ( + "renderItem"?: ( index: number, data: T, dataList: Array, @@ -2307,7 +2307,7 @@ export namespace Components { /** * Context */ - "context": TreeItemContext; + "context"?: TreeItemContext; /** * Has tree item children */ @@ -2315,7 +2315,7 @@ export namespace Components { /** * Text */ - "text": string; + "text"?: string; } /** * @since 2.0.0 @@ -6550,7 +6550,7 @@ declare namespace LocalJSX { /** * Initial root element will not be rendered */ - "root"?: string; + "root": string; } interface IxTreeItem { /** diff --git a/packages/core/src/components/tree-item/tree-item.scss b/packages/core/src/components/tree-item/tree-item.scss index f917ad4427..2cc962134e 100644 --- a/packages/core/src/components/tree-item/tree-item.scss +++ b/packages/core/src/components/tree-item/tree-item.scss @@ -23,11 +23,16 @@ cursor: pointer; .tree-node-container { + @include ellipsis; display: flex; align-items: center; height: $x-large-space; flex-grow: 1; align-items: center; + + .tree-node-text { + @include ellipsis; + } } .icon-toggle-container { @@ -36,6 +41,7 @@ justify-content: center; width: 2rem; height: 2rem; + min-width: 2rem; ix-icon { transition: transform var(--theme-default-time) ease-in-out; diff --git a/packages/core/src/components/tree-item/tree-item.tsx b/packages/core/src/components/tree-item/tree-item.tsx index d52838884e..883ebb20e4 100644 --- a/packages/core/src/components/tree-item/tree-item.tsx +++ b/packages/core/src/components/tree-item/tree-item.tsx @@ -19,33 +19,33 @@ export class TreeItem { /** * Text */ - @Prop() text: string; + @Prop() text?: string; /** * Has tree item children */ - @Prop() hasChildren: boolean; + @Prop() hasChildren = false; /** * Context */ - @Prop() context: TreeItemContext; + @Prop() context?: TreeItemContext; /** * Expand/Collapsed toggled */ - @Event() toggle: EventEmitter; + @Event() toggle!: EventEmitter; /** * Clicked */ - @Event() itemClick: EventEmitter; + @Event() itemClick!: EventEmitter; render() { return (
- {this.text} +
{this.text}
diff --git a/packages/core/src/components/tree/tree.tsx b/packages/core/src/components/tree/tree.tsx index 9875913c71..887c3b3c8b 100644 --- a/packages/core/src/components/tree/tree.tsx +++ b/packages/core/src/components/tree/tree.tsx @@ -39,17 +39,17 @@ export class Tree { /** * Initial root element will not be rendered */ - @Prop() root: string; + @Prop() root!: string; /** * Tree model */ - @Prop() model: TreeModel; + @Prop() model: TreeModel = {}; /** * Render function of tree items */ - @Prop() renderItem: ( + @Prop() renderItem?: ( index: number, data: T, dataList: Array, @@ -65,31 +65,31 @@ export class Tree { /** * Context changed */ - @Event() contextChange: EventEmitter; + @Event() contextChange!: EventEmitter; /** * Node toggled event * @since 1.5.0 */ - @Event() nodeToggled: EventEmitter<{ id: string; isExpaned: boolean }>; + @Event() nodeToggled!: EventEmitter<{ id: string; isExpaned: boolean }>; /** * Node clicked event * @since 1.5.0 */ - @Event() nodeClicked: EventEmitter; + @Event() nodeClicked!: EventEmitter; /** * Emits removed nodes */ - @Event() nodeRemoved: EventEmitter; + @Event() nodeRemoved!: EventEmitter; private hyperlist: Hyperlist; private toggleListener = new Map(); private itemClickListener = new Map(); private updates = new Map(); - private observer: MutationObserver; + private observer!: MutationObserver; private hasFirstRender = false; private updatePadding(element: HTMLElement, item: TreeItemVisual) { @@ -138,7 +138,10 @@ export class Tree { if (this.updates.has(item.id)) { const doUpdate = this.updates.get(item.id); - doUpdate(item, { ...this.context }); + + if (doUpdate) { + doUpdate(item, { ...this.context }); + } } this.updatePadding(renderedTreeItem, item); @@ -240,7 +243,7 @@ export class Tree { this.initList(); this.observer = new MutationObserver((records) => { - let removed = []; + let removed: unknown[] = []; records.forEach((record) => { removed = [...removed, ...Array.from(record.removedNodes)]; diff --git a/packages/core/src/tests/tree/overflow/index.html b/packages/core/src/tests/tree/overflow/index.html new file mode 100644 index 0000000000..37f902a207 --- /dev/null +++ b/packages/core/src/tests/tree/overflow/index.html @@ -0,0 +1,86 @@ + + + + + + + Stencil Component Starter + + +
+ +
+ + + + + diff --git a/packages/core/src/tests/tree/tree.e2e.ts b/packages/core/src/tests/tree/tree.e2e.ts index 21e0acbe16..f4d8128e9f 100644 --- a/packages/core/src/tests/tree/tree.e2e.ts +++ b/packages/core/src/tests/tree/tree.e2e.ts @@ -70,4 +70,23 @@ regressionTest.describe('tree', () => { expect(await page.screenshot({ fullPage: true })).toMatchSnapshot(); }); + + regressionTest('item overflow', async ({ page }) => { + await page.goto('tree/overflow'); + + page.setViewportSize({ width: 100, height: 100 }); + + const treeViewportHandle = await page.waitForSelector('ix-tree'); + + await page.evaluate((tree) => { + const model = tree.model; + + model['sample-child-1'].data.name = + 'This is a very long text that should overflow'; + + tree.model = { ...model }; + }, treeViewportHandle); + + expect(await page.screenshot({ fullPage: true })).toMatchSnapshot(); + }); }); diff --git a/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-dark-linux.png b/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-dark-linux.png new file mode 100644 index 0000000000..5cc1b611ce Binary files /dev/null and b/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-dark-linux.png differ diff --git a/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-light-linux.png b/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-light-linux.png new file mode 100644 index 0000000000..3ce9f29e70 Binary files /dev/null and b/packages/core/src/tests/tree/tree.e2e.ts-snapshots/tree-item-overflow-1-chromium---theme-classic-light-linux.png differ