@tiptap/core 2.1.0-rc.11 → 2.1.0-rc.13

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.
Files changed (34) hide show
  1. package/dist/index.cjs +336 -78
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +323 -75
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.umd.js +336 -78
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/packages/core/src/commands/index.d.ts +2 -0
  8. package/dist/packages/core/src/commands/joinItemBackward.d.ts +12 -0
  9. package/dist/packages/core/src/commands/joinItemForward.d.ts +12 -0
  10. package/dist/packages/core/src/helpers/index.d.ts +1 -0
  11. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +1 -1
  12. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +20 -0
  13. package/dist/packages/core/src/utilities/createStyleTag.d.ts +1 -1
  14. package/dist/packages/extension-list-keymap/src/listHelpers/findListItemPos.d.ts +6 -0
  15. package/dist/packages/extension-list-keymap/src/listHelpers/getNextListDepth.d.ts +2 -0
  16. package/dist/packages/extension-list-keymap/src/listHelpers/handleBackspace.d.ts +2 -0
  17. package/dist/packages/extension-list-keymap/src/listHelpers/handleDelete.d.ts +2 -0
  18. package/dist/packages/extension-list-keymap/src/listHelpers/hasListBefore.d.ts +2 -0
  19. package/dist/packages/extension-list-keymap/src/listHelpers/hasListItemAfter.d.ts +2 -0
  20. package/dist/packages/extension-list-keymap/src/listHelpers/hasListItemBefore.d.ts +2 -0
  21. package/dist/packages/extension-list-keymap/src/listHelpers/index.d.ts +10 -0
  22. package/dist/packages/extension-list-keymap/src/listHelpers/listItemHasSubList.d.ts +3 -0
  23. package/dist/packages/extension-list-keymap/src/listHelpers/nextListIsDeeper.d.ts +2 -0
  24. package/dist/packages/extension-list-keymap/src/listHelpers/nextListIsHigher.d.ts +2 -0
  25. package/package.json +2 -2
  26. package/src/commands/cut.ts +11 -9
  27. package/src/commands/index.ts +2 -0
  28. package/src/commands/joinItemBackward.ts +36 -0
  29. package/src/commands/joinItemForward.ts +38 -0
  30. package/src/extensions/keymap.ts +2 -0
  31. package/src/helpers/index.ts +1 -0
  32. package/src/helpers/isAtEndOfNode.ts +20 -2
  33. package/src/inputRules/nodeInputRule.ts +49 -3
  34. package/src/utilities/createStyleTag.ts +3 -3
@@ -17,6 +17,8 @@ export * from './forEach.js';
17
17
  export * from './insertContent.js';
18
18
  export * from './insertContentAt.js';
19
19
  export * from './join.js';
20
+ export * from './joinItemBackward.js';
21
+ export * from './joinItemForward.js';
20
22
  export * from './keyboardShortcut.js';
21
23
  export * from './lift.js';
22
24
  export * from './liftEmptyBlock.js';
@@ -0,0 +1,12 @@
1
+ import { RawCommands } from '../types.js';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ joinItemBackward: {
5
+ /**
6
+ * Join two nodes Forwards.
7
+ */
8
+ joinItemBackward: () => ReturnType;
9
+ };
10
+ }
11
+ }
12
+ export declare const joinItemBackward: RawCommands['joinItemBackward'];
@@ -0,0 +1,12 @@
1
+ import { RawCommands } from '../types.js';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ joinItemForward: {
5
+ /**
6
+ * Join two nodes Forwards.
7
+ */
8
+ joinItemForward: () => ReturnType;
9
+ };
10
+ }
11
+ }
12
+ export declare const joinItemForward: RawCommands['joinItemForward'];
@@ -1,3 +1,4 @@
1
+ export * from '../../../extension-list-keymap/src/listHelpers/index.js';
1
2
  export * from './combineTransactionSteps.js';
2
3
  export * from './createChainableState.js';
3
4
  export * from './createDocument.js';
@@ -1,2 +1,2 @@
1
1
  import { EditorState } from '@tiptap/pm/state';
2
- export declare const istAtEndOfNode: (state: EditorState) => boolean;
2
+ export declare const isAtEndOfNode: (state: EditorState, nodeType?: string) => boolean;
@@ -6,7 +6,27 @@ import { ExtendedRegExpMatchArray } from '../types.js';
6
6
  * matched text is typed into it.
7
7
  */
