feat(editor): add inline packages (#11048)

This commit is contained in:
Saul-Mirone
2025-03-20 13:47:35 +00:00
parent aa620af40f
commit e5e429e7b2
170 changed files with 1337 additions and 804 deletions

View File

@@ -35,6 +35,9 @@
"@blocksuite/affine-fragment-outline": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
"@blocksuite/affine-inline-link": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
@@ -91,6 +94,9 @@
"./blocks/table": "./src/blocks/table.ts",
"./data-view": "./src/data-view/index.ts",
"./data-view/effects": "./src/data-view/effects.ts",
"./inlines/link": "./src/inlines/link.ts",
"./inlines/reference": "./src/inlines/reference.ts",
"./inlines/preset": "./src/inlines/preset.ts",
"./widgets/drag-handle": "./src/widgets/drag-handle.ts",
"./widgets/edgeless-auto-connect": "./src/widgets/edgeless-auto-connect.ts",
"./widgets/frame-title": "./src/widgets/frame-title.ts",

View File

@@ -5,7 +5,7 @@ import {
InlineDeltaToPlainTextAdapterExtensions,
MarkdownInlineToDeltaAdapterExtensions,
NotionHtmlInlineToDeltaAdapterExtensions,
} from '@blocksuite/affine-rich-text';
} from '@blocksuite/affine-inline-preset';
import {
AttachmentAdapterFactoryExtension,
HtmlAdapterFactoryExtension,

View File

@@ -45,6 +45,9 @@ import { effects as componentViewDropdownMenuEffects } from '@blocksuite/affine-
import { effects as fragmentDocTitleEffects } from '@blocksuite/affine-fragment-doc-title/effects';
import { effects as fragmentFramePanelEffects } from '@blocksuite/affine-fragment-frame-panel/effects';
import { effects as fragmentOutlineEffects } from '@blocksuite/affine-fragment-outline/effects';
import { effects as inlineLinkEffects } from '@blocksuite/affine-inline-link/effects';
import { effects as inlinePresetEffects } from '@blocksuite/affine-inline-preset/effects';
import { effects as inlineReferenceEffects } from '@blocksuite/affine-inline-reference/effects';
import { effects as richTextEffects } from '@blocksuite/affine-rich-text/effects';
import { effects as widgetDragHandleEffects } from '@blocksuite/affine-widget-drag-handle/effects';
import { effects as widgetEdgelessAutoConnectEffects } from '@blocksuite/affine-widget-edgeless-auto-connect/effects';
@@ -113,6 +116,10 @@ export function effects() {
dataViewEffects();
richTextEffects();
inlineReferenceEffects();
inlinePresetEffects();
inlineLinkEffects();
blockNoteEffects();
blockAttachmentEffects();
blockBookmarkEffects();

View File

@@ -25,10 +25,7 @@ import {
PageSurfaceRefBlockSpec,
} from '@blocksuite/affine-block-surface-ref';
import { TableBlockSpec } from '@blocksuite/affine-block-table';
import {
RefNodeSlotsExtension,
RichTextExtensions,
} from '@blocksuite/affine-rich-text';
import { inlinePresetExtensions } from '@blocksuite/affine-inline-preset';
import {
DefaultOpenDocExtension,
DocDisplayMetaService,
@@ -38,10 +35,9 @@ import {
import type { ExtensionType } from '@blocksuite/store';
export const CommonBlockSpecs: ExtensionType[] = [
inlinePresetExtensions,
DocDisplayMetaService,
RefNodeSlotsExtension,
EditPropsStore,
RichTextExtensions,
LatexBlockSpec,
ListBlockSpec,
DatabaseBlockSpec,

View File

@@ -0,0 +1 @@
export * from '@blocksuite/affine-inline-link';

View File

@@ -0,0 +1 @@
export * from '@blocksuite/affine-inline-preset';

View File

@@ -0,0 +1 @@
export * from '@blocksuite/affine-inline-reference';

View File

@@ -32,6 +32,9 @@
{ "path": "../fragments/fragment-outline" },
{ "path": "../gfx/text" },
{ "path": "../gfx/turbo-renderer" },
{ "path": "../inlines/link" },
{ "path": "../inlines/preset" },
{ "path": "../inlines/reference" },
{ "path": "../model" },
{ "path": "../rich-text" },
{ "path": "../shared" },

View File

@@ -11,6 +11,7 @@
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,7 +1,7 @@
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import { createLitPortal } from '@blocksuite/affine-components/portal';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import { type CalloutBlockModel } from '@blocksuite/affine-model';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-rich-text';
import { NOTE_SELECTOR } from '@blocksuite/affine-shared/consts';
import {
DocModeProvider,
@@ -12,7 +12,6 @@ import type { BlockComponent } from '@blocksuite/block-std';
import { flip, offset } from '@floating-ui/dom';
import { css, html } from 'lit';
import { query } from 'lit/decorators.js';
export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockModel> {
static override styles = css`
:host {

View File

@@ -8,6 +8,7 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -11,6 +11,8 @@
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-link": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,4 +1,4 @@
import { deleteTextCommand } from '@blocksuite/affine-rich-text';
import { deleteTextCommand } from '@blocksuite/affine-inline-preset';
import {
HtmlAdapter,
pasteMiddleware,

View File

@@ -1,3 +1,4 @@
import { LinkInlineSpecExtension } from '@blocksuite/affine-inline-link';
import {
BackgroundInlineSpecExtension,
BoldInlineSpecExtension,
@@ -5,10 +6,9 @@ import {
ColorInlineSpecExtension,
ItalicInlineSpecExtension,
LatexInlineSpecExtension,
LinkInlineSpecExtension,
StrikeInlineSpecExtension,
UnderlineInlineSpecExtension,
} from '@blocksuite/affine-rich-text';
} from '@blocksuite/affine-inline-preset';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import {
InlineManagerExtension,

View File

@@ -1,5 +1,5 @@
import { textKeymap } from '@blocksuite/affine-inline-preset';
import { CodeBlockSchema } from '@blocksuite/affine-model';
import { textKeymap } from '@blocksuite/affine-rich-text';
import { KeymapExtension } from '@blocksuite/block-std';
export const CodeKeymapExtension = KeymapExtension(textKeymap, {

View File

@@ -1,4 +1,4 @@
import { affineTextStyles } from '@blocksuite/affine-rich-text';
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/block-std';
import { ZERO_WIDTH_SPACE } from '@blocksuite/block-std/inline';

View File

@@ -8,6 +8,8 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../inlines/link" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -11,6 +11,8 @@
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,4 +1,4 @@
import { DefaultInlineManagerExtension } from '@blocksuite/affine-rich-text';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { EditorHost } from '@blocksuite/block-std';
import { ShadowlessElement } from '@blocksuite/block-std';
import type { DetailSlotProps } from '@blocksuite/data-view';

View File

@@ -1,4 +1,4 @@
import { RefNodeSlotsProvider } from '@blocksuite/affine-rich-text';
import { RefNodeSlotsProvider } from '@blocksuite/affine-inline-reference';
import { ParseDocUrlProvider } from '@blocksuite/affine-shared/services';
import {
isValidUrl,

View File

@@ -1,13 +1,13 @@
import type {
AffineInlineEditor,
RichText,
} from '@blocksuite/affine-rich-text';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-rich-text';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { RichText } from '@blocksuite/affine-rich-text';
import {
ParseDocUrlProvider,
TelemetryProvider,
} from '@blocksuite/affine-shared/services';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type {
AffineInlineEditor,
AffineTextAttributes,
} from '@blocksuite/affine-shared/types';
import {
getViewportElement,
isValidUrl,

View File

@@ -1,7 +1,5 @@
import {
DefaultInlineManagerExtension,
type RichText,
} from '@blocksuite/affine-rich-text';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { RichText } from '@blocksuite/affine-rich-text';
import {
ParseDocUrlProvider,
TelemetryProvider,

View File

@@ -9,6 +9,8 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../inlines/reference" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,10 +1,10 @@
import { TextUtils } from '@blocksuite/affine-block-surface';
import { formatBlockCommand } from '@blocksuite/affine-inline-preset';
import {
type EdgelessTextBlockModel,
ListBlockModel,
ParagraphBlockModel,
} from '@blocksuite/affine-model';
import { formatBlockCommand } from '@blocksuite/affine-rich-text';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { matchModels } from '@blocksuite/affine-shared/utils';
import type { BlockComponent } from '@blocksuite/block-std';

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../block-surface" },
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,11 +1,11 @@
import { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
import { isPeekable, Peekable } from '@blocksuite/affine-components/peek';
import { RefNodeSlotsProvider } from '@blocksuite/affine-inline-reference';
import type {
DocMode,
EmbedLinkedDocModel,
EmbedLinkedDocStyles,
} from '@blocksuite/affine-model';
import { RefNodeSlotsProvider } from '@blocksuite/affine-rich-text';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,

View File

@@ -1,4 +1,8 @@
import { Peekable } from '@blocksuite/affine-components/peek';
import {
type DocLinkClickedEvent,
RefNodeSlotsProvider,
} from '@blocksuite/affine-inline-reference';
import {
type AliasInfo,
type DocMode,
@@ -6,10 +10,6 @@ import {
NoteDisplayMode,
type ReferenceInfo,
} from '@blocksuite/affine-model';
import {
type DocLinkClickedEvent,
RefNodeSlotsProvider,
} from '@blocksuite/affine-rich-text';
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
import {
DocDisplayMetaProvider,

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../block-surface" },
{ "path": "../../components" },
{ "path": "../../inlines/reference" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-block-note": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,4 +1,4 @@
import { insertInlineLatex } from '@blocksuite/affine-rich-text';
import { insertInlineLatex } from '@blocksuite/affine-inline-preset';
import {
getSelectedModelsCommand,
getTextSelectionCommand,

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../block-note" },
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -11,6 +11,7 @@
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -3,11 +3,9 @@ import '@blocksuite/affine-shared/commands';
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import { playCheckAnimation } from '@blocksuite/affine-components/icons';
import { TOGGLE_BUTTON_PARENT_CLASS } from '@blocksuite/affine-components/toggle-button';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { ListBlockModel } from '@blocksuite/affine-model';
import {
DefaultInlineManagerExtension,
type RichText,
} from '@blocksuite/affine-rich-text';
import type { RichText } from '@blocksuite/affine-rich-text';
import {
BLOCK_CHILDREN_CONTAINER_PADDING_LEFT,
NOTE_SELECTOR,

View File

@@ -1,5 +1,6 @@
import { textKeymap } from '@blocksuite/affine-inline-preset';
import { ListBlockSchema } from '@blocksuite/affine-model';
import { markdownInput, textKeymap } from '@blocksuite/affine-rich-text';
import { markdownInput } from '@blocksuite/affine-rich-text';
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
import { KeymapExtension, TextSelection } from '@blocksuite/block-std';
import { IS_MAC } from '@blocksuite/global/env';

View File

@@ -8,6 +8,7 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -14,6 +14,7 @@
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,9 +1,11 @@
import {
formatBlockCommand,
type TextConversionConfig,
textConversionConfigs,
type TextFormatConfig,
textFormatConfigs,
} from '@blocksuite/affine-inline-preset';
import {
type TextConversionConfig,
textConversionConfigs,
} from '@blocksuite/affine-rich-text';
import { isInsideBlockByFlavour } from '@blocksuite/affine-shared/utils';
import {

View File

@@ -11,6 +11,7 @@
{ "path": "../block-surface" },
{ "path": "../../components" },
{ "path": "../../fragments/fragment-doc-title" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,10 +1,8 @@
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import { TOGGLE_BUTTON_PARENT_CLASS } from '@blocksuite/affine-components/toggle-button';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
import {
DefaultInlineManagerExtension,
type RichText,
} from '@blocksuite/affine-rich-text';
import type { RichText } from '@blocksuite/affine-rich-text';
import {
BLOCK_CHILDREN_CONTAINER_PADDING_LEFT,
NOTE_SELECTOR,

View File

@@ -1,3 +1,4 @@
import { textKeymap } from '@blocksuite/affine-inline-preset';
import {
CalloutBlockModel,
ParagraphBlockModel,
@@ -7,7 +8,6 @@ import {
focusTextModel,
getInlineEditorByModel,
markdownInput,
textKeymap,
} from '@blocksuite/affine-rich-text';
import {
calculateCollapsedSiblings,

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../components" },
{ "path": "../../gfx/turbo-renderer" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -28,6 +28,9 @@
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-inline-link": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -1,4 +1,4 @@
import { deleteTextCommand } from '@blocksuite/affine-rich-text';
import { deleteTextCommand } from '@blocksuite/affine-inline-preset';
import {
pasteMiddleware,
replaceIdMiddleware,

View File

@@ -16,9 +16,9 @@ import {
formatNativeCommand,
formatTextCommand,
isFormatSupported,
textConversionConfigs,
textFormatConfigs,
} from '@blocksuite/affine-rich-text';
} from '@blocksuite/affine-inline-preset';
import { textConversionConfigs } from '@blocksuite/affine-rich-text';
import {
copySelectedModelsCommand,
deleteSelectedModelsCommand,

View File

@@ -20,21 +20,23 @@ import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
import { insertSurfaceRefBlockCommand } from '@blocksuite/affine-block-surface-ref';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import { toast } from '@blocksuite/affine-components/toast';
import type { FrameBlockModel } from '@blocksuite/affine-model';
import { toggleLink } from '@blocksuite/affine-inline-link';
import {
formatBlockCommand,
formatNativeCommand,
formatTextCommand,
getInlineEditorByModel,
getTextStyle,
insertContent,
insertInlineLatex,
toggleBold,
toggleCode,
toggleItalic,
toggleLink,
toggleStrike,
toggleUnderline,
} from '@blocksuite/affine-inline-preset';
import type { FrameBlockModel } from '@blocksuite/affine-model';
import {
getInlineEditorByModel,
insertContent,
} from '@blocksuite/affine-rich-text';
import {
copySelectedModelsCommand,

View File

@@ -5,14 +5,12 @@ import {
NewDocIcon,
} from '@blocksuite/affine-components/icons';
import { toast } from '@blocksuite/affine-components/toast';
import {
type AffineInlineEditor,
insertLinkedNode,
} from '@blocksuite/affine-rich-text';
import { insertLinkedNode } from '@blocksuite/affine-inline-reference';
import {
DocModeProvider,
TelemetryProvider,
} from '@blocksuite/affine-shared/services';
import type { AffineInlineEditor } from '@blocksuite/affine-shared/types';
import {
createDefaultDoc,
isFuzzyMatch,

View File

@@ -25,6 +25,9 @@
{ "path": "../../components" },
{ "path": "../../fragments/fragment-doc-title" },
{ "path": "../../gfx/text" },
{ "path": "../../inlines/link" },
{ "path": "../../inlines/preset" },
{ "path": "../../inlines/reference" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -5,11 +5,9 @@ import {
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { TextBackgroundDuotoneIcon } from '@blocksuite/affine-components/icons';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import type { TableColumn, TableRow } from '@blocksuite/affine-model';
import {
DefaultInlineManagerExtension,
RichText,
} from '@blocksuite/affine-rich-text';
import { RichText } from '@blocksuite/affine-rich-text';
import { cssVarV2 } from '@blocksuite/affine-shared/theme';
import { getViewportElement } from '@blocksuite/affine-shared/utils';
import { ShadowlessElement } from '@blocksuite/block-std';

View File

@@ -9,6 +9,7 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../inlines/preset" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },

View File

@@ -0,0 +1,46 @@
{
"name": "@blocksuite/affine-inline-link",
"description": "Inline link for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.2.6",
"@blocksuite/store": "workspace:*",
"@floating-ui/dom": "^1.6.13",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"collapse-white-space": "^2.1.0",
"date-fns": "^4.0.0",
"lit": "^3.2.0",
"lit-html": "^3.2.1",
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1",
"yjs": "^13.6.21",
"zod": "^3.23.8"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.20.0"
}

View File

@@ -0,0 +1,70 @@
import {
type HtmlAST,
HtmlASTToDeltaExtension,
} from '@blocksuite/affine-shared/adapters';
import type { Element } from 'hast';
const isElement = (ast: HtmlAST): ast is Element => {
return ast.type === 'element';
};
export const htmlLinkElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const href = ast.properties?.href;
if (typeof href !== 'string') {
return [];
}
const { configs } = context;
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
if (baseUrl && href.startsWith(baseUrl)) {
const path = href.substring(baseUrl.length);
// ^ - /{pageId}?mode={mode}&blockIds={blockIds}&elementIds={elementIds}
const match = path.match(/^\/([^?]+)(\?.*)?$/);
if (match) {
const pageId = match?.[1];
const search = match?.[2];
const searchParams = search ? new URLSearchParams(search) : undefined;
const mode = searchParams?.get('mode');
const blockIds = searchParams?.get('blockIds')?.split(',');
const elementIds = searchParams?.get('elementIds')?.split(',');
return [
{
insert: ' ',
attributes: {
reference: {
type: 'LinkedPage',
pageId,
params: {
mode:
mode && ['edgeless', 'page'].includes(mode)
? (mode as 'edgeless' | 'page')
: undefined,
blockIds,
elementIds,
},
},
},
},
];
}
}
return ast.children.flatMap(child =>
context.toDelta(child, { trim: false }).map(delta => {
if (href.startsWith('http')) {
delta.attributes = {
...delta.attributes,
link: href,
};
return delta;
}
return delta;
})
);
},
});

View File

@@ -0,0 +1,25 @@
import type { InlineHtmlAST } from '@blocksuite/affine-shared/adapters';
import { InlineDeltaToHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
export const linkDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
name: 'link',
match: delta => !!delta.attributes?.link,
toAST: (delta, _) => {
const hast: InlineHtmlAST = {
type: 'text',
value: delta.insert,
};
const link = delta.attributes?.link;
if (!link) {
return hast;
}
return {
type: 'element',
tagName: 'a',
properties: {
href: link,
},
children: [hast],
};
},
});

View File

@@ -0,0 +1,6 @@
export * from './html/html-inline';
export * from './html/inline-delta';
export * from './markdown/inline-delta';
export * from './markdown/markdown-inline';
export * from './notion-html/html-inline';
export * from './plain-text/inline-delta';

View File

@@ -0,0 +1,36 @@
import { InlineDeltaToMarkdownAdapterExtension } from '@blocksuite/affine-shared/adapters';
import type { PhrasingContent } from '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;
},
});

View File

@@ -0,0 +1,52 @@
import { MarkdownASTToDeltaExtension } from '@blocksuite/affine-shared/adapters';
export const markdownLinkToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'link',
match: ast => ast.type === 'link',
toDelta: (ast, context) => {
if (!('children' in ast) || !('url' in ast)) {
return [];
}
const { configs } = context;
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
if (baseUrl && ast.url.startsWith(baseUrl)) {
const path = ast.url.substring(baseUrl.length);
// ^ - /{pageId}?mode={mode}&blockIds={blockIds}&elementIds={elementIds}
const match = path.match(/^\/([^?]+)(\?.*)?$/);
if (match) {
const pageId = match?.[1];
const search = match?.[2];
const searchParams = search ? new URLSearchParams(search) : undefined;
const mode = searchParams?.get('mode');
const blockIds = searchParams?.get('blockIds')?.split(',');
const elementIds = searchParams?.get('elementIds')?.split(',');
return [
{
insert: ' ',
attributes: {
reference: {
type: 'LinkedPage',
pageId,
params: {
mode:
mode && ['edgeless', 'page'].includes(mode)
? (mode as 'edgeless' | 'page')
: undefined,
blockIds,
elementIds,
},
},
},
},
];
}
}
return ast.children.flatMap(child =>
context.toDelta(child).map(delta => {
delta.attributes = { ...delta.attributes, link: ast.url };
return delta;
})
);
},
});

View File

@@ -0,0 +1,52 @@
import {
type HtmlAST,
NotionHtmlASTToDeltaExtension,
} from '@blocksuite/affine-shared/adapters';
import type { Element } from 'hast';
const isElement = (ast: HtmlAST): ast is Element => {
return ast.type === 'element';
};
export const notionHtmlLinkElementToDeltaMatcher =
NotionHtmlASTToDeltaExtension({
name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const href = ast.properties?.href;
if (typeof href !== 'string') {
return [];
}
const { toDelta, options } = context;
return ast.children.flatMap(child =>
toDelta(child, options).map(delta => {
if (options.pageMap) {
const pageId = options.pageMap.get(decodeURIComponent(href));
if (pageId) {
delta.attributes = {
...delta.attributes,
reference: {
type: 'LinkedPage',
pageId,
},
};
delta.insert = ' ';
return delta;
}
}
if (href.startsWith('http')) {
delta.attributes = {
...delta.attributes,
link: href,
};
return delta;
}
return delta;
})
);
},
});

View File

@@ -0,0 +1,25 @@
import {
InlineDeltaToPlainTextAdapterExtension,
type TextBuffer,
} from '@blocksuite/affine-shared/adapters';
export const linkDeltaMarkdownAdapterMatch =
InlineDeltaToPlainTextAdapterExtension({
name: 'link',
match: delta => !!delta.attributes?.link,
toAST: delta => {
const linkText = delta.insert;
const node: TextBuffer = {
content: linkText,
};
const link = delta.attributes?.link;
if (!link) {
return node;
}
const content = `${linkText ? `${linkText}: ` : ''}${link}`;
return {
content,
};
},
});

View File

@@ -0,0 +1,42 @@
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { Command } from '@blocksuite/block-std';
import {
INLINE_ROOT_ATTR,
type InlineRootElement,
} from '@blocksuite/block-std/inline';
import { toggleLinkPopup } from './link-node/link-popup/toggle-link-popup';
export const toggleLink: Command = (ctx, next) => {
const selection = document.getSelection();
if (!selection || selection.rangeCount === 0) return false;
const range = selection.getRangeAt(0);
if (range.collapsed) return false;
const inlineRoot = range.startContainer.parentElement?.closest<
InlineRootElement<AffineTextAttributes>
>(`[${INLINE_ROOT_ATTR}]`);
if (!inlineRoot) return false;
const inlineEditor = inlineRoot.inlineEditor;
const targetInlineRange = inlineEditor.getInlineRange();
if (!targetInlineRange || targetInlineRange.length === 0) return false;
const format = inlineEditor.getFormat(targetInlineRange);
if (format.link) {
inlineEditor.formatText(targetInlineRange, { link: null });
return next();
}
const abortController = new AbortController();
const popup = toggleLinkPopup(
ctx.std,
'create',
inlineEditor,
targetInlineRange,
abortController
);
abortController.signal.addEventListener('abort', () => popup.remove());
return next();
};

View File

@@ -0,0 +1,7 @@
import { AffineLink } from './link-node/affine-link';
import { LinkPopup } from './link-node/link-popup/link-popup';
export function effects() {
customElements.define('link-popup', LinkPopup);
customElements.define('affine-link', AffineLink);
}

View File

@@ -0,0 +1,9 @@
import type { ExtensionType } from '@blocksuite/store';
import { LinkInlineSpecExtension } from './inline-spec';
import { linkToolbar } from './toolbar';
export const inlineLinkExtensions: ExtensionType[] = [
LinkInlineSpecExtension,
linkToolbar,
];

View File

@@ -0,0 +1,6 @@
export * from './adapters';
export * from './command';
export * from './exts';
export * from './inline-spec';
export * from './link-node';
export * from './toolbar';

View File

@@ -0,0 +1,20 @@
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { StdIdentifier } from '@blocksuite/block-std';
import { InlineSpecExtension } from '@blocksuite/block-std/inline';
import { html } from 'lit';
import { z } from 'zod';
export const LinkInlineSpecExtension =
InlineSpecExtension<AffineTextAttributes>('link', provider => {
const std = provider.get(StdIdentifier);
return {
name: 'link',
schema: z.string().optional().nullable().catch(undefined),
match: delta => {
return !!delta.attributes?.link;
},
renderer: ({ delta }) => {
return html`<affine-link .std=${std} .delta=${delta}></affine-link>`;
},
};
});

View File

@@ -1,9 +1,11 @@
import { whenHover } from '@blocksuite/affine-components/hover';
import { RefNodeSlotsProvider } from '@blocksuite/affine-inline-reference';
import type { ReferenceInfo } from '@blocksuite/affine-model';
import {
ParseDocUrlProvider,
ToolbarRegistryIdentifier,
} from '@blocksuite/affine-shared/services';
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { BlockComponent, BlockStdScope } from '@blocksuite/block-std';
import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/block-std';
@@ -18,9 +20,6 @@ import { css, html } from 'lit';
import { property } from 'lit/decorators.js';
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
import { RefNodeSlotsProvider } from '../../../../extension';
import { affineTextStyles } from '../affine-text';
export class AffineLink extends WithDisposable(ShadowlessElement) {
static override styles = css`
affine-link a:hover [data-v-text='true'] {

View File

@@ -1,4 +1,5 @@
import type { EditorIconButton } from '@blocksuite/affine-components/toolbar';
import type { AffineInlineEditor } from '@blocksuite/affine-shared/types';
import {
isValidUrl,
normalizeUrl,
@@ -13,7 +14,6 @@ import { html, LitElement } from 'lit';
import { property, query } from 'lit/decorators.js';
import { choose } from 'lit/directives/choose.js';
import type { AffineInlineEditor } from '../../../affine-inline-specs';
import { linkPopupStyle } from './styles';
export class LinkPopup extends WithDisposable(LitElement) {

View File

@@ -1,7 +1,7 @@
import type { AffineInlineEditor } from '@blocksuite/affine-shared/types';
import type { BlockStdScope } from '@blocksuite/block-std';
import type { InlineRange } from '@blocksuite/block-std/inline';
import type { AffineInlineEditor } from '../../../affine-inline-specs';
import { LinkPopup } from './link-popup';
export function toggleLinkPopup(

View File

@@ -0,0 +1,9 @@
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { builtinInlineLinkToolbarConfig } from './link-node/configs/toolbar.js';
export const linkToolbar = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:link'),
config: builtinInlineLinkToolbarConfig,
});

View File

@@ -0,0 +1,18 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
},
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../reference" },
{ "path": "../../model" },
{ "path": "../../shared" },
{ "path": "../../../framework/block-std" },
{ "path": "../../../framework/global" },
{ "path": "../../../framework/store" }
]
}

View File

@@ -0,0 +1,54 @@
{
"name": "@blocksuite/affine-inline-preset",
"description": "Inline preset for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-link": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.2.6",
"@blocksuite/store": "workspace:*",
"@floating-ui/dom": "^1.6.13",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"@types/hast": "^3.0.4",
"@types/katex": "^0.16.7",
"@types/lodash-es": "^4.17.12",
"@types/mdast": "^4.0.4",
"collapse-white-space": "^2.1.0",
"date-fns": "^4.0.0",
"katex": "^0.16.11",
"lit": "^3.2.0",
"lit-html": "^3.2.1",
"lodash-es": "^4.17.21",
"remark-math": "^6.0.0",
"rxjs": "^7.8.1",
"shiki": "^3.0.0",
"yjs": "^13.6.21",
"zod": "^3.23.8"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.20.0"
}

View File

@@ -15,3 +15,10 @@ export const InlineAdapterExtensions: ExtensionType[] = [
InlineDeltaToMarkdownAdapterExtensions,
MarkdownInlineToDeltaAdapterExtensions,
].flat();
export * from './html/html-inline';
export * from './html/inline-delta';
export * from './markdown/inline-delta';
export * from './markdown/markdown-inline';
export * from './notion-html/html-inline';
export * from './plain-text/inline-delta';

View File

@@ -1,3 +1,4 @@
import { htmlLinkElementToDeltaMatcher } from '@blocksuite/affine-inline-link';
import {
type HtmlAST,
HtmlASTToDeltaExtension,
@@ -136,67 +137,6 @@ export const htmlUnderlineElementToDeltaMatcher = HtmlASTToDeltaExtension({
},
});
export const htmlLinkElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const href = ast.properties?.href;
if (typeof href !== 'string') {
return [];
}
const { configs } = context;
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
if (baseUrl && href.startsWith(baseUrl)) {
const path = href.substring(baseUrl.length);
// ^ - /{pageId}?mode={mode}&blockIds={blockIds}&elementIds={elementIds}
const match = path.match(/^\/([^?]+)(\?.*)?$/);
if (match) {
const pageId = match?.[1];
const search = match?.[2];
const searchParams = search ? new URLSearchParams(search) : undefined;
const mode = searchParams?.get('mode');
const blockIds = searchParams?.get('blockIds')?.split(',');
const elementIds = searchParams?.get('elementIds')?.split(',');
return [
{
insert: ' ',
attributes: {
reference: {
type: 'LinkedPage',
pageId,
params: {
mode:
mode && ['edgeless', 'page'].includes(mode)
? (mode as 'edgeless' | 'page')
: undefined,
blockIds,
elementIds,
},
},
},
},
];
}
}
return ast.children.flatMap(child =>
context.toDelta(child, { trim: false }).map(delta => {
if (href.startsWith('http')) {
delta.attributes = {
...delta.attributes,
link: href,
};
return delta;
}
return delta;
})
);
},
});
export const htmlMarkElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'mark-element',
match: ast => isElement(ast) && ast.tagName === 'mark',

View File

@@ -1,8 +1,7 @@
import { linkDeltaToHtmlAdapterMatcher } from '@blocksuite/affine-inline-link';
import { referenceDeltaToHtmlAdapterMatcher } from '@blocksuite/affine-inline-reference';
import type { InlineHtmlAST } from '@blocksuite/affine-shared/adapters';
import {
AdapterTextUtils,
InlineDeltaToHtmlAdapterExtension,
} from '@blocksuite/affine-shared/adapters';
import { InlineDeltaToHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
export const boldDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
@@ -74,66 +73,6 @@ export const underlineDeltaToHtmlAdapterMatcher =
},
});
export const referenceDeltaToHtmlAdapterMatcher =
InlineDeltaToHtmlAdapterExtension({
name: 'reference',
match: delta => !!delta.attributes?.reference,
toAST: (delta, context) => {
let hast: InlineHtmlAST = {
type: 'text',
value: delta.insert,
};
const reference = delta.attributes?.reference;
if (!reference) {
return hast;
}
const { configs } = context;
const title = configs.get(`title:${reference.pageId}`);
const url = AdapterTextUtils.generateDocUrl(
configs.get('docLinkBaseUrl') ?? '',
String(reference.pageId),
reference.params ?? Object.create(null)
);
if (title) {
hast.value = title;
}
hast = {
type: 'element',
tagName: 'a',
properties: {
href: url,
},
children: [hast],
};
return hast;
},
});
export const linkDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
name: 'link',
match: delta => !!delta.attributes?.link,
toAST: (delta, _) => {
const hast: InlineHtmlAST = {
type: 'text',
value: delta.insert,
};
const link = delta.attributes?.link;
if (!link) {
return hast;
}
return {
type: 'element',
tagName: 'a',
properties: {
href: link,
},
children: [hast],
};
},
});
export const highlightBackgroundDeltaToHtmlAdapterMatcher =
InlineDeltaToHtmlAdapterExtension({
name: 'highlight-background',

View File

@@ -1,5 +1,6 @@
import { linkDeltaToMarkdownAdapterMatcher } from '@blocksuite/affine-inline-link';
import { referenceDeltaToMarkdownAdapterMatcher } from '@blocksuite/affine-inline-reference';
import {
AdapterTextUtils,
FOOTNOTE_DEFINITION_PREFIX,
InlineDeltaToMarkdownAdapterExtension,
} from '@blocksuite/affine-shared/adapters';
@@ -57,77 +58,6 @@ export const inlineCodeDeltaToMarkdownAdapterMatcher =
}),
});
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',

