diff --git a/package-lock.json b/package-lock.json index 121755c77f..b1e930f3b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19147,8 +19147,9 @@ }, "node_modules/parchment": { "version": "3.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0-alpha.1.tgz", - "integrity": "sha512-CJN5G75j0W3gPHMHDmY82sdtPf5wVO2YRhdXPBypvwj5YA5C9zsTnUdpq92Zxca8Eha331wMOlf6rTN+vi2dlA==" + "resolved": "git+ssh://git@github.com/quilljs/parchment.git#9d148df41cc3d62ab07c25ebcead46a3d513d2c6", + "integrity": "sha512-kfi1efkh2AOqw7AnlwD9IBgw3tTHW8auDfVtz7jjgARuK/jg8RXN2gFTAuaNnjXHuXzNaWFmv9slTz96G90YNg==", + "license": "BSD-3-Clause" }, "node_modules/parent-module": { "version": "1.0.1", @@ -26417,7 +26418,7 @@ "dependencies": { "eventemitter3": "^5.0.1", "lodash-es": "^4.17.21", - "parchment": "^3.0.0-alpha.1", + "parchment": "github:quilljs/parchment#9d148df41cc3d62ab07c25ebcead46a3d513d2c6", "quill-delta": "^5.1.0" }, "devDependencies": { diff --git a/packages/quill/package.json b/packages/quill/package.json index 11764f9bb5..99913ad803 100644 --- a/packages/quill/package.json +++ b/packages/quill/package.json @@ -8,7 +8,7 @@ "dependencies": { "eventemitter3": "^5.0.1", "lodash-es": "^4.17.21", - "parchment": "^3.0.0-alpha.1", + "parchment": "github:quilljs/parchment#9d148df41cc3d62ab07c25ebcead46a3d513d2c6", "quill-delta": "^5.1.0" }, "devDependencies": { diff --git a/packages/quill/scripts/build b/packages/quill/scripts/build index b5ad4843af..6dd3286d49 100755 --- a/packages/quill/scripts/build +++ b/packages/quill/scripts/build @@ -4,8 +4,13 @@ set -e DIST=dist +TMPDIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir') +npx tsc --declaration --emitDeclarationOnly --outDir $TMPDIR + rm -rf $DIST -npx tsc --declaration --emitDeclarationOnly --outDir $DIST +mkdir $DIST +mv $TMPDIR/src/* $DIST +rm -rf $TMPDIR npx babel src --out-dir $DIST --copy-files --no-copy-ignored --extensions .ts --source-maps npx webpack -- --mode $1 cp package.json $DIST diff --git a/packages/quill/src/blots/scroll.ts b/packages/quill/src/blots/scroll.ts index a84dadd093..91968fb7e6 100644 --- a/packages/quill/src/blots/scroll.ts +++ b/packages/quill/src/blots/scroll.ts @@ -440,12 +440,4 @@ function insertInlineContents( }, index); } -export interface ScrollConstructor { - new ( - registry: Registry, - domNode: HTMLDivElement, - options: { emitter: Emitter }, - ): Scroll; -} - export default Scroll; diff --git a/packages/quill/src/core/quill.ts b/packages/quill/src/core/quill.ts index 5e022b682f..a23a914c8f 100644 --- a/packages/quill/src/core/quill.ts +++ b/packages/quill/src/core/quill.ts @@ -5,7 +5,6 @@ import Delta from 'quill-delta'; import type { BlockEmbed } from '../blots/block'; import type Block from '../blots/block'; import type Scroll from '../blots/scroll'; -import type { ScrollConstructor } from '../blots/scroll'; import type Clipboard from '../modules/clipboard'; import type History from '../modules/history'; import type Keyboard from '../modules/keyboard'; @@ -120,6 +119,8 @@ class Quill { this.imports[path] = target; if ( (path.startsWith('blots/') || path.startsWith('formats/')) && + target && + typeof target !== 'boolean' && // @ts-expect-error target.blotName !== 'abstract' ) { @@ -167,13 +168,16 @@ class Quill { this.root = this.addContainer('ql-editor'); this.root.classList.add('ql-blank'); this.emitter = new Emitter(); - // @ts-expect-error TODO: fix BlotConstructor - const ScrollBlot = this.options.registry.query( - Parchment.ScrollBlot.blotName, - ) as ScrollConstructor; + const scrollBlotName = Parchment.ScrollBlot.blotName; + const ScrollBlot = this.options.registry.query(scrollBlotName); + if (!ScrollBlot || !('blotName' in ScrollBlot)) { + throw new Error( + `Cannot initialize Quill without "${scrollBlotName}" blot`, + ); + } this.scroll = new ScrollBlot(this.options.registry, this.root, { emitter: this.emitter, - }); + }) as Scroll; this.editor = new Editor(this.scroll); this.selection = new Selection(this.scroll, this.emitter); this.composition = new Composition(this.scroll, this.emitter); diff --git a/packages/quill/src/formats/bold.ts b/packages/quill/src/formats/bold.ts index 0739a0bfcd..7f70218726 100644 --- a/packages/quill/src/formats/bold.ts +++ b/packages/quill/src/formats/bold.ts @@ -5,7 +5,6 @@ class Bold extends Inline { static tagName = ['STRONG', 'B']; static create() { - // @ts-expect-error return super.create(); } diff --git a/packages/quill/src/formats/color.ts b/packages/quill/src/formats/color.ts index 3ee44a1bcf..e4891c69b0 100644 --- a/packages/quill/src/formats/color.ts +++ b/packages/quill/src/formats/color.ts @@ -2,7 +2,7 @@ import { ClassAttributor, Scope, StyleAttributor } from 'parchment'; class ColorAttributor extends StyleAttributor { value(domNode: HTMLElement) { - let value = super.value(domNode); + let value = super.value(domNode) as string; if (!value.startsWith('rgb(')) return value; value = value.replace(/^[^\d]+/, '').replace(/[^\d]+$/, ''); const hex = value diff --git a/packages/quill/src/formats/indent.ts b/packages/quill/src/formats/indent.ts index 6cb66bb8a1..480a6b250f 100644 --- a/packages/quill/src/formats/indent.ts +++ b/packages/quill/src/formats/indent.ts @@ -20,8 +20,7 @@ class IndentAttributor extends ClassAttributor { return super.canAdd(node, value) || super.canAdd(node, parseInt(value, 10)); } - // @ts-expect-error TODO: ClassAttributor may support numbers - value(node) { + value(node: HTMLElement) { return parseInt(super.value(node), 10) || undefined; // Don't return NaN } } diff --git a/packages/quill/src/formats/link.ts b/packages/quill/src/formats/link.ts index 80649b8c92..e832099630 100644 --- a/packages/quill/src/formats/link.ts +++ b/packages/quill/src/formats/link.ts @@ -7,7 +7,7 @@ class Link extends Inline { static PROTOCOL_WHITELIST = ['http', 'https', 'mailto', 'tel', 'sms']; static create(value: string) { - const node = super.create(value) as Element; + const node = super.create(value) as HTMLElement; node.setAttribute('href', this.sanitize(value)); node.setAttribute('rel', 'noopener noreferrer'); node.setAttribute('target', '_blank'); diff --git a/packages/quill/src/formats/list.ts b/packages/quill/src/formats/list.ts index b36f53d29e..d422a713c3 100644 --- a/packages/quill/src/formats/list.ts +++ b/packages/quill/src/formats/list.ts @@ -9,8 +9,7 @@ ListContainer.tagName = 'OL'; class ListItem extends Block { static create(value: string) { - // @ts-expect-error - const node = super.create() as Element; + const node = super.create() as HTMLElement; node.setAttribute('data-list', value); return node; } diff --git a/packages/quill/src/formats/table.ts b/packages/quill/src/formats/table.ts index b6a04717bd..2f891e10c9 100644 --- a/packages/quill/src/formats/table.ts +++ b/packages/quill/src/formats/table.ts @@ -7,8 +7,7 @@ class TableCell extends Block { static tagName = 'TD'; static create(value: string) { - // @ts-expect-error - const node = super.create() as Element; + const node = super.create() as HTMLElement; if (value) { node.setAttribute('data-row', value); } else { diff --git a/packages/quill/src/modules/syntax.ts b/packages/quill/src/modules/syntax.ts index 24eb8f3b7e..14daa09415 100644 --- a/packages/quill/src/modules/syntax.ts +++ b/packages/quill/src/modules/syntax.ts @@ -61,7 +61,6 @@ class SyntaxCodeBlock extends CodeBlock { static create(value: unknown) { const domNode = super.create(value); if (typeof value === 'string') { - // @ts-expect-error domNode.setAttribute('data-language', value); } return domNode; diff --git a/packages/quill/test/unit/__helpers__/factory.ts b/packages/quill/test/unit/__helpers__/factory.ts index b4f4359883..445fe94272 100644 --- a/packages/quill/test/unit/__helpers__/factory.ts +++ b/packages/quill/test/unit/__helpers__/factory.ts @@ -1,4 +1,5 @@ import { Registry } from 'parchment'; +import type { Attributor } from 'parchment'; import Block from '../../../src/blots/block'; import Break from '../../../src/blots/break'; @@ -14,7 +15,7 @@ export const createRegistry = (formats: unknown[] = []) => { const registry = new Registry(); formats.forEach((format) => { - registry.register(format); + registry.register(format as Attributor); }); registry.register(Block); registry.register(Break); diff --git a/packages/quill/test/unit/modules/toolbar.spec.ts b/packages/quill/test/unit/modules/toolbar.spec.ts index 183281ed27..bdae05f9f9 100644 --- a/packages/quill/test/unit/modules/toolbar.spec.ts +++ b/packages/quill/test/unit/modules/toolbar.spec.ts @@ -178,12 +178,10 @@ describe('Toolbar', () => { ) as HTMLButtonElement; quill.setSelection(7); expect(boldButton.classList.contains('ql-active')).toBe(true); - // @ts-expect-error -- TODO fix later - expect(boldButton.attributes['aria-pressed'].value).toBe('true'); + expect(boldButton.getAttribute('aria-pressed')).toBe('true'); quill.setSelection(2); expect(boldButton.classList.contains('ql-active')).toBe(false); - // @ts-expect-error -- TODO fix later - expect(boldButton.attributes['aria-pressed'].value).toBe('false'); + expect(boldButton.getAttribute('aria-pressed')).toBe('false'); }); test('link', () => { @@ -193,12 +191,10 @@ describe('Toolbar', () => { ) as HTMLButtonElement; quill.setSelection(12); expect(linkButton.classList.contains('ql-active')).toBe(true); - // @ts-expect-error -- TODO fix later - expect(linkButton.attributes['aria-pressed'].value).toBe('true'); + expect(linkButton.getAttribute('aria-pressed')).toBe('true'); quill.setSelection(2); expect(linkButton.classList.contains('ql-active')).toBe(false); - // @ts-expect-error -- TODO fix later - expect(linkButton.attributes['aria-pressed'].value).toBe('false'); + expect(linkButton.getAttribute('aria-pressed')).toBe('false'); }); test('dropdown', () => { @@ -227,24 +223,18 @@ describe('Toolbar', () => { quill.setSelection(17); expect(centerButton.classList.contains('ql-active')).toBe(true); expect(leftButton.classList.contains('ql-active')).toBe(false); - // @ts-expect-error -- TODO fix later - expect(centerButton.attributes['aria-pressed'].value).toBe('true'); - // @ts-expect-error -- TODO fix later - expect(leftButton.attributes['aria-pressed'].value).toBe('false'); + expect(centerButton.getAttribute('aria-pressed')).toBe('true'); + expect(leftButton.getAttribute('aria-pressed')).toBe('false'); quill.setSelection(2); expect(centerButton.classList.contains('ql-active')).toBe(false); expect(leftButton.classList.contains('ql-active')).toBe(true); - // @ts-expect-error -- TODO fix later - expect(centerButton.attributes['aria-pressed'].value).toBe('false'); - // @ts-expect-error -- TODO fix later - expect(leftButton.attributes['aria-pressed'].value).toBe('true'); + expect(centerButton.getAttribute('aria-pressed')).toBe('false'); + expect(leftButton.getAttribute('aria-pressed')).toBe('true'); quill.blur(); expect(centerButton.classList.contains('ql-active')).toBe(false); expect(leftButton.classList.contains('ql-active')).toBe(false); - // @ts-expect-error -- TODO fix later - expect(centerButton.attributes['aria-pressed'].value).toBe('false'); - // @ts-expect-error -- TODO fix later - expect(leftButton.attributes['aria-pressed'].value).toBe('false'); + expect(centerButton.getAttribute('aria-pressed')).toBe('false'); + expect(leftButton.getAttribute('aria-pressed')).toBe('false'); }); }); }); diff --git a/packages/quill/tsconfig.json b/packages/quill/tsconfig.json index 3fe707cb26..c99fce116e 100644 --- a/packages/quill/tsconfig.json +++ b/packages/quill/tsconfig.json @@ -13,10 +13,10 @@ "resolveJsonModule": true, "declaration": false, "module": "ES2020", - "moduleResolution": "node", + "moduleResolution": "bundler", "strictNullChecks": true, "noImplicitAny": true, "noUnusedLocals": true }, - "include": ["src/**/*"] + "include": ["src/**/*", "test/**/*"] } diff --git a/scripts/release.js b/scripts/release.js index aff93fc07f..4c4e477a03 100755 --- a/scripts/release.js +++ b/scripts/release.js @@ -152,19 +152,23 @@ exec(`npm publish --tag ${distTag}${dryRun ? " --dry-run" : ""}`, { /* * Create GitHub release */ -const filename = `release-note-${version}-${(Math.random() * 1000) | 0}.txt`; -fs.writeFileSync(filename, releaseNots); -try { - const prereleaseFlag = distTag === "latest" ? "--latest" : " --prerelease"; - const releaseCommand = `gh release create v${version} ${prereleaseFlag} -t "Version ${version}" --notes-file "${filename}" --draft`; - if (dryRun) { - console.log(`Skipping: "${releaseCommand}" in dry-run mode`); - console.log(`Release note:\n${releaseNots}`); - } else { - exec(releaseCommand); +if (version === "experimental") { + console.log("Skipping GitHub release for experimental version"); +} else { + const filename = `release-note-${version}-${(Math.random() * 1000) | 0}.txt`; + fs.writeFileSync(filename, releaseNots); + try { + const prereleaseFlag = distTag === "latest" ? "--latest" : " --prerelease"; + const releaseCommand = `gh release create v${version} ${prereleaseFlag} -t "Version ${version}" --notes-file "${filename}" --draft`; + if (dryRun) { + console.log(`Skipping: "${releaseCommand}" in dry-run mode`); + console.log(`Release note:\n${releaseNots}`); + } else { + exec(releaseCommand); + } + } finally { + fs.unlinkSync(filename); } -} finally { - fs.unlinkSync(filename); } /*