Merge branch 'main' of github.com:ueberdosis/tiptap-next

# Bitte geben Sie eine Commit-Beschreibung ein, um zu erklären, warum dieser
# Merge erforderlich ist, insbesondere wenn es einen aktualisierten
# Upstream-Branch mit einem Thema-Branch zusammenführt.
#
# Zeilen, die mit '#' beginnen, werden ignoriert,
# und eine leere Beschreibung bricht den Commit ab.
This commit is contained in:
Hans Pagel 2021-02-10 15:14:03 +01:00
commit a0ce975a51
7 changed files with 141 additions and 4 deletions

View File

@ -32,7 +32,7 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Load cached dependencies - name: Load cached dependencies
uses: actions/cache@v2 uses: actions/cache@v2.1.4
id: cache id: cache
with: with:
path: | path: |
@ -144,7 +144,7 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Load cached dependencies - name: Load cached dependencies
uses: actions/cache@v2 uses: actions/cache@v2.1.4
id: cache id: cache
with: with:
path: | path: |

View File

@ -33,8 +33,8 @@ To check out some live examples, visit [next.tiptap.dev](https://next.tiptap.dev
Please see [CONTRIBUTING](CONTRIBUTING.md) for details. Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
## Maintainers ## Maintainers
- [Philipp Kühn](https://github.com/philippkuehn) (development) - [Philipp Kühn](https://github.com/philippkuehn) (developer)
- [Hans Pagel](https://github.com/hanspagel) (documentation) - [Hans Pagel](https://github.com/hanspagel) (maintainer)
## Premium Sponsors ## Premium Sponsors
- [überdosis](https://ueberdosis.io/) - [überdosis](https://ueberdosis.io/)

View File

@ -177,7 +177,9 @@ Have a look at all of the core commands listed below. They should give you a goo
| .blur() | Removes focus from the editor. | | .blur() | Removes focus from the editor. |
| .deleteRange() | Delete a given range. | | .deleteRange() | Delete a given range. |
| .deleteSelection() | Delete the selection, if there is one. | | .deleteSelection() | Delete the selection, if there is one. |
| .enter() | Trigger enter. |
| .focus() | Focus the editor at the given position. | | .focus() | Focus the editor at the given position. |
| .keyboardShortcut() | Trigger a keyboard shortcut. |
| .scrollIntoView() | Scroll the selection into view. | | .scrollIntoView() | Scroll the selection into view. |
| .selectAll() | Select the whole document. | | .selectAll() | Select the whole document. |
| .selectNodeBackward() | Select a node backward. | | .selectNodeBackward() | Select a node backward. |

View File

@ -307,12 +307,40 @@ export class Editor extends EventEmitter {
return this.createDocument('') return this.createDocument('')
} }
public isCapturingTransaction = false
private capturedTransaction: Transaction | null = null
public captureTransaction(fn: Function) {
this.isCapturingTransaction = true
fn()
this.isCapturingTransaction = false
const tr = this.capturedTransaction
this.capturedTransaction = null
return tr
}
/** /**
* The callback over which to send transactions (state updates) produced by the view. * The callback over which to send transactions (state updates) produced by the view.
* *
* @param transaction An editor state transaction * @param transaction An editor state transaction
*/ */
private dispatchTransaction(transaction: Transaction): void { private dispatchTransaction(transaction: Transaction): void {
if (this.isCapturingTransaction) {
if (!this.capturedTransaction) {
this.capturedTransaction = transaction
return
}
transaction.steps.forEach(step => this.capturedTransaction?.step(step))
return
}
const state = this.state.apply(transaction) const state = this.state.apply(transaction)
const selectionHasChanged = !this.state.selection.eq(state.selection) const selectionHasChanged = !this.state.selection.eq(state.selection)

View File

@ -0,0 +1,8 @@
import { Command } from '../types'
/**
* Trigger enter.
*/
export const enter = (): Command => ({ commands }) => {
return commands.keyboardShortcut('Enter')
}

View File

@ -0,0 +1,95 @@
import { Command } from '../types'
const mac = typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false
function normalizeKeyName(name: string) {
const parts = name.split(/-(?!$)/)
let result = parts[parts.length - 1]
if (result === 'Space') {
result = ' '
}
let alt
let ctrl
let shift
let meta
for (let i = 0; i < parts.length - 1; i += 1) {
const mod = parts[i]
if (/^(cmd|meta|m)$/i.test(mod)) {
meta = true
} else if (/^a(lt)?$/i.test(mod)) {
alt = true
} else if (/^(c|ctrl|control)$/i.test(mod)) {
ctrl = true
} else if (/^s(hift)?$/i.test(mod)) {
shift = true
} else if (/^mod$/i.test(mod)) {
if (mac) {
meta = true
} else {
ctrl = true
}
} else {
throw new Error(`Unrecognized modifier name: ${mod}`)
}
}
if (alt) {
result = `Alt-${result}`
}
if (ctrl) {
result = `Ctrl-${result}`
}
if (meta) {
result = `Meta-${result}`
}
if (shift) {
result = `Shift-${result}`
}
return result
}
/**
* Trigger a keyboard shortcut.
*/
export const keyboardShortcut = (name: string): Command => ({
editor,
view,
tr,
dispatch,
}) => {
const keys = normalizeKeyName(name).split(/-(?!$)/)
const key = keys.find(item => !['Alt', 'Ctrl', 'Meta', 'Shift'].includes(item))
const event = new KeyboardEvent('keydown', {
key: key === 'Space'
? ' '
: key,
altKey: keys.includes('Alt'),
ctrlKey: keys.includes('Ctrl'),
metaKey: keys.includes('Meta'),
shiftKey: keys.includes('Shift'),
bubbles: true,
cancelable: true,
})
const capturedTransaction = editor.captureTransaction(() => {
view.someProp('handleKeyDown', f => f(view, event))
})
capturedTransaction?.steps.forEach(step => {
const newStep = step.map(tr.mapping)
if (newStep && dispatch) {
tr.maybeStep(newStep)
}
})
return true
}

View File

@ -6,6 +6,7 @@ import * as command from '../commands/command'
import * as createParagraphNear from '../commands/createParagraphNear' import * as createParagraphNear from '../commands/createParagraphNear'
import * as deleteRange from '../commands/deleteRange' import * as deleteRange from '../commands/deleteRange'
import * as deleteSelection from '../commands/deleteSelection' import * as deleteSelection from '../commands/deleteSelection'
import * as enter from '../commands/enter'
import * as exitCode from '../commands/exitCode' import * as exitCode from '../commands/exitCode'
import * as extendMarkRange from '../commands/extendMarkRange' import * as extendMarkRange from '../commands/extendMarkRange'
import * as first from '../commands/first' import * as first from '../commands/first'
@ -14,6 +15,7 @@ import * as insertHTML from '../commands/insertHTML'
import * as insertText from '../commands/insertText' import * as insertText from '../commands/insertText'
import * as joinBackward from '../commands/joinBackward' import * as joinBackward from '../commands/joinBackward'
import * as joinForward from '../commands/joinForward' import * as joinForward from '../commands/joinForward'
import * as keyboardShortcut from '../commands/keyboardShortcut'
import * as lift from '../commands/lift' import * as lift from '../commands/lift'
import * as liftEmptyBlock from '../commands/liftEmptyBlock' import * as liftEmptyBlock from '../commands/liftEmptyBlock'
import * as liftListItem from '../commands/liftListItem' import * as liftListItem from '../commands/liftListItem'
@ -55,6 +57,7 @@ export const Commands = Extension.create({
...createParagraphNear, ...createParagraphNear,
...deleteRange, ...deleteRange,
...deleteSelection, ...deleteSelection,
...enter,
...exitCode, ...exitCode,
...extendMarkRange, ...extendMarkRange,
...first, ...first,
@ -63,6 +66,7 @@ export const Commands = Extension.create({
...insertText, ...insertText,
...joinBackward, ...joinBackward,
...joinForward, ...joinForward,
...keyboardShortcut,
...lift, ...lift,
...liftEmptyBlock, ...liftEmptyBlock,
...liftListItem, ...liftListItem,