diff --git a/packages/quill/src/core.ts b/packages/quill/src/core.ts index 982f72c6d3..77816b5644 100644 --- a/packages/quill/src/core.ts +++ b/packages/quill/src/core.ts @@ -1,6 +1,7 @@ -import Quill from './core/quill.js'; +import Quill, { Parchment, Range } from './core/quill.js'; import type { DebugLevel, + EmitterSource, ExpandedQuillOptions, QuillOptions, } from './core/quill.js'; @@ -22,8 +23,8 @@ import Delta, { Op, OpIterator, AttributeMap } from 'quill-delta'; import Input from './modules/input.js'; import UINode from './modules/uiNode.js'; -export { Delta, Op, OpIterator, AttributeMap }; -export type { DebugLevel, ExpandedQuillOptions, QuillOptions }; +export { Delta, Op, OpIterator, AttributeMap, Parchment, Range }; +export type { DebugLevel, EmitterSource, ExpandedQuillOptions, QuillOptions }; Quill.register({ 'blots/block': Block, diff --git a/packages/quill/src/core/quill.ts b/packages/quill/src/core/quill.ts index 17219c33f7..59da9d0513 100644 --- a/packages/quill/src/core/quill.ts +++ b/packages/quill/src/core/quill.ts @@ -412,7 +412,13 @@ class Quill { length: number, name: string, value: unknown, - source: EmitterSource, + source?: EmitterSource, + ): Delta; + formatText( + index: number, + length: number, + formats: Record, + source?: EmitterSource, ): Delta; formatText( index: number | { index: number; length: number }, @@ -568,24 +574,24 @@ class Quill { ); } - insertText(index: number, text: string, source: EmitterSource): Delta; + insertText(index: number, text: string, source?: EmitterSource): Delta; insertText( index: number, text: string, formats: Record, - source: EmitterSource, + source?: EmitterSource, ): Delta; insertText( index: number, text: string, name: string, value: unknown, - source: EmitterSource, + source?: EmitterSource, ): Delta; insertText( index: number, text: string, - name: string | Record | EmitterSource, + name?: string | Record | EmitterSource, value?: unknown, source?: EmitterSource, ): Delta { @@ -647,8 +653,8 @@ class Quill { return this.emitter.once(...args); } - removeFormat(...args: Parameters) { - const [index, length, , source] = overload(...args); + removeFormat(index: number, length: number, source?: EmitterSource) { + [index, length, , source] = overload(index, length, source); return modify.call( this, () => { @@ -1027,6 +1033,7 @@ function shiftRange( return new Range(start, end - start); } -export type { DebugLevel }; +export type { DebugLevel, EmitterSource }; +export { Parchment, Range }; export { globalRegistry, expandConfig, overload, Quill as default }; diff --git a/packages/quill/src/quill.ts b/packages/quill/src/quill.ts index fd364394c4..bc2535b1b8 100644 --- a/packages/quill/src/quill.ts +++ b/packages/quill/src/quill.ts @@ -1,5 +1,10 @@ -import Quill from './core.js'; -import type { DebugLevel, ExpandedQuillOptions, QuillOptions } from './core.js'; +import Quill, { Parchment, Range } from './core.js'; +import type { + DebugLevel, + EmitterSource, + ExpandedQuillOptions, + QuillOptions, +} from './core.js'; import { AlignClass, AlignStyle } from './formats/align.js'; import { @@ -109,6 +114,7 @@ Quill.register( true, ); -export type { DebugLevel, ExpandedQuillOptions, QuillOptions }; +export type { DebugLevel, EmitterSource, ExpandedQuillOptions, QuillOptions }; +export { Parchment, Range }; export default Quill; diff --git a/packages/quill/test/types/quill.test-d.ts b/packages/quill/test/types/quill.test-d.ts new file mode 100644 index 0000000000..d7ae524188 --- /dev/null +++ b/packages/quill/test/types/quill.test-d.ts @@ -0,0 +1,211 @@ +import { assertType, expectTypeOf } from 'vitest'; +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'; + +const quill = new Quill('#editor'); + +{ + quill.deleteText(0, 1); + quill.deleteText(0, 1, 'api'); + quill.deleteText({ index: 0, length: 1 }); + quill.deleteText({ index: 0, length: 1 }, 'api'); +} + +{ + assertType(quill.getContents()); + assertType(quill.getContents(1)); + assertType(quill.getContents(1, 2)); +} + +{ + assertType(quill.getLength()); +} + +{ + assertType(quill.getSemanticHTML()); + assertType(quill.getSemanticHTML(1)); + assertType(quill.getSemanticHTML(1, 2)); +} + +{ + quill.insertEmbed(10, 'image', 'https://example.com/logo.png'); + quill.insertEmbed(10, 'image', 'https://example.com/logo.png', 'api'); +} + +{ + quill.insertText(0, 'Hello'); + quill.insertText(0, 'Hello', 'api'); + quill.insertText(0, 'Hello', 'bold', true); + quill.insertText(0, 'Hello', 'bold', true, 'api'); + quill.insertText(5, 'Quill', { + color: '#ffff00', + italic: true, + }); + quill.insertText( + 5, + 'Quill', + { + color: '#ffff00', + italic: true, + }, + 'api', + ); +} + +{ + quill.enable(); + quill.enable(true); +} + +{ + quill.disable(); +} + +{ + assertType(quill.editReadOnly(() => true)); + assertType(quill.editReadOnly(() => 'success')); +} + +{ + quill.setText('Hello World!'); + quill.setText('Hello World!', 'api'); +} + +{ + quill.updateContents([{ insert: 'Hello World!' }]); + quill.updateContents([{ insert: 'Hello World!' }], 'api'); + quill.updateContents(new Delta().insert('Hello World!')); + quill.updateContents(new Delta().insert('Hello World!'), 'api'); +} + +{ + quill.setContents([{ insert: 'Hello World!\n' }]); + quill.setContents([{ insert: 'Hello World!\n' }], 'api'); + quill.setContents(new Delta().insert('Hello World!\n')); + quill.setContents(new Delta().insert('Hello World!\n'), 'api'); +} + +{ + quill.format('bold', true); + quill.format('bold', true, 'api'); +} + +{ + quill.formatText(0, 1, 'bold', true); + quill.formatText(0, 1, 'bold', true, 'api'); + quill.formatText(0, 5, { + bold: false, + color: 'rgb(0, 0, 255)', + }); + quill.formatText( + 0, + 5, + { + bold: false, + color: 'rgb(0, 0, 255)', + }, + 'api', + ); +} + +{ + quill.formatLine(0, 1, 'bold', true); + quill.formatLine(0, 1, 'bold', true, 'api'); + quill.formatLine(0, 5, { + bold: false, + color: 'rgb(0, 0, 255)', + }); + quill.formatLine( + 0, + 5, + { + bold: false, + color: 'rgb(0, 0, 255)', + }, + 'api', + ); +} + +{ + quill.getFormat(); + quill.getFormat(1); + quill.getFormat(1, 10); + quill.getFormat({ index: 1, length: 1 }); +} + +{ + quill.removeFormat(3, 2); + quill.removeFormat(3, 2, 'user'); +} + +{ + quill.getBounds(3, 2); +} + +{ + quill.getSelection(); + quill.getSelection(true); +} + +{ + quill.setSelection(1, 2); + quill.setSelection(1, 2, 'api'); + quill.setSelection({ index: 1, length: 2 }); + quill.setSelection({ index: 1, length: 2 }, 'api'); +} + +{ + quill.scrollSelectionIntoView(); +} + +{ + quill.blur(); +} + +{ + quill.focus(); +} + +{ + assertType(quill.hasFocus()); +} + +{ + quill.update(); + quill.update('user'); +} + +{ + quill.scrollRectIntoView({ left: 0, right: 0, top: 0, bottom: 0 }); +} + +{ + quill.on('text-change', (delta, oldDelta, source) => { + expectTypeOf(delta); + expectTypeOf(oldDelta); + expectTypeOf(source); + }); +} + +{ + quill.on('selection-change', (range, oldRange, source) => { + expectTypeOf(range); + expectTypeOf(oldRange); + expectTypeOf(source); + }); +} + +{ + assertType<[Parchment.LeafBlot | null, number]>(quill.getLeaf(0)); +} + +{ + assertType<[BlockEmbed | Block | null, number]>(quill.getLine(0)); +} + +{ + assertType<(BlockEmbed | Block)[]>(quill.getLines(0)); + assertType<(BlockEmbed | Block)[]>(quill.getLines(0, 10)); +} diff --git a/packages/quill/test/unit/core/quill.spec.ts b/packages/quill/test/unit/core/quill.spec.ts index dc17087b96..ca9f413afc 100644 --- a/packages/quill/test/unit/core/quill.spec.ts +++ b/packages/quill/test/unit/core/quill.spec.ts @@ -120,20 +120,36 @@ describe('Quill', () => { ); }); - test('formatText()', () => { - const { quill, oldDelta } = setup(); - // @ts-expect-error - quill.formatText(3, 2, 'bold', true); - const change = new Delta().retain(3).retain(2, { bold: true }); - expect(quill.root.innerHTML).toMatchInlineSnapshot( - '"

01234567

"', - ); - expect(quill.emitter.emit).toHaveBeenCalledWith( - Emitter.events.TEXT_CHANGE, - change, - oldDelta, - Emitter.sources.API, - ); + describe('formatText()', () => { + test('single format', () => { + const { quill, oldDelta } = setup(); + quill.formatText(3, 2, 'bold', true); + const change = new Delta().retain(3).retain(2, { bold: true }); + expect(quill.root.innerHTML).toMatchInlineSnapshot( + '"

01234567

"', + ); + expect(quill.emitter.emit).toHaveBeenCalledWith( + Emitter.events.TEXT_CHANGE, + change, + oldDelta, + Emitter.sources.API, + ); + }); + + test('format object', () => { + const { quill, oldDelta } = setup(); + quill.formatText(3, 2, { bold: true }); + const change = new Delta().retain(3).retain(2, { bold: true }); + expect(quill.root.innerHTML).toMatchInlineSnapshot( + '"

01234567

"', + ); + expect(quill.emitter.emit).toHaveBeenCalledWith( + Emitter.events.TEXT_CHANGE, + change, + oldDelta, + Emitter.sources.API, + ); + }); }); test('insertEmbed()', () => { @@ -155,7 +171,6 @@ describe('Quill', () => { test('insertText()', () => { const { quill, oldDelta } = setup(); - // @ts-expect-error quill.insertText(5, '|', 'bold', true); const change = new Delta() .retain(5) @@ -205,7 +220,6 @@ describe('Quill', () => { test('removeFormat()', () => { const { quill, oldDelta } = setup(); - // @ts-expect-error quill.removeFormat(5, 1); const change = new Delta().retain(5).retain(1, { italic: null }); expect(quill.root.innerHTML).toMatchInlineSnapshot( @@ -261,7 +275,6 @@ describe('Quill', () => { test('api text insert', () => { const { quill, oldDelta } = setup(); - // @ts-expect-error quill.insertText(2, '!'); const delta = new Delta().retain(2).insert('!'); expect(quill.emitter.emit).toHaveBeenCalledWith( diff --git a/packages/quill/test/unit/modules/history.spec.ts b/packages/quill/test/unit/modules/history.spec.ts index 28c69ce14e..cfaaca37cd 100644 --- a/packages/quill/test/unit/modules/history.spec.ts +++ b/packages/quill/test/unit/modules/history.spec.ts @@ -88,7 +88,6 @@ describe('History', () => { test('limits undo stack size', () => { const { quill } = setup({ delay: 0, maxStack: 2 }); ['A', 'B', 'C'].forEach((text) => { - // @ts-expect-error quill.insertText(0, text); }); expect(quill.history.stack.undo.length).toEqual(2); @@ -96,7 +95,6 @@ describe('History', () => { test('emits selection changes', () => { const { quill } = setup({ delay: 0 }); - // @ts-expect-error quill.insertText(0, 'foo'); const change = vitest.fn(); quill.on('selection-change', change); diff --git a/packages/quill/test/unit/modules/syntax.spec.ts b/packages/quill/test/unit/modules/syntax.spec.ts index afdd5a5148..cd1646bbb6 100644 --- a/packages/quill/test/unit/modules/syntax.spec.ts +++ b/packages/quill/test/unit/modules/syntax.spec.ts @@ -229,7 +229,6 @@ describe('Syntax', () => { test('modification', async () => { const quill = createQuill(); - // @ts-expect-error quill.formatText(2, 3, 'bold', true); await sleep(HIGHLIGHT_INTERVAL + 1); expect(quill.root).toEqualHTML(` @@ -252,7 +251,6 @@ describe('Syntax', () => { test('removal', async () => { const quill = createQuill(); - // @ts-expect-error quill.formatText(2, 3, 'bold', true); await sleep(HIGHLIGHT_INTERVAL + 1); quill.formatLine(0, 15, 'code-block', false); @@ -270,7 +268,6 @@ describe('Syntax', () => { test('addition', async () => { const quill = createQuill(); quill.setText('var test = 1;\n'); - // @ts-expect-error quill.formatText(2, 3, 'bold', true); quill.formatLine(0, 1, 'code-block', 'javascript'); await sleep(HIGHLIGHT_INTERVAL + 1); diff --git a/packages/quill/test/unit/vitest.config.ts b/packages/quill/test/unit/vitest.config.ts index 5b727f9db3..67cdfa0c4c 100644 --- a/packages/quill/test/unit/vitest.config.ts +++ b/packages/quill/test/unit/vitest.config.ts @@ -7,6 +7,10 @@ export default defineConfig({ }, test: { include: [resolve(__dirname, '**/*.spec.ts')], + typecheck: { + enabled: true, + include: [resolve(__dirname, '**/*.test-d.ts')], + }, setupFiles: [ resolve(__dirname, '__helpers__/expect.ts'), resolve(__dirname, '__helpers__/cleanup.ts'), diff --git a/packages/website/content/docs/api.mdx b/packages/website/content/docs/api.mdx index acd6263b6e..66d456eb76 100644 --- a/packages/website/content/docs/api.mdx +++ b/packages/website/content/docs/api.mdx @@ -154,7 +154,7 @@ Inserts text into the editor, optionally with a specified format or multiple [fo insertText(index: number, text: string, source: string = 'api'): Delta insertText(index: number, text: string, format: string, value: any, source: string = 'api'): Delta -insertText(index: number, text: string, formats: { [String]: any }, +insertText(index: number, text: string, formats: { [name: string]: any }, source: string = 'api'): Delta ``` @@ -265,7 +265,7 @@ Formats all lines in given range, returning a [Delta](/docs/delta/) representing formatLine(index: number, length: number, source: string = 'api'): Delta formatLine(index: number, length: number, format: string, value: any, source: string = 'api'): Delta -formatLine(index: number, length: number, formats: { [String]: any }, +formatLine(index: number, length: number, formats: { [name: string]: any }, source: string = 'api'): Delta ``` @@ -288,7 +288,7 @@ Formats text in the editor, returning a [Delta](/docs/delta/) representing the c formatText(index: number, length: number, source: string = 'api'): Delta formatText(index: number, length: number, format: string, value: any, source: string = 'api'): Delta -formatText(index: number, length: number, formats: { [String]: any }, +formatText(index: number, length: number, formats: { [name: string]: any }, source: string = 'api'): Delta ``` @@ -314,8 +314,8 @@ Retrieves common formatting of the text in the given range. For a format to be r **Methods** ```typescript -getFormat(range: Range = current): { [String]: any } -getFormat(index: number, length: number = 0): { [String]: any } +getFormat(range: Range = current): Record +getFormat(index: number, length: number = 0): Record ``` **Examples** @@ -528,7 +528,7 @@ Checks if editor has focus. Note focus on toolbar, tooltips, does not count as t **Methods** ```typescript -hasFocus(): Boolean +hasFocus(): boolean ``` **Examples** @@ -798,7 +798,7 @@ Returns the leaf [Blot](https://github.com/quilljs/parchment) at the specified i **Methods** ```typescript -getLeaf(index: number): Blot +getLeaf(index: number): [LeafBlot | null, number] ``` **Examples** @@ -819,7 +819,7 @@ Returns the line [Blot](https://github.com/quilljs/parchment) at the specified i **Methods** ```typescript -getLine(index: number): [Blot, Number] +getLine(index: number): [Block | BlockEmbed | null, number] ``` **Examples** @@ -839,8 +839,8 @@ Returns the lines contained within the specified location. **Methods** ```typescript -getLines(index: number = 0, length: number = remaining): Blot[] -getLines(range: Range): Blot[] +getLines(index: number = 0, length: number = remaining): (Block | BlockEmbed)[] +getLines(range: Range): (Block | BlockEmbed)[] ``` **Examples** @@ -863,7 +863,7 @@ Static method enabling logging messages at a given level: `'error'`, `'warn'`, ` **Methods** ```typescript -Quill.debug(level: string | Boolean) +Quill.debug(level: string | boolean) ``` **Examples** @@ -905,9 +905,9 @@ Registers a module, theme, or format(s), making them available to be added to an **Methods** ```typescript -Quill.register(format: Attributor | BlotDefinintion, supressWarning: Boolean = false) -Quill.register(path: string, def: any, supressWarning: Boolean = false) -Quill.register(defs: { [String]: any }, supressWarning: Boolean = false) +Quill.register(format: Attributor | BlotDefinintion, supressWarning: boolean = false) +Quill.register(path: string, def: any, supressWarning: boolean = false) +Quill.register(defs: { [path: string]: any }, supressWarning: boolean = false) ``` **Examples**