import './database-header-column.js'; import { ShadowlessElement, WithDisposable } from '@blockeditor/lit'; import { autoUpdate, computePosition, shift } from '@floating-ui/dom'; import { nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { createRef, ref } from 'lit/directives/ref.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; import { html } from 'lit/static-html.js'; import { renderTemplate } from '../../../../_common/components/uni-component/render-template.js'; import { AddCursorIcon } from '../../../../_common/icons/index.js'; import type { DataViewTableManager } from '../../table-view-manager.js'; import { styles } from './styles.js'; @customElement('affine-database-column-header') export class DatabaseColumnHeader extends WithDisposable(ShadowlessElement) { static override styles = styles; @property({ attribute: false }) tableViewManager!: DataViewTableManager; private get readonly() { return this.tableViewManager.readonly; } private addColumnPositionRef = createRef(); addColumnButton = renderTemplate(() => { if (this.readonly) return nothing; return html`
${AddCursorIcon}
`; }); public override connectedCallback() { super.connectedCallback(); this.disposables.add( this.tableViewManager.slots.update.on(() => { this.requestUpdate(); }) ); const group = this.closest('affine-data-view-table-group'); if (group) { this.disposables.addFromEvent(group, 'mouseenter', () => { this.addColumnButton.style.visibility = 'visible'; }); this.disposables.addFromEvent(group, 'mouseleave', () => { this.addColumnButton.style.visibility = 'hidden'; }); this.disposables.addFromEvent(this.addColumnButton, 'mouseenter', () => { this.addColumnButton.style.visibility = 'visible'; }); this.disposables.addFromEvent(this.addColumnButton, 'mouseleave', () => { this.addColumnButton.style.visibility = 'hidden'; }); this.addColumnButton.style.visibility = 'hidden'; this.addColumnButton.style.transition = 'visibility 0.2s'; this.addColumnButton.style.marginLeft = '20px'; this.addColumnButton.style.position = 'absolute'; this.addColumnButton.style.zIndex = '1'; this.closest('affine-data-view-native')?.append(this.addColumnButton); requestAnimationFrame(() => { const referenceEl = this.addColumnPositionRef.value; if (!referenceEl) { return; } const cleanup = autoUpdate( referenceEl, this.addColumnButton, this.updateAddButton ); this.disposables.add({ dispose: () => { cleanup(); this.addColumnButton.remove(); }, }); }); } } updateAddButton = () => { const referenceEl = this.addColumnPositionRef.value; if (!referenceEl) { return; } computePosition(referenceEl, this.addColumnButton, { middleware: [ shift({ boundary: this.closest('affine-database-table') ?? this, padding: -20, }), ], }) .then(({ x, y }) => { Object.assign(this.addColumnButton.style, { left: `${x}px`, top: `${y}px`, }); }) .catch(console.error); }; private _onAddColumn = () => { if (this.readonly) return; this.tableViewManager.columnAdd('end'); requestAnimationFrame(() => { this.editLastColumnTitle(); }); }; editLastColumnTitle = () => { const columns = this.querySelectorAll('affine-database-header-column'); const column = columns.item(columns.length - 1); column.scrollIntoView({ block: 'nearest', inline: 'nearest' }); column.editTitle(); }; override render() { this.updateAddButton(); return html`
${repeat( this.tableViewManager.columnManagerList, column => column.id, (column, index) => { const style = styleMap({ width: `${column.width}px`, border: index === 0 ? 'none' : undefined, }); return html` `; } )}
`; } } declare global { interface HTMLElementTagNameMap { 'affine-database-column-header': DatabaseColumnHeader; } }