View File

@@ -1,3 +1,4 @@
import { markdownLinkToDeltaMatcher } from '@blocksuite/affine-inline-link';
import { FootNoteReferenceParamsSchema } from '@blocksuite/affine-model';
import {
FOOTNOTE_DEFINITION_PREFIX,
@@ -74,57 +75,6 @@ export const markdownDeleteToDeltaMatcher = MarkdownASTToDeltaExtension({
},
});
export const markdownLinkToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'link',
match: ast => ast.type === 'link',
toDelta: (ast, context) => {
if (!('children' in ast) || !('url' in ast)) {
return [];
}
const { configs } = context;
const baseUrl = configs.get('docLinkBaseUrl') ?? '';
if (baseUrl && ast.url.startsWith(baseUrl)) {
const path = ast.url.substring(baseUrl.length);
// ^ - /{pageId}?mode={mode}&blockIds={blockIds}&elementIds={elementIds}
const match = path.match(/^\/([^?]+)(\?.*)?$/);
if (match) {
const pageId = match?.[1];
const search = match?.[2];
const searchParams = search ? new URLSearchParams(search) : undefined;
const mode = searchParams?.get('mode');
const blockIds = searchParams?.get('blockIds')?.split(',');
const elementIds = searchParams?.get('elementIds')?.split(',');
return [
{
insert: ' ',
attributes: {
reference: {
type: 'LinkedPage',
pageId,
params: {
mode:
mode && ['edgeless', 'page'].includes(mode)
? (mode as 'edgeless' | 'page')
: undefined,
blockIds,
elementIds,
},
},
},
},
];
}
}
return ast.children.flatMap(child =>
context.toDelta(child).map(delta => {
delta.attributes = { ...delta.attributes, link: ast.url };
return delta;
})
);
},
});
export const markdownListToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'list',
match: ast => ast.type === 'list',

