@seorii/tiptap 0.3.0-next.8 → 0.3.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.
Files changed (45) hide show
  1. package/dist/i18n/index.d.ts +106 -6
  2. package/dist/i18n/index.js +56 -11
  3. package/dist/plugin/command/emoji.d.ts +3 -17
  4. package/dist/plugin/command/emoji.js +51 -24
  5. package/dist/plugin/command/stores.svelte.d.ts +52 -0
  6. package/dist/plugin/command/stores.svelte.js +69 -0
  7. package/dist/plugin/command/suggest.d.ts +6 -19
  8. package/dist/plugin/command/suggest.js +133 -51
  9. package/dist/plugin/embed.d.ts +2 -2
  10. package/dist/plugin/embed.js +5 -1
  11. package/dist/plugin/image/dragdrop.d.ts +2 -0
  12. package/dist/plugin/image/dragdrop.js +66 -2
  13. package/dist/plugin/image/index.js +3 -2
  14. package/dist/plugin/indent.js +0 -1
  15. package/dist/plugin/orderedlist/index.d.ts +1 -1
  16. package/dist/plugin/orderedlist/index.js +1 -1
  17. package/dist/plugin/orderedlist/{korean.scss → korean.css} +2 -2
  18. package/dist/plugin/table/index.d.ts +1 -1
  19. package/dist/plugin/table/index.js +19 -11
  20. package/dist/plugin/table/style/{cell.scss → cell.css} +6 -5
  21. package/dist/plugin/table/style/{grip.scss → grip.css} +14 -19
  22. package/dist/plugin/table/style/resize.css +28 -0
  23. package/dist/plugin/table/style/{table.scss → table.css} +15 -17
  24. package/dist/plugin/table/style.css +4 -0
  25. package/dist/plugin/table/tableCell/index.js +2 -4
  26. package/dist/plugin/table/tableHeader/index.js +1 -2
  27. package/dist/tiptap/Bubble.svelte +106 -71
  28. package/dist/tiptap/Bubble.svelte.d.ts +8 -6
  29. package/dist/tiptap/Command.svelte +160 -158
  30. package/dist/tiptap/Command.svelte.d.ts +2 -3
  31. package/dist/tiptap/Floating.svelte +51 -24
  32. package/dist/tiptap/Floating.svelte.d.ts +1 -0
  33. package/dist/tiptap/TipTap.svelte +215 -135
  34. package/dist/tiptap/TipTap.svelte.d.ts +7 -3
  35. package/dist/tiptap/ToolbarButton.svelte +30 -10
  36. package/dist/tiptap/ToolbarButton.svelte.d.ts +10 -6
  37. package/dist/tiptap/setMath.d.ts +2 -1
  38. package/dist/tiptap/setMath.js +74 -12
  39. package/dist/tiptap/tiptap.d.ts +9 -1
  40. package/dist/tiptap/tiptap.js +170 -16
  41. package/package.json +63 -57
  42. package/dist/plugin/command/stores.d.ts +0 -13
  43. package/dist/plugin/command/stores.js +0 -7
  44. package/dist/plugin/table/style/resize.scss +0 -26
  45. package/dist/plugin/table/style.scss +0 -4
@@ -1,4 +1,4 @@
1
- import { Editor, mergeAttributes } from '@tiptap/core';
1
+ import { Editor, Extension, mergeAttributes } from '@tiptap/core';
2
2
  import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
3
3
  import { all, createLowlight } from 'lowlight';
4
4
  import Code from '@tiptap/extension-code';
@@ -18,7 +18,7 @@ import Superscript from '@tiptap/extension-superscript';
18
18
  import Subscript from '@tiptap/extension-subscript';
19
19
  import { Indent } from '../plugin/indent';
20
20
  import { Color } from '@tiptap/extension-color';
21
- import TextStyle from '@tiptap/extension-text-style';
21
+ import { TextStyle } from '@tiptap/extension-text-style';
22
22
  import Iframe from '../plugin/iframe';
