Skip to content

Commit

Permalink
fix(core/ix-input/ix-number-input|ix-date-input): prevent overlapping…
Browse files Browse the repository at this point in the history
… of stepper-buttons and value (#1672)

Co-authored-by: Julian Lamplmair <151610373+jul-lam@users.noreply.github.com>
Co-authored-by: AndreasBerliner <41509230+AndreasBerliner@users.noreply.github.com>
Co-authored-by: Andreas Berliner <andreas.berliner@siemens.com>
Co-authored-by: jul-lam <julian.lamplmair.ext@siemens.com>
Co-authored-by: Lukas Maurer <lukas.maurer@siemens.com>
  • Loading branch information
6 people authored Feb 10, 2025
1 parent 3f5d0a4 commit 4558698
Show file tree
Hide file tree
Showing 22 changed files with 372 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/little-days-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siemens/ix': patch
---

Fix initial overlapping between value and end slots on `ix-input`, `ix-number-input` and `ix-date-input`
17 changes: 17 additions & 0 deletions packages/angular-test-app/src/preview-examples/input-types.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/*
* Styles get overwritten by html-test-app css files each build or dev task.
* If you want to modify the example styles do this only inside the html-test-app
*/

ix-input {
margin-bottom: 1rem;
width: 11rem;
}
5 changes: 3 additions & 2 deletions packages/angular-test-app/src/preview-examples/input-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Siemens AG
* SPDX-FileCopyrightText: 2025 Siemens AG
*
* SPDX-License-Identifier: MIT
*
Expand All @@ -11,6 +11,7 @@ import { Component } from '@angular/core';

@Component({
selector: 'app-example',
templateUrl: './input-types.html'
templateUrl: './input-types.html',
styleUrls: ['./input-types.css'],
})
export default class InputTypes {}
23 changes: 15 additions & 8 deletions packages/core/src/components/date-input/date-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import {
import { DateTime } from 'luxon';
import { dropdownController } from '../dropdown/dropdown-controller';
import { SlotEnd, SlotStart } from '../input/input.fc';
import { adjustPaddingForStartAndEnd } from '../input/input.util';
import {
DisposableChangesAndVisibilityObservers,
addDisposableChangesAndVisibilityObservers,
adjustPaddingForStartAndEnd,
} from '../input/input.util';
import {
ClassMutationObserver,
HookValidationLifecycle,
Expand Down Expand Up @@ -174,6 +178,8 @@ export class DateInput implements IxInputFieldComponent<string> {
private classObserver?: ClassMutationObserver;
private invalidReason?: string;

private disposableChangesAndVisibilityObservers?: DisposableChangesAndVisibilityObservers;

updateFormInternalValue(value: string): void {
this.formInternals.setFormValue(value);
this.value = value;
Expand All @@ -183,6 +189,12 @@ export class DateInput implements IxInputFieldComponent<string> {
this.classObserver = createClassMutationObserver(this.hostElement, () =>
this.checkClassList()
);

this.disposableChangesAndVisibilityObservers =
addDisposableChangesAndVisibilityObservers(
this.hostElement,
this.updatePaddings.bind(this)
);
}

componentWillLoad(): void {
Expand All @@ -197,10 +209,6 @@ export class DateInput implements IxInputFieldComponent<string> {
this.updateFormInternalValue(this.value);
}

componentDidRender(): void {
this.updatePaddings();
}

private updatePaddings() {
adjustPaddingForStartAndEnd(
this.slotStartRef.current,
Expand All @@ -210,9 +218,8 @@ export class DateInput implements IxInputFieldComponent<string> {
}

disconnectedCallback(): void {
if (this.classObserver) {
this.classObserver.destroy();
}
this.classObserver?.destroy();
this.disposableChangesAndVisibilityObservers?.();
}

@Watch('value')
Expand Down
16 changes: 14 additions & 2 deletions packages/core/src/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ import {
import { makeRef } from '../utils/make-ref';
import { InputElement, SlotEnd, SlotStart } from './input.fc';
import {
addDisposableChangesAndVisibilityObservers,
adjustPaddingForStartAndEnd,
checkAllowedKeys,
DisposableChangesAndVisibilityObservers,
getAriaAttributesForInput,
mapValidationResult,
onInputBlur,
Expand Down Expand Up @@ -174,6 +176,8 @@ export class Input implements IxInputFieldComponent<string> {

private readonly inputId = `input-${inputIds++}`;

private disposableChangesAndVisibilityObservers?: DisposableChangesAndVisibilityObservers;

@HookValidationLifecycle()
updateClassMappings(result: ValidationResults) {
mapValidationResult(this, result);
Expand All @@ -189,8 +193,12 @@ export class Input implements IxInputFieldComponent<string> {
this.inputType = this.type;
}

componentDidRender() {
this.updatePaddings();
connectedCallback(): void {
this.disposableChangesAndVisibilityObservers =
addDisposableChangesAndVisibilityObservers(
this.hostElement,
this.updatePaddings.bind(this)
);
}

private updatePaddings() {
Expand All @@ -201,6 +209,10 @@ export class Input implements IxInputFieldComponent<string> {
);
}

disconnectedCallback(): void {
this.disposableChangesAndVisibilityObservers?.();
}

updateFormInternalValue(value: string) {
this.formInternals.setFormValue(value);
this.value = value;
Expand Down
37 changes: 37 additions & 0 deletions packages/core/src/components/input/input.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ValidationResults,
shouldSuppressInternalValidation,
} from '../utils/input';
import { createMutationObserver } from '../utils/mutation-observer';
import { convertToRemString } from '../utils/rwd.util';
import { generateUUID } from '../utils/uuid';
import { shakeInput } from './input.animation';
Expand Down Expand Up @@ -152,3 +153,39 @@ export function getAriaAttributesForInput(
}
return inputAria;
}

export type DisposableChangesAndVisibilityObservers = () => void;

export const addDisposableChangesAndVisibilityObservers = (
element: HTMLElement,
callback: () => void
): DisposableChangesAndVisibilityObservers => {
const intersectionObserver = observeElementUntilVisible(element, callback);
const mutationObserver = createMutationObserver(callback);

mutationObserver.observe(element, {
subtree: true,
attributes: true,
});

return () => {
intersectionObserver.disconnect();
mutationObserver.disconnect();
};
};

function observeElementUntilVisible(
hostElement: HTMLElement,
updateCallback: () => void
): IntersectionObserver {
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
updateCallback();
}
});
});

intersectionObserver.observe(hostElement);
return intersectionObserver;
}
19 changes: 16 additions & 3 deletions packages/core/src/components/input/number-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {
Element,
Event,
EventEmitter,
h,
Host,
Method,
Prop,
State,
h,
} from '@stencil/core';
import {
HookValidationLifecycle,
Expand All @@ -28,9 +28,11 @@ import {
import { makeRef } from '../utils/make-ref';
import { InputElement, SlotEnd, SlotStart } from './input.fc';
import {
addDisposableChangesAndVisibilityObservers,
adjustPaddingForStartAndEnd,
checkAllowedKeys,
checkInternalValidity,
DisposableChangesAndVisibilityObservers,
mapValidationResult,
onInputBlur,
} from './input.util';
Expand Down Expand Up @@ -169,6 +171,8 @@ export class NumberInput implements IxInputFieldComponent<number> {
private readonly slotStartRef = makeRef<HTMLDivElement>();
private readonly numberInputId = `number-input-${numberInputIds++}`;

private disposableChangesAndVisibilityObservers?: DisposableChangesAndVisibilityObservers;

@HookValidationLifecycle()
updateClassMappings(result: ValidationResults) {
mapValidationResult(this, result);
Expand All @@ -178,8 +182,16 @@ export class NumberInput implements IxInputFieldComponent<number> {
this.updateFormInternalValue(this.value);
}

componentDidRender() {
this.updatePaddings();
connectedCallback() {
this.disposableChangesAndVisibilityObservers =
addDisposableChangesAndVisibilityObservers(
this.hostElement,
this.updatePaddings.bind(this)
);
}

disconnectedCallback() {
this.disposableChangesAndVisibilityObservers?.();
}

private updatePaddings() {
Expand Down Expand Up @@ -260,6 +272,7 @@ export class NumberInput implements IxInputFieldComponent<number> {
slotStartRef={this.slotStartRef}
onSlotChange={() => this.updatePaddings()}
></SlotStart>

<InputElement
id={this.numberInputId}
readonly={this.readonly}
Expand Down
41 changes: 41 additions & 0 deletions packages/core/src/tests/date-input/basic/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
SPDX-FileCopyrightText: 2025 Siemens AG
SPDX-License-Identifier: MIT
-->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"
/>
<title>Date Input Test</title>
<style>
.date-input-wrapper {
padding: 1rem;
}
</style>
</head>
<body>
<div class="date-input-wrapper">
<h4>Default</h4>
<ix-date-input></ix-date-input>

<h4>Disabled</h4>
<ix-date-input value='1970/01/01' disabled></ix-date-input>

<h4>Label</h4>
<ix-date-input
label='Begin'
name='begin'
helper-text='Some helper text'
value='1970/01/01'
></ix-date-input>

</div>
<script src="http://127.0.0.1:8080/scripts/e2e/load-e2e-runtime.js"></script>
</body>
</html>
18 changes: 18 additions & 0 deletions packages/core/src/tests/date-input/date-input.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2025 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { expect } from '@playwright/test';
import { regressionTest } from '@utils/test';

regressionTest.describe('date-input', () => {
regressionTest('basic', async ({ page }) => {
await page.goto('date-input/basic');
await expect(page).toHaveScreenshot();
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions packages/core/src/tests/input-common/dynamic/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!--
SPDX-FileCopyrightText: 2025 Siemens AG
SPDX-License-Identifier: MIT
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"
/>
<title>Common dynamic test for inputs</title>
<style>
.input-wrapper {
padding: 1rem;
}
.input-container {
display: none;
margin: 1rem;
}
.display-none {
display: none;
}
</style>
</head>
<body>
<div class="input-wrapper">
<ix-button onclick="displayInputs()">Display inputs</ix-button>
<div class="input-container" id="input-container">
<ix-input value="Lorem ipsum">
<ix-icon-button slot="start" icon="star" size="24"></ix-icon-button>
<ix-icon slot="end" name="info" class="display-none"></ix-icon>
</ix-input>
</div>
<div class="input-container" id="number-input-container">
<ix-number-input show-stepper-buttons value="0">
<ix-icon slot="end" name="info" class="display-none"></ix-icon>
</ix-number-input>
</div>
<div class="input-container" id="date-input-container">
<ix-date-input>
<ix-icon slot="end" name="info" class="display-none"></ix-icon>
</ix-date-input>
</div>
</div>

<script>
function displayInputs() {
const containers = document.getElementsByClassName('input-container');
for (const container of containers) {
container.style.display = 'block';
}
}
</script>
<script src="http://127.0.0.1:8080/scripts/e2e/load-e2e-runtime.js"></script>
</body>
</html>
Loading

0 comments on commit 4558698

Please sign in to comment.