import { DatabaseBlockSchema } from '@blocksuite/affine-model'; import { AdapterTextUtils, BlockNotionHtmlAdapterExtension, type BlockNotionHtmlAdapterMatcher, HastUtils, } from '@blocksuite/affine-shared/adapters'; import { getTagColor } from '@blocksuite/data-view'; import { type BlockSnapshot, nanoid } from '@blocksuite/store'; const ColumnClassMap: Record = { typesSelect: 'select', typesMultipleSelect: 'multi-select', typesNumber: 'number', typesCheckbox: 'checkbox', typesText: 'rich-text', typesTitle: 'title', typesDate: 'date', }; const NotionDatabaseToken = '.collection-content'; const NotionDatabaseTitleToken = '.collection-title'; type BlocksuiteTableColumn = { type: string; name: string; data: { options?: { id: string; value: string; color: string; }[]; }; id: string; }; type BlocksuiteTableRow = Record< string, { columnId: string; value: unknown; } >; const DATABASE_NODE_TYPES = new Set(['table', 'th', 'tr']); export const databaseBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatcher = { flavour: DatabaseBlockSchema.model.flavour, toMatch: o => HastUtils.isElement(o.node) && DATABASE_NODE_TYPES.has(o.node.tagName), fromMatch: () => false, toBlockSnapshot: { enter: (o, context) => { if (!HastUtils.isElement(o.node)) { return; } const { walkerContext, deltaConverter, pageMap } = context; switch (o.node.tagName) { case 'th': { const columnId = nanoid(); const columnTypeClass = HastUtils.querySelector(o.node, 'svg') ?.properties?.className; const columnType = Array.isArray(columnTypeClass) ? (ColumnClassMap[columnTypeClass[0] ?? ''] ?? 'rich-text') : 'rich-text'; walkerContext.pushGlobalContextStack( 'hast:table:column', { type: columnType, name: HastUtils.getTextContent( HastUtils.getTextChildrenOnlyAst(o.node) ), data: Object.create(null), id: columnId, } ); // disable icon img in th walkerContext.setGlobalContext('hast:disableimg', true); break; } case 'tr': { if ( o.parent?.node.type === 'element' && o.parent.node.tagName === 'tbody' ) { const columns = walkerContext.getGlobalContextStack( 'hast:table:column' ); const row = Object.create(null); let plainTable = false; HastUtils.getElementChildren(o.node).forEach((child, index) => { if (plainTable || columns[index] === undefined) { plainTable = true; if (columns[index] === undefined) { columns.push({ type: 'rich-text', name: '', data: Object.create(null), id: nanoid(), }); walkerContext.pushGlobalContextStack( 'hast:table:children', { type: 'block', id: nanoid(), flavour: 'affine:paragraph', props: { text: { '$blocksuite:internal:text$': true, delta: deltaConverter.astToDelta(child), }, type: 'text', }, children: [], } ); } walkerContext.pushGlobalContextStack( 'hast:table:children', { type: 'block', id: nanoid(), flavour: 'affine:paragraph', props: { text: { '$blocksuite:internal:text$': true, delta: deltaConverter.astToDelta(child), }, type: 'text', }, children: [], } ); const column = columns[index]; if (!column) { return; } row[column.id] = { columnId: column.id, value: HastUtils.getTextContent(child), }; } else if (HastUtils.querySelector(child, '.cell-title')) { walkerContext.pushGlobalContextStack( 'hast:table:children', { type: 'block', id: nanoid(), flavour: 'affine:paragraph', props: { text: { '$blocksuite:internal:text$': true, delta: deltaConverter.astToDelta(child, { pageMap }), }, type: 'text', }, children: [], } ); columns[index].type = 'title'; return; } const optionIds: string[] = []; const column = columns[index]; if (!column) { return; } // Check for