@gravity-ui/markdown-editor 13.16.0 → 13.17.1

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 (48) hide show
  1. package/build/cjs/extensions/behavior/Resizable/Resizable.css +38 -0
  2. package/build/cjs/extensions/behavior/Resizable/Resizable.d.ts +9 -0
  3. package/build/cjs/extensions/behavior/Resizable/Resizable.js +14 -0
  4. package/build/cjs/extensions/markdown/Table/plugins/TableCellContextPlugin/index.js +19 -9
  5. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.css +6 -0
  6. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.d.ts +6 -1
  7. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.js +21 -37
  8. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.d.ts +1 -1
  9. package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +62 -4
  10. package/build/cjs/extensions/yfm/Mermaid/MermaidNodeView/MermaidView.js +8 -7
  11. package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.js +31 -9
  12. package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockSpecs/index.d.ts +1 -1
  13. package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockSpecs/index.js +2 -2
  14. package/build/cjs/extensions/yfm/YfmHtmlBlock/index.d.ts +1 -1
  15. package/build/cjs/i18n/yfm-table/en.json +10 -1
  16. package/build/cjs/i18n/yfm-table/index.d.ts +10 -1
  17. package/build/cjs/i18n/yfm-table/ru.json +10 -1
  18. package/build/cjs/react-utils/useNodeEditing.d.ts +3 -2
  19. package/build/cjs/react-utils/useNodeEditing.js +1 -1
  20. package/build/cjs/react-utils/useNodeResizing.d.ts +22 -0
  21. package/build/cjs/react-utils/useNodeResizing.js +82 -0
  22. package/build/cjs/version.js +1 -1
  23. package/build/cjs/view/hocs/withYfmHtml/index.js +2 -2
  24. package/build/esm/extensions/behavior/Resizable/Resizable.css +38 -0
  25. package/build/esm/extensions/behavior/Resizable/Resizable.d.ts +10 -0
  26. package/build/esm/extensions/behavior/Resizable/Resizable.js +10 -0
  27. package/build/esm/extensions/markdown/Table/plugins/TableCellContextPlugin/index.js +19 -9
  28. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.css +6 -0
  29. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.d.ts +7 -1
  30. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImgSettingsButton.js +23 -38
  31. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.d.ts +1 -1
  32. package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/NodeView.js +63 -5
  33. package/build/esm/extensions/yfm/Mermaid/MermaidNodeView/MermaidView.js +5 -4
  34. package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.js +31 -9
  35. package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockSpecs/index.d.ts +1 -1
  36. package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockSpecs/index.js +2 -2
  37. package/build/esm/extensions/yfm/YfmHtmlBlock/index.d.ts +1 -1
  38. package/build/esm/i18n/yfm-table/en.json +10 -1
  39. package/build/esm/i18n/yfm-table/index.d.ts +10 -1
  40. package/build/esm/i18n/yfm-table/ru.json +10 -1
  41. package/build/esm/react-utils/useNodeEditing.d.ts +3 -2
  42. package/build/esm/react-utils/useNodeEditing.js +1 -1
  43. package/build/esm/react-utils/useNodeResizing.d.ts +22 -0
  44. package/build/esm/react-utils/useNodeResizing.js +77 -0
  45. package/build/esm/version.js +1 -1
  46. package/build/esm/view/hocs/withYfmHtml/index.js +3 -3
  47. package/build/styles.css +44 -0
  48. package/package.json +4 -4
