@kungal/editor-core 0.16.0 → 0.18.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/CHANGELOG.md +49 -0
- package/dist/preset/index.cjs +150 -9
- package/dist/preset/index.cjs.map +1 -1
- package/dist/preset/index.d.cts +34 -3
- package/dist/preset/index.d.ts +34 -3
- package/dist/preset/index.js +147 -9
- package/dist/preset/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# @kungal/editor-core
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6545866: Toolbar image upload now shows an in-document "uploading…" placeholder.
|
|
8
|
+
|
|
9
|
+
Previously only paste/drop showed the in-flight placeholder (Milkdown's `upload`
|
|
10
|
+
plugin); the toolbar image button uploaded silently — the image just popped in
|
|
11
|
+
when the adapter resolved. Now the toolbar path uses the same placeholder UX
|
|
12
|
+
(ProseMirror's official upload-example pattern).
|
|
13
|
+
|
|
14
|
+
- **editor-core**: `startImageUpload(view, file, { uploadImage, notify, locale })`
|
|
15
|
+
- the `imageUploadPlaceholder` decoration plugin (exported from `/preset`;
|
|
16
|
+
wired by the preset when `uploadImage` is present). Inserts a
|
|
17
|
+
`.kun-editor__uploading` widget at the caret, uploads, then replaces it with the
|
|
18
|
+
image (or removes it + notifies on failure); not an undo step. The paste/drop
|
|
19
|
+
placeholder now uses the same `.kun-editor__uploading` class so both look
|
|
20
|
+
identical.
|
|
21
|
+
- **editor-vue**: `KunEditorToolbarApi` gains `uploadImage(file)`; both the
|
|
22
|
+
headless `EditorToolbar` and the `#toolbar` slot API route uploads through
|
|
23
|
+
`startImageUpload`.
|
|
24
|
+
- **editor-nuxt**: `<KunEditorToolbar>`'s image button uses it.
|
|
25
|
+
- **Headless kept**: the placeholder is a class + widget hook only; style it via
|
|
26
|
+
`.kun-editor__uploading` in the reference `kun-editor.css` (primary-colored).
|
|
27
|
+
|
|
28
|
+
Customizable: style the placeholder via `.kun-editor__uploading`; the text is
|
|
29
|
+
localized (zh/en). Verified in the docs production build: uploading via either
|
|
30
|
+
toolbar inserts the image; the unit tests confirm the placeholder shows during a
|
|
31
|
+
pending upload and is replaced on success / removed on failure.
|
|
32
|
+
|
|
33
|
+
## 0.17.0
|
|
34
|
+
|
|
35
|
+
### Minor Changes
|
|
36
|
+
|
|
37
|
+
- 59abbc8: Add a placeholder (empty-state text).
|
|
38
|
+
|
|
39
|
+
- **editor-core**: `createPlaceholderPlugin({ text, mode })` — a `$prose` plugin
|
|
40
|
+
that adds a ProseMirror node DECORATION to the empty block (`.kun-editor__placeholder`
|
|
41
|
+
class + `data-placeholder` attribute). Same mechanism as Milkdown Crepe's v7
|
|
42
|
+
placeholder feature — purely visual (a decoration), so it never enters the doc
|
|
43
|
+
or the markdown output. `mode` `'block'` (default) shows on any empty block,
|
|
44
|
+
`'doc'` only when the whole document is empty; skipped in readonly / code blocks
|
|
45
|
+
/ lists / tables. `createKunEditorPlugins(..., { placeholder, placeholderMode })`
|
|
46
|
+
wires it (only when `placeholder` is non-empty). Exported from `/preset`.
|
|
47
|
+
- **editor-vue**: `<KunEditor placeholder="…">` prop, threaded through.
|
|
48
|
+
- **Headless**: the core ships only the class + `data-placeholder` hook; render it
|
|
49
|
+
with `.kun-editor__placeholder::before { content: attr(data-placeholder) }` (added
|
|
50
|
+
to the reference `kun-editor.css`, muted via a KunUI token).
|
|
51
|
+
|
|
3
52
|
## 0.16.0
|
|
4
53
|
|
|
5
54
|
## 0.15.0
|
package/dist/preset/index.cjs
CHANGED
|
@@ -19,13 +19,13 @@ var katex = require('katex');
|
|
|
19
19
|
var remarkMath = require('remark-math');
|
|
20
20
|
var codeBlock = require('@milkdown/kit/component/code-block');
|
|
21
21
|
var commands$1 = require('@codemirror/commands');
|
|
22
|
-
var view = require('@codemirror/view');
|
|
22
|
+
var view$1 = require('@codemirror/view');
|
|
23
23
|
var languageData = require('@codemirror/language-data');
|
|
24
24
|
var codemirror = require('codemirror');
|
|
25
25
|
var language = require('@codemirror/language');
|
|
26
26
|
var highlight = require('@lezer/highlight');
|
|
27
27
|
var upload = require('@milkdown/kit/plugin/upload');
|
|
28
|
-
var view
|
|
28
|
+
var view = require('@milkdown/kit/prose/view');
|
|
29
29
|
|
|
30
30
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
31
31
|
|
|
@@ -374,7 +374,7 @@ var colors = {
|
|
|
374
374
|
content2: "var(--color-content2)",
|
|
375
375
|
content3: "var(--color-content3)"};
|
|
376
376
|
var kunCMTheme = () => {
|
|
377
|
-
return view.EditorView.theme({
|
|
377
|
+
return view$1.EditorView.theme({
|
|
378
378
|
"&": {
|
|
379
379
|
backgroundColor: colors.backgroundAlpha,
|
|
380
380
|
borderRadius: "0.75rem",
|
|
@@ -690,8 +690,8 @@ var applyCodeBlockConfig = (ctx, options = {}) => {
|
|
|
690
690
|
...prev,
|
|
691
691
|
extensions: [
|
|
692
692
|
kunCM(),
|
|
693
|
-
view.EditorView.lineWrapping,
|
|
694
|
-
view.keymap.of(commands$1.defaultKeymap.concat(commands$1.indentWithTab)),
|
|
693
|
+
view$1.EditorView.lineWrapping,
|
|
694
|
+
view$1.keymap.of(commands$1.defaultKeymap.concat(commands$1.indentWithTab)),
|
|
695
695
|
codemirror.basicSetup,
|
|
696
696
|
...options.extensions ?? []
|
|
697
697
|
],
|
|
@@ -958,12 +958,15 @@ var createUploader = (uploadImage, options = {}) => {
|
|
|
958
958
|
return nodes.filter((node) => node !== null);
|
|
959
959
|
};
|
|
960
960
|
};
|
|
961
|
+
var uploadingWidget = (locale) => {
|
|
962
|
+
const el = document.createElement("span");
|
|
963
|
+
el.className = "kun-editor__uploading";
|
|
964
|
+
el.textContent = uploadingLabel(locale);
|
|
965
|
+
return el;
|
|
966
|
+
};
|
|
961
967
|
var createUploadWidgetFactory = (options = {}) => {
|
|
962
968
|
return (pos, spec) => {
|
|
963
|
-
|
|
964
|
-
widgetDOM.textContent = uploadingLabel(options.locale);
|
|
965
|
-
widgetDOM.style.color = "var(--color-primary)";
|
|
966
|
-
return view$1.Decoration.widget(pos, widgetDOM, spec);
|
|
969
|
+
return view.Decoration.widget(pos, uploadingWidget(options.locale), spec);
|
|
967
970
|
};
|
|
968
971
|
};
|
|
969
972
|
var applyUploadConfig = (ctx, uploadImage, options = {}) => {
|
|
@@ -977,6 +980,132 @@ var uploadConfigPlugin = (uploadImage, options) => (ctx) => () => {
|
|
|
977
980
|
applyUploadConfig(ctx, uploadImage, options);
|
|
978
981
|
};
|
|
979
982
|
var createUploadPlugin = (uploadImage, options = {}) => [...upload.upload, uploadConfigPlugin(uploadImage, options)];
|
|
983
|
+
var placeholderKey = new state.PluginKey("KUN_IMAGE_UPLOAD_PLACEHOLDER");
|
|
984
|
+
var imageUploadPlaceholder = utils.$prose(
|
|
985
|
+
() => new state.Plugin({
|
|
986
|
+
key: placeholderKey,
|
|
987
|
+
state: {
|
|
988
|
+
init: () => view.DecorationSet.empty,
|
|
989
|
+
apply(tr, set) {
|
|
990
|
+
let next = set.map(tr.mapping, tr.doc);
|
|
991
|
+
const meta = tr.getMeta(placeholderKey);
|
|
992
|
+
if (meta?.add) {
|
|
993
|
+
const deco = view.Decoration.widget(
|
|
994
|
+
meta.add.pos,
|
|
995
|
+
uploadingWidget(meta.add.locale),
|
|
996
|
+
{ id: meta.add.id }
|
|
997
|
+
);
|
|
998
|
+
next = next.add(tr.doc, [deco]);
|
|
999
|
+
} else if (meta?.remove) {
|
|
1000
|
+
const { id } = meta.remove;
|
|
1001
|
+
next = next.remove(
|
|
1002
|
+
next.find(void 0, void 0, (spec) => spec.id === id)
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
return next;
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
props: {
|
|
1009
|
+
decorations: (state) => placeholderKey.getState(state)
|
|
1010
|
+
}
|
|
1011
|
+
})
|
|
1012
|
+
);
|
|
1013
|
+
var findPlaceholder = (view, id) => {
|
|
1014
|
+
const set = placeholderKey.getState(view.state);
|
|
1015
|
+
const found = set?.find(void 0, void 0, (spec) => spec.id === id);
|
|
1016
|
+
return found && found.length ? found[0].from : null;
|
|
1017
|
+
};
|
|
1018
|
+
var startImageUpload = async (view, file, options) => {
|
|
1019
|
+
if (!file.type.startsWith("image/")) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const id = {};
|
|
1023
|
+
const tr = view.state.tr;
|
|
1024
|
+
if (!tr.selection.empty) {
|
|
1025
|
+
tr.deleteSelection();
|
|
1026
|
+
}
|
|
1027
|
+
tr.setMeta(placeholderKey, {
|
|
1028
|
+
add: { id, pos: tr.selection.from, locale: options.locale }
|
|
1029
|
+
});
|
|
1030
|
+
tr.setMeta("addToHistory", false);
|
|
1031
|
+
view.dispatch(tr);
|
|
1032
|
+
try {
|
|
1033
|
+
const src = await options.uploadImage(file);
|
|
1034
|
+
const pos = findPlaceholder(view, id);
|
|
1035
|
+
if (pos === null) {
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const imageType = view.state.schema.nodes.image;
|
|
1039
|
+
const node = imageType?.createAndFill({ src, alt: file.name });
|
|
1040
|
+
if (!node) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
view.dispatch(
|
|
1044
|
+
view.state.tr.replaceWith(pos, pos, node).setMeta(placeholderKey, { remove: { id } })
|
|
1045
|
+
);
|
|
1046
|
+
} catch {
|
|
1047
|
+
view.dispatch(
|
|
1048
|
+
view.state.tr.setMeta(placeholderKey, { remove: { id } }).setMeta("addToHistory", false)
|
|
1049
|
+
);
|
|
1050
|
+
options.notify?.(uploadFailedLabel(options.locale), "error");
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
var SKIP_PARENTS = /* @__PURE__ */ new Set([
|
|
1054
|
+
"code_block",
|
|
1055
|
+
"bullet_list",
|
|
1056
|
+
"ordered_list",
|
|
1057
|
+
"list_item",
|
|
1058
|
+
"table"
|
|
1059
|
+
]);
|
|
1060
|
+
var isDocEmpty = (doc) => doc.childCount <= 1 && !doc.firstChild?.content.size;
|
|
1061
|
+
var isInSkippedParent = (state) => {
|
|
1062
|
+
const { $anchor } = state.selection;
|
|
1063
|
+
for (let depth = $anchor.depth; depth > 0; depth--) {
|
|
1064
|
+
if (SKIP_PARENTS.has($anchor.node(depth).type.name)) {
|
|
1065
|
+
return true;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return false;
|
|
1069
|
+
};
|
|
1070
|
+
var createPlaceholderPlugin = (config = {}) => {
|
|
1071
|
+
const text = config.text ?? "";
|
|
1072
|
+
const mode = config.mode ?? "block";
|
|
1073
|
+
const plugin = utils.$prose(
|
|
1074
|
+
(ctx) => new state.Plugin({
|
|
1075
|
+
key: new state.PluginKey("KUN_PLACEHOLDER"),
|
|
1076
|
+
props: {
|
|
1077
|
+
decorations: (state) => {
|
|
1078
|
+
if (!text) {
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
const editable = ctx.get(core.editorViewOptionsCtx).editable;
|
|
1082
|
+
if (editable && !editable(state)) {
|
|
1083
|
+
return null;
|
|
1084
|
+
}
|
|
1085
|
+
if (mode === "doc" && !isDocEmpty(state.doc)) {
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
const { selection } = state;
|
|
1089
|
+
if (!selection.empty || isInSkippedParent(state)) {
|
|
1090
|
+
return null;
|
|
1091
|
+
}
|
|
1092
|
+
const node = selection.$anchor.parent;
|
|
1093
|
+
if (node.content.size > 0) {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
const before = selection.$anchor.before();
|
|
1097
|
+
return view.DecorationSet.create(state.doc, [
|
|
1098
|
+
view.Decoration.node(before, before + node.nodeSize, {
|
|
1099
|
+
class: "kun-editor__placeholder",
|
|
1100
|
+
"data-placeholder": text
|
|
1101
|
+
})
|
|
1102
|
+
]);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
})
|
|
1106
|
+
);
|
|
1107
|
+
return [plugin].flat();
|
|
1108
|
+
};
|
|
980
1109
|
|
|
981
1110
|
// src/preset/index.ts
|
|
982
1111
|
var createKunEditorPlugins = (adapters = {}, features = {}, options = {}) => {
|
|
@@ -1028,9 +1157,18 @@ var createKunEditorPlugins = (adapters = {}, features = {}, options = {}) => {
|
|
|
1028
1157
|
notify: adapters.notify
|
|
1029
1158
|
})
|
|
1030
1159
|
);
|
|
1160
|
+
plugins.push(imageUploadPlaceholder);
|
|
1031
1161
|
}
|
|
1032
1162
|
plugins.push(createStopLinkPlugin());
|
|
1033
1163
|
plugins.push(createHeadingPlugin());
|
|
1164
|
+
if (options.placeholder) {
|
|
1165
|
+
plugins.push(
|
|
1166
|
+
createPlaceholderPlugin({
|
|
1167
|
+
text: options.placeholder,
|
|
1168
|
+
mode: options.placeholderMode
|
|
1169
|
+
})
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1034
1172
|
return plugins.flat();
|
|
1035
1173
|
};
|
|
1036
1174
|
|
|
@@ -1045,6 +1183,7 @@ exports.createHeadingPlugin = createHeadingPlugin;
|
|
|
1045
1183
|
exports.createKatexPlugins = createKatexPlugins;
|
|
1046
1184
|
exports.createKunEditorPlugins = createKunEditorPlugins;
|
|
1047
1185
|
exports.createMentionPlugin = createMentionPlugin;
|
|
1186
|
+
exports.createPlaceholderPlugin = createPlaceholderPlugin;
|
|
1048
1187
|
exports.createQuotePlugin = createQuotePlugin;
|
|
1049
1188
|
exports.createSpoilerPlugin = createSpoilerPlugin;
|
|
1050
1189
|
exports.createStopLinkPlugin = createStopLinkPlugin;
|
|
@@ -1052,6 +1191,7 @@ exports.createUploadPlugin = createUploadPlugin;
|
|
|
1052
1191
|
exports.createUploadWidgetFactory = createUploadWidgetFactory;
|
|
1053
1192
|
exports.createUploader = createUploader;
|
|
1054
1193
|
exports.editIcon = editIcon;
|
|
1194
|
+
exports.imageUploadPlaceholder = imageUploadPlaceholder;
|
|
1055
1195
|
exports.insertKunSpoilerCommand = insertKunSpoilerCommand;
|
|
1056
1196
|
exports.insertMentionCommand = insertMentionCommand;
|
|
1057
1197
|
exports.insertQuoteCommand = insertQuoteCommand;
|
|
@@ -1077,6 +1217,7 @@ exports.searchIcon = searchIcon;
|
|
|
1077
1217
|
exports.setHeadingCommand = setHeadingCommand;
|
|
1078
1218
|
exports.spoilerAttr = spoilerAttr;
|
|
1079
1219
|
exports.spoilerSchema = spoilerSchema;
|
|
1220
|
+
exports.startImageUpload = startImageUpload;
|
|
1080
1221
|
exports.stopLinkCommand = stopLinkCommand;
|
|
1081
1222
|
exports.toggleLatexCommand = toggleLatexCommand;
|
|
1082
1223
|
exports.visibilityOffIcon = visibilityOffIcon;
|