diff --git a/packages/quill/src/core/quill.ts b/packages/quill/src/core/quill.ts index 5622856527..135a7b73a2 100644 --- a/packages/quill/src/core/quill.ts +++ b/packages/quill/src/core/quill.ts @@ -30,18 +30,7 @@ const debug = logger('quill'); const globalRegistry = new Parchment.Registry(); Parchment.ParentBlot.uiClass = 'ql-ui'; -type ClassToConstructor = { new (...args: any[]): T & object }; - -type RegistryTarget = Parchment.RegistryDefinition | Module | boolean; - -interface RegistryRecord { - [key: `blots/${string}`]: Parchment.BlotConstructor; - [key: `formats/${string}`]: Parchment.RegistryDefinition; - [key: `attributors/${string}`]: Parchment.Attributor; - [key: `modules/${string}`]: ClassToConstructor; - [key: `themes/${string}`]: ClassToConstructor; - [key: string]: any; -} +type RegisterTarget = Parchment.RegistryDefinition | Theme | Module | Function; // ES5 constructor functions /** * Options for initializing a Quill instance @@ -134,21 +123,39 @@ class Quill { return this.imports[name]; } - static register(record: RegistryRecord, overwrite?: boolean): void; static register( - target: Exclude, + targets: Record, + overwrite?: boolean, + ): void; + static register( + target: Parchment.RegistryDefinition, overwrite?: boolean, ): void; static register( path: string, - target: RegistryTarget, + target: RegisterTarget, overwrite?: boolean, ): void; static register(...args: any[]): void { - const path = typeof args[0] === 'string' ? args[0] : ''; - const target = path ? args[1] : args[0]; - const overwrite = (path ? args[2] : args[1]) ?? false; - if (path) { + 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) + this.register(`formats/${name}`, target, overwrite); + } else { + 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); } @@ -164,16 +171,6 @@ class Quill { if (typeof target.register === 'function') { target.register(globalRegistry); } - return; - } - const name: string | undefined = target['attrName'] ?? target['blotName']; - if (typeof name === 'string') { - // register(Blot | Attributor, overwrite) - this.register(`formats/${name}`, target, overwrite); - } else { - Object.keys(target).forEach((key) => { - this.register(key, target[key], overwrite); - }); } } diff --git a/packages/quill/src/modules/syntax.ts b/packages/quill/src/modules/syntax.ts index c3d1a81959..da99fdc41d 100644 --- a/packages/quill/src/modules/syntax.ts +++ b/packages/quill/src/modules/syntax.ts @@ -80,7 +80,6 @@ class SyntaxCodeBlock extends CodeBlock { } } - // TODO maybe something wrong replaceWith(name: string | Blot, value?: any) { this.formatAt(0, this.length(), CodeToken.blotName, false); return super.replaceWith(name, value); diff --git a/packages/quill/src/quill.ts b/packages/quill/src/quill.ts index de2f0a609f..648183434b 100644 --- a/packages/quill/src/quill.ts +++ b/packages/quill/src/quill.ts @@ -115,7 +115,7 @@ Quill.register( true, ); -export { default as Module } from './core/module.js'; +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());