Compare commits

...

14 Commits
main ... cjs

Author SHA1 Message Date
Scott Nonnenberg
40d5781c6b v2.1.2 2025-01-27 15:06:03 -10:00
Scott Nonnenberg
2a0bd6dda2 Preserve formatting on entering newline
Restoring behavior removed here: https://github.com/slab/quill/pull/3428
2025-01-23 13:16:38 -10:00
Scott Nonnenberg
f6eeddde2d v2.1.1 2025-01-21 16:46:59 -10:00
Scott Nonnenberg
9394a4592d package-lock.json: Catch-up after recent changes 2025-01-21 16:46:38 -10:00
Scott Nonnenberg
ff34142824 scripts/build: Don't delete dist/dist - that's for css and built js 2025-01-21 16:46:23 -10:00
Scott Nonnenberg
b12bacbc12 Update the per-package README as well 2025-01-21 10:22:16 +10:00
Scott Nonnenberg
2e6261c62a Update package name/version, move to CJS version of parchment 2025-01-21 10:10:55 +10:00
Scott Nonnenberg
42100f814c New clipboard options: disable listeners, override default matchers 2025-01-21 09:01:07 +10:00
Scott Nonnenberg
b030001387 Scroll: Prevent paste of anything other than text 2025-01-20 17:25:13 +10:00
Scott Nonnenberg
a5abc5db27 On paste, apply existing selection's styles to incoming Delta 2025-01-20 17:25:13 +10:00
Scott Nonnenberg
c52143fdfc Clipboard: Prevent too many newlines in a row on paste 2025-01-20 17:04:11 +10:00
Scott Nonnenberg
194335b4d3 isLine: Add time element 2025-01-20 17:04:11 +10:00
Scott Nonnenberg
a826b90428 Keyboard: Fix crash when line is missing 2025-01-20 17:04:11 +10:00
Scott Nonnenberg
723daabb7d First move towards CJS 2025-01-20 17:04:11 +10:00
43 changed files with 303 additions and 140 deletions

View File

@ -1,3 +1,19 @@
## Note: This fork is for use in Signal Desktop
The biggest change is moving from ESM to CJS.
Beyond that, there are a few other changes:
- keyboard: fix a crash in keydown handler when line is missing
- clipboard: add `time` element to list of elements in `isLine`
- clipboard: update `matchNewline` to prevent too many newlines in a row
- clipboard: update `convert` to apply provided formats to both text and html inputs
- scroll: use `contenteditable="plaintext-only"` to fully prevent image paste
- clipboard: introduce two new options:
- `disableDefaultListeners` - if set to something truthy, disables the clipboard module's `cut`/`copy`/`paste` handlers
- `defaultMatchersOverride` - if set, overrides all the default clipboard matchers, giving full control of the list of installed matchers
It's published as `@signalapp/quill-cjs`.
<h1 align="center"> <h1 align="center">
<a href="https://quilljs.com/" title="Quill">Quill Rich Text Editor</a> <a href="https://quilljs.com/" title="Quill">Quill Rich Text Editor</a>
</h1> </h1>

52
package-lock.json generated
View File

