add size to radio group; fixes #1301

This commit is contained in:
Cory LaViska
2023-04-14 12:20:17 -04:00
parent 0e7487257b
commit 385b5451c8
5 changed files with 69 additions and 24 deletions

View File

@@ -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 `<sl-animated-image>` [#1246](https://github.com/shoelace-style/shoelace/pull/1246)
- Added tests for `<sl-animation>` [#1274](https://github.com/shoelace-style/shoelace/pull/1274)
- Added the `size` attribute to `<sl-radio-group>` so labels and controls will be sized consistently [#1301](https://github.com/shoelace-style/shoelace/issues/1301)
- Fixed a bug in `<sl-tree-item>` that prevented long labels from wrapping [#1243](https://github.com/shoelace-style/shoelace/issues/1243)
- Fixed a bug in `<sl-tree-item>` 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 `<sl-checkbox>` [#1272](https://github.com/shoelace-style/shoelace/pull/1272)

View File

@@ -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. */

View File

@@ -151,30 +151,30 @@ describe('<sl-radio-group>', () => {
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<HTMLFormElement>(html`
<form>
<sl-radio-group value="1">
<sl-radio id="radio-1" name="a" value="1"></sl-radio>
<sl-radio id="radio-2" name="a" value="2"></sl-radio>
</sl-radio-group>
<sl-button type="submit">Submit</sl-button>
</form>
`);
const button = form.querySelector('sl-button')!;
const radioGroup = form.querySelector<SlRadioGroup>('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<HTMLFormElement>(html`
<form>
<sl-radio-group value="1">
<sl-radio id="radio-1" name="a" value="1"></sl-radio>
<sl-radio id="radio-2" name="a" value="2"></sl-radio>
</sl-radio-group>
<sl-button type="submit">Submit</sl-button>
</form>
`);
const button = form.querySelector('sl-button')!;
const radioGroup = form.querySelector<SlRadioGroup>('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<SlRadioGroup>(html`
<sl-radio-group size="large">
<sl-radio id="radio-1" value="1"></sl-radio>
<sl-radio id="radio-2" value="2"></sl-radio>
</sl-radio-group>
`);
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<SlRadioGroup>(html`
<sl-radio-group size="large">
<sl-radio-button id="radio-1" value="1"></sl-radio-button>
<sl-radio-button id="radio-2" value="2"></sl-radio-button>
</sl-radio-group>
`);
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<SlRadioGroup>(html`

View File

@@ -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 `<form>` 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

View File

@@ -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. */