Skip to content

Commit

Permalink
fix(sbb-select): handle properties change (#3334)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavideMininni-Fincons authored Jan 8, 2025
1 parent ec5bdfe commit 6ad135e
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/elements/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ class SbbAccordionElement extends SbbHydrationMixin(LitElement) {
* The heading level for the sbb-expansion-panel-headers within the component.
* @controls SbbExpansionPanelElement.titleLevel
*/
@handleDistinctChange((e) => e._setTitleLevelOnChildren())
@handleDistinctChange((e: SbbAccordionElement) => e._setTitleLevelOnChildren())
@property({ attribute: 'title-level' })
public accessor titleLevel: SbbTitleLevel | null = null;

/** Whether more than one sbb-expansion-panel can be open at the same time. */
@forceType()
@handleDistinctChange((e, newValue, oldValue) => e._resetExpansionPanels(newValue, !!oldValue))
@handleDistinctChange(
(e: SbbAccordionElement, newValue: boolean, oldValue: boolean | undefined) =>
e._resetExpansionPanels(newValue, !!oldValue),
)
@property({ type: Boolean })
public accessor multi: boolean = false;

Expand Down
2 changes: 1 addition & 1 deletion src/elements/core/mixins/disabled-mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const SbbDisabledMixin = <T extends AbstractConstructor<LitElement>>(
/** Whether the component is disabled. */
@forceType()
@property({ reflect: true, type: Boolean })
@getOverride((e, v) => v || e.isDisabledExternally())
@getOverride((e: SbbDisabledElement, v: boolean): boolean => v || e.isDisabledExternally())
public accessor disabled: boolean = false;

/**
Expand Down
63 changes: 63 additions & 0 deletions src/elements/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,69 @@ describe(`sbb-select`, () => {
expect(comboBoxElement).to.have.attribute('aria-expanded', 'true');
});

it('update multiple attribute', async () => {
const didOpen = new EventSpy(SbbSelectElement.events.didOpen, element);
element.dispatchEvent(new CustomEvent('click'));
await didOpen.calledOnce();
expect(didOpen.count).to.be.equal(1);
await waitForLitRender(element);

expect(element.value).to.be.equal(null);
element.toggleAttribute('multiple', true);
await waitForLitRender(element);
expect(element.value).to.be.eql([]);
element.toggleAttribute('multiple', false);
await waitForLitRender(element);
expect(element.value).to.be.equal(null);

firstOption.dispatchEvent(new CustomEvent('click'));
await waitForLitRender(element);
expect(element.value).to.be.eql('1');
element.toggleAttribute('multiple', true);
await waitForLitRender(element);
expect(element.value).to.be.eql(['1']);

firstOption.dispatchEvent(new CustomEvent('click'));
thirdOption.dispatchEvent(new CustomEvent('click'));
secondOption.dispatchEvent(new CustomEvent('click'));
await waitForLitRender(element);

expect(element.value).to.be.eql(['3', '2']);
element.toggleAttribute('multiple', false);
await waitForLitRender(element);
expect(element.value).to.be.eql('3');
});

it('close the panel if disabled', async () => {
const didOpen = new EventSpy(SbbSelectElement.events.didOpen, element);
const didClose = new EventSpy(SbbSelectElement.events.didClose, element);
element.dispatchEvent(new CustomEvent('click'));
await didOpen.calledOnce();
expect(didOpen.count).to.be.equal(1);
await waitForLitRender(element);

element.toggleAttribute('disabled', true);
await waitForLitRender(element);

await didClose.calledOnce();
expect(didClose.count).to.be.equal(1);
});

it('close the panel if readonly', async () => {
const didOpen = new EventSpy(SbbSelectElement.events.didOpen, element);
const didClose = new EventSpy(SbbSelectElement.events.didClose, element);
element.dispatchEvent(new CustomEvent('click'));
await didOpen.calledOnce();
expect(didOpen.count).to.be.equal(1);
await waitForLitRender(element);

element.toggleAttribute('readonly', true);
await waitForLitRender(element);

await didClose.calledOnce();
expect(didClose.count).to.be.equal(1);
});

it('handles keypress on host', async () => {
const didOpen = new EventSpy(SbbSelectElement.events.didOpen, element);
const didClose = new EventSpy(SbbSelectElement.events.didClose, element);
Expand Down
45 changes: 44 additions & 1 deletion src/elements/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import { until } from 'lit/directives/until.js';
import { getNextElementIndex } from '../core/a11y.js';
import { SbbOpenCloseBaseElement } from '../core/base-elements.js';
import { SbbLanguageController } from '../core/controllers.js';
import { forceType, hostAttributes } from '../core/decorators.js';
import {
forceType,
getOverride,
handleDistinctChange,
hostAttributes,
} from '../core/decorators.js';
import { isNextjs, isSafari, isZeroAnimationDuration, setOrRemoveAttribute } from '../core/dom.js';
import { EventEmitter } from '../core/eventing.js';
import {
Expand Down Expand Up @@ -92,11 +97,23 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(

/** Whether the select allows for multiple selection. */
@forceType()
@handleDistinctChange((e: SbbSelectElement, newValue: boolean) => e._onMultipleChanged(newValue))
@property({ reflect: true, type: Boolean })
public accessor multiple: boolean = false;

@forceType()
@handleDistinctChange((e: SbbSelectElement, newValue: boolean) =>
e._closeOnDisabledReadonlyChanged(newValue),
)
@property({ reflect: true, type: Boolean })
@getOverride((e: SbbSelectElement, v: boolean): boolean => v || e.isDisabledExternally())
public override accessor disabled: boolean = false;

/** Whether the select is readonly. */
@forceType()
@handleDistinctChange((e: SbbSelectElement, newValue: boolean) =>
e._closeOnDisabledReadonlyChanged(newValue),
)
@property({ type: Boolean })
public accessor readonly: boolean = false;

Expand Down Expand Up @@ -305,6 +322,28 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(
}
}

/**
* The `value` property should be adapted when the `multiple` property changes:
* - if it changes to true, the 'value' is set to an array;
* - if it changes to false, the first available option is set as 'value' otherwise it's set to null.
*/
private _onMultipleChanged(newValue: boolean): void {
if (newValue) {
this.value = this.value !== null ? [this.value as string] : [];
} else {
this.value = (this.value as string[]).length ? (this.value as string[])[0] : null;
}
}

/**
* If the `disabled` or the `readonly` properties are set, and the panel is open, close it.
*/
private _closeOnDisabledReadonlyChanged(newValue: boolean): void {
if (this.isOpen && newValue) {
this.close();
}
}

/** Sets the _displayValue by checking the internal sbb-options and setting the correct `selected` value on them. */
private _onValueChanged(newValue: string | string[]): void {
const options = this._filteredOptions;
Expand Down Expand Up @@ -453,6 +492,10 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(
element.toggleAttribute('data-negative', this.negative);
element.toggleAttribute('data-multiple', this.multiple);
});

this.querySelectorAll?.<SbbOptionElement | SbbOptGroupElement>(
'sbb-option, sbb-optgroup',
).forEach((e) => e.requestUpdate?.());
}

private _setupSelect(): void {
Expand Down
2 changes: 1 addition & 1 deletion src/elements/toggle/toggle/toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class SbbToggleElement extends LitElement {

/** Whether the toggle is disabled. */
@forceType()
@handleDistinctChange((e) => e._updateDisabled())
@handleDistinctChange((e: SbbToggleElement) => e._updateDisabled())
@property({ reflect: true, type: Boolean })
public accessor disabled: boolean = false;

Expand Down
2 changes: 1 addition & 1 deletion src/elements/train/train-wagon/train-wagon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class SbbTrainWagonElement extends SbbNamedSlotListMixin<SbbIconElement, typeof

/** Sector in which the wagon stops. */
@forceType()
@handleDistinctChange((e) => e._sectorChanged())
@handleDistinctChange((e: SbbTrainWagonElement) => e._sectorChanged())
@property({ reflect: true, converter: omitEmptyConverter })
public accessor sector: string = '';

Expand Down

0 comments on commit 6ad135e

Please sign in to comment.