@btst/components 0.0.0-stage → 1.0.0-beta.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 (161) hide show
  1. package/LICENSE.md +17 -0
  2. package/dist/_private/ui/styles/markdown-editor.css +31 -0
  3. package/dist/auto-form/index.cjs +8 -0
  4. package/dist/auto-form/index.d.cts +26 -0
  5. package/dist/auto-form/index.d.mts +26 -0
  6. package/dist/auto-form/index.d.ts +26 -0
  7. package/dist/auto-form/index.mjs +1 -0
  8. package/dist/empty/index.cjs +12 -0
  9. package/dist/empty/index.d.cts +15 -0
  10. package/dist/empty/index.d.mts +15 -0
  11. package/dist/empty/index.d.ts +15 -0
  12. package/dist/empty/index.mjs +1 -0
  13. package/dist/form-builder/index.cjs +16 -0
  14. package/dist/form-builder/index.d.cts +395 -0
  15. package/dist/form-builder/index.d.mts +395 -0
  16. package/dist/form-builder/index.d.ts +395 -0
  17. package/dist/form-builder/index.mjs +4 -0
  18. package/dist/markdown/index.cjs +9 -0
  19. package/dist/markdown/index.d.cts +46 -0
  20. package/dist/markdown/index.d.mts +46 -0
  21. package/dist/markdown/index.d.ts +46 -0
  22. package/dist/markdown/index.mjs +2 -0
  23. package/dist/multi-select/index.cjs +7 -0
  24. package/dist/multi-select/index.d.cts +78 -0
  25. package/dist/multi-select/index.d.mts +78 -0
  26. package/dist/multi-select/index.d.ts +78 -0
  27. package/dist/multi-select/index.mjs +1 -0
  28. package/dist/search-select/index.cjs +7 -0
  29. package/dist/search-select/index.d.cts +16 -0
  30. package/dist/search-select/index.d.mts +16 -0
  31. package/dist/search-select/index.d.ts +16 -0
  32. package/dist/search-select/index.mjs +1 -0
  33. package/dist/shared/components.BdvBiegH.d.cts +291 -0
  34. package/dist/shared/components.BdvBiegH.d.mts +291 -0
  35. package/dist/shared/components.BdvBiegH.d.ts +291 -0
  36. package/dist/shared/components.CZMWR72v.d.cts +10 -0
  37. package/dist/shared/components.CZMWR72v.d.mts +10 -0
  38. package/dist/shared/components.CZMWR72v.d.ts +10 -0
  39. package/dist/stepped-auto-form/index.cjs +7 -0
  40. package/dist/stepped-auto-form/index.d.cts +37 -0
  41. package/dist/stepped-auto-form/index.d.mts +37 -0
  42. package/dist/stepped-auto-form/index.d.ts +37 -0
  43. package/dist/stepped-auto-form/index.mjs +1 -0
  44. package/dist/style.css +440 -0
  45. package/dist/ui/src/components/accordion.cjs +81 -0
  46. package/dist/ui/src/components/accordion.mjs +62 -0
  47. package/dist/ui/src/components/auto-form/common/label.cjs +18 -0
  48. package/dist/ui/src/components/auto-form/common/label.mjs +16 -0
  49. package/dist/ui/src/components/auto-form/common/tooltip.cjs +9 -0
  50. package/dist/ui/src/components/auto-form/common/tooltip.mjs +7 -0
  51. package/dist/ui/src/components/auto-form/config.cjs +40 -0
  52. package/dist/ui/src/components/auto-form/config.mjs +37 -0
  53. package/dist/ui/src/components/auto-form/dependencies.cjs +48 -0
  54. package/dist/ui/src/components/auto-form/dependencies.mjs +46 -0
  55. package/dist/ui/src/components/auto-form/fields/array.cjs +266 -0
  56. package/dist/ui/src/components/auto-form/fields/array.mjs +264 -0
  57. package/dist/ui/src/components/auto-form/fields/checkbox.cjs +38 -0
  58. package/dist/ui/src/components/auto-form/fields/checkbox.mjs +36 -0
  59. package/dist/ui/src/components/auto-form/fields/date.cjs +67 -0
  60. package/dist/ui/src/components/auto-form/fields/date.mjs +65 -0
  61. package/dist/ui/src/components/auto-form/fields/enum.cjs +73 -0
  62. package/dist/ui/src/components/auto-form/fields/enum.mjs +71 -0
  63. package/dist/ui/src/components/auto-form/fields/input.cjs +32 -0
  64. package/dist/ui/src/components/auto-form/fields/input.mjs +30 -0
  65. package/dist/ui/src/components/auto-form/fields/number.cjs +31 -0
  66. package/dist/ui/src/components/auto-form/fields/number.mjs +29 -0
  67. package/dist/ui/src/components/auto-form/fields/object.cjs +233 -0
  68. package/dist/ui/src/components/auto-form/fields/object.mjs +217 -0
  69. package/dist/ui/src/components/auto-form/fields/radio-group.cjs +67 -0
  70. package/dist/ui/src/components/auto-form/fields/radio-group.mjs +65 -0
  71. package/dist/ui/src/components/auto-form/fields/switch.cjs +38 -0
  72. package/dist/ui/src/components/auto-form/fields/switch.mjs +36 -0
  73. package/dist/ui/src/components/auto-form/fields/textarea.cjs +31 -0
  74. package/dist/ui/src/components/auto-form/fields/textarea.mjs +29 -0
  75. package/dist/ui/src/components/auto-form/helpers.cjs +270 -0
  76. package/dist/ui/src/components/auto-form/helpers.mjs +259 -0
  77. package/dist/ui/src/components/auto-form/index.cjs +102 -0
  78. package/dist/ui/src/components/auto-form/index.mjs +93 -0
  79. package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +374 -0
  80. package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
  81. package/dist/ui/src/components/auto-form/types.cjs +11 -0
  82. package/dist/ui/src/components/auto-form/types.mjs +9 -0
  83. package/dist/ui/src/components/badge.cjs +42 -0
  84. package/dist/ui/src/components/badge.mjs +39 -0
  85. package/dist/ui/src/components/button.cjs +56 -0
  86. package/dist/ui/src/components/button.mjs +53 -0
  87. package/dist/ui/src/components/calendar.cjs +207 -0
  88. package/dist/ui/src/components/calendar.mjs +190 -0
  89. package/dist/ui/src/components/checkbox.cjs +48 -0
  90. package/dist/ui/src/components/checkbox.mjs +32 -0
  91. package/dist/ui/src/components/command.cjs +118 -0
  92. package/dist/ui/src/components/command.mjs +111 -0
  93. package/dist/ui/src/components/date-picker.cjs +41 -0
  94. package/dist/ui/src/components/date-picker.mjs +39 -0
  95. package/dist/ui/src/components/dialog.cjs +141 -0
  96. package/dist/ui/src/components/dialog.mjs +118 -0
  97. package/dist/ui/src/components/empty.cjs +104 -0
  98. package/dist/ui/src/components/empty.mjs +97 -0
  99. package/dist/ui/src/components/form-builder/canvas.cjs +111 -0
  100. package/dist/ui/src/components/form-builder/canvas.mjs +109 -0
  101. package/dist/ui/src/components/form-builder/components/index.cjs +571 -0
  102. package/dist/ui/src/components/form-builder/components/index.mjs +554 -0
  103. package/dist/ui/src/components/form-builder/edit-field-dialog.cjs +131 -0
  104. package/dist/ui/src/components/form-builder/edit-field-dialog.mjs +129 -0
  105. package/dist/ui/src/components/form-builder/form-preview.cjs +73 -0
  106. package/dist/ui/src/components/form-builder/form-preview.mjs +71 -0
  107. package/dist/ui/src/components/form-builder/index.cjs +350 -0
  108. package/dist/ui/src/components/form-builder/index.mjs +344 -0
  109. package/dist/ui/src/components/form-builder/nested-field-editor-dialog.cjs +263 -0
  110. package/dist/ui/src/components/form-builder/nested-field-editor-dialog.mjs +261 -0
  111. package/dist/ui/src/components/form-builder/palette.cjs +52 -0
  112. package/dist/ui/src/components/form-builder/palette.mjs +49 -0
  113. package/dist/ui/src/components/form-builder/schema-utils.cjs +128 -0
  114. package/dist/ui/src/components/form-builder/schema-utils.mjs +122 -0
  115. package/dist/ui/src/components/form-builder/sortable-field.cjs +151 -0
  116. package/dist/ui/src/components/form-builder/sortable-field.mjs +148 -0
  117. package/dist/ui/src/components/form-builder/step-tabs.cjs +180 -0
  118. package/dist/ui/src/components/form-builder/step-tabs.mjs +178 -0
  119. package/dist/ui/src/components/form-builder/types.cjs +7 -0
  120. package/dist/ui/src/components/form-builder/types.mjs +5 -0
  121. package/dist/ui/src/components/form-builder/validation-schemas.cjs +67 -0
  122. package/dist/ui/src/components/form-builder/validation-schemas.mjs +56 -0
  123. package/dist/ui/src/components/form.cjs +120 -0
  124. package/dist/ui/src/components/form.mjs +98 -0
  125. package/dist/ui/src/components/input.cjs +23 -0
  126. package/dist/ui/src/components/input.mjs +21 -0
  127. package/dist/ui/src/components/label.cjs +39 -0
  128. package/dist/ui/src/components/label.mjs +23 -0
  129. package/dist/ui/src/components/markdown-content.cjs +334 -0
  130. package/dist/ui/src/components/markdown-content.mjs +325 -0
  131. package/dist/ui/src/components/markdown-editor.cjs +180 -0
  132. package/dist/ui/src/components/markdown-editor.mjs +178 -0
  133. package/dist/ui/src/components/multi-select.cjs +555 -0
  134. package/dist/ui/src/components/multi-select.mjs +540 -0
  135. package/dist/ui/src/components/popover.cjs +60 -0
  136. package/dist/ui/src/components/popover.mjs +42 -0
  137. package/dist/ui/src/components/radio-group.cjs +62 -0
  138. package/dist/ui/src/components/radio-group.mjs +45 -0
  139. package/dist/ui/src/components/search-select.cjs +99 -0
  140. package/dist/ui/src/components/search-select.mjs +83 -0
  141. package/dist/ui/src/components/select.cjs +161 -0
  142. package/dist/ui/src/components/select.mjs +139 -0
  143. package/dist/ui/src/components/separator.cjs +43 -0
  144. package/dist/ui/src/components/separator.mjs +27 -0
  145. package/dist/ui/src/components/switch.cjs +48 -0
  146. package/dist/ui/src/components/switch.mjs +32 -0
  147. package/dist/ui/src/components/tabs.cjs +84 -0
  148. package/dist/ui/src/components/tabs.mjs +65 -0
  149. package/dist/ui/src/components/textarea.cjs +20 -0
  150. package/dist/ui/src/components/textarea.mjs +18 -0
  151. package/dist/ui/src/hooks/use-debounce.cjs +16 -0
  152. package/dist/ui/src/hooks/use-debounce.mjs +14 -0
  153. package/dist/ui/src/lib/schema-converter.cjs +94 -0
  154. package/dist/ui/src/lib/schema-converter.mjs +92 -0
  155. package/dist/ui/src/lib/throttle.cjs +56 -0
  156. package/dist/ui/src/lib/throttle.mjs +54 -0
  157. package/dist/ui/src/lib/utils.cjs +10 -0
  158. package/dist/ui/src/lib/utils.mjs +8 -0
  159. package/dist/ui.css +131 -0
  160. package/package.json +176 -3
  161. package/README.md +0 -3