@@ -0,0 +1,38 @@
1
+ body :has(.g-md-resizable_resizing) {
2
+ cursor: col-resize;
3
+ }
4
+
5
+ .g-md-resizable {
6
+ position: relative;
7
+ }
8
+ .g-md-resizable_resizing .g-md-resizable__resizer-wrapper, .g-md-resizable_hover .g-md-resizable__resizer-wrapper {
9
+ position: absolute;
10
+ z-index: 1;
11
+ top: 0;
12
+ display: flex;
13
+ justify-content: center;
14
+ align-items: center;
15
+ width: 20px;
16
+ height: 100%;
17
+ cursor: col-resize;
18
+ pointer-events: auto;
19
+ }
20
+ .g-md-resizable_resizing .g-md-resizable__resizer-wrapper_left, .g-md-resizable_hover .g-md-resizable__resizer-wrapper_left {
21
+ left: 0;
22
+ }
23
+ .g-md-resizable_resizing .g-md-resizable__resizer-wrapper_right, .g-md-resizable_hover .g-md-resizable__resizer-wrapper_right {
24
+ right: 0;
25
+ }
26
+ .g-md-resizable__resizer {
27
+ opacity: 0;
28
+ }
29
+ .g-md-resizable_resizing .g-md-resizable__resizer, .g-md-resizable_hover .g-md-resizable__resizer {
30
+ box-sizing: content-box;
31
+ width: 4px;
32
+ height: 50px;
33
+ max-height: 50%;
34
+ opacity: 1;
35
+ border-radius: 6px;
36
+ background: rgba(127, 127, 127, 0.8);
37
+ transition: opacity 300ms ease-in 0s;
38
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ export interface ResizableProps {
3
+ children: React.ReactNode;
4
+ onResizeLeft: (event: React.MouseEvent<HTMLElement>) => void;
5
+ onResizeRight: (event: React.MouseEvent<HTMLElement>) => void;
6
+ hover?: boolean;
7
+ resizing?: boolean;
8
+ }
9
+ export declare const Resizable: React.FC<ResizableProps>;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Resizable = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const classname_1 = require("../../../classname");
7
+ const b = (0, classname_1.cn)('resizable');
8
+ const Resizer = ({ onMouseDown, direction }) => (react_1.default.createElement("div", { className: b('resizer-wrapper', { [direction]: true }), role: "button", tabIndex: 0, onMouseDown: onMouseDown },
9
+ react_1.default.createElement("div", { className: b('resizer') })));
10
+ const Resizable = ({ hover, resizing, children, onResizeLeft, onResizeRight, }) => (react_1.default.createElement("div", { className: b({ hover, resizing }) },
11
+ children,
12
+ react_1.default.createElement(Resizer, { onMouseDown: onResizeLeft, direction: "left" }),
13
+ react_1.default.createElement(Resizer, { onMouseDown: onResizeRight, direction: "right" })));
14
+ exports.Resizable = Resizable;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tableCellContextPlugin = void 0;
4
4
  const prosemirror_state_1 = require("prosemirror-state");
5
5
  const core_1 = require("../../../../../core");
6
+ const yfm_table_1 = require("../../../../../i18n/yfm-table");
6
7
  const yfm_1 = require("../../../../yfm");
7
8
  const TableSpecs_1 = require("../../TableSpecs");
8
9
  const innerActions_1 = require("../../actions/innerActions");
@@ -17,18 +18,27 @@ const tableCellContextPlugin = () => new prosemirror_state_1.Plugin({
17
18
  } }))(view);
18
19
  return new view_1.TableCellContextView(view, [
19
20
  [
20
- { action: actions.setCellLeftAlign, text: 'left' },
21
- { action: actions.setCellCenterAlign, text: 'center' },
22
- { action: actions.setCellRightAlign, text: 'right' },
21
+ {
22
+ action: actions.setCellLeftAlign,
23
+ text: (0, yfm_table_1.i18n)('table.menu.cell.align.left'),
24
+ },
25
+ {
26
+ action: actions.setCellCenterAlign,
27
+ text: (0, yfm_table_1.i18n)('table.menu.cell.align.center'),
28
+ },
29
+ {
30
+ action: actions.setCellRightAlign,
31
+ text: (0, yfm_table_1.i18n)('table.menu.cell.align.right'),
32
+ },
23
33
  ],
24
34
  [
25
- { action: actions.addRow, text: 'add row' },
26
- { action: actions.deleteRow, text: 'del row' },
27
- { action: actions.addColumn, text: 'add column' },
28
- { action: actions.deleteColumn, text: 'del column' },
35
+ { action: actions.addRow, text: (0, yfm_table_1.i18n)('table.menu.row.add') },
36
+ { action: actions.deleteRow, text: (0, yfm_table_1.i18n)('table.menu.row.remove') },
37
+ { action: actions.addColumn, text: (0, yfm_table_1.i18n)('table.menu.column.add') },
38
+ { action: actions.deleteColumn, text: (0, yfm_table_1.i18n)('table.menu.column.remove') },
29
39
  ],
30
- { action: actions.convert, text: 'convert to yfm table' },
31
- { action: actions.deleteTable, text: 'del table' },
40
+ { action: actions.convert, text: (0, yfm_table_1.i18n)('table.menu.convert.yfm') },
41
+ { action: actions.deleteTable, text: (0, yfm_table_1.i18n)('table.menu.table.remove') },
32
42
  ], [schema.nodes[TableSpecs_1.TableNode.HeaderCell], schema.nodes[TableSpecs_1.TableNode.DataCell]]);
33
43
  },
34
44
  });
@@ -0,0 +1,6 @@
1
+ .g-md-img-settings-button {
2
+ position: absolute;
3
+ z-index: 2;
4
+ top: 3px;
5
+ right: 3px;
6
+ }
@@ -5,6 +5,11 @@ export declare const ImgSettingsButton: React.FC<{
5
5
  node: Node;
6
6
  view: EditorView;
7
7
  getPos: () => number | undefined;
8
- nodeRef: RefObject<HTMLElement>;
9
8
  updateAttributes: (o: object) => void;
9
+ nodeRef: RefObject<HTMLDivElement>;
10
+ visible: boolean;
11
+ toggleEdit: () => void;
12
+ edit: boolean;
13
+ unsetEdit: () => void;
14
+ onDelete: () => void;
10
15
  }>;
@@ -5,49 +5,33 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importStar(require("react"));
6
6
  const icons_1 = require("@gravity-ui/icons");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
