@prosekit/core 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{editor-4lgGc3CY.d.ts → editor.d.ts} +58 -18
- package/dist/editor.d.ts.map +1 -0
- package/dist/{editor-DGNUXn-u.js → editor.js} +40 -81
- package/dist/editor.js.map +1 -0
- package/dist/prosekit-core-test.d.ts +1 -2
- package/dist/prosekit-core-test.d.ts.map +1 -1
- package/dist/prosekit-core-test.js +2 -4
- package/dist/prosekit-core-test.js.map +1 -1
- package/dist/prosekit-core.d.ts +148 -68
- package/dist/prosekit-core.d.ts.map +1 -1
- package/dist/prosekit-core.js +184 -138
- package/dist/prosekit-core.js.map +1 -1
- package/package.json +9 -9
- package/src/commands/add-mark.ts +3 -6
- package/src/commands/expand-mark.ts +4 -11
- package/src/commands/insert-default-block.spec.ts +4 -8
- package/src/commands/insert-default-block.ts +2 -5
- package/src/commands/insert-node.ts +7 -11
- package/src/commands/remove-mark.ts +3 -6
- package/src/commands/remove-node.ts +4 -4
- package/src/commands/select-block.spec.ts +6 -8
- package/src/commands/select-block.ts +2 -5
- package/src/commands/set-block-type.ts +3 -6
- package/src/commands/set-node-attrs-between.spec.ts +221 -0
- package/src/commands/set-node-attrs-between.ts +77 -0
- package/src/commands/set-node-attrs.spec.ts +129 -0
- package/src/commands/set-node-attrs.ts +26 -27
- package/src/commands/toggle-mark.ts +3 -6
- package/src/commands/toggle-node.ts +4 -7
- package/src/commands/toggle-wrap.spec.ts +2 -6
- package/src/commands/toggle-wrap.ts +3 -6
- package/src/commands/unset-block-type.spec.ts +2 -6
- package/src/commands/unset-block-type.ts +3 -9
- package/src/commands/unset-mark.spec.ts +2 -6
- package/src/commands/unset-mark.ts +1 -1
- package/src/commands/wrap.ts +2 -5
- package/src/editor/action.spec.ts +5 -9
- package/src/editor/action.ts +7 -14
- package/src/editor/editor.spec.ts +8 -15
- package/src/editor/editor.ts +18 -52
- package/src/editor/union.spec.ts +8 -12
- package/src/editor/union.ts +4 -7
- package/src/editor/with-priority.ts +3 -3
- package/src/error.ts +8 -1
- package/src/extensions/clipboard-serializer.ts +22 -26
- package/src/extensions/command.ts +22 -54
- package/src/extensions/default-state.spec.ts +4 -8
- package/src/extensions/default-state.ts +6 -12
- package/src/extensions/events/doc-change.ts +2 -2
- package/src/extensions/events/dom-event.spec.ts +4 -9
- package/src/extensions/events/dom-event.ts +9 -21
- package/src/extensions/events/editor-event.ts +8 -20
- package/src/extensions/events/focus.spec.ts +7 -12
- package/src/extensions/events/focus.ts +2 -2
- package/src/extensions/events/plugin-view.ts +5 -12
- package/src/extensions/history.ts +7 -14
- package/src/extensions/keymap-base.spec.ts +6 -15
- package/src/extensions/keymap-base.ts +6 -9
- package/src/extensions/keymap.spec.ts +10 -24
- package/src/extensions/keymap.ts +5 -15
- package/src/extensions/mark-spec.spec.ts +6 -21
- package/src/extensions/mark-spec.ts +10 -21
- package/src/extensions/mark-view-effect.ts +6 -12
- package/src/extensions/mark-view.ts +5 -11
- package/src/extensions/node-spec.spec.ts +10 -26
- package/src/extensions/node-spec.ts +10 -21
- package/src/extensions/node-view-effect.ts +6 -12
- package/src/extensions/node-view.ts +5 -11
- package/src/extensions/plugin.spec.ts +9 -22
- package/src/extensions/plugin.ts +6 -15
- package/src/facets/base-extension.ts +7 -10
- package/src/facets/command.ts +3 -9
- package/src/facets/facet-extension.spec.ts +10 -21
- package/src/facets/facet-extension.ts +12 -8
- package/src/facets/facet-node.spec.ts +4 -11
- package/src/facets/facet-node.ts +27 -22
- package/src/facets/facet.spec.ts +2 -5
- package/src/facets/facet.ts +14 -7
- package/src/facets/root.ts +2 -2
- package/src/facets/schema-spec.ts +3 -10
- package/src/facets/schema.ts +4 -13
- package/src/facets/state.spec.ts +8 -15
- package/src/facets/state.ts +5 -19
- package/src/facets/union-extension.ts +10 -13
- package/src/index.ts +74 -200
- package/src/test/index.ts +1 -4
- package/src/test/test-builder.ts +2 -5
- package/src/test/test-editor.spec.ts +2 -6
- package/src/test/test-editor.ts +7 -26
- package/src/testing/index.ts +26 -22
- package/src/types/extension-mark.ts +1 -1
- package/src/types/extension-node.ts +1 -1
- package/src/types/extension.spec.ts +2 -5
- package/src/types/extension.ts +8 -18
- package/src/types/pick-string-literal.spec.ts +2 -2
- package/src/types/pick-string-literal.ts +1 -1
- package/src/types/pick-sub-type.spec.ts +2 -2
- package/src/types/priority.ts +50 -7
- package/src/types/simplify-deeper.spec.ts +2 -2
- package/src/types/simplify-union.spec.ts +2 -2
- package/src/types/simplify-union.ts +1 -4
- package/src/utils/array-grouping.spec.ts +2 -5
- package/src/utils/assert.ts +1 -1
- package/src/utils/attrs-match.ts +1 -5
- package/src/utils/can-use-regex-lookbehind.ts +2 -8
- package/src/utils/clsx.spec.ts +2 -5
- package/src/utils/combine-event-handlers.spec.ts +2 -6
- package/src/utils/default-block-at.ts +1 -4
- package/src/utils/editor-content.spec.ts +3 -6
- package/src/utils/editor-content.ts +5 -17
- package/src/utils/find-node.ts +65 -0
- package/src/utils/find-parent-node-of-type.ts +6 -12
- package/src/utils/find-parent-node.spec.ts +3 -7
- package/src/utils/find-parent-node.ts +1 -4
- package/src/utils/get-custom-selection.ts +1 -5
- package/src/utils/get-dom-api.ts +1 -1
- package/src/utils/get-mark-type.ts +2 -5
- package/src/utils/get-node-type.ts +2 -5
- package/src/utils/get-node-types.ts +2 -5
- package/src/utils/includes-mark.ts +2 -6
- package/src/utils/is-at-block-start.ts +1 -4
- package/src/utils/is-mark-absent.spec.ts +3 -6
- package/src/utils/is-mark-absent.ts +2 -6
- package/src/utils/is-mark-active.ts +4 -7
- package/src/utils/is-node-active.spec.ts +109 -0
- package/src/utils/is-node-active.ts +19 -10
- package/src/utils/is-subset.spec.ts +2 -5
- package/src/utils/maybe-run.spec.ts +2 -6
- package/src/utils/merge-objects.spec.ts +2 -5
- package/src/utils/merge-objects.ts +3 -2
- package/src/utils/merge-specs.ts +2 -5
- package/src/utils/object-equal.spec.ts +2 -5
- package/src/utils/output-spec.test.ts +2 -6
- package/src/utils/output-spec.ts +2 -10
- package/src/utils/parse.spec.ts +6 -15
- package/src/utils/parse.ts +4 -16
- package/src/utils/remove-undefined-values.spec.ts +2 -5
- package/src/utils/set-selection-around.ts +1 -4
- package/src/utils/type-assertion.ts +2 -21
- package/src/utils/unicode.spec.ts +2 -5
- package/src/utils/with-skip-code-block.ts +1 -1
- package/dist/editor-4lgGc3CY.d.ts.map +0 -1
- package/dist/editor-DGNUXn-u.js.map +0 -1
package/src/utils/assert.ts
CHANGED
package/src/utils/attrs-match.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { supportsRegexLookbehind } from '@ocavue/utils'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Checks if the browser supports [regex lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion).
|
|
5
5
|
*/
|
|
6
|
-
export const canUseRegexLookbehind: () => boolean =
|
|
7
|
-
try {
|
|
8
|
-
return 'ab'.replace(new RegExp('(?<=a)b', 'g'), 'c') === 'ac'
|
|
9
|
-
} catch {
|
|
10
|
-
return false
|
|
11
|
-
}
|
|
12
|
-
})
|
|
6
|
+
export const canUseRegexLookbehind: () => boolean = supportsRegexLookbehind
|
package/src/utils/clsx.spec.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
expect,
|
|
3
|
-
test,
|
|
4
|
-
vi,
|
|
5
|
-
} from 'vitest'
|
|
1
|
+
import { expect, test, vi } from 'vitest'
|
|
6
2
|
|
|
7
|
-
import { combineEventHandlers } from './combine-event-handlers'
|
|
3
|
+
import { combineEventHandlers } from './combine-event-handlers.ts'
|
|
8
4
|
|
|
9
5
|
test('runs handlers in reverse order and stops on true', () => {
|
|
10
6
|
const handler1 = vi.fn(() => false)
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { AllSelection } from '@prosekit/pm/state'
|
|
2
|
-
import {
|
|
3
|
-
expect,
|
|
4
|
-
test,
|
|
5
|
-
} from 'vitest'
|
|
2
|
+
import { expect, test } from 'vitest'
|
|
6
3
|
|
|
7
|
-
import { setupTest } from '../testing'
|
|
4
|
+
import { setupTest } from '../testing/index.ts'
|
|
8
5
|
|
|
9
|
-
import { getEditorSelection } from './editor-content'
|
|
6
|
+
import { getEditorSelection } from './editor-content.ts'
|
|
10
7
|
|
|
11
8
|
test('getEditorSelection', () => {
|
|
12
9
|
const { n } = setupTest()
|
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
import { isElementLike } from '@ocavue/utils'
|
|
2
|
-
import type {
|
|
3
|
-
ProseMirrorNode,
|
|
4
|
-
Schema,
|
|
5
|
-
} from '@prosekit/pm/model'
|
|
2
|
+
import type { ProseMirrorNode, Schema } from '@prosekit/pm/model'
|
|
6
3
|
import { Selection } from '@prosekit/pm/state'
|
|
7
4
|
|
|
8
|
-
import type {
|
|
9
|
-
NodeJSON,
|
|
10
|
-
SelectionJSON,
|
|
11
|
-
} from '../types/model'
|
|
5
|
+
import type { NodeJSON, SelectionJSON } from '../types/model.ts'
|
|
12
6
|
|
|
13
|
-
import { assert } from './assert'
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
jsonFromHTML,
|
|
17
|
-
} from './parse'
|
|
18
|
-
import {
|
|
19
|
-
isProseMirrorNode,
|
|
20
|
-
isSelection,
|
|
21
|
-
} from './type-assertion'
|
|
7
|
+
import { assert } from './assert.ts'
|
|
8
|
+
import { jsonFromElement, jsonFromHTML } from './parse.ts'
|
|
9
|
+
import { isProseMirrorNode, isSelection } from './type-assertion.ts'
|
|
22
10
|
|
|
23
11
|
export function getEditorContentJSON(
|
|
24
12
|
schema: Schema,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ProseMirrorNode } from '@prosekit/pm/model'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Finds the first node that satisfies the predicate from the given document.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export function findNode(
|
|
9
|
+
doc: ProseMirrorNode,
|
|
10
|
+
predicate: (node: ProseMirrorNode) => boolean,
|
|
11
|
+
): FindNodeResult | undefined {
|
|
12
|
+
let found: FindNodeResult | undefined
|
|
13
|
+
doc.descendants((node, pos, parent, index) => {
|
|
14
|
+
if (found) {
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
if (predicate(node)) {
|
|
18
|
+
found = { node, pos, parent, index }
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
return found
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Finds all nodes that satisfy the predicate from the given document.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export function findNodes(
|
|
31
|
+
doc: ProseMirrorNode,
|
|
32
|
+
predicate: (node: ProseMirrorNode) => boolean,
|
|
33
|
+
): FindNodeResult[] {
|
|
34
|
+
const results: FindNodeResult[] = []
|
|
35
|
+
doc.descendants((node, pos, parent, index) => {
|
|
36
|
+
if (predicate(node)) {
|
|
37
|
+
results.push({ node, pos, parent, index })
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
return results
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The result of the {@link findNode} function.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export interface FindNodeResult {
|
|
49
|
+
/**
|
|
50
|
+
* The node that satisfies the predicate.
|
|
51
|
+
*/
|
|
52
|
+
node: ProseMirrorNode
|
|
53
|
+
/**
|
|
54
|
+
* The position of the node.
|
|
55
|
+
*/
|
|
56
|
+
pos: number
|
|
57
|
+
/**
|
|
58
|
+
* The parent of the node.
|
|
59
|
+
*/
|
|
60
|
+
parent: ProseMirrorNode | null
|
|
61
|
+
/**
|
|
62
|
+
* The index of the node in the parent.
|
|
63
|
+
*/
|
|
64
|
+
index: number
|
|
65
|
+
}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
NodeType,
|
|
3
|
-
ResolvedPos,
|
|
4
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { NodeType, ResolvedPos } from '@prosekit/pm/model'
|
|
5
2
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
type FindParentNodeResult,
|
|
9
|
-
} from './find-parent-node'
|
|
10
|
-
import { getNodeType } from './get-node-type'
|
|
3
|
+
import { findParentNode, type FindParentNodeResult } from './find-parent-node.ts'
|
|
4
|
+
import { getNodeTypes } from './get-node-types.ts'
|
|
11
5
|
|
|
12
6
|
/**
|
|
13
7
|
* Finds the closest parent node that matches the given node type.
|
|
@@ -18,12 +12,12 @@ export function findParentNodeOfType(
|
|
|
18
12
|
/**
|
|
19
13
|
* The type of the node to find.
|
|
20
14
|
*/
|
|
21
|
-
type: NodeType | string,
|
|
15
|
+
type: string | NodeType | string[] | NodeType[],
|
|
22
16
|
/**
|
|
23
17
|
* The position to start searching from.
|
|
24
18
|
*/
|
|
25
19
|
$pos: ResolvedPos,
|
|
26
20
|
): FindParentNodeResult | undefined {
|
|
27
|
-
const
|
|
28
|
-
return findParentNode((node) => node.type
|
|
21
|
+
const nodeTypes = getNodeTypes($pos.doc.type.schema, type)
|
|
22
|
+
return findParentNode((node) => nodeTypes.includes(node.type), $pos)
|
|
29
23
|
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
describe,
|
|
3
|
-
expect,
|
|
4
|
-
it,
|
|
5
|
-
} from 'vitest'
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
6
2
|
|
|
7
|
-
import { setupTest } from '../testing'
|
|
3
|
+
import { setupTest } from '../testing/index.ts'
|
|
8
4
|
|
|
9
|
-
import { findParentNode } from './find-parent-node'
|
|
5
|
+
import { findParentNode } from './find-parent-node.ts'
|
|
10
6
|
|
|
11
7
|
describe('findParentNode', () => {
|
|
12
8
|
it('finds parent node with cursor directly inside', () => {
|
package/src/utils/get-dom-api.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Attrs,
|
|
3
|
-
Mark,
|
|
4
|
-
MarkType,
|
|
5
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { Attrs, Mark, MarkType } from '@prosekit/pm/model'
|
|
6
2
|
|
|
7
|
-
import { isSubset } from './is-subset'
|
|
3
|
+
import { isSubset } from './is-subset.ts'
|
|
8
4
|
|
|
9
5
|
export function includesMark(
|
|
10
6
|
marks: readonly Mark[],
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { ResolvedPos } from '@prosekit/pm/model'
|
|
2
|
-
import type {
|
|
3
|
-
EditorState,
|
|
4
|
-
TextSelection,
|
|
5
|
-
} from '@prosekit/pm/state'
|
|
2
|
+
import type { EditorState, TextSelection } from '@prosekit/pm/state'
|
|
6
3
|
import type { EditorView } from '@prosekit/pm/view'
|
|
7
4
|
|
|
8
5
|
/**
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
expect,
|
|
3
|
-
test,
|
|
4
|
-
} from 'vitest'
|
|
1
|
+
import { expect, test } from 'vitest'
|
|
5
2
|
|
|
6
|
-
import { setupTest } from '../testing'
|
|
3
|
+
import { setupTest } from '../testing/index.ts'
|
|
7
4
|
|
|
8
|
-
import { isMarkAbsent } from './is-mark-absent'
|
|
5
|
+
import { isMarkAbsent } from './is-mark-absent.ts'
|
|
9
6
|
|
|
10
7
|
test('isMarkAbsent', () => {
|
|
11
8
|
const { editor, m, n } = setupTest()
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Attrs,
|
|
3
|
-
MarkType,
|
|
4
|
-
ProseMirrorNode,
|
|
5
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { Attrs, MarkType, ProseMirrorNode } from '@prosekit/pm/model'
|
|
6
2
|
|
|
7
|
-
import { includesMark } from './includes-mark'
|
|
3
|
+
import { includesMark } from './includes-mark.ts'
|
|
8
4
|
|
|
9
5
|
/**
|
|
10
6
|
* Returns true if the given mark is missing in some part of the range.
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Attrs,
|
|
3
|
-
MarkType,
|
|
4
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { Attrs, MarkType } from '@prosekit/pm/model'
|
|
5
2
|
import type { EditorState } from '@prosekit/pm/state'
|
|
6
3
|
|
|
7
|
-
import { getMarkType } from './get-mark-type'
|
|
8
|
-
import { includesMark } from './includes-mark'
|
|
9
|
-
import { isMarkAbsent } from './is-mark-absent'
|
|
4
|
+
import { getMarkType } from './get-mark-type.ts'
|
|
5
|
+
import { includesMark } from './includes-mark.ts'
|
|
6
|
+
import { isMarkAbsent } from './is-mark-absent.ts'
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* @internal
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { NodeSelection } from '@prosekit/pm/state'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { setupTest } from '../testing/index.ts'
|
|
5
|
+
|
|
6
|
+
import { isNodeActive } from './is-node-active.ts'
|
|
7
|
+
|
|
8
|
+
describe('isNodeActive', () => {
|
|
9
|
+
it('should return true when cursor is in a node of the specified type', () => {
|
|
10
|
+
const { editor, n } = setupTest()
|
|
11
|
+
editor.set(n.doc(n.p('Hello <a>world')))
|
|
12
|
+
|
|
13
|
+
expect(isNodeActive(editor.state, 'paragraph')).toBe(true)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should return false when cursor is not in a node of the specified type', () => {
|
|
17
|
+
const { editor, n } = setupTest()
|
|
18
|
+
editor.set(n.doc(n.p('Hello <a>world')))
|
|
19
|
+
|
|
20
|
+
expect(isNodeActive(editor.state, 'codeBlock')).toBe(false)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should return true when cursor is in a nested node of the specified type', () => {
|
|
24
|
+
const { editor, n } = setupTest()
|
|
25
|
+
editor.set(n.doc(n.blockquote(n.p('Hello <a>world'))))
|
|
26
|
+
|
|
27
|
+
expect(isNodeActive(editor.state, 'blockquote')).toBe(true)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should return true when cursor is in a node with matching attributes', () => {
|
|
31
|
+
const { editor, n } = setupTest()
|
|
32
|
+
editor.set(n.doc(n.codeBlock({ language: 'typescript' }, '<a>code')))
|
|
33
|
+
|
|
34
|
+
expect(isNodeActive(editor.state, 'codeBlock', { language: 'typescript' })).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should return false when cursor is in a node with non-matching attributes', () => {
|
|
38
|
+
const { editor, n } = setupTest()
|
|
39
|
+
editor.set(n.doc(n.codeBlock({ language: 'typescript' }, '<a>code')))
|
|
40
|
+
|
|
41
|
+
expect(isNodeActive(editor.state, 'codeBlock', { language: 'javascript' })).toBe(false)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should return true when using NodeSelection with matching type', () => {
|
|
45
|
+
const { editor, n } = setupTest()
|
|
46
|
+
editor.set(n.doc(n.p('Hello world')))
|
|
47
|
+
|
|
48
|
+
const $pos = editor.state.doc.resolve(0)
|
|
49
|
+
const state = editor.state.apply(
|
|
50
|
+
editor.state.tr.setSelection(NodeSelection.create(editor.state.doc, $pos.pos)),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
expect(isNodeActive(state, 'paragraph')).toBe(true)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should return true when using NodeSelection with matching type and attributes', () => {
|
|
57
|
+
const { editor, n } = setupTest()
|
|
58
|
+
editor.set(n.doc(n.codeBlock({ language: 'python' }, 'code')))
|
|
59
|
+
|
|
60
|
+
const $pos = editor.state.doc.resolve(0)
|
|
61
|
+
const state = editor.state.apply(
|
|
62
|
+
editor.state.tr.setSelection(NodeSelection.create(editor.state.doc, $pos.pos)),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
expect(isNodeActive(state, 'codeBlock', { language: 'python' })).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should return false when using NodeSelection with non-matching attributes', () => {
|
|
69
|
+
const { editor, n } = setupTest()
|
|
70
|
+
editor.set(n.doc(n.codeBlock({ language: 'python' }, 'code')))
|
|
71
|
+
|
|
72
|
+
const $pos = editor.state.doc.resolve(0)
|
|
73
|
+
const state = editor.state.apply(
|
|
74
|
+
editor.state.tr.setSelection(NodeSelection.create(editor.state.doc, $pos.pos)),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
expect(isNodeActive(state, 'codeBlock', { language: 'javascript' })).toBe(false)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should work with NodeType instead of string', () => {
|
|
81
|
+
const { editor, n } = setupTest()
|
|
82
|
+
editor.set(n.doc(n.p('Hello <a>world')))
|
|
83
|
+
|
|
84
|
+
expect(isNodeActive(editor.state, editor.state.schema.nodes.paragraph)).toBe(true)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should return true when node is at any depth in the hierarchy', () => {
|
|
88
|
+
const { editor, n } = setupTest()
|
|
89
|
+
editor.set(n.doc(n.blockquote(n.p('Hello <a>world'))))
|
|
90
|
+
|
|
91
|
+
expect(isNodeActive(editor.state, 'paragraph')).toBe(true)
|
|
92
|
+
expect(isNodeActive(editor.state, 'blockquote')).toBe(true)
|
|
93
|
+
expect(isNodeActive(editor.state, 'doc')).toBe(true)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should return true when attributes is null', () => {
|
|
97
|
+
const { editor, n } = setupTest()
|
|
98
|
+
editor.set(n.doc(n.codeBlock({ language: 'typescript' }, '<a>code')))
|
|
99
|
+
|
|
100
|
+
expect(isNodeActive(editor.state, 'codeBlock', null)).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should match partial attributes', () => {
|
|
104
|
+
const { editor, n } = setupTest()
|
|
105
|
+
editor.set(n.doc(n.codeBlock({ language: 'typescript', lineNumbers: true }, '<a>code')))
|
|
106
|
+
|
|
107
|
+
expect(isNodeActive(editor.state, 'codeBlock', { language: 'typescript' })).toBe(true)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
@@ -1,25 +1,34 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Attrs,
|
|
3
|
-
NodeType,
|
|
4
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { Attrs, NodeType, ProseMirrorNode } from '@prosekit/pm/model'
|
|
5
2
|
import type { EditorState } from '@prosekit/pm/state'
|
|
6
3
|
|
|
7
|
-
import { attrsMatch } from './attrs-match'
|
|
8
|
-
import { getNodeType } from './get-node-type'
|
|
4
|
+
import { attrsMatch } from './attrs-match.ts'
|
|
5
|
+
import { getNodeType } from './get-node-type.ts'
|
|
6
|
+
import { isNodeSelection } from './type-assertion.ts'
|
|
9
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
10
11
|
export function isNodeActive(
|
|
11
12
|
state: EditorState,
|
|
12
13
|
type: string | NodeType,
|
|
13
14
|
attrs?: Attrs | null,
|
|
14
15
|
): boolean {
|
|
15
|
-
const
|
|
16
|
-
const
|
|
16
|
+
const { selection, schema } = state
|
|
17
|
+
const $pos = selection.$from
|
|
18
|
+
const nodeType = getNodeType(schema, type)
|
|
19
|
+
|
|
20
|
+
if (isNodeSelection(selection) && checkNode(selection.node, nodeType, attrs)) {
|
|
21
|
+
return true
|
|
22
|
+
}
|
|
17
23
|
|
|
18
24
|
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
19
|
-
|
|
20
|
-
if (node.type === nodeType && (!attrs || attrsMatch(node, attrs))) {
|
|
25
|
+
if (checkNode($pos.node(depth), nodeType, attrs)) {
|
|
21
26
|
return true
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
return false
|
|
25
30
|
}
|
|
31
|
+
|
|
32
|
+
function checkNode(node: ProseMirrorNode, nodeType: NodeType, attrs?: Attrs | null): boolean {
|
|
33
|
+
return node.type === nodeType && (!attrs || attrsMatch(node, attrs))
|
|
34
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
expect,
|
|
3
|
-
test,
|
|
4
|
-
} from 'vitest'
|
|
1
|
+
import { expect, test } from 'vitest'
|
|
5
2
|
|
|
6
|
-
import { isSubset } from './is-subset'
|
|
3
|
+
import { isSubset } from './is-subset.ts'
|
|
7
4
|
|
|
8
5
|
test('isSubset', () => {
|
|
9
6
|
expect(isSubset({ a: 1, b: 2 }, { a: 1, b: 2, c: 3 })).toBe(true)
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
expect,
|
|
3
|
-
test,
|
|
4
|
-
vi,
|
|
5
|
-
} from 'vitest'
|
|
1
|
+
import { expect, test, vi } from 'vitest'
|
|
6
2
|
|
|
7
|
-
import { maybeRun } from './maybe-run'
|
|
3
|
+
import { maybeRun } from './maybe-run.ts'
|
|
8
4
|
|
|
9
5
|
test('executes function argument', () => {
|
|
10
6
|
const fn = vi.fn((x: number) => x + 1)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { isNotNullish } from '@ocavue/utils'
|
|
2
|
+
|
|
3
|
+
import { removeUndefinedValues } from './remove-undefined-values.ts'
|
|
3
4
|
|
|
4
5
|
export function mergeObjects<T extends object>(
|
|
5
6
|
...objects: Array<Partial<T> | null | undefined>
|
package/src/utils/merge-specs.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MarkSpec,
|
|
3
|
-
NodeSpec,
|
|
4
|
-
} from '@prosekit/pm/model'
|
|
1
|
+
import type { MarkSpec, NodeSpec } from '@prosekit/pm/model'
|
|
5
2
|
|
|
6
|
-
import { mergeObjects } from './merge-objects'
|
|
3
|
+
import { mergeObjects } from './merge-objects.ts'
|
|
7
4
|
|
|
8
5
|
function mergeSpecs(a: NodeSpec, b: NodeSpec): NodeSpec
|
|
9
6
|
function mergeSpecs(a: MarkSpec, b: MarkSpec): MarkSpec
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
expect,
|
|
3
|
-
test,
|
|
4
|
-
} from 'vitest'
|
|
1
|
+
import { expect, test } from 'vitest'
|
|
5
2
|
|
|
6
|
-
import { objectEqual } from './object-equal'
|
|
3
|
+
import { objectEqual } from './object-equal.ts'
|
|
7
4
|
|
|
8
5
|
test('objects with same keys and values are equal', () => {
|
|
9
6
|
expect(objectEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true)
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { DOMOutputSpec } from '@prosekit/pm/model'
|
|
2
|
-
import {
|
|
3
|
-
describe,
|
|
4
|
-
expect,
|
|
5
|
-
it,
|
|
6
|
-
} from 'vitest'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
7
3
|
|
|
8
|
-
import { insertOutputSpecAttrs } from './output-spec'
|
|
4
|
+
import { insertOutputSpecAttrs } from './output-spec.ts'
|
|
9
5
|
|
|
10
6
|
describe('insertOutputSpecAttrs', () => {
|
|
11
7
|
it('should insert attrs into an array without attributes', () => {
|
package/src/utils/output-spec.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import { isElementLike } from '@ocavue/utils'
|
|
2
|
-
import type {
|
|
3
|
-
DOMOutputSpec,
|
|
4
|
-
Mark,
|
|
5
|
-
ParseRule,
|
|
6
|
-
ProseMirrorNode,
|
|
7
|
-
TagParseRule,
|
|
8
|
-
} from '@prosekit/pm/model'
|
|
9
|
-
|
|
10
|
-
import { isNotNullish } from './type-assertion'
|
|
1
|
+
import { isElementLike, isNotNullish } from '@ocavue/utils'
|
|
2
|
+
import type { DOMOutputSpec, Mark, ParseRule, ProseMirrorNode, TagParseRule } from '@prosekit/pm/model'
|
|
11
3
|
|
|
12
4
|
interface AttrOptions {
|
|
13
5
|
attr: string
|