import { createLitPortal } from '@blocksuite/affine-components/portal'; import { SignalWatcher } from '@blocksuite/global/lit'; import { ArrowDownSmallIcon, FlipDirectionIcon } from '@blocksuite/icons/lit'; import { flip, offset } from '@floating-ui/dom'; import { consume } from '@lit/context'; import { css, html, LitElement } from 'lit'; import { property, query } from 'lit/decorators.js'; import { type AdapterPanelContext, adapterPanelContext } from '../config'; export const AFFINE_ADAPTER_PANEL_HEADER = 'affine-adapter-panel-header'; export class AdapterPanelHeader extends SignalWatcher(LitElement) { static override styles = css` .adapter-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: var(--affine-background-primary-color); } .adapter-selector { display: flex; align-items: center; justify-content: space-between; width: 100px; cursor: pointer; border-radius: 4px; border: 1px solid var(--affine-border-color); padding: 4px 8px; } .adapter-selector:hover { background: var(--affine-hover-color); } .adapter-selector-label { display: flex; align-items: center; color: var(--affine-text-primary-color); font-size: var(--affine-font-xs); } .update-button { height: 20px; width: 20px; display: flex; align-items: center; justify-content: center; border-radius: 4px; cursor: pointer; color: var(--affine-icon-color); } .update-button:hover { background-color: var(--affine-hover-color); } `; get activeAdapter() { return this._context.activeAdapter$.value; } private _adapterMenuAbortController: AbortController | null = null; private readonly _toggleAdapterMenu = () => { if (this._adapterMenuAbortController) { this._adapterMenuAbortController.abort(); } this._adapterMenuAbortController = new AbortController(); createLitPortal({ template: html``, portalStyles: { zIndex: 'var(--affine-z-index-popover)', }, container: this._adapterPanelHeader, computePosition: { referenceElement: this._adapterSelector, placement: 'bottom-start', middleware: [flip(), offset(4)], autoUpdate: { animationFrame: true }, }, abortController: this._adapterMenuAbortController, closeOnClickAway: true, }); }; override render() { return html`
${this.activeAdapter.label} ${ArrowDownSmallIcon({ width: '16px', height: '16px' })}
${FlipDirectionIcon({ width: '16px', height: '16px' })}
`; } @query('.adapter-panel-header') private accessor _adapterPanelHeader!: HTMLDivElement; @query('.adapter-selector') private accessor _adapterSelector!: HTMLDivElement; @property({ attribute: false }) accessor updateActiveContent: () => void = () => {}; @consume({ context: adapterPanelContext }) private accessor _context!: AdapterPanelContext; } declare global { interface HTMLElementTagNameMap { [AFFINE_ADAPTER_PANEL_HEADER]: AdapterPanelHeader; } }