+ const classname_1 = require("../../../../../classname");
8
9
  const common_1 = require("../../../../../i18n/common");
9
10
  const hooks_1 = require("../../../../../react-utils/hooks");
10
- const useNodeEditing_1 = require("../../../../../react-utils/useNodeEditing");
11
- const useNodeHovered_1 = require("../../../../../react-utils/useNodeHovered");
12
- const remove_node_1 = require("../../../../../utils/remove-node");
13
- const const_1 = require("../../const");
14
11
  const ImageForm_1 = require("./ImageForm");
15
- const ImgSettingsButton = function ({ node, view, getPos, nodeRef, updateAttributes }) {
12
+ const b = (0, classname_1.cn)('img-settings-button');
13
+ const ImgSettingsButton = function ({ node, view, updateAttributes, visible, edit, toggleEdit, nodeRef, unsetEdit, onDelete, }) {
16
14
  const [popupOpen, setPopupOpen, unsetPopupOpen] = (0, hooks_1.useBooleanState)(false);
17
15
  const placement = ['bottom-end', 'bottom-start'];
18
16
  const buttonRef = (0, react_1.useRef)(null);
19
- const isNodeHovered = (0, useNodeHovered_1.useNodeHovered)(nodeRef);
20
- const isButtonHovered = (0, useNodeHovered_1.useNodeHovered)(buttonRef);
21
- const [edit, setEditing, unsetEdit, toggleEdit] = (0, useNodeEditing_1.useNodeEditing)({ nodeRef, view });
22
- const visible = (isNodeHovered || isButtonHovered || popupOpen) && !edit;
23
- (0, react_1.useEffect)(() => {
24
- var _a;
25
- if ((_a = const_1.imageRendererKey.getState(view.state)) === null || _a === void 0 ? void 0 : _a.linkAdded) {
26
- setEditing();
27
- }
28
- }, [view, setEditing]);
29
- if (edit)
30
- return (react_1.default.createElement(ImageForm_1.ImageForm, { node: node, view: view, updateAttributes: updateAttributes, dom: nodeRef, unsetEdit: unsetEdit }));
31
- return visible ? (react_1.default.createElement(react_1.default.Fragment, null,
32
- react_1.default.createElement(uikit_1.Button, { onClick: setPopupOpen, ref: buttonRef, size: "s", view: 'raised', style: { position: 'absolute', right: '3px', top: '3px' } },
33
- react_1.default.createElement(uikit_1.Icon, { data: icons_1.Ellipsis })),
34
- react_1.default.createElement(uikit_1.Popup, { open: popupOpen, anchorRef: buttonRef, onClose: unsetPopupOpen, placement: placement },
17
+ const handleEdit = () => {
18
+ toggleEdit();
19
+ unsetPopupOpen();
20
+ };
21
+ const isVisibleImageForm = edit;
22
+ const isVisibleEditButton = !edit && (visible || popupOpen);
23
+ const isVisiblePopup = !edit && popupOpen;
24
+ const handleEditButtonClick = (event) => {
25
+ event.preventDefault();
26
+ setPopupOpen();
27
+ };
28
+ return (react_1.default.createElement(react_1.default.Fragment, null,
29
+ isVisibleImageForm && (react_1.default.createElement(ImageForm_1.ImageForm, { node: node, view: view, updateAttributes: updateAttributes, dom: nodeRef, unsetEdit: unsetEdit })),
30
+ isVisibleEditButton && (react_1.default.createElement(uikit_1.Button, { onClick: handleEditButtonClick, ref: buttonRef, size: "s", view: 'raised', className: b() },
31
+ react_1.default.createElement(uikit_1.Icon, { data: icons_1.Ellipsis }))),
32
+ react_1.default.createElement(uikit_1.Popup, { open: isVisiblePopup, anchorRef: buttonRef, onClose: unsetPopupOpen, placement: placement },
35
33
  react_1.default.createElement(uikit_1.Menu, null,
36
- react_1.default.createElement(uikit_1.Menu.Item, { onClick: () => {
37
- toggleEdit();
38
- unsetPopupOpen();
39
- } }, (0, common_1.i18n)('edit')),
40
- react_1.default.createElement(uikit_1.Menu.Item, { onClick: () => {
41
- const pos = getPos();
42
- if (pos === undefined)
43
- return;
44
- (0, remove_node_1.removeNode)({
45
- node,
46
- pos,
47
- tr: view.state.tr,
48
- dispatch: view.dispatch,
49
- });
50
- view.focus();
51
- } }, (0, common_1.i18n)('delete')))))) : null;
34
+ react_1.default.createElement(uikit_1.Menu.Item, { onClick: handleEdit }, (0, common_1.i18n)('edit')),
35
+ react_1.default.createElement(uikit_1.Menu.Item, { onClick: onDelete }, (0, common_1.i18n)('delete'))))));
52
36
  };
