@gravity-ui/markdown-editor 13.23.0 → 13.24.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 (28) hide show
  1. package/build/cjs/bundle/MarkdownEditorView.css +1 -0
  2. package/build/cjs/bundle/MarkdownEditorView.d.ts +4 -0
  3. package/build/cjs/bundle/MarkdownEditorView.js +10 -2
  4. package/build/cjs/extensions/yfm/Math/commands.d.ts +6 -2
  5. package/build/cjs/extensions/yfm/Math/commands.js +33 -7
  6. package/build/cjs/extensions/yfm/Math/index.js +1 -1
  7. package/build/cjs/extensions/yfm/Math/view-and-edit.js +4 -4
  8. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +6 -6
  9. package/build/cjs/extensions/yfm/YfmCut/actions/toYfmCut.js +1 -1
  10. package/build/cjs/extensions/yfm/YfmCut/index.css +12 -0
  11. package/build/cjs/extensions/yfm/YfmCut/nodeviews/yfm-cut-title.js +2 -1
  12. package/build/cjs/extensions/yfm/YfmCut/plugins/auto-open.js +3 -1
  13. package/build/cjs/version.js +1 -1
  14. package/build/esm/bundle/MarkdownEditorView.css +1 -0
  15. package/build/esm/bundle/MarkdownEditorView.d.ts +4 -0
  16. package/build/esm/bundle/MarkdownEditorView.js +10 -2
  17. package/build/esm/extensions/yfm/Math/commands.d.ts +6 -2
  18. package/build/esm/extensions/yfm/Math/commands.js +30 -5
  19. package/build/esm/extensions/yfm/Math/index.js +2 -2
  20. package/build/esm/extensions/yfm/Math/view-and-edit.js +6 -5
  21. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +6 -6
  22. package/build/esm/extensions/yfm/YfmCut/actions/toYfmCut.js +1 -1
  23. package/build/esm/extensions/yfm/YfmCut/index.css +12 -0
  24. package/build/esm/extensions/yfm/YfmCut/nodeviews/yfm-cut-title.js +2 -1
  25. package/build/esm/extensions/yfm/YfmCut/plugins/auto-open.js +3 -1
  26. package/build/esm/version.js +1 -1
  27. package/build/styles.css +13 -0
  28. package/package.json +3 -3
@@ -1,6 +1,7 @@
1
1
  .g-md-editor-component {
2
2
  display: flex;
3
3
  height: 100%;
4
+ outline: none;
4
5
  }
5
6
  .g-md-editor-component_split_vertical {
6
7
  display: grid;
@@ -15,6 +15,8 @@ export declare type MarkdownEditorViewProps = ClassNameProps & {
15
15
  settingsVisible?: boolean;
16
16
  toaster: ToasterPublicMethods;
17
17
  stickyToolbar: boolean;
18
+ enableSubmitInPreview?: boolean;
19
+ hidePreviewAfterSubmit?: boolean;
18
20
  };
19
21
  export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNameProps & {
20
22
  editor?: Editor | undefined;
@@ -27,4 +29,6 @@ export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNa
27
29
  settingsVisible?: boolean | undefined;
28
30
  toaster: ToasterPublicMethods;
29
31
  stickyToolbar: boolean;
32
+ enableSubmitInPreview?: boolean | undefined;
33
+ hidePreviewAfterSubmit?: boolean | undefined;
30
34
  } & React.RefAttributes<HTMLDivElement>>;
@@ -33,7 +33,7 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
33
33
  const editor = ((_a = props.editor) !== null && _a !== void 0 ? _a : context);
34
34
  if (!editor)
35
35
  throw new Error('[MarkdownEditorView]: an instance of the editor must be passed through the props or context');
36
- const { autofocus, className, settingsVisible = true, markupToolbarConfig = config_1.mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = config_1.wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = config_1.mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = config_1.wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, } = props;
36
+ const { autofocus, className, settingsVisible = true, markupToolbarConfig = config_1.mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = config_1.wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = config_1.mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = config_1.wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, enableSubmitInPreview = true, hidePreviewAfterSubmit = false, } = props;
37
37
  const rerender = (0, react_use_1.useUpdate)();
38
38
  react_1.default.useLayoutEffect(() => {
39
39
  editor.on('rerender', rerender);
@@ -68,7 +68,15 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
68
68
  divRef.current.focus();
69
69
  }
70
70
  }, [divRef, showPreview]);
