/** * Copyright Aquera Inc 2023 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import { html, CSSResultArray, TemplateResult } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { styles } from './nile-app-shell-nav-toggle.css'; import { renderGlyph } from '../internal/glyph'; import '../nile-button/nile-button'; import NileElement from '../internal/nile-element'; import type { NileAppShell } from '../nile-app-shell/nile-app-shell'; /** * @summary The side-nav toggle as a standalone control, for a header you build yourself. * * @status stable * @since 2.0 * * @tag nile-app-shell-nav-toggle * * @dependency nile-app-shell * @dependency nile-glyph * * @csspart button - The toggle button. * @csspart rule - The trailing vertical rule. * * @cssproperty [--nile-app-shell-nav-toggle-offset=-6px] - Optical start offset, so the glyph lands on the bar's text origin. * @cssproperty [--nile-app-shell-utility-size=32px] - Box the toggle sits in; the hit area and hover surface, not a visible chip. */ @customElement('nile-app-shell-nav-toggle') export class NileAppShellNavToggle extends NileElement { public static get styles(): CSSResultArray { return [styles]; } /** Draws the vertical rule the shell's own bar puts after the toggle. */ @property({ type: Boolean, reflect: true, attribute: 'with-rule' }) withRule: boolean = false; /** The shell to drive. Defaults to the nearest `nile-app-shell` ancestor, or the element with this id. */ @property({ type: String }) shell?: string; @state() private _rail: boolean = false; @state() private _locked: boolean = false; private _observed?: NileAppShell; public connectedCallback(): void { super.connectedCallback(); // The shell may upgrade after this element does, so read it on a microtask. Promise.resolve().then(() => this._attach()); } public disconnectedCallback(): void { super.disconnectedCallback(); this._observed?.removeEventListener('nile-nav-toggle', this._onShellToggle); this._observed = undefined; } /** The shell this toggle drives, if it found one. */ public get appShell(): NileAppShell | null { if (this.shell) { const root = this.getRootNode() as Document | ShadowRoot; return (root.querySelector(`#${this.shell}`) as NileAppShell) ?? null; } return this.closest('nile-app-shell') ?? null; } private _attach(): void { const shell = this.appShell; if (!shell || shell === this._observed) return; this._observed?.removeEventListener('nile-nav-toggle', this._onShellToggle); this._observed = shell; shell.addEventListener('nile-nav-toggle', this._onShellToggle); this._sync(); } private _onShellToggle = (): void => { this._sync(); }; private _sync(): void { const shell = this._observed; if (!shell) return; this._rail = shell.rail; this._locked = shell.navLocked; } public render(): TemplateResult { const expanded = !this._rail; return html` ${renderGlyph( expanded ? 'ng-panel-left' : 'ng-panel-right', 20, 'currentColor' )} `; } private _onClick = (): void => { this._attach(); this._observed?.toggleNav(); this._sync(); }; } export default NileAppShellNavToggle; declare global { interface HTMLElementTagNameMap { 'nile-app-shell-nav-toggle': NileAppShellNavToggle; } }