mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
refactor(editor): move database selection into the corresponding view (#9752)
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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<string, unknown>): 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<T extends DataViewSelection['type']>(
|
||||
type: T
|
||||
): GetDataViewSelection<T> | undefined {
|
||||
return this.viewSelection.type === type
|
||||
? (this.viewSelection as GetDataViewSelection<T>)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
override toJSON(): Record<string, unknown> {
|
||||
return {
|
||||
type: 'database',
|
||||
blockId: this.blockId,
|
||||
viewSelection: this.viewSelection,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface Selection {
|
||||
database: typeof DatabaseSelection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const DatabaseSelectionExtension = SelectionExtension(DatabaseSelection);
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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<string, unknown> = Record<string, unknown>,
|
||||
@@ -20,7 +14,3 @@ export type PropertyDataUpdater<
|
||||
export interface DatabaseFlags {
|
||||
enable_number_formatting: boolean;
|
||||
}
|
||||
|
||||
export const defaultDatabaseFlags: Readonly<DatabaseFlags> = {
|
||||
enable_number_formatting: false,
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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<typeof KanbanCellSelectionSchema>;
|
||||
export type KanbanCardSelectionCard = z.TypeOf<
|
||||
typeof KanbanCardSelectionCardSchema
|
||||
>;
|
||||
export type KanbanCardSelection = z.TypeOf<typeof KanbanCardSelectionSchema>;
|
||||
export type KanbanGroupSelection = z.TypeOf<typeof KanbanGroupSelectionSchema>;
|
||||
export type KanbanViewSelection = z.TypeOf<typeof KanbanViewSelectionSchema>;
|
||||
export type KanbanViewSelectionWithType = z.TypeOf<
|
||||
typeof KanbanViewSelectionWithTypeSchema
|
||||
>;
|
||||
@@ -1,32 +0,0 @@
|
||||
type WithKanbanViewType<T> = 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<KanbanViewSelection>;
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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] : [],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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],
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
123
blocksuite/affine/data-view/src/view-presets/table/selection.ts
Normal file
123
blocksuite/affine/data-view/src/view-presets/table/selection.ts
Normal file
@@ -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<typeof RowWithGroupSchema>;
|
||||
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<typeof FocusSchema>;
|
||||
export type MultiSelection = z.TypeOf<typeof RangeSchema>;
|
||||
export type TableViewSelection = z.TypeOf<typeof TableViewSelectionSchema>;
|
||||
export type TableViewSelectionWithType = z.TypeOf<
|
||||
typeof TableViewSelectionWithTypeSchema
|
||||
>;
|
||||
@@ -10,108 +10,3 @@ export interface Column<
|
||||
}
|
||||
|
||||
export type StatCalcOpType = string | undefined;
|
||||
|
||||
type WithTableViewType<T> = 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
|
||||
>;
|
||||
|
||||
Reference in New Issue
Block a user