diff --git a/docs/components/radio-group.md b/docs/components/radio-group.md index d5a28963d..d860877d5 100644 --- a/docs/components/radio-group.md +++ b/docs/components/radio-group.md @@ -5,10 +5,10 @@ Radio groups are used to group multiple [radios](/components/radio) or [radio buttons](/components/radio-button) so they function as a single form control. ```html preview - - Option 1 - Option 2 - Option 3 + + Option 1 + Option 2 + Option 3 ``` @@ -16,16 +16,10 @@ Radio groups are used to group multiple [radios](/components/radio) or [radio bu import { SlRadio, SlRadioGroup } from '@shoelace-style/shoelace/dist/react'; const App = () => ( - - - Option 1 - - - Option 2 - - - Option 3 - + + Option 1 + Option 2 + Option 3 ); ``` @@ -37,8 +31,8 @@ const App = () => ( You can show the fieldset and legend that wraps the radio group using the `fieldset` attribute. If you don't use this option, you should still provide a label so screen readers announce the control correctly. ```html preview - - Option 1 + + Option 1 Option 2 Option 3 @@ -48,8 +42,8 @@ You can show the fieldset and legend that wraps the radio group using the `field import { SlRadio, SlRadioGroup } from '@shoelace-style/shoelace/dist/react'; const App = () => ( - - + + Option 1 @@ -67,8 +61,8 @@ const App = () => ( [Radio buttons](/components/radio-button) offer an alternate way to display radio controls. In this case, an internal [button group](/components/button-group) is used to group the buttons into a single, cohesive control. ```html preview - - Option 1 + + Option 1 Option 2 Option 3 @@ -78,8 +72,8 @@ const App = () => ( import { SlRadioButton, SlRadioGroup } from '@shoelace-style/shoelace/dist/react'; const App = () => ( - - + + Option 1 diff --git a/src/components/button-group/button-group.ts b/src/components/button-group/button-group.ts index 6ce752eb1..d3edd1126 100644 --- a/src/components/button-group/button-group.ts +++ b/src/components/button-group/button-group.ts @@ -1,5 +1,5 @@ import { LitElement, html } from 'lit'; -import { customElement, property, query } from 'lit/decorators.js'; +import { customElement, property, query, state } from 'lit/decorators.js'; import styles from './button-group.styles'; import type { CSSResultGroup } from 'lit'; @@ -19,6 +19,8 @@ export default class SlButtonGroup extends LitElement { @query('slot') defaultSlot: HTMLSlotElement; + @state() disableRole = false; + /** A label to use for the button group's `aria-label` attribute. */ @property() label = ''; @@ -65,14 +67,14 @@ export default class SlButtonGroup extends LitElement {
- +
`; } diff --git a/src/components/radio-button/radio-button.ts b/src/components/radio-button/radio-button.ts index e77b302d4..85aecbd6f 100644 --- a/src/components/radio-button/radio-button.ts +++ b/src/components/radio-button/radio-button.ts @@ -3,9 +3,7 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { html } from 'lit/static-html.js'; -import { defaultValue } from '../../internal/default-value'; import { emit } from '../../internal/event'; -import { FormSubmitController } from '../../internal/form'; import { HasSlotController } from '../../internal/slot'; import { watch } from '../../internal/watch'; import styles from './radio-button.styles'; @@ -18,7 +16,6 @@ import type { CSSResultGroup } from 'lit'; * @slot - The radio's label. * * @event sl-blur - Emitted when the button loses focus. - * @event sl-change - Emitted when the button's checked state changes. * @event sl-focus - Emitted when the button gains focus. * * @slot - The button's label. @@ -38,17 +35,13 @@ export default class SlRadioButton extends LitElement { @query('.button') input: HTMLInputElement; @query('.hidden-input') hiddenInput: HTMLInputElement; - protected readonly formSubmitController = new FormSubmitController(this, { - value: (control: SlRadioButton) => (control.checked ? control.value : undefined), - defaultValue: (control: SlRadioButton) => control.defaultChecked, - setValue: (control: SlRadioButton, checked: boolean) => (control.checked = checked) - }); private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix'); @state() protected hasFocus = false; + @state() protected checked = false; /** The radio's name attribute. */ - @property() name: string; + @property({ reflect: true }) name: string; /** The radio's value attribute. */ @property() value: string; @@ -56,46 +49,20 @@ export default class SlRadioButton extends LitElement { /** Disables the radio. */ @property({ type: Boolean, reflect: true }) disabled = false; - /** Draws the radio in a checked state. */ - @property({ type: Boolean, reflect: true }) checked = false; + /** The button's size. */ + @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; - /** - * This will be true when the control is in an invalid state. Validity in radios is determined by the message provided - * by the `setCustomValidity` method. - */ - @property({ type: Boolean, reflect: true }) invalid = false; - - /** Gets or sets the default value used to reset this element. The initial value corresponds to the one originally specified in the HTML that created this element. */ - @defaultValue('checked') - defaultChecked = false; + /** Draws a pill-style button with rounded edges. */ + @property({ type: Boolean, reflect: true }) pill = false; connectedCallback(): void { super.connectedCallback(); + this.setAttribute('role', 'presentation'); } - /** Simulates a click on the radio. */ - click() { - this.input.click(); - } - - /** Sets focus on the radio. */ - focus(options?: FocusOptions) { - this.input.focus(options); - } - - /** Removes focus from the radio. */ - blur() { - this.input.blur(); - } - - /** Checks for validity and shows the browser's validation message if the control is invalid. */ - reportValidity() { - return this.hiddenInput.reportValidity(); - } - - /** Sets a custom validation message. If `message` is not empty, the field will be considered invalid. */ - setCustomValidity(message: string) { - this.hiddenInput.setCustomValidity(message); + @watch('disabled', { waitUntilFirstUpdate: true }) + handleDisabledChange() { + this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); } handleBlur() { @@ -103,10 +70,14 @@ export default class SlRadioButton extends LitElement { emit(this, 'sl-blur'); } - handleClick() { - if (!this.disabled) { - this.checked = true; + handleClick(e: MouseEvent) { + if (this.disabled) { + e.preventDefault(); + e.stopPropagation(); + return; } + + this.checked = true; } handleFocus() { @@ -114,38 +85,13 @@ export default class SlRadioButton extends LitElement { emit(this, 'sl-focus'); } - @watch('checked') - handleCheckedChange() { - this.setAttribute('aria-checked', this.checked ? 'true' : 'false'); - - if (this.hasUpdated) { - emit(this, 'sl-change'); - } - } - - @watch('disabled', { waitUntilFirstUpdate: true }) - handleDisabledChange() { - this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); - - // Disabled form controls are always valid, so we need to recheck validity when the state changes - if (this.hasUpdated) { - this.input.disabled = this.disabled; - this.invalid = !this.input.checkValidity(); - } - } - - /** The button's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; - - /** Draws a pill-style button with rounded edges. */ - @property({ type: Boolean, reflect: true }) pill = false; - render() { return html` -
- +