View File

@@ -1,3 +1,4 @@
import { notionHtmlLinkElementToDeltaMatcher } from '@blocksuite/affine-inline-link';
import {
HastUtils,
type HtmlAST,
@@ -185,49 +186,6 @@ export const notionHtmlUnderlineElementToDeltaMatcher =
},
});
export const notionHtmlLinkElementToDeltaMatcher =
NotionHtmlASTToDeltaExtension({
name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const href = ast.properties?.href;
if (typeof href !== 'string') {
return [];
}
const { toDelta, options } = context;
return ast.children.flatMap(child =>
toDelta(child, options).map(delta => {
if (options.pageMap) {
const pageId = options.pageMap.get(decodeURIComponent(href));
if (pageId) {
delta.attributes = {
...delta.attributes,
reference: {
type: 'LinkedPage',
pageId,
},
};
delta.insert = ' ';
return delta;
}
}
if (href.startsWith('http')) {
delta.attributes = {
...delta.attributes,
link: href,
};
return delta;
}
return delta;
})
);
},
});
export const notionHtmlMarkElementToDeltaMatcher =
NotionHtmlASTToDeltaExtension({
name: 'mark-element',

View File

@@ -0,0 +1,30 @@
import { linkDeltaMarkdownAdapterMatch } from '@blocksuite/affine-inline-link';
import { referenceDeltaMarkdownAdapterMatch } from '@blocksuite/affine-inline-reference';
import {
InlineDeltaToPlainTextAdapterExtension,
type TextBuffer,
} from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/store';
export const latexDeltaMarkdownAdapterMatch =
InlineDeltaToPlainTextAdapterExtension({
name: 'inlineLatex',
match: delta => !!delta.attributes?.latex,
toAST: delta => {
const node: TextBuffer = {
content: delta.insert,
};
if (!delta.attributes?.latex) {
return node;
}
return {
content: delta.attributes?.latex,
};
},
});
export const InlineDeltaToPlainTextAdapterExtensions: ExtensionType[] = [
referenceDeltaMarkdownAdapterMatch,
linkDeltaMarkdownAdapterMatch,
latexDeltaMarkdownAdapterMatch,
];

View File

@@ -6,6 +6,7 @@ import {
StrikethroughIcon,
UnderlineIcon,
} from '@blocksuite/affine-components/icons';
import { toggleLink } from '@blocksuite/affine-inline-link';
import { type EditorHost, TextSelection } from '@blocksuite/block-std';
import type { TemplateResult } from 'lit';
@@ -14,7 +15,6 @@ import {
toggleBold,
toggleCode,
toggleItalic,
toggleLink,
toggleStrike,
toggleUnderline,
} from './text-style.js';

View File

@@ -1,3 +1,4 @@
import { clearMarksOnDiscontinuousInput } from '@blocksuite/affine-rich-text';
import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { Command, TextSelection } from '@blocksuite/block-std';
@@ -7,7 +8,6 @@ import {
} from '@blocksuite/block-std/inline';
import { FORMAT_TEXT_SUPPORT_FLAVOURS } from './consts.js';
import { clearMarksOnDiscontinuousInput } from './utils.js';
// for text selection
export const formatTextCommand: Command<{

View File

@@ -16,13 +16,8 @@ export {
toggleBold,
toggleCode,
toggleItalic,
toggleLink,
toggleStrike,
toggleTextStyleCommand,
toggleUnderline,
} from './text-style.js';
export {
clearMarksOnDiscontinuousInput,
insertContent,
isFormatSupported,
} from './utils.js';
export { isFormatSupported } from './utils.js';

View File

@@ -4,12 +4,7 @@ import {
} from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { Command } from '@blocksuite/block-std';
import {
INLINE_ROOT_ATTR,
type InlineRootElement,
} from '@blocksuite/block-std/inline';
import { toggleLinkPopup } from '../inline/index.js';
import { formatBlockCommand } from './format-block.js';
import { formatNativeCommand } from './format-native.js';
import { formatTextCommand } from './format-text.js';
@@ -71,40 +66,6 @@ export const toggleUnderline = toggleTextStyleCommandWrapper('underline');
export const toggleStrike = toggleTextStyleCommandWrapper('strike');
export const toggleCode = toggleTextStyleCommandWrapper('code');
export const toggleLink: Command = (ctx, next) => {
const selection = document.getSelection();
if (!selection || selection.rangeCount === 0) return false;
const range = selection.getRangeAt(0);
if (range.collapsed) return false;
const inlineRoot = range.startContainer.parentElement?.closest<
InlineRootElement<AffineTextAttributes>
>(`[${INLINE_ROOT_ATTR}]`);
if (!inlineRoot) return false;
const inlineEditor = inlineRoot.inlineEditor;
const targetInlineRange = inlineEditor.getInlineRange();
if (!targetInlineRange || targetInlineRange.length === 0) return false;
const format = inlineEditor.getFormat(targetInlineRange);
if (format.link) {
inlineEditor.formatText(targetInlineRange, { link: null });
return next();
}
const abortController = new AbortController();
const popup = toggleLinkPopup(
ctx.std,
'create',
inlineEditor,
targetInlineRange,
abortController
);
abortController.signal.addEventListener('abort', () => popup.remove());
return next();
};
export const getTextStyle: Command<{}, { textStyle: AffineTextAttributes }> = (
ctx,
next

View File

@@ -3,11 +3,13 @@ import {
getSelectedBlocksCommand,
getTextSelectionCommand,
} from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type {
AffineInlineEditor,
AffineTextAttributes,
} from '@blocksuite/affine-shared/types';
import {
BLOCK_ID_ATTR,
type BlockComponent,
type BlockStdScope,
type Chain,
type InitCommandCtx,
} from '@blocksuite/block-std';
@@ -17,11 +19,7 @@ import {
type InlineRange,
type InlineRootElement,
} from '@blocksuite/block-std/inline';
import type { BlockModel } from '@blocksuite/store';
import { effect } from '@preact/signals-core';
import { getInlineEditorByModel } from '../dom.js';
import type { AffineInlineEditor } from '../inline/index.js';
import {
FORMAT_BLOCK_SUPPORT_FLAVOURS,
FORMAT_NATIVE_SUPPORT_FLAVOURS,
@@ -209,50 +207,3 @@ export function isFormatSupported(chain: Chain<InitCommandCtx>) {
(_type, inlineEditors) => inlineEditors.length > 0
);
}
// When the user selects a range, check if it matches the previous selection.
// If it does, apply the marks from the previous selection.
// If it does not, remove the marks from the previous selection.
export function clearMarksOnDiscontinuousInput(
inlineEditor: InlineEditor
): void {
let inlineRange = inlineEditor.getInlineRange();
const dispose = effect(() => {
const r = inlineEditor.inlineRange$.value;
if (
inlineRange &&
r &&
(inlineRange.index === r.index || inlineRange.index === r.index + 1)
) {
inlineRange = r;
} else {
inlineEditor.resetMarks();
dispose();
}
});
}
export function insertContent(
std: BlockStdScope,
model: BlockModel,
text: string,
attributes?: AffineTextAttributes
) {
if (!model.text) {
console.error("Can't insert text! Text not found");
return;
}
const inlineEditor = getInlineEditorByModel(std, model);
if (!inlineEditor) {
console.error("Can't insert text! Inline editor not found");
return;
}
const inlineRange = inlineEditor.getInlineRange();
const index = inlineRange ? inlineRange.index : model.text.length;
model.text.insert(text, index, attributes as Record<string, unknown>);
// Update the caret to the end of the inserted text
inlineEditor.setInlineRange({
index: index + text.length,
length: 0,
});
}

View File

@@ -1,6 +1,7 @@
import { LinkInlineSpecExtension } from '@blocksuite/affine-inline-link';
import { ReferenceInlineSpecExtension } from '@blocksuite/affine-inline-reference';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { InlineManagerExtension } from '@blocksuite/block-std/inline';
import type { ExtensionType } from '@blocksuite/store';
import {
BackgroundInlineSpecExtension,
@@ -8,17 +9,11 @@ import {
CodeInlineSpecExtension,
ColorInlineSpecExtension,
FootNoteInlineSpecExtension,
InlineAdapterExtensions,
InlineSpecExtensions,
ItalicInlineSpecExtension,
LatexInlineSpecExtension,
LinkInlineSpecExtension,
MarkdownExtensions,
ReferenceInlineSpecExtension,
StrikeInlineSpecExtension,
UnderlineInlineSpecExtension,
} from './inline/index.js';
import { LatexEditorInlineManagerExtension } from './inline/presets/nodes/latex-node/latex-editor-menu.js';
} from './inline-spec';
export const DefaultInlineManagerExtension =
InlineManagerExtension<AffineTextAttributes>({
@@ -37,11 +32,3 @@ export const DefaultInlineManagerExtension =
FootNoteInlineSpecExtension.identifier,
],
});
export const RichTextExtensions: ExtensionType[] = [
InlineSpecExtensions,
MarkdownExtensions,
LatexEditorInlineManagerExtension,
DefaultInlineManagerExtension,
InlineAdapterExtensions,
].flat();

View File

@@ -0,0 +1,29 @@
import { AffineText } from './nodes/affine-text';
import { AffineFootnoteNode } from './nodes/footnote-node/footnote-node';
import { FootNotePopup } from './nodes/footnote-node/footnote-popup';
import { FootNotePopupChip } from './nodes/footnote-node/footnote-popup-chip';
import { LatexEditorMenu } from './nodes/latex-node/latex-editor-menu';
import { LatexEditorUnit } from './nodes/latex-node/latex-editor-unit';
import { AffineLatexNode } from './nodes/latex-node/latex-node';
export function effects() {
customElements.define('affine-text', AffineText);
customElements.define('latex-editor-menu', LatexEditorMenu);
customElements.define('latex-editor-unit', LatexEditorUnit);
customElements.define('affine-latex-node', AffineLatexNode);
customElements.define('affine-footnote-node', AffineFootnoteNode);
customElements.define('footnote-popup', FootNotePopup);
customElements.define('footnote-popup-chip', FootNotePopupChip);
}
declare global {
interface HTMLElementTagNameMap {
'affine-latex-node': AffineLatexNode;
'affine-footnote-node': AffineFootnoteNode;
'footnote-popup': FootNotePopup;
'footnote-popup-chip': FootNotePopupChip;
'affine-text': AffineText;
'latex-editor-unit': LatexEditorUnit;
'latex-editor-menu': LatexEditorMenu;
}
}

View File

@@ -0,0 +1,13 @@
import { InlineAdapterExtensions } from './adapters/extensions';
import { DefaultInlineManagerExtension } from './default-inline-manager';
import { InlineSpecExtensions } from './inline-spec';
import { MarkdownExtensions } from './markdown';
import { LatexEditorInlineManagerExtension } from './nodes/latex-node/latex-editor-menu';
export const inlinePresetExtensions = [
DefaultInlineManagerExtension,
...MarkdownExtensions,
LatexEditorInlineManagerExtension,
...InlineSpecExtensions,
...InlineAdapterExtensions,
];

View File

@@ -0,0 +1,12 @@
import type * as RichTextEffects from '@blocksuite/affine-rich-text/effects';
declare type _GLOBAL_ = typeof RichTextEffects;
export * from './adapters/extensions';
export * from './command';
export * from './default-inline-manager';
export * from './exts';
export * from './inline-spec';
export * from './keymap';
export * from './markdown';
export * from './nodes';

View File

@@ -1,24 +1,18 @@
import { FootNoteSchema, ReferenceInfoSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { inlineLinkExtensions } from '@blocksuite/affine-inline-link';
import { inlineReferenceExtensions } from '@blocksuite/affine-inline-reference';
import { FootNoteSchema } from '@blocksuite/affine-model';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { BlockFlavourIdentifier, StdIdentifier } from '@blocksuite/block-std';
import { StdIdentifier } from '@blocksuite/block-std';
import {
type InlineEditor,
type InlineRootElement,
InlineSpecExtension,
} from '@blocksuite/block-std/inline';
import type { ExtensionType } from '@blocksuite/store';
import { html } from 'lit';
import { z } from 'zod';
import { FootNoteNodeConfigIdentifier } from './nodes/footnote-node/footnote-config.js';
import { builtinInlineLinkToolbarConfig } from './nodes/link-node/configs/toolbar.js';
import { builtinInlineReferenceToolbarConfig } from './nodes/reference-node/configs/toolbar.js';
import {
ReferenceNodeConfigExtension,
ReferenceNodeConfigProvider,
} from './nodes/reference-node/reference-config.js';
export type AffineInlineEditor = InlineEditor<AffineTextAttributes>;
export type AffineInlineRootElement = InlineRootElement<AffineTextAttributes>;
export const BoldInlineSpecExtension =
@@ -126,65 +120,6 @@ export const LatexInlineSpecExtension =
};
});
export const ReferenceInlineSpecExtension =
InlineSpecExtension<AffineTextAttributes>('reference', provider => {
const std = provider.get(StdIdentifier);
const configProvider = new ReferenceNodeConfigProvider(std);
const config =
provider.getOptional(ReferenceNodeConfigExtension.identifier) ?? {};
if (config.customContent) {
configProvider.setCustomContent(config.customContent);
}
if (config.interactable !== undefined) {
configProvider.setInteractable(config.interactable);
}
if (config.hidePopup !== undefined) {
configProvider.setHidePopup(config.hidePopup);
}
return {
name: 'reference',
schema: z
.object({
type: z.enum([
// @deprecated Subpage is deprecated, use LinkedPage instead
'Subpage',
'LinkedPage',
]),
})
.merge(ReferenceInfoSchema)
.optional()
.nullable()
.catch(undefined),
match: delta => {
return !!delta.attributes?.reference;
},
renderer: ({ delta, selected }) => {
return html`<affine-reference
.std=${std}
.delta=${delta}
.selected=${selected}
.config=${configProvider}
></affine-reference>`;
},
embed: true,
};
});
export const LinkInlineSpecExtension =
InlineSpecExtension<AffineTextAttributes>('link', provider => {
const std = provider.get(StdIdentifier);
return {
name: 'link',
schema: z.string().optional().nullable().catch(undefined),
match: delta => {
return !!delta.attributes?.link;
},
renderer: ({ delta }) => {
return html`<affine-link .std=${std} .delta=${delta}></affine-link>`;
},
};
});
export const LatexEditorUnitSpecExtension =
InlineSpecExtension<AffineTextAttributes>({
name: 'latex-editor-unit',
@@ -217,7 +152,7 @@ export const FootNoteInlineSpecExtension =
};
});
export const InlineSpecExtensions = [
export const InlineSpecExtensions: ExtensionType[] = [
BoldInlineSpecExtension,
ItalicInlineSpecExtension,
UnderlineInlineSpecExtension,
@@ -226,18 +161,8 @@ export const InlineSpecExtensions = [
BackgroundInlineSpecExtension,
ColorInlineSpecExtension,
LatexInlineSpecExtension,
ReferenceInlineSpecExtension,
LinkInlineSpecExtension,
...inlineLinkExtensions,
...inlineReferenceExtensions,
LatexEditorUnitSpecExtension,
FootNoteInlineSpecExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:reference'),
config: builtinInlineReferenceToolbarConfig,
}),
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:link'),
config: builtinInlineLinkToolbarConfig,
}),
];

