Skip to content

Commit

Permalink
fix(sbb-form-field): update floating label on programmatic changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Dec 5, 2024
1 parent 39e531e commit b959191
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 9 deletions.
9 changes: 1 addition & 8 deletions src/elements/form-field/form-field/form-field.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,14 +433,7 @@ describe(`sbb-form-field`, () => {
input.value = '';
await waitForLitRender(element);

// Then empty state is not updated
expect(element).not.to.have.attribute('data-input-empty');

// When manually calling reset method
element.reset();
await waitForLitRender(element);

// Then empty state should be updated
// Then the empty state is updated
expect(element).to.have.attribute('data-input-empty');
});
});
Expand Down
46 changes: 45 additions & 1 deletion src/elements/form-field/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,44 @@ let nextFormFieldErrorId = 0;

const supportedPopupTagNames = ['sbb-autocomplete', 'sbb-autocomplete-grid', 'sbb-select'];

interface PatchedInputElement extends HTMLInputElement {
// eslint-disable-next-line @typescript-eslint/naming-convention
_originalValueDescriptor?: PropertyDescriptor;
}

function patchInputValue(inputElement: PatchedInputElement, callback: (value: any) => void): void {
// Speichern der ursprünglichen Getter und Setter
const originalDescriptor = Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(inputElement),
'value',
);
const originalGetter = originalDescriptor!.get!;
const originalSetter = originalDescriptor!.set!;

inputElement._originalValueDescriptor = originalDescriptor;

// Neue Getter und Setter definieren
Object.defineProperty(inputElement, 'value', {
get() {
return originalGetter.call(this);
},
set(newValue) {
originalSetter.call(this, newValue);
callback(newValue);
},
configurable: true,
enumerable: true,
});
}

function unpatchInputValue(inputElement: PatchedInputElement): void {
const originalDescriptor = inputElement._originalValueDescriptor;
if (originalDescriptor) {
Object.defineProperty(inputElement, 'value', originalDescriptor);
delete inputElement._originalValueDescriptor;
}
}

/**
* It wraps an input element adding label, errors, icon, etc.
*
Expand Down Expand Up @@ -155,6 +193,9 @@ class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitElement)
super.disconnectedCallback();
this._formFieldAttributeObserver?.disconnect();
this._inputAbortController.abort();
if (this._input?.localName === 'input') {
unpatchInputValue(this._input as HTMLInputElement);
}
}

private _onPopupOpen({ target }: CustomEvent<void>): void {
Expand Down Expand Up @@ -285,7 +326,10 @@ class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitElement)

let inputFocusElement = this._input;

if (this._input.localName === 'sbb-select') {
if (this._input.localName === 'input') {
// Patch value of HTMLInputElement in order to update floating label
patchInputValue(this._input as HTMLInputElement, () => this.reset());
} else if (this._input.localName === 'sbb-select') {
this._input.addEventListener('stateChange', () => this._checkAndUpdateInputEmpty(), {
signal: this._inputAbortController.signal,
});
Expand Down

0 comments on commit b959191

Please sign in to comment.