Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sbb-radio-button-group): radio group state update #2138

Merged
merged 7 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3178,6 +3178,10 @@ declare namespace LocalJSX {
* @deprecated only used for React. Will probably be removed once React 19 is available.
*/
"onDidChange"?: (event: SbbCheckboxCustomEvent<any>) => void;
/**
* Internal event that emits when the input element is loaded.
*/
"onSbb-checkbox-loaded"?: (event: SbbCheckboxCustomEvent<void>) => void;
"onState-change"?: (event: SbbCheckboxCustomEvent<CheckboxStateChange>) => void;
/**
* Whether the checkbox is required.
Expand Down Expand Up @@ -4176,6 +4180,10 @@ declare namespace LocalJSX {
* Whether the radio button is disabled.
*/
"disabled"?: boolean;
/**
* Internal event that emits when the input element is loaded.
*/
"onSbb-radio-button-loaded"?: (event: SbbRadioButtonCustomEvent<void>) => void;
/**
* Internal event that emits whenever the state of the radio option in relation to the parent selection panel changes.
*/
Expand Down
7 changes: 4 additions & 3 deletions src/components/sbb-checkbox/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ If you don't want the label to appear next to the checkbox, you can use `aria-la

## Events

| Event | Description | Type |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `didChange` | <span style="color:red">**[DEPRECATED]**</span> only used for React. Will probably be removed once React 19 is available.<br/><br/> | `CustomEvent<any>` |
| Event | Description | Type |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `didChange` | <span style="color:red">**[DEPRECATED]**</span> only used for React. Will probably be removed once React 19 is available.<br/><br/> | `CustomEvent<any>` |
| `sbb-checkbox-loaded` | Internal event that emits when the input element is loaded. | `CustomEvent<void>` |


## Slots
Expand Down
1 change: 1 addition & 0 deletions src/components/sbb-checkbox/sbb-checkbox.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
*/
export default {
didChange: 'didChange',
sbbCheckboxLoaded: 'sbb-checkbox-loaded',
stateChange: 'state-change',
};
10 changes: 10 additions & 0 deletions src/components/sbb-checkbox/sbb-checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ export class SbbCheckbox implements ComponentInterface {
})
public stateChange: EventEmitter<CheckboxStateChange>;

/**
* Internal event that emits when the input element is loaded.
*/
@Event({
bubbles: true,
eventName: 'sbb-checkbox-loaded',
})
public sbbCheckboxLoaded: EventEmitter<void>;
dauriamarco marked this conversation as resolved.
Show resolved Hide resolved