View File

@@ -1,3 +1,8 @@
import {
focusTextModel,
getInlineEditorByModel,
selectTextModel,
} from '@blocksuite/affine-rich-text';
import {
BlockSelection,
type BlockStdScope,
@@ -5,12 +10,6 @@ import {
type UIEventHandler,
} from '@blocksuite/block-std';
import {
focusTextModel,
getInlineEditorByModel,
selectTextModel,
} from '../dom.js';
export const textCommonKeymap = (
std: BlockStdScope
): Record<string, UIEventHandler> => {

View File

@@ -1,4 +1,6 @@
import { insertLinkedNode } from '@blocksuite/affine-inline-reference';
import { CodeBlockModel } from '@blocksuite/affine-model';
import { getInlineEditorByModel } from '@blocksuite/affine-rich-text';
import { BRACKET_PAIRS } from '@blocksuite/affine-shared/consts';
import { createDefaultDoc, matchModels } from '@blocksuite/affine-shared/utils';
import {
@@ -8,9 +10,6 @@ import {
} from '@blocksuite/block-std';
import type { InlineEditor } from '@blocksuite/block-std/inline';
import { getInlineEditorByModel } from '../dom.js';
import { insertLinkedNode } from '../linked-node.js';
export const bracketKeymap = (
std: BlockStdScope
): Record<string, UIEventHandler> => {

Some files were not shown because too many files have changed in this diff Show More