-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(blocksuite): add plain text adapter for database block
- Loading branch information
1 parent
03dd354
commit 185ba27
Showing
5 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
blocksuite/blocks/src/database-block/adapters/plain-text.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { | ||
type Column, | ||
DatabaseBlockSchema, | ||
type SerializedCells, | ||
} from '@blocksuite/affine-model'; | ||
import { | ||
BlockPlainTextAdapterExtension, | ||
type BlockPlainTextAdapterMatcher, | ||
} from '@blocksuite/affine-shared/adapters'; | ||
import type { DeltaInsert } from '@blocksuite/inline'; | ||
import type { BlockSnapshot } from '@blocksuite/store'; | ||
import { format } from 'date-fns/format'; | ||
|
||
import { formatTable } from './utils.js'; | ||
|
||
export const databaseBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = | ||
{ | ||
flavour: DatabaseBlockSchema.model.flavour, | ||
toMatch: () => false, | ||
fromMatch: o => o.node.flavour === DatabaseBlockSchema.model.flavour, | ||
toBlockSnapshot: {}, | ||
fromBlockSnapshot: { | ||
enter: (o, context) => { | ||
const { walkerContext, deltaConverter } = context; | ||
const rows: string[][] = []; | ||
const columns = o.node.props.columns as Array<Column>; | ||
const children = o.node.children; | ||
const cells = o.node.props.cells as SerializedCells; | ||
const tableCells = children.map((v: BlockSnapshot) => | ||
columns.map(col => { | ||
const cell = cells[v.id]?.[col.id]; | ||
if (!cell && col.type !== 'title') { | ||
return ''; | ||
} | ||
switch (col.type) { | ||
case 'rich-text': | ||
return deltaConverter | ||
.deltaToAST((cell.value as { delta: DeltaInsert[] }).delta) | ||
.join(''); | ||
case 'title': | ||
return deltaConverter | ||
.deltaToAST((v.props.text as { delta: DeltaInsert[] }).delta) | ||
.join(''); | ||
case 'date': | ||
return format(new Date(cell.value as number), 'yyyy-MM-dd'); | ||
case 'select': { | ||
const value = ( | ||
col.data as { options: Array<Record<string, string>> } | ||
).options.find(opt => opt.id === cell.value)?.value; | ||
return value || ''; | ||
} | ||
case 'multi-select': { | ||
const value = (cell.value as string[]) | ||
.map( | ||
val => | ||
( | ||
col.data as { options: Array<Record<string, string>> } | ||
).options.find(opt => val === opt.id)?.value | ||
) | ||
.filter(Boolean) | ||
.join(','); | ||
return value || ''; | ||
} | ||
default: | ||
return String(cell.value); | ||
} | ||
}) | ||
); | ||
|
||
// Handle first row. | ||
if (Array.isArray(columns)) { | ||
rows.push(columns.map(col => col.name)); | ||
} | ||
|
||
// Handle 2-... rows | ||
tableCells.forEach(children => { | ||
rows.push(children); | ||
}); | ||
|
||
// Convert rows to table string | ||
const tableString = formatTable(rows); | ||
|
||
context.textBuffer.content += tableString; | ||
context.textBuffer.content += '\n'; | ||
|
||
walkerContext.skipAllChildren(); | ||
}, | ||
}, | ||
}; | ||
|
||
export const DatabaseBlockPlainTextAdapterExtension = | ||
BlockPlainTextAdapterExtension(databaseBlockPlainTextAdapterMatcher); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
function calculateColumnWidths(rows: string[][]): number[] { | ||
return rows[0].map((_, colIndex) => | ||
Math.max(...rows.map(row => (row[colIndex] || '').length)) | ||
); | ||
} | ||
|
||
function formatRow( | ||
row: string[], | ||
columnWidths: number[], | ||
isHeader: boolean | ||
): string { | ||
const cells = row.map((cell, colIndex) => | ||
cell.padEnd(columnWidths[colIndex], ' ') | ||
); | ||
const rowString = `| ${cells.join(' | ')} |`; | ||
return isHeader | ||
? `${rowString}\n${formatSeparator(columnWidths)}` | ||
: rowString; | ||
} | ||
|
||
function formatSeparator(columnWidths: number[]): string { | ||
const separator = columnWidths.map(width => '-'.repeat(width)).join(' | '); | ||
return `| ${separator} |`; | ||
} | ||
|
||
export function formatTable(rows: string[][]): string { | ||
const columnWidths = calculateColumnWidths(rows); | ||
const formattedRows = rows.map((row, index) => | ||
formatRow(row, columnWidths, index === 0) | ||
); | ||
return formattedRows.join('\n'); | ||
} |