import { menu, popFilterableSimpleMenu, popupTargetFromElement, } from '@blocksuite/affine-components/context-menu'; import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit'; import { PlusIcon } from '@blocksuite/icons/lit'; import { ShadowlessElement } from '@blocksuite/std'; import { effect } from '@preact/signals-core'; import { cssVarV2 } from '@toeverything/theme/v2'; import { css, html, unsafeCSS } from 'lit'; import { property, query } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { GroupTitle } from '../../../core/group-by/group-title.js'; import type { Group } from '../../../core/group-by/trait.js'; import type { Row } from '../../../core/index.js'; import { createDndContext } from '../../../core/utils/wc-dnd/dnd-context.js'; import { defaultActivators } from '../../../core/utils/wc-dnd/sensors/index.js'; import { linearMove } from '../../../core/utils/wc-dnd/utils/linear-move.js'; import { LEFT_TOOL_BAR_WIDTH } from '../consts.js'; import { TableViewAreaSelection } from '../selection'; import { DataViewColumnPreview } from './header/column-renderer.js'; import { getVerticalIndicator } from './header/vertical-indicator.js'; import type { TableViewUILogic } from './table-view-ui-logic.js'; const styles = css` affine-data-view-table-group:hover .group-header-op { visibility: visible; opacity: 1; } .data-view-table-group-add-row { display: flex; width: 100%; height: 28px; position: relative; z-index: 0; cursor: pointer; transition: opacity 0.2s ease-in-out; padding: 4px 8px; border-bottom: 1px solid ${unsafeCSS(cssVarV2.layer.insideBorder.border)}; } @media print { .data-view-table-group-add-row { display: none; } } .data-view-table-group-add-row-button { position: sticky; left: ${8 + LEFT_TOOL_BAR_WIDTH}px; display: flex; align-items: center; justify-content: center; gap: 10px; user-select: none; font-size: 12px; line-height: 20px; color: var(--affine-text-secondary-color); } `; export class TableGroup extends SignalWatcher( WithDisposable(ShadowlessElement) ) { static override styles = styles; private readonly clickAddRow = () => { this.view.rowAdd('end', this.group?.key); const selectionController = this.tableViewLogic.selectionController; selectionController.selection = undefined; requestAnimationFrame(() => { const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: this.rows.length - 1, columnIndex: index, }, isEditing: true, }); this.requestUpdate(); }); }; private readonly clickAddRowInStart = () => { this.view.rowAdd('start', this.group?.key); const selectionController = this.tableViewLogic.selectionController; selectionController.selection = undefined; requestAnimationFrame(() => { const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: 0, columnIndex: index, }, isEditing: true, }); this.requestUpdate(); }); }; private readonly clickGroupOptions = (e: MouseEvent) => { const group = this.group; if (!group) { return; } const ele = e.currentTarget as HTMLElement; popFilterableSimpleMenu(popupTargetFromElement(ele), [ menu.action({ name: 'Ungroup', hide: () => group.value == null, select: () => { group.rows.forEach(row => { group.manager.removeFromGroup(row.rowId, group.key); }); }, }), menu.action({ name: 'Delete Cards', select: () => { this.view.rowsDelete(group.rows.map(row => row.rowId)); this.requestUpdate(); }, }), ]); }; private readonly renderGroupHeader = () => { if (!this.group) { return null; } return html`