8
8
  export declare function nodeInputRule(config: {
9
+ /**
10
+ * The regex to match.
11
+ */
9
12
  find: InputRuleFinder;
13
+ /**
14
+ * The node type to add.
15
+ */
10
16
  type: NodeType;
17
+ /**
18
+ * Should the input rule replace the node or append to it
19
+ * If true, the node will be replaced
20
+ */
21
+ blockReplace?: boolean;
22
+ /**
23
+ * Insert empty paragraph after inserting the node
24
+ * Only works if blockReplace is true
25
+ */
26
+ addExtraNewline?: boolean;
27
+ /**
28
+ * A function that returns the attributes for the node
29
+ * can also be an object of attributes
30
+ */
11
31
  getAttributes?: Record<string, any> | ((match: ExtendedRegExpMatchArray) => Record<string, any>) | false | null;
12
32
  }): InputRule;
@@ -1 +1 @@
1
- export declare function createStyleTag(style: string, nonce?: string): HTMLStyleElement;
1
+ export declare function createStyleTag(style: string, nonce?: string, suffix?: string): HTMLStyleElement;
@@ -0,0 +1,6 @@
1
+ import { NodeType } from '@tiptap/pm/model';
2
+ import { EditorState } from '@tiptap/pm/state';
3
+ export declare const findListItemPos: (typeOrName: string | NodeType, state: EditorState) => {
4
+ $pos: import("prosemirror-model").ResolvedPos;
5
+ depth: number;
6
+ } | null;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const getNextListDepth: (typeOrName: string, state: EditorState) => number | false;
@@ -0,0 +1,2 @@
1
+ import { Editor } from '../../../core/src/Editor.js';
2
+ export declare const handleBackspace: (editor: Editor, name: string, parentListTypes: string[]) => boolean;
@@ -0,0 +1,2 @@
1
+ import { Editor } from '../../../core/src/Editor.js';
2
+ export declare const handleDelete: (editor: Editor, name: string) => boolean;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const hasListBefore: (editorState: EditorState, name: string, parentListTypes: string[]) => boolean;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const hasListItemAfter: (typeOrName: string, state: EditorState) => boolean;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const hasListItemBefore: (typeOrName: string, state: EditorState) => boolean;
@@ -0,0 +1,10 @@
1
+ export * from './findListItemPos.js';
2
+ export * from './getNextListDepth.js';
3
+ export * from './handleBackspace.js';
4
+ export * from './handleDelete.js';
5
+ export * from './hasListBefore.js';
6
+ export * from './hasListItemAfter.js';
7
+ export * from './hasListItemBefore.js';
8
+ export * from './listItemHasSubList.js';
9
+ export * from './nextListIsDeeper.js';
10
+ export * from './nextListIsHigher.js';
@@ -0,0 +1,3 @@
1
+ import { Node } from '@tiptap/pm/model';
2
+ import { EditorState } from '@tiptap/pm/state';
3
+ export declare const listItemHasSubList: (typeOrName: string, state: EditorState, node?: Node) => boolean;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const nextListIsDeeper: (typeOrName: string, state: EditorState) => boolean;
@@ -0,0 +1,2 @@
1
+ import { EditorState } from '@tiptap/pm/state';
2
+ export declare const nextListIsHigher: (typeOrName: string, state: EditorState) => boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/core",
3
3
  "description": "headless rich text editor",
4
- "version": "2.1.0-rc.11",
4
+ "version": "2.1.0-rc.13",
5
5
  "homepage": "https://tiptap.dev",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -32,7 +32,7 @@
32
32
  "dist"
33
33
  ],