23
23
  import Embed from '../plugin/embed';
24
24
  // @ts-ignore
@@ -27,6 +27,7 @@ import Youtube from '../plugin/youtube';
27
27
  import Placeholder from '@tiptap/extension-placeholder';
28
28
  import command from '../plugin/command/suggest';
29
29
  import emoji from '../plugin/command/emoji';
30
+ import { countSlashItems, moveSlashSelection, runSlashItemAt, slashState } from '../plugin/command/stores.svelte';
30
31
  import i18n from '../i18n';
31
32
  import js from 'highlight.js/lib/languages/javascript';
32
33
  import ts from 'highlight.js/lib/languages/typescript';
@@ -37,6 +38,18 @@ import kotlin from 'highlight.js/lib/languages/kotlin';
37
38
  import go from 'highlight.js/lib/languages/go';
38
39
  import csharp from 'highlight.js/lib/languages/csharp';
39
40
  import rust from 'highlight.js/lib/languages/rust';
41
+ const codeBlockLanguageOptions = [
42
+ { value: 'auto', label: 'auto' },
43
+ { value: 'cpp', label: 'cpp' },
44
+ { value: 'python', label: 'python' },
45
+ { value: 'java', label: 'java' },
46
+ { value: 'js', label: 'js' },
47
+ { value: 'ts', label: 'ts' },
48
+ { value: 'kotlin', label: 'kotlin' },
49
+ { value: 'go', label: 'go' },
50
+ { value: 'csharp', label: 'csharp' },
51
+ { value: 'rust', label: 'rust' }
52
+ ];
40
53
  const lowlight = () => {
41
54
  const lowlight = createLowlight(all);
42
55
  lowlight.register('js', js);
@@ -50,20 +63,160 @@ const lowlight = () => {
50
63
  lowlight.register('rust', rust);
51
64
  return lowlight;
52
65
  };
53
- const extensions = (placeholder, plugins, crossorigin) => [
54
- CodeBlockLowlight.extend({
55
- addKeyboardShortcuts() {
66
+ const normalizeCodeBlockLanguage = (language) => {
67
+ if (typeof language !== 'string')
68
+ return 'auto';
69
+ const normalized = language.trim();
70
+ return normalized.length ? normalized : 'auto';
71
+ };
72
+ const resolveCodeBlockLanguageLabel = (value, labelMap, fallbackLabel = value) => {
73
+ const label = labelMap[value]?.trim();
74
+ return label?.length ? label : fallbackLabel;
75
+ };
76
+ const slashKeymap = Extension.create({
77
+ name: 'slash-keymap',
78
+ priority: 10000,
79
+ addKeyboardShortcuts() {
80
+ return {
81
+ Enter: () => {
82
+ if (!slashState.visible)
83
+ return false;
84
+ return runSlashItemAt(slashState.selectedIndex);
85
+ },
86
+ Tab: () => {
87
+ if (!slashState.visible || countSlashItems() === 0)
88
+ return false;
89
+ moveSlashSelection(1);
90
+ return true;
91
+ },
92
+ 'Shift-Tab': () => {
93
+ if (!slashState.visible || countSlashItems() === 0)
94
+ return false;
95
+ moveSlashSelection(-1);
96
+ return true;
97
+ },
98
+ ArrowUp: () => {
99
+ if (!slashState.visible || countSlashItems() === 0)
100
+ return false;
101
+ moveSlashSelection(-1);
102
+ return true;
103
+ },
104
+ ArrowDown: () => {
105
+ if (!slashState.visible || countSlashItems() === 0)
106
+ return false;
107
+ moveSlashSelection(1);
108
+ return true;
109
+ }
110
+ };
111
+ }
112
+ });
113
+ const CodeBlockWithLanguageSelect = CodeBlockLowlight.extend({
114
+ addOptions() {
115
+ return {
116
+ ...this.parent?.(),
117
+ languageLabelMap: {}
118
+ };
119
+ },
120
+ addKeyboardShortcuts() {
121
+ return {
122
+ ...this.parent?.(),
123
+ Tab: () => {
124
+ if (this.editor.isActive('codeBlock')) {
125
+ return this.editor.commands.insertContent(' ');
126
+ }
127
+ return false;
128
+ }
129
+ };
130
+ },
131
+ addNodeView() {
132
+ return ({ node, getPos, editor }) => {
133
+ let currentNode = node;
134
+ const languageLabelMap = this.options.languageLabelMap || {};
135
+ const dom = document.createElement('div');
136
+ dom.className = 'tiptap-code-block';
137
+ const toolbar = document.createElement('div');
138
+ toolbar.className = 'tiptap-code-block-toolbar';
139
+ const languageSelect = document.createElement('select');
140
+ languageSelect.className = 'tiptap-code-block-language';
141
+ for (const option of codeBlockLanguageOptions) {
142
+ const element = document.createElement('option');
143
+ element.value = option.value;
144
+ element.textContent = resolveCodeBlockLanguageLabel(option.value, languageLabelMap, option.label);
145
+ languageSelect.append(element);
146
+ }
147
+ toolbar.append(languageSelect);
148
+ const pre = document.createElement('pre');
149
+ const contentDOM = document.createElement('code');
150
+ pre.append(contentDOM);
151
+ dom.append(toolbar, pre);
152
+ const ensureLanguageOption = (value) => {
153
+ if ([...languageSelect.options].some((option) => option.value === value))
154
+ return;
155
+ const element = document.createElement('option');
156
+ element.value = value;
157
+ element.textContent = resolveCodeBlockLanguageLabel(value, languageLabelMap);
158
+ languageSelect.append(element);
159
+ };
160
+ const syncLanguageSelection = () => {
161
+ const language = normalizeCodeBlockLanguage(currentNode.attrs.language);
162
+ ensureLanguageOption(language);
163
+ languageSelect.value = language;
164
+ };
165
+ const handleLanguageChange = () => {
166
+ let pos = null;
167
+ try {
168
+ pos = getPos();
169
+ }
170
+ catch {
171
+ pos = null;
172
+ }
173
+ if (typeof pos !== 'number')
174
+ return;
175
+ const selectedLanguage = languageSelect.value;
176
+ const language = selectedLanguage === 'auto' ? null : selectedLanguage;
177
+ const latestNode = editor.state.doc.nodeAt(pos);
178
+ if (!latestNode || latestNode.type.name !== this.name)
179
+ return;
180
+ editor.commands.command(({ tr, dispatch }) => {
181
+ tr.setNodeMarkup(pos, undefined, {
182
+ ...latestNode.attrs,
183
+ language
184
+ });
185
+ dispatch?.(tr);
186
+ return true;
187
+ });
188
+ };
189
+ languageSelect.addEventListener('change', handleLanguageChange);
190
+ syncLanguageSelection();
56
191
  return {
57
- ...this.parent?.(),
58
- Tab: () => {
59
- if (this.editor.isActive('codeBlock')) {
60
- return this.editor.commands.insertContent(' ');
61
- }
192
+ dom,
193
+ contentDOM,
194
+ update: (updatedNode) => {
195
+ if (updatedNode.type !== currentNode.type)
196
+ return false;
197
+ currentNode = updatedNode;
198
+ syncLanguageSelection();
62
199
  return true;
200
+ },
201
+ stopEvent: (event) => {
202
+ const target = event.target;
203
+ if (!(target instanceof HTMLElement))
204
+ return false;
205
+ return Boolean(target.closest('.tiptap-code-block-toolbar'));
206
+ },
207
+ destroy: () => {
208
+ languageSelect.removeEventListener('change', handleLanguageChange);
63
209
  }
64
210
  };
65
- }
66
- }).configure({ lowlight: lowlight() }),
211
+ };
212
+ }
213
+ });
214
+ const extensions = (placeholder, plugins, crossorigin, codeBlockLanguageLabels) => [
215
+ CodeBlockWithLanguageSelect.configure({
216
+ lowlight: lowlight(),
217
+ languageLabelMap: codeBlockLanguageLabels
218
+ }),
219
+ slashKeymap,
67
220
  Image(crossorigin),
68
221
  Youtube,
69
222
  StarterKit,
@@ -104,14 +257,15 @@ const extensions = (placeholder, plugins, crossorigin) => [
104
257
  Placeholder.configure({ placeholder }),
105
258
  ...plugins
106
259
  ];
107
- export default (element, content, { placeholder = i18n('placeholder'), plugins = [], crossorigin, ...props } = {}) => {
260
+ export default (element, content, { placeholder = i18n('placeholder'), plugins = [], crossorigin, codeBlockLanguageLabels = {}, ...props } = {}) => {
108
261
  const tt = new Editor({
109
262
  element,
110
263
  content,
111
264
  ...props,
112
- extensions: extensions(placeholder, plugins, crossorigin)
265
+ extensions: extensions(placeholder, plugins, crossorigin, codeBlockLanguageLabels)
113
266
  });
114
- tt.registerPlugin(emoji(tt));
115
- tt.registerPlugin(command(tt));
267
+ // Suggestion key handlers must run before default keymap handlers.
268
+ tt.registerPlugin(emoji(tt), (plugin, all) => [plugin, ...all]);
269
+ tt.registerPlugin(command(tt), (plugin, all) => [plugin, ...all]);
116
270
  return tt;
117
271
  };
package/package.json CHANGED
@@ -1,86 +1,88 @@
1
1
  {
2
2
  "name": "@seorii/tiptap",
3
- "version": "0.3.0-next.8",
3
+ "version": "0.3.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "svelte-kit sync && svelte-package",
7
7
  "build-page": "vite build",
8
8
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
9
9
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
10
- "lint": "prettier --plugin-search-dir . --check . && eslint .",
11
- "format": "prettier --plugin-search-dir . --write .",
10
+ "lint": "prettier --check . && eslint .",
11
+ "format": "prettier --write .",
12
12
  "package": "svelte-kit sync && svelte-package && publint",
13
13
  "prepublishOnly": "npm run package",
14
14
  "page": "npm run build-page && node gh-pages.js"
15
15
  },
16
16
  "devDependencies": {
17
- "@sveltejs/adapter-auto": "^4.0.0",
18
- "@sveltejs/adapter-static": "^3.0.8",
19
- "@sveltejs/kit": "^2.16.1",
20
- "@sveltejs/package": "^2.3.7",
21
- "@sveltejs/vite-plugin-svelte": "4.0.0",
22
- "@types/sanitize-html": "^2.13.0",
23
- "@typescript-eslint/eslint-plugin": "^8.21.0",
24
- "@typescript-eslint/parser": "^8.21.0",
25
- "eslint": "^9.19.0",
26
- "eslint-config-prettier": "^10.0.1",
27
- "eslint-plugin-svelte3": "^4.0.0",
17
+ "@eslint/js": "^9.39.3",
18
+ "@sveltejs/adapter-auto": "^7.0.1",
19
+ "@sveltejs/adapter-static": "^3.0.10",
20
+ "@sveltejs/kit": "^2.53.0",
21
+ "@sveltejs/package": "^2.5.7",
22
+ "@sveltejs/vite-plugin-svelte": "6.2.4",
23
+ "@types/sanitize-html": "^2.16.0",
24
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
25
+ "@typescript-eslint/parser": "^8.56.0",
26
+ "eslint": "^9.39.3",
27
+ "eslint-config-prettier": "^10.1.8",
28
+ "eslint-plugin-svelte": "^3.15.0",
28
29
  "gh-pages": "^6.3.0",
30
+ "globals": "^17.3.0",
29
31
  "highlight.js": "^11.11.1",
30
- "prettier": "^3.4.2",
31
- "prettier-plugin-svelte": "^3.3.3",
32
- "publint": "^0.2.12",
33
- "sass-embedded": "^1.83.4",
34
- "svelte": "^5.19.3",
35
- "svelte-check": "^4.0.5",
32
+ "prettier": "^3.8.1",
33
+ "prettier-plugin-svelte": "^3.5.0",
34
+ "publint": "^0.3.17",
35
+ "svelte": "^5.53.2",
36
+ "svelte-check": "^4.4.3",
37
+ "svelte-eslint-parser": "^1.4.1",
36
38
  "tslib": "^2.8.1",
37
- "typescript": "^5.7.3",
38
- "vite": "^5.4.10"
39
+ "typescript": "^5.9.3",
40
+ "vite": "^7.3.1"
39
41
  },
40
42
  "peerDependencies": {
41
43
  "svelte": "^5.0.0"
42
44
  },
43
45
  "type": "module",
44
46
  "dependencies": {
45
- "@justinribeiro/lite-youtube": "^1.7.1",
47
+ "@justinribeiro/lite-youtube": "^1.9.0",
46
48
  "@seorii/prosemirror-math": "^0.4.2",
47
- "@tiptap/core": "^2.11.5",
48
- "@tiptap/extension-code": "^2.11.5",
49
- "@tiptap/extension-code-block": "^2.11.5",
50
- "@tiptap/extension-code-block-lowlight": "^2.11.5",
51
- "@tiptap/extension-color": "^2.11.5",
52
- "@tiptap/extension-dropcursor": "^2.11.5",
53
- "@tiptap/extension-highlight": "^2.11.5",
54
- "@tiptap/extension-image": "^2.11.5",
55
- "@tiptap/extension-link": "^2.11.5",
56
- "@tiptap/extension-ordered-list": "^2.11.5",
57
- "@tiptap/extension-placeholder": "^2.11.5",
58
- "@tiptap/extension-subscript": "^2.11.5",
59
- "@tiptap/extension-superscript": "^2.11.5",
60
- "@tiptap/extension-table": "^2.11.5",
61
- "@tiptap/extension-table-cell": "^2.11.5",
62
- "@tiptap/extension-table-header": "^2.11.5",
63
- "@tiptap/extension-table-row": "^2.11.5",
64
- "@tiptap/extension-text-align": "^2.11.5",
65
- "@tiptap/extension-text-style": "^2.11.5",
66
- "@tiptap/extension-underline": "^2.11.5",
67
- "@tiptap/html": "^2.11.5",
68
- "@tiptap/pm": "^2.11.5",
69
- "@tiptap/starter-kit": "^2.11.5",
70
- "@tiptap/suggestion": "^2.11.5",
49
+ "@tiptap/core": "^2",
50
+ "@tiptap/extension-code": "^2",
51
+ "@tiptap/extension-code-block": "^2",
52
+ "@tiptap/extension-code-block-lowlight": "^2",
53
+ "@tiptap/extension-color": "^2",
54
+ "@tiptap/extension-dropcursor": "^2",
55
+ "@tiptap/extension-highlight": "^2",
56
+ "@tiptap/extension-image": "^2",
57
+ "@tiptap/extension-link": "^2",
58
+ "@tiptap/extension-ordered-list": "^2",
59
+ "@tiptap/extension-placeholder": "^2",
60
+ "@tiptap/extension-subscript": "^2",
61
+ "@tiptap/extension-superscript": "^2",
62
+ "@tiptap/extension-table": "^2",
63
+ "@tiptap/extension-table-cell": "^2",
64
+ "@tiptap/extension-table-header": "^2",
65
+ "@tiptap/extension-table-row": "^2",
66
+ "@tiptap/extension-text-align": "^2",
67
+ "@tiptap/extension-text-style": "^2",
68
+ "@tiptap/extension-underline": "^2",
69
+ "@tiptap/html": "^2",
70
+ "@tiptap/pm": "^2",
71
+ "@tiptap/starter-kit": "^2",
72
+ "@tiptap/suggestion": "^2",
71
73
  "emojis-keywords": "2.0.0",
72
74
  "emojis-list": "3.0.0",
73
75
  "lowlight": "^3.3.0",
74
- "nunui": "2.0.0-next.47",
75
- "prosemirror-commands": "^1.7.0",
76
- "prosemirror-model": "^1.25.0",
77
- "prosemirror-state": "^1.4.3",
78
- "prosemirror-tables": "^1.6.4",
79
- "prosemirror-transform": "^1.10.3",
80
- "prosemirror-view": "^1.38.1",
81
- "sanitize-html": "^2.15.0",
82
- "svelte-awesome-color-picker": "^4.0.0",
83
- "svelte-tiptap": "^2.1.0",
76
+ "nunui": "2.0.0-next.51",
77
+ "prosemirror-commands": "^1.7.1",
78
+ "prosemirror-model": "^1.25.4",
79
+ "prosemirror-state": "^1.4.4",
80
+ "prosemirror-tables": "^1.8.5",
81
+ "prosemirror-transform": "^1.11.0",
82
+ "prosemirror-view": "^1.41.6",
83
+ "sanitize-html": "^2.17.1",
84
+ "svelte-awesome-color-picker": "^4.1.1",
85
+ "svelte-tiptap": "^2",
84
86
  "tippy.js": "^6.3.7"
85
87
  },
86
88
  "exports": {
@@ -103,6 +105,10 @@
103
105
  "url": "https://github.com/seorii/tiptap.git"
104
106
  },
105
107
  "pnpm": {
108
+ "overrides": {
109
+ "@tiptap/extension-bubble-menu": "2.6.6",
110
+ "@tiptap/extension-floating-menu": "2.6.6"
111
+ },
106
112
  "onlyBuiltDependencies": [
107
113
  "@parcel/watcher",
108
114
  "esbuild"
@@ -1,13 +0,0 @@
1
- export declare const slashVisible: import("svelte/store").Writable<boolean>;
2
- export declare const slashItems: import("svelte/store").Writable<never[]>;
3
- export declare const slashLocaltion: import("svelte/store").Writable<{
4
- x: number;
5
- y: number;
6
- height: number;
7
- }>;
8
- export declare const slashProps: import("svelte/store").Writable<{
9
- editor: null;
10
- range: null;
11
- }>;
12
- export declare const slashDetail: import("svelte/store").Writable<null>;
13
- export declare const slashSelection: import("svelte/store").Writable<null>;
@@ -1,7 +0,0 @@
1
- import { writable } from 'svelte/store';
2
- export const slashVisible = writable(false);
3
- export const slashItems = writable([]);
4
- export const slashLocaltion = writable({ x: 0, y: 0, height: 0 });
5
- export const slashProps = writable({ editor: null, range: null });
6
- export const slashDetail = writable(null);
7
- export const slashSelection = writable(null);
@@ -1,26 +0,0 @@
1
- .ProseMirror {
2
- table .column-resize-handle {
3
- position: absolute;
4
- top: 0;
5
- right: -2px;
6
- bottom: -2px;
7
- width: 4px;
8
- pointer-events: none;
9
- background-color: var(--primary-light6);
10
- opacity: 0;
11
-
12
- .editable & {
13
- opacity: 1;
14
- }
15
- }
16
-
17
- &.resize-cursor {
18
- pointer-events: none;
19
-
20
- .editable & {
21
- pointer-events: initial;
22
- cursor: ew-resize;
23
- cursor: col-resize; /* stylelint-disable declaration-block-no-duplicate-properties */
24
- }
25
- }
26
- }
@@ -1,4 +0,0 @@
1
- @import './style/grip';
2
- @import './style/table';
3
- @import './style/cell';
4
- @import './style/resize';