@Watch('checked')
public handleCheckedChange(currentValue: boolean, previousValue: boolean): void {
if (this._isSelectionPanelInput && currentValue !== previousValue) {
Expand Down Expand Up @@ -168,6 +177,7 @@ export class SbbCheckbox implements ComponentInterface {
!this._element.closest('sbb-selection-panel [slot="content"]');
this._handlerRepository.connect();
this._setupInitialStateAndAttributeObserver();
this._isSelectionPanelInput && this.sbbCheckboxLoaded.emit();
}

public componentDidLoad(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('sbb-radio-button-group', () => {
'sbb-radio-button-group > sbb-radio-button#sbb-radio-3',
);

await element.setProperty('disabled', true);
element.setProperty('disabled', true);
await page.waitForChanges();

await disabledRadio.click();
Expand All @@ -82,7 +82,7 @@ describe('sbb-radio-button-group', () => {
await page.waitForChanges();
expect(secondRadio).not.toHaveAttribute('checked');

await element.setProperty('disabled', false);
element.setProperty('disabled', false);
await page.waitForChanges();

await disabledRadio.click();
Expand Down Expand Up @@ -146,5 +146,33 @@ describe('sbb-radio-button-group', () => {

expect(firstRadio).toHaveAttribute('checked');
});

it('sets the value correctly on slot change', async () => {
const firstRadio = await page.find('sbb-radio-button-group > sbb-radio-button#sbb-radio-1');

expect(firstRadio).toHaveAttribute('checked');
expect(await element.getProperty('value')).toBe('Value one');

await page.evaluate(() => {
const newRadios = ['New radio one', 'New radio two'];
const radioGroup = document.querySelector('sbb-radio-button-group');

// Remove all the radio buttons
while (radioGroup.firstChild) {
radioGroup.removeChild(radioGroup.firstChild);
}

// Add two new radios
newRadios.forEach(async (radio, i) => {
const newRadio = document.createElement('SBB-RADIO-BUTTON') as HTMLSbbRadioButtonElement;
newRadio.innerText = radio;
newRadio.value = radio;
newRadio.checked = i === 0;
radioGroup.appendChild(newRadio);
});
});

expect(await element.getProperty('value')).toBe('New radio one');
});
});
});
14 changes: 10 additions & 4 deletions src/components/sbb-radio-button-group/sbb-radio-button-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class SbbRadioButtonGroup implements ComponentInterface {
@Element() private _element!: HTMLElement;

private _hasSelectionPanel: boolean;
private _componentLoaded = false;

@Watch('value')
public valueChanged(value: any | undefined): void {
Expand Down Expand Up @@ -155,6 +156,11 @@ export class SbbRadioButtonGroup implements ComponentInterface {
this._hasSelectionPanel = !!this._element.querySelector('sbb-selection-panel');
toggleDatasetEntry(this._element, 'hasSelectionPanel', this._hasSelectionPanel);
this._handlerRepository.connect();
this._updateRadios(this.value);
}

public componentDidLoad(): void {
this._componentLoaded = true;
}

public disconnectedCallback(): void {
Expand All @@ -164,7 +170,7 @@ export class SbbRadioButtonGroup implements ComponentInterface {
@Listen('state-change', { passive: true })
public onRadioButtonSelect(event: CustomEvent<RadioButtonStateChange>): void {
event.stopPropagation();
if (event.detail.type !== 'checked') {
if (event.detail.type !== 'checked' || !this._componentLoaded) {
return;
}

Expand All @@ -185,11 +191,11 @@ export class SbbRadioButtonGroup implements ComponentInterface {
this.didChange.emit({ value });
}

private _updateRadios(): void {
const value = this.value ?? this._radioButtons.find((radio) => radio.checked)?.value;
private _updateRadios(initValue?: string): void {
this.value = initValue ?? this._radioButtons.find((radio) => radio.checked)?.value;

for (const radio of this._radioButtons) {
radio.checked = radio.value === value;
radio.checked = radio.value === this.value;
radio.size = this.size;
radio.allowEmptySelection = this.allowEmptySelection;

Expand Down
7 changes: 4 additions & 3 deletions src/components/sbb-radio-button/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ The component has two different sizes, which can be changed using the `size` pro

## Events

| Event | Description | Type |
| -------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `state-change` | Internal event that emits whenever the state of the radio option in relation to the parent selection panel changes. | `CustomEvent<RadioButtonStateChangeChecked \| RadioButtonStateChangeDisabled>` |
| Event | Description | Type |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `sbb-radio-button-loaded` | Internal event that emits when the input element is loaded. | `CustomEvent<void>` |
| `state-change` | Internal event that emits whenever the state of the radio option in relation to the parent selection panel changes. | `CustomEvent<RadioButtonStateChangeChecked \| RadioButtonStateChangeDisabled>` |


## Methods
Expand Down
1 change: 1 addition & 0 deletions src/components/sbb-radio-button/sbb-radio-button.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
* See stencil.config.ts in the root directory.
*/
export default {
sbbRadioButtonLoaded: 'sbb-radio-button-loaded',
stateChange: 'state-change',
};
10 changes: 10 additions & 0 deletions src/components/sbb-radio-button/sbb-radio-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ export class SbbRadioButton implements ComponentInterface {
})
public stateChange: EventEmitter<RadioButtonStateChange>;

/**
* Internal event that emits when the input element is loaded.
*/
@Event({
bubbles: true,
eventName: 'sbb-radio-button-loaded',
})
public sbbRadioButtonLoaded: EventEmitter<void>;

@Watch('checked')
public handleCheckedChange(currentValue: boolean, previousValue: boolean): void {
if (currentValue !== previousValue) {
Expand Down Expand Up @@ -169,6 +178,7 @@ export class SbbRadioButton implements ComponentInterface {
!!this._selectionPanelElement &&
!this._element.closest('sbb-selection-panel [slot="content"]');
this._setupInitialStateAndAttributeObserver();
this._isSelectionPanelInput && this.sbbRadioButtonLoaded.emit();
}

public componentDidLoad(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('sbb-selection-panel', () => {
});

expect(root).toEqualHtml(`
<sbb-selection-panel data-has-content data-state="closed">
<sbb-selection-panel data-has-content>
<mock:shadow-root>
<div class="sbb-selection-panel">
<div class="sbb-selection-panel__badge">
Expand Down
12 changes: 9 additions & 3 deletions src/components/sbb-selection-panel/sbb-selection-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export class SbbSelectionPanel implements ComponentInterface {
);

private _contentElement: HTMLElement;
private _componentLoaded = false;

private get _input(): HTMLSbbCheckboxElement | HTMLSbbRadioButtonElement {
return this._element.querySelector('sbb-checkbox, sbb-radio-button') as
Expand All @@ -128,7 +129,7 @@ export class SbbSelectionPanel implements ComponentInterface {

@Listen('state-change', { passive: true })
public onInputChange(event: CustomEvent<RadioButtonStateChange | CheckboxStateChange>): void {
if (!this._state) {
if (!this._state || !this._componentLoaded) {
return;
}

Expand Down Expand Up @@ -157,15 +158,20 @@ export class SbbSelectionPanel implements ComponentInterface {
}

public connectedCallback(): void {
this._updateSelectionPanel();
this._handlerRepository.connect();
}

public componentDidLoad(): void {
this._componentLoaded = true;
}

public disconnectedCallback(): void {
this._handlerRepository.disconnect();
}

private _updateSelectionPanel(): void {
@Listen('sbb-checkbox-loaded')
@Listen('sbb-radio-button-loaded')
public updateSelectionPanel(): void {
this._checked = this._input?.checked;
this._state = this._checked || this.forceOpen ? 'opened' : 'closed';
this._disabled = this._input?.disabled;
Expand Down