Skip to content

Commit

Permalink
feat(radio-button): slug (carbon-design-system#11208)
Browse files Browse the repository at this point in the history
* feat(radio-button): slug

* fix(radion-button): opening slug and cleanup

* fix(tile): style token
  • Loading branch information
ariellalgilmore authored Dec 8, 2023
1 parent 29c2c5b commit 5b48b8f
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
}
}

/**
* Handles `slotchange` event.
*/
protected _handleSlotChange({ target }: Event) {
const hasContent = (target as HTMLSlotElement)
.assignedNodes()
.filter((elem) =>
(elem as HTMLElement).matches !== undefined
? (elem as HTMLElement).matches(
(this.constructor as typeof CDSRadioButtonGroup).slugItem
)
: false
);

this._hasSlug = Boolean(hasContent);
(hasContent[0] as HTMLElement).setAttribute('size', 'mini');
this.requestUpdate();
}

/**
* `true` if there is a slug.
*/
protected _hasSlug = false;

/**
* The `value` attribute for the `<input>` for selection.
*/
Expand Down Expand Up @@ -189,6 +213,8 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
orientation,
legendText,
helperText,
_hasSlug: hasSlug,
_handleSlotChange: handleSlotChange,
} = this;

const showWarning = !readOnly && !invalid && warn;
Expand All @@ -211,14 +237,18 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
[`${prefix}--radio-button-group--readonly`]: readOnly,
[`${prefix}--radio-button-group--${orientation}`]:
orientation === 'vertical',
[`${prefix}--radio-button-group--slug`]: hasSlug,
});

