@gravity-ui/markdown-editor 13.1.2 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @gravity-ui/markdown-editor · [![npm package](https://img.shields.io/npm/v/@gravity-ui/markdown-editor)](https://www.npmjs.com/package/@gravity-ui/markdown-editor) [![CI](https://img.shields.io/github/actions/workflow/status/gravity-ui/markdown-editor/ci.yml?branch=main&label=CI)](https://github.com/gravity-ui/markdown-editor/actions/workflows/ci.yml?query=branch:main) [![Release](https://img.shields.io/github/actions/workflow/status/gravity-ui/markdown-editor/release.yml?branch=main&label=Release)](https://github.com/gravity-ui/markdown-editor/actions/workflows/release.yml?query=branch:main) [![storybook](https://img.shields.io/badge/Storybook-deployed-ff4685)](https://preview.gravity-ui.com/md-editor/)
2
2
 
3
- ## Markdown wysiwyg and markup editor
3
+ ## Markdown wysiwyg and markup editor
4
4
 
5
5
  MarkdownEditor is a powerful tool for working with Markdown, which combines WYSIWYG and Markup modes. This means that you can create and edit content in a convenient visual mode, as well as have full control over the markup.
6
6
 
@@ -69,5 +69,5 @@ Don't forget to call `configure()` from [UIKit](https://github.com/gravity-ui/ui
69
69
  To start the dev storybook
70
70
 
71
71
  ```shell
72
- npm run dev
72
+ npm start
73
73
  ```
@@ -2,10 +2,12 @@ import { PopupProps } from '@gravity-ui/uikit';
2
2
  import { EditorState } from 'prosemirror-state';
3
3
  import { EditorView } from 'prosemirror-view';
4
4
  import { ActionStorage } from '../../../core';
5
- import { ToolbarGroupItemData } from '../../../toolbar';
6
- export declare type ContextGroupItemData = ToolbarGroupItemData<ActionStorage> & {
5
+ import { ToolbarButtonPopupData, ToolbarGroupItemData, ToolbarSingleItemData } from '../../../toolbar';
6
+ export declare type ContextGroupItemData = (ToolbarGroupItemData<ActionStorage> & {
7
7
  condition?: (state: EditorState) => void;
8
- };
8
+ }) | ((ToolbarSingleItemData<ActionStorage> | ToolbarButtonPopupData<ActionStorage>) & {
9
+ condition?: 'enabled';
10
+ });
9
11
  export declare type ContextGroupData = ContextGroupItemData[];
10
12
  export declare type ContextConfig = ContextGroupData[];
11
13
  export declare class TooltipView {
@@ -54,7 +54,16 @@ class TooltipView {
54
54
  getFilteredConfig() {
55
55
  return this.baseProps.show
56
56
  ? this.menuConfig
57
- .map((groupData) => groupData.filter(({ condition }) => (0, lodash_1.isFunction)(condition) ? condition(this.view.state) : true))
57
+ .map((groupData) => groupData.filter((item) => {
58
+ const { condition } = item;
59
+ if (condition === 'enabled') {
60
+ return item.isEnable(this.actions);
61
+ }
62
+ if ((0, lodash_1.isFunction)(condition)) {
63
+ return condition(this.view.state);
64
+ }
65
+ return true;
66
+ }))
58
67
  .filter((groupData) => Boolean(groupData.length))
59
68
  : [];
60
69
  }
@@ -4,4 +4,5 @@ export declare const YfmHeadingAttr: {
4
4
  readonly Level: "level";
5
5
  readonly Id: "id";
6
6
  readonly DataLine: "data-line";
7
+ readonly Folding: "folding";
7
8
  };
@@ -9,4 +9,5 @@ exports.YfmHeadingAttr = {
9
9
  Level: HeadingSpecs_1.headingLevelAttr,
10
10
  Id: 'id',
11
11
  DataLine: 'data-line',
12
+ Folding: 'folding',
12
13
  };
@@ -16,6 +16,7 @@ const YfmHeadingSpecs = (builder, opts) => {
16
16
  [const_1.YfmHeadingAttr.Id]: { default: '' },
17
17
  [const_1.YfmHeadingAttr.Level]: { default: 1 },
18
18
  [const_1.YfmHeadingAttr.DataLine]: { default: null },
19
+ [const_1.YfmHeadingAttr.Folding]: { default: false },
19
20
  },
20
21
  content: '(text | inline)*',
21
22
  group: 'block',
@@ -32,11 +33,13 @@ const YfmHeadingSpecs = (builder, opts) => {
32
33
  toDOM(node) {
33
34
  const id = node.attrs[const_1.YfmHeadingAttr.Id];
34
35
  const lineNumber = node.attrs[const_1.YfmHeadingAttr.DataLine];
36
+ const folding = node.attrs[const_1.YfmHeadingAttr.Folding];
35
37
  return [
36
38
  'h' + node.attrs[const_1.YfmHeadingAttr.Level],
37
39
  {
38
40
  id: id || null,
39
41
  [const_1.YfmHeadingAttr.DataLine]: lineNumber,
42
+ [`data-${const_1.YfmHeadingAttr.Folding}`]: folding ? '' : null,
40
43
  },
41
44
  0,
42
45
  // [
@@ -61,6 +64,7 @@ const YfmHeadingSpecs = (builder, opts) => {
61
64
  name: const_1.headingNodeName,
62
65
  type: 'block',
63
66
  getAttrs: (token) => {
67
+ var _a;
64
68
  if (token.type.endsWith('_close'))
65
69
  return {};
66
70
  const attrs = Object.fromEntries(token.attrs || []);
@@ -70,12 +74,14 @@ const YfmHeadingSpecs = (builder, opts) => {
70
74
  // attrs[YfmHeadingAttr.Id] = slugify(tokens[index + 1].content);
71
75
  // }
72
76
  // attrs have id only if it explicitly specified manually
73
- return Object.assign({ [const_1.YfmHeadingAttr.Level]: Number(token.tag.slice(1)) }, attrs);
77
+ return Object.assign({ [const_1.YfmHeadingAttr.Level]: Number(token.tag.slice(1)), [const_1.YfmHeadingAttr.Folding]: (_a = token.meta) === null || _a === void 0 ? void 0 : _a.folding }, attrs);
74
78
  },
75
79
  },
76
80
  },
77
81
  toMd: (state, node) => {
78
- state.write(state.repeat('#', node.attrs[const_1.YfmHeadingAttr.Level]) + ' ');
82
+ const folding = node.attrs[const_1.YfmHeadingAttr.Folding];
83
+ const level = node.attrs[const_1.YfmHeadingAttr.Level];
84
+ state.write(state.repeat('#', level) + (folding ? '+' : '') + ' ');
79
85
  state.renderInline(node);
80
86
  const anchor = node.attrs[const_1.YfmHeadingAttr.Id];
81
87
  if (anchor /*&& anchor !== node.firstChild?.textContent*/) {
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "headingRule", { enumerable: true, get: function
10
10
  const getNodeAttrs = (level) => (node) => ({
11
11
  [const_1.YfmHeadingAttr.Level]: level,
12
12
  [const_1.YfmHeadingAttr.Id]: node.getAttribute('id') || '',
13
+ [const_1.YfmHeadingAttr.Folding]: node.hasAttribute(`data-${const_1.YfmHeadingAttr.Folding}`),
13
14
  });
14
15
  exports.getNodeAttrs = getNodeAttrs;
15
16
  // export const slugify = (str: string) =>
@@ -9,15 +9,17 @@ const const_1 = require("./const");
9
9
  var commands_1 = require("../../markdown/Heading/commands");
10
10
  Object.defineProperty(exports, "resetHeading", { enumerable: true, get: function () { return commands_1.resetHeading; } });
11
11
  const toHeading = (level) => (state, dispatch, view) => {
12
+ const attrs = {};
12
13
  const parentHeading = (0, prosemirror_utils_1.findParentNodeOfType)((0, utils_1.hType)(state.schema))(state.selection);
13
- if (parentHeading && parentHeading.node.attrs[const_1.headingLevelAttr] === level) {
14
- return (0, base_1.toParagraph)(state, dispatch, view);
14
+ if (parentHeading) {
15
+ if (parentHeading.node.attrs[const_1.headingLevelAttr] === level) {
16
+ return (0, base_1.toParagraph)(state, dispatch, view);
17
+ }
18
+ Object.assign(attrs, parentHeading.node.attrs);
15
19
  }
16
20
  // const text = state.selection.$head.parent.textContent;
17
- const attrs = {
18
- // [YfmHeadingAttr.Id]: slugify(text),
19
- [const_1.YfmHeadingAttr.Level]: level,
20
- };
21
+ // attrs[YfmHeadingAttr.Id] = slugify(text);
22
+ attrs[const_1.YfmHeadingAttr.Level] = level;
21
23
  return (0, prosemirror_commands_1.setBlockType)((0, utils_1.hType)(state.schema), attrs)(state, dispatch);
22
24
  };
23
25
  exports.toHeading = toHeading;
@@ -33,4 +33,28 @@ exports.gravityTheme = view_1.EditorView.baseTheme({
33
33
  '&.cm-focused .cm-selectionBackground, &.cm-focused ::selection': {
34
34
  background: 'var(--g-color-base-misc-medium)',
35
35
  },
36
+ '.cm-tooltip.cm-tooltip-autocomplete': {
37
+ padding: '4px 0',
38
+ lineHeight: '24px',
39
+ color: 'var(--g-color-text-primary)',
40
+ fontFamily: 'var(--g-font-family-monospace)',
41
+ fontSize: 'var(--g-text-body-1-font-size)',
42
+ backgroundColor: 'var(--g-color-base-float)',
43
+ border: '1px solid var(--g-color-line-generic-solid)',
44
+ borderRadius: '4px',
45
+ '& > ul': {
46
+ '& > completion-section': {
47
+ color: 'var(--g-color-text-hint)',
48
+ fontWeight: 'var(--g-text-accent-font-weight)',
49
+ borderBottom: '1px solid var(--g-color-line-generic)',
50
+ },
51
+ '& > li:hover': {
52
+ backgroundColor: 'var(--g-color-base-simple-hover)',
53
+ },
54
+ '& > li[aria-selected]': {
55
+ backgroundColor: 'var(--g-color-base-selection)',
56
+ color: 'revert',
57
+ },
58
+ },
59
+ },
36
60
  });
@@ -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.1.2' !== 'undefined' ? '13.1.2' : 'unknown';
5
+ exports.VERSION = typeof '13.2.0' !== 'undefined' ? '13.2.0' : 'unknown';
@@ -2,10 +2,12 @@ import { PopupProps } from '@gravity-ui/uikit';
2
2
  import { EditorState } from 'prosemirror-state';
3
3
  import { EditorView } from 'prosemirror-view';
4
4
  import { ActionStorage } from '../../../core';
5
- import { ToolbarGroupItemData } from '../../../toolbar';
6
- export declare type ContextGroupItemData = ToolbarGroupItemData<ActionStorage> & {
5
+ import { ToolbarButtonPopupData, ToolbarGroupItemData, ToolbarSingleItemData } from '../../../toolbar';
6
+ export declare type ContextGroupItemData = (ToolbarGroupItemData<ActionStorage> & {
7
7
  condition?: (state: EditorState) => void;
8
- };
8
+ }) | ((ToolbarSingleItemData<ActionStorage> | ToolbarButtonPopupData<ActionStorage>) & {
9
+ condition?: 'enabled';
10
+ });
9
11
  export declare type ContextGroupData = ContextGroupItemData[];
10
12
  export declare type ContextConfig = ContextGroupData[];
11
13
  export declare class TooltipView {
@@ -5,7 +5,7 @@ import { Popup } from '@gravity-ui/uikit';
5
5
  import { isFunction } from '../../../lodash';
6
6
  import { logger } from '../../../logger';
7
7
  import { ErrorLoggerBoundary } from '../../../react-utils/ErrorBoundary';
8
- import { Toolbar } from '../../../toolbar';
8
+ import { Toolbar, } from '../../../toolbar';
9
9
  import { getReactRendererFromState } from '../ReactRenderer';
10
10
  const SelectionTooltip = (_a) => {
11
11
  var { show, poppupProps } = _a, toolbarProps = __rest(_a, ["show", "poppupProps"]);
@@ -51,7 +51,16 @@ export class TooltipView {
51
51
  getFilteredConfig() {
52
52
  return this.baseProps.show
53
53
  ? this.menuConfig
54
- .map((groupData) => groupData.filter(({ condition }) => isFunction(condition) ? condition(this.view.state) : true))
54
+ .map((groupData) => groupData.filter((item) => {
55
+ const { condition } = item;
56
+ if (condition === 'enabled') {
57
+ return item.isEnable(this.actions);
58
+ }
59
+ if (isFunction(condition)) {
60
+ return condition(this.view.state);
61
+ }
62
+ return true;
63
+ }))
55
64
  .filter((groupData) => Boolean(groupData.length))
56
65
  : [];
57
66
  }
@@ -4,4 +4,5 @@ export declare const YfmHeadingAttr: {
4
4
  readonly Level: "level";
5
5
  readonly Id: "id";
6
6
  readonly DataLine: "data-line";
7
+ readonly Folding: "folding";
7
8
  };
@@ -4,4 +4,5 @@ export const YfmHeadingAttr = {
4
4
  Level: headingLevelAttr,
5
5
  Id: 'id',
6
6
  DataLine: 'data-line',
7
+ Folding: 'folding',
7
8
  };
@@ -12,6 +12,7 @@ export const YfmHeadingSpecs = (builder, opts) => {
12
12
  [YfmHeadingAttr.Id]: { default: '' },
13
13
  [YfmHeadingAttr.Level]: { default: 1 },
14
14
  [YfmHeadingAttr.DataLine]: { default: null },
15
+ [YfmHeadingAttr.Folding]: { default: false },
15
16
  },
16
17
  content: '(text | inline)*',
17
18
  group: 'block',
@@ -28,11 +29,13 @@ export const YfmHeadingSpecs = (builder, opts) => {
28
29
  toDOM(node) {
29
30
  const id = node.attrs[YfmHeadingAttr.Id];
30
31
  const lineNumber = node.attrs[YfmHeadingAttr.DataLine];
32
+ const folding = node.attrs[YfmHeadingAttr.Folding];
31
33
  return [
32
34
  'h' + node.attrs[YfmHeadingAttr.Level],
33
35
  {
34
36
  id: id || null,
35
37
  [YfmHeadingAttr.DataLine]: lineNumber,
38
+ [`data-${YfmHeadingAttr.Folding}`]: folding ? '' : null,
36
39
  },
37
40
  0,
38
41
  // [
@@ -57,6 +60,7 @@ export const YfmHeadingSpecs = (builder, opts) => {
57
60
  name: headingNodeName,
58
61
  type: 'block',
59
62
  getAttrs: (token) => {
63
+ var _a;
60
64
  if (token.type.endsWith('_close'))
61
65
  return {};
62
66
  const attrs = Object.fromEntries(token.attrs || []);
@@ -66,12 +70,14 @@ export const YfmHeadingSpecs = (builder, opts) => {
66
70
  // attrs[YfmHeadingAttr.Id] = slugify(tokens[index + 1].content);
67
71
  // }
68
72
  // attrs have id only if it explicitly specified manually
69
- return Object.assign({ [YfmHeadingAttr.Level]: Number(token.tag.slice(1)) }, attrs);
73
+ return Object.assign({ [YfmHeadingAttr.Level]: Number(token.tag.slice(1)), [YfmHeadingAttr.Folding]: (_a = token.meta) === null || _a === void 0 ? void 0 : _a.folding }, attrs);
70
74
  },
71
75
  },
72
76
  },
73
77
  toMd: (state, node) => {
74
- state.write(state.repeat('#', node.attrs[YfmHeadingAttr.Level]) + ' ');
78
+ const folding = node.attrs[YfmHeadingAttr.Folding];
79
+ const level = node.attrs[YfmHeadingAttr.Level];
80
+ state.write(state.repeat('#', level) + (folding ? '+' : '') + ' ');
75
81
  state.renderInline(node);
76
82
  const anchor = node.attrs[YfmHeadingAttr.Id];
77
83
  if (anchor /*&& anchor !== node.firstChild?.textContent*/) {
@@ -4,6 +4,7 @@ export { hType, hasParentHeading, headingRule } from '../../../markdown/Heading/
4
4
  export const getNodeAttrs = (level) => (node) => ({
5
5
  [YfmHeadingAttr.Level]: level,
6
6
  [YfmHeadingAttr.Id]: node.getAttribute('id') || '',
7
+ [YfmHeadingAttr.Folding]: node.hasAttribute(`data-${YfmHeadingAttr.Folding}`),
7
8
  });
8
9
  // export const slugify = (str: string) =>
9
10
  // // same config as in yfm-transform
@@ -5,14 +5,16 @@ import { hType } from './YfmHeadingSpecs/utils';
5
5
  import { YfmHeadingAttr, headingLevelAttr } from './const';
6
6
  export { resetHeading } from '../../markdown/Heading/commands';
7
7
  export const toHeading = (level) => (state, dispatch, view) => {
8
+ const attrs = {};
8
9
  const parentHeading = findParentNodeOfType(hType(state.schema))(state.selection);
9
- if (parentHeading && parentHeading.node.attrs[headingLevelAttr] === level) {
10
- return toParagraph(state, dispatch, view);
10
+ if (parentHeading) {
11
+ if (parentHeading.node.attrs[headingLevelAttr] === level) {
12
+ return toParagraph(state, dispatch, view);
13
+ }
14
+ Object.assign(attrs, parentHeading.node.attrs);
11
15
  }
12
16
  // const text = state.selection.$head.parent.textContent;
13
- const attrs = {
14
- // [YfmHeadingAttr.Id]: slugify(text),
15
- [YfmHeadingAttr.Level]: level,
16
- };
17
+ // attrs[YfmHeadingAttr.Id] = slugify(text);
18
+ attrs[YfmHeadingAttr.Level] = level;
17
19
  return setBlockType(hType(state.schema), attrs)(state, dispatch);
18
20
  };
@@ -30,4 +30,28 @@ export const gravityTheme = EditorView.baseTheme({
30
30
  '&.cm-focused .cm-selectionBackground, &.cm-focused ::selection': {
31
31
  background: 'var(--g-color-base-misc-medium)',
32
32
  },
33
+ '.cm-tooltip.cm-tooltip-autocomplete': {
34
+ padding: '4px 0',
35
+ lineHeight: '24px',
36
+ color: 'var(--g-color-text-primary)',
37
+ fontFamily: 'var(--g-font-family-monospace)',
38
+ fontSize: 'var(--g-text-body-1-font-size)',
39
+ backgroundColor: 'var(--g-color-base-float)',
40
+ border: '1px solid var(--g-color-line-generic-solid)',
41
+ borderRadius: '4px',
42
+ '& > ul': {
43
+ '& > completion-section': {
44
+ color: 'var(--g-color-text-hint)',
45
+ fontWeight: 'var(--g-text-accent-font-weight)',
46
+ borderBottom: '1px solid var(--g-color-line-generic)',
47
+ },
48
+ '& > li:hover': {
49
+ backgroundColor: 'var(--g-color-base-simple-hover)',
50
+ },
51
+ '& > li[aria-selected]': {
52
+ backgroundColor: 'var(--g-color-base-selection)',
53
+ color: 'revert',
54
+ },
55
+ },
56
+ },
33
57
  });
@@ -1,2 +1,2 @@
1
1
  /** During build process, the current version will be injected here */
2
- export const VERSION = typeof '13.1.2' !== 'undefined' ? '13.1.2' : 'unknown';
2
+ export const VERSION = typeof '13.2.0' !== 'undefined' ? '13.2.0' : 'unknown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/markdown-editor",
3
- "version": "13.1.2",
3
+ "version": "13.2.0",
4
4
  "description": "Markdown wysiwyg and markup editor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,7 +16,6 @@
16
16
  ],
17
17
  "scripts": {
18
18
  "start": "npm run storybook:start",
19
- "dev": "npm run storybook:start",
20
19
  "clean": "gulp clean",
21
20
  "build": "gulp",
22
21
  "typecheck": "tsc -p tsconfig.json --noEmit",