Files
AFFiNE-Mirror/blocksuite/affine/rich-text/src/inline/adapters/markdown/inline-delta.ts
Saul-Mirone fe5f0f62ec feat(editor): rich text package (#10689)
This PR performs a significant architectural refactoring by extracting rich text functionality into a dedicated package. Here are the key changes:

1. **New Package Creation**
- Created a new package `@blocksuite/affine-rich-text` to house rich text related functionality
- Moved rich text components, utilities, and types from `@blocksuite/affine-components` to this new package

2. **Dependency Updates**
- Updated multiple block packages to include the new `@blocksuite/affine-rich-text` as a direct dependency:
  - block-callout
  - block-code
  - block-database
  - block-edgeless-text
  - block-embed
  - block-list
  - block-note
  - block-paragraph

3. **Import Path Updates**
- Refactored all imports that previously referenced rich text functionality from `@blocksuite/affine-components/rich-text` to now use `@blocksuite/affine-rich-text`
- Updated imports for components like:
  - DefaultInlineManagerExtension
  - RichText types and interfaces
  - Text manipulation utilities (focusTextModel, textKeymap, etc.)
  - Reference node components and providers

4. **Build Configuration Updates**
- Added references to the new rich text package in the `tsconfig.json` files of all affected packages
- Maintained workspace dependencies using the `workspace:*` version specifier

The primary motivation appears to be:
1. Better separation of concerns by isolating rich text functionality
2. Improved maintainability through more modular package structure
3. Clearer dependencies between packages
4. Potential for better tree-shaking and bundle optimization

This is primarily an architectural improvement that should make the codebase more maintainable and better organized.
2025-03-07 04:08:47 +00:00

200 lines
5.4 KiB
TypeScript

import {
AdapterTextUtils,
FOOTNOTE_DEFINITION_PREFIX,
InlineDeltaToMarkdownAdapterExtension,
} from '@blocksuite/affine-shared/adapters';
import type { PhrasingContent } from 'mdast';
import type RemarkMath from 'remark-math';
declare type _GLOBAL_ = typeof RemarkMath;
export const boldDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'bold',
match: delta => !!delta.attributes?.bold,
toAST: (_, context) => {
const { current: currentMdast } = context;
return {
type: 'strong',
children: [currentMdast],
};
},
});
export const italicDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'italic',
match: delta => !!delta.attributes?.italic,
toAST: (_, context) => {
const { current: currentMdast } = context;
return {
type: 'emphasis',
children: [currentMdast],
};
},
});
export const strikeDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'strike',
match: delta => !!delta.attributes?.strike,
toAST: (_, context) => {
const { current: currentMdast } = context;
return {
type: 'delete',
children: [currentMdast],
};
},
});
export const inlineCodeDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'inlineCode',
match: delta => !!delta.attributes?.code,
toAST: delta => ({
type: 'inlineCode',
value: delta.insert,
}),
});
export const referenceDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'reference',
match: delta => !!delta.attributes?.reference,
toAST: (delta, context) => {
let mdast: PhrasingContent = {
type: 'text',
value: delta.insert,
};
const reference = delta.attributes?.reference;
if (!reference) {
return mdast;
}
const { configs } = context;
const title = configs.get(`title:${reference.pageId}`);
const params = reference.params ?? {};
const url = AdapterTextUtils.generateDocUrl(
configs.get('docLinkBaseUrl') ?? '',
String(reference.pageId),
params
);
mdast = {
type: 'link',
url,
children: [
{
type: 'text',
value: title ?? '',
},
],
};
return mdast;
},
});
export const linkDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'link',
match: delta => !!delta.attributes?.link,
toAST: (delta, context) => {
const mdast: PhrasingContent = {
type: 'text',
value: delta.insert,
};
const link = delta.attributes?.link;
if (!link) {
return mdast;
}
const { current: currentMdast } = context;
if ('value' in currentMdast) {
if (currentMdast.value === '') {
return {
type: 'text',
value: link,
};
}
if (mdast.value !== link) {
return {
type: 'link',
url: link,
children: [currentMdast],
};
}
}
return mdast;
},
});
export const latexDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'inlineLatex',
match: delta => !!delta.attributes?.latex,
toAST: delta => {
const mdast: PhrasingContent = {
type: 'text',
value: delta.insert,
};
if (delta.attributes?.latex) {
return {
type: 'inlineMath',
value: delta.attributes.latex,
};
}
return mdast;
},
});
export const footnoteReferenceDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'footnote-reference',
match: delta => !!delta.attributes?.footnote,
toAST: (delta, context) => {
const mdast: PhrasingContent = {
type: 'text',
value: delta.insert,
};
const footnote = delta.attributes?.footnote;
if (!footnote) {
return mdast;
}
const footnoteDefinitionKey = `${FOOTNOTE_DEFINITION_PREFIX}${footnote.label}`;
const { configs } = context;
// FootnoteReference should be paired with FootnoteDefinition
// If the footnoteDefinition is not in the configs, set it to configs
// We should add the footnoteDefinition markdown ast nodes to tree after all the footnoteReference markdown ast nodes are added
if (!configs.has(footnoteDefinitionKey)) {
// clone the footnote reference
const clonedFootnoteReference = { ...footnote.reference };
// If the footnote reference contains url, encode it
if (clonedFootnoteReference.url) {
clonedFootnoteReference.url = encodeURIComponent(
clonedFootnoteReference.url
);
}
configs.set(
footnoteDefinitionKey,
JSON.stringify(clonedFootnoteReference)
);
}
return {
type: 'footnoteReference',
label: footnote.label,
identifier: footnote.label,
};
},
});
export const InlineDeltaToMarkdownAdapterExtensions = [
referenceDeltaToMarkdownAdapterMatcher,
linkDeltaToMarkdownAdapterMatcher,
inlineCodeDeltaToMarkdownAdapterMatcher,
boldDeltaToMarkdownAdapterMatcher,
italicDeltaToMarkdownAdapterMatcher,
strikeDeltaToMarkdownAdapterMatcher,
latexDeltaToMarkdownAdapterMatcher,
footnoteReferenceDeltaToMarkdownAdapterMatcher,
];