return html` <fieldset
class="${fieldsetClasses}"
?disabled="${disabled}"
aria-readonly="${readOnly}">
${legendText
? html` <legend class="${prefix}--label">${legendText}</legend>`
? html` <legend class="${prefix}--label">
${legendText}
<slot name="slug" @slotchange="${handleSlotChange}"></slot>
</legend>`
: ``}
<slot></slot>
</fieldset>
Expand All @@ -244,6 +274,13 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
return `${prefix}-radio-button`;
}

/**
* A selector that will return the slug item.
*/
static get slugItem() {
return `${prefix}-slug`;
}

/**
* The name of the custom event fired after this radio button group changes its selected item.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ $css--plex: true !default;
@use '@carbon/styles/scss/theme' as *;
@use '@carbon/styles/scss/spacing' as *;
@use '@carbon/styles/scss/utilities' as *;
@use '@carbon/styles/scss/utilities/convert' as *;
@use '@carbon/styles/scss/components/form';
@use '@carbon/styles/scss/components/radio-button/radio-button' as *;

Expand Down Expand Up @@ -58,8 +59,13 @@ $css--plex: true !default;
}
}

:host(#{$prefix}-radio-button[orientation='vertical']) {
margin-block-end: to-rem(6px);
margin-inline-end: 0;
}

:host(#{$prefix}-radio-button[invalid]) .#{$prefix}--radio-button__appearance {
border-color: $support-error;
border-color: $support-error !important; /* stylelint-disable-line declaration-no-important */
}

:host(#{$prefix}-radio-button[data-table]) {
Expand Down Expand Up @@ -102,3 +108,23 @@ $css--plex: true !default;
margin-left: $spacing-03;
}
}

:host(#{$prefix}-radio-button[slug]) {
.#{$prefix}--radio-button__label-text {
display: flex;
}
}

:host(#{$prefix}-radio-button-group) .#{$prefix}--radio-button-group--slug,
:host(#{$prefix}-radio-button[slug]) {
::slotted(#{$prefix}-slug) {
margin-inline-start: $spacing-03;
}
}

:host(#{$prefix}-radio-button[slug]) {
::slotted(#{$prefix}-slug[inline]) {
line-height: inherit;
margin-block-start: to-rem(-1px);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,33 +120,39 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
/**
* The hidden radio button.
*/
@query('#input')
@query('input')
private _inputNode!: HTMLInputElement;

/**
* Handles `click` event on this element.
*/
@HostListener('click')
// @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to
private _handleClick = () => {
const { disabled, _radioButtonDelegate: radioButtonDelegate } = this;
if (radioButtonDelegate && !disabled && !this.disabledItem) {
this.checked = true;
if (this._manager) {
this._manager.select(radioButtonDelegate, this.readOnly);
private _handleClick = (event) => {
if (
!(event.target as HTMLElement).matches(
(this.constructor as typeof CDSRadioButton)?.slugItem
)
) {
const { disabled, _radioButtonDelegate: radioButtonDelegate } = this;
if (radioButtonDelegate && !disabled && !this.disabledItem) {
this.checked = true;
if (this._manager) {
this._manager.select(radioButtonDelegate, this.readOnly);
}
this.dispatchEvent(
new CustomEvent(
(this.constructor as typeof CDSRadioButton).eventChange,
{
bubbles: true,
composed: true,
detail: {
checked: this.checked,
},
}
)
);
}
this.dispatchEvent(
new CustomEvent(
(this.constructor as typeof CDSRadioButton).eventChange,
{
bubbles: true,
composed: true,
detail: {
checked: this.checked,
},
}
)
);
}
};

Expand All @@ -156,26 +162,60 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
@HostListener('keydown')
// @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to
private _handleKeydown = (event: KeyboardEvent) => {
const { orientation, _radioButtonDelegate: radioButtonDelegate } = this;
const manager = this._manager;
if (radioButtonDelegate && manager) {
const navigationDirectionForKey =
orientation === RADIO_BUTTON_ORIENTATION.HORIZONTAL
? navigationDirectionForKeyHorizontal
: navigationDirectionForKeyVertical;
const navigationDirection = navigationDirectionForKey[event.key];
if (navigationDirection) {
manager.select(
manager.navigate(radioButtonDelegate, navigationDirection),
this.readOnly
);
}
if (event.key === ' ' || event.key === 'Enter') {
manager.select(radioButtonDelegate, this.readOnly);
if (
!(event.target as HTMLElement).matches(
(this.constructor as typeof CDSRadioButton)?.slugItem
)
) {
const { orientation, _radioButtonDelegate: radioButtonDelegate } = this;
const manager = this._manager;
if (radioButtonDelegate && manager) {
const navigationDirectionForKey =
orientation === RADIO_BUTTON_ORIENTATION.HORIZONTAL
? navigationDirectionForKeyHorizontal
: navigationDirectionForKeyVertical;
const navigationDirection = navigationDirectionForKey[event.key];
if (navigationDirection) {
manager.select(
manager.navigate(radioButtonDelegate, navigationDirection),
this.readOnly
);
}
if (event.key === ' ' || event.key === 'Enter') {
manager.select(radioButtonDelegate, this.readOnly);
}
}
}
};

/**
* Handles `slotchange` event.
*/
protected _handleSlotChange({ target }: Event) {
const hasContent = (target as HTMLSlotElement)
.assignedNodes()
.filter((elem) =>
(elem as HTMLElement).matches !== undefined
? (elem as HTMLElement).matches(
(this.constructor as typeof CDSRadioButton).slugItem
)
: false
);

this._hasSlug = Boolean(hasContent);
const type = (hasContent[0] as HTMLElement).getAttribute('kind');
(hasContent[0] as HTMLElement).setAttribute(
'size',
type === 'inline' ? 'md' : 'mini'
);
this.requestUpdate();
}

/**
* `true` if there is a slug.
*/
protected _hasSlug = false;

/**
* `true` if this radio button should be checked.
*/
Expand Down Expand Up @@ -261,10 +301,12 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {

updated(changedProperties) {
const {
_hasSlug: hasSlug,
_inputNode: inputNode,
_radioButtonDelegate: radioButtonDelegate,
name,
} = this;

if (changedProperties.has('checked') || changedProperties.has('name')) {
if (this.readOnly) {
this.checked = false;
Expand All @@ -288,6 +330,7 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
: '0'
);
}
hasSlug ? this.setAttribute('slug', '') : this.removeAttribute('slug');
}

render() {
Expand All @@ -301,11 +344,12 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
disabledItem,
} = this;
const innerLabelClasses = classMap({
[`${prefix}--radio-button__label-text`]: true,
[`${prefix}--visually-hidden`]: hideLabel,
});
return html`
<input
id="input"
id="radio"
type="radio"
class="${prefix}--radio-button"
.checked=${checked}
Expand All @@ -314,11 +358,21 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
value=${ifDefined(value)} />
<label for="input" class="${prefix}--radio-button__label">
<span class="${prefix}--radio-button__appearance"></span>
<span class="${innerLabelClasses}"><slot>${labelText}</slot></span>
<span class="${innerLabelClasses}"
>${labelText}
<slot name="slug" @slotchange="${this._handleSlotChange}"></slot
></span>
</label>
`;
}

/**
* A selector that will return the slug item.
*/
static get slugItem() {
return `${prefix}-slug`;
}

/**
* The name of the custom event fired after this radio button changes its checked state.
*/
Expand Down
Loading

0 comments on commit 5b48b8f

Please sign in to comment.