53
37
  exports.ImgSettingsButton = ImgSettingsButton;
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { ReactNodeViewProps } from '../../../../../react-utils/react-node-view';
2
+ import { ReactNodeViewProps } from '../../../../../react-utils';
3
3
  export declare const cnImgSizeNodeView: import("@bem-react/classname").ClassNameFormatter;
4
4
  export declare const ImageNodeView: React.FC<ReactNodeViewProps>;
@@ -4,12 +4,70 @@ exports.ImageNodeView = exports.cnImgSizeNodeView = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importStar(require("react"));
6
6
  const classname_1 = require("../../../../../classname");
7
+ const react_utils_1 = require("../../../../../react-utils");
8
+ const useNodeResizing_1 = require("../../../../../react-utils/useNodeResizing");
9
+ const utils_1 = require("../../../../../utils");
10
+ const Resizable_1 = require("../../../../behavior/Resizable/Resizable");
11
+ const ImgSizeSpecs_1 = require("../../ImgSizeSpecs");
12
+ const const_1 = require("../../const");
7
13
  const ImgSettingsButton_1 = require("./ImgSettingsButton");
8
14
  exports.cnImgSizeNodeView = (0, classname_1.cn)('img-size-node-view');
9
15
  const ImageNodeView = ({ node, view, getPos, updateAttributes, }) => {
10
- const ref = (0, react_1.useRef)(null);
11
- return (react_1.default.createElement(react_1.default.Fragment, null,
12
- react_1.default.createElement(ImgSettingsButton_1.ImgSettingsButton, { node: node, view: view, getPos: getPos, updateAttributes: updateAttributes, nodeRef: ref }),
13
- react_1.default.createElement("img", Object.assign({}, node.attrs, { ref: ref }))));
16
+ const imageContainerRef = (0, react_1.useRef)(null);
17
+ const imageRef = (0, react_1.useRef)(null);
18
+ const alt = node.attrs[ImgSizeSpecs_1.ImgSizeAttr.Alt] || '';
19
+ const initialHeight = node.attrs[ImgSizeSpecs_1.ImgSizeAttr.Height];
20
+ const initialWidth = node.attrs[ImgSizeSpecs_1.ImgSizeAttr.Width];
21
+ const src = node.attrs[ImgSizeSpecs_1.ImgSizeAttr.Src] || '';
22
+ const title = node.attrs[ImgSizeSpecs_1.ImgSizeAttr.Title] || '';
23
+ const isNodeHovered = (0, react_utils_1.useNodeHovered)(imageContainerRef);
24
+ const [edit, setEditing, unsetEdit, toggleEdit] = (0, react_utils_1.useNodeEditing)({
25
+ nodeRef: imageContainerRef,
26
+ view,
27
+ });
28
+ const handleResize = (0, react_1.useCallback)(({ width, height }) => {
29
+ updateAttributes({
30
+ width: width === undefined ? undefined : String(Math.round(width)),
31
+ height: height === undefined ? undefined : String(Math.round(height)),
32
+ name: title,
33
+ alt,
34
+ });
35
+ }, [alt, title, updateAttributes]);
36
+ const { state, startResizing } = (0, useNodeResizing_1.useNodeResizing)({
37
+ width: initialWidth,
38
+ height: initialHeight,
39
+ ref: imageRef,
40
+ onResize: handleResize,
41
+ });
42
+ const style = {
43
+ width: state.width ? `${state.width}px` : '',
44
+ height: state.height ? `${state.height}px` : '',
45
+ transition: 'width 0.15s ease-out, height 0.15s ease-out',
46
+ };
47
+ const handleDelete = (0, react_1.useCallback)(() => {
48
+ const pos = getPos();
49
+ if (pos === undefined)
50
+ return;
51
+ (0, utils_1.removeNode)({
52
+ node,
53
+ pos,
54
+ tr: view.state.tr,
55
+ dispatch: view.dispatch,
56
+ });
57
+ view.focus();
58
+ }, [getPos, node, view]);
59
+ const createHandleResize = (direction) => (event) => {
60
+ startResizing(event, direction);
61
+ };
62
+ (0, react_1.useEffect)(() => {
63
+ var _a;
64
+ if ((_a = const_1.imageRendererKey.getState(view.state)) === null || _a === void 0 ? void 0 : _a.linkAdded) {
65
+ setEditing();
66
+ }
67
+ }, [view, setEditing]);
68
+ return (react_1.default.createElement("div", { ref: imageContainerRef },
69
+ react_1.default.createElement(Resizable_1.Resizable, { hover: isNodeHovered, resizing: state.resizing, onResizeLeft: createHandleResize('left'), onResizeRight: createHandleResize('right') },
70
+ react_1.default.createElement(ImgSettingsButton_1.ImgSettingsButton, { node: node, view: view, getPos: getPos, updateAttributes: updateAttributes, visible: isNodeHovered && !edit && !state.resizing, edit: edit, toggleEdit: toggleEdit, nodeRef: imageRef, onDelete: handleDelete, unsetEdit: unsetEdit }),
71
+ react_1.default.createElement("img", { ref: imageRef, src: src, alt: alt, style: style }))));
14
72
  };
