From aa21ac6d6434a8eda53f7de718f77b9cbd297cc4 Mon Sep 17 00:00:00 2001 From: zzj3720 <17165520+zzj3720@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:03:13 +0000 Subject: [PATCH] refactor(editor): move database selection into the corresponding view (#9752) --- .../block-data-view/src/data-view-block.ts | 7 +- .../block-database/src/database-block.ts | 2 +- blocksuite/affine/block-database/src/index.ts | 1 + .../affine/block-database/src/selection.ts | 76 ++++++++++ .../affine/data-view/src/core/common/index.ts | 1 - .../src/core/common/selection-schema.ts | 133 ------------------ .../data-view/src/core/detail/selection.ts | 2 +- blocksuite/affine/data-view/src/core/types.ts | 18 +-- .../src/view-presets/kanban/index.ts | 1 + .../view-presets/kanban/mobile/kanban-view.ts | 2 +- .../src/view-presets/kanban/pc/cell.ts | 2 +- .../kanban/pc/controller/clipboard.ts | 2 +- .../kanban/pc/controller/selection.ts | 2 +- .../src/view-presets/kanban/pc/kanban-view.ts | 2 +- .../src/view-presets/kanban/selection.ts | 50 +++++++ .../src/view-presets/kanban/types.ts | 32 ----- .../data-view/src/view-presets/table/index.ts | 1 + .../src/view-presets/table/mobile/cell.ts | 4 +- .../src/view-presets/table/mobile/group.ts | 6 +- .../view-presets/table/mobile/table-view.ts | 2 +- .../src/view-presets/table/pc/cell.ts | 10 +- .../table/pc/controller/clipboard.ts | 18 +-- .../table/pc/controller/drag-to-fill.ts | 4 +- .../table/pc/controller/hotkeys.ts | 90 ++++++------ .../table/pc/controller/selection.ts | 30 ++-- .../src/view-presets/table/pc/group.ts | 6 +- .../src/view-presets/table/pc/menu.ts | 6 +- .../table/pc/row/row-select-checkbox.ts | 6 +- .../src/view-presets/table/pc/row/row.ts | 15 +- .../src/view-presets/table/pc/table-view.ts | 2 +- .../src/view-presets/table/selection.ts | 123 ++++++++++++++++ .../data-view/src/view-presets/table/types.ts | 105 -------------- blocksuite/blocks/src/_specs/common.ts | 6 +- .../widgets/format-bar/format-bar.ts | 2 +- 34 files changed, 375 insertions(+), 394 deletions(-) create mode 100644 blocksuite/affine/block-database/src/selection.ts delete mode 100644 blocksuite/affine/data-view/src/core/common/selection-schema.ts create mode 100644 blocksuite/affine/data-view/src/view-presets/kanban/selection.ts delete mode 100644 blocksuite/affine/data-view/src/view-presets/kanban/types.ts create mode 100644 blocksuite/affine/data-view/src/view-presets/table/selection.ts diff --git a/blocksuite/affine/block-data-view/src/data-view-block.ts b/blocksuite/affine/block-data-view/src/data-view-block.ts index 3d03e23e52..6cd10b792c 100644 --- a/blocksuite/affine/block-data-view/src/data-view-block.ts +++ b/blocksuite/affine/block-data-view/src/data-view-block.ts @@ -1,4 +1,8 @@ -import { BlockRenderer, NoteRenderer } from '@blocksuite/affine-block-database'; +import { + BlockRenderer, + DatabaseSelection, + NoteRenderer, +} from '@blocksuite/affine-block-database'; import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption'; import { menu, @@ -26,7 +30,6 @@ import { import { createRecordDetail, createUniComponentFromWebComponent, - DatabaseSelection, type DataSource, DataView, dataViewCommonStyle, diff --git a/blocksuite/affine/block-database/src/database-block.ts b/blocksuite/affine/block-database/src/database-block.ts index 46e94693d6..c54ee352c9 100644 --- a/blocksuite/affine/block-database/src/database-block.ts +++ b/blocksuite/affine/block-database/src/database-block.ts @@ -23,7 +23,6 @@ import { import { createRecordDetail, createUniComponentFromWebComponent, - DatabaseSelection, DataView, dataViewCommonStyle, type DataViewInstance, @@ -55,6 +54,7 @@ import { DatabaseBlockDataSource } from './data-source.js'; import type { DatabaseBlockService } from './database-service.js'; import { BlockRenderer } from './detail-panel/block-renderer.js'; import { NoteRenderer } from './detail-panel/note-renderer.js'; +import { DatabaseSelection } from './selection.js'; import { currentViewStorage } from './utils/current-view.js'; import { getSingleDocIdFromText } from './utils/title-doc.js'; diff --git a/blocksuite/affine/block-database/src/index.ts b/blocksuite/affine/block-database/src/index.ts index 9c9eab562e..6d826b0dd3 100644 --- a/blocksuite/affine/block-database/src/index.ts +++ b/blocksuite/affine/block-database/src/index.ts @@ -13,4 +13,5 @@ export * from './detail-panel/note-renderer'; export * from './properties'; export * from './properties/rich-text/cell-renderer'; export * from './properties/utils'; +export * from './selection.js'; export * from './utils/block-utils'; diff --git a/blocksuite/affine/block-database/src/selection.ts b/blocksuite/affine/block-database/src/selection.ts new file mode 100644 index 0000000000..5f660668aa --- /dev/null +++ b/blocksuite/affine/block-database/src/selection.ts @@ -0,0 +1,76 @@ +import type { DataViewSelection } from '@blocksuite/data-view'; +import { + KanbanViewSelectionWithTypeSchema, + TableViewSelectionWithTypeSchema, +} from '@blocksuite/data-view/view-presets'; +import { BaseSelection, SelectionExtension } from '@blocksuite/store'; +import { z } from 'zod'; + +const ViewSelectionSchema = z.union([ + TableViewSelectionWithTypeSchema, + KanbanViewSelectionWithTypeSchema, +]); + +const DatabaseSelectionSchema = z.object({ + blockId: z.string(), + viewSelection: ViewSelectionSchema, +}); + +export class DatabaseSelection extends BaseSelection { + static override group = 'note'; + + static override type = 'database'; + + readonly viewSelection: DataViewSelection; + + get viewId() { + return this.viewSelection.viewId; + } + + constructor({ + blockId, + viewSelection, + }: { + blockId: string; + viewSelection: DataViewSelection; + }) { + super({ + blockId, + }); + + this.viewSelection = viewSelection; + } + + static override fromJSON(json: Record): DatabaseSelection { + const { blockId, viewSelection } = DatabaseSelectionSchema.parse(json); + return new DatabaseSelection({ + blockId, + viewSelection: viewSelection, + }); + } + + override equals(other: BaseSelection): boolean { + if (!(other instanceof DatabaseSelection)) { + return false; + } + return this.blockId === other.blockId; + } + + override toJSON(): Record { + return { + type: 'database', + blockId: this.blockId, + viewSelection: this.viewSelection, + }; + } +} + +declare global { + namespace BlockSuite { + interface Selection { + database: typeof DatabaseSelection; + } + } +} + +export const DatabaseSelectionExtension = SelectionExtension(DatabaseSelection); diff --git a/blocksuite/affine/data-view/src/core/common/index.ts b/blocksuite/affine/data-view/src/core/common/index.ts index bab3f2282b..e0b4fbacae 100644 --- a/blocksuite/affine/data-view/src/core/common/index.ts +++ b/blocksuite/affine/data-view/src/core/common/index.ts @@ -5,5 +5,4 @@ export * from '../group-by/matcher.js'; export type { GroupByConfig } from '../group-by/types.js'; export type { GroupRenderProps } from '../group-by/types.js'; export * from './css-variable.js'; -export * from './selection-schema.js'; export * from './types.js'; diff --git a/blocksuite/affine/data-view/src/core/common/selection-schema.ts b/blocksuite/affine/data-view/src/core/common/selection-schema.ts deleted file mode 100644 index 76e0b90393..0000000000 --- a/blocksuite/affine/data-view/src/core/common/selection-schema.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { BaseSelection, SelectionExtension } from '@blocksuite/store'; -import { z } from 'zod'; - -import type { DataViewSelection, GetDataViewSelection } from '../types.js'; - -const TableViewSelectionSchema = z.union([ - z.object({ - viewId: z.string(), - type: z.literal('table'), - selectionType: z.literal('area'), - rowsSelection: z.object({ - start: z.number(), - end: z.number(), - }), - columnsSelection: z.object({ - start: z.number(), - end: z.number(), - }), - focus: z.object({ - rowIndex: z.number(), - columnIndex: z.number(), - }), - isEditing: z.boolean(), - }), - z.object({ - viewId: z.string(), - type: z.literal('table'), - selectionType: z.literal('row'), - rows: z.array( - z.object({ id: z.string(), groupKey: z.string().optional() }) - ), - }), -]); - -const KanbanCellSelectionSchema = z.object({ - selectionType: z.literal('cell'), - groupKey: z.string(), - cardId: z.string(), - columnId: z.string(), - isEditing: z.boolean(), -}); - -const KanbanCardSelectionSchema = z.object({ - selectionType: z.literal('card'), - cards: z.array( - z.object({ - groupKey: z.string(), - cardId: z.string(), - }) - ), -}); - -const KanbanGroupSelectionSchema = z.object({ - selectionType: z.literal('group'), - groupKeys: z.array(z.string()), -}); - -const DatabaseSelectionSchema = z.object({ - blockId: z.string(), - viewSelection: z.union([ - TableViewSelectionSchema, - KanbanCellSelectionSchema, - KanbanCardSelectionSchema, - KanbanGroupSelectionSchema, - ]), -}); - -export class DatabaseSelection extends BaseSelection { - static override group = 'note'; - - static override type = 'database'; - - readonly viewSelection: DataViewSelection; - - get viewId() { - return this.viewSelection.viewId; - } - - constructor({ - blockId, - viewSelection, - }: { - blockId: string; - viewSelection: DataViewSelection; - }) { - super({ - blockId, - }); - - this.viewSelection = viewSelection; - } - - static override fromJSON(json: Record): DatabaseSelection { - DatabaseSelectionSchema.parse(json); - return new DatabaseSelection({ - blockId: json.blockId as string, - viewSelection: json.viewSelection as DataViewSelection, - }); - } - - override equals(other: BaseSelection): boolean { - if (!(other instanceof DatabaseSelection)) { - return false; - } - return this.blockId === other.blockId; - } - - getSelection( - type: T - ): GetDataViewSelection | undefined { - return this.viewSelection.type === type - ? (this.viewSelection as GetDataViewSelection) - : undefined; - } - - override toJSON(): Record { - return { - type: 'database', - blockId: this.blockId, - viewSelection: this.viewSelection, - }; - } -} - -declare global { - namespace BlockSuite { - interface Selection { - database: typeof DatabaseSelection; - } - } -} - -export const DatabaseSelectionExtension = SelectionExtension(DatabaseSelection); diff --git a/blocksuite/affine/data-view/src/core/detail/selection.ts b/blocksuite/affine/data-view/src/core/detail/selection.ts index a0ab39daf2..2493b6111f 100644 --- a/blocksuite/affine/data-view/src/core/detail/selection.ts +++ b/blocksuite/affine/data-view/src/core/detail/selection.ts @@ -1,6 +1,6 @@ +import type { KanbanCardSelection } from '../../view-presets'; import type { KanbanCard } from '../../view-presets/kanban/pc/card.js'; import { KanbanCell } from '../../view-presets/kanban/pc/cell.js'; -import type { KanbanCardSelection } from '../../view-presets/kanban/types.js'; import type { RecordDetail } from './detail.js'; import { RecordField } from './field.js'; diff --git a/blocksuite/affine/data-view/src/core/types.ts b/blocksuite/affine/data-view/src/core/types.ts index 033dd04e7f..42d15b2331 100644 --- a/blocksuite/affine/data-view/src/core/types.ts +++ b/blocksuite/affine/data-view/src/core/types.ts @@ -1,17 +1,11 @@ -import type { KanbanViewSelectionWithType } from '../view-presets/kanban/types.js'; -import type { TableViewSelectionWithType } from '../view-presets/table/types.js'; +import type { + KanbanViewSelectionWithType, + TableViewSelectionWithType, +} from '../view-presets'; export type DataViewSelection = | TableViewSelectionWithType | KanbanViewSelectionWithType; -export type GetDataViewSelection< - K extends DataViewSelection['type'], - T = DataViewSelection, -> = T extends { - type: K; -} - ? T - : never; export type DataViewSelectionState = DataViewSelection | undefined; export type PropertyDataUpdater< Data extends Record = Record, @@ -20,7 +14,3 @@ export type PropertyDataUpdater< export interface DatabaseFlags { enable_number_formatting: boolean; } - -export const defaultDatabaseFlags: Readonly = { - enable_number_formatting: false, -}; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/index.ts b/blocksuite/affine/data-view/src/view-presets/kanban/index.ts index b83489afcb..848cbb8805 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/index.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/index.ts @@ -2,3 +2,4 @@ export * from './define.js'; export * from './kanban-view-manager.js'; export * from './pc/kanban-view.js'; export * from './renderer.js'; +export * from './selection.js'; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/mobile/kanban-view.ts b/blocksuite/affine/data-view/src/view-presets/kanban/mobile/kanban-view.ts index 73128a9a3b..82b77a0bb2 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/mobile/kanban-view.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/mobile/kanban-view.ts @@ -14,7 +14,7 @@ import { type DataViewInstance, renderUniLit } from '../../../core/index.js'; import { sortable } from '../../../core/utils/wc-dnd/sort/sort-context.js'; import { DataViewBase } from '../../../core/view/data-view-base.js'; import type { KanbanSingleView } from '../kanban-view-manager.js'; -import type { KanbanViewSelectionWithType } from '../types.js'; +import type { KanbanViewSelectionWithType } from '../selection'; const styles = css` mobile-data-view-kanban { diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/cell.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/cell.ts index 8deef53dae..f58be98175 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/cell.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/cell.ts @@ -14,7 +14,7 @@ import type { import { renderUniLit } from '../../../core/utils/uni-component/uni-component.js'; import type { Property } from '../../../core/view-manager/property.js'; import type { KanbanSingleView } from '../kanban-view-manager.js'; -import type { KanbanViewSelection } from '../types.js'; +import type { KanbanViewSelection } from '../selection'; const styles = css` affine-data-view-kanban-cell { diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/clipboard.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/clipboard.ts index d45206ea98..267ea150b6 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/clipboard.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/clipboard.ts @@ -1,7 +1,7 @@ import type { UIEventStateContext } from '@blocksuite/block-std'; import type { ReactiveController } from 'lit'; -import type { KanbanViewSelectionWithType } from '../../types.js'; +import type { KanbanViewSelectionWithType } from '../../selection'; import type { DataViewKanban } from '../kanban-view.js'; export class KanbanClipboardController implements ReactiveController { diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts index 17ea1caf77..573e5d76cf 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts @@ -9,7 +9,7 @@ import type { KanbanGroupSelection, KanbanViewSelection, KanbanViewSelectionWithType, -} from '../../types.js'; +} from '../../selection'; import { KanbanCard } from '../card.js'; import { KanbanCell } from '../cell.js'; import type { KanbanGroup } from '../group.js'; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts index 46f6b7237b..ee45634c81 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts @@ -20,7 +20,7 @@ import { import { horizontalListSortingStrategy } from '../../../core/utils/wc-dnd/sort/strategies/index.js'; import { DataViewBase } from '../../../core/view/data-view-base.js'; import type { KanbanSingleView } from '../kanban-view-manager.js'; -import type { KanbanViewSelectionWithType } from '../types.js'; +import type { KanbanViewSelectionWithType } from '../selection'; import { KanbanClipboardController } from './controller/clipboard.js'; import { KanbanDragController } from './controller/drag.js'; import { KanbanHotkeysController } from './controller/hotkeys.js'; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/selection.ts b/blocksuite/affine/data-view/src/view-presets/kanban/selection.ts new file mode 100644 index 0000000000..1490b528b6 --- /dev/null +++ b/blocksuite/affine/data-view/src/view-presets/kanban/selection.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; + +export const KanbanViewTypeSchema = z.object({ + viewId: z.string(), + type: z.literal('kanban'), +}); +export const KanbanCellSelectionSchema = z.object({ + selectionType: z.literal('cell'), + groupKey: z.string(), + cardId: z.string(), + columnId: z.string(), + isEditing: z.boolean(), +}); + +const KanbanCardSelectionCardSchema = z.object({ + groupKey: z.string(), + cardId: z.string(), +}); +export const KanbanCardSelectionSchema = z.object({ + selectionType: z.literal('card'), + cards: z + .tuple([KanbanCardSelectionCardSchema]) + .rest(KanbanCardSelectionCardSchema), +}); + +export const KanbanGroupSelectionSchema = z.object({ + selectionType: z.literal('group'), + groupKeys: z.tuple([z.string()]).rest(z.string()), +}); + +export const KanbanViewSelectionSchema = z.union([ + KanbanCellSelectionSchema, + KanbanCardSelectionSchema, + KanbanGroupSelectionSchema, +]); +export const KanbanViewSelectionWithTypeSchema = z.union([ + z.intersection(KanbanViewTypeSchema, KanbanCellSelectionSchema), + z.intersection(KanbanViewTypeSchema, KanbanCardSelectionSchema), + z.intersection(KanbanViewTypeSchema, KanbanGroupSelectionSchema), +]); +export type KanbanCellSelection = z.TypeOf; +export type KanbanCardSelectionCard = z.TypeOf< + typeof KanbanCardSelectionCardSchema +>; +export type KanbanCardSelection = z.TypeOf; +export type KanbanGroupSelection = z.TypeOf; +export type KanbanViewSelection = z.TypeOf; +export type KanbanViewSelectionWithType = z.TypeOf< + typeof KanbanViewSelectionWithTypeSchema +>; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/types.ts b/blocksuite/affine/data-view/src/view-presets/kanban/types.ts deleted file mode 100644 index f79dbdcf51..0000000000 --- a/blocksuite/affine/data-view/src/view-presets/kanban/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -type WithKanbanViewType = T extends unknown - ? { - viewId: string; - type: 'kanban'; - } & T - : never; - -export type KanbanCellSelection = { - selectionType: 'cell'; - groupKey: string; - cardId: string; - columnId: string; - isEditing: boolean; -}; -export type KanbanCardSelectionCard = { - groupKey: string; - cardId: string; -}; -export type KanbanCardSelection = { - selectionType: 'card'; - cards: [KanbanCardSelectionCard, ...KanbanCardSelectionCard[]]; -}; -export type KanbanGroupSelection = { - selectionType: 'group'; - groupKeys: [string, ...string[]]; -}; -export type KanbanViewSelection = - | KanbanCellSelection - | KanbanCardSelection - | KanbanGroupSelection; -export type KanbanViewSelectionWithType = - WithKanbanViewType; diff --git a/blocksuite/affine/data-view/src/view-presets/table/index.ts b/blocksuite/affine/data-view/src/view-presets/table/index.ts index 7f11c0fe16..58fe1f7dfa 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/index.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/index.ts @@ -1,4 +1,5 @@ export * from './define.js'; export * from './pc/table-view.js'; export * from './renderer.js'; +export * from './selection.js'; export * from './table-view-manager.js'; diff --git a/blocksuite/affine/data-view/src/view-presets/table/mobile/cell.ts b/blocksuite/affine/data-view/src/view-presets/table/mobile/cell.ts index a55f9f6619..aa29beaf35 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/mobile/cell.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/mobile/cell.ts @@ -11,8 +11,8 @@ import { renderUniLit, type SingleView, } from '../../../core/index.js'; +import { TableViewAreaSelection } from '../selection'; import type { TableColumn } from '../table-view-manager.js'; -import { TableAreaSelection } from '../types.js'; export class MobileTableCell extends SignalWatcher( WithDisposable(ShadowlessElement) @@ -78,7 +78,7 @@ export class MobileTableCell extends SignalWatcher( setSelection({ viewId, type: 'table', - ...TableAreaSelection.create({ + ...TableViewAreaSelection.create({ groupKey: this.groupKey, focus: { rowIndex: this.rowIndex, diff --git a/blocksuite/affine/data-view/src/view-presets/table/mobile/group.ts b/blocksuite/affine/data-view/src/view-presets/table/mobile/group.ts index 0911f6fbab..9d06404271 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/mobile/group.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/mobile/group.ts @@ -15,8 +15,8 @@ import { GroupTitle } from '../../../core/group-by/group-title.js'; import type { GroupData } from '../../../core/group-by/trait.js'; import { LEFT_TOOL_BAR_WIDTH } from '../consts.js'; import type { DataViewTable } from '../pc/table-view.js'; +import { TableViewAreaSelection } from '../selection'; import type { TableSingleView } from '../table-view-manager.js'; -import { TableAreaSelection } from '../types.js'; const styles = css` .data-view-table-group-add-row { @@ -57,7 +57,7 @@ export class MobileTableGroup extends SignalWatcher( const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); - selectionController.selection = TableAreaSelection.create({ + selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: this.rows.length - 1, @@ -75,7 +75,7 @@ export class MobileTableGroup extends SignalWatcher( const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); - selectionController.selection = TableAreaSelection.create({ + selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: 0, diff --git a/blocksuite/affine/data-view/src/view-presets/table/mobile/table-view.ts b/blocksuite/affine/data-view/src/view-presets/table/mobile/table-view.ts index ab8c9abf2b..4fe28ddaa5 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/mobile/table-view.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/mobile/table-view.ts @@ -16,8 +16,8 @@ import type { DataViewInstance } from '../../../core/index.js'; import { renderUniLit } from '../../../core/utils/uni-component/uni-component.js'; import { DataViewBase } from '../../../core/view/data-view-base.js'; import { LEFT_TOOL_BAR_WIDTH } from '../consts.js'; +import type { TableViewSelectionWithType } from '../selection'; import type { TableSingleView } from '../table-view-manager.js'; -import type { TableViewSelectionWithType } from '../types.js'; export class MobileDataViewTable extends DataViewBase< TableSingleView, diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts index 7508728f8d..044492124a 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts @@ -15,11 +15,11 @@ import type { DataViewCellLifeCycle, } from '../../../core/property/index.js'; import type { SingleView } from '../../../core/view-manager/single-view.js'; -import type { TableColumn } from '../table-view-manager.js'; import { - TableAreaSelection, + TableViewAreaSelection, type TableViewSelectionWithType, -} from '../types.js'; +} from '../selection'; +import type { TableColumn } from '../table-view-manager.js'; export class DatabaseCellContainer extends SignalWatcher( WithDisposable(ShadowlessElement) @@ -63,7 +63,7 @@ export class DatabaseCellContainer extends SignalWatcher( if (selectionView) { const selection = selectionView.selection; if (selection && this.isSelected(selection) && editing) { - selectionView.selection = TableAreaSelection.create({ + selectionView.selection = TableViewAreaSelection.create({ groupKey: this.groupKey, focus: { rowIndex: this.rowIndex, @@ -72,7 +72,7 @@ export class DatabaseCellContainer extends SignalWatcher( isEditing: true, }); } else { - selectionView.selection = TableAreaSelection.create({ + selectionView.selection = TableViewAreaSelection.create({ groupKey: this.groupKey, focus: { rowIndex: this.rowIndex, diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/clipboard.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/clipboard.ts index f80a8c85ef..42b116961d 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/clipboard.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/clipboard.ts @@ -4,11 +4,11 @@ import type { ReactiveController } from 'lit'; import type { Cell } from '../../../../core/view-manager/cell.js'; import type { Row } from '../../../../core/view-manager/row.js'; import { - TableAreaSelection, - TableRowSelection, + TableViewAreaSelection, + TableViewRowSelection, type TableViewSelection, type TableViewSelectionWithType, -} from '../../types.js'; +} from '../../selection'; import type { DataViewTable } from '../table-view.js'; const BLOCKSUITE_DATABASE_TABLE = 'blocksuite/database/table'; @@ -85,7 +85,7 @@ export class TableClipboardController implements ReactiveController { if (!clipboardData) return; const tableSelection = this.host.selectionController.selection; - if (TableRowSelection.is(tableSelection)) { + if (TableViewRowSelection.is(tableSelection)) { return; } if (tableSelection) { @@ -196,8 +196,8 @@ function getSelectedArea( table: DataViewTable ): SelectedArea | undefined { const view = table.props.view; - if (TableRowSelection.is(selection)) { - const rows = TableRowSelection.rows(selection) + if (TableViewRowSelection.is(selection)) { + const rows = TableViewRowSelection.rows(selection) .map(row => { const y = table.selectionController @@ -255,11 +255,11 @@ type SelectedArea = { }[]; function getTargetRangeFromSelection( - selection: TableAreaSelection, + selection: TableViewAreaSelection, data: JsonAreaData ) { const { rowsSelection, columnsSelection, focus } = selection; - return TableAreaSelection.isFocus(selection) + return TableViewAreaSelection.isFocus(selection) ? { row: { start: focus.rowIndex, @@ -285,7 +285,7 @@ function getTargetRangeFromSelection( function pasteToCells( table: DataViewTable, rows: JsonAreaData, - selection: TableAreaSelection + selection: TableViewAreaSelection ) { const srcRowLength = rows.length; const srcColumnLength = rows[0]?.length ?? 0; diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts index 2c8f9af16d..6799584ed1 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts @@ -7,7 +7,7 @@ import { createRef, ref } from 'lit/directives/ref.js'; import * as Y from 'yjs'; import { t } from '../../../../core/index.js'; -import type { TableAreaSelection } from '../../types.js'; +import type { TableViewAreaSelection } from '../../selection'; import type { DataViewTable } from '../table-view.js'; export class DragToFillElement extends ShadowlessElement { @@ -50,7 +50,7 @@ export class DragToFillElement extends ShadowlessElement { export function fillSelectionWithFocusCellData( host: DataViewTable, - selection: TableAreaSelection + selection: TableViewAreaSelection ) { const { groupKey, rowsSelection, columnsSelection, focus } = selection; diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/hotkeys.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/hotkeys.ts index 0c8ffdf289..e44ec382d2 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/hotkeys.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/hotkeys.ts @@ -1,7 +1,7 @@ import { popupTargetFromElement } from '@blocksuite/affine-components/context-menu'; import type { ReactiveController } from 'lit'; -import { TableAreaSelection, TableRowSelection } from '../../types.js'; +import { TableViewAreaSelection, TableViewRowSelection } from '../../selection'; import { popRowMenu } from '../menu.js'; import type { DataViewTable } from '../table-view.js'; @@ -22,8 +22,8 @@ export class TableHotkeysController implements ReactiveController { if (!selection) { return; } - if (TableRowSelection.is(selection)) { - const rows = TableRowSelection.rowsIds(selection); + if (TableViewRowSelection.is(selection)) { + const rows = TableViewRowSelection.rowsIds(selection); this.selectionController.selection = undefined; this.host.props.view.rowDelete(rows); return; @@ -73,23 +73,24 @@ export class TableHotkeysController implements ReactiveController { if (!selection) { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { const result = this.selectionController.rowsToArea( selection.rows.map(v => v.id) ); if (result) { - this.selectionController.selection = TableAreaSelection.create({ - groupKey: result.groupKey, - focus: { - rowIndex: result.start, - columnIndex: 0, - }, - rowsSelection: { - start: result.start, - end: result.end, - }, - isEditing: false, - }); + this.selectionController.selection = + TableViewAreaSelection.create({ + groupKey: result.groupKey, + focus: { + rowIndex: result.start, + columnIndex: 0, + }, + rowsSelection: { + start: result.start, + end: result.end, + }, + isEditing: false, + }); } else { this.selectionController.selection = undefined; } @@ -112,23 +113,24 @@ export class TableHotkeysController implements ReactiveController { if (!selection) { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { const result = this.selectionController.rowsToArea( selection.rows.map(v => v.id) ); if (result) { - this.selectionController.selection = TableAreaSelection.create({ - groupKey: result.groupKey, - focus: { - rowIndex: result.start, - columnIndex: 0, - }, - rowsSelection: { - start: result.start, - end: result.end, - }, - isEditing: false, - }); + this.selectionController.selection = + TableViewAreaSelection.create({ + groupKey: result.groupKey, + focus: { + rowIndex: result.start, + columnIndex: 0, + }, + rowsSelection: { + start: result.start, + end: result.end, + }, + isEditing: false, + }); } } else if (selection.isEditing) { return false; @@ -145,7 +147,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing ) { return false; @@ -167,7 +169,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing ) { return false; @@ -180,7 +182,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing ) { return false; @@ -193,7 +195,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing ) { return false; @@ -206,7 +208,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing ) { return false; @@ -221,7 +223,7 @@ export class TableHotkeysController implements ReactiveController { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { this.selectionController.navigateRowSelection('up', false); } else if (selection.isEditing) { return false; @@ -238,7 +240,7 @@ export class TableHotkeysController implements ReactiveController { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { this.selectionController.navigateRowSelection('down', false); } else if (selection.isEditing) { return false; @@ -256,7 +258,7 @@ export class TableHotkeysController implements ReactiveController { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { this.selectionController.navigateRowSelection('up', true); } else if (selection.isEditing) { return false; @@ -274,7 +276,7 @@ export class TableHotkeysController implements ReactiveController { return false; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { this.selectionController.navigateRowSelection('down', true); } else if (selection.isEditing) { return false; @@ -290,7 +292,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing || this.selectionController.isRowSelection() ) { @@ -307,7 +309,7 @@ export class TableHotkeysController implements ReactiveController { const selection = this.selectionController.selection; if ( !selection || - TableRowSelection.is(selection) || + TableViewRowSelection.is(selection) || selection.isEditing || this.selectionController.isRowSelection() ) { @@ -322,7 +324,7 @@ export class TableHotkeysController implements ReactiveController { 'Mod-a': context => { const selection = this.selectionController.selection; - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { return false; } if (selection?.isEditing) { @@ -330,7 +332,7 @@ export class TableHotkeysController implements ReactiveController { } if (selection) { context.get('keyboardState').raw.preventDefault(); - this.selectionController.selection = TableRowSelection.create({ + this.selectionController.selection = TableViewRowSelection.create({ rows: this.host.props.view.groupTrait.groupsDataList$.value?.flatMap( group => @@ -350,7 +352,7 @@ export class TableHotkeysController implements ReactiveController { if (!selection) { return; } - if (TableRowSelection.is(selection)) { + if (TableViewRowSelection.is(selection)) { // open multi-rows context-menu return; } @@ -368,7 +370,7 @@ export class TableHotkeysController implements ReactiveController { id: cell.rowId, groupKey: selection.groupKey, }; - this.selectionController.selection = TableRowSelection.create({ + this.selectionController.selection = TableViewRowSelection.create({ rows: [row], }); popRowMenu( diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts index f87c69a384..d6b0ed9435 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts @@ -13,11 +13,11 @@ import { type CellFocus, type MultiSelection, RowWithGroup, - TableAreaSelection, - TableRowSelection, + TableViewAreaSelection, + TableViewRowSelection, type TableViewSelection, type TableViewSelectionWithType, -} from '../../types.js'; +} from '../../selection'; import type { DatabaseCellContainer } from '../cell.js'; import type { TableRow } from '../row/row.js'; import type { DataViewTable } from '../table-view.js'; @@ -240,7 +240,7 @@ export class TableSelectionController implements ReactiveController { const index = this.host.props.view.properties$.value.findIndex( v => v.type$.value === 'title' ); - this.selection = TableAreaSelection.create({ + this.selection = TableViewAreaSelection.create({ groupKey: groupKey, focus: { rowIndex: rows?.findIndex(v => v === id) ?? 0, @@ -279,7 +279,7 @@ export class TableSelectionController implements ReactiveController { }); } - areaToRows(selection: TableAreaSelection) { + areaToRows(selection: TableViewAreaSelection) { const rows = this.rows(selection.groupKey) ?? []; const ids = Array.from({ length: selection.rowsSelection.end - selection.rowsSelection.start + 1, @@ -350,7 +350,7 @@ export class TableSelectionController implements ReactiveController { } focusFirstCell() { - this.selection = TableAreaSelection.create({ + this.selection = TableViewAreaSelection.create({ focus: { rowIndex: 0, columnIndex: 0, @@ -359,7 +359,7 @@ export class TableSelectionController implements ReactiveController { }); } - focusToArea(selection: TableAreaSelection) { + focusToArea(selection: TableViewAreaSelection) { return { ...selection, rowsSelection: selection.rowsSelection ?? { @@ -371,7 +371,7 @@ export class TableSelectionController implements ReactiveController { end: selection.focus.columnIndex, }, isEditing: false, - } satisfies TableAreaSelection; + } satisfies TableViewAreaSelection; } focusToCell(position: 'left' | 'right' | 'up' | 'down') { @@ -544,7 +544,7 @@ export class TableSelectionController implements ReactiveController { } navigateRowSelection(direction: 'up' | 'down', append = false) { - if (!TableRowSelection.is(this.selection)) return; + if (!TableViewRowSelection.is(this.selection)) return; const rows = this.selection.rows; const lastRow = rows[rows.length - 1]; if (!lastRow) return; @@ -593,7 +593,7 @@ export class TableSelectionController implements ReactiveController { } else { const target = direction === 'up' ? prevRow : nextRow; if (target != null) { - this.selection = TableRowSelection.create({ + this.selection = TableViewRowSelection.create({ rows: [target], }); } @@ -619,7 +619,7 @@ export class TableSelectionController implements ReactiveController { }) { const key = (r: RowWithGroup) => `${r.id}.${r.groupKey ? r.groupKey : ''}`; const rows = new Set( - TableRowSelection.rows(this.selection).map(r => key(r)) + TableViewRowSelection.rows(this.selection).map(r => key(r)) ); remove.forEach(row => rows.delete(key(row))); add.forEach(row => rows.add(key(row))); @@ -634,7 +634,7 @@ export class TableSelectionController implements ReactiveController { }, ]; }); - this.selection = TableRowSelection.create({ + this.selection = TableViewRowSelection.create({ rows: result, }); } @@ -826,7 +826,7 @@ export class TableSelectionController implements ReactiveController { row: MultiSelection; column: MultiSelection; }) => { - this.selection = TableAreaSelection.create({ + this.selection = TableViewAreaSelection.create({ groupKey: groupKey, rowsSelection: selection.row, columnsSelection: selection.column, @@ -881,7 +881,7 @@ export class TableSelectionController implements ReactiveController { this.__dragToFillElement.dragging = false; fillSelectionWithFocusCellData( this.host, - TableAreaSelection.create({ + TableViewAreaSelection.create({ groupKey: groupKey, rowsSelection: selection.row, columnsSelection: selection.column, @@ -921,7 +921,7 @@ export class TableSelectionController implements ReactiveController { id: rowId, groupKey, }; - const isSelected = TableRowSelection.includes(this.selection, row); + const isSelected = TableViewRowSelection.includes(this.selection, row); this.rowSelectionChange({ add: isSelected ? [] : [row], remove: isSelected ? [row] : [], diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/group.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/group.ts index c427c2c552..1d3e784796 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/group.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/group.ts @@ -18,8 +18,8 @@ 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 type { TableSingleView } from '../table-view-manager.js'; -import { TableAreaSelection } from '../types.js'; import { DataViewColumnPreview } from './header/column-renderer.js'; import { getVerticalIndicator } from './header/vertical-indicator.js'; import type { DataViewTable } from './table-view.js'; @@ -74,7 +74,7 @@ export class TableGroup extends SignalWatcher( const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); - selectionController.selection = TableAreaSelection.create({ + selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: this.rows.length - 1, @@ -92,7 +92,7 @@ export class TableGroup extends SignalWatcher( const index = this.view.properties$.value.findIndex( v => v.type$.value === 'title' ); - selectionController.selection = TableAreaSelection.create({ + selectionController.selection = TableViewAreaSelection.create({ groupKey: this.group?.key, focus: { rowIndex: 0, diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts index c8b4621fc9..f1be34bb4a 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts @@ -13,7 +13,7 @@ import { import { html } from 'lit'; import type { DataViewRenderer } from '../../../core/data-view.js'; -import { TableRowSelection } from '../types.js'; +import { TableViewRowSelection } from '../selection'; import type { TableSelectionController } from './controller/selection.js'; export const openDetail = ( @@ -38,11 +38,11 @@ export const popRowMenu = ( selectionController: TableSelectionController ) => { const selection = selectionController.selection; - if (!TableRowSelection.is(selection)) { + if (!TableViewRowSelection.is(selection)) { return; } if (selection.rows.length > 1) { - const rows = TableRowSelection.rowsIds(selection); + const rows = TableViewRowSelection.rowsIds(selection); popFilterableSimpleMenu(ele, [ menu.group({ name: '', diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/row/row-select-checkbox.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/row/row-select-checkbox.ts index 1906710f09..48d9c3043d 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/row/row-select-checkbox.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/row/row-select-checkbox.ts @@ -7,9 +7,9 @@ import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { - TableRowSelection, + TableViewRowSelection, type TableViewSelectionWithType, -} from '../../types.js'; +} from '../../selection'; export class RowSelectCheckbox extends SignalWatcher( WithDisposable(ShadowlessElement) @@ -49,7 +49,7 @@ export class RowSelectCheckbox extends SignalWatcher( if (!selection || selection.selectionType !== 'row') { return false; } - return TableRowSelection.includes(selection, { + return TableViewRowSelection.includes(selection, { id: this.rowId, groupKey: this.groupKey, }); diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/row/row.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/row/row.ts index dc2f635b8d..49d9329821 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/row/row.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/row/row.ts @@ -9,8 +9,11 @@ import { styleMap } from 'lit/directives/style-map.js'; import { html } from 'lit/static-html.js'; import type { DataViewRenderer } from '../../../../core/data-view.js'; +import { + TableViewRowSelection, + type TableViewSelection, +} from '../../selection'; import type { TableSingleView } from '../../table-view-manager.js'; -import { TableRowSelection, type TableViewSelection } from '../../types.js'; import { openDetail, popRowMenu } from '../menu.js'; export class TableRow extends SignalWatcher(WithDisposable(ShadowlessElement)) { @@ -133,8 +136,8 @@ export class TableRow extends SignalWatcher(WithDisposable(ShadowlessElement)) { const ele = e.target as HTMLElement; const cell = ele.closest('affine-database-cell-container'); const row = { id: this.rowId, groupKey: this.groupKey }; - if (!TableRowSelection.includes(selection.selection, row)) { - selection.selection = TableRowSelection.create({ + if (!TableViewRowSelection.includes(selection.selection, row)) { + selection.selection = TableViewRowSelection.create({ rows: [row], }); } @@ -201,7 +204,7 @@ export class TableRow extends SignalWatcher(WithDisposable(ShadowlessElement)) { return; } this.setSelection( - TableRowSelection.create({ + TableViewRowSelection.create({ rows: [{ id: this.rowId, groupKey: this.groupKey }], }) ); @@ -214,14 +217,14 @@ export class TableRow extends SignalWatcher(WithDisposable(ShadowlessElement)) { const ele = e.currentTarget as HTMLElement; const selection = this.selectionController.selection; if ( - !TableRowSelection.is(selection) || + !TableViewRowSelection.is(selection) || !selection.rows.some( row => row.id === this.rowId && row.groupKey === this.groupKey ) ) { const row = { id: this.rowId, groupKey: this.groupKey }; this.setSelection( - TableRowSelection.create({ + TableViewRowSelection.create({ rows: [row], }) ); diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/table-view.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/table-view.ts index be35b5bb38..d87167bb6c 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/table-view.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/table-view.ts @@ -14,8 +14,8 @@ import type { DataViewInstance } from '../../../core/index.js'; import { renderUniLit } from '../../../core/utils/uni-component/uni-component.js'; import { DataViewBase } from '../../../core/view/data-view-base.js'; import { LEFT_TOOL_BAR_WIDTH } from '../consts.js'; +import type { TableViewSelectionWithType } from '../selection'; import type { TableSingleView } from '../table-view-manager.js'; -import type { TableViewSelectionWithType } from '../types.js'; import { TableClipboardController } from './controller/clipboard.js'; import { TableDragController } from './controller/drag.js'; import { TableHotkeysController } from './controller/hotkeys.js'; diff --git a/blocksuite/affine/data-view/src/view-presets/table/selection.ts b/blocksuite/affine/data-view/src/view-presets/table/selection.ts new file mode 100644 index 0000000000..439f2f94ab --- /dev/null +++ b/blocksuite/affine/data-view/src/view-presets/table/selection.ts @@ -0,0 +1,123 @@ +import { z } from 'zod'; + +export const TableViewTypeSchema = z.object({ + viewId: z.string(), + type: z.literal('table'), +}); +export const RangeSchema = z.object({ + start: z.number(), + end: z.number(), +}); +export const FocusSchema = z.object({ + rowIndex: z.number(), + columnIndex: z.number(), +}); +export const TableViewAreaSelectionSchema = z.object({ + selectionType: z.literal('area'), + groupKey: z.string().optional(), + rowsSelection: RangeSchema, + columnsSelection: RangeSchema, + focus: FocusSchema, + isEditing: z.boolean(), +}); + +export const RowWithGroupSchema = z.object({ + id: z.string(), + groupKey: z.string().optional(), +}); + +export const TableViewRowSelectionSchema = z.object({ + selectionType: z.literal('row'), + rows: z.array(RowWithGroupSchema), +}); + +export const TableViewSelectionSchema = z.union([ + TableViewAreaSelectionSchema, + TableViewRowSelectionSchema, +]); +export const TableViewSelectionWithTypeSchema = z.union([ + z.intersection(TableViewTypeSchema, TableViewAreaSelectionSchema), + z.intersection(TableViewTypeSchema, TableViewRowSelectionSchema), +]); +export type RowWithGroup = z.TypeOf; +export const RowWithGroup = { + equal(a?: RowWithGroup, b?: RowWithGroup) { + if (a == null || b == null) { + return false; + } + return a.id === b.id && a.groupKey === b.groupKey; + }, +}; +export type TableViewRowSelection = z.TypeOf< + typeof TableViewRowSelectionSchema +>; +export const TableViewRowSelection = { + rows: (selection?: TableViewSelection): RowWithGroup[] => { + if (selection?.selectionType === 'row') { + return selection.rows; + } + return []; + }, + rowsIds: (selection?: TableViewSelection): string[] => { + return TableViewRowSelection.rows(selection).map(v => v.id); + }, + includes( + selection: TableViewSelection | undefined, + row: RowWithGroup + ): boolean { + if (!selection) { + return false; + } + return TableViewRowSelection.rows(selection).some(v => + RowWithGroup.equal(v, row) + ); + }, + create(options: { rows: RowWithGroup[] }): TableViewRowSelection { + return { + selectionType: 'row', + rows: options.rows, + }; + }, + is(selection?: TableViewSelection): selection is TableViewRowSelection { + return selection?.selectionType === 'row'; + }, +}; +export type TableViewAreaSelection = z.TypeOf< + typeof TableViewAreaSelectionSchema +>; +export const TableViewAreaSelection = { + create: (options: { + groupKey?: string; + focus: CellFocus; + rowsSelection?: MultiSelection; + columnsSelection?: MultiSelection; + isEditing: boolean; + }): TableViewAreaSelection => { + return { + ...options, + selectionType: 'area', + rowsSelection: options.rowsSelection ?? { + start: options.focus.rowIndex, + end: options.focus.rowIndex, + }, + columnsSelection: options.columnsSelection ?? { + start: options.focus.columnIndex, + end: options.focus.columnIndex, + }, + }; + }, + isFocus(selection: TableViewAreaSelection) { + return ( + selection.focus.rowIndex === selection.rowsSelection.start && + selection.focus.rowIndex === selection.rowsSelection.end && + selection.focus.columnIndex === selection.columnsSelection.start && + selection.focus.columnIndex === selection.columnsSelection.end + ); + }, +}; +export type CellFocus = z.TypeOf; +export type MultiSelection = z.TypeOf; +export type TableViewSelection = z.TypeOf; +export type TableViewSelectionWithType = z.TypeOf< + typeof TableViewSelectionWithTypeSchema +>; diff --git a/blocksuite/affine/data-view/src/view-presets/table/types.ts b/blocksuite/affine/data-view/src/view-presets/table/types.ts index 066ac257c3..3e34b33668 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/types.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/types.ts @@ -10,108 +10,3 @@ export interface Column< } export type StatCalcOpType = string | undefined; - -type WithTableViewType = T extends unknown - ? { - viewId: string; - type: 'table'; - } & T - : never; -export type RowWithGroup = { - id: string; - groupKey?: string; -}; -export const RowWithGroup = { - equal(a?: RowWithGroup, b?: RowWithGroup) { - if (a == null || b == null) { - return false; - } - return a.id === b.id && a.groupKey === b.groupKey; - }, -}; -export type TableRowSelection = { - selectionType: 'row'; - rows: RowWithGroup[]; -}; -export const TableRowSelection = { - rows: (selection?: TableViewSelection): RowWithGroup[] => { - if (selection?.selectionType === 'row') { - return selection.rows; - } - return []; - }, - rowsIds: (selection?: TableViewSelection): string[] => { - return TableRowSelection.rows(selection).map(v => v.id); - }, - includes( - selection: TableViewSelection | undefined, - row: RowWithGroup - ): boolean { - if (!selection) { - return false; - } - return TableRowSelection.rows(selection).some(v => - RowWithGroup.equal(v, row) - ); - }, - create(options: { rows: RowWithGroup[] }): TableRowSelection { - return { - selectionType: 'row', - rows: options.rows, - }; - }, - is(selection?: TableViewSelection): selection is TableRowSelection { - return selection?.selectionType === 'row'; - }, -}; -export type TableAreaSelection = { - selectionType: 'area'; - groupKey?: string; - rowsSelection: MultiSelection; - columnsSelection: MultiSelection; - focus: CellFocus; - isEditing: boolean; -}; -export const TableAreaSelection = { - create: (options: { - groupKey?: string; - focus: CellFocus; - rowsSelection?: MultiSelection; - columnsSelection?: MultiSelection; - isEditing: boolean; - }): TableAreaSelection => { - return { - ...options, - selectionType: 'area', - rowsSelection: options.rowsSelection ?? { - start: options.focus.rowIndex, - end: options.focus.rowIndex, - }, - columnsSelection: options.columnsSelection ?? { - start: options.focus.columnIndex, - end: options.focus.columnIndex, - }, - }; - }, - isFocus(selection: TableAreaSelection) { - return ( - selection.focus.rowIndex === selection.rowsSelection.start && - selection.focus.rowIndex === selection.rowsSelection.end && - selection.focus.columnIndex === selection.columnsSelection.start && - selection.focus.columnIndex === selection.columnsSelection.end - ); - }, -}; - -export type CellFocus = { - rowIndex: number; - columnIndex: number; -}; -export type MultiSelection = { - start: number; - end: number; -}; -export type TableViewSelection = TableAreaSelection | TableRowSelection; -export type TableViewSelectionWithType = WithTableViewType< - TableAreaSelection | TableRowSelection ->; diff --git a/blocksuite/blocks/src/_specs/common.ts b/blocksuite/blocks/src/_specs/common.ts index 24e556f486..fed967cf4d 100644 --- a/blocksuite/blocks/src/_specs/common.ts +++ b/blocksuite/blocks/src/_specs/common.ts @@ -2,7 +2,10 @@ import { AttachmentBlockSpec } from '@blocksuite/affine-block-attachment'; import { BookmarkBlockSpec } from '@blocksuite/affine-block-bookmark'; import { CodeBlockSpec } from '@blocksuite/affine-block-code'; import { DataViewBlockSpec } from '@blocksuite/affine-block-data-view'; -import { DatabaseBlockSpec } from '@blocksuite/affine-block-database'; +import { + DatabaseBlockSpec, + DatabaseSelectionExtension, +} from '@blocksuite/affine-block-database'; import { DividerBlockSpec } from '@blocksuite/affine-block-divider'; import { EdgelessTextBlockSpec } from '@blocksuite/affine-block-edgeless-text'; import { EmbedExtensions } from '@blocksuite/affine-block-embed'; @@ -44,7 +47,6 @@ import { SurfaceSelectionExtension, TextSelectionExtension, } from '@blocksuite/block-std'; -import { DatabaseSelectionExtension } from '@blocksuite/data-view'; import type { ExtensionType } from '@blocksuite/store'; import { AdapterFactoryExtensions } from '../_common/adapters/extension.js'; diff --git a/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts b/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts index 8ec0e5c5bd..6524831521 100644 --- a/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts +++ b/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts @@ -1,3 +1,4 @@ +import { DatabaseSelection } from '@blocksuite/affine-block-database'; import { HoverController } from '@blocksuite/affine-components/hover'; import type { RichText } from '@blocksuite/affine-components/rich-text'; import { isFormatSupported } from '@blocksuite/affine-components/rich-text'; @@ -15,7 +16,6 @@ import { TextSelection, WidgetComponent, } from '@blocksuite/block-std'; -import { DatabaseSelection } from '@blocksuite/data-view'; import { assertExists, DisposableGroup,