From 385b5451c839f1f22914ca561862edd7b692cf78 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Fri, 14 Apr 2023 12:20:17 -0400 Subject: [PATCH] add size to radio group; fixes #1301 --- docs/resources/changelog.md | 1 + src/components/radio-button/radio-button.ts | 5 +- .../radio-group/radio-group.test.ts | 68 +++++++++++++------ src/components/radio-group/radio-group.ts | 14 +++- src/components/radio/radio.ts | 5 +- 5 files changed, 69 insertions(+), 24 deletions(-) diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index a6c507106..cf432ea1f 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -11,6 +11,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti - Added the `discover()` function to the experimental autoloader's exports [#1236](https://github.com/shoelace-style/shoelace/pull/1236) - Added more tests for `` [#1246](https://github.com/shoelace-style/shoelace/pull/1246) - Added tests for `` [#1274](https://github.com/shoelace-style/shoelace/pull/1274) +- Added the `size` attribute to `` so labels and controls will be sized consistently [#1301](https://github.com/shoelace-style/shoelace/issues/1301) - Fixed a bug in `` that prevented long labels from wrapping [#1243](https://github.com/shoelace-style/shoelace/issues/1243) - Fixed a bug in `` that caused labels to be misaligned when text wraps [#1244](https://github.com/shoelace-style/shoelace/issues/1244) - Fixed an incorrect CSS property value in `` [#1272](https://github.com/shoelace-style/shoelace/pull/1272) diff --git a/src/components/radio-button/radio-button.ts b/src/components/radio-button/radio-button.ts index 5b1b835eb..9ee4d896c 100644 --- a/src/components/radio-button/radio-button.ts +++ b/src/components/radio-button/radio-button.ts @@ -51,7 +51,10 @@ export default class SlRadioButton extends ShoelaceElement { /** Disables the radio button. */ @property({ type: Boolean, reflect: true }) disabled = false; - /** The radio button's size. */ + /** + * The radio button's size. When used inside a radio group, the size will be determined by the radio group's size so + * this attribute can typically be omitted. + */ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; /** Draws a pill-style radio button with rounded edges. */ diff --git a/src/components/radio-group/radio-group.test.ts b/src/components/radio-group/radio-group.test.ts index 4591c8605..124a0c841 100644 --- a/src/components/radio-group/radio-group.test.ts +++ b/src/components/radio-group/radio-group.test.ts @@ -151,30 +151,30 @@ describe('', () => { expect(radioGroup.hasAttribute('data-user-invalid')).to.be.false; expect(radioGroup.hasAttribute('data-user-valid')).to.be.false; }); - }); - it('should show a constraint validation error when setCustomValidity() is called', async () => { - const form = await fixture(html` -
- - - - - Submit -
- `); - const button = form.querySelector('sl-button')!; - const radioGroup = form.querySelector('sl-radio-group')!; - const submitHandler = sinon.spy((event: SubmitEvent) => event.preventDefault()); + it('should show a constraint validation error when setCustomValidity() is called', async () => { + const form = await fixture(html` +
+ + + + + Submit +
+ `); + const button = form.querySelector('sl-button')!; + const radioGroup = form.querySelector('sl-radio-group')!; + const submitHandler = sinon.spy((event: SubmitEvent) => event.preventDefault()); - // Submitting the form after setting custom validity should not trigger the handler - radioGroup.setCustomValidity('Invalid selection'); - form.addEventListener('submit', submitHandler); - button.click(); + // Submitting the form after setting custom validity should not trigger the handler + radioGroup.setCustomValidity('Invalid selection'); + form.addEventListener('submit', submitHandler); + button.click(); - await aTimeout(100); + await aTimeout(100); - expect(submitHandler).to.not.have.been.called; + expect(submitHandler).to.not.have.been.called; + }); }); }); @@ -252,6 +252,34 @@ describe('when submitting a form', () => { }); }); +describe('when a size is applied', () => { + it('should apply the same size to all radios', async () => { + const radioGroup = await fixture(html` + + + + + `); + const [radio1, radio2] = radioGroup.querySelectorAll('sl-radio')!; + + expect(radio1.size).to.equal('large'); + expect(radio2.size).to.equal('large'); + }); + + it('should apply the same size to all radio buttons', async () => { + const radioGroup = await fixture(html` + + + + + `); + const [radio1, radio2] = radioGroup.querySelectorAll('sl-radio-button')!; + + expect(radio1.size).to.equal('large'); + expect(radio2.size).to.equal('large'); + }); +}); + describe('when the value changes', () => { it('should emit sl-change when toggled with the arrow keys', async () => { const radioGroup = await fixture(html` diff --git a/src/components/radio-group/radio-group.ts b/src/components/radio-group/radio-group.ts index 8afd4bf8f..4c22b55a8 100644 --- a/src/components/radio-group/radio-group.ts +++ b/src/components/radio-group/radio-group.ts @@ -71,6 +71,9 @@ export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFor /** The current value of the radio group, submitted as a name/value pair with form data. */ @property({ reflect: true }) value = ''; + /** The radio group's size. This size will be applied to all child radios and radio buttons. */ + @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + /** * By default, form controls are associated with the nearest containing `
` element. This attribute allows you * to place the form control outside of a form and associate it with the form that has this `id`. The form must be in @@ -199,7 +202,12 @@ export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFor private handleSlotChange() { if (customElements.get('sl-radio') || customElements.get('sl-radio-button')) { const radios = this.getAllRadios(); - radios.forEach(radio => (radio.checked = radio.value === this.value)); + + // Sync the checked state and size + radios.forEach(radio => { + radio.checked = radio.value === this.value; + radio.size = this.size; + }); this.hasButtonGroup = radios.some(radio => radio.tagName.toLowerCase() === 'sl-radio-button'); @@ -312,7 +320,9 @@ export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFor part="form-control" class=${classMap({ 'form-control': true, - 'form-control--medium': true, + 'form-control--small': this.size === 'small', + 'form-control--medium': this.size === 'medium', + 'form-control--large': this.size === 'large', 'form-control--radio-group': true, 'form-control--has-label': hasLabel, 'form-control--has-help-text': hasHelpText diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index ab39e285d..90183717d 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -36,7 +36,10 @@ export default class SlRadio extends ShoelaceElement { /** The radio's value. When selected, the radio group will receive this value. */ @property() value: string; - /** The radio's size. */ + /** + * The radio's size. When used inside a radio group, the size will be determined by the radio group's size so this + * attribute can typically be omitted. + */ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; /** Disables the radio. */