15
73
  exports.ImageNodeView = ImageNodeView;
@@ -7,8 +7,9 @@ const icons_1 = require("@gravity-ui/icons");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const classname_1 = require("../../../../classname");
9
9
  const TextInput_1 = require("../../../../forms/TextInput");
10
- const hooks_1 = require("../../../../react-utils/hooks");
11
- const remove_node_1 = require("../../../../utils/remove-node");
10
+ const common_1 = require("../../../../i18n/common");
11
+ const react_utils_1 = require("../../../../react-utils");
12
+ const utils_1 = require("../../../../utils");
12
13
  const const_1 = require("../MermaidSpecs/const");
13
14
  exports.cnMermaid = (0, classname_1.cn)('Mermaid');
14
15
  exports.cnDiagramHelper = (0, classname_1.cn)('MermaidHelper');
@@ -58,8 +59,8 @@ const DiagramEditMode = ({ initialText, onSave, onCancel, mermaidInstance }) =>
58
59
  };
59
60
  const MermaidView = ({ onChange, node, getPos, view, getMermaidInstance }) => {
60
61
  const [mermaidInstance, setMermaidInstance] = (0, react_1.useState)(null);
61
- const [editing, setEditing, unsetEditing, toggleEditing] = (0, hooks_1.useBooleanState)(Boolean(node.attrs[const_1.MermaidConsts.NodeAttrs.newCreated]));
62
- const [menuOpen, , , toggleMenuOpen] = (0, hooks_1.useBooleanState)(false);
62
+ const [editing, setEditing, unsetEditing, toggleEditing] = (0, react_utils_1.useBooleanState)(Boolean(node.attrs[const_1.MermaidConsts.NodeAttrs.newCreated]));
63
+ const [menuOpen, , , toggleMenuOpen] = (0, react_utils_1.useBooleanState)(false);
63
64
  const buttonRef = (0, react_1.useRef)(null);
64
65
  (0, react_1.useEffect)(() => {
65
66
  const waitForMermaid = () => setTimeout(() => {
@@ -88,17 +89,17 @@ const MermaidView = ({ onChange, node, getPos, view, getMermaidInstance }) => {
88
89
  react_1.default.createElement(uikit_1.Menu.Item, { onClick: () => {
89
90
  toggleEditing();
90
91
  toggleMenuOpen();
91
- } }, "Edit"),
92
+ } }, (0, common_1.i18n)('edit')),
92
93
  react_1.default.createElement(uikit_1.Menu.Item, { onClick: () => {
93
94
  const pos = getPos();
94
95
  if (pos === undefined)
95
96
  return;
96
- (0, remove_node_1.removeNode)({
97
+ (0, utils_1.removeNode)({
97
98
  node,
98
99
  pos,
99
100
  tr: view.state.tr,
100
101
  dispatch: view.dispatch,
101
102
  });
102
- } }, "Remove"))))));
103
+ } }, (0, common_1.i18n)('remove')))))));
103
104
  };
104
105
  exports.MermaidView = MermaidView;
