fix: radio group race condition (#1364)

* fix: radio group race condition

* update changelog

* prettier

* fix changelog
pull/1368/head
Konnor Rogers 2023-06-08 15:45:34 -04:00 zatwierdzone przez GitHub
rodzic dc63f858b0
commit 1ef8e1cf73
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 71 dodań i 22 usunięć

Wyświetl plik

@ -19,6 +19,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti
- Added tests for `<sl-split-panel>` [#1343](https://github.com/shoelace-style/shoelace/pull/1343)
- Fixed a bug where changing the size of `<sl-radio-group>` wouldn't update the size of child elements
- Fixed a bug in `<sl-select>` and `<sl-color-picker>` where the `size` attribute wasn't being reflected [#1318](https://github.com/shoelace-style/shoelace/issues/1348)
- Fixed a bug in `<sl-radio-group>` where `<sl-radio>` would not get checked if `<sl-radio-group>` was defined first. [#1364](https://github.com/shoelace-style/shoelace/pull/1364/)
- Improved `<sl-button>` so it can accept children of variable heights [#1317](https://github.com/shoelace-style/shoelace/pull/1317)
- Improved the docs to more clearly explain sizing radios and radio buttons
- Improved the performance of `<sl-rating>` by partially rendering unseen icons [#1310](https://github.com/shoelace-style/shoelace/pull/1310)

Wyświetl plik

@ -365,5 +365,36 @@ describe('when the value changes', () => {
await radioGroup.updateComplete;
});
/**
* @see https://github.com/shoelace-style/shoelace/issues/1361
* This isn't really possible to test right now due to importing "shoelace.js" which
* auto-defines all of our components up front. This should be tested if we ever split
* to non-auto-defining components and not auto-defining for tests.
*/
it.skip('should sync up radios and radio buttons if defined after radio group', async () => {
// customElements.define("sl-radio-group", SlRadioGroup)
//
// const radioGroup = await fixture<SlRadioGroup>(html`
// <sl-radio-group value="1">
// <sl-radio id="radio-1" value="1"></sl-radio>
// <sl-radio id="radio-2" value="2"></sl-radio>
// </sl-radio-group>
// `);
//
// await aTimeout(1)
//
// customElements.define("sl-radio-button", SlRadioButton)
//
// expect(radioGroup.querySelector("sl-radio")?.getAttribute("aria-checked")).to.equal("false")
//
// await aTimeout(1)
//
// customElements.define("sl-radio", SlRadio)
//
// await aTimeout(1)
//
// expect(radioGroup.querySelector("sl-radio")?.getAttribute("aria-checked")).to.equal("true")
});
runFormControlBaseTests('sl-radio-group');
});

Wyświetl plik

@ -204,40 +204,57 @@ export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFor
this.formControlController.emitInvalidEvent(event);
}
private syncRadios() {
if (customElements.get('sl-radio') || customElements.get('sl-radio-button')) {
const radios = this.getAllRadios();
private async syncRadioElements() {
const radios = this.getAllRadios();
await Promise.all(
// Sync the checked state and size
radios.forEach(radio => {
radios.map(async radio => {
await radio.updateComplete;
radio.checked = radio.value === this.value;
radio.size = this.size;
});
})
);
this.hasButtonGroup = radios.some(radio => radio.tagName.toLowerCase() === 'sl-radio-button');
if (!radios.some(radio => radio.checked)) {
if (this.hasButtonGroup) {
const buttonRadio = radios[0].shadowRoot?.querySelector('button');
if (buttonRadio) {
buttonRadio.tabIndex = 0;
}
} else {
radios[0].tabIndex = 0;
}
}
this.hasButtonGroup = radios.some(radio => radio.tagName.toLowerCase() === 'sl-radio-button');
if (!radios.some(radio => radio.checked)) {
if (this.hasButtonGroup) {
const buttonGroup = this.shadowRoot?.querySelector('sl-button-group');
const buttonRadio = radios[0].shadowRoot?.querySelector('button');
if (buttonGroup) {
buttonGroup.disableRole = true;
if (buttonRadio) {
buttonRadio.tabIndex = 0;
}
} else {
radios[0].tabIndex = 0;
}
}
if (this.hasButtonGroup) {
const buttonGroup = this.shadowRoot?.querySelector('sl-button-group');
if (buttonGroup) {
buttonGroup.disableRole = true;
}
}
}
private syncRadios() {
if (customElements.get('sl-radio') && customElements.get('sl-radio-button')) {
this.syncRadioElements();
return;
}
if (customElements.get('sl-radio')) {
this.syncRadioElements();
} else {
customElements.whenDefined('sl-radio').then(() => this.syncRadios());
}
if (customElements.get('sl-radio-button')) {
this.syncRadioElements();
} else {
// Rerun this handler when <sl-radio> or <sl-radio-button> is registered
customElements.whenDefined('sl-radio').then(() => this.syncRadios());
customElements.whenDefined('sl-radio-button').then(() => this.syncRadios());
}
}