34
34
  "devDependencies": {
35
- "@tiptap/pm": "^2.1.0-rc.11"
35
+ "@tiptap/pm": "^2.1.0-rc.13"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@tiptap/pm": "^2.0.0"
@@ -1,3 +1,5 @@
1
+ import { TextSelection } from '@tiptap/pm/state'
2
+
1
3
  import { RawCommands } from '../types.js'
2
4
 
3
5
  declare module '@tiptap/core' {
@@ -11,17 +13,17 @@ declare module '@tiptap/core' {
11
13
  }
12
14
  }
13
15
 
14
- export const cut: RawCommands['cut'] = (originRange, targetPos) => ({ editor }) => {
16
+ export const cut: RawCommands['cut'] = (originRange, targetPos) => ({ editor, tr }) => {
15
17
  const { state } = editor
16
18
 
17
19
  const contentSlice = state.doc.slice(originRange.from, originRange.to)
18
20
 
19
- return editor
20
- .chain()
21
- .deleteRange(originRange)
22
- .command(({ commands, tr }) => {
23
- return commands.insertContentAt(tr.mapping.map(targetPos), contentSlice.content.toJSON())
24
- })
25
- .focus()
26
- .run()
21
+ tr.deleteRange(originRange.from, originRange.to)
22
+ const newPos = tr.mapping.map(targetPos)
23
+
24
+ tr.insert(newPos, contentSlice.content)
25
+
26
+ tr.setSelection(new TextSelection(tr.doc.resolve(newPos - 1)))
27
+
28
+ return true
27
29
  }
@@ -17,6 +17,8 @@ export * from './forEach.js'
17
17
  export * from './insertContent.js'
18
18
  export * from './insertContentAt.js'
19
19
  export * from './join.js'
20
+ export * from './joinItemBackward.js'
21
+ export * from './joinItemForward.js'
20
22
  export * from './keyboardShortcut.js'
21
23
  export * from './lift.js'
22
24
  export * from './liftEmptyBlock.js'
@@ -0,0 +1,36 @@
1
+ import { joinPoint } from '@tiptap/pm/transform'
2
+
3
+ import { RawCommands } from '../types.js'
4
+
5
+ declare module '@tiptap/core' {
6
+ interface Commands<ReturnType> {
7
+ joinItemBackward: {
8
+ /**
9
+ * Join two nodes Forwards.
10
+ */
11
+ joinItemBackward: () => ReturnType
12
+ }
13
+ }
14
+ }
15
+
16
+ export const joinItemBackward: RawCommands['joinItemBackward'] = () => ({
17
+ tr, state, dispatch,
18
+ }) => {
19
+ try {
20
+ const point = joinPoint(state.doc, state.selection.$from.pos, -1)
21
+
22
+ if (point === null || point === undefined) {
23
+ return false
24
+ }
25
+
26
+ tr.join(point, 2)
27
+
28
+ if (dispatch) {
29
+ dispatch(tr)
30
+ }
31
+
32
+ return true
33
+ } catch {
34
+ return false
35
+ }
36
+ }
@@ -0,0 +1,38 @@
1
+ import { joinPoint } from '@tiptap/pm/transform'
2
+
3
+ import { RawCommands } from '../types.js'
4
+
5
+ declare module '@tiptap/core' {
6
+ interface Commands<ReturnType> {
7
+ joinItemForward: {
8
+ /**
9
+ * Join two nodes Forwards.
10
+ */
11
+ joinItemForward: () => ReturnType
12
+ }
13
+ }
14
+ }
15
+
16
+ export const joinItemForward: RawCommands['joinItemForward'] = () => ({
17
+ state,
18
+ dispatch,
19
+ tr,
20
+ }) => {
21
+ try {
22
+ const point = joinPoint(state.doc, state.selection.$from.pos, +1)
23
+
24
+ if (point === null || point === undefined) {
25
+ return false
26
+ }
27
+
28
+ tr.join(point, 2)
29
+
30
+ if (dispatch) {
31
+ dispatch(tr)
32
+ }
33
+
34
+ return true
35
+ } catch (e) {
36
+ return false
37
+ }
38
+ }
@@ -12,6 +12,7 @@ export const Keymap = Extension.create({
12
12
  addKeyboardShortcuts() {
13
13
  const handleBackspace = () => this.editor.commands.first(({ commands }) => [
14
14
  () => commands.undoInputRule(),
15
+
15
16
  // maybe convert first text block node to default node
16
17
  () => commands.command(({ tr }) => {
17
18
  const { selection, doc } = tr
@@ -32,6 +33,7 @@ export const Keymap = Extension.create({
32
33
 
33
34
  return commands.clearNodes()
34
35
  }),
36
+
35
37
  () => commands.deleteSelection(),
36
38
  () => commands.joinBackward(),
37
39
  () => commands.selectNodeBackward(),
@@ -1,3 +1,4 @@
1
+ export * from '../../../extension-list-keymap/src/listHelpers/index.js'
1
2
  export * from './combineTransactionSteps.js'
2
3
  export * from './createChainableState.js'
3
4
  export * from './createDocument.js'
@@ -1,7 +1,25 @@
1
1
  import { EditorState } from '@tiptap/pm/state'
2
2
 
3
- export const istAtEndOfNode = (state: EditorState) => {
4
- const { $from, $to } = state.selection
3
+ import { findParentNode } from './findParentNode.js'
4
+
5
+ export const isAtEndOfNode = (state: EditorState, nodeType?: string) => {
6
+ const { $from, $to, $anchor } = state.selection
7
+
8
+ if (nodeType) {
9
+ const parentNode = findParentNode(node => node.type.name === nodeType)(state.selection)
10
+
11
+ if (!parentNode) {
12
+ return false
13
+ }
14
+
15
+ const $parentPos = state.doc.resolve(parentNode.pos + 1)
16
+
17
+ if ($anchor.pos + 1 === $parentPos.end()) {
18
+ return true
19
+ }
20
+
21
+ return false
22
+ }
5
23
 
6
24
  if ($to.parentOffset < $to.parent.nodeSize - 2 || $from.pos !== $to.pos) {
7
25
  return false
@@ -1,4 +1,5 @@
1
1
  import { NodeType } from '@tiptap/pm/model'
2
+ import { TextSelection } from '@tiptap/pm/state'
2
3
 
3
4
  import { InputRule, InputRuleFinder } from '../InputRule.js'
4
5
  import { ExtendedRegExpMatchArray } from '../types.js'
@@ -9,8 +10,32 @@ import { callOrReturn } from '../utilities/callOrReturn.js'
9
10
  * matched text is typed into it.
10
11
  */
11
12
  export function nodeInputRule(config: {
13
+ /**
14
+ * The regex to match.
15
+ */
12
16
  find: InputRuleFinder
17
+
18
+ /**
19
+ * The node type to add.
20
+ */
13
21
  type: NodeType
22
+
23
+ /**
24
+ * Should the input rule replace the node or append to it
25
+ * If true, the node will be replaced
26
+ */
27
+ blockReplace?: boolean
28
+
29
+ /**
30
+ * Insert empty paragraph after inserting the node
31
+ * Only works if blockReplace is true
32
+ */
33
+ addExtraNewline?: boolean
34
+
35
+ /**
36
+ * A function that returns the attributes for the node
37
+ * can also be an object of attributes
38
+ */
14
39
  getAttributes?:
15
40
  | Record<string, any>
16
41
  | ((match: ExtendedRegExpMatchArray) => Record<string, any>)
@@ -22,9 +47,11 @@ export function nodeInputRule(config: {
22
47
  handler: ({ state, range, match }) => {
23
48
  const attributes = callOrReturn(config.getAttributes, undefined, match) || {}
24
49
  const { tr } = state
25
- const start = range.from
50
+ const start = config.blockReplace ? range.from - 1 : range.from
26
51
  let end = range.to
27
52
 
53
+ const newNode = config.type.create(attributes)
54
+
28
55
  if (match[1]) {
29
56
  const offset = match[0].lastIndexOf(match[1])
30
57
  let matchStart = start + offset
@@ -41,9 +68,28 @@ export function nodeInputRule(config: {
41
68
  tr.insertText(lastChar, start + match[0].length - 1)
42
69
 
43
70
  // insert node from input rule
44
- tr.replaceWith(matchStart, end, config.type.create(attributes))
71
+ tr.replaceWith(matchStart, end, newNode)
45
72
  } else if (match[0]) {
46
- tr.replaceWith(start, end, config.type.create(attributes))
73
+ tr.replaceWith(start, end, newNode)
74
+ }
75
+
76
+ if (config.blockReplace && config.addExtraNewline) {
77
+ const { $to } = tr.selection
78
+ const posAfter = $to.end()
79
+
80
+ if ($to.nodeAfter) {
81
+ tr.setSelection(TextSelection.create(tr.doc, $to.pos))
82
+ } else {
83
+ // add node after horizontal rule if it’s the end of the document
84
+ const node = $to.parent.type.contentMatch.defaultType?.create()
85
+
86
+ if (node) {
87
+ tr.insert(posAfter, node)
88
+ tr.setSelection(TextSelection.create(tr.doc, posAfter))
89
+ }
90
+ }
91
+
92
+ tr.scrollIntoView()
47
93
  }
48
94
  },
49
95
  })
@@ -1,5 +1,5 @@
1
- export function createStyleTag(style: string, nonce?: string): HTMLStyleElement {
2
- const tiptapStyleTag = (<HTMLStyleElement>document.querySelector('style[data-tiptap-style]'))
1
+ export function createStyleTag(style: string, nonce?: string, suffix?: string): HTMLStyleElement {
2
+ const tiptapStyleTag = (<HTMLStyleElement>document.querySelector(`style[data-tiptap-style${suffix ? `-${suffix}` : ''}]`))
3
3
 
4
4
  if (tiptapStyleTag !== null) {
5
5
  return tiptapStyleTag
@@ -11,7 +11,7 @@ export function createStyleTag(style: string, nonce?: string): HTMLStyleElement
11
11
  styleNode.setAttribute('nonce', nonce)
12
12
  }
13
13
 
14
- styleNode.setAttribute('data-tiptap-style', '')
14
+ styleNode.setAttribute(`data-tiptap-style${suffix ? `-${suffix}` : ''}`, '')
15
15
  styleNode.innerHTML = style
16
16
  document.getElementsByTagName('head')[0].appendChild(styleNode)
17
17