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.
This commit is contained in:
Saul-Mirone
2025-03-07 04:08:47 +00:00
parent 8da12025af
commit fe5f0f62ec
176 changed files with 503 additions and 180 deletions

View File

@@ -0,0 +1,116 @@
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { isStrictUrl } from '@blocksuite/affine-shared/utils';
import type {
BeforeinputHookCtx,
CompositionEndHookCtx,
HookContext,
} from '@blocksuite/inline';
const EDGE_IGNORED_ATTRIBUTES = ['code', 'link'] as const;
const GLOBAL_IGNORED_ATTRIBUTES = [] as const;
const autoIdentifyLink = (ctx: HookContext<AffineTextAttributes>) => {
// auto identify link only on pressing space
if (ctx.data !== ' ') {
return;
}
// space is typed at the end of link, remove the link attribute on typed space
if (ctx.attributes?.link) {
if (ctx.inlineRange.index === ctx.inlineEditor.yText.length) {
delete ctx.attributes['link'];
}
return;
}
const lineInfo = ctx.inlineEditor.getLine(ctx.inlineRange.index);
if (!lineInfo) {
return;
}
const { line, lineIndex, rangeIndexRelatedToLine } = lineInfo;
if (lineIndex !== 0) {
return;
}
const verifyData = line.vTextContent
.slice(0, rangeIndexRelatedToLine)
.split(' ');
const verifyStr = verifyData[verifyData.length - 1];
const isUrl = isStrictUrl(verifyStr);
if (!isUrl) {
return;
}
const startIndex = ctx.inlineRange.index - verifyStr.length;
ctx.inlineEditor.formatText(
{
index: startIndex,
length: verifyStr.length,
},
{
link: verifyStr,
}
);
};
function handleExtendedAttributes(
ctx:
| BeforeinputHookCtx<AffineTextAttributes>
| CompositionEndHookCtx<AffineTextAttributes>
) {
const { data, inlineEditor, inlineRange } = ctx;
const deltas = inlineEditor.getDeltasByInlineRange(inlineRange);
// eslint-disable-next-line sonarjs/no-collapsible-if
if (data && data.length > 0 && data !== '\n') {
if (
// cursor is in the between of two deltas
(deltas.length > 1 ||
// cursor is in the end of line or in the middle of a delta
(deltas.length === 1 && inlineRange.index !== 0)) &&
!inlineEditor.isEmbed(deltas[0][0]) // embeds should not be extended
) {
// each new text inserted by inline editor will not contain any attributes,
// but we want to keep the attributes of previous text or current text where the cursor is in
// here are two cases:
// 1. aaa**b|bb**ccc --input 'd'--> aaa**bdbb**ccc, d should extend the bold attribute
// 2. aaa**bbb|**ccc --input 'd'--> aaa**bbbd**ccc, d should extend the bold attribute
const { attributes } = deltas[0][0];
if (
deltas.length !== 1 ||
inlineRange.index === inlineEditor.yText.length
) {
// `EDGE_IGNORED_ATTRIBUTES` is which attributes should be ignored in case 2
EDGE_IGNORED_ATTRIBUTES.forEach(attr => {
delete attributes?.[attr];
});
}
// `GLOBAL_IGNORED_ATTRIBUTES` is which attributes should be ignored in case 1, 2
GLOBAL_IGNORED_ATTRIBUTES.forEach(attr => {
delete attributes?.[attr];
});
ctx.attributes = attributes ?? {};
}
}
return ctx;
}
export const onVBeforeinput = (
ctx: BeforeinputHookCtx<AffineTextAttributes>
) => {
handleExtendedAttributes(ctx);
autoIdentifyLink(ctx);
};
export const onVCompositionEnd = (
ctx: CompositionEndHookCtx<AffineTextAttributes>
) => {
handleExtendedAttributes(ctx);
};