@tessera-editor/core 0.1.0 → 0.2.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/index.d.ts +137 -173
- package/dist/index.js +307 -405
- package/dist/index.js.map +1 -1
- package/dist/tessera.css +132 -120
- package/package.json +1 -1
- package/src/__tests__/host-config.test.ts +115 -0
- package/src/__tests__/linkedit.test.ts +98 -0
- package/src/__tests__/table-guard.test.ts +155 -0
- package/src/__tests__/v11.test.ts +1 -50
- package/src/extensions/context-menu.ts +7 -2
- package/src/extensions/shortcuts.ts +8 -6
- package/src/extensions/slash.ts +43 -25
- package/src/i18n.ts +26 -33
- package/src/index.ts +10 -13
- package/src/linkedit.ts +66 -0
- package/src/markdown.ts +0 -1
- package/src/nodes/table.ts +130 -0
- package/src/preset.ts +65 -26
- package/src/services.ts +1 -22
- package/src/styles/tessera.css +132 -120
- package/src/diff.ts +0 -150
- package/src/extensions/history.ts +0 -133
- package/src/marks/placeholder.ts +0 -63
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core'
|
|
2
|
-
import type { JSONContent } from '@tiptap/core'
|
|
3
|
-
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
4
|
-
import { getStorageService, type DocSnapshot } from '../services'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Version history capture (v1.1): snapshots the canonical JSON into the
|
|
8
|
-
* injected StorageService. Auto-capture fires after `idleMs` of inactivity
|
|
9
|
-
* (Slite: 5 minutes); manual capture is always available as a command.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export interface HistorySnapshotOptions {
|
|
13
|
-
/** idle window before auto-capture (default 5 minutes) */
|
|
14
|
-
idleMs?: number
|
|
15
|
-
/** minimum ms between two auto-captures (default 60s) */
|
|
16
|
-
minIntervalMs?: number
|
|
17
|
-
/** snapshot label source */
|
|
18
|
-
label?: () => string | undefined
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
declare module '@tiptap/core' {
|
|
22
|
-
interface Commands<ReturnType> {
|
|
23
|
-
tesseraHistory: {
|
|
24
|
-
captureSnapshot: (label?: string) => ReturnType
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
interface EditorEvents {
|
|
28
|
-
'tessera:snapshotSaved': { snapshot: DocSnapshot }
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const historyKey = new PluginKey('tesseraHistory')
|
|
33
|
-
|
|
34
|
-
export const TesseraHistory = Extension.create<HistorySnapshotOptions>({
|
|
35
|
-
name: 'tesseraHistory',
|
|
36
|
-
|
|
37
|
-
addOptions() {
|
|
38
|
-
return {
|
|
39
|
-
idleMs: 5 * 60 * 1000,
|
|
40
|
-
minIntervalMs: 60 * 1000,
|
|
41
|
-
label: undefined,
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
addCommands() {
|
|
46
|
-
return {
|
|
47
|
-
captureSnapshot:
|
|
48
|
-
(label?: string) =>
|
|
49
|
-
({ editor, state }) => {
|
|
50
|
-
const storage = getStorageService(editor)
|
|
51
|
-
if (!storage) {
|
|
52
|
-
return false
|
|
53
|
-
}
|
|
54
|
-
const doc = editor.getJSON() as JSONContent
|
|
55
|
-
const snapshot: DocSnapshot = {
|
|
56
|
-
id: `snap-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
57
|
-
ts: Date.now(),
|
|
58
|
-
doc,
|
|
59
|
-
label: label ?? this.options.label?.(),
|
|
60
|
-
}
|
|
61
|
-
void storage.saveSnapshot(snapshot).then(() => {
|
|
62
|
-
editor.emit('tessera:snapshotSaved', { snapshot })
|
|
63
|
-
})
|
|
64
|
-
const tr = state.tr.setMeta(historyKey, { type: 'captured', ts: snapshot.ts })
|
|
65
|
-
editor.view.dispatch(tr)
|
|
66
|
-
return true
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
addProseMirrorPlugins() {
|
|
72
|
-
const editor = this.editor
|
|
73
|
-
const options = this.options
|
|
74
|
-
return [
|
|
75
|
-
new Plugin({
|
|
76
|
-
key: historyKey,
|
|
77
|
-
state: {
|
|
78
|
-
init: () => ({ lastChange: 0, lastCapture: 0, timer: null as ReturnType<typeof setTimeout> | null }),
|
|
79
|
-
apply: (tr, prev) => {
|
|
80
|
-
const meta = tr.getMeta(historyKey) as { type: string; ts?: number } | undefined
|
|
81
|
-
if (meta?.type === 'captured') {
|
|
82
|
-
return { ...prev, lastCapture: meta.ts ?? Date.now() }
|
|
83
|
-
}
|
|
84
|
-
if (!tr.docChanged) {
|
|
85
|
-
return prev
|
|
86
|
-
}
|
|
87
|
-
return { ...prev, lastChange: Date.now() }
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
view() {
|
|
91
|
-
return {
|
|
92
|
-
update: (_view, prevState) => {
|
|
93
|
-
const before = historyKey.getState(prevState)
|
|
94
|
-
const after = historyKey.getState(editor.state)
|
|
95
|
-
if (!before || !after || after.lastChange === before.lastChange) {
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
const storage = getStorageService(editor)
|
|
99
|
-
if (!storage) {
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
const s = historyKey.getState(editor.state)
|
|
103
|
-
if (s?.timer) {
|
|
104
|
-
clearTimeout(s.timer)
|
|
105
|
-
}
|
|
106
|
-
const timer = setTimeout(() => {
|
|
107
|
-
const now = Date.now()
|
|
108
|
-
const cur = historyKey.getState(editor.state)
|
|
109
|
-
if (!cur || now - cur.lastChange < options.idleMs! - 50) {
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
if (now - cur.lastCapture < options.minIntervalMs!) {
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
editor.commands.captureSnapshot()
|
|
116
|
-
}, options.idleMs!)
|
|
117
|
-
const st = historyKey.getState(editor.state)
|
|
118
|
-
if (st) {
|
|
119
|
-
st.timer = timer
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
destroy() {
|
|
123
|
-
const s = historyKey.getState(editor.state)
|
|
124
|
-
if (s?.timer) {
|
|
125
|
-
clearTimeout(s.timer)
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
}),
|
|
131
|
-
]
|
|
132
|
-
},
|
|
133
|
-
})
|
package/src/marks/placeholder.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Mark, mergeAttributes, Extension } from '@tiptap/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Placeholder mark (v1.1, Slite's 占位符): dashed-underline token marking a
|
|
5
|
-
* spot to fill in later — text / person / date / doc-link. ⌘⌥P toggles it on
|
|
6
|
-
* a selection; slash items insert ready-made tokens.
|
|
7
|
-
*/
|
|
8
|
-
export type PlaceholderKind = 'text' | 'person' | 'date' | 'doc'
|
|
9
|
-
|
|
10
|
-
export const PlaceholderMark = Mark.create({
|
|
11
|
-
name: 'tesseraPlaceholder',
|
|
12
|
-
|
|
13
|
-
addAttributes() {
|
|
14
|
-
return {
|
|
15
|
-
kind: {
|
|
16
|
-
default: 'text' as PlaceholderKind,
|
|
17
|
-
parseHTML: element => (element.getAttribute('data-kind') as PlaceholderKind) ?? 'text',
|
|
18
|
-
renderHTML: attributes => ({ 'data-kind': String(attributes.kind) }),
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
parseHTML() {
|
|
24
|
-
return [{ tag: 'span[data-type="tessera-placeholder"]' }]
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
renderHTML({ HTMLAttributes }) {
|
|
28
|
-
return ['span', mergeAttributes({ 'data-type': 'tessera-placeholder' }, HTMLAttributes)]
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
declare module '@tiptap/core' {
|
|
33
|
-
interface Commands<ReturnType> {
|
|
34
|
-
tesseraPlaceholder: {
|
|
35
|
-
togglePlaceholderMark: (kind?: PlaceholderKind) => ReturnType
|
|
36
|
-
/** Insert a placeholder token at the caret (selection replaced). */
|
|
37
|
-
insertPlaceholderToken: (kind: PlaceholderKind, label: string) => ReturnType
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const PlaceholderCommands = Extension.create({
|
|
43
|
-
name: 'tesseraPlaceholderCommands',
|
|
44
|
-
|
|
45
|
-
addCommands() {
|
|
46
|
-
return {
|
|
47
|
-
togglePlaceholderMark:
|
|
48
|
-
(kind: PlaceholderKind = 'text') =>
|
|
49
|
-
({ commands }) =>
|
|
50
|
-
commands.toggleMark('tesseraPlaceholder', { kind }),
|
|
51
|
-
insertPlaceholderToken:
|
|
52
|
-
(kind: PlaceholderKind, label: string) =>
|
|
53
|
-
({ chain }) =>
|
|
54
|
-
chain()
|
|
55
|
-
.insertContent({
|
|
56
|
-
type: 'text',
|
|
57
|
-
text: label,
|
|
58
|
-
marks: [{ type: 'tesseraPlaceholder', attrs: { kind } }],
|
|
59
|
-
})
|
|
60
|
-
.run(),
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
})
|