@ -5709,6 +5709,16 @@
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
"dev": true "dev": true
}, },
"node_modules/@signalapp/parchment-cjs": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@signalapp/parchment-cjs/-/parchment-cjs-3.0.1.tgz",
"integrity": "sha512-hSBMQ1M7wE4GcC8ZeNtvpJF+DAJg3eIRRf1SiHS3I3Algav/sgJJNm6HIYm6muHuK7IJmuEjkL3ILSXgmu0RfQ==",
"license": "BSD-3-Clause"
},
"node_modules/@signalapp/quill-cjs": {
"resolved": "packages/quill",
"link": true
},
"node_modules/@sinclair/typebox": { "node_modules/@sinclair/typebox": {
"version": "0.27.8", "version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@ -6184,19 +6194,11 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
}, },
"node_modules/@types/lodash": { "node_modules/@types/lodash": {
"version": "4.17.0", "version": "4.17.14",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==",
"dev": true
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"dev": true, "dev": true,
"dependencies": { "license": "MIT"
"@types/lodash": "*"
}
}, },
"node_modules/@types/mdast": { "node_modules/@types/mdast": {
"version": "3.0.15", "version": "3.0.15",
@ -13233,13 +13235,7 @@
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"dev": true
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
}, },
"node_modules/lodash.clonedeep": { "node_modules/lodash.clonedeep": {
"version": "4.5.0", "version": "4.5.0",
@ -14840,11 +14836,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/parchment": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
"integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A=="
},
"node_modules/parent-module": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -15550,10 +15541,6 @@
} }
] ]
}, },
"node_modules/quill": {
"resolved": "packages/quill",
"link": true
},
"node_modules/quill-delta": { "node_modules/quill-delta": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
@ -19236,12 +19223,13 @@
} }
}, },
"packages/quill": { "packages/quill": {
"version": "2.0.3", "name": "@signalapp/quill-cjs",
"version": "2.1.0",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@signalapp/parchment-cjs": "3.0.1",
"eventemitter3": "^5.0.1", "eventemitter3": "^5.0.1",
"lodash-es": "^4.17.21", "lodash": "^4.17.21",
"parchment": "^3.0.0",
"quill-delta": "^5.1.0" "quill-delta": "^5.1.0"
}, },
"devDependencies": { "devDependencies": {
@ -19251,7 +19239,7 @@
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@playwright/test": "1.44.1", "@playwright/test": "1.44.1",
"@types/highlight.js": "^9.12.4", "@types/highlight.js": "^9.12.4",
"@types/lodash-es": "^4.17.12", "@types/lodash": "^4.17.14",
"@types/node": "^20.10.0", "@types/node": "^20.10.0",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/eslint-plugin": "^7.2.0",

View File

@ -1,3 +1,5 @@
## Note: This fork is for use in Signal Desktop
# Quill # Quill
This is the main package of Quill. This is the main package of Quill.

View File

@ -2,7 +2,7 @@ const pkg = require('./package.json');
module.exports = { module.exports = {
presets: [ presets: [
['@babel/preset-env', { modules: false }], ['@babel/preset-env', { modules: 'cjs' }],
'@babel/preset-typescript', '@babel/preset-typescript',
], ],
plugins: [ plugins: [

View File

@ -1,15 +1,14 @@
{ {
"name": "quill", "name": "@signalapp/quill-cjs",
"version": "2.0.3", "version": "2.1.2",
"description": "Your powerful, rich text editor", "description": "Your powerful, rich text editor",
"author": "Jason Chen <jhchen7@gmail.com>", "author": "Jason Chen <jhchen7@gmail.com>",
"homepage": "https://quilljs.com", "homepage": "https://quilljs.com",
"main": "quill.js", "main": "quill.js",
"type": "module",
"dependencies": { "dependencies": {
"eventemitter3": "^5.0.1", "eventemitter3": "^5.0.1",
"lodash-es": "^4.17.21", "lodash": "^4.17.21",
"parchment": "^3.0.0", "@signalapp/parchment-cjs": "3.0.1",
"quill-delta": "^5.1.0" "quill-delta": "^5.1.0"
}, },
"devDependencies": { "devDependencies": {
@ -19,7 +18,7 @@
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@playwright/test": "1.44.1", "@playwright/test": "1.44.1",
"@types/highlight.js": "^9.12.4", "@types/highlight.js": "^9.12.4",
"@types/lodash-es": "^4.17.12", "@types/lodash": "^4.17.14",
"@types/node": "^20.10.0", "@types/node": "^20.10.0",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/eslint-plugin": "^7.2.0",

View File

@ -11,7 +11,7 @@ rm -rf $DIST
mkdir $DIST mkdir $DIST
mv $TMPDIR/src/* $DIST mv $TMPDIR/src/* $DIST
rm -rf $TMPDIR rm -rf $TMPDIR
npx babel src --out-dir $DIST --copy-files --no-copy-ignored --extensions .ts --source-maps npx babel src --out-dir $DIST --copy-files --no-copy-ignored --extensions .ts
npx webpack -- --mode $1 npx webpack -- --mode $1
# https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151 # https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151
rm -rf $DIST/dist/*.css.js $DIST/dist/*.css.js.* rm -rf $DIST/dist/*.css.js $DIST/dist/*.css.js.*

View File

@ -4,8 +4,8 @@ import {
EmbedBlot, EmbedBlot,
LeafBlot, LeafBlot,
Scope, Scope,
} from 'parchment'; } from '@signalapp/parchment-cjs';
import type { Blot, Parent } from 'parchment'; import type { Blot, Parent } from '@signalapp/parchment-cjs';
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import Break from './break.js'; import Break from './break.js';
import Inline from './inline.js'; import Inline from './inline.js';

View File

@ -1,4 +1,4 @@
import { EmbedBlot } from 'parchment'; import { EmbedBlot } from '@signalapp/parchment-cjs';
class Break extends EmbedBlot { class Break extends EmbedBlot {
static value() { static value() {

View File

@ -1,4 +1,4 @@
import { ContainerBlot } from 'parchment'; import { ContainerBlot } from '@signalapp/parchment-cjs';
class Container extends ContainerBlot {} class Container extends ContainerBlot {}

View File

@ -1,5 +1,5 @@
import { EmbedBlot, Scope } from 'parchment'; import { EmbedBlot, Scope } from '@signalapp/parchment-cjs';
import type { Parent, ScrollBlot } from 'parchment'; import type { Parent, ScrollBlot } from '@signalapp/parchment-cjs';
import type Selection from '../core/selection.js'; import type Selection from '../core/selection.js';
import TextBlot from './text.js'; import TextBlot from './text.js';
import type { EmbedContextRange } from './embed.js'; import type { EmbedContextRange } from './embed.js';

View File

@ -1,5 +1,5 @@
import type { ScrollBlot } from 'parchment'; import type { ScrollBlot } from '@signalapp/parchment-cjs';
import { EmbedBlot } from 'parchment'; import { EmbedBlot } from '@signalapp/parchment-cjs';
import TextBlot from './text.js'; import TextBlot from './text.js';
const GUARD_TEXT = '\uFEFF'; const GUARD_TEXT = '\uFEFF';

View File

@ -1,5 +1,5 @@
import { EmbedBlot, InlineBlot, Scope } from 'parchment'; import { EmbedBlot, InlineBlot, Scope } from '@signalapp/parchment-cjs';
import type { BlotConstructor } from 'parchment'; import type { BlotConstructor } from '@signalapp/parchment-cjs';
import Break from './break.js'; import Break from './break.js';
import Text from './text.js'; import Text from './text.js';

View File

@ -1,5 +1,16 @@
import { ContainerBlot, LeafBlot, Scope, ScrollBlot } from 'parchment'; import {
import type { Blot, Parent, EmbedBlot, ParentBlot, Registry } from 'parchment'; ContainerBlot,
LeafBlot,
Scope,
ScrollBlot,
} from '@signalapp/parchment-cjs';
import type {
Blot,
Parent,
EmbedBlot,
ParentBlot,
Registry,
} from '@signalapp/parchment-cjs';
import Delta, { AttributeMap, Op } from 'quill-delta'; import Delta, { AttributeMap, Op } from 'quill-delta';
import Emitter from '../core/emitter.js'; import Emitter from '../core/emitter.js';
import type { EmitterSource } from '../core/emitter.js'; import type { EmitterSource } from '../core/emitter.js';
@ -96,7 +107,10 @@ class Scroll extends ScrollBlot {
} }
enable(enabled = true) { enable(enabled = true) {
this.domNode.setAttribute('contenteditable', enabled ? 'true' : 'false'); this.domNode.setAttribute(
'contenteditable',
enabled ? 'plaintext-only' : 'false',
);
} }
formatAt(index: number, length: number, format: string, value: unknown) { formatAt(index: number, length: number, format: string, value: unknown) {
@ -210,7 +224,8 @@ class Scroll extends ScrollBlot {
} }
isEnabled() { isEnabled() {
return this.domNode.getAttribute('contenteditable') === 'true'; const value = this.domNode.getAttribute('contenteditable');
return value === 'true' || value === 'plaintext-only';
} }
leaf(index: number): [LeafBlot | null, number] { leaf(index: number): [LeafBlot | null, number] {

View File

@ -1,4 +1,4 @@
import { TextBlot } from 'parchment'; import { TextBlot } from '@signalapp/parchment-cjs';
class Text extends TextBlot {} class Text extends TextBlot {}

View File

@ -1,6 +1,11 @@
import { cloneDeep, isEqual, merge } from 'lodash-es'; import { cloneDeep, isEqual, merge } from 'lodash';
import { LeafBlot, EmbedBlot, Scope, ParentBlot } from 'parchment'; import {
import type { Blot } from 'parchment'; LeafBlot,
EmbedBlot,
Scope,
ParentBlot,
} from '@signalapp/parchment-cjs';
import type { Blot } from '@signalapp/parchment-cjs';
import Delta, { AttributeMap, Op } from 'quill-delta'; import Delta, { AttributeMap, Op } from 'quill-delta';
import Block, { BlockEmbed, bubbleFormats } from '../blots/block.js'; import Block, { BlockEmbed, bubbleFormats } from '../blots/block.js';
import Break from '../blots/break.js'; import Break from '../blots/break.js';

View File

@ -1,5 +1,5 @@
import { merge } from 'lodash-es'; import { merge } from 'lodash';
import * as Parchment from 'parchment'; import * as Parchment from '@signalapp/parchment-cjs';
import type { Op } from 'quill-delta'; import type { Op } from 'quill-delta';
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import type { BlockEmbed } from '../blots/block.js'; import type { BlockEmbed } from '../blots/block.js';

View File

@ -1,5 +1,5 @@
import { LeafBlot, Scope } from 'parchment'; import { LeafBlot, Scope } from '@signalapp/parchment-cjs';
import { cloneDeep, isEqual } from 'lodash-es'; import { cloneDeep, isEqual } from 'lodash';
import Emitter from './emitter.js'; import Emitter from './emitter.js';
import type { EmitterSource } from './emitter.js'; import type { EmitterSource } from './emitter.js';
import logger from './logger.js'; import logger from './logger.js';

View File

@ -1,4 +1,4 @@
import { Registry } from 'parchment'; import { Registry } from '@signalapp/parchment-cjs';
const MAX_REGISTER_ITERATIONS = 100; const MAX_REGISTER_ITERATIONS = 100;
const CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text']; const CORE_FORMATS = ['block', 'break', 'cursor', 'inline', 'scroll', 'text'];

View File

@ -1,4 +1,9 @@
import { Attributor, ClassAttributor, Scope, StyleAttributor } from 'parchment'; import {
Attributor,
ClassAttributor,
Scope,
StyleAttributor,
} from '@signalapp/parchment-cjs';
const config = { const config = {
scope: Scope.BLOCK, scope: Scope.BLOCK,

View File

@ -1,4 +1,4 @@
import { ClassAttributor, Scope } from 'parchment'; import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
import { ColorAttributor } from './color.js'; import { ColorAttributor } from './color.js';
const BackgroundClass = new ClassAttributor('background', 'ql-bg', { const BackgroundClass = new ClassAttributor('background', 'ql-bg', {

View File

@ -1,4 +1,8 @@
import { ClassAttributor, Scope, StyleAttributor } from 'parchment'; import {
ClassAttributor,
Scope,
StyleAttributor,
} from '@signalapp/parchment-cjs';
class ColorAttributor extends StyleAttributor { class ColorAttributor extends StyleAttributor {
value(domNode: HTMLElement) { value(domNode: HTMLElement) {

View File

@ -1,4 +1,9 @@
import { Attributor, ClassAttributor, Scope, StyleAttributor } from 'parchment'; import {
Attributor,
ClassAttributor,
Scope,
StyleAttributor,
} from '@signalapp/parchment-cjs';
const config = { const config = {
scope: Scope.BLOCK, scope: Scope.BLOCK,

View File

@ -1,4 +1,8 @@
import { ClassAttributor, Scope, StyleAttributor } from 'parchment'; import {
ClassAttributor,
Scope,
StyleAttributor,
} from '@signalapp/parchment-cjs';
const config = { const config = {
scope: Scope.INLINE, scope: Scope.INLINE,

View File

@ -1,4 +1,4 @@
import { EmbedBlot } from 'parchment'; import { EmbedBlot } from '@signalapp/parchment-cjs';
import { sanitize } from './link.js'; import { sanitize } from './link.js';
const ATTRIBUTES = ['alt', 'height', 'width']; const ATTRIBUTES = ['alt', 'height', 'width'];

View File

@ -1,4 +1,4 @@
import { ClassAttributor, Scope } from 'parchment'; import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
class IndentAttributor extends ClassAttributor { class IndentAttributor extends ClassAttributor {
add(node: HTMLElement, value: string | number) { add(node: HTMLElement, value: string | number) {

View File

@ -1,4 +1,8 @@
import { ClassAttributor, Scope, StyleAttributor } from 'parchment'; import {
ClassAttributor,
Scope,
StyleAttributor,
} from '@signalapp/parchment-cjs';
const SizeClass = new ClassAttributor('size', 'ql-size', { const SizeClass = new ClassAttributor('size', 'ql-size', {
scope: Scope.INLINE, scope: Scope.INLINE,

View File

@ -1,4 +1,4 @@
import type { LinkedList } from 'parchment'; import type { LinkedList } from '@signalapp/parchment-cjs';
import Block from '../blots/block.js'; import Block from '../blots/block.js';
import Container from '../blots/container.js'; import Container from '../blots/container.js';

View File

@ -1,4 +1,4 @@
import type { ScrollBlot } from 'parchment'; import type { ScrollBlot } from '@signalapp/parchment-cjs';
import { import {
Attributor, Attributor,
BlockBlot, BlockBlot,
@ -6,8 +6,9 @@ import {
EmbedBlot, EmbedBlot,
Scope, Scope,
StyleAttributor, StyleAttributor,
} from 'parchment'; } from '@signalapp/parchment-cjs';
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import type { AttributeMap } from 'quill-delta';
import { BlockEmbed } from '../blots/block.js'; import { BlockEmbed } from '../blots/block.js';
import type { EmitterSource } from '../core/emitter.js'; import type { EmitterSource } from '../core/emitter.js';
import logger from '../core/logger.js'; import logger from '../core/logger.js';
@ -27,7 +28,12 @@ import normalizeExternalHTML from './normalizeExternalHTML/index.js';
const debug = logger('quill:clipboard'); const debug = logger('quill:clipboard');
type Selector = string | Node['TEXT_NODE'] | Node['ELEMENT_NODE']; type Selector = string | Node['TEXT_NODE'] | Node['ELEMENT_NODE'];
type Matcher = (node: Node, delta: Delta, scroll: ScrollBlot) => Delta; type Matcher = (
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) => Delta;
const CLIPBOARD_CONFIG: [Selector, Matcher][] = [ const CLIPBOARD_CONFIG: [Selector, Matcher][] = [
[Node.TEXT_NODE, matchText], [Node.TEXT_NODE, matchText],
@ -69,6 +75,8 @@ const STYLE_ATTRIBUTORS = [
interface ClipboardOptions { interface ClipboardOptions {
matchers: [Selector, Matcher][]; matchers: [Selector, Matcher][];
defaultMatchersOverride?: [Selector, Matcher][];
disableDefaultListeners?: boolean;
} }
class Clipboard extends Module<ClipboardOptions> { class Clipboard extends Module<ClipboardOptions> {
@ -80,17 +88,24 @@ class Clipboard extends Module<ClipboardOptions> {
constructor(quill: Quill, options: Partial<ClipboardOptions>) { constructor(quill: Quill, options: Partial<ClipboardOptions>) {
super(quill, options); super(quill, options);
this.quill.root.addEventListener('copy', (e) =>
this.onCaptureCopy(e, false), if (!options.disableDefaultListeners) {
); this.quill.root.addEventListener('copy', (e) =>
this.quill.root.addEventListener('cut', (e) => this.onCaptureCopy(e, true)); this.onCaptureCopy(e, false),
this.quill.root.addEventListener('paste', this.onCapturePaste.bind(this)); );
this.quill.root.addEventListener('cut', (e) =>
this.onCaptureCopy(e, true),
);
this.quill.root.addEventListener('paste', this.onCapturePaste.bind(this));
}
this.matchers = []; this.matchers = [];
CLIPBOARD_CONFIG.concat(this.options.matchers ?? []).forEach( const baseMatchers = options.defaultMatchersOverride ?? CLIPBOARD_CONFIG;
([selector, matcher]) => { baseMatchers
.concat(this.options.matchers ?? [])
.forEach(([selector, matcher]) => {
this.addMatcher(selector, matcher); this.addMatcher(selector, matcher);
}, });
);
} }
addMatcher(selector: Selector, matcher: Matcher) { addMatcher(selector: Selector, matcher: Matcher) {
@ -109,7 +124,7 @@ class Clipboard extends Module<ClipboardOptions> {
if (!html) { if (!html) {
return new Delta().insert(text || '', formats); return new Delta().insert(text || '', formats);
} }
const delta = this.convertHTML(html); const delta = this.convertHTML(html, formats);
// Remove trailing newline // Remove trailing newline
if ( if (
deltaEndsWith(delta, '\n') && deltaEndsWith(delta, '\n') &&
@ -124,7 +139,7 @@ class Clipboard extends Module<ClipboardOptions> {
normalizeExternalHTML(doc); normalizeExternalHTML(doc);
} }
protected convertHTML(html: string) { protected convertHTML(html: string, formats: Record<string, unknown> = {}) {
const doc = new DOMParser().parseFromString(html, 'text/html'); const doc = new DOMParser().parseFromString(html, 'text/html');
this.normalizeHTML(doc); this.normalizeHTML(doc);
const container = doc.body; const container = doc.body;
@ -139,6 +154,7 @@ class Clipboard extends Module<ClipboardOptions> {
elementMatchers, elementMatchers,
textMatchers, textMatchers,
nodeMatches, nodeMatches,
formats,
); );
} }
@ -282,6 +298,7 @@ function applyFormat(
format: string, format: string,
value: unknown, value: unknown,
scroll: ScrollBlot, scroll: ScrollBlot,
attributes: AttributeMap,
): Delta { ): Delta {
if (!scroll.query(format)) { if (!scroll.query(format)) {
return delta; return delta;
@ -290,10 +307,14 @@ function applyFormat(
return delta.reduce((newDelta, op) => { return delta.reduce((newDelta, op) => {
if (!op.insert) return newDelta; if (!op.insert) return newDelta;
if (op.attributes && op.attributes[format]) { if (op.attributes && op.attributes[format]) {
return newDelta.push(op); return newDelta.insert(op.insert, { ...op.attributes, ...attributes });
} }
const formats = value ? { [format]: value } : {}; const formats = value ? { [format]: value } : {};
return newDelta.insert(op.insert, { ...formats, ...op.attributes }); return newDelta.insert(op.insert, {
...formats,
...op.attributes,
...attributes,
});
}, new Delta()); }, new Delta());
} }
@ -349,6 +370,7 @@ function isLine(node: Node, scroll: ScrollBlot) {
'section', 'section',
'table', 'table',
'td', 'td',
'time',
'tr', 'tr',
'ul', 'ul',
'video', 'video',
@ -384,11 +406,12 @@ function traverse(
elementMatchers: Matcher[], elementMatchers: Matcher[],
textMatchers: Matcher[], textMatchers: Matcher[],
nodeMatches: WeakMap<Node, Matcher[]>, nodeMatches: WeakMap<Node, Matcher[]>,
attributes: AttributeMap,
): Delta { ): Delta {
// Post-order // Post-order
if (node.nodeType === node.TEXT_NODE) { if (node.nodeType === node.TEXT_NODE) {
return textMatchers.reduce((delta: Delta, matcher) => { return textMatchers.reduce((delta: Delta, matcher) => {
return matcher(node, delta, scroll); return matcher(node, delta, scroll, attributes);
}, new Delta()); }, new Delta());
} }
if (node.nodeType === node.ELEMENT_NODE) { if (node.nodeType === node.ELEMENT_NODE) {
@ -399,14 +422,20 @@ function traverse(
elementMatchers, elementMatchers,
textMatchers, textMatchers,
nodeMatches, nodeMatches,
attributes,
); );
if (childNode.nodeType === node.ELEMENT_NODE) { if (childNode.nodeType === node.ELEMENT_NODE) {
childrenDelta = elementMatchers.reduce((reducedDelta, matcher) => { childrenDelta = elementMatchers.reduce((reducedDelta, matcher) => {
return matcher(childNode as HTMLElement, reducedDelta, scroll); return matcher(
childNode as HTMLElement,
reducedDelta,
scroll,
attributes,
);
}, childrenDelta); }, childrenDelta);
childrenDelta = (nodeMatches.get(childNode) || []).reduce( childrenDelta = (nodeMatches.get(childNode) || []).reduce(
(reducedDelta, matcher) => { (reducedDelta, matcher) => {
return matcher(childNode, reducedDelta, scroll); return matcher(childNode, reducedDelta, scroll, attributes);
}, },
childrenDelta, childrenDelta,
); );
@ -417,13 +446,23 @@ function traverse(
return new Delta(); return new Delta();
} }
function createMatchAlias(format: string) { function createMatchAlias(format: string): Matcher {
return (_node: Element, delta: Delta, scroll: ScrollBlot) => { return (
return applyFormat(delta, format, true, scroll); _node: Element,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) => {
return applyFormat(delta, format, true, scroll, attributes);
}; };
} }
function matchAttributor(node: HTMLElement, delta: Delta, scroll: ScrollBlot) { function matchAttributor(
node: HTMLElement,
delta: Delta,
scroll: ScrollBlot,
targetAttributes: AttributeMap,
) {
const attributes = Attributor.keys(node); const attributes = Attributor.keys(node);
const classes = ClassAttributor.keys(node); const classes = ClassAttributor.keys(node);
const styles = StyleAttributor.keys(node); const styles = StyleAttributor.keys(node);
@ -449,12 +488,18 @@ function matchAttributor(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
}); });
return Object.entries(formats).reduce( return Object.entries(formats).reduce(
(newDelta, [name, value]) => applyFormat(newDelta, name, value, scroll), (newDelta, [name, value]) =>
applyFormat(newDelta, name, value, scroll, targetAttributes),
delta, delta,
); );
} }
function matchBlot(node: Node, delta: Delta, scroll: ScrollBlot) { function matchBlot(
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
const match = scroll.query(node); const match = scroll.query(node);
if (match == null) return delta; if (match == null) return delta;
// @ts-expect-error // @ts-expect-error
@ -483,33 +528,49 @@ function matchBlot(node: Node, delta: Delta, scroll: ScrollBlot) {
match.blotName, match.blotName,
match.formats(node, scroll), match.formats(node, scroll),
scroll, scroll,
attributes,
); );
} }
} }
return delta; return delta;
} }
function matchBreak(node: Node, delta: Delta) { function matchBreak(
node: Node,
delta: Delta,
_scroll: ScrollBlot,
attributes: AttributeMap,
) {
if (!deltaEndsWith(delta, '\n')) { if (!deltaEndsWith(delta, '\n')) {
delta.insert('\n'); delta.insert('\n', attributes);
} }
return delta; return delta;
} }
function matchCodeBlock(node: Node, delta: Delta, scroll: ScrollBlot) { function matchCodeBlock(
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
const match = scroll.query('code-block'); const match = scroll.query('code-block');
const language = const language =
match && 'formats' in match && typeof match.formats === 'function' match && 'formats' in match && typeof match.formats === 'function'
? match.formats(node, scroll) ? match.formats(node, scroll)
: true; : true;
return applyFormat(delta, 'code-block', language, scroll); return applyFormat(delta, 'code-block', language, scroll, attributes);
} }
function matchIgnore() { function matchIgnore() {
return new Delta(); return new Delta();
} }
function matchIndent(node: Node, delta: Delta, scroll: ScrollBlot) { function matchIndent(
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
const match = scroll.query(node); const match = scroll.query(node);
if ( if (
match == null || match == null ||
@ -534,11 +595,20 @@ function matchIndent(node: Node, delta: Delta, scroll: ScrollBlot) {
if (op.attributes && typeof op.attributes.indent === 'number') { if (op.attributes && typeof op.attributes.indent === 'number') {
return composed.push(op); return composed.push(op);
} }
return composed.insert(op.insert, { indent, ...(op.attributes || {}) }); return composed.insert(op.insert, {
indent,
...(op.attributes || {}),
attributes,
});
}, new Delta()); }, new Delta());
} }
function matchList(node: Node, delta: Delta, scroll: ScrollBlot) { function matchList(
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
const element = node as Element; const element = node as Element;
let list = element.tagName === 'OL' ? 'ordered' : 'bullet'; let list = element.tagName === 'OL' ? 'ordered' : 'bullet';
@ -547,27 +617,48 @@ function matchList(node: Node, delta: Delta, scroll: ScrollBlot) {
list = checkedAttr === 'true' ? 'checked' : 'unchecked'; list = checkedAttr === 'true' ? 'checked' : 'unchecked';
} }
return applyFormat(delta, 'list', list, scroll); return applyFormat(delta, 'list', list, scroll, attributes);
} }
function matchNewline(node: Node, delta: Delta, scroll: ScrollBlot) { function deltaIs(delta: Delta, text: string): boolean {
if (!deltaEndsWith(delta, '\n')) { let allText = '';
for (
let i = delta.ops.length - 1;
i >= 0 && allText.length <= text.length;
i -= 1
) {
const op = delta.ops[i];
if (typeof op.insert !== 'string') {
break;
}
allText = op.insert + allText;
}
return allText === text;
}
function matchNewline(
node: Node,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
if (!deltaIs(delta, '\n') && !deltaEndsWith(delta, '\n\n')) {
if ( if (
isLine(node, scroll) && isLine(node, scroll) &&
(node.childNodes.length > 0 || node instanceof HTMLParagraphElement) (node.childNodes.length > 0 || node instanceof HTMLParagraphElement)
) { ) {
return delta.insert('\n'); return delta.insert('\n', attributes);
} }
if (delta.length() > 0 && node.nextSibling) { if (delta.length() > 0 && node.nextSibling) {
let nextSibling: Node | null = node.nextSibling; let nextSibling: Node | null = node.nextSibling;
while (nextSibling != null) { while (nextSibling != null) {
if (isLine(nextSibling, scroll)) { if (isLine(nextSibling, scroll)) {
return delta.insert('\n'); return delta.insert('\n', attributes);
} }
const match = scroll.query(nextSibling); const match = scroll.query(nextSibling);
// @ts-expect-error // @ts-expect-error
if (match && match.prototype instanceof BlockEmbed) { if (match && match.prototype instanceof BlockEmbed) {
return delta.insert('\n'); return delta.insert('\n', attributes);
} }
nextSibling = nextSibling.firstChild; nextSibling = nextSibling.firstChild;
} }
@ -576,7 +667,12 @@ function matchNewline(node: Node, delta: Delta, scroll: ScrollBlot) {
return delta; return delta;
} }
function matchStyles(node: HTMLElement, delta: Delta, scroll: ScrollBlot) { function matchStyles(
node: HTMLElement,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
const formats: Record<string, unknown> = {}; const formats: Record<string, unknown> = {};
const style: Partial<CSSStyleDeclaration> = node.style || {}; const style: Partial<CSSStyleDeclaration> = node.style || {};
if (style.fontStyle === 'italic') { if (style.fontStyle === 'italic') {
@ -596,13 +692,14 @@ function matchStyles(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
formats.bold = true; formats.bold = true;
} }
delta = Object.entries(formats).reduce( delta = Object.entries(formats).reduce(
(newDelta, [name, value]) => applyFormat(newDelta, name, value, scroll), (newDelta, [name, value]) =>
applyFormat(newDelta, name, value, scroll, attributes),
delta, delta,
); );
// @ts-expect-error // @ts-expect-error
if (parseFloat(style.textIndent || 0) > 0) { if (parseFloat(style.textIndent || 0) > 0) {
// Could be 0.5in // Could be 0.5in
return new Delta().insert('\t').concat(delta); return new Delta().insert('\t', attributes).concat(delta);
} }
return delta; return delta;
} }
@ -611,6 +708,7 @@ function matchTable(
node: HTMLTableRowElement, node: HTMLTableRowElement,
delta: Delta, delta: Delta,
scroll: ScrollBlot, scroll: ScrollBlot,
attributes: AttributeMap,
) { ) {
const table = const table =
node.parentElement?.tagName === 'TABLE' node.parentElement?.tagName === 'TABLE'
@ -619,17 +717,22 @@ function matchTable(
if (table != null) { if (table != null) {
const rows = Array.from(table.querySelectorAll('tr')); const rows = Array.from(table.querySelectorAll('tr'));
const row = rows.indexOf(node) + 1; const row = rows.indexOf(node) + 1;
return applyFormat(delta, 'table', row, scroll); return applyFormat(delta, 'table', row, scroll, attributes);
} }
return delta; return delta;
} }
function matchText(node: HTMLElement, delta: Delta, scroll: ScrollBlot) { function matchText(
node: HTMLElement,
delta: Delta,
scroll: ScrollBlot,
attributes: AttributeMap,
) {
// @ts-expect-error // @ts-expect-error
let text = node.data as string; let text = node.data as string;
// Word represents empty line with <o:p>&nbsp;</o:p> // Word represents empty line with <o:p>&nbsp;</o:p>
if (node.parentElement?.tagName === 'O:P') { if (node.parentElement?.tagName === 'O:P') {
return delta.insert(text.trim()); return delta.insert(text.trim(), attributes);
} }
if (!isPre(node)) { if (!isPre(node)) {
if ( if (
@ -665,13 +768,14 @@ function matchText(node: HTMLElement, delta: Delta, scroll: ScrollBlot) {
// done removing whitespace and can normalize all to regular space // done removing whitespace and can normalize all to regular space
text = text.replaceAll('\u00a0', ' '); text = text.replaceAll('\u00a0', ' ');
} }
return delta.insert(text); return delta.insert(text, attributes);
} }
export { export {
Clipboard as default, Clipboard as default,
matchAttributor, matchAttributor,
matchBlot, matchBlot,
matchBreak,
matchNewline, matchNewline,
matchText, matchText,
traverse, traverse,

View File

@ -1,4 +1,4 @@
import { Scope } from 'parchment'; import { Scope } from '@signalapp/parchment-cjs';
import type Delta from 'quill-delta'; import type Delta from 'quill-delta';
import Module from '../core/module.js'; import Module from '../core/module.js';
import Quill from '../core/quill.js'; import Quill from '../core/quill.js';

View File

@ -1,7 +1,7 @@
import { cloneDeep, isEqual } from 'lodash-es'; import { cloneDeep, isEqual } from 'lodash';
import Delta, { AttributeMap } from 'quill-delta'; import Delta, { AttributeMap } from 'quill-delta';
import { EmbedBlot, Scope, TextBlot } from 'parchment'; import { EmbedBlot, Scope, TextBlot } from '@signalapp/parchment-cjs';
import type { Blot, BlockBlot } from 'parchment'; import type { Blot, BlockBlot } from '@signalapp/parchment-cjs';
import Quill from '../core/quill.js'; import Quill from '../core/quill.js';
import logger from '../core/logger.js'; import logger from '../core/logger.js';
import Module from '../core/module.js'; import Module from '../core/module.js';
@ -206,8 +206,7 @@ class Keyboard extends Module<KeyboardOptions> {
leafEnd instanceof TextBlot ? leafEnd.value().slice(offsetEnd) : ''; leafEnd instanceof TextBlot ? leafEnd.value().slice(offsetEnd) : '';
const curContext = { const curContext = {
collapsed: range.length === 0, collapsed: range.length === 0,
// @ts-expect-error Fix me later empty: range.length === 0 && (line?.length() ?? 0) <= 1,
empty: range.length === 0 && line.length() <= 1,
format: this.quill.getFormat(range), format: this.quill.getFormat(range),
line, line,
offset, offset,
@ -351,6 +350,13 @@ class Keyboard extends Module<KeyboardOptions> {
this.quill.updateContents(delta, Quill.sources.USER); this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(range.index + 1, Quill.sources.SILENT); this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
this.quill.focus(); this.quill.focus();
Object.keys(context.format).forEach((name) => {
if (lineFormats[name] != null) return;
if (Array.isArray(context.format[name])) return;
if (name === 'code' || name === 'link') return;
this.quill.format(name, context.format[name], Quill.sources.USER);
});
} }
} }

View File

@ -1,6 +1,6 @@
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import { ClassAttributor, Scope } from 'parchment'; import { ClassAttributor, Scope } from '@signalapp/parchment-cjs';
import type { Blot, ScrollBlot } from 'parchment'; import type { Blot, ScrollBlot } from '@signalapp/parchment-cjs';
import Inline from '../blots/inline.js'; import Inline from '../blots/inline.js';
import Quill from '../core/quill.js'; import Quill from '../core/quill.js';
import Module from '../core/module.js'; import Module from '../core/module.js';
@ -302,6 +302,10 @@ class Syntax extends Module<SyntaxOptions> {
const container = this.quill.root.ownerDocument.createElement('div'); const container = this.quill.root.ownerDocument.createElement('div');
container.classList.add(CodeBlock.className); container.classList.add(CodeBlock.className);
container.innerHTML = highlight(this.options.hljs, language, text); container.innerHTML = highlight(this.options.hljs, language, text);
const attributes = this.quill.getFormat(
this.quill.selection.savedRange.index,
);
return traverse( return traverse(
this.quill.scroll, this.quill.scroll,
container, container,
@ -329,6 +333,7 @@ class Syntax extends Module<SyntaxOptions> {
}, },
], ],
new WeakMap(), new WeakMap(),
attributes,
); );
} }
} }

View File

@ -1,5 +1,5 @@
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import { EmbedBlot, Scope } from 'parchment'; import { EmbedBlot, Scope } from '@signalapp/parchment-cjs';
import Quill from '../core/quill.js'; import Quill from '../core/quill.js';
import logger from '../core/logger.js'; import logger from '../core/logger.js';
import Module from '../core/module.js'; import Module from '../core/module.js';

View File

@ -1,4 +1,4 @@
import { ParentBlot } from 'parchment'; import { ParentBlot } from '@signalapp/parchment-cjs';
import Module from '../core/module.js'; import Module from '../core/module.js';
import Quill from '../core/quill.js'; import Quill from '../core/quill.js';

View File

@ -1,4 +1,4 @@
import { merge } from 'lodash-es'; import { merge } from 'lodash';
import type Quill from '../core/quill.js'; import type Quill from '../core/quill.js';
import Emitter from '../core/emitter.js'; import Emitter from '../core/emitter.js';
import Theme from '../core/theme.js'; import Theme from '../core/theme.js';

View File

@ -1,4 +1,4 @@
import { merge } from 'lodash-es'; import { merge } from 'lodash';
import Emitter from '../core/emitter.js'; import Emitter from '../core/emitter.js';
import BaseTheme, { BaseTooltip } from './base.js'; import BaseTheme, { BaseTooltip } from './base.js';
import { Range } from '../core/selection.js'; import { Range } from '../core/selection.js';

View File

@ -1,4 +1,4 @@
import { merge } from 'lodash-es'; import { merge } from 'lodash';
import Emitter from '../core/emitter.js'; import Emitter from '../core/emitter.js';
import BaseTheme, { BaseTooltip } from './base.js'; import BaseTheme, { BaseTooltip } from './base.js';
import LinkBlot from '../formats/link.js'; import LinkBlot from '../formats/link.js';

View File

@ -3,7 +3,7 @@ import Quill, { Delta } from '../../src/quill.js';
import type { EmitterSource, Parchment, Range } from '../../src/quill.js'; import type { EmitterSource, Parchment, Range } from '../../src/quill.js';
import type { default as Block, BlockEmbed } from '../../src/blots/block.js'; import type { default as Block, BlockEmbed } from '../../src/blots/block.js';
import SnowTheme from '../../src/themes/snow.js'; import SnowTheme from '../../src/themes/snow.js';
import { LeafBlot } from 'parchment'; import { LeafBlot } from '@signalapp/parchment-cjs';
{ {
const Counter = (quill: Quill, options: { unit: string }) => { const Counter = (quill: Quill, options: { unit: string }) => {

View File

@ -1,5 +1,5 @@
import { Registry } from 'parchment'; import { Registry } from '@signalapp/parchment-cjs';
import type { Attributor } from 'parchment'; import type { Attributor } from '@signalapp/parchment-cjs';
import Block from '../../../src/blots/block.js'; import Block from '../../../src/blots/block.js';
import Break from '../../../src/blots/break.js'; import Break from '../../../src/blots/break.js';

View File

@ -3,7 +3,7 @@ import Editor from '../../../src/core/editor.js';
import Block from '../../../src/blots/block.js'; import Block from '../../../src/blots/block.js';
import { Range } from '../../../src/core/selection.js'; import { Range } from '../../../src/core/selection.js';
import Scroll from '../../../src/blots/scroll.js'; import Scroll from '../../../src/blots/scroll.js';
import { Registry } from 'parchment'; import { Registry } from '@signalapp/parchment-cjs';
import Text from '../../../src/blots/text.js'; import Text from '../../../src/blots/text.js';
import Emitter from '../../../src/core/emitter.js'; import Emitter from '../../../src/core/emitter.js';
import Break from '../../../src/blots/break.js'; import Break from '../../../src/blots/break.js';

View File

@ -1,6 +1,6 @@
import '../../../src/quill.js'; import '../../../src/quill.js';
import Delta from 'quill-delta'; import Delta from 'quill-delta';
import { LeafBlot, Registry } from 'parchment'; import { LeafBlot, Registry } from '@signalapp/parchment-cjs';
import { afterEach, beforeEach, describe, expect, test, vitest } from 'vitest'; import { afterEach, beforeEach, describe, expect, test, vitest } from 'vitest';
import type { MockedFunction } from 'vitest'; import type { MockedFunction } from 'vitest';
import Emitter from '../../../src/core/emitter.js'; import Emitter from '../../../src/core/emitter.js';

View File

@ -3,7 +3,7 @@ import { describe, expect, test, vitest } from 'vitest';
import createRegistryWithFormats from '../../../../src/core/utils/createRegistryWithFormats.js'; import createRegistryWithFormats from '../../../../src/core/utils/createRegistryWithFormats.js';
import { globalRegistry } from '../../../../src/core/quill.js'; import { globalRegistry } from '../../../../src/core/quill.js';
import logger from '../../../../src/core/logger.js'; import logger from '../../../../src/core/logger.js';
import { Registry } from 'parchment'; import { Registry } from '@signalapp/parchment-cjs';
import Inline from '../../../../src/blots/inline.js'; import Inline from '../../../../src/blots/inline.js';
import Container from '../../../../src/blots/container.js'; import Container from '../../../../src/blots/container.js';

View File

@ -17,7 +17,7 @@ import {
} from '../../../src/formats/table.js'; } from '../../../src/formats/table.js';
import Video from '../../../src/formats/video.js'; import Video from '../../../src/formats/video.js';
import { createRegistry } from '../__helpers__/factory.js'; import { createRegistry } from '../__helpers__/factory.js';
import type { RegistryDefinition } from 'parchment'; import type { RegistryDefinition } from '@signalapp/parchment-cjs';
import { import {
DirectionAttribute, DirectionAttribute,
DirectionClass, DirectionClass,

View File

@ -11,11 +11,12 @@
"sourceMap": true, "sourceMap": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"declaration": false, "declaration": false,
"module": "ES2020", "module": "CommonJS",
"moduleResolution": "bundler", "moduleResolution": "node",
"strictNullChecks": true, "strictNullChecks": true,
"noImplicitAny": true, "noImplicitAny": true,
"noUnusedLocals": true "noUnusedLocals": true,
"skipLibCheck": true
}, },
"include": ["src/**/*", "test/**/*"] "include": ["src/**/*", "test/**/*"]
} }