71
- (0, react_use_1.useKey)((e) => showPreview && isWrapperFocused(divRef) && isSubmitKeyDown(e), () => editor.emit('submit', null), { event: 'keydown' }, [showPreview]);
71
+ (0, react_use_1.useKey)((e) => enableSubmitInPreview &&
72
+ showPreview &&
73
+ isWrapperFocused(divRef) &&
74
+ isSubmitKeyDown(e), () => {
75
+ editor.emit('submit', null);
76
+ if (hidePreviewAfterSubmit) {
77
+ onShowPreviewChange(false);
78
+ }
79
+ }, { event: 'keydown' }, [hidePreviewAfterSubmit, enableSubmitInPreview, showPreview, showPreview]);
72
80
  const settings = (0, react_1.useMemo)(() => (react_1.default.createElement(Settings, { mode: editorMode, onModeChange: onModeChange, toolbarVisibility: editor.toolbarVisible && !showPreview, onToolbarVisibilityChange: onToolbarVisibilityChange, onSplitModeChange: onSplitModeChange, splitModeEnabled: editor.splitModeEnabled, splitMode: editor.splitMode, stickyToolbar: stickyToolbar, onShowPreviewChange: onShowPreviewChange, showPreview: showPreview, renderPreviewButton: canRenderPreview })), [
73
81
  canRenderPreview,
74
82
  stickyToolbar,
@@ -7,6 +7,10 @@ export declare const ignoreIfCursorInsideMathInline: Command;
7
7
  */
8
8
  export declare const removeEmptyMathInlineIfCursorIsAtBeginning: Command;
9
9
  /**
10
- * If MathInline is before cursor move cursor to the end of the math
10
+ * Handle cursor movement to the right at the boundary of a MathInline block
11
11
  */
12
- export declare const moveCursorToEndOfMathInline: Command;
12
+ export declare const moveCursorRightOfMathInline: Command;
13
+ /**
14
+ * Handle cursor movement to the left at the boundary of a MathInline block
15
+ */
16
+ export declare const moveCursorLeftOfMathInline: Command;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.moveCursorToEndOfMathInline = exports.removeEmptyMathInlineIfCursorIsAtBeginning = exports.ignoreIfCursorInsideMathInline = void 0;
3
+ exports.moveCursorLeftOfMathInline = exports.moveCursorRightOfMathInline = exports.removeEmptyMathInlineIfCursorIsAtBeginning = exports.ignoreIfCursorInsideMathInline = void 0;
4
4
  const prosemirror_state_1 = require("prosemirror-state");
5
5
  const selection_1 = require("../../../utils/selection");
6
6
  const const_1 = require("./const");
@@ -30,15 +30,41 @@ const removeEmptyMathInlineIfCursorIsAtBeginning = ({ tr, schema }, dispatch) =>
30
30
  };
31
31
  exports.removeEmptyMathInlineIfCursorIsAtBeginning = removeEmptyMathInlineIfCursorIsAtBeginning;
32
32
  /**
33
- * If MathInline is before cursor move cursor to the end of the math
33
+ * Handle cursor movement to the right at the boundary of a MathInline block
34
34
  */
35
- const moveCursorToEndOfMathInline = ({ tr, schema }, dispatch) => {
35
+ const moveCursorRightOfMathInline = ({ tr, schema }, dispatch) => {
36
36
  var _a;
37
37
  const $cursor = (0, selection_1.get$Cursor)(tr.selection);
38
- if (((_a = $cursor === null || $cursor === void 0 ? void 0 : $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === (0, const_1.mathIType)(schema)) {
39
- dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, $cursor.pos - 1)));
40
- return true;
38
+ if ($cursor) {
39
+ const mathType = (0, const_1.mathIType)(schema);
40
+ const isOnBeforeOfMathInline = ((_a = $cursor.nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === mathType;
41
+ const isOnEndOfMathInline = $cursor.parentOffset === $cursor.parent.content.size &&
42
+ $cursor.parent.type === mathType;
43
+ if (isOnBeforeOfMathInline || isOnEndOfMathInline) {
44
+ const newPos = $cursor.pos + 1;
45
+ dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, newPos)));
46
+ return true;
47
+ }
48
+ }
49
+ return false;
50
+ };
51
+ exports.moveCursorRightOfMathInline = moveCursorRightOfMathInline;
52
+ /**
53
+ * Handle cursor movement to the left at the boundary of a MathInline block
54
+ */
55
+ const moveCursorLeftOfMathInline = ({ tr, schema }, dispatch) => {
56
+ var _a;
57
+ const $cursor = (0, selection_1.get$Cursor)(tr.selection);
58
+ if ($cursor) {
59
+ const mathType = (0, const_1.mathIType)(schema);
60
+ const isOnAfterOfMathInline = ((_a = $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === mathType;
61
+ const isOnStartOfMathInline = $cursor.parentOffset === 0 && $cursor.parent.type === mathType;
62
+ if (isOnAfterOfMathInline || isOnStartOfMathInline) {
63
+ const newPos = $cursor.pos - 1;
64
+ dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, newPos)));
65
+ return true;
66
+ }
41
67
  }
42
68
  return false;
43
69
  };
