UNPKG

@sandlada/mdc

Version:

@sandlada/mdc is an open source component library that follows the Material Design 3 design specifications.

27 lines 8.61 kB
import{customElement as e}from"../../node_modules/@lit/reactive-element/decorators/custom-element.js";import{property as t}from"../../node_modules/@lit/reactive-element/decorators/property.js";import{query as n}from"../../node_modules/@lit/reactive-element/decorators/query.js";import"../../node_modules/lit/decorators.js";import{html as r}from"../../node_modules/lit-html/lit-html.js";import{LitElement as i}from"../../node_modules/lit-element/lit-element.js";import"../../node_modules/lit/index.js";import{classMap as a}from"../../node_modules/lit-html/directives/class-map.js";import"../../node_modules/lit/directives/class-map.js";import{mixinElementInternals as o}from"../../utils/behaviors/element-internals.js";import{composeMixin as s}from"../../utils/compose-mixin/compose-mixin.js";import c from"../../_virtual/_@oxc-project_runtime@0.144.0/helpers/esm/decorate.js";import{mixinDelegatesAria as l}from"../../utils/aria/delegate.js";import{MeasuredDimensionController as u}from"../../utils/controller/measured-dimension-controller.js";import{OpacityTransitionController as d}from"../../utils/controller/opacity-transition-controller.js";import{mixinFocusRingOptions as f}from"../focus-ring/focus-ring-options.mixin.js";import{mixinRippleOptions as p}from"../ripple/ripple-options.mixin.js";import{SelectionController as m}from"../../utils/controller/selection-controller.js";import{GlobalNavigationStateStore as h}from"../../utils/navigation/navigation-state-store.js";import{NavigationTabStyles as g}from"./navigation-tab.style.js"; /** * @license * Copyright 2026 Kai-Orion & Sandlada * SPDX-License-Identifier: MIT * * @fileoverview * Navigation tab component that behaves like a single-select control and * synchronizes selection through the navigation state store. * * @example * ```html * <mdc-navigation-bar navigation-scope="main-nav"> * <mdc-navigation-tab name="bar-tabs" value="/home">Home</mdc-navigation-tab> * <mdc-navigation-tab name="bar-tabs" value="/settings">Settings</mdc-navigation-tab> * </mdc-navigation-bar> * * <script> * const tab = document.querySelector('mdc-navigation-tab') * tab?.addEventListener('change', (event) => { * console.log(event.detail.value, event.detail.source, event.detail.trigger) * }) * <\/script> * ``` */ const _=new Set([` `,`Enter`,`Spacebar`]);function v(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`mdc-navigation-tab-${Math.random().toString(36).slice(2)}`}let y=class extends s(o,l,p,f)(i){static{this.shadowRootOptions={...i.shadowRootOptions,delegatesFocus:!0}}static{this.styles=g}get rippleControl(){return this.inputElement}get focusRingControl(){return this.inputElement}constructor(){super(),this.label=``,this.name=``,this.value=``,this.href=null,this.navigationScope=`global`,this.checked=!1,this.disabled=!1,this.variant=`bar-vertical`,this.focusRingInward=!0,this.tabId=v(),this.unsubscribeScope=null,this.pendingUserTrigger=null,this.checkedBeforeControllerSelection=!1,this.selectionHandledByController=!1,this.suppressCheckedUpdatePublish=!1,this.selectionController=new m(this,{multiple:!1,canCancel:!1,preventSelectionDuringInitialFocus:!0,preventSelectionDuringSwitching:!0,dispatchNavigationClick:!1,dispatchInputChangeEvents:!1,getFocusableElement:e=>e,onBeforeSelect:()=>{this.selectionHandledByController=!0,this.checkedBeforeControllerSelection=this.checked},onAfterSelected:()=>{let e=this.checkedBeforeControllerSelection!==this.checked;this.handleControllerSelection(e)}}),this.opacityController=new d(this,{target:()=>this.labelElement}),this.widthController=new u(this,{target:()=>this.labelElement}),this.handlePointerDownCapture=()=>{this.disabled||(this.pendingUserTrigger=`pointer`)},this.handleKeyDownCapture=e=>{this.disabled||_.has(e.key)&&(this.pendingUserTrigger=`keyboard`)},this.stopNativeInputAndChange=e=>{e.stopPropagation()},this.handleScopeMutation=e=>{if(e.originId===this.tabId)return;if(e.activeValue===null){this.checked&&=(this.suppressCheckedUpdatePublish=!0,!1);return}let t=e.activeValue===this.value;this.checked!==t&&(this.suppressCheckedUpdatePublish=!0,this.checked=t),t&&(this.dispatchNavigationInput(`external`,e.trigger),e.changed&&this.dispatchNavigationChange(`external`,e.trigger))},this.role=`tab`,this.tabIndex=0,this.setAttribute(`aria-label`,this.label),this.setAttribute(`aria-selected`,String(this.checked)),this.setAttribute(`aria-disabled`,String(this.disabled)),this.addEventListener(`pointerdown`,this.handlePointerDownCapture,{capture:!0}),this.addEventListener(`keydown`,this.handleKeyDownCapture,{capture:!0})}connectedCallback(){super.connectedCallback(),this.subscribeScope()}disconnectedCallback(){this.unsubscribeScope?.(),this.unsubscribeScope=null,super.disconnectedCallback()}willUpdate(e){e.has(`checked`)&&this.selectionController.handleCheckedChange()}updated(e){super.updated(e),e.has(`checked`)&&(this.setAttribute(`aria-selected`,String(this.checked)),this.handleCheckedMutation()),e.has(`disabled`)&&this.setAttribute(`aria-disabled`,String(this.disabled)),e.has(`navigationScope`)&&this.isConnected&&this.subscribeScope(),e.has(`value`)&&this.isConnected&&this.syncWithScopeState()}getRenderClasses(){return{container:!0,[this.variant]:!0}}render(){return r`<button class="${a(this.getRenderClasses())}"><div aria-hidden="true" class="indicator"><div aria-hidden="true" class="ripple-layer">${this.renderRipple()}</div></div><div class="icon-container"><span class="icon inactive-icon">${this.renderInactiveIconSlot()} </span><span class="icon active-icon">${this.renderActiveIconSlot()}</span><div class="label in-icon-container">${this.label}</div></div><div class="label out-icon-container">${this.label}</div>${this.renderInput()} ${this.renderFocusRing()}</button>`}renderInactiveIconSlot(){return r`<slot name="inactive-icon"></slot>`}renderActiveIconSlot(){return r`<slot name="active-icon"></slot>`}renderInput(){return r`<input id="touch-target" tabindex="-1" type="radio" name="${this.name}" .value="${this.value}" .checked="${this.checked}" ?disabled="${this.disabled}" @input="${this.stopNativeInputAndChange}" @change="${this.stopNativeInputAndChange}">`}handleControllerSelection(e){let t=this.pendingUserTrigger??`programmatic`;if(this.pendingUserTrigger=null,this.checked&&!this.disabled){let e=h.setActive(this.normalizedScope,this.value,{source:`user`,trigger:t,originId:this.tabId});this.dispatchNavigationInput(`user`,t),e.changed&&this.dispatchNavigationChange(`user`,t)}e||(this.selectionHandledByController=!1)}handleCheckedMutation(){if(this.selectionHandledByController){this.selectionHandledByController=!1;return}if(this.suppressCheckedUpdatePublish){this.suppressCheckedUpdatePublish=!1;return}if(!this.checked||this.disabled)return;let e=h.setActive(this.normalizedScope,this.value,{source:`external`,trigger:`programmatic`,originId:this.tabId});this.dispatchNavigationInput(`external`,`programmatic`),e.changed&&this.dispatchNavigationChange(`external`,`programmatic`)}subscribeScope(){this.unsubscribeScope?.(),this.unsubscribeScope=h.subscribe(this.normalizedScope,this.handleScopeMutation),this.syncWithScopeState()}syncWithScopeState(){let e=h.getActive(this.normalizedScope);if(e===null){this.checked&&h.setActive(this.normalizedScope,this.value,{source:`external`,trigger:`programmatic`,originId:this.tabId});return}let t=e===this.value;this.checked!==t&&(this.suppressCheckedUpdatePublish=!0,this.checked=t)}dispatchNavigationInput(e,t){this.dispatchEvent(new CustomEvent(`input`,{bubbles:!0,composed:!0,detail:{value:this.value,source:e,trigger:t}}))}dispatchNavigationChange(e,t){this.dispatchEvent(new CustomEvent(`change`,{bubbles:!0,composed:!0,detail:{value:this.value,source:e,trigger:t}}))}get normalizedScope(){let e=this.navigationScope.trim();return e.length>0?e:`global`}};c([t({type:String,reflect:!0})],y.prototype,`label`,void 0),c([t({type:String,reflect:!0})],y.prototype,`name`,void 0),c([t({type:String})],y.prototype,`value`,void 0),c([t({type:String})],y.prototype,`href`,void 0),c([t({type:String,reflect:!0,attribute:`navigation-scope`})],y.prototype,`navigationScope`,void 0),c([t({type:Boolean,reflect:!0})],y.prototype,`checked`,void 0),c([t({type:Boolean,reflect:!0})],y.prototype,`disabled`,void 0),c([t({type:String,reflect:!0})],y.prototype,`variant`,void 0),c([n(`#touch-target`)],y.prototype,`inputElement`,void 0),c([n(`.indicator`)],y.prototype,`indicatorElement`,void 0),c([n(`.label`)],y.prototype,`labelElement`,void 0),y=c([e(`mdc-navigation-tab`)],y);export{y as MDCNavigationTab}; //# sourceMappingURL=navigation-tab.js.map