Skip to content

Commit 699958d

Browse files
ridvandmrcDemircidaniellerouxmatthiashadernuke-ellington
authored
fix(core/drawer|input-group): prevent layout issues in nested content of ix-drawer (#1561)
Co-authored-by: Demirci <ridvan.demirci@siemens.com> Co-authored-by: Daniel Leroux <daniel.leroux@siemens.com> Co-authored-by: matthias <matthias.hader.ext@siemens.com> Co-authored-by: matthiashader <144090716+matthiashader@users.noreply.github.com> Co-authored-by: Lukas Maurer <lukas.maurer@siemens.com>
1 parent 01780cb commit 699958d

15 files changed

+284
-67
lines changed

.changeset/proud-waves-care.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@siemens/ix': patch
3+
---
4+
5+
Update slot references for **ix-input-group**.

.changeset/tame-deers-kick.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@siemens/ix': patch
3+
---
4+
5+
**ix-drawer**: Allow nested content to calculate it's layout properly by setting drawer width explicitly.

packages/core/component-doc.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -10879,11 +10879,17 @@
1087910879
"overview": "",
1088010880
"usage": {},
1088110881
"docs": "",
10882-
"docsTags": [],
10882+
"docsTags": [
10883+
{
10884+
"name": "deprecated",
10885+
"text": "since 3.0.0. Will be removed with 4.0.0.\nUse the 'ix-input' component instead"
10886+
}
10887+
],
1088310888
"encapsulation": "shadow",
1088410889
"dependents": [],
1088510890
"dependencies": [],
1088610891
"dependencyGraph": {},
10892+
"deprecation": "since 3.0.0. Will be removed with 4.0.0.\nUse the 'ix-input' component instead",
1088710893
"props": [],
1088810894
"methods": [],
1088910895
"events": [],

packages/core/src/components.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,10 @@ export namespace Components {
16561656
*/
16571657
"warningText"?: string;
16581658
}
1659+
/**
1660+
* @deprecated since 3.0.0. Will be removed with 4.0.0.
1661+
* Use the 'ix-input' component instead
1662+
*/
16591663
interface IxInputGroup {
16601664
}
16611665
/**
@@ -4220,6 +4224,10 @@ declare global {
42204224
prototype: HTMLIxInputElement;
42214225
new (): HTMLIxInputElement;
42224226
};
4227+
/**
4228+
* @deprecated since 3.0.0. Will be removed with 4.0.0.
4229+
* Use the 'ix-input' component instead
4230+
*/
42234231
interface HTMLIxInputGroupElement extends Components.IxInputGroup, HTMLStencilElement {
42244232
}
42254233
var HTMLIxInputGroupElement: {
@@ -6887,6 +6895,10 @@ declare namespace LocalJSX {
68876895
*/
68886896
"warningText"?: string;
68896897
}
6898+
/**
6899+
* @deprecated since 3.0.0. Will be removed with 4.0.0.
6900+
* Use the 'ix-input' component instead
6901+
*/
68906902
interface IxInputGroup {
68916903
}
68926904
/**
@@ -8880,6 +8892,10 @@ declare module "@stencil/core" {
88808892
* @form-ready 2.6.0
88818893
*/
88828894
"ix-input": LocalJSX.IxInput & JSXBase.HTMLAttributes<HTMLIxInputElement>;
8895+
/**
8896+
* @deprecated since 3.0.0. Will be removed with 4.0.0.
8897+
* Use the 'ix-input' component instead
8898+
*/
88838899
"ix-input-group": LocalJSX.IxInputGroup & JSXBase.HTMLAttributes<HTMLIxInputGroupElement>;
88848900
/**
88858901
* @since 1.6.0

packages/core/src/components/drawer/drawer.scss

+6-3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
right: 0;
1818
@include box-shadow(3);
1919

20-
display: flex;
20+
display: block;
2121
position: absolute;
22-
flex-flow: column nowrap;
2322
justify-content: flex-start;
2423
align-items: center;
24+
opacity: 0;
2525

2626
max-height: 100vh;
2727
min-height: $large-space;
@@ -52,10 +52,13 @@
5252
.content {
5353
position: relative;
5454
flex: 1;
55-
flex-grow: 1;
5655
order: 2;
5756
height: 100%;
5857
width: 100%;
5958
overflow-y: auto;
6059
}
6160
}
61+
62+
:host(.display-none) {
63+
display: none;
64+
}

packages/core/src/components/drawer/drawer.tsx

+79-50
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
Host,
1616
Method,
1717
Prop,
18+
State,
1819
Watch,
1920
} from '@stencil/core';
2021
import anime from 'animejs';
@@ -71,6 +72,8 @@ export class Drawer {
7172
private callback = this.clickedOutside.bind(this);
7273
private divElement?: HTMLElement;
7374

75+
@State() showContent = true;
76+
7477
@Watch('show')
7578
onShowChanged(newValue: boolean, oldValue?: boolean) {
7679
if (newValue === oldValue) {
@@ -96,14 +99,12 @@ export class Drawer {
9699
}
97100

98101
this.show = true;
99-
100-
if (!this.toggle) {
102+
if (!this.toggle && this.divElement) {
101103
this.slideInRight(this.divElement);
104+
setTimeout(() => {
105+
window.addEventListener('mousedown', this.callback);
106+
}, Drawer.duration);
102107
}
103-
104-
setTimeout(() => {
105-
window.addEventListener('mousedown', this.callback);
106-
}, 300);
107108
} else {
108109
const { defaultPrevented } = this.drawerClose.emit();
109110

@@ -113,7 +114,7 @@ export class Drawer {
113114

114115
this.show = false;
115116

116-
if (this.toggle) {
117+
if (this.toggle && this.divElement) {
117118
this.slideOutRight(this.divElement);
118119
}
119120

@@ -147,34 +148,45 @@ export class Drawer {
147148
}
148149
}
149150

150-
private slideOutRight(el?: HTMLElement) {
151-
if (el) {
152-
anime({
153-
targets: el,
154-
duration: Drawer.duration,
155-
translateX: [0, '16rem'],
156-
opacity: [1, 0],
157-
easing: 'easeInSine',
158-
complete: () => {
159-
el.classList.add('d-none');
160-
},
161-
});
162-
}
151+
private getConstrainedWidth(width: number) {
152+
return Math.min(Math.max(width, this.minWidth), this.maxWidth);
163153
}
164154

165-
private slideInRight(el?: HTMLElement) {
166-
if (el) {
167-
anime({
168-
targets: el,
169-
duration: Drawer.duration,
170-
translateX: ['16rem', 0],
171-
opacity: [0, 1],
172-
easing: 'easeOutSine',
173-
begin: () => {
174-
el.classList.remove('d-none');
175-
},
176-
});
177-
}
155+
private slideOutRight(el: HTMLElement) {
156+
const initialWidth = `${this.getConstrainedWidth(
157+
this.width === 'auto' ? this.minWidth : this.width
158+
)}rem`;
159+
160+
anime({
161+
targets: el,
162+
duration: Drawer.duration,
163+
width: [initialWidth, 0],
164+
opacity: [1, 0],
165+
easing: 'easeInSine',
166+
complete: () => {
167+
el.classList.add('display-none');
168+
},
169+
});
170+
}
171+
172+
private slideInRight(el: HTMLElement) {
173+
const targetWidth = `${this.getConstrainedWidth(
174+
this.width === 'auto' ? this.minWidth : this.width
175+
)}rem`;
176+
177+
anime({
178+
targets: el,
179+
duration: Drawer.duration,
180+
width: [0, targetWidth],
181+
opacity: [0, 1],
182+
easing: 'easeOutSine',
183+
begin: () => {
184+
el.classList.remove('display-none');
185+
},
186+
complete: () => {
187+
this.showContent = true;
188+
},
189+
});
178190
}
179191

180192
componentDidLoad() {
@@ -186,33 +198,50 @@ export class Drawer {
186198
<Host
187199
class={{
188200
'drawer-container': true,
189-
'd-none': true,
201+
'display-none': true,
190202
}}
191203
style={{
192-
width: this.width === 'auto' ? this.width : `${this.width}rem`,
193-
'min-width': `${this.minWidth}rem`,
204+
width: '0',
194205
'max-width': `${this.maxWidth}rem`,
195206
height: this.fullHeight ? '100%' : 'auto',
207+
overflow: 'hidden',
196208
}}
197209
ref={(el) => (this.divElement = el as HTMLElement)}
198210
data-testid="container"
199211
id="div-container"
200212
>
201-
<div class="header">
202-
<div class="header-content">
203-
<slot name="header"></slot>
213+
<div
214+
style={{
215+
width:
216+
this.width === 'auto'
217+
? 'auto'
218+
: `${this.getConstrainedWidth(this.width)}rem`,
219+
}}
220+
>
221+
<div class="header">
222+
<div class="header-content">
223+
<slot name="header"></slot>
224+
</div>
225+
<ix-icon-button
226+
class="close-button"
227+
style={{
228+
display: this.showContent ? 'block' : 'none',
229+
}}
230+
icon={'close'}
231+
size="24"
232+
ghost
233+
onClick={() => this.onCloseClicked()}
234+
data-testid="close-button"
235+
></ix-icon-button>
236+
</div>
237+
<div
238+
class="content"
239+
style={{
240+
display: this.showContent ? 'block' : 'none',
241+
}}
242+
>
243+
<slot></slot>
204244
</div>
205-
<ix-icon-button
206-
class="close-button"
207-
icon={'close'}
208-
size="24"
209-
ghost
210-
onClick={() => this.onCloseClicked()}
211-
data-testid="close-button"
212-
></ix-icon-button>
213-
</div>
214-
<div class="content">
215-
<slot></slot>
216245
</div>
217246
</Host>
218247
);

packages/core/src/components/input-group/input-group.tsx

+18-13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
import { Component, Element, h, Host, State } from '@stencil/core';
1111
import { getSlottedElements } from '../utils/shadow-dom';
1212

13+
/**
14+
* @deprecated since 3.0.0. Will be removed with 4.0.0.
15+
* Use the 'ix-input' component instead
16+
*/
1317
@Component({
1418
tag: 'ix-input-group',
1519
styleUrl: 'input-group.scss',
@@ -23,6 +27,9 @@ export class InputGroup {
2327
@State() inputPaddingLeft = 0;
2428
@State() inputPaddingRight = 0;
2529

30+
startSlotRef?: HTMLElement;
31+
endSlotRef?: HTMLElement;
32+
2633
private get inputElement() {
2734
return this.hostElement.querySelector('input') as HTMLInputElement;
2835
}
@@ -100,12 +107,8 @@ export class InputGroup {
100107
}
101108

102109
private startSlotChanged() {
103-
const slot = this.hostElement.shadowRoot!.querySelector(
104-
'slot[name="input-start"]'
105-
)!;
106-
107110
setTimeout(() => {
108-
const startPadding = this.getChildrenWidth(slot);
111+
const startPadding = this.getChildrenWidth(this.startSlotRef);
109112

110113
if (startPadding !== 0) {
111114
this.inputPaddingLeft = 11 + startPadding;
@@ -134,16 +137,12 @@ export class InputGroup {
134137
}
135138

136139
private endSlotChanged() {
137-
const slot = this.hostElement.shadowRoot!.querySelector(
138-
'slot[name="input-end"]'
139-
)!;
140-
141140
setTimeout(() => {
142-
this.inputPaddingRight = 15 + this.getChildrenWidth(slot);
141+
this.inputPaddingRight = 15 + this.getChildrenWidth(this.endSlotRef);
143142
});
144143
}
145144

146-
private getChildrenWidth(slotElement: Element) {
145+
private getChildrenWidth(slotElement: Element | undefined) {
147146
if (!slotElement) {
148147
return 0;
149148
}
@@ -166,11 +165,17 @@ export class InputGroup {
166165
return (
167166
<Host class={{ disabled: this.disabled }}>
168167
<div class="group group-start">
169-
<slot name="input-start"></slot>
168+
<slot
169+
ref={(el) => (this.startSlotRef = el as HTMLElement)}
170+
name="input-start"
171+
></slot>
170172
</div>
171173
<slot></slot>
172174
<div class="group group-end">
173-
<slot name="input-end"></slot>
175+
<slot
176+
ref={(el) => (this.endSlotRef = el as HTMLElement)}
177+
name="input-end"
178+
></slot>
174179
</div>
175180
</Host>
176181
);

packages/core/src/tests/drawer/drawer.e2e.ts

+14
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,18 @@ regressionTest.describe('drawer', () => {
2424
await page.waitForTimeout(2000);
2525
expect(await page.screenshot()).toMatchSnapshot();
2626
});
27+
28+
regressionTest('input-group', async ({ page }) => {
29+
await page.goto('drawer/input-group');
30+
await page.locator('ix-button').click();
31+
await page.waitForSelector('ix-drawer[style*="opacity: 1;"]');
32+
expect(await page.screenshot({ animations: 'disabled' })).toMatchSnapshot();
33+
});
34+
35+
regressionTest('inside container', async ({ page }) => {
36+
await page.goto('drawer/inside-container');
37+
await page.locator('ix-button').click();
38+
await page.waitForSelector('ix-drawer[style*="opacity: 1;"]');
39+
expect(await page.screenshot({ animations: 'disabled' })).toMatchSnapshot();
40+
});
2741
});

0 commit comments

Comments
 (0)