diff --git a/packages/quill/src/core.ts b/packages/quill/src/core.ts index cdf5724768..5b8946ad5f 100644 --- a/packages/quill/src/core.ts +++ b/packages/quill/src/core.ts @@ -24,6 +24,7 @@ import Delta, { Op, OpIterator, AttributeMap } from 'quill-delta'; import Input from './modules/input.js'; import UINode from './modules/uiNode.js'; +export { default as Module } from './core/module.js'; export { Delta, Op, OpIterator, AttributeMap, Parchment, Range }; export type { Bounds, diff --git a/packages/quill/src/core/quill.ts b/packages/quill/src/core/quill.ts index b88a4f5fa4..f182583816 100644 --- a/packages/quill/src/core/quill.ts +++ b/packages/quill/src/core/quill.ts @@ -122,27 +122,41 @@ class Quill { } static register( - path: - | string - | Parchment.BlotConstructor - | Parchment.Attributor - | Record, - target?: Parchment.BlotConstructor | Parchment.Attributor | boolean, - overwrite = false, - ) { - if (typeof path !== 'string') { - const name = 'attrName' in path ? path.attrName : path.blotName; + targets: Record< + string, + | Parchment.RegistryDefinition + | Record // any objects + | Theme + | Module + | Function // ES5 constructors + >, + overwrite?: boolean, + ): void; + static register( + target: Parchment.RegistryDefinition, + overwrite?: boolean, + ): void; + static register(path: string, target: any, overwrite?: boolean): void; + static register(...args: any[]): void { + if (typeof args[0] !== 'string') { + const target = args[0]; + const overwrite = !!args[1]; + + const name = 'attrName' in target ? target.attrName : target.blotName; if (typeof name === 'string') { + // Shortcut for formats: // register(Blot | Attributor, overwrite) - // @ts-expect-error - this.register(`formats/${name}`, path, target); + this.register(`formats/${name}`, target, overwrite); } else { - Object.keys(path).forEach((key) => { - // @ts-expect-error - this.register(key, path[key], target); + Object.keys(target).forEach((key) => { + this.register(key, target[key], overwrite); }); } } else { + const path = args[0]; + const target = args[1]; + const overwrite = !!args[2]; + if (this.imports[path] != null && !overwrite) { debug.warn(`Overwriting ${path} with`, target); } @@ -151,14 +165,11 @@ class Quill { (path.startsWith('blots/') || path.startsWith('formats/')) && target && typeof target !== 'boolean' && - // @ts-expect-error target.blotName !== 'abstract' ) { globalRegistry.register(target); } - // @ts-expect-error if (typeof target.register === 'function') { - // @ts-expect-error target.register(globalRegistry); } } diff --git a/packages/quill/src/modules/syntax.ts b/packages/quill/src/modules/syntax.ts index ed8214e81f..da99fdc41d 100644 --- a/packages/quill/src/modules/syntax.ts +++ b/packages/quill/src/modules/syntax.ts @@ -80,7 +80,7 @@ class SyntaxCodeBlock extends CodeBlock { } } - replaceWith(name: string, value: unknown) { + replaceWith(name: string | Blot, value?: any) { this.formatAt(0, this.length(), CodeToken.blotName, false); return super.replaceWith(name, value); } @@ -180,7 +180,7 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { } } } -// @ts-expect-error + SyntaxCodeBlockContainer.allowedChildren = [SyntaxCodeBlock]; SyntaxCodeBlock.requiredContainer = SyntaxCodeBlockContainer; SyntaxCodeBlock.allowedChildren = [CodeToken, CursorBlot, TextBlot, BreakBlot]; @@ -206,7 +206,6 @@ class Syntax extends Module { static register() { Quill.register(CodeToken, true); - // @ts-expect-error Quill.register(SyntaxCodeBlock, true); Quill.register(SyntaxCodeBlockContainer, true); } diff --git a/packages/quill/src/quill.ts b/packages/quill/src/quill.ts index 0c3626fd8a..648183434b 100644 --- a/packages/quill/src/quill.ts +++ b/packages/quill/src/quill.ts @@ -115,6 +115,7 @@ Quill.register( true, ); +export { Module } from './core.js'; export type { Bounds, DebugLevel, diff --git a/packages/quill/test/types/quill.test-d.ts b/packages/quill/test/types/quill.test-d.ts index 1d65de3823..cb3873ea06 100644 --- a/packages/quill/test/types/quill.test-d.ts +++ b/packages/quill/test/types/quill.test-d.ts @@ -3,6 +3,37 @@ import Quill from '../../src/quill.js'; import type { EmitterSource, Parchment, Range } from '../../src/quill.js'; import Delta from 'quill-delta'; import type { default as Block, BlockEmbed } from '../../src/blots/block.js'; +import SnowTheme from '../../src/themes/snow.js'; +import { LeafBlot } from 'parchment'; + +{ + const Counter = (quill: Quill, options: { unit: string }) => { + console.log(quill, options); + }; + Quill.register('modules/counter', Counter); + Quill.register('themes/snow', SnowTheme); + Quill.register('themes/snow', SnowTheme, true); + + class MyBlot extends LeafBlot {} + + Quill.register(MyBlot); + Quill.register(MyBlot, true); + // @ts-expect-error + Quill.register(SnowTheme); + Quill.register({ + 'modules/counter': Counter, + 'themes/snow': SnowTheme, + 'formats/my-blot': MyBlot, + }); + Quill.register( + { + 'modules/counter': Counter, + 'themes/snow': SnowTheme, + 'formats/my-blot': MyBlot, + }, + true, + ); +} const quill = new Quill('#editor'); diff --git a/packages/quill/test/unit/core/quill.spec.ts b/packages/quill/test/unit/core/quill.spec.ts index ca9f413afc..0df2b40a98 100644 --- a/packages/quill/test/unit/core/quill.spec.ts +++ b/packages/quill/test/unit/core/quill.spec.ts @@ -1,7 +1,7 @@ import '../../../src/quill.js'; import Delta from 'quill-delta'; -import { Registry } from 'parchment'; -import { beforeEach, describe, expect, test, vitest } from 'vitest'; +import { LeafBlot, Registry } from 'parchment'; +import { afterEach, beforeEach, describe, expect, test, vitest } from 'vitest'; import type { MockedFunction } from 'vitest'; import Emitter from '../../../src/core/emitter.js'; import Theme from '../../../src/core/theme.js'; @@ -29,6 +29,47 @@ describe('Quill', () => { }); }); + describe('register', () => { + const imports = { ...Quill.imports }; + afterEach(() => { + Quill.imports = imports; + }); + + test('register(path, target)', () => { + class Counter {} + Quill.register('modules/counter', Counter); + + expect(Quill.imports).toHaveProperty('modules/counter', Counter); + expect(Quill.import('modules/counter')).toEqual(Counter); + }); + + test('register(formats)', () => { + class MyCounterBlot extends LeafBlot { + static blotName = 'my-counter'; + static className = 'ql-my-counter'; + } + Quill.register(MyCounterBlot); + + expect(Quill.imports).toHaveProperty('formats/my-counter', MyCounterBlot); + expect(Quill.import('formats/my-counter')).toEqual(MyCounterBlot); + }); + + test('register(targets)', () => { + class ABlot extends LeafBlot { + static blotName = 'a-blot'; + static className = 'ql-a-blot'; + } + class AModule {} + Quill.register({ + 'formats/a-blot': ABlot, + 'modules/a-module': AModule, + }); + + expect(Quill.import('formats/a-blot')).toEqual(ABlot); + expect(Quill.import('modules/a-module')).toEqual(AModule); + }); + }); + describe('construction', () => { test('empty', () => { const quill = new Quill(createContainer());