mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-18 02:21:51 +08:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export * from './inline-manager.js';
|
||||
export * from './inline-spec.js';
|
||||
export * from './markdown-matcher.js';
|
||||
export * from './ref-node-slots.js';
|
||||
export * from './type.js';
|
||||
@@ -0,0 +1,131 @@
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import {
|
||||
type BlockStdScope,
|
||||
type ExtensionType,
|
||||
StdIdentifier,
|
||||
} from '@blocksuite/block-std';
|
||||
import {
|
||||
createIdentifier,
|
||||
type ServiceIdentifier,
|
||||
} from '@blocksuite/global/di';
|
||||
import {
|
||||
type AttributeRenderer,
|
||||
baseTextAttributes,
|
||||
type DeltaInsert,
|
||||
getDefaultAttributeRenderer,
|
||||
KEYBOARD_ALLOW_DEFAULT,
|
||||
type KeyboardBindingContext,
|
||||
} from '@blocksuite/inline';
|
||||
import type { Y } from '@blocksuite/store';
|
||||
import { z, type ZodObject, type ZodTypeAny } from 'zod';
|
||||
|
||||
import { MarkdownMatcherIdentifier } from './markdown-matcher.js';
|
||||
import type { InlineMarkdownMatch, InlineSpecs } from './type.js';
|
||||
|
||||
export class InlineManager {
|
||||
embedChecker = (delta: DeltaInsert<AffineTextAttributes>) => {
|
||||
for (const spec of this.specs) {
|
||||
if (spec.embed && spec.match(delta)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
getRenderer = (): AttributeRenderer<AffineTextAttributes> => {
|
||||
const defaultRenderer = getDefaultAttributeRenderer<AffineTextAttributes>();
|
||||
|
||||
const renderer: AttributeRenderer<AffineTextAttributes> = props => {
|
||||
// Priority increases from front to back
|
||||
for (const spec of this.specs.toReversed()) {
|
||||
if (spec.match(props.delta)) {
|
||||
return spec.renderer(props);
|
||||
}
|
||||
}
|
||||
return defaultRenderer(props);
|
||||
};
|
||||
return renderer;
|
||||
};
|
||||
|
||||
getSchema = (): ZodObject<Record<keyof AffineTextAttributes, ZodTypeAny>> => {
|
||||
const defaultSchema = baseTextAttributes as unknown as ZodObject<
|
||||
Record<keyof AffineTextAttributes, ZodTypeAny>
|
||||
>;
|
||||
|
||||
const schema: ZodObject<Record<keyof AffineTextAttributes, ZodTypeAny>> =
|
||||
this.specs.reduce((acc, cur) => {
|
||||
const currentSchema = z.object({
|
||||
[cur.name]: cur.schema,
|
||||
}) as ZodObject<Record<keyof AffineTextAttributes, ZodTypeAny>>;
|
||||
return acc.merge(currentSchema) as ZodObject<
|
||||
Record<keyof AffineTextAttributes, ZodTypeAny>
|
||||
>;
|
||||
}, defaultSchema);
|
||||
return schema;
|
||||
};
|
||||
|
||||
markdownShortcutHandler = (
|
||||
context: KeyboardBindingContext<AffineTextAttributes>,
|
||||
undoManager: Y.UndoManager
|
||||
) => {
|
||||
const { inlineEditor, prefixText, inlineRange } = context;
|
||||
for (const match of this.markdownMatches) {
|
||||
const matchedText = prefixText.match(match.pattern);
|
||||
if (matchedText) {
|
||||
return match.action({
|
||||
inlineEditor,
|
||||
prefixText,
|
||||
inlineRange,
|
||||
pattern: match.pattern,
|
||||
undoManager,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return KEYBOARD_ALLOW_DEFAULT;
|
||||
};
|
||||
|
||||
readonly specs: Array<InlineSpecs<AffineTextAttributes>>;
|
||||
|
||||
constructor(
|
||||
readonly std: BlockStdScope,
|
||||
readonly markdownMatches: InlineMarkdownMatch<AffineTextAttributes>[],
|
||||
...specs: Array<InlineSpecs<AffineTextAttributes>>
|
||||
) {
|
||||
this.specs = specs;
|
||||
}
|
||||
}
|
||||
|
||||
export const InlineManagerIdentifier = createIdentifier<InlineManager>(
|
||||
'AffineInlineManager'
|
||||
);
|
||||
|
||||
export type InlineManagerExtensionConfig = {
|
||||
id: string;
|
||||
enableMarkdown?: boolean;
|
||||
specs: ServiceIdentifier<InlineSpecs<AffineTextAttributes>>[];
|
||||
};
|
||||
|
||||
export function InlineManagerExtension({
|
||||
id,
|
||||
enableMarkdown = true,
|
||||
specs,
|
||||
}: InlineManagerExtensionConfig): ExtensionType & {
|
||||
identifier: ServiceIdentifier<InlineManager>;
|
||||
} {
|
||||
const identifier = InlineManagerIdentifier(id);
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(identifier, provider => {
|
||||
return new InlineManager(
|
||||
provider.get(StdIdentifier),
|
||||
enableMarkdown
|
||||
? Array.from(provider.getAll(MarkdownMatcherIdentifier).values())
|
||||
: [],
|
||||
...specs.map(spec => provider.get(spec))
|
||||
);
|
||||
});
|
||||
},
|
||||
identifier,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import {
|
||||
createIdentifier,
|
||||
type ServiceIdentifier,
|
||||
type ServiceProvider,
|
||||
} from '@blocksuite/global/di';
|
||||
|
||||
import type { InlineSpecs } from './type.js';
|
||||
|
||||
export const InlineSpecIdentifier =
|
||||
createIdentifier<InlineSpecs<AffineTextAttributes>>('AffineInlineSpec');
|
||||
|
||||
export function InlineSpecExtension(
|
||||
name: string,
|
||||
getSpec: (provider: ServiceProvider) => InlineSpecs<AffineTextAttributes>
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<InlineSpecs<AffineTextAttributes>>;
|
||||
};
|
||||
export function InlineSpecExtension(
|
||||
spec: InlineSpecs<AffineTextAttributes>
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<InlineSpecs<AffineTextAttributes>>;
|
||||
};
|
||||
export function InlineSpecExtension(
|
||||
nameOrSpec: string | InlineSpecs<AffineTextAttributes>,
|
||||
getSpec?: (provider: ServiceProvider) => InlineSpecs<AffineTextAttributes>
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<InlineSpecs<AffineTextAttributes>>;
|
||||
} {
|
||||
if (typeof nameOrSpec === 'string') {
|
||||
const identifier = InlineSpecIdentifier(nameOrSpec);
|
||||
return {
|
||||
identifier,
|
||||
setup: di => {
|
||||
di.addImpl(identifier, provider => getSpec!(provider));
|
||||
},
|
||||
};
|
||||
}
|
||||
const identifier = InlineSpecIdentifier(nameOrSpec.name);
|
||||
return {
|
||||
identifier,
|
||||
setup: di => {
|
||||
di.addImpl(identifier, nameOrSpec);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import {
|
||||
createIdentifier,
|
||||
type ServiceIdentifier,
|
||||
} from '@blocksuite/global/di';
|
||||
|
||||
import type { InlineMarkdownMatch } from './type.js';
|
||||
|
||||
export const MarkdownMatcherIdentifier = createIdentifier<
|
||||
InlineMarkdownMatch<AffineTextAttributes>
|
||||
>('AffineMarkdownMatcher');
|
||||
|
||||
export function InlineMarkdownExtension(
|
||||
matcher: InlineMarkdownMatch<AffineTextAttributes>
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<InlineMarkdownMatch<AffineTextAttributes>>;
|
||||
} {
|
||||
const identifier = MarkdownMatcherIdentifier(matcher.name);
|
||||
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(identifier, () => ({ ...matcher }));
|
||||
},
|
||||
identifier,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import { createIdentifier } from '@blocksuite/global/di';
|
||||
import { Slot } from '@blocksuite/global/utils';
|
||||
|
||||
import type { RefNodeSlots } from '../inline/index.js';
|
||||
|
||||
export const RefNodeSlotsProvider =
|
||||
createIdentifier<RefNodeSlots>('AffineRefNodeSlots');
|
||||
|
||||
export function RefNodeSlotsExtension(
|
||||
slots: RefNodeSlots = {
|
||||
docLinkClicked: new Slot(),
|
||||
}
|
||||
): ExtensionType {
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(RefNodeSlotsProvider, () => slots);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import type {
|
||||
AttributeRenderer,
|
||||
BaseTextAttributes,
|
||||
DeltaInsert,
|
||||
InlineEditor,
|
||||
InlineRange,
|
||||
KeyboardBindingHandler,
|
||||
} from '@blocksuite/inline';
|
||||
import type { Y } from '@blocksuite/store';
|
||||
import type { ZodTypeAny } from 'zod';
|
||||
|
||||
export type InlineSpecs<
|
||||
AffineTextAttributes extends BaseTextAttributes = BaseTextAttributes,
|
||||
> = {
|
||||
name: keyof AffineTextAttributes | string;
|
||||
schema: ZodTypeAny;
|
||||
match: (delta: DeltaInsert<AffineTextAttributes>) => boolean;
|
||||
renderer: AttributeRenderer<AffineTextAttributes>;
|
||||
embed?: boolean;
|
||||
};
|
||||
|
||||
export type InlineMarkdownMatchAction<
|
||||
// @ts-expect-error We allow to covariance for AffineTextAttributes
|
||||
in AffineTextAttributes extends BaseTextAttributes = BaseTextAttributes,
|
||||
> = (props: {
|
||||
inlineEditor: InlineEditor<AffineTextAttributes>;
|
||||
prefixText: string;
|
||||
inlineRange: InlineRange;
|
||||
pattern: RegExp;
|
||||
undoManager: Y.UndoManager;
|
||||
}) => ReturnType<KeyboardBindingHandler>;
|
||||
|
||||
export type InlineMarkdownMatch<
|
||||
AffineTextAttributes extends BaseTextAttributes = BaseTextAttributes,
|
||||
> = {
|
||||
name: string;
|
||||
pattern: RegExp;
|
||||
action: InlineMarkdownMatchAction<AffineTextAttributes>;
|
||||
};
|
||||
Reference in New Issue
Block a user