@lobehub/ui 1.156.4 → 1.157.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.
@@ -1,18 +1,19 @@
1
- import { type TextAreaRef } from 'antd/es/input/TextArea';
2
- import { type CSSProperties, type FocusEventHandler, type KeyboardEventHandler, type MouseEventHandler } from 'react';
3
- import { SyntaxHighlighterProps } from "../Highlighter/SyntaxHighlighter";
4
- export interface CodeEditorProps {
1
+ import { CSSProperties, FocusEventHandler, KeyboardEventHandler, MouseEventHandler, Ref } from 'react';
2
+ import { FlexboxProps } from 'react-layout-kit';
3
+ export interface CodeEditorProps extends Omit<FlexboxProps, 'onFocus' | 'onBlur' | 'onKeyUp' | 'onKeyDown' | 'onClick'> {
5
4
  autoFocus?: boolean;
6
- className?: string;
5
+ classNames?: {
6
+ highlight?: string;
7
+ textarea?: string;
8
+ };
7
9
  disabled?: boolean;
8
10
  fontSize?: number | string;
9
11
  form?: string;
10
12
  ignoreTabKey?: boolean;
11
13
  insertSpaces?: boolean;
12
- language: SyntaxHighlighterProps['language'];
14
+ language: string;
13
15
  maxLength?: number;
14
16
  minLength?: number;
15
- name?: string;
16
17
  onBlur?: FocusEventHandler<HTMLTextAreaElement>;
17
18
  onClick?: MouseEventHandler<HTMLTextAreaElement>;
18
19
  onFocus?: FocusEventHandler<HTMLTextAreaElement>;
@@ -20,16 +21,32 @@ export interface CodeEditorProps {
20
21
  onKeyUp?: KeyboardEventHandler<HTMLTextAreaElement>;
21
22
  onValueChange: (value: string) => void;
22
23
  placeholder?: string;
23
- preClassName?: string;
24
24
  readOnly?: boolean;
25
25
  required?: boolean;
26
- resize?: boolean;
27
26
  style?: CSSProperties;
27
+ styles?: {
28
+ highlight?: CSSProperties;
29
+ textarea?: CSSProperties;
30
+ };
28
31
  tabSize?: number;
29
- textareaClassName?: string;
30
32
  textareaId?: string;
31
- type?: 'ghost' | 'block' | 'pure';
32
33
  value: string;
34
+ variant?: 'ghost' | 'block' | 'pure';
33
35
  }
34
- declare const CodeEditor: import("react").ForwardRefExoticComponent<CodeEditorProps & import("react").RefAttributes<TextAreaRef>>;
35
- export default CodeEditor;
36
+ type Record = {
37
+ selectionEnd: number;
38
+ selectionStart: number;
39
+ value: string;
40
+ };
41
+ type History = {
42
+ offset: number;
43
+ stack: (Record & {
44
+ timestamp: number;
45
+ })[];
46
+ };
47
+ declare const Editor: import("react").ForwardRefExoticComponent<CodeEditorProps & import("react").RefAttributes<Ref<{
48
+ session: {
49
+ history: History;
50
+ };
51
+ } | null>>>;
52
+ export default Editor;
@@ -1,51 +1,414 @@
1
- 'use client';
2
-
3
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4
3
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
5
- var _excluded = ["style", "language", "value", "onValueChange", "resize", "className", "textareaClassName", "type", "fontSize"];
6
- import { forwardRef } from 'react';
7
- import Editor from 'react-simple-code-editor';
8
- import SyntaxHighlighter from "../Highlighter/SyntaxHighlighter";
4
+ var _excluded = ["autoFocus", "disabled", "form", "classNames", "styles", "ignoreTabKey", "insertSpaces", "maxLength", "minLength", "onBlur", "onClick", "onFocus", "onKeyDown", "onKeyUp", "onValueChange", "placeholder", "readOnly", "required", "style", "className", "tabSize", "textareaId", "value", "language", "fontSize", "variant"];
5
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
6
+ import { Flexbox } from 'react-layout-kit';
9
7
  import { useStyles } from "./style";
8
+ import SyntaxHighlighter from "../Highlighter/SyntaxHighlighter";
10
9
  import { jsx as _jsx } from "react/jsx-runtime";
11
- var CodeEditor = /*#__PURE__*/forwardRef(function (_ref, ref) {
12
- var style = _ref.style,
13
- language = _ref.language,
14
- value = _ref.value,
10
+ import { jsxs as _jsxs } from "react/jsx-runtime";
11
+ var KEYCODE_Y = 89;
12
+ var KEYCODE_Z = 90;
13
+ var KEYCODE_M = 77;
14
+ var KEYCODE_PARENS = 57;
15
+ var KEYCODE_BRACKETS = 219;
16
+ var KEYCODE_QUOTE = 222;
17
+ var KEYCODE_BACK_QUOTE = 192;
18
+ var HISTORY_LIMIT = 100;
19
+ var HISTORY_TIME_GAP = 3000;
20
+ var isWindows = typeof window !== 'undefined' && 'navigator' in window && /win/i.test(navigator.platform);
21
+ var isMacLike = typeof window !== 'undefined' && 'navigator' in window && /(mac|iphone|ipod|ipad)/i.test(navigator.platform);
22
+ var getLines = function getLines(text, position) {
23
+ return text.slice(0, Math.max(0, position)).split('\n');
24
+ };
25
+ var Editor = /*#__PURE__*/forwardRef(function (_ref, ref) {
26
+ var autoFocus = _ref.autoFocus,
27
+ disabled = _ref.disabled,
28
+ form = _ref.form,
29
+ _ref$classNames = _ref.classNames,
30
+ classNames = _ref$classNames === void 0 ? {} : _ref$classNames,
31
+ _ref$styles = _ref.styles,
32
+ s = _ref$styles === void 0 ? {} : _ref$styles,
33
+ _ref$ignoreTabKey = _ref.ignoreTabKey,
34
+ ignoreTabKey = _ref$ignoreTabKey === void 0 ? false : _ref$ignoreTabKey,
35
+ _ref$insertSpaces = _ref.insertSpaces,
36
+ insertSpaces = _ref$insertSpaces === void 0 ? true : _ref$insertSpaces,
37
+ maxLength = _ref.maxLength,
38
+ minLength = _ref.minLength,
39
+ onBlur = _ref.onBlur,
40
+ onClick = _ref.onClick,
41
+ onFocus = _ref.onFocus,
42
+ onKeyDown = _ref.onKeyDown,
43
+ onKeyUp = _ref.onKeyUp,
15
44
  onValueChange = _ref.onValueChange,
16
- _ref$resize = _ref.resize,
17
- resize = _ref$resize === void 0 ? true : _ref$resize,
45
+ placeholder = _ref.placeholder,
46
+ readOnly = _ref.readOnly,
47
+ required = _ref.required,
48
+ style = _ref.style,
18
49
  className = _ref.className,
19
- textareaClassName = _ref.textareaClassName,
20
- _ref$type = _ref.type,
21
- type = _ref$type === void 0 ? 'ghost' : _ref$type,
50
+ _ref$tabSize = _ref.tabSize,
51
+ tabSize = _ref$tabSize === void 0 ? 2 : _ref$tabSize,
52
+ textareaId = _ref.textareaId,
53
+ value = _ref.value,
54
+ language = _ref.language,
22
55
  _ref$fontSize = _ref.fontSize,
23
56
  fontSize = _ref$fontSize === void 0 ? 12 : _ref$fontSize,
57
+ _ref$variant = _ref.variant,
58
+ variant = _ref$variant === void 0 ? 'ghost' : _ref$variant,
24
59
  rest = _objectWithoutProperties(_ref, _excluded);
25
60
  var _useStyles = useStyles({
26
61
  fontSize: fontSize,
27
- resize: resize,
28
- type: type
62
+ variant: variant
29
63
  }),
30
64
  styles = _useStyles.styles,
31
65
  cx = _useStyles.cx;
32
- return /*#__PURE__*/_jsx("div", {
33
- className: cx(styles.container, className),
34
- style: style,
35
- children: /*#__PURE__*/_jsx(Editor, _objectSpread({
36
- className: styles.editor,
37
- highlight: function highlight(code) {
38
- return /*#__PURE__*/_jsx(SyntaxHighlighter, {
39
- language: language,
40
- children: code
66
+ var historyRef = useRef({
67
+ offset: -1,
68
+ stack: []
69
+ });
70
+ var inputRef = useRef(null);
71
+ var _useState = useState(true),
72
+ _useState2 = _slicedToArray(_useState, 2),
73
+ capture = _useState2[0],
74
+ setCapture = _useState2[1];
75
+ var recordChange = useCallback(function (record) {
76
+ var overwrite = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
77
+ var _historyRef$current = historyRef.current,
78
+ stack = _historyRef$current.stack,
79
+ offset = _historyRef$current.offset;
80
+ if (stack.length > 0 && offset > -1) {
81
+ // When something updates, drop the redo operations
82
+ historyRef.current.stack = stack.slice(0, offset + 1);
83
+
84
+ // Limit the number of operations to 100
85
+ var count = historyRef.current.stack.length;
86
+ if (count > HISTORY_LIMIT) {
87
+ var extras = count - HISTORY_LIMIT;
88
+ historyRef.current.stack = stack.slice(extras, count);
89
+ historyRef.current.offset = Math.max(historyRef.current.offset - extras, 0);
90
+ }
91
+ }
92
+ var timestamp = Date.now();
93
+ if (overwrite) {
94
+ var last = historyRef.current.stack[historyRef.current.offset];
95
+ if (last && timestamp - last.timestamp < HISTORY_TIME_GAP) {
96
+ var _getLines$pop, _getLines$pop2, _current$;
97
+ // A previous entry exists and was in short interval
98
+
99
+ // Match the last word in the line
100
+ var re = /[^\da-z]([\da-z]+)$/i;
101
+
102
+ // Get the previous line
103
+ var previous = (_getLines$pop = getLines(last.value, last.selectionStart).pop()) === null || _getLines$pop === void 0 ? void 0 : _getLines$pop.match(re);
104
+
105
+ // Get the current line
106
+ var current = (_getLines$pop2 = getLines(record.value, record.selectionStart).pop()) === null || _getLines$pop2 === void 0 ? void 0 : _getLines$pop2.match(re);
107
+ if (previous !== null && previous !== void 0 && previous[1] && current !== null && current !== void 0 && (_current$ = current[1]) !== null && _current$ !== void 0 && _current$.startsWith(previous[1])) {
108
+ // The last word of the previous line and current line match
109
+ // Overwrite previous entry so that undo will remove whole word
110
+ historyRef.current.stack[historyRef.current.offset] = _objectSpread(_objectSpread({}, record), {}, {
111
+ timestamp: timestamp
112
+ });
113
+ return;
114
+ }
115
+ }
116
+ }
117
+
118
+ // Add the new operation to the stack
119
+ historyRef.current.stack.push(_objectSpread(_objectSpread({}, record), {}, {
120
+ timestamp: timestamp
121
+ }));
122
+ historyRef.current.offset++;
123
+ }, []);
124
+ var recordCurrentState = useCallback(function () {
125
+ var input = inputRef.current;
126
+ if (!input) return;
127
+
128
+ // Save current state of the input
129
+ var value = input.value,
130
+ selectionStart = input.selectionStart,
131
+ selectionEnd = input.selectionEnd;
132
+ recordChange({
133
+ selectionEnd: selectionEnd,
134
+ selectionStart: selectionStart,
135
+ value: value
136
+ });
137
+ }, [recordChange]);
138
+ var updateInput = function updateInput(record) {
139
+ var input = inputRef.current;
140
+ if (!input) return;
141
+
142
+ // Update values and selection state
143
+ input.value = record.value;
144
+ input.selectionStart = record.selectionStart;
145
+ input.selectionEnd = record.selectionEnd;
146
+ onValueChange === null || onValueChange === void 0 || onValueChange(record.value);
147
+ };
148
+ var applyEdits = function applyEdits(record) {
149
+ // Save last selection state
150
+ var input = inputRef.current;
151
+ var last = historyRef.current.stack[historyRef.current.offset];
152
+ if (last && input) {
153
+ historyRef.current.stack[historyRef.current.offset] = _objectSpread(_objectSpread({}, last), {}, {
154
+ selectionEnd: input.selectionEnd,
155
+ selectionStart: input.selectionStart
156
+ });
157
+ }
158
+
159
+ // Save the changes
160
+ recordChange(record);
161
+ updateInput(record);
162
+ };
163
+ var undoEdit = function undoEdit() {
164
+ var _historyRef$current2 = historyRef.current,
165
+ stack = _historyRef$current2.stack,
166
+ offset = _historyRef$current2.offset;
167
+
168
+ // Get the previous edit
169
+ var record = stack[offset - 1];
170
+ if (record) {
171
+ // Apply the changes and update the offset
172
+ updateInput(record);
173
+ historyRef.current.offset = Math.max(offset - 1, 0);
174
+ }
175
+ };
176
+ var redoEdit = function redoEdit() {
177
+ var _historyRef$current3 = historyRef.current,
178
+ stack = _historyRef$current3.stack,
179
+ offset = _historyRef$current3.offset;
180
+
181
+ // Get the next edit
182
+ var record = stack[offset + 1];
183
+ if (record) {
184
+ // Apply the changes and update the offset
185
+ updateInput(record);
186
+ historyRef.current.offset = Math.min(offset + 1, stack.length - 1);
187
+ }
188
+ };
189
+ var handleKeyDown = function handleKeyDown(e) {
190
+ if (onKeyDown) {
191
+ onKeyDown(e);
192
+ if (e.defaultPrevented) {
193
+ return;
194
+ }
195
+ }
196
+ if (e.key === 'Escape') {
197
+ e.currentTarget.blur();
198
+ }
199
+ var _e$currentTarget = e.currentTarget,
200
+ value = _e$currentTarget.value,
201
+ selectionStart = _e$currentTarget.selectionStart,
202
+ selectionEnd = _e$currentTarget.selectionEnd;
203
+ var tabCharacter = (insertSpaces ? ' ' : '\t').repeat(tabSize);
204
+ if (e.key === 'Tab' && !ignoreTabKey && capture) {
205
+ // Prevent focus change
206
+ e.preventDefault();
207
+ if (e.shiftKey) {
208
+ // Unindent selected lines
209
+ var linesBeforeCaret = getLines(value, selectionStart);
210
+ var startLine = linesBeforeCaret.length - 1;
211
+ var endLine = getLines(value, selectionEnd).length - 1;
212
+ var nextValue = value.split('\n').map(function (line, i) {
213
+ if (i >= startLine && i <= endLine && line.startsWith(tabCharacter)) {
214
+ return line.slice(tabCharacter.length);
215
+ }
216
+ return line;
217
+ }).join('\n');
218
+ if (value !== nextValue) {
219
+ var startLineText = linesBeforeCaret[startLine];
220
+ applyEdits({
221
+ // Move the end cursor by total number of characters removed
222
+ selectionEnd: selectionEnd - (value.length - nextValue.length),
223
+ // Move the start cursor if first line in selection was modified
224
+ // It was modified only if it started with a tab
225
+ selectionStart: startLineText !== null && startLineText !== void 0 && startLineText.startsWith(tabCharacter) ? selectionStart - tabCharacter.length : selectionStart,
226
+ value: nextValue
227
+ });
228
+ }
229
+ } else if (selectionStart === selectionEnd) {
230
+ var updatedSelection = selectionStart + tabCharacter.length;
231
+ applyEdits({
232
+ selectionEnd: updatedSelection,
233
+ // Update caret position
234
+ selectionStart: updatedSelection,
235
+ // Insert tab character at caret
236
+ value: value.slice(0, Math.max(0, selectionStart)) + tabCharacter + value.slice(Math.max(0, selectionEnd))
41
237
  });
42
- },
43
- onValueChange: onValueChange,
44
- padding: 0,
45
- ref: ref,
46
- textareaClassName: cx(styles.textarea, textareaClassName),
238
+ } else {
239
+ // Indent selected lines
240
+ var _linesBeforeCaret = getLines(value, selectionStart);
241
+ var _startLine = _linesBeforeCaret.length - 1;
242
+ var _endLine = getLines(value, selectionEnd).length - 1;
243
+ var _startLineText = _linesBeforeCaret[_startLine];
244
+ applyEdits({
245
+ // Move the end cursor by total number of characters added
246
+ selectionEnd: selectionEnd + tabCharacter.length * (_endLine - _startLine + 1),
247
+ // Move the start cursor by number of characters added in first line of selection
248
+ // Don't move it if it there was no text before cursor
249
+ selectionStart: _startLineText && /\S/.test(_startLineText) ? selectionStart + tabCharacter.length : selectionStart,
250
+ value: value.split('\n').map(function (line, i) {
251
+ if (i >= _startLine && i <= _endLine) {
252
+ return tabCharacter + line;
253
+ }
254
+ return line;
255
+ }).join('\n')
256
+ });
257
+ }
258
+ } else if (e.key === 'Backspace') {
259
+ var hasSelection = selectionStart !== selectionEnd;
260
+ var textBeforeCaret = value.slice(0, Math.max(0, selectionStart));
261
+ if (textBeforeCaret.endsWith(tabCharacter) && !hasSelection) {
262
+ // Prevent default delete behaviour
263
+ e.preventDefault();
264
+ var _updatedSelection = selectionStart - tabCharacter.length;
265
+ applyEdits({
266
+ selectionEnd: _updatedSelection,
267
+ // Update caret position
268
+ selectionStart: _updatedSelection,
269
+ // Remove tab character at caret
270
+ value: value.slice(0, Math.max(0, selectionStart - tabCharacter.length)) + value.slice(Math.max(0, selectionEnd))
271
+ });
272
+ }
273
+ } else if (e.key === 'Enter') {
274
+ // Ignore selections
275
+ if (selectionStart === selectionEnd) {
276
+ // Get the current line
277
+ var line = getLines(value, selectionStart).pop();
278
+ var matches = line === null || line === void 0 ? void 0 : line.match(/^\s+/);
279
+ if (matches !== null && matches !== void 0 && matches[0]) {
280
+ e.preventDefault();
281
+
282
+ // Preserve indentation on inserting a new line
283
+ var indent = '\n' + matches[0];
284
+ var _updatedSelection2 = selectionStart + indent.length;
285
+ applyEdits({
286
+ selectionEnd: _updatedSelection2,
287
+ // Update caret position
288
+ selectionStart: _updatedSelection2,
289
+ // Insert indentation character at caret
290
+ value: value.slice(0, Math.max(0, selectionStart)) + indent + value.slice(Math.max(0, selectionEnd))
291
+ });
292
+ }
293
+ }
294
+ } else if (e.keyCode === KEYCODE_PARENS || e.keyCode === KEYCODE_BRACKETS || e.keyCode === KEYCODE_QUOTE || e.keyCode === KEYCODE_BACK_QUOTE) {
295
+ var chars;
296
+ if (e.keyCode === KEYCODE_PARENS && e.shiftKey) {
297
+ chars = ['(', ')'];
298
+ } else if (e.keyCode === KEYCODE_BRACKETS) {
299
+ chars = e.shiftKey ? ['{', '}'] : ['[', ']'];
300
+ } else if (e.keyCode === KEYCODE_QUOTE) {
301
+ chars = e.shiftKey ? ['"', '"'] : ["'", "'"];
302
+ } else if (e.keyCode === KEYCODE_BACK_QUOTE && !e.shiftKey) {
303
+ chars = ['`', '`'];
304
+ }
305
+
306
+ // If text is selected, wrap them in the characters
307
+ if (selectionStart !== selectionEnd && chars) {
308
+ e.preventDefault();
309
+ applyEdits({
310
+ selectionEnd: selectionEnd + 2,
311
+ // Update caret position
312
+ selectionStart: selectionStart,
313
+ value: value.slice(0, Math.max(0, selectionStart)) + chars[0] +
314
+ // eslint-disable-next-line unicorn/prefer-string-slice
315
+ value.substring(selectionStart, selectionEnd) + chars[1] + value.slice(Math.max(0, selectionEnd))
316
+ });
317
+ }
318
+ } else if ((isMacLike ?
319
+ // Trigger undo with ⌘+Z on Mac
320
+ e.metaKey && e.keyCode === KEYCODE_Z :
321
+ // Trigger undo with Ctrl+Z on other platforms
322
+ e.ctrlKey && e.keyCode === KEYCODE_Z) && !e.shiftKey && !e.altKey) {
323
+ e.preventDefault();
324
+ undoEdit();
325
+ } else if ((isMacLike ?
326
+ // Trigger redo with ⌘+Shift+Z on Mac
327
+ e.metaKey && e.keyCode === KEYCODE_Z && e.shiftKey : isWindows ?
328
+ // Trigger redo with Ctrl+Y on Windows
329
+ e.ctrlKey && e.keyCode === KEYCODE_Y :
330
+ // Trigger redo with Ctrl+Shift+Z on other platforms
331
+ e.ctrlKey && e.keyCode === KEYCODE_Z && e.shiftKey) && !e.altKey) {
332
+ e.preventDefault();
333
+ redoEdit();
334
+ } else if (e.keyCode === KEYCODE_M && e.ctrlKey && (isMacLike ? e.shiftKey : true)) {
335
+ e.preventDefault();
336
+
337
+ // Toggle capturing tab key so users can focus away
338
+ setCapture(function (prev) {
339
+ return !prev;
340
+ });
341
+ }
342
+ };
343
+ var handleChange = function handleChange(e) {
344
+ var _e$currentTarget2 = e.currentTarget,
345
+ value = _e$currentTarget2.value,
346
+ selectionStart = _e$currentTarget2.selectionStart,
347
+ selectionEnd = _e$currentTarget2.selectionEnd;
348
+ recordChange({
349
+ selectionEnd: selectionEnd,
350
+ selectionStart: selectionStart,
47
351
  value: value
48
- }, rest))
49
- });
352
+ }, true);
353
+ onValueChange(value);
354
+ };
355
+ useEffect(function () {
356
+ recordCurrentState();
357
+ }, [recordCurrentState]);
358
+
359
+ // @ts-ignore
360
+ useImperativeHandle(ref, function () {
361
+ return {
362
+ get session() {
363
+ return {
364
+ history: historyRef.current
365
+ };
366
+ },
367
+ set session(session) {
368
+ historyRef.current = session.history;
369
+ }
370
+ };
371
+ }, []);
372
+ return /*#__PURE__*/_jsx(Flexbox, _objectSpread(_objectSpread({
373
+ className: cx(styles.container, className),
374
+ style: style
375
+ }, rest), {}, {
376
+ children: /*#__PURE__*/_jsxs("div", {
377
+ className: styles.editor,
378
+ children: [/*#__PURE__*/_jsx(SyntaxHighlighter, {
379
+ className: cx(styles.highlight, classNames === null || classNames === void 0 ? void 0 : classNames.highlight),
380
+ language: language,
381
+ style: s.highlight,
382
+ children: value
383
+ }), /*#__PURE__*/_jsx("textarea", {
384
+ autoCapitalize: "off",
385
+ autoComplete: "off",
386
+ autoCorrect: "off",
387
+ autoFocus: autoFocus,
388
+ className: cx(styles.textarea, classNames === null || classNames === void 0 ? void 0 : classNames.textarea),
389
+ "data-gramm": false,
390
+ disabled: disabled,
391
+ form: form,
392
+ id: textareaId,
393
+ maxLength: maxLength,
394
+ minLength: minLength,
395
+ onBlur: onBlur,
396
+ onChange: handleChange,
397
+ onClick: onClick,
398
+ onFocus: onFocus,
399
+ onKeyDown: handleKeyDown,
400
+ onKeyUp: onKeyUp,
401
+ placeholder: placeholder,
402
+ readOnly: readOnly,
403
+ ref: function ref(c) {
404
+ return inputRef.current = c;
405
+ },
406
+ required: required,
407
+ spellCheck: false,
408
+ style: _objectSpread({}, s === null || s === void 0 ? void 0 : s.textarea),
409
+ value: value
410
+ })]
411
+ })
412
+ }));
50
413
  });
51
- export default CodeEditor;
414
+ export default Editor;
@@ -1,9 +1,9 @@
1
1
  export declare const useStyles: (props?: {
2
2
  fontSize: string | number;
3
- resize: boolean;
4
- type: 'ghost' | 'block' | 'pure';
3
+ variant: 'ghost' | 'block' | 'pure';
5
4
  } | undefined) => import("antd-style").ReturnStyles<{
6
5
  container: string;
7
6
  editor: import("antd-style").SerializedStyles;
7
+ highlight: import("antd-style").SerializedStyles;
8
8
  textarea: import("antd-style").SerializedStyles;
9
9
  }>;
@@ -1,19 +1,19 @@
1
1
  import _taggedTemplateLiteral from "@babel/runtime/helpers/esm/taggedTemplateLiteral";
2
- var _templateObject, _templateObject2, _templateObject3, _templateObject4;
2
+ var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5;
3
3
  import { createStyles } from 'antd-style';
4
4
  import { isNumber } from 'lodash-es';
5
5
  export var useStyles = createStyles(function (_ref, _ref2) {
6
6
  var cx = _ref.cx,
7
7
  css = _ref.css,
8
8
  token = _ref.token;
9
- var type = _ref2.type,
10
- resize = _ref2.resize,
9
+ var variant = _ref2.variant,
11
10
  fontSize = _ref2.fontSize;
12
11
  var size = isNumber(fontSize) ? "".concat(fontSize, "px") : fontSize;
13
- var typeStylish = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n padding-block: 8px;\n padding-inline: 12px;\n\n background-color: ", ";\n border: 1px solid ", ";\n border-radius: ", "px;\n\n transition:\n background-color 100ms ", ",\n border-color 200ms ", ";\n\n &:hover {\n background-color: ", ";\n border-color: ", ";\n }\n "])), type === 'block' ? token.colorFillTertiary : 'transparent', type === 'block' ? 'transparent' : token.colorBorderSecondary, token.borderRadius, token.motionEaseOut, token.motionEaseOut, type === 'block' ? token.colorFillSecondary : token.colorFillQuaternary, token.colorBorder);
12
+ var typeStylish = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n padding-block: 8px;\n padding-inline: 12px;\n\n background-color: ", ";\n border: 1px solid ", ";\n border-radius: ", "px;\n "])), variant === 'block' ? token.colorFillTertiary : 'transparent', variant === 'block' ? 'transparent' : token.colorBorderSecondary, token.borderRadius);
14
13
  return {
15
- container: cx(type !== 'pure' && typeStylish, css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n overflow: hidden auto;\n width: 100%;\n height: fit-content;\n\n * {\n font-size: ", " !important;\n line-height: 1.5 !important;\n }\n "])), size)),
16
- editor: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n resize: ", ";\n height: fit-content;\n min-height: 100%;\n font-family: ", " !important;\n\n textarea {\n min-height: 36px !important;\n }\n\n pre {\n min-height: 36px !important;\n word-break: break-all;\n word-wrap: break-word;\n white-space: pre-wrap;\n\n &.shiki {\n margin: 0;\n }\n }\n "])), resize ? 'vertical' : 'none', token.fontFamilyCode),
17
- textarea: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n overflow: hidden auto;\n\n height: 100% !important;\n\n color: transparent !important;\n word-break: break-all !important;\n word-wrap: break-word !important;\n\n caret-color: ", ";\n\n -webkit-text-fill-color: unset !important;\n\n &::placeholder {\n color: ", ";\n }\n\n &:focus {\n border: none !important;\n outline: none !important;\n box-shadow: none !important;\n }\n "])), token.colorText, token.colorTextQuaternary)
14
+ container: cx(variant !== 'pure' && typeStylish, css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n position: relative;\n overflow: hidden auto;\n width: 100%;\n "])))),
15
+ editor: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n position: relative;\n width: 100%;\n height: fit-content;\n\n * {\n font-family: ", " !important;\n font-size: ", " !important;\n line-height: 1.5 !important;\n word-break: break-all !important;\n word-wrap: break-word !important;\n white-space: pre-wrap !important;\n }\n "])), token.fontFamilyCode, size),
16
+ highlight: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n pointer-events: none;\n\n pre,\n code {\n overflow: hidden;\n }\n "]))),
17
+ textarea: css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n resize: none;\n\n position: absolute;\n inset-block-start: 0;\n inset-inline-start: 0;\n\n overflow: hidden;\n\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: 0;\n\n color: transparent !important;\n text-align: start;\n\n background: transparent;\n border: none;\n outline: none;\n caret-color: ", ";\n\n &::placeholder {\n color: ", ";\n }\n\n &:focus {\n border: none !important;\n outline: none !important;\n box-shadow: none !important;\n }\n "])), token.colorText, token.colorTextQuaternary)
18
18
  };
19
19
  });
@@ -18,7 +18,7 @@ var SyntaxHighlighter = /*#__PURE__*/memo(function (_ref) {
18
18
  cx = _useStyles.cx;
19
19
  var _useThemeMode = useThemeMode(),
20
20
  isDarkMode = _useThemeMode.isDarkMode;
21
- var _useHighlight = useHighlight(children.trim(), language, isDarkMode),
21
+ var _useHighlight = useHighlight(children, language, isDarkMode),
22
22
  data = _useHighlight.data,
23
23
  isLoading = _useHighlight.isLoading;
24
24
  return /*#__PURE__*/_jsxs(_Fragment, {
@@ -27,7 +27,7 @@ var SyntaxHighlighter = /*#__PURE__*/memo(function (_ref) {
27
27
  style: style,
28
28
  children: /*#__PURE__*/_jsx("pre", {
29
29
  children: /*#__PURE__*/_jsx("code", {
30
- children: children.trim()
30
+ children: children
31
31
  })
32
32
  })
33
33
  }) : /*#__PURE__*/_jsx("div", {
@@ -42,7 +42,7 @@ var MessageContent = /*#__PURE__*/memo(function (_ref) {
42
42
  onEditingChange: onEditingChange,
43
43
  openModal: mobile ? editing : undefined,
44
44
  text: text,
45
- value: message ? String(message).trim() : ''
45
+ value: message ? String(message) : ''
46
46
  });
47
47
  var messageContent = renderMessage ? renderMessage(content) : content;
48
48
  return /*#__PURE__*/_jsxs(Flexbox, {
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ import type { Pluggable } from 'unified';
3
+ import { type TypographyProps } from "../../Markdown/Typography";
4
+ export interface MdxProps extends Omit<TypographyProps, 'children'> {
5
+ children: string;
6
+ components?: any[];
7
+ enableImageGallery?: boolean;
8
+ enableLatex?: boolean;
9
+ enableMermaid?: boolean;
10
+ fallback?: ReactNode;
11
+ fullFeaturedCodeBlock?: boolean;
12
+ onDoubleClick?: () => void;
13
+ rehypePlugins?: Pluggable[];
14
+ remarkPlugins?: Pluggable[];
15
+ }
16
+ declare const Mdx: import("react").NamedExoticComponent<MdxProps>;
17
+ export default Mdx;
@@ -0,0 +1,135 @@
1
+ 'use client';
2
+
3
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
4
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
5
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
6
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
7
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
8
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
9
+ var _excluded = ["children", "className", "style", "fullFeaturedCodeBlock", "enableLatex", "enableMermaid", "rehypePlugins", "remarkPlugins", "components", "fallback"];
10
+ import { evaluate } from '@mdx-js/mdx';
11
+ import { memo, useEffect, useMemo, useState } from 'react';
12
+ import jsxDevRuntime from 'react/jsx-dev-runtime';
13
+ import jsxRuntime from 'react/jsx-runtime';
14
+ import rehypeKatex from 'rehype-katex';
15
+ import remarkGfm from 'remark-gfm';
16
+ import remarkMath from 'remark-math';
17
+ import Alert from "../../Alert";
18
+ import { Typography } from "../../Markdown/Typography";
19
+ import { escapeBrackets, escapeMhchem, fixMarkdownBold } from "../../Markdown/utils";
20
+ import mdxComponents from "../mdxComponents";
21
+ import CodeBlock from "../mdxComponents/CodeBlock";
22
+ import { jsx as _jsx } from "react/jsx-runtime";
23
+ var runtime = process.env.NODE_ENV === 'production' ? jsxRuntime : jsxDevRuntime;
24
+ var Mdx = /*#__PURE__*/memo(function (_ref) {
25
+ var children = _ref.children,
26
+ className = _ref.className,
27
+ style = _ref.style,
28
+ _ref$fullFeaturedCode = _ref.fullFeaturedCodeBlock,
29
+ fullFeaturedCodeBlock = _ref$fullFeaturedCode === void 0 ? true : _ref$fullFeaturedCode,
30
+ _ref$enableLatex = _ref.enableLatex,
31
+ enableLatex = _ref$enableLatex === void 0 ? true : _ref$enableLatex,
32
+ _ref$enableMermaid = _ref.enableMermaid,
33
+ enableMermaid = _ref$enableMermaid === void 0 ? true : _ref$enableMermaid,
34
+ rehypePlugins = _ref.rehypePlugins,
35
+ remarkPlugins = _ref.remarkPlugins,
36
+ _ref$components = _ref.components,
37
+ components = _ref$components === void 0 ? {} : _ref$components,
38
+ _ref$fallback = _ref.fallback,
39
+ fallback = _ref$fallback === void 0 ? null : _ref$fallback,
40
+ rest = _objectWithoutProperties(_ref, _excluded);
41
+ var _useState = useState(function () {
42
+ return function () {
43
+ return null;
44
+ };
45
+ }),
46
+ _useState2 = _slicedToArray(_useState, 2),
47
+ MDXContent = _useState2[0],
48
+ setMDXContent = _useState2[1];
49
+ var escapedContent = useMemo(function () {
50
+ if (!enableLatex) return fixMarkdownBold(children);
51
+ return fixMarkdownBold(escapeMhchem(escapeBrackets(children)));
52
+ }, [children, enableLatex]);
53
+ var innerRehypePlugins = Array.isArray(rehypePlugins) ? rehypePlugins : [rehypePlugins];
54
+ var memoRehypePlugins = useMemo(function () {
55
+ return [enableLatex && rehypeKatex].concat(_toConsumableArray(innerRehypePlugins)).filter(Boolean);
56
+ }, [enableLatex].concat(_toConsumableArray(innerRehypePlugins)));
57
+ var innerRemarkPlugins = Array.isArray(remarkPlugins) ? remarkPlugins : [remarkPlugins];
58
+ var memoRemarkPlugins = useMemo(function () {
59
+ return [remarkGfm, enableLatex && remarkMath].concat(_toConsumableArray(innerRemarkPlugins)).filter(Boolean);
60
+ }, [enableLatex].concat(_toConsumableArray(innerRemarkPlugins)));
61
+ var memoComponents = useMemo(function () {
62
+ var list = {};
63
+ Object.entries(_objectSpread(_objectSpread({}, mdxComponents), {}, {
64
+ pre: function pre(props) {
65
+ return /*#__PURE__*/_jsx(CodeBlock, _objectSpread(_objectSpread({}, props), {}, {
66
+ enableMermaid: enableMermaid,
67
+ fullFeatured: fullFeaturedCodeBlock
68
+ }));
69
+ }
70
+ }, components)).forEach(function (_ref2) {
71
+ var _ref3 = _slicedToArray(_ref2, 2),
72
+ key = _ref3[0],
73
+ Render = _ref3[1];
74
+ list[key] = function (props) {
75
+ return /*#__PURE__*/_jsx(Render, _objectSpread({}, props));
76
+ };
77
+ });
78
+ return list;
79
+ }, [components, enableMermaid, fullFeaturedCodeBlock]);
80
+ useEffect(function () {
81
+ _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
82
+ var _yield$evaluate, Content;
83
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
84
+ while (1) switch (_context.prev = _context.next) {
85
+ case 0:
86
+ _context.prev = 0;
87
+ _context.next = 3;
88
+ return evaluate(escapedContent, _objectSpread(_objectSpread({}, runtime), {}, {
89
+ development: process.env.NODE_ENV !== 'production',
90
+ rehypePlugins: memoRehypePlugins,
91
+ remarkPlugins: memoRemarkPlugins
92
+ }));
93
+ case 3:
94
+ _yield$evaluate = _context.sent;
95
+ Content = _yield$evaluate.default;
96
+ setMDXContent(function () {
97
+ return Content;
98
+ });
99
+ _context.next = 12;
100
+ break;
101
+ case 8:
102
+ _context.prev = 8;
103
+ _context.t0 = _context["catch"](0);
104
+ // @ts-ignore
105
+ setMDXContent(function () {
106
+ return function () {
107
+ return /*#__PURE__*/_jsx(Alert, {
108
+ description: String(_context.t0 === null || _context.t0 === void 0 ? void 0 : _context.t0.message),
109
+ message: 'Error compiling MDX',
110
+ style: {
111
+ width: '100%'
112
+ },
113
+ type: "error"
114
+ });
115
+ };
116
+ });
117
+ console.error('Error compiling MDX:', _context.t0);
118
+ case 12:
119
+ case "end":
120
+ return _context.stop();
121
+ }
122
+ }, _callee, null, [[0, 8]]);
123
+ }))();
124
+ }, [escapedContent, memoRehypePlugins, memoRemarkPlugins]);
125
+ if (!MDXContent) return fallback;
126
+ return /*#__PURE__*/_jsx(Typography, _objectSpread(_objectSpread({
127
+ className: className,
128
+ style: style
129
+ }, rest), {}, {
130
+ children: /*#__PURE__*/_jsx(MDXContent, {
131
+ components: memoComponents
132
+ })
133
+ }));
134
+ });
135
+ export default Mdx;
package/es/mdx/index.d.ts CHANGED
@@ -4,7 +4,9 @@ export { default as Card, type CardProps } from './Cards/Card';
4
4
  export { default as FileTree, type FileTreeProps } from './FileTree';
5
5
  export { default as File, type FileProps } from './FileTree/File';
6
6
  export { default as Folder, type FolderProps } from './FileTree/Folder';
7
+ export { default as Mdx, type MdxProps } from './Mdx';
7
8
  export { default as mdxComponents } from './mdxComponents';
9
+ export { default as CodeBlock } from './mdxComponents/CodeBlock';
8
10
  export { default as Image, type ImageProps } from './mdxComponents/Image';
9
11
  export { default as Link, type LinkProps } from './mdxComponents/Link';
10
12
  export { default as Pre, type PreProps, PreSingleLine } from './mdxComponents/Pre';
package/es/mdx/index.js CHANGED
@@ -4,7 +4,9 @@ export { default as Card } from "./Cards/Card";
4
4
  export { default as FileTree } from "./FileTree";
5
5
  export { default as File } from "./FileTree/File";
6
6
  export { default as Folder } from "./FileTree/Folder";
7
+ export { default as Mdx } from "./Mdx";
7
8
  export { default as mdxComponents } from "./mdxComponents";
9
+ export { default as CodeBlock } from "./mdxComponents/CodeBlock";
8
10
  export { default as Image } from "./mdxComponents/Image";
9
11
  export { default as Link } from "./mdxComponents/Link";
10
12
  export { default as Pre, PreSingleLine } from "./mdxComponents/Pre";
@@ -0,0 +1,10 @@
1
+ import { FC } from 'react';
2
+ import type { MermaidProps } from "../../Mermaid";
3
+ interface CodeBlockProps {
4
+ children: any;
5
+ enableMermaid?: boolean;
6
+ fullFeatured?: boolean;
7
+ mermaid?: MermaidProps;
8
+ }
9
+ declare const CodeBlock: FC<CodeBlockProps>;
10
+ export default CodeBlock;
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+
3
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
4
+ import { Pre, PreMermaid, PreSingleLine } from "../mdxComponents/Pre";
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ var countLines = function countLines(str) {
7
+ var regex = /\n/g;
8
+ var matches = str.match(regex);
9
+ return matches ? matches.length : 1;
10
+ };
11
+ var useCode = function useCode(raw) {
12
+ if (!raw) return;
13
+ var _raw$props = raw.props,
14
+ children = _raw$props.children,
15
+ className = _raw$props.className;
16
+ if (!children) return;
17
+ var content = Array.isArray(children) ? children[0] : children;
18
+ var lang = (className === null || className === void 0 ? void 0 : className.replace('language-', '')) || 'txt';
19
+ var isSingleLine = countLines(content) <= 1 && content.length <= 32;
20
+ return {
21
+ content: content,
22
+ isSingleLine: isSingleLine,
23
+ lang: lang
24
+ };
25
+ };
26
+ var CodeBlock = function CodeBlock(_ref) {
27
+ var children = _ref.children,
28
+ fullFeatured = _ref.fullFeatured,
29
+ enableMermaid = _ref.enableMermaid,
30
+ mermaid = _ref.mermaid;
31
+ var code = useCode(children);
32
+ if (!code) return;
33
+ if (enableMermaid && code.lang === 'mermaid') return /*#__PURE__*/_jsx(PreMermaid, _objectSpread(_objectSpread({
34
+ fullFeatured: fullFeatured
35
+ }, mermaid), {}, {
36
+ children: code.content
37
+ }));
38
+ if (code.isSingleLine) return /*#__PURE__*/_jsx(PreSingleLine, {
39
+ language: code.lang,
40
+ children: code.content
41
+ });
42
+ return /*#__PURE__*/_jsx(Pre, {
43
+ allowChangeLanguage: false,
44
+ fullFeatured: fullFeatured,
45
+ language: code.lang,
46
+ children: code.content
47
+ });
48
+ };
49
+ export default CodeBlock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/ui",
3
- "version": "1.156.4",
3
+ "version": "1.157.0",
4
4
  "description": "Lobe UI is an open-source UI component library for building AIGC web apps",
5
5
  "keywords": [
6
6
  "lobehub",
@@ -97,6 +97,8 @@
97
97
  "@floating-ui/react": "^0.26.28",
98
98
  "@giscus/react": "^3.0.0",
99
99
  "@lobehub/fluent-emoji": "^1.0.1",
100
+ "@mdx-js/mdx": "^2.3.0",
101
+ "@mdx-js/react": "^2.3.0",
100
102
  "@radix-ui/react-slot": "^1.1.0",
101
103
  "@react-spring/web": "^9.7.5",
102
104
  "@shikijs/transformers": "^1.24.0",