44
- exports.moveCursorToEndOfMathInline = moveCursorToEndOfMathInline;
70
+ exports.moveCursorLeftOfMathInline = moveCursorLeftOfMathInline;
@@ -24,7 +24,7 @@ const Math = (builder, opts) => {
24
24
  builder.use(MathSpecs_1.MathSpecs);
25
25
  builder.addKeymap(() => ({
26
26
  Enter: commands_1.ignoreIfCursorInsideMathInline,
27
- Backspace: (0, prosemirror_commands_1.chainCommands)(commands_1.moveCursorToEndOfMathInline, commands_1.removeEmptyMathInlineIfCursorIsAtBeginning),
27
+ Backspace: (0, prosemirror_commands_1.chainCommands)(commands_1.removeEmptyMathInlineIfCursorIsAtBeginning, commands_1.moveCursorLeftOfMathInline),
28
28
  }));
29
29
  builder
30
30
  .addPlugin(() => (0, view_and_edit_1.mathViewAndEditPlugin)(Object.assign(Object.assign({}, opts), { reactRenderer: builder.context.get('reactrenderer') })))
@@ -8,7 +8,6 @@ const selection_1 = require("../../../utils/selection");
8
8
  const commands_1 = require("./commands");
9
9
  const const_1 = require("./const");
10
10
  const hint_1 = require("./hint");
11
- // eslint-disable-line import/order
12
11
  const MATH_ACTIVE_DECO = 'math_active_decoration';
13
12
  class MathNodeView {
14
13
  constructor(node, opts) {
@@ -162,13 +161,14 @@ class MathBlockNodeView extends MathNodeView {
162
161
  exports.MathBlockNodeView = MathBlockNodeView;
163
162
  const mathViewAndEditPlugin = (options) => new prosemirror_state_1.Plugin({
164
163
  props: {
164
+ handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
165
+ ArrowRight: commands_1.moveCursorRightOfMathInline,
166
+ ArrowLeft: commands_1.moveCursorLeftOfMathInline,
167
+ }),
165
168
  nodeViews: {
166
169
  [const_1.MathNode.Block]: (node) => new MathBlockNodeView(node, options),
167
170
  [const_1.MathNode.Inline]: (node) => new MathInlineNodeView(node, options),
168
171
  },
169
- handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
170
- ArrowLeft: commands_1.moveCursorToEndOfMathInline,
171
- }),
172
172
  decorations: (state) => {
173
173
  const { selection } = state;
174
174
  if ((0, selection_1.isTextSelection)(selection)) {
@@ -10,12 +10,12 @@ const getSchemaSpecs = (opts, placeholder) => {
10
10
  var _a, _b, _c, _d;
11
11
  return ({
12
12
  [const_1.CutNode.Cut]: {
13
- attrs: { class: { default: 'yfm-cut' } },
13
+ attrs: { class: { default: 'yfm-cut' }, open: { default: null } },
14
14
  content: `${const_1.CutNode.CutTitle} ${const_1.CutNode.CutContent}`,
15
15
  group: 'block yfm-cut',
16
- parseDOM: [{ tag: 'div.yfm-cut' }],
16
+ parseDOM: [{ tag: '.yfm-cut' }],
17
17
  toDOM(node) {
18
- return ['div', node.attrs, 0];
18
+ return ['details', node.attrs, 0];
19
19
  },
20
20
  selectable: true,
21
21
  allowSelection: true,
@@ -26,9 +26,9 @@ const getSchemaSpecs = (opts, placeholder) => {
26
26
  attrs: { class: { default: 'yfm-cut-title' } },
27
27
  content: 'inline*',
28
28
  group: 'block yfm-cut',
29
- parseDOM: [{ tag: 'div.yfm-cut-title' }],
29
+ parseDOM: [{ tag: '.yfm-cut-title' }],
30
30
  toDOM(node) {
31
- return ['div', node.attrs, 0];
31
+ return ['summary', node.attrs, 0];
32
32
  },
33
33
  placeholder: {
34
34
  content: (_b = (_a = placeholder === null || placeholder === void 0 ? void 0 : placeholder[const_1.CutNode.CutTitle]) !== null && _a !== void 0 ? _a : opts === null || opts === void 0 ? void 0 : opts.yfmCutTitlePlaceholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDERS.Title,
@@ -43,7 +43,7 @@ const getSchemaSpecs = (opts, placeholder) => {
43
43
  attrs: { class: { default: 'yfm-cut-content' } },
44
44
  content: '(block | paragraph)+',
45
45
  group: 'block yfm-cut',
46
- parseDOM: [{ tag: 'div.yfm-cut-content' }],
46
+ parseDOM: [{ tag: '.yfm-cut-content' }],
47
47
  toDOM(node) {
48
48
  return ['div', node.attrs, 0];
49
49
  },
@@ -5,7 +5,7 @@ const prosemirror_state_1 = require("prosemirror-state");
5
5
  const prosemirror_utils_1 = require("prosemirror-utils");
6
6
  const const_1 = require("../const");
7
7
  const createYfmCutNode = (schema) => (content) => {
8
- return (0, const_1.cutType)(schema).create({ class: 'yfm-cut open' }, [
8
+ return (0, const_1.cutType)(schema).create({ class: 'yfm-cut open', open: true }, [
9
9
  (0, const_1.cutTitleType)(schema).create(null),
10
10
  (0, const_1.cutContentType)(schema).create(null, content),
11
11
  ]);
@@ -1,10 +1,22 @@
1
1
  .ProseMirror.yfm .yfm-cut {
2
2
  border: 1px dashed transparent;
3
3
  border-radius: var(--g-border-radius-s);
4
+ /* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
5
+ /* This ensures backward compatibility with earlier versions of cut-extension */
4
6
  }
5
7
  .ProseMirror.yfm .yfm-cut:hover {
6
8
  border-color: var(--g-color-line-generic);
7
9
  }
8
10
  .ProseMirror.yfm .yfm-cut.yfm-cut-active {
9
11
  border-color: var(--g-color-line-generic);
12
+ }
13
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
14
+ outline: 0;
15
+ }
16
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title {
17
+ list-style: none;
18
+ }
19
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
20
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
21
+ display: none;
10
22
  }
@@ -4,7 +4,7 @@ exports.YfmCutTitleNodeView = void 0;
4
4
  class YfmCutTitleNodeView {
5
5
  constructor(node) {
6
6
  this.node = node;
7
- this.dom = document.createElement('div');
7
+ this.dom = document.createElement('summary');
8
8
  this.dom.classList.add('yfm-cut-title');
9
9
  this.dom.replaceChildren((this.contentDOM = document.createElement('div')));
10
10
  this.contentDOM.classList.add('g-md-yfm-cut-title-inner');
@@ -12,6 +12,7 @@ class YfmCutTitleNodeView {
12
12
  // ignore clicking on the title content
13
13
  // you can open/close yfm-cut by clicking on the arrow icon
14
14
  e.stopPropagation();
15
+ e.preventDefault();
15
16
  });
16
17
  }
17
18
  update(node) {
@@ -42,6 +42,7 @@ function openParentYfmCuts($pos, domAtPos) {
42
42
  if ($pos.node(depth - 1).type === (0, const_1.cutType)(schema)) {
43
43
  const { node: cutDomNode } = domAtPos($pos.start(depth - 1), 0);
44
44
  cutDomNode.classList.add('open');
45
+ cutDomNode.setAttribute('open', 'true');
45
46
  depth--;
46
47
  }
47
48
  }
@@ -89,9 +90,10 @@ class CutAutoOpenOnDragOver {
89
90
  this._timeout = setTimeout(this._openCut.bind(this), CutAutoOpenOnDragOver.OPEN_TIMEOUT);
90
91
  }
91
92
  _openCut() {
92
- var _a;
93
+ var _a, _b;
93
94
  if (this._editorView.dragging) {
94
95
  (_a = this._cutElem) === null || _a === void 0 ? void 0 : _a.classList.add('open');
96
+ (_b = this._cutElem) === null || _b === void 0 ? void 0 : _b.setAttribute('open', 'true');
95
97
  }
96
98
  this._clear();
97
99
  }
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  /** During build process, the current version will be injected here */
5
- exports.VERSION = typeof '13.23.0' !== 'undefined' ? '13.23.0' : 'unknown';
5
+ exports.VERSION = typeof '13.24.0' !== 'undefined' ? '13.24.0' : 'unknown';
@@ -1,6 +1,7 @@
1
1
  .g-md-editor-component {
2
2
  display: flex;
3
3
  height: 100%;
4
+ outline: none;
4
5
  }
5
6
  .g-md-editor-component_split_vertical {
6
7
  display: grid;
@@ -17,6 +17,8 @@ export declare type MarkdownEditorViewProps = ClassNameProps & {
17
17
  settingsVisible?: boolean;
18
18
  toaster: ToasterPublicMethods;
19
19
  stickyToolbar: boolean;
20
+ enableSubmitInPreview?: boolean;
21
+ hidePreviewAfterSubmit?: boolean;
20
22
  };
21
23
  export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNameProps & {
22
24
  editor?: Editor | undefined;
@@ -29,4 +31,6 @@ export declare const MarkdownEditorView: React.ForwardRefExoticComponent<ClassNa
29
31
  settingsVisible?: boolean | undefined;
30
32
  toaster: ToasterPublicMethods;
31
33
  stickyToolbar: boolean;
34
+ enableSubmitInPreview?: boolean | undefined;
35
+ hidePreviewAfterSubmit?: boolean | undefined;
32
36
  } & React.RefAttributes<HTMLDivElement>>;
@@ -30,7 +30,7 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
30
30
  const editor = ((_a = props.editor) !== null && _a !== void 0 ? _a : context);
31
31
  if (!editor)
32
32
  throw new Error('[MarkdownEditorView]: an instance of the editor must be passed through the props or context');
33
- const { autofocus, className, settingsVisible = true, markupToolbarConfig = mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, } = props;
33
+ const { autofocus, className, settingsVisible = true, markupToolbarConfig = mToolbarConfigByPreset[editor.preset], wysiwygToolbarConfig = wToolbarConfigByPreset[editor.preset], markupHiddenActionsConfig = mHiddenDataByPreset[editor.preset], wysiwygHiddenActionsConfig = wHiddenDataByPreset[editor.preset], toaster, stickyToolbar, enableSubmitInPreview = true, hidePreviewAfterSubmit = false, } = props;
34
34
  const rerender = useUpdate();
35
35
  React.useLayoutEffect(() => {
36
36
  editor.on('rerender', rerender);
@@ -65,7 +65,15 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
65
65
  divRef.current.focus();
66
66
  }
67
67
  }, [divRef, showPreview]);
68
- useKey((e) => showPreview && isWrapperFocused(divRef) && isSubmitKeyDown(e), () => editor.emit('submit', null), { event: 'keydown' }, [showPreview]);
68
+ useKey((e) => enableSubmitInPreview &&
69
+ showPreview &&
70
+ isWrapperFocused(divRef) &&
71
+ isSubmitKeyDown(e), () => {
72
+ editor.emit('submit', null);
73
+ if (hidePreviewAfterSubmit) {
74
+ onShowPreviewChange(false);
75
+ }
76
+ }, { event: 'keydown' }, [hidePreviewAfterSubmit, enableSubmitInPreview, showPreview, showPreview]);
69
77
  const settings = useMemo(() => (React.createElement(Settings, { mode: editorMode, onModeChange: onModeChange, toolbarVisibility: editor.toolbarVisible && !showPreview, onToolbarVisibilityChange: onToolbarVisibilityChange, onSplitModeChange: onSplitModeChange, splitModeEnabled: editor.splitModeEnabled, splitMode: editor.splitMode, stickyToolbar: stickyToolbar, onShowPreviewChange: onShowPreviewChange, showPreview: showPreview, renderPreviewButton: canRenderPreview })), [
70
78
  canRenderPreview,
71
79
  stickyToolbar,
@@ -7,6 +7,10 @@ export declare const ignoreIfCursorInsideMathInline: Command;
7
7
  */
8
8
  export declare const removeEmptyMathInlineIfCursorIsAtBeginning: Command;
9
9
  /**
10
- * If MathInline is before cursor move cursor to the end of the math
10
+ * Handle cursor movement to the right at the boundary of a MathInline block
11
11
  */
12
- export declare const moveCursorToEndOfMathInline: Command;
12
+ export declare const moveCursorRightOfMathInline: Command;
13
+ /**
14
+ * Handle cursor movement to the left at the boundary of a MathInline block
15
+ */
16
+ export declare const moveCursorLeftOfMathInline: Command;
@@ -25,14 +25,39 @@ export const removeEmptyMathInlineIfCursorIsAtBeginning = ({ tr, schema }, dispa
25
25
  return false;
26
26
  };
27
27
  /**
28
- * If MathInline is before cursor move cursor to the end of the math
28
+ * Handle cursor movement to the right at the boundary of a MathInline block
29
29
  */
30
- export const moveCursorToEndOfMathInline = ({ tr, schema }, dispatch) => {
30
+ export const moveCursorRightOfMathInline = ({ tr, schema }, dispatch) => {
31
31
  var _a;
32
32
  const $cursor = get$Cursor(tr.selection);
33
- if (((_a = $cursor === null || $cursor === void 0 ? void 0 : $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === mathIType(schema)) {
34
- dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(TextSelection.create(tr.doc, $cursor.pos - 1)));
35
- return true;
33
+ if ($cursor) {
34
+ const mathType = mathIType(schema);
35
+ const isOnBeforeOfMathInline = ((_a = $cursor.nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === mathType;
36
+ const isOnEndOfMathInline = $cursor.parentOffset === $cursor.parent.content.size &&
37
+ $cursor.parent.type === mathType;
38
+ if (isOnBeforeOfMathInline || isOnEndOfMathInline) {
39
+ const newPos = $cursor.pos + 1;
40
+ dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(TextSelection.create(tr.doc, newPos)));
41
+ return true;
42
+ }
43
+ }
44
+ return false;
45
+ };
46
+ /**
47
+ * Handle cursor movement to the left at the boundary of a MathInline block
48
+ */
49
+ export const moveCursorLeftOfMathInline = ({ tr, schema }, dispatch) => {
50
+ var _a;
51
+ const $cursor = get$Cursor(tr.selection);
52
+ if ($cursor) {
53
+ const mathType = mathIType(schema);
54
+ const isOnAfterOfMathInline = ((_a = $cursor.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === mathType;
55
+ const isOnStartOfMathInline = $cursor.parentOffset === 0 && $cursor.parent.type === mathType;
56
+ if (isOnAfterOfMathInline || isOnStartOfMathInline) {
57
+ const newPos = $cursor.pos - 1;
58
+ dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr.setSelection(TextSelection.create(tr.doc, newPos)));
59
+ return true;
60
+ }
36
61
  }
37
62
  return false;
38
63
  };
@@ -4,7 +4,7 @@ import { hasParentNodeOfType } from 'prosemirror-utils';
4
4
  import { inlineNodeInputRule, textblockTypeInputRule } from '../../../utils/inputrules';
5
5
  import { isTextSelection } from '../../../utils/selection';
6
6
  import { MathSpecs } from './MathSpecs';
7
- import { ignoreIfCursorInsideMathInline, moveCursorToEndOfMathInline, removeEmptyMathInlineIfCursorIsAtBeginning, } from './commands';
7
+ import { ignoreIfCursorInsideMathInline, moveCursorLeftOfMathInline, removeEmptyMathInlineIfCursorIsAtBeginning, } from './commands';
8
8
  import { mathBType, mathIType } from './const';
9
9
  import { mathViewAndEditPlugin } from './view-and-edit';
10
10
  import './index.css';
@@ -17,7 +17,7 @@ export const Math = (builder, opts) => {
17
17
  builder.use(MathSpecs);
18
18
  builder.addKeymap(() => ({
19
19
  Enter: ignoreIfCursorInsideMathInline,
20
- Backspace: chainCommands(moveCursorToEndOfMathInline, removeEmptyMathInlineIfCursorIsAtBeginning),
20
+ Backspace: chainCommands(removeEmptyMathInlineIfCursorIsAtBeginning, moveCursorLeftOfMathInline),
21
21
  }));
22
22
  builder
23
23
  .addPlugin(() => mathViewAndEditPlugin(Object.assign(Object.assign({}, opts), { reactRenderer: builder.context.get('reactrenderer') })))
@@ -2,10 +2,10 @@ import { keydownHandler } from 'prosemirror-keymap';
2
2
  import { Plugin } from 'prosemirror-state';
3
3
  import { Decoration, DecorationSet } from 'prosemirror-view';
4
4
  import { isTextSelection } from '../../../utils/selection';
5
- import { moveCursorToEndOfMathInline } from './commands';
5
+ import { moveCursorLeftOfMathInline, moveCursorRightOfMathInline } from './commands';
6
6
  import { CLASSNAMES, MathNode } from './const';
7
7
  import { b, renderMathHint } from './hint';
8
- import './view-and-edit.css'; // eslint-disable-line import/order
8
+ import './view-and-edit.css';
9
9
  const MATH_ACTIVE_DECO = 'math_active_decoration';
10
10
  export class MathNodeView {
11
11
  constructor(node, opts) {
@@ -156,13 +156,14 @@ export class MathBlockNodeView extends MathNodeView {
156
156
  }
157
157
  export const mathViewAndEditPlugin = (options) => new Plugin({
158
158
  props: {
159
+ handleKeyDown: keydownHandler({
160
+ ArrowRight: moveCursorRightOfMathInline,
161
+ ArrowLeft: moveCursorLeftOfMathInline,
162
+ }),
159
163
  nodeViews: {
160
164
  [MathNode.Block]: (node) => new MathBlockNodeView(node, options),
161
165
  [MathNode.Inline]: (node) => new MathInlineNodeView(node, options),
162
166
  },
163
- handleKeyDown: keydownHandler({
164
- ArrowLeft: moveCursorToEndOfMathInline,
165
- }),
166
167
  decorations: (state) => {
167
168
  const { selection } = state;
168
169
  if (isTextSelection(selection)) {
@@ -7,12 +7,12 @@ export const getSchemaSpecs = (opts, placeholder) => {
7
7
  var _a, _b, _c, _d;
8
8
  return ({
9
9
  [CutNode.Cut]: {
10
- attrs: { class: { default: 'yfm-cut' } },
10
+ attrs: { class: { default: 'yfm-cut' }, open: { default: null } },
11
11
  content: `${CutNode.CutTitle} ${CutNode.CutContent}`,
12
12
  group: 'block yfm-cut',
13
- parseDOM: [{ tag: 'div.yfm-cut' }],
13
+ parseDOM: [{ tag: '.yfm-cut' }],
14
14
  toDOM(node) {
15
- return ['div', node.attrs, 0];
15
+ return ['details', node.attrs, 0];
16
16
  },
17
17
  selectable: true,
18
18
  allowSelection: true,
@@ -23,9 +23,9 @@ export const getSchemaSpecs = (opts, placeholder) => {
23
23
  attrs: { class: { default: 'yfm-cut-title' } },
24
24
  content: 'inline*',
25
25
  group: 'block yfm-cut',
26
- parseDOM: [{ tag: 'div.yfm-cut-title' }],
26
+ parseDOM: [{ tag: '.yfm-cut-title' }],
27
27
  toDOM(node) {
28
- return ['div', node.attrs, 0];
28
+ return ['summary', node.attrs, 0];
29
29
  },
30
30
  placeholder: {
31
31
  content: (_b = (_a = placeholder === null || placeholder === void 0 ? void 0 : placeholder[CutNode.CutTitle]) !== null && _a !== void 0 ? _a : opts === null || opts === void 0 ? void 0 : opts.yfmCutTitlePlaceholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDERS.Title,
@@ -40,7 +40,7 @@ export const getSchemaSpecs = (opts, placeholder) => {
40
40
  attrs: { class: { default: 'yfm-cut-content' } },
41
41
  content: '(block | paragraph)+',
42
42
  group: 'block yfm-cut',
43
- parseDOM: [{ tag: 'div.yfm-cut-content' }],
43
+ parseDOM: [{ tag: '.yfm-cut-content' }],
44
44
  toDOM(node) {
45
45
  return ['div', node.attrs, 0];
46
46
  },
@@ -2,7 +2,7 @@ import { TextSelection } from 'prosemirror-state';
2
2
  import { findParentNodeClosestToPos } from 'prosemirror-utils';
3
3
  import { cutContentType, cutTitleType, cutType } from '../const';
4
4
  const createYfmCutNode = (schema) => (content) => {
5
- return cutType(schema).create({ class: 'yfm-cut open' }, [
5
+ return cutType(schema).create({ class: 'yfm-cut open', open: true }, [
6
6
  cutTitleType(schema).create(null),
7
7
  cutContentType(schema).create(null, content),
8
8
  ]);
@@ -1,10 +1,22 @@
1
1
  .ProseMirror.yfm .yfm-cut {
2
2
  border: 1px dashed transparent;
3
3
  border-radius: var(--g-border-radius-s);
4
+ /* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
5
+ /* This ensures backward compatibility with earlier versions of cut-extension */
4
6
  }
5
7
  .ProseMirror.yfm .yfm-cut:hover {
6
8
  border-color: var(--g-color-line-generic);
7
9
  }
8
10
  .ProseMirror.yfm .yfm-cut.yfm-cut-active {
9
11
  border-color: var(--g-color-line-generic);
12
+ }
13
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
14
+ outline: 0;
15
+ }
16
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title {
17
+ list-style: none;
18
+ }
19
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
20
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
21
+ display: none;
10
22
  }
@@ -2,7 +2,7 @@ import './yfm-cut-title.css';
2
2
  export class YfmCutTitleNodeView {
3
3
  constructor(node) {
4
4
  this.node = node;
5
- this.dom = document.createElement('div');
5
+ this.dom = document.createElement('summary');
6
6
  this.dom.classList.add('yfm-cut-title');
7
7
  this.dom.replaceChildren((this.contentDOM = document.createElement('div')));
8
8
  this.contentDOM.classList.add('g-md-yfm-cut-title-inner');
@@ -10,6 +10,7 @@ export class YfmCutTitleNodeView {
10
10
  // ignore clicking on the title content
11
11
  // you can open/close yfm-cut by clicking on the arrow icon
12
12
  e.stopPropagation();
13
+ e.preventDefault();
13
14
  });
14
15
  }
15
16
  update(node) {
@@ -38,6 +38,7 @@ function openParentYfmCuts($pos, domAtPos) {
38
38
  if ($pos.node(depth - 1).type === cutType(schema)) {
39
39
  const { node: cutDomNode } = domAtPos($pos.start(depth - 1), 0);
40
40
  cutDomNode.classList.add('open');
41
+ cutDomNode.setAttribute('open', 'true');
41
42
  depth--;
42
43
  }
43
44
  }
@@ -85,9 +86,10 @@ class CutAutoOpenOnDragOver {
85
86
  this._timeout = setTimeout(this._openCut.bind(this), CutAutoOpenOnDragOver.OPEN_TIMEOUT);
86
87
  }
87
88
  _openCut() {
88
- var _a;
89
+ var _a, _b;
89
90
  if (this._editorView.dragging) {
90
91
  (_a = this._cutElem) === null || _a === void 0 ? void 0 : _a.classList.add('open');
92
+ (_b = this._cutElem) === null || _b === void 0 ? void 0 : _b.setAttribute('open', 'true');
91
93
  }
92
94
  this._clear();
93
95
  }
@@ -1,2 +1,2 @@
1
1
  /** During build process, the current version will be injected here */
2
- export const VERSION = typeof '13.23.0' !== 'undefined' ? '13.23.0' : 'unknown';
2
+ export const VERSION = typeof '13.24.0' !== 'undefined' ? '13.24.0' : 'unknown';
package/build/styles.css CHANGED
@@ -1,6 +1,7 @@
1
1
  .g-md-editor-component {
2
2
  display: flex;
3
3
  height: 100%;
4
+ outline: none;
4
5
  }
5
6
  .g-md-editor-component_split_vertical {
6
7
  display: grid;
@@ -1047,6 +1048,8 @@ body :has(.g-md-resizable_resizing) {
1047
1048
  .ProseMirror.yfm .yfm-cut {
1048
1049
  border: 1px dashed transparent;
1049
1050
  border-radius: var(--g-border-radius-s);
1051
+ /* TODO: Remove this after updating @diplodoc/transform to version 4.19.0 or higher */
1052
+ /* This ensures backward compatibility with earlier versions of cut-extension */
1050
1053
  }
1051
1054
  .ProseMirror.yfm .yfm-cut:hover {
1052
1055
  border-color: var(--g-color-line-generic);
@@ -1054,6 +1057,16 @@ body :has(.g-md-resizable_resizing) {
1054
1057
  .ProseMirror.yfm .yfm-cut.yfm-cut-active {
1055
1058
  border-color: var(--g-color-line-generic);
1056
1059
  }
1060
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title:focus {
1061
+ outline: 0;
1062
+ }
1063
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title {
1064
+ list-style: none;
1065
+ }
1066
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::-webkit-details-marker,
1067
+ .ProseMirror.yfm .yfm-cut .yfm-cut-title::marker {
1068
+ display: none;
1069
+ }
1057
1070
  .yfm-editor .yfm-file {
1058
1071
  pointer-events: none;
1059
1072
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/markdown-editor",
3
- "version": "13.23.0",
3
+ "version": "13.24.0",
4
4
  "description": "Markdown wysiwyg and markup editor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -204,7 +204,7 @@
204
204
  "@diplodoc/html-extension": "2.3.2",
205
205
  "@diplodoc/latex-extension": "1.0.3",
206
206
  "@diplodoc/mermaid-extension": "1.2.1",
207
- "@diplodoc/transform": "4.22.0",
207
+ "@diplodoc/transform": "4.26.0",
208
208
  "@gravity-ui/components": "3.0.0",
209
209
  "@gravity-ui/eslint-config": "3.1.1",
210
210
  "@gravity-ui/prettier-config": "1.1.0",
@@ -279,7 +279,7 @@
279
279
  "@diplodoc/html-extension": "2.3.2",
280
280
  "@diplodoc/latex-extension": "^1.0.3",
281
281
  "@diplodoc/mermaid-extension": "^1.0.0",
282
- "@diplodoc/transform": ">=4.5.0 <4.19.0",
282
+ "@diplodoc/transform": ">=4.5.0 <=4.26.0",
283
283
  "@gravity-ui/components": "^3.0.0",
284
284
  "@gravity-ui/uikit": "^6.11.0",
285
285
  "highlight.js": "^11.8.0",