import type { EventName, UIEventHandler } from '@blockeditor/block-std';
import { PathFinder } from '@blockeditor/block-std';
import type { Disposable } from '@blockeditor/global/utils';
import { assertExists, Slot } from '@blockeditor/global/utils';
import { ShadowlessElement, WithDisposable } from '@blockeditor/lit';
import type { PropertyValues } from 'lit';
import { css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { createModal } from '../../../../../_common/components/menu/index.js';
import { renderTemplate } from '../../../../../_common/components/uni-component/render-template.js';
import {
CrossIcon,
ExpandWideIcon,
} from '../../../../../_common/icons/index.js';
import type { DataViewSelection } from '../../../../../_common/utils/index.js';
import type { DataViewNativeConfig } from '../../../../data-view.js';
import type { DatabaseBlockComponent } from '../../../../database-block.js';
import { DatabaseSelection } from '../../../selection.js';
export function showDatabasePreviewModal(database: DatabaseBlockComponent) {
const viewComponent = new DatabaseBlockModalPreview();
viewComponent.database = database;
const root = document.querySelector('editor-host');
assertExists(root);
const modal = createModal(root);
const close = () => {
modal.remove();
};
const container = renderTemplate(() => {
return html`
`;
});
container.onclick = e => {
e.stopPropagation();
};
modal.onclick = close;
modal.style.backgroundColor = 'var(--affine-black-60)';
modal.append(container);
}
@customElement('expand-database-block-modal')
export class ExpandDatabaseBlockModal extends WithDisposable(
ShadowlessElement
) {
expandDatabase = () => {
const database = this.closest('affine-database');
if (database) {
showDatabasePreviewModal(database);
}
};
get database() {
return this.closest('affine-database');
}
protected override render(): unknown {
if (
this.closest('database-block-modal-preview') ||
!this.database?.page.awarenessStore.getFlag(
'enable_expand_database_block'
)
) {
return;
}
return html`
${ExpandWideIcon}
`;
}
}
@customElement('database-block-modal-preview')
export class DatabaseBlockModalPreview extends WithDisposable(
ShadowlessElement
) {
static override styles = css`
database-block-modal-preview {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
}
`;
path = ['modal', 'preview'];
@property({ attribute: false })
database!: DatabaseBlockComponent;
public override connectedCallback() {
super.connectedCallback();
this.database.selection.slots.changed.on(selections => {
const selection = selections.find(v => {
return PathFinder.equals(v.path, this.path);
});
if (selection && selection instanceof DatabaseSelection) {
this.selectionUpdated.emit(selection.viewSelection);
} else {
this.selectionUpdated.emit(undefined);
}
});
}
protected override firstUpdated(_changedProperties: PropertyValues) {
super.firstUpdated(_changedProperties);
requestAnimationFrame(() => {
this.querySelector('affine-data-view-native')?.focusFirstCell();
});
}
selectionUpdated: Slot = new Slot();
setSelection: (selection?: DataViewSelection) => void = selection => {
this.database.host.selection.set(
selection
? [new DatabaseSelection({ path: this.path, viewSelection: selection })]
: []
);
};
bindHotkey: (hotkeys: Record) => Disposable =
hotkeys => {
return {
dispose: this.database.host.event.bindHotkey(hotkeys, {
path: [],
}),
};
};
handleEvent: (name: EventName, handler: UIEventHandler) => Disposable = (
name,
handler
) => {
return {
dispose: this.database.host.event.add(name, handler, {
path: [],
}),
};
};
protected override render(): unknown {
const config: DataViewNativeConfig = {
bindHotkey: this.bindHotkey,
handleEvent: this.handleEvent,
getFlag: this.database.getFlag,
selectionUpdated: this.selectionUpdated,
setSelection: this.setSelection,
dataSource: this.database.dataSource,
viewSource: this.database.viewSource,
headerComponent: this.database.headerComponent,
std: this.database.std,
};
return html`
`;
}
}