2022-08-17 15:37:37 +00:00
import { html } from 'lit' ;
2022-08-02 17:03:47 +00:00
import { customElement , property , query , state } from 'lit/decorators.js' ;
2022-08-17 15:37:37 +00:00
import ShoelaceElement from '../../internal/shoelace-element' ;
2021-07-10 00:45:44 +00:00
import styles from './button-group.styles' ;
2022-07-19 12:27:39 +00:00
import type { CSSResultGroup } from 'lit' ;
2020-08-06 13:07:24 +00:00
/ * *
2022-10-21 13:56:35 +00:00
* @summary Button groups can be used to group related buttons into sections .
*
2020-08-06 13:07:24 +00:00
* @since 2.0
* @status stable
*
2021-06-25 20:25:46 +00:00
* @slot - One or more ` <sl-button> ` elements to display in the button group .
2020-08-06 13:07:24 +00:00
*
2022-03-09 20:54:18 +00:00
* @csspart base - The component ' s internal wrapper .
2020-08-06 13:07:24 +00:00
* /
2021-03-18 13:04:23 +00:00
@customElement ( 'sl-button-group' )
2022-08-17 15:37:37 +00:00
export default class SlButtonGroup extends ShoelaceElement {
2022-07-19 12:27:39 +00:00
static styles : CSSResultGroup = styles ;
2020-08-06 13:07:24 +00:00
2021-04-02 11:24:59 +00:00
@query ( 'slot' ) defaultSlot : HTMLSlotElement ;
2022-08-02 17:03:47 +00:00
@state ( ) disableRole = false ;
2020-09-04 21:11:25 +00:00
/** A label to use for the button group's `aria-label` attribute. */
2021-07-01 00:04:46 +00:00
@property ( ) label = '' ;
2020-08-06 13:07:24 +00:00
handleFocus ( event : CustomEvent ) {
2021-04-02 11:24:59 +00:00
const button = findButton ( event . target as HTMLElement ) ;
button ? . classList . add ( 'sl-button-group__button--focus' ) ;
2020-08-06 13:07:24 +00:00
}
handleBlur ( event : CustomEvent ) {
2021-04-02 11:24:59 +00:00
const button = findButton ( event . target as HTMLElement ) ;
button ? . classList . remove ( 'sl-button-group__button--focus' ) ;
}
handleMouseOver ( event : CustomEvent ) {
const button = findButton ( event . target as HTMLElement ) ;
button ? . classList . add ( 'sl-button-group__button--hover' ) ;
}
handleMouseOut ( event : CustomEvent ) {
const button = findButton ( event . target as HTMLElement ) ;
button ? . classList . remove ( 'sl-button-group__button--hover' ) ;
}
handleSlotChange() {
const slottedElements = [ . . . this . defaultSlot . assignedElements ( { flatten : true } ) ] as HTMLElement [ ] ;
2022-01-16 05:47:14 +00:00
slottedElements . forEach ( el = > {
2021-04-02 11:24:59 +00:00
const index = slottedElements . indexOf ( el ) ;
const button = findButton ( el ) ;
2022-01-16 05:47:14 +00:00
if ( button !== null ) {
2021-04-02 11:24:59 +00:00
button . classList . add ( 'sl-button-group__button' ) ;
button . classList . toggle ( 'sl-button-group__button--first' , index === 0 ) ;
button . classList . toggle ( 'sl-button-group__button--inner' , index > 0 && index < slottedElements . length - 1 ) ;
button . classList . toggle ( 'sl-button-group__button--last' , index === slottedElements . length - 1 ) ;
2022-07-06 13:48:30 +00:00
button . classList . toggle ( 'sl-button-group__button--radio' , button . tagName . toLowerCase ( ) === 'sl-radio-button' ) ;
2021-04-02 11:24:59 +00:00
}
} ) ;
2020-08-06 13:07:24 +00:00
}
render() {
2022-01-17 04:44:10 +00:00
// eslint-disable-next-line lit-a11y/mouse-events-have-key-events -- focusout & focusin support bubbling whereas focus & blur do not which is necessary here
2021-02-26 14:09:13 +00:00
return html `
< div
part = "base"
class = "button-group"
2022-08-02 17:03:47 +00:00
role = "${this.disableRole ? 'presentation' : 'group'}"
2021-02-26 14:09:13 +00:00
aria - label = $ { this . label }
2021-03-06 17:01:39 +00:00
@focusout = $ { this . handleBlur }
@focusin = $ { this . handleFocus }
2021-04-02 11:24:59 +00:00
@mouseover = $ { this . handleMouseOver }
@mouseout = $ { this . handleMouseOut }
2021-02-26 14:09:13 +00:00
>
2022-08-02 17:03:47 +00:00
< slot @ slotchange = $ { this.handleSlotChange } role = "none" > < / slot >
2020-08-06 13:07:24 +00:00
< / div >
2021-02-26 14:09:13 +00:00
` ;
2020-08-06 13:07:24 +00:00
}
}
2021-03-12 14:07:38 +00:00
2021-04-02 11:24:59 +00:00
function findButton ( el : HTMLElement ) {
2022-08-09 20:22:44 +00:00
const children = [ 'sl-button' , 'sl-radio-button' ] ;
return children . includes ( el . tagName . toLowerCase ( ) ) ? el : el.querySelector ( children . join ( ',' ) ) ;
2021-04-02 11:24:59 +00:00
}
2021-03-12 14:09:08 +00:00
declare global {
interface HTMLElementTagNameMap {
'sl-button-group' : SlButtonGroup ;
}
}