@@ -0,0 +1,180 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const crepe = require('@milkdown/crepe');
6
+ require('@milkdown/crepe/theme/common/style.css');
7
+ require('../../../_private/ui/styles/markdown-editor.css');
8
+ const utils = require('../lib/utils.cjs');
9
+ const throttle = require('../lib/throttle.cjs');
10
+ const core = require('@milkdown/kit/core');
11
+ const listener = require('@milkdown/kit/plugin/listener');
12
+ const model = require('@milkdown/kit/prose/model');
13
+ const state = require('@milkdown/kit/prose/state');
14
+ const React = require('react');
15
+
16
+ function MarkdownEditor({
17
+ value,
18
+ onChange,
19
+ className,
20
+ uploadImage,
21
+ placeholder = "Write something...",
22
+ insertImageRef,
23
+ openMediaPickerForImageBlock
24
+ }) {
25
+ const containerRef = React.useRef(null);
26
+ const crepeRef = React.useRef(null);
27
+ const isReadyRef = React.useRef(false);
28
+ const [isReady, setIsReady] = React.useState(false);
29
+ const onChangeRef = React.useRef(onChange);
30
+ const initialValueRef = React.useRef(value ?? "");
31
+ const openMediaPickerRef = React.useRef(
32
+ openMediaPickerForImageBlock
33
+ );
34
+ const throttledOnChangeRef = React.useRef(null);
35
+ onChangeRef.current = onChange;
36
+ openMediaPickerRef.current = openMediaPickerForImageBlock;
37
+ React.useLayoutEffect(() => {
38
+ if (crepeRef.current) return;
39
+ const container = containerRef.current;
40
+ if (!container) return;
41
+ const hasMediaPicker = !!openMediaPickerRef.current;
42
+ const imageBlockConfig = {};
43
+ if (uploadImage) {
44
+ imageBlockConfig.onUpload = async (file) => uploadImage(file);
45
+ }
46
+ if (hasMediaPicker) {
47
+ imageBlockConfig.blockUploadPlaceholderText = "Media Picker";
48
+ imageBlockConfig.inlineUploadPlaceholderText = "Media Picker";
49
+ }
50
+ const crepe$1 = new crepe.Crepe({
51
+ root: container,
52
+ defaultValue: initialValueRef.current,
53
+ featureConfigs: {
54
+ [crepe.CrepeFeature.Placeholder]: {
55
+ text: placeholder
56
+ },
57
+ ...Object.keys(imageBlockConfig).length > 0 ? { [crepe.CrepeFeature.ImageBlock]: imageBlockConfig } : {}
58
+ }
59
+ });
60
+ const interceptHandler = (e) => {
61
+ if (!openMediaPickerRef.current) return;
62
+ const target = e.target;
63
+ const inPlaceholder = target.closest(".image-edit .placeholder");
64
+ if (!inPlaceholder) return;
65
+ if (target.matches("input")) return;
66
+ e.preventDefault();
67
+ e.stopPropagation();
68
+ const imageEdit = inPlaceholder.closest(".image-edit");
69
+ const linkInput = imageEdit?.querySelector(
70
+ ".link-input-area"
71
+ );
72
+ openMediaPickerRef.current((url) => {
73
+ if (!linkInput) return;
74
+ const nativeSetter = Object.getOwnPropertyDescriptor(
75
+ HTMLInputElement.prototype,
76
+ "value"
77
+ )?.set;
78
+ nativeSetter?.call(linkInput, url);
79
+ linkInput.dispatchEvent(new Event("input", { bubbles: true }));
80
+ linkInput.dispatchEvent(
81
+ new KeyboardEvent("keydown", { key: "Enter", bubbles: true })
82
+ );
83
+ });
84
+ };
85
+ container.addEventListener("click", interceptHandler, true);
86
+ throttledOnChangeRef.current = throttle.throttle((markdown) => {
87
+ if (onChangeRef.current) onChangeRef.current(markdown);
88
+ }, 200);
89
+ crepe$1.editor.config((ctx) => {
90
+ ctx.get(listener.listenerCtx).markdownUpdated((_, markdown) => {
91
+ throttledOnChangeRef.current?.(markdown);
92
+ });
93
+ ctx.get(listener.listenerCtx).blur(() => {
94
+ if (!isReadyRef.current) return;
95
+ throttledOnChangeRef.current?.cancel?.();
96
+ onChangeRef.current?.(crepe$1.getMarkdown());
97
+ });
98
+ }).use(listener.listener);
99
+ crepe$1.create().then(() => {
100
+ isReadyRef.current = true;
101
+ setIsReady(true);
102
+ });
103
+ crepeRef.current = crepe$1;
104
+ return () => {
105
+ container.removeEventListener("click", interceptHandler, true);
106
+ try {
107
+ isReadyRef.current = false;
108
+ throttledOnChangeRef.current?.cancel?.();
109
+ throttledOnChangeRef.current = null;
110
+ crepe$1.destroy();
111
+ } finally {
112
+ crepeRef.current = null;
113
+ }
114
+ };
115
+ }, []);
116
+ React.useLayoutEffect(() => {
117
+ if (!isReady) return;
118
+ if (!crepeRef.current) return;
119
+ if (typeof value !== "string") return;
120
+ let currentMarkdown;
121
+ try {
122
+ currentMarkdown = crepeRef.current?.getMarkdown?.();
123
+ } catch {
124
+ return;
125
+ }
126
+ if (currentMarkdown === value) return;
127
+ crepeRef.current.editor.action((ctx) => {
128
+ const view = ctx.get(core.editorViewCtx);
129
+ if (view?.hasFocus?.() === true) return;
130
+ const parser = ctx.get(core.parserCtx);
131
+ const doc = parser(value);
132
+ if (!doc) return;
133
+ const state$1 = view.state;
134
+ const selection = state$1.selection;
135
+ const from = selection.from;
136
+ let tr = state$1.tr;
137
+ tr = tr.replace(0, state$1.doc.content.size, new model.Slice(doc.content, 0, 0));
138
+ const docSize = doc.content.size;
139
+ const safeFrom = Math.max(1, Math.min(from, Math.max(1, docSize - 2)));
140
+ tr = tr.setSelection(state.Selection.near(tr.doc.resolve(safeFrom)));
141
+ view.dispatch(tr);
142
+ });
143
+ }, [value, isReady]);
144
+ React.useLayoutEffect(() => {
145
+ if (!insertImageRef) return;
146
+ insertImageRef.current = (url) => {
147
+ if (!crepeRef.current || !isReadyRef.current) return;
148
+ try {
149
+ const currentMarkdown = crepeRef.current.getMarkdown?.() ?? "";
150
+ const imageMarkdown = `
151
+
152
+ ![](${url})
153
+
154
+ `;
155
+ const newMarkdown = currentMarkdown.trimEnd() + imageMarkdown;
156
+ crepeRef.current.editor.action((ctx) => {
157
+ const view = ctx.get(core.editorViewCtx);
158
+ const parser = ctx.get(core.parserCtx);
159
+ const doc = parser(newMarkdown);
160
+ if (!doc) return;
161
+ const state = view.state;
162
+ const tr = state.tr.replace(
163
+ 0,
164
+ state.doc.content.size,
165
+ new model.Slice(doc.content, 0, 0)
166
+ );
167
+ view.dispatch(tr);
168
+ });
169
+ if (onChangeRef.current) onChangeRef.current(newMarkdown);
170
+ } catch {
171
+ }
172
+ };
173
+ return () => {
174
+ if (insertImageRef) insertImageRef.current = null;
175
+ };
176
+ }, [insertImageRef]);
177
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: utils.cn("milkdown-custom", className) });
178
+ }
179
+
180
+ exports.MarkdownEditor = MarkdownEditor;
@@ -0,0 +1,178 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { Crepe, CrepeFeature } from '@milkdown/crepe';
4
+ import '@milkdown/crepe/theme/common/style.css';
5
+ import '../../../_private/ui/styles/markdown-editor.css';
6
+ import { cn } from '../lib/utils.mjs';
7
+ import { throttle } from '../lib/throttle.mjs';
8
+ import { editorViewCtx, parserCtx } from '@milkdown/kit/core';
9
+ import { listenerCtx, listener } from '@milkdown/kit/plugin/listener';
10
+ import { Slice } from '@milkdown/kit/prose/model';
11
+ import { Selection } from '@milkdown/kit/prose/state';
12
+ import { useRef, useState, useLayoutEffect } from 'react';
13
+
14
+ function MarkdownEditor({
15
+ value,
16
+ onChange,
17
+ className,
18
+ uploadImage,
19
+ placeholder = "Write something...",
20
+ insertImageRef,
21
+ openMediaPickerForImageBlock
22
+ }) {
23
+ const containerRef = useRef(null);
24
+ const crepeRef = useRef(null);
25
+ const isReadyRef = useRef(false);
26
+ const [isReady, setIsReady] = useState(false);
27
+ const onChangeRef = useRef(onChange);
28
+ const initialValueRef = useRef(value ?? "");
29
+ const openMediaPickerRef = useRef(
30
+ openMediaPickerForImageBlock
31
+ );
32
+ const throttledOnChangeRef = useRef(null);
33
+ onChangeRef.current = onChange;
34
+ openMediaPickerRef.current = openMediaPickerForImageBlock;
35
+ useLayoutEffect(() => {
36
+ if (crepeRef.current) return;
37
+ const container = containerRef.current;
38
+ if (!container) return;
39
+ const hasMediaPicker = !!openMediaPickerRef.current;
40
+ const imageBlockConfig = {};
41
+ if (uploadImage) {
42
+ imageBlockConfig.onUpload = async (file) => uploadImage(file);
43
+ }
44
+ if (hasMediaPicker) {
45
+ imageBlockConfig.blockUploadPlaceholderText = "Media Picker";
46
+ imageBlockConfig.inlineUploadPlaceholderText = "Media Picker";
47
+ }
48
+ const crepe = new Crepe({
49
+ root: container,
50
+ defaultValue: initialValueRef.current,
51
+ featureConfigs: {
52
+ [CrepeFeature.Placeholder]: {
53
+ text: placeholder
54
+ },
55
+ ...Object.keys(imageBlockConfig).length > 0 ? { [CrepeFeature.ImageBlock]: imageBlockConfig } : {}
56
+ }
57
+ });
58
+ const interceptHandler = (e) => {
59
+ if (!openMediaPickerRef.current) return;
60
+ const target = e.target;
61
+ const inPlaceholder = target.closest(".image-edit .placeholder");
62
+ if (!inPlaceholder) return;
63
+ if (target.matches("input")) return;
64
+ e.preventDefault();
65
+ e.stopPropagation();
66
+ const imageEdit = inPlaceholder.closest(".image-edit");
67
+ const linkInput = imageEdit?.querySelector(
68
+ ".link-input-area"
69
+ );
70
+ openMediaPickerRef.current((url) => {
71
+ if (!linkInput) return;
72
+ const nativeSetter = Object.getOwnPropertyDescriptor(
73
+ HTMLInputElement.prototype,
74
+ "value"
75
+ )?.set;
76
+ nativeSetter?.call(linkInput, url);
77
+ linkInput.dispatchEvent(new Event("input", { bubbles: true }));
78
+ linkInput.dispatchEvent(
79
+ new KeyboardEvent("keydown", { key: "Enter", bubbles: true })
80
+ );
81
+ });
82
+ };
83
+ container.addEventListener("click", interceptHandler, true);
84
+ throttledOnChangeRef.current = throttle((markdown) => {
85
+ if (onChangeRef.current) onChangeRef.current(markdown);
86
+ }, 200);
87
+ crepe.editor.config((ctx) => {
88
+ ctx.get(listenerCtx).markdownUpdated((_, markdown) => {
89
+ throttledOnChangeRef.current?.(markdown);
90
+ });
91
+ ctx.get(listenerCtx).blur(() => {
92
+ if (!isReadyRef.current) return;
93
+ throttledOnChangeRef.current?.cancel?.();
94
+ onChangeRef.current?.(crepe.getMarkdown());
95
+ });
96
+ }).use(listener);
97
+ crepe.create().then(() => {
98
+ isReadyRef.current = true;
99
+ setIsReady(true);
100
+ });
101
+ crepeRef.current = crepe;
102
+ return () => {
103
+ container.removeEventListener("click", interceptHandler, true);
104
+ try {
105
+ isReadyRef.current = false;
106
+ throttledOnChangeRef.current?.cancel?.();
107
+ throttledOnChangeRef.current = null;
108
+ crepe.destroy();
109
+ } finally {
110
+ crepeRef.current = null;
111
+ }
112
+ };
113
+ }, []);
114
+ useLayoutEffect(() => {
115
+ if (!isReady) return;
116
+ if (!crepeRef.current) return;
117
+ if (typeof value !== "string") return;
118
+ let currentMarkdown;
119
+ try {
120
+ currentMarkdown = crepeRef.current?.getMarkdown?.();
121
+ } catch {
122
+ return;
123
+ }
124
+ if (currentMarkdown === value) return;
125
+ crepeRef.current.editor.action((ctx) => {
126
+ const view = ctx.get(editorViewCtx);
127
+ if (view?.hasFocus?.() === true) return;
128
+ const parser = ctx.get(parserCtx);
129
+ const doc = parser(value);
130
+ if (!doc) return;
131
+ const state = view.state;
132
+ const selection = state.selection;
133
+ const from = selection.from;
134
+ let tr = state.tr;
135
+ tr = tr.replace(0, state.doc.content.size, new Slice(doc.content, 0, 0));
136
+ const docSize = doc.content.size;
137
+ const safeFrom = Math.max(1, Math.min(from, Math.max(1, docSize - 2)));
138
+ tr = tr.setSelection(Selection.near(tr.doc.resolve(safeFrom)));
139
+ view.dispatch(tr);
140
+ });
141
+ }, [value, isReady]);
142
+ useLayoutEffect(() => {
143
+ if (!insertImageRef) return;
144
+ insertImageRef.current = (url) => {
145
+ if (!crepeRef.current || !isReadyRef.current) return;
146
+ try {
147
+ const currentMarkdown = crepeRef.current.getMarkdown?.() ?? "";
148
+ const imageMarkdown = `
149
+
150
+ ![](${url})
151
+
152
+ `;
153
+ const newMarkdown = currentMarkdown.trimEnd() + imageMarkdown;
154
+ crepeRef.current.editor.action((ctx) => {
155
+ const view = ctx.get(editorViewCtx);
156
+ const parser = ctx.get(parserCtx);
157
+ const doc = parser(newMarkdown);
158
+ if (!doc) return;
159
+ const state = view.state;
160
+ const tr = state.tr.replace(
161
+ 0,
162
+ state.doc.content.size,
163
+ new Slice(doc.content, 0, 0)
164
+ );
165
+ view.dispatch(tr);
166
+ });
167
+ if (onChangeRef.current) onChangeRef.current(newMarkdown);
168
+ } catch {
169
+ }
170
+ };
171
+ return () => {
172
+ if (insertImageRef) insertImageRef.current = null;
173
+ };
174
+ }, [insertImageRef]);
175
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("milkdown-custom", className) });
176
+ }
177
+
178
+ export { MarkdownEditor };