@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.
@@ -4,7 +4,7 @@ import { b as KunEditorLocale, N as Notify, U as UploadImage, K as KunEditorAdap
4
4
  import * as _milkdown_kit_utils from '@milkdown/kit/utils';
5
5
  import { Extension } from '@codemirror/state';
6
6
  import { Uploader } from '@milkdown/kit/plugin/upload';
7
- import { Decoration } from '@milkdown/kit/prose/view';
7
+ import { Decoration, EditorView } from '@milkdown/kit/prose/view';
8
8
  import { HighlightStyle } from '@codemirror/language';
9
9
 
10
10
  /** DOM attrs for the rendered spoiler chip. The styling references KunUI CSS
@@ -174,7 +174,8 @@ interface UploadPluginOptions {
174
174
  * the whole batch — more robust than the forum's all-or-nothing Promise.all.
175
175
  */
176
176
  declare const createUploader: (uploadImage: UploadImage, options?: UploadPluginOptions) => Uploader;
177
- /** The in-flight "uploading…" placeholder shown at the drop position. */
177
+ /** The in-flight "uploading…" placeholder shown at the drop position (paste/drop
178
+ * path — Milkdown's `upload` plugin calls this). */
178
179
  declare const createUploadWidgetFactory: (options?: UploadPluginOptions) => (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration;
179
180
  /** Applies the uploader + placeholder to a Milkdown ctx. Call after the `upload`
180
181
  * plugin has registered its config slice. */
@@ -186,6 +187,32 @@ declare const applyUploadConfig: (ctx: Ctx, uploadImage: UploadImage, options?:
186
187
  * image-free editor (galgame 简介) is expressed.
187
188
  */
188
189
  declare const createUploadPlugin: (uploadImage: UploadImage, options?: UploadPluginOptions) => MilkdownPlugin[];
190
+ /** The placeholder DecorationSet plugin — add it when uploads are enabled. */
191
+ declare const imageUploadPlaceholder: MilkdownPlugin;
192
+ /**
193
+ * Upload a File and show an in-document "uploading…" placeholder at the caret
194
+ * until it resolves, then replace it with the image (or remove it + notify on
195
+ * failure). The placeholder isn't an undo step (`addToHistory: false`), so undo
196
+ * removes the inserted image cleanly. Used by the toolbar image button.
197
+ */
198
+ declare const startImageUpload: (view: EditorView, file: File, options: {
199
+ uploadImage: UploadImage;
200
+ notify?: Notify;
201
+ locale?: KunEditorLocale;
202
+ }) => Promise<void>;
203
+
204
+ type PlaceholderMode = 'doc' | 'block';
205
+ interface PlaceholderConfig {
206
+ /** The placeholder text. Empty string disables the placeholder. */
207
+ text?: string;
208
+ /** `'block'` (default) shows on any empty block; `'doc'` only when empty. */
209
+ mode?: PlaceholderMode;
210
+ }
211
+ /**
212
+ * The placeholder plugin. `text` is baked in at creation (the editor is built
213
+ * once); pass it from `createKunEditorPlugins(..., { placeholder })`.
214
+ */
215
+ declare const createPlaceholderPlugin: (config?: PlaceholderConfig) => MilkdownPlugin[];
189
216
 
190
217
  /** Extra, non-adapter options for the composed bundle. */
191
218
  interface KunEditorPluginOptions {
@@ -193,6 +220,10 @@ interface KunEditorPluginOptions {
193
220
  locale?: KunEditorLocale;
194
221
  /** KaTeX options forwarded to the code-block `latex` preview. */
195
222
  katexOptions?: KatexOptions;
223
+ /** Placeholder text shown when empty. Omit / empty string → no placeholder. */
224
+ placeholder?: string;
225
+ /** `'block'` (default) shows on any empty block; `'doc'` only when empty. */
226
+ placeholderMode?: 'doc' | 'block';
196
227
  }
197
228
  /**
198
229
  * Assemble the KunEditor Milkdown plugin list.
@@ -209,4 +240,4 @@ interface KunEditorPluginOptions {
209
240
  */
210
241
  declare const createKunEditorPlugins: (adapters?: KunEditorAdapters, features?: KunEditorFeatures, options?: KunEditorPluginOptions) => MilkdownPlugin[];
211
242
 
212
- export { type CodeBlockOptions, type KunEditorPluginOptions, type MentionUrlConfig, type QuoteReference, type UploadPluginOptions, applyCodeBlockConfig, applyUploadConfig, blockKatexSchema, chevronDownIcon, clearIcon, copyIcon, createCodeBlockPlugins, createHeadingPlugin, createKatexPlugins, createKunEditorPlugins, createMentionPlugin, createQuotePlugin, createSpoilerPlugin, createStopLinkPlugin, createUploadPlugin, createUploadWidgetFactory, createUploader, editIcon, insertKunSpoilerCommand, insertMentionCommand, insertQuoteCommand, insertSpoilerInputRule, kunCM, kunCMHighlightStyle, kunCMTheme, linkCustomKeymap, mathBlockInputRule, mathInlineId, mathInlineInputRule, mathInlineSchema, mentionId, mentionSchema, quoteId, quoteSchema, remarkMathBlockPlugin, remarkMathPlugin, remarkMentionPlugin, remarkQuotePlugin, remarkSpoilerPlugin, searchIcon, setHeadingCommand, spoilerAttr, spoilerSchema, stopLinkCommand, toggleLatexCommand, visibilityOffIcon };
243
+ export { type CodeBlockOptions, type KunEditorPluginOptions, type MentionUrlConfig, type PlaceholderConfig, type PlaceholderMode, type QuoteReference, type UploadPluginOptions, applyCodeBlockConfig, applyUploadConfig, blockKatexSchema, chevronDownIcon, clearIcon, copyIcon, createCodeBlockPlugins, createHeadingPlugin, createKatexPlugins, createKunEditorPlugins, createMentionPlugin, createPlaceholderPlugin, createQuotePlugin, createSpoilerPlugin, createStopLinkPlugin, createUploadPlugin, createUploadWidgetFactory, createUploader, editIcon, imageUploadPlaceholder, insertKunSpoilerCommand, insertMentionCommand, insertQuoteCommand, insertSpoilerInputRule, kunCM, kunCMHighlightStyle, kunCMTheme, linkCustomKeymap, mathBlockInputRule, mathInlineId, mathInlineInputRule, mathInlineSchema, mentionId, mentionSchema, quoteId, quoteSchema, remarkMathBlockPlugin, remarkMathPlugin, remarkMentionPlugin, remarkQuotePlugin, remarkSpoilerPlugin, searchIcon, setHeadingCommand, spoilerAttr, spoilerSchema, startImageUpload, stopLinkCommand, toggleLatexCommand, visibilityOffIcon };
@@ -8,12 +8,12 @@ import { indent } from '@milkdown/kit/plugin/indent';
8
8
  import { trailing } from '@milkdown/kit/plugin/trailing';
9
9
  import { expectDomTypeError } from '@milkdown/kit/exception';
10
10
  import { InputRule, textblockTypeInputRule } from '@milkdown/kit/prose/inputrules';
11
- import { $nodeAttr, $nodeSchema, $command, $inputRule, $remark, $useKeymap } from '@milkdown/kit/utils';
11
+ import { $nodeAttr, $nodeSchema, $command, $inputRule, $remark, $useKeymap, $prose } from '@milkdown/kit/utils';
12
12
  import { visit } from 'unist-util-visit';
13
- import { commandsCtx } from '@milkdown/kit/core';
13
+ import { commandsCtx, editorViewOptionsCtx } from '@milkdown/kit/core';
14
14
  import { setBlockType } from '@milkdown/kit/prose/commands';
15
15
  import { findNodeInSelection, nodeRule } from '@milkdown/kit/prose';
16
- import { NodeSelection, TextSelection } from '@milkdown/kit/prose/state';
16
+ import { NodeSelection, TextSelection, PluginKey, Plugin } from '@milkdown/kit/prose/state';
17
17
  import katex from 'katex';
18
18
  import remarkMath from 'remark-math';
19
19
  import { codeBlockComponent, codeBlockConfig } from '@milkdown/kit/component/code-block';
@@ -24,7 +24,7 @@ import { basicSetup } from 'codemirror';
24
24
  import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
25
25
  import { tags } from '@lezer/highlight';
26
26
  import { upload, uploadConfig } from '@milkdown/kit/plugin/upload';
27
- import { Decoration } from '@milkdown/kit/prose/view';
27
+ import { DecorationSet, Decoration } from '@milkdown/kit/prose/view';
28
28
 
29
29
  var spoilerAttr = $nodeAttr("kun-spoiler", () => ({
30
30
  container: {
@@ -945,12 +945,15 @@ var createUploader = (uploadImage, options = {}) => {
945
945
  return nodes.filter((node) => node !== null);
946
946
  };
947
947
  };
948
+ var uploadingWidget = (locale) => {
949
+ const el = document.createElement("span");
950
+ el.className = "kun-editor__uploading";
951
+ el.textContent = uploadingLabel(locale);
952
+ return el;
953
+ };
948
954
  var createUploadWidgetFactory = (options = {}) => {
949
955
  return (pos, spec) => {
950
- const widgetDOM = document.createElement("span");
951
- widgetDOM.textContent = uploadingLabel(options.locale);
952
- widgetDOM.style.color = "var(--color-primary)";
953
- return Decoration.widget(pos, widgetDOM, spec);
956
+ return Decoration.widget(pos, uploadingWidget(options.locale), spec);
954
957
  };
955
958
  };
956
959
  var applyUploadConfig = (ctx, uploadImage, options = {}) => {
@@ -964,6 +967,132 @@ var uploadConfigPlugin = (uploadImage, options) => (ctx) => () => {
964
967
  applyUploadConfig(ctx, uploadImage, options);
965
968
  };
966
969
  var createUploadPlugin = (uploadImage, options = {}) => [...upload, uploadConfigPlugin(uploadImage, options)];
970
+ var placeholderKey = new PluginKey("KUN_IMAGE_UPLOAD_PLACEHOLDER");
971
+ var imageUploadPlaceholder = $prose(
972
+ () => new Plugin({
973
+ key: placeholderKey,
974
+ state: {
975
+ init: () => DecorationSet.empty,
976
+ apply(tr, set) {
977
+ let next = set.map(tr.mapping, tr.doc);
978
+ const meta = tr.getMeta(placeholderKey);
979
+ if (meta?.add) {
980
+ const deco = Decoration.widget(
981
+ meta.add.pos,
982
+ uploadingWidget(meta.add.locale),
983
+ { id: meta.add.id }
984
+ );
985
+ next = next.add(tr.doc, [deco]);
986
+ } else if (meta?.remove) {
987
+ const { id } = meta.remove;
988
+ next = next.remove(
989
+ next.find(void 0, void 0, (spec) => spec.id === id)
990
+ );
991
+ }
992
+ return next;
993
+ }
994
+ },
995
+ props: {
996
+ decorations: (state) => placeholderKey.getState(state)
997
+ }
998
+ })
999
+ );
1000
+ var findPlaceholder = (view, id) => {
1001
+ const set = placeholderKey.getState(view.state);
1002
+ const found = set?.find(void 0, void 0, (spec) => spec.id === id);
1003
+ return found && found.length ? found[0].from : null;
1004
+ };
1005
+ var startImageUpload = async (view, file, options) => {
1006
+ if (!file.type.startsWith("image/")) {
1007
+ return;
1008
+ }
1009
+ const id = {};
1010
+ const tr = view.state.tr;
1011
+ if (!tr.selection.empty) {
1012
+ tr.deleteSelection();
1013
+ }
1014
+ tr.setMeta(placeholderKey, {
1015
+ add: { id, pos: tr.selection.from, locale: options.locale }
1016
+ });
1017
+ tr.setMeta("addToHistory", false);
1018
+ view.dispatch(tr);
1019
+ try {
1020
+ const src = await options.uploadImage(file);
1021
+ const pos = findPlaceholder(view, id);
1022
+ if (pos === null) {
1023
+ return;
1024
+ }
1025
+ const imageType = view.state.schema.nodes.image;
1026
+ const node = imageType?.createAndFill({ src, alt: file.name });
1027
+ if (!node) {
1028
+ return;
1029
+ }
1030
+ view.dispatch(
1031
+ view.state.tr.replaceWith(pos, pos, node).setMeta(placeholderKey, { remove: { id } })
1032
+ );
1033
+ } catch {
1034
+ view.dispatch(
1035
+ view.state.tr.setMeta(placeholderKey, { remove: { id } }).setMeta("addToHistory", false)
1036
+ );
1037
+ options.notify?.(uploadFailedLabel(options.locale), "error");
1038
+ }
1039
+ };
1040
+ var SKIP_PARENTS = /* @__PURE__ */ new Set([
1041
+ "code_block",
1042
+ "bullet_list",
1043
+ "ordered_list",
1044
+ "list_item",
1045
+ "table"
1046
+ ]);
1047
+ var isDocEmpty = (doc) => doc.childCount <= 1 && !doc.firstChild?.content.size;
1048
+ var isInSkippedParent = (state) => {
1049
+ const { $anchor } = state.selection;
1050
+ for (let depth = $anchor.depth; depth > 0; depth--) {
1051
+ if (SKIP_PARENTS.has($anchor.node(depth).type.name)) {
1052
+ return true;
1053
+ }
1054
+ }
1055
+ return false;
1056
+ };
1057
+ var createPlaceholderPlugin = (config = {}) => {
1058
+ const text = config.text ?? "";
1059
+ const mode = config.mode ?? "block";
1060
+ const plugin = $prose(
1061
+ (ctx) => new Plugin({
1062
+ key: new PluginKey("KUN_PLACEHOLDER"),
1063
+ props: {
1064
+ decorations: (state) => {
1065
+ if (!text) {
1066
+ return null;
1067
+ }
1068
+ const editable = ctx.get(editorViewOptionsCtx).editable;
1069
+ if (editable && !editable(state)) {
1070
+ return null;
1071
+ }
1072
+ if (mode === "doc" && !isDocEmpty(state.doc)) {
1073
+ return null;
1074
+ }
1075
+ const { selection } = state;
1076
+ if (!selection.empty || isInSkippedParent(state)) {
1077
+ return null;
1078
+ }
1079
+ const node = selection.$anchor.parent;
1080
+ if (node.content.size > 0) {
1081
+ return null;
1082
+ }
1083
+ const before = selection.$anchor.before();
1084
+ return DecorationSet.create(state.doc, [
1085
+ Decoration.node(before, before + node.nodeSize, {
1086
+ class: "kun-editor__placeholder",
1087
+ "data-placeholder": text
1088
+ })
1089
+ ]);
1090
+ }
1091
+ }
1092
+ })
1093
+ );
1094
+ return [plugin].flat();
1095
+ };
967
1096
 
968
1097
  // src/preset/index.ts
969
1098
  var createKunEditorPlugins = (adapters = {}, features = {}, options = {}) => {
@@ -1015,12 +1144,21 @@ var createKunEditorPlugins = (adapters = {}, features = {}, options = {}) => {
1015
1144
  notify: adapters.notify
1016
1145
  })
1017
1146
  );
1147
+ plugins.push(imageUploadPlaceholder);
1018
1148
  }
1019
1149
  plugins.push(createStopLinkPlugin());
1020
1150
  plugins.push(createHeadingPlugin());
1151
+ if (options.placeholder) {
1152
+ plugins.push(
1153
+ createPlaceholderPlugin({
1154
+ text: options.placeholder,
1155
+ mode: options.placeholderMode
1156
+ })
1157
+ );
1158
+ }
1021
1159
  return plugins.flat();
1022
1160
  };
1023
1161
 
1024
- export { applyCodeBlockConfig, applyUploadConfig, blockKatexSchema, chevronDownIcon, clearIcon, copyIcon, createCodeBlockPlugins, createHeadingPlugin, createKatexPlugins, createKunEditorPlugins, createMentionPlugin, createQuotePlugin, createSpoilerPlugin, createStopLinkPlugin, createUploadPlugin, createUploadWidgetFactory, createUploader, editIcon, insertKunSpoilerCommand, insertMentionCommand, insertQuoteCommand, insertSpoilerInputRule, kunCM, kunCMHighlightStyle, kunCMTheme, linkCustomKeymap, mathBlockInputRule, mathInlineId, mathInlineInputRule, mathInlineSchema, mentionId, mentionSchema, quoteId, quoteSchema, remarkMathBlockPlugin, remarkMathPlugin, remarkMentionPlugin, remarkQuotePlugin, remarkSpoilerPlugin, searchIcon, setHeadingCommand, spoilerAttr, spoilerSchema, stopLinkCommand, toggleLatexCommand, visibilityOffIcon };
1162
+ export { applyCodeBlockConfig, applyUploadConfig, blockKatexSchema, chevronDownIcon, clearIcon, copyIcon, createCodeBlockPlugins, createHeadingPlugin, createKatexPlugins, createKunEditorPlugins, createMentionPlugin, createPlaceholderPlugin, createQuotePlugin, createSpoilerPlugin, createStopLinkPlugin, createUploadPlugin, createUploadWidgetFactory, createUploader, editIcon, imageUploadPlaceholder, insertKunSpoilerCommand, insertMentionCommand, insertQuoteCommand, insertSpoilerInputRule, kunCM, kunCMHighlightStyle, kunCMTheme, linkCustomKeymap, mathBlockInputRule, mathInlineId, mathInlineInputRule, mathInlineSchema, mentionId, mentionSchema, quoteId, quoteSchema, remarkMathBlockPlugin, remarkMathPlugin, remarkMentionPlugin, remarkQuotePlugin, remarkSpoilerPlugin, searchIcon, setHeadingCommand, spoilerAttr, spoilerSchema, startImageUpload, stopLinkCommand, toggleLatexCommand, visibilityOffIcon };
1025
1163
  //# sourceMappingURL=index.js.map
1026
1164
  //# sourceMappingURL=index.js.map