@@ -22,6 +22,16 @@ function generateID() {
22
22
  exports.generateID = generateID;
23
23
  const DEFAULT_PADDING = 20;
24
24
  const DEFAULT_DELAY = 100;
25
+ const createLinkCLickHandler = (value, document) => (event) => {
26
+ event.preventDefault();
27
+ const targetId = value.getAttribute('href');
28
+ if (targetId) {
29
+ const targetElement = document.querySelector(targetId);
30
+ if (targetElement) {
31
+ targetElement.scrollIntoView({ behavior: 'smooth' });
32
+ }
33
+ }
34
+ };
25
35
  const YfmHtmlBlockPreview = ({ html, onСlick, config }) => {
26
36
  var _a, _b, _c, _d, _e, _f;
27
37
  const ref = (0, react_1.useRef)(null);
@@ -30,11 +40,6 @@ const YfmHtmlBlockPreview = ({ html, onСlick, config }) => {
30
40
  const resizeConfig = (0, react_1.useRef)({});
31
41
  const [height, setHeight] = (0, react_1.useState)('100%');
32
42
  (0, react_1.useEffect)(() => {
33
- var _a, _b;
34
- resizeConfig.current = {
35
- padding: (_a = config === null || config === void 0 ? void 0 : config.resizePadding) !== null && _a !== void 0 ? _a : DEFAULT_PADDING,
36
- delay: (_b = config === null || config === void 0 ? void 0 : config.resizeDelay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY,
37
- };
38
43
  setStyles(config === null || config === void 0 ? void 0 : config.styles);
39
44
  setClassNames(config === null || config === void 0 ? void 0 : config.classNames);
40
45
  }, [config, (_c = (_b = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.document) === null || _c === void 0 ? void 0 : _c.body]);
@@ -103,18 +108,35 @@ const YfmHtmlBlockPreview = ({ html, onСlick, config }) => {
103
108
  styles.current = newStyles;
104
109
  }
105
110
  };
106
- (0, react_1.useEffect)(() => {
111
+ // finds all relative links (href^="#") and changes their click behavior
112
+ const createAnchorLinkHandlers = (type) => () => {
107
113
  var _a;
114
+ const document = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.contentWindow.document;
115
+ if (document) {
116
+ document.querySelectorAll('a[href^="#"]').forEach((value) => {
117
+ const handler = createLinkCLickHandler(value, document);
118
+ if (type === 'add') {
119
+ value.addEventListener('click', handler);
120
+ }
121
+ else {
122
+ value.removeEventListener('click', handler);
123
+ }
124
+ });
125
+ }
126
+ };
127
+ (0, react_1.useEffect)(() => {
128
+ var _a, _b;
108
129
  (_a = ref.current) === null || _a === void 0 ? void 0 : _a.addEventListener('load', handleLoadIFrame);
130
+ (_b = ref.current) === null || _b === void 0 ? void 0 : _b.addEventListener('load', createAnchorLinkHandlers('add'));
109
131
  return () => {
110
- var _a;
132
+ var _a, _b;
111
133
  (_a = ref.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('load', handleLoadIFrame);
134
+ (_b = ref.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('load', createAnchorLinkHandlers('remove'));
112
135
  };
113
136
  }, [html]);
114
137
  (0, react_1.useEffect)(() => {
115
- var _a, _b;
116
138
  if (ref.current) {
117
- const resizeObserver = new window.ResizeObserver((0, debounce_1.default)(handleResizeIFrame, (_b = (_a = resizeConfig.current) === null || _a === void 0 ? void 0 : _a.delay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY));
139
+ const resizeObserver = new window.ResizeObserver((0, debounce_1.default)(handleResizeIFrame, DEFAULT_DELAY));
118
140
  resizeObserver.observe(ref.current);
119
141
  }
120
142
  }, [(_f = (_e = (_d = ref.current) === null || _d === void 0 ? void 0 : _d.contentWindow) === null || _e === void 0 ? void 0 : _e.document) === null || _f === void 0 ? void 0 : _f.body]);
@@ -1,7 +1,7 @@
1
1
  import { PluginOptions } from '@diplodoc/html-extension/plugin/transform';
2
2
  import type { ExtensionNodeSpec } from '../../../../core';
3
3
  export { yfmHtmlBlockNodeName } from './const';
4
- export interface YfmHtmlBlockSpecsOptions extends Omit<PluginOptions, 'runtimeJsPath' | 'containerClasses' | 'bundle'> {
4
+ export interface YfmHtmlBlockSpecsOptions extends Omit<PluginOptions, 'runtimeJsPath' | 'containerClasses' | 'bundle' | 'embeddingMode'> {
5
5
  nodeView?: ExtensionNodeSpec['view'];
6
6
  }
7
7
  export declare const YfmHtmlBlockSpecs: import("../../../../core").ExtensionWithOptions<YfmHtmlBlockSpecsOptions> & {
@@ -10,14 +10,14 @@ Object.defineProperty(exports, "yfmHtmlBlockNodeName", { enumerable: true, get:
10
10
  const YfmHtmlBlockSpecsExtension = (builder, _a) => {
11
11
  var { nodeView } = _a, options = tslib_1.__rest(_a, ["nodeView"]);
12
12
  builder
13
- .configureMd((md) => md.use((0, html_extension_1.transform)(Object.assign({ bundle: false }, options)), {}))
13
+ .configureMd((md) => md.use((0, html_extension_1.transform)(Object.assign({ bundle: false, embeddingMode: 'srcdoc' }, options)), {}))
14
14
  .addNode(const_1.YfmHtmlBlockConsts.NodeName, () => ({
15
15
  fromMd: {
16
16
  tokenSpec: {
17
17
  name: const_1.YfmHtmlBlockConsts.NodeName,
18
18
  type: 'node',
19
19
  noCloseToken: true,
20
- getAttrs: (token) => { var _a; return Object.fromEntries((_a = token.attrs) !== null && _a !== void 0 ? _a : []); },
20
+ getAttrs: ({ content }) => ({ srcdoc: content }),
21
21
  },
22
22
  },
23
23
  spec: {
@@ -2,7 +2,7 @@ import { PluginOptions } from '@diplodoc/html-extension/plugin/transform';
2
2
  import type { IHTMLIFrameElementConfig } from '@diplodoc/html-extension/runtime';
3
3
  import { Action, ExtensionAuto } from '../../../core';
4
4
  import { YfmHtmlBlockAction } from './YfmHtmlBlockSpecs/const';
5
- export interface YfmHtmlBlockOptions extends Omit<PluginOptions, 'runtimeJsPath' | 'containerClasses' | 'bundle'> {
5
+ export interface YfmHtmlBlockOptions extends Omit<PluginOptions, 'runtimeJsPath' | 'containerClasses' | 'bundle' | 'embeddingMode'> {
6
6
  useConfig?: () => IHTMLIFrameElementConfig | undefined;
7
7
  }
8
8
  export declare const YfmHtmlBlock: ExtensionAuto<YfmHtmlBlockOptions>;
@@ -5,5 +5,14 @@
5
5
  "row.add.before": "Add row before",
6
6
  "row.add.after": "Add row after",
7
7
  "row.remove": "Remove row",
8
- "table.remove": "Remove table"
8
+ "table.remove": "Remove table",
9
+ "table.menu.cell.align.left": "Align cell content to the left",
10
+ "table.menu.cell.align.right": "Align cell content to the right",
11
+ "table.menu.cell.align.center": "Align cell content to the center",
12
+ "table.menu.row.add": "Add row after",
13
+ "table.menu.row.remove": "Remove row",
14
+ "table.menu.column.add": "Add column after",
15
+ "table.menu.column.remove": "Remove column",
16
+ "table.menu.convert.yfm": "Convert to YFM table",
17
+ "table.menu.table.remove": "Remove table"
9
18
  }
@@ -1,4 +1,4 @@
1
- export declare const i18n: <G extends "column.add.before" | "column.add.after" | "column.remove" | "row.add.before" | "row.add.after" | "row.remove" | "table.remove", S extends string>(key: G | (string extends S ? S : never), params?: {
1
+ export declare const i18n: <G extends "column.add.before" | "column.add.after" | "column.remove" | "row.add.before" | "row.add.after" | "row.remove" | "table.remove" | "table.menu.cell.align.left" | "table.menu.cell.align.right" | "table.menu.cell.align.center" | "table.menu.row.add" | "table.menu.row.remove" | "table.menu.column.add" | "table.menu.column.remove" | "table.menu.convert.yfm" | "table.menu.table.remove", S extends string>(key: G | (string extends S ? S : never), params?: {
2
2
  [key: string]: any;
3
3
  } | undefined) => S extends G ? {
4
4
  "column.add.before": string;
@@ -8,4 +8,13 @@ export declare const i18n: <G extends "column.add.before" | "column.add.after" |
8
8
  "row.add.after": string;
9
9
  "row.remove": string;
10
10
  "table.remove": string;
11
+ "table.menu.cell.align.left": string;
12
+ "table.menu.cell.align.right": string;
13
+ "table.menu.cell.align.center": string;
14
+ "table.menu.row.add": string;
15
+ "table.menu.row.remove": string;
16
+ "table.menu.column.add": string;
17
+ "table.menu.column.remove": string;
18
+ "table.menu.convert.yfm": string;
19
+ "table.menu.table.remove": string;
11
20
  }[G] : string;
@@ -5,5 +5,14 @@
5
5
  "row.add.before": "Добавить строку до",
6
6
  "row.add.after": "Добавить строку после",
7
7
  "row.remove": "Удалить строку",
8
- "table.remove": "Удалить таблицу"
8
+ "table.remove": "Удалить таблицу",
9
+ "table.menu.cell.align.left": "Выровнять контент ячейки по левому краю",
10
+ "table.menu.cell.align.right": "Выровнять контент ячейки по правому краю",
11
+ "table.menu.cell.align.center": "Выровнять контент ячейки по центру",
12
+ "table.menu.row.add": "Добавить строку после",
13
+ "table.menu.row.remove": "Удалить строку",
14
+ "table.menu.column.add": "Добавить столбец после",
15
+ "table.menu.column.remove": "Удалить столбец",
16
+ "table.menu.convert.yfm": "Преобразовать в таблицу YFM",
17
+ "table.menu.table.remove": "Удалить таблицу"
9
18
  }
@@ -1,6 +1,7 @@
1
1
  import { RefObject } from 'react';
2
2
  import { EditorView } from 'prosemirror-view';
3
- export declare const useNodeEditing: ({ nodeRef, view, }: {
3
+ export interface UseNodeEditingArgs {
4
4
  nodeRef: RefObject<HTMLElement>;
5
5
  view: EditorView;
6
- }) => [boolean, () => void, () => void, () => void];
6
+ }
7
+ export declare const useNodeEditing: ({ nodeRef, view }: UseNodeEditingArgs) => [boolean, () => void, () => void, () => void];
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useNodeEditing = void 0;
4
4
  const react_1 = require("react");
5
5
  const hooks_1 = require("./hooks");
6
- const useNodeEditing = ({ nodeRef, view, }) => {
6
+ const useNodeEditing = ({ nodeRef, view }) => {
7
7
  const state = (0, hooks_1.useBooleanState)(false);
8
8
  const [, , unsetEdit, toggleEdit] = state;
9
9
  (0, react_1.useEffect)(() => {
@@ -0,0 +1,22 @@
1
+ import React, { RefObject } from 'react';
2
+ export declare type ResizeDirection = 'left' | 'right';
3
+ export interface UseNodeResizingArgs {
4
+ width?: number;
5
+ height?: number;
6
+ onResize?: ({ width, height }: {
7
+ width?: number;
8
+ height?: number;
9
+ }) => void;
10
+ ref: RefObject<HTMLImageElement | HTMLDivElement> | null;
11
+ delay?: number;
12
+ threshold?: number;
13
+ minWidth?: number;
14
+ }
15
+ export declare const useNodeResizing: ({ width, height, onResize, ref, delay, threshold, minWidth, }: UseNodeResizingArgs) => {
16
+ startResizing: (event: React.MouseEvent<HTMLElement>, direction: ResizeDirection) => void;
17
+ state: {
18
+ resizing: boolean;
19
+ width: number | undefined;
20
+ height: number | undefined;
21
+ };
22
+ };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useNodeResizing = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = require("react");
6
+ const throttle_1 = tslib_1.__importDefault(require("lodash/throttle"));
7
+ const hooks_1 = require("./hooks");
8
+ const RESIZE_DELAY = 50;
9
+ const MIN_WIDTH = 40;
10
+ const THRESHOLD = 4;
11
+ const useNodeResizing = ({ width, height, onResize, ref, delay = RESIZE_DELAY, threshold = THRESHOLD, minWidth = MIN_WIDTH, }) => {
12
+ const state = (0, hooks_1.useBooleanState)(false);
13
+ const [resizing, , , toggleResizing] = state;
14
+ const [initialWidth, setInitialWidth] = (0, react_1.useState)(width);
15
+ const [initialHeight, setInitialHeight] = (0, react_1.useState)(height);
16
+ const [currentWidth, setCurrentWidth] = (0, react_1.useState)(width);
17
+ const [currentHeight, setCurrentHeight] = (0, react_1.useState)(height);
18
+ // The dimensions specified as arguments take primacy over
19
+ // the dimensions detected during the mouse movement.
20
+ (0, react_1.useEffect)(() => {
21
+ if (width !== initialWidth) {
22
+ setCurrentWidth(width);
23
+ setInitialWidth(width);
24
+ }
25
+ if (height !== initialHeight) {
26
+ setCurrentHeight(height);
27
+ setInitialHeight(height);
28
+ }
29
+ }, [width, height, initialWidth, initialHeight]);
30
+ const startResizing = (event, direction) => {
31
+ // prohibit the selection of text and other artifacts when resizing.
32
+ event.preventDefault();
33
+ const element = ref === null || ref === void 0 ? void 0 : ref.current;
34
+ if (!element) {
35
+ throw new Error('Reference element not found!');
36
+ }
37
+ const startX = event.pageX;
38
+ const startWidth = element.getBoundingClientRect().width || 0;
39
+ const startHeight = element.getBoundingClientRect().height || 0;
40
+ let animationFrameId;
41
+ const handleMouseMove = (0, throttle_1.default)((event) => {
42
+ if (animationFrameId) {
43
+ cancelAnimationFrame(animationFrameId);
44
+ }
45
+ animationFrameId = requestAnimationFrame(() => {
46
+ const currentX = event.pageX;
47
+ const diffX = currentX - startX;
48
+ const newWidthByDirection = direction === 'right' ? startWidth + diffX : startWidth - diffX;
49
+ if (Math.abs(newWidthByDirection - startWidth) >= threshold) {
50
+ const newWidth = newWidthByDirection >= minWidth ? newWidthByDirection : minWidth;
51
+ const newHeight = (startHeight / startWidth) * newWidth;
52
+ setCurrentWidth(newWidth);
53
+ setCurrentHeight(newHeight);
54
+ onResize === null || onResize === void 0 ? void 0 : onResize({
55
+ width: !initialWidth && initialWidth !== 0 ? undefined : newWidth,
56
+ height: !initialHeight && initialHeight !== 0 ? undefined : newHeight,
57
+ });
58
+ }
59
+ });
60
+ }, delay);
61
+ const handleMouseUp = () => {
62
+ document.removeEventListener('mousemove', handleMouseMove);
63
+ document.removeEventListener('mouseup', handleMouseUp);
64
+ toggleResizing();
65
+ if (animationFrameId) {
66
+ cancelAnimationFrame(animationFrameId);
67
+ }
68
+ };
69
+ document.addEventListener('mousemove', handleMouseMove);
70
+ document.addEventListener('mouseup', handleMouseUp);
71
+ toggleResizing();
72
+ };
73
+ return {
74
+ startResizing,
75
+ state: {
76
+ resizing,
77
+ width: !initialWidth && initialWidth !== 0 ? undefined : currentWidth,
78
+ height: !initialHeight && initialHeight !== 0 ? undefined : currentHeight,
79
+ },
80
+ };
81
+ };
82
+ exports.useNodeResizing = useNodeResizing;
@@ -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.16.0' !== 'undefined' ? '13.16.0' : 'unknown';
5
+ exports.VERSION = typeof '13.17.1' !== 'undefined' ? '13.17.1' : 'unknown';