diff --git a/.changeset/chatty-beers-divide.md b/.changeset/chatty-beers-divide.md new file mode 100644 index 0000000000..0284a8fc4b --- /dev/null +++ b/.changeset/chatty-beers-divide.md @@ -0,0 +1,5 @@ +--- +'@solid-design-system/docs': patch +--- + +Fixed `sd-radio-group` default story markup. diff --git a/.changeset/swift-snails-own.md b/.changeset/swift-snails-own.md new file mode 100644 index 0000000000..205b6eacd0 --- /dev/null +++ b/.changeset/swift-snails-own.md @@ -0,0 +1,5 @@ +--- +'@solid-design-system/components': patch +--- + +Improved `sd-radio-group` robustness when no radios are present, preventing errors and logging a helpful warning instead. diff --git a/packages/components/src/components/radio-group/radio-group.test.ts b/packages/components/src/components/radio-group/radio-group.test.ts index e9aa5e8fb5..db19570b76 100644 --- a/packages/components/src/components/radio-group/radio-group.test.ts +++ b/packages/components/src/components/radio-group/radio-group.test.ts @@ -239,6 +239,20 @@ describe('', () => { }); }); +describe('when there are no radios', () => { + it('should warn but not throw error', async () => { + const radioGroup = await fixture(html` `); + const warningLog = sinon.stub(console, 'warn'); + + radioGroup.focus(); + await radioGroup.updateComplete; + + expect(warningLog.calledOnceWith('No radios found in the radio group.')).to.be.true; + + warningLog.restore(); + }); +}); + describe('when resetting a form', () => { it('should reset the element to its initial value', async () => { const form = await fixture(html` diff --git a/packages/components/src/components/radio-group/radio-group.ts b/packages/components/src/components/radio-group/radio-group.ts index 84b289b3eb..86ae5ba862 100644 --- a/packages/components/src/components/radio-group/radio-group.ts +++ b/packages/components/src/components/radio-group/radio-group.ts @@ -141,13 +141,22 @@ export default class SdRadioGroup extends SolidElement implements SolidFormContr } private getAllRadios() { - return [...this.querySelectorAll('sd-radio, sd-radio-button')]; + const radios = [...this.querySelectorAll('sd-radio, sd-radio-button')]; + + if (radios.length === 0) { + console.warn('No radios found in the radio group.'); + } + + return radios; } private handleRadioClick(event: MouseEvent) { const target = (event.target as HTMLElement).closest('sd-radio, sd-radio-button')!; - const radios = this.getAllRadios(); const oldValue = this.value; + const radios = this.getAllRadios(); + if (radios.length === 0) { + return; + } if (target.disabled) { return; @@ -168,6 +177,10 @@ export default class SdRadioGroup extends SolidElement implements SolidFormContr } const radios = this.getAllRadios().filter(radio => !radio.disabled); + if (radios.length === 0) { + return; + } + const checkedRadio = radios.find(radio => radio.checked) ?? radios[0]; const incr = event.key === ' ' ? 0 : ['ArrowUp', 'ArrowLeft'].includes(event.key) ? -1 : 1; const oldValue = this.value; @@ -210,6 +223,10 @@ export default class SdRadioGroup extends SolidElement implements SolidFormContr /** Move focus to the checked radio (or the first one if none are checked) */ focus() { const radios = this.getAllRadios(); + if (radios.length === 0) { + return; + } + const checked = radios.find(radio => radio.checked); const radioToFocus = checked || radios[0]; @@ -226,6 +243,10 @@ export default class SdRadioGroup extends SolidElement implements SolidFormContr private async syncRadioElements() { const radios = this.getAllRadios(); + if (radios.length === 0) { + this.hasButtonGroup = false; + return; + } await Promise.all( // Sync the checked state and size @@ -286,6 +307,10 @@ export default class SdRadioGroup extends SolidElement implements SolidFormContr private updateCheckedRadio() { const radios = this.getAllRadios(); + if (radios.length === 0) { + return; + } + radios.forEach(radio => (radio.checked = radio.value === this.value)); this.formControlController.setValidity(this.validity.valid); } diff --git a/packages/docs/src/stories/components/radio-group.stories.ts b/packages/docs/src/stories/components/radio-group.stories.ts index b66a78fa7a..a4c5a33fb8 100644 --- a/packages/docs/src/stories/components/radio-group.stories.ts +++ b/packages/docs/src/stories/components/radio-group.stories.ts @@ -21,14 +21,14 @@ export default { { type: 'slot', name: 'default', - value: ` - Radio 1 - Radio 2 - Radio 3 - ` + value: `Radio 1 + Radio 2 + Radio 3` }, { type: 'attribute', name: 'name', value: 'radio-group' }, - { type: 'attribute', name: 'value', value: '1' } + { type: 'attribute', name: 'value', value: '1' }, + { type: 'attribute', name: 'label', value: 'Group label' }, + { type: 'attribute', name: 'size', value: 'lg' } ]), argTypes };