@gravity-ui/markdown-editor 13.11.0 → 13.12.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.
- package/build/cjs/bundle/Editor.d.ts +3 -1
- package/build/cjs/bundle/Editor.js +5 -4
- package/build/cjs/bundle/MarkdownEditorView.js +5 -1
- package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/NodeView.js +1 -1
- package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.d.ts +2 -3
- package/build/cjs/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.js +9 -2
- package/build/cjs/extensions/yfm/YfmHtmlBlock/utils.d.ts +7 -0
- package/build/cjs/extensions/yfm/YfmHtmlBlock/utils.js +73 -0
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/Editor.d.ts +3 -1
- package/build/esm/bundle/Editor.js +6 -5
- package/build/esm/bundle/MarkdownEditorView.js +5 -1
- package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/NodeView.js +1 -1
- package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.d.ts +3 -4
- package/build/esm/extensions/yfm/YfmHtmlBlock/YfmHtmlBlockNodeView/YfmHtmlBlockView.js +10 -3
- package/build/esm/extensions/yfm/YfmHtmlBlock/utils.d.ts +7 -0
- package/build/esm/extensions/yfm/YfmHtmlBlock/utils.js +67 -0
- package/build/esm/version.js +1 -1
- package/package.json +3 -2
|
@@ -39,11 +39,12 @@ export interface EventMap {
|
|
|
39
39
|
export interface Editor extends Receiver<EventMap>, CommonEditor {
|
|
40
40
|
readonly currentMode: EditorMode;
|
|
41
41
|
readonly toolbarVisible: boolean;
|
|
42
|
-
setEditorMode(mode: EditorMode): void;
|
|
42
|
+
setEditorMode(mode: EditorMode, opts?: SetEditorModeOptions): void;
|
|
43
43
|
moveCursor(position: 'start' | 'end' | {
|
|
44
44
|
line: number;
|
|
45
45
|
}): void;
|
|
46
46
|
}
|
|
47
|
+
declare type SetEditorModeOptions = Pick<ChangeEditorModeOptions, 'emit'>;
|
|
47
48
|
export declare type MarkupConfig = {
|
|
48
49
|
/** Additional extensions for codemirror instance. */
|
|
49
50
|
extensions?: CreateCodemirrorParams['extensions'];
|
|
@@ -88,3 +89,4 @@ export declare type EditorOptions = Pick<WysiwygEditorOptions, 'allowHTML' | 'li
|
|
|
88
89
|
extraMarkupExtensions?: CodemirrorExtension[];
|
|
89
90
|
markupConfig?: MarkupConfig;
|
|
90
91
|
};
|
|
92
|
+
export {};
|
|
@@ -195,15 +195,16 @@ class EditorImpl extends event_emitter_1.SafeEventEmitter {
|
|
|
195
195
|
tslib_1.__classPrivateFieldSet(this, _EditorImpl_markupEditor, undefined, "f");
|
|
196
196
|
tslib_1.__classPrivateFieldSet(this, _EditorImpl_wysiwygEditor, undefined, "f");
|
|
197
197
|
}
|
|
198
|
-
setEditorMode(mode) {
|
|
199
|
-
this.changeEditorMode({ mode, reason: 'manually' });
|
|
198
|
+
setEditorMode(mode, opts) {
|
|
199
|
+
this.changeEditorMode({ mode, reason: 'manually', emit: opts === null || opts === void 0 ? void 0 : opts.emit });
|
|
200
200
|
}
|
|
201
|
-
changeEditorMode(
|
|
201
|
+
changeEditorMode(_a) {
|
|
202
|
+
var { emit = true } = _a, opts = tslib_1.__rest(_a, ["emit"]);
|
|
202
203
|
if (tslib_1.__classPrivateFieldGet(this, _EditorImpl_editorMode, "f") === opts.mode)
|
|
203
204
|
return;
|
|
204
205
|
this.currentMode = opts.mode;
|
|
205
206
|
this.emit('rerender', null);
|
|
206
|
-
if (
|
|
207
|
+
if (emit) {
|
|
207
208
|
this.emit('change-editor-mode', opts);
|
|
208
209
|
}
|
|
209
210
|
}
|
|
@@ -90,7 +90,11 @@ exports.MarkdownEditorView = react_1.default.forwardRef((props, ref) => {
|
|
|
90
90
|
});
|
|
91
91
|
setTimeout(() => {
|
|
92
92
|
resetErrorBoundary();
|
|
93
|
-
editor.changeEditorMode({
|
|
93
|
+
editor.changeEditorMode({
|
|
94
|
+
mode: 'markup',
|
|
95
|
+
reason: 'error-boundary',
|
|
96
|
+
emit: false,
|
|
97
|
+
});
|
|
94
98
|
});
|
|
95
99
|
return null;
|
|
96
100
|
} },
|
|
@@ -51,7 +51,7 @@ class WYfmHtmlBlockNodeView {
|
|
|
51
51
|
this.view.dispatch(tr);
|
|
52
52
|
}
|
|
53
53
|
renderYfmHtmlBlock() {
|
|
54
|
-
return (0, react_dom_1.createPortal)(react_1.default.createElement(YfmHtmlBlockView_1.YfmHtmlBlockView, { getPos: this.getPos, node: this.node, onChange: this.onChange.bind(this),
|
|
54
|
+
return (0, react_dom_1.createPortal)(react_1.default.createElement(YfmHtmlBlockView_1.YfmHtmlBlockView, { getPos: this.getPos, node: this.node, onChange: this.onChange.bind(this), options: this.options, view: this.view }), this.dom);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
exports.WYfmHtmlBlockNodeView = WYfmHtmlBlockNodeView;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { IHTMLIFrameElementConfig } from '@diplodoc/html-extension/runtime';
|
|
3
2
|
import { Node } from 'prosemirror-model';
|
|
4
3
|
import { EditorView } from 'prosemirror-view';
|
|
5
4
|
import { YfmHtmlBlockConsts } from '../YfmHtmlBlockSpecs/const';
|
|
5
|
+
import { YfmHtmlBlockOptions } from '../index';
|
|
6
6
|
export declare const cnYfmHtmlBlock: import("@bem-react/classname").ClassNameFormatter;
|
|
7
7
|
export declare const cnHelper: import("@bem-react/classname").ClassNameFormatter;
|
|
8
8
|
export declare function generateID(): string;
|
|
@@ -12,7 +12,6 @@ export declare const YfmHtmlBlockView: React.FC<{
|
|
|
12
12
|
onChange: (attrs: {
|
|
13
13
|
[YfmHtmlBlockConsts.NodeAttrs.srcdoc]: string;
|
|
14
14
|
}) => void;
|
|
15
|
-
|
|
16
|
-
useConfig?: () => IHTMLIFrameElementConfig | undefined;
|
|
15
|
+
options: YfmHtmlBlockOptions;
|
|
17
16
|
view: EditorView;
|
|
18
17
|
}>;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.YfmHtmlBlockView = exports.generateID = exports.cnHelper = exports.cnYfmHtmlBlock = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const react_1 = tslib_1.__importStar(require("react"));
|
|
6
|
+
const html_extension_1 = require("@diplodoc/html-extension");
|
|
6
7
|
const icons_1 = require("@gravity-ui/icons");
|
|
7
8
|
const uikit_1 = require("@gravity-ui/uikit");
|
|
8
9
|
const debounce_1 = tslib_1.__importDefault(require("lodash/debounce"));
|
|
@@ -137,7 +138,7 @@ const CodeEditMode = ({ initialText, onSave, onCancel }) => {
|
|
|
137
138
|
react_1.default.createElement(uikit_1.Button, { onClick: () => onSave(text), view: 'action' },
|
|
138
139
|
react_1.default.createElement("span", { className: (0, exports.cnHelper)({ 'prosemirror-stop-event': true }) }, (0, common_1.i18n)('save'))))))));
|
|
139
140
|
};
|
|
140
|
-
const YfmHtmlBlockView = ({ onChange, node, getPos, view, useConfig, sanitize }) => {
|
|
141
|
+
const YfmHtmlBlockView = ({ onChange, node, getPos, view, options: { useConfig, sanitize, styles, baseTarget = '_' } }) => {
|
|
141
142
|
const [editing, setEditing, unsetEditing, toggleEditing] = (0, hooks_1.useBooleanState)(Boolean(node.attrs[const_1.YfmHtmlBlockConsts.NodeAttrs.newCreated]));
|
|
142
143
|
const config = useConfig === null || useConfig === void 0 ? void 0 : useConfig();
|
|
143
144
|
const [menuOpen, , , toggleMenuOpen] = (0, hooks_1.useBooleanState)(false);
|
|
@@ -151,7 +152,13 @@ const YfmHtmlBlockView = ({ onChange, node, getPos, view, useConfig, sanitize })
|
|
|
151
152
|
unsetEditing();
|
|
152
153
|
} }));
|
|
153
154
|
}
|
|
154
|
-
|
|
155
|
+
let dirtyHtml = `<base target="${baseTarget}">` + node.attrs[const_1.YfmHtmlBlockConsts.NodeAttrs.srcdoc];
|
|
156
|
+
if (styles) {
|
|
157
|
+
const stylesContent = typeof styles === 'string'
|
|
158
|
+
? `<link rel="stylesheet" href="${styles}" />`
|
|
159
|
+
: `<style>${(0, html_extension_1.getStyles)(styles)}</style>`;
|
|
160
|
+
dirtyHtml = stylesContent + dirtyHtml;
|
|
161
|
+
}
|
|
155
162
|
const html = sanitize ? sanitize(dirtyHtml) : dirtyHtml;
|
|
156
163
|
return (react_1.default.createElement("div", { className: b(), onDoubleClick: setEditing },
|
|
157
164
|
react_1.default.createElement(uikit_1.Label, { className: b('label'), icon: react_1.default.createElement(uikit_1.Icon, { size: 16, data: icons_1.Eye }) }, (0, common_1.i18n)('preview')),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SanitizeOptions } from '@diplodoc/transform/lib/sanitize';
|
|
2
|
+
export declare const getYfmHtmlBlockOptions: (defaultOptions: SanitizeOptions) => SanitizeOptions;
|
|
3
|
+
export interface GetSanitizeYfmHtmlBlockArgs {
|
|
4
|
+
options: SanitizeOptions;
|
|
5
|
+
sanitize?: (html: string, options?: SanitizeOptions) => string;
|
|
6
|
+
}
|
|
7
|
+
export declare const getSanitizeYfmHtmlBlock: ({ options, sanitize }: GetSanitizeYfmHtmlBlockArgs) => (content: string) => string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSanitizeYfmHtmlBlock = exports.getYfmHtmlBlockOptions = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const sanitize_1 = tslib_1.__importDefault(require("@diplodoc/transform/lib/sanitize"));
|
|
6
|
+
// yfmHtmlBlock additional css properties white list
|
|
7
|
+
const getYfmHtmlBlockWhiteList = () => {
|
|
8
|
+
const whiteList = {};
|
|
9
|
+
whiteList['align-content'] = true; // default: auto
|
|
10
|
+
whiteList['align-items'] = true; // default: auto
|
|
11
|
+
whiteList['align-self'] = true; // default: auto
|
|
12
|
+
whiteList.columns = true; // default: depending on individual properties
|
|
13
|
+
whiteList['column-count'] = true; // default: auto
|
|
14
|
+
whiteList['column-fill'] = true; // default: balance
|
|
15
|
+
whiteList['column-gap'] = true; // default: normal
|
|
16
|
+
whiteList['column-rule'] = true; // default: depending on individual properties
|
|
17
|
+
whiteList['column-rule-color'] = true; // default: current color
|
|
18
|
+
whiteList['column-rule-style'] = true; // default: medium
|
|
19
|
+
whiteList['column-rule-width'] = true; // default: medium
|
|
20
|
+
whiteList['column-span'] = true; // default: none
|
|
21
|
+
whiteList['column-width'] = true; // default: auto
|
|
22
|
+
whiteList.flex = true; // default: depending on individual properties
|
|
23
|
+
whiteList['flex-basis'] = true; // default: auto
|
|
24
|
+
whiteList['flex-direction'] = true; // default: row
|
|
25
|
+
whiteList['flex-flow'] = true; // default: depending on individual properties
|
|
26
|
+
whiteList['flex-grow'] = true; // default: 0
|
|
27
|
+
whiteList['flex-shrink'] = true; // default: 1
|
|
28
|
+
whiteList['flex-wrap'] = true; // default: nowrap
|
|
29
|
+
whiteList.gap = true; // default: normal normal
|
|
30
|
+
whiteList.grid = true; // default: depending on individual properties
|
|
31
|
+
whiteList['grid-area'] = true; // default: depending on individual properties
|
|
32
|
+
whiteList['grid-auto-columns'] = true; // default: auto
|
|
33
|
+
whiteList['grid-auto-flow'] = true; // default: none
|
|
34
|
+
whiteList['grid-auto-rows'] = true; // default: auto
|
|
35
|
+
whiteList['grid-column'] = true; // default: depending on individual properties
|
|
36
|
+
whiteList['grid-column-end'] = true; // default: auto
|
|
37
|
+
whiteList['grid-column-start'] = true; // default: auto
|
|
38
|
+
whiteList['grid-row'] = true; // default: depending on individual properties
|
|
39
|
+
whiteList['grid-row-end'] = true; // default: auto
|
|
40
|
+
whiteList['grid-row-start'] = true; // default: auto
|
|
41
|
+
whiteList['grid-template'] = true; // default: depending on individual properties
|
|
42
|
+
whiteList['grid-template-areas'] = true; // default: none
|
|
43
|
+
whiteList['grid-template-columns'] = true; // default: none
|
|
44
|
+
whiteList['grid-template-rows'] = true; // default: none
|
|
45
|
+
whiteList['justify-content'] = true; // default: auto
|
|
46
|
+
whiteList['justify-items'] = true; // default: auto
|
|
47
|
+
whiteList['justify-self'] = true; // default: auto
|
|
48
|
+
whiteList['line-height'] = true; // default: normal
|
|
49
|
+
whiteList['object-fit'] = true; // default: fill
|
|
50
|
+
whiteList['object-position'] = true; // default: 50% 50%
|
|
51
|
+
whiteList.order = true; // default: 0
|
|
52
|
+
whiteList.orphans = true; // default: 2
|
|
53
|
+
whiteList['row-gap'] = true;
|
|
54
|
+
return whiteList;
|
|
55
|
+
};
|
|
56
|
+
// yfmHtmlBlock additional allowedTags
|
|
57
|
+
const yfmHtmlBlockAllowedTags = ['link', 'base', 'style'];
|
|
58
|
+
// yfmHtmlBlock additional allowedTags
|
|
59
|
+
const yfmHtmlBlockAllowedAttributes = {
|
|
60
|
+
link: ['rel', 'href'],
|
|
61
|
+
base: ['target'],
|
|
62
|
+
style: [],
|
|
63
|
+
};
|
|
64
|
+
const getYfmHtmlBlockOptions = (defaultOptions) => {
|
|
65
|
+
var _a;
|
|
66
|
+
const defaultAllowedAttributes = defaultOptions.allowedAttributes;
|
|
67
|
+
return Object.assign(Object.assign({}, defaultOptions), { allowedAttributes: Object.assign(Object.assign({}, defaultAllowedAttributes), yfmHtmlBlockAllowedAttributes), allowedTags: typeof defaultOptions.allowedTags === 'boolean'
|
|
68
|
+
? defaultOptions.allowedTags
|
|
69
|
+
: [...((_a = defaultOptions.allowedTags) !== null && _a !== void 0 ? _a : []), ...yfmHtmlBlockAllowedTags], cssWhiteList: Object.assign(Object.assign({}, defaultOptions.cssWhiteList), getYfmHtmlBlockWhiteList()) });
|
|
70
|
+
};
|
|
71
|
+
exports.getYfmHtmlBlockOptions = getYfmHtmlBlockOptions;
|
|
72
|
+
const getSanitizeYfmHtmlBlock = ({ options, sanitize = sanitize_1.default }) => (content) => sanitize(content, (0, exports.getYfmHtmlBlockOptions)(options));
|
|
73
|
+
exports.getSanitizeYfmHtmlBlock = getSanitizeYfmHtmlBlock;
|
package/build/cjs/version.js
CHANGED
|
@@ -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.
|
|
5
|
+
exports.VERSION = typeof '13.12.1' !== 'undefined' ? '13.12.1' : 'unknown';
|
|
@@ -39,11 +39,12 @@ export interface EventMap {
|
|
|
39
39
|
export interface Editor extends Receiver<EventMap>, CommonEditor {
|
|
40
40
|
readonly currentMode: EditorMode;
|
|
41
41
|
readonly toolbarVisible: boolean;
|
|
42
|
-
setEditorMode(mode: EditorMode): void;
|
|
42
|
+
setEditorMode(mode: EditorMode, opts?: SetEditorModeOptions): void;
|
|
43
43
|
moveCursor(position: 'start' | 'end' | {
|
|
44
44
|
line: number;
|
|
45
45
|
}): void;
|
|
46
46
|
}
|
|
47
|
+
declare type SetEditorModeOptions = Pick<ChangeEditorModeOptions, 'emit'>;
|
|
47
48
|
export declare type MarkupConfig = {
|
|
48
49
|
/** Additional extensions for codemirror instance. */
|
|
49
50
|
extensions?: CreateCodemirrorParams['extensions'];
|
|
@@ -88,3 +89,4 @@ export declare type EditorOptions = Pick<WysiwygEditorOptions, 'allowHTML' | 'li
|
|
|
88
89
|
extraMarkupExtensions?: CodemirrorExtension[];
|
|
89
90
|
markupConfig?: MarkupConfig;
|
|
90
91
|
};
|
|
92
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var _EditorImpl_markup, _EditorImpl_editorMode, _EditorImpl_toolbarVisible, _EditorImpl_splitModeEnabled, _EditorImpl_splitMode, _EditorImpl_renderPreview, _EditorImpl_wysiwygEditor, _EditorImpl_markupEditor, _EditorImpl_markupConfig, _EditorImpl_preset, _EditorImpl_allowHTML, _EditorImpl_linkify, _EditorImpl_linkifyTlds, _EditorImpl_extensions, _EditorImpl_renderStorage, _EditorImpl_fileUploadHandler, _EditorImpl_needToSetDimensionsForUploadedImages, _EditorImpl_prepareRawMarkup;
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
2
|
+
import { __classPrivateFieldGet, __classPrivateFieldSet, __rest } from "tslib";
|
|
3
3
|
import { TextSelection } from 'prosemirror-state';
|
|
4
4
|
import { WysiwygEditor } from '../core';
|
|
5
5
|
import { i18n } from '../i18n/bundle';
|
|
@@ -192,15 +192,16 @@ export class EditorImpl extends SafeEventEmitter {
|
|
|
192
192
|
__classPrivateFieldSet(this, _EditorImpl_markupEditor, undefined, "f");
|
|
193
193
|
__classPrivateFieldSet(this, _EditorImpl_wysiwygEditor, undefined, "f");
|
|
194
194
|
}
|
|
195
|
-
setEditorMode(mode) {
|
|
196
|
-
this.changeEditorMode({ mode, reason: 'manually' });
|
|
195
|
+
setEditorMode(mode, opts) {
|
|
196
|
+
this.changeEditorMode({ mode, reason: 'manually', emit: opts === null || opts === void 0 ? void 0 : opts.emit });
|
|
197
197
|
}
|
|
198
|
-
changeEditorMode(
|
|
198
|
+
changeEditorMode(_a) {
|
|
199
|
+
var { emit = true } = _a, opts = __rest(_a, ["emit"]);
|
|
199
200
|
if (__classPrivateFieldGet(this, _EditorImpl_editorMode, "f") === opts.mode)
|
|
200
201
|
return;
|
|
201
202
|
this.currentMode = opts.mode;
|
|
202
203
|
this.emit('rerender', null);
|
|
203
|
-
if (
|
|
204
|
+
if (emit) {
|
|
204
205
|
this.emit('change-editor-mode', opts);
|
|
205
206
|
}
|
|
206
207
|
}
|
|
@@ -87,7 +87,11 @@ export const MarkdownEditorView = React.forwardRef((props, ref) => {
|
|
|
87
87
|
});
|
|
88
88
|
setTimeout(() => {
|
|
89
89
|
resetErrorBoundary();
|
|
90
|
-
editor.changeEditorMode({
|
|
90
|
+
editor.changeEditorMode({
|
|
91
|
+
mode: 'markup',
|
|
92
|
+
reason: 'error-boundary',
|
|
93
|
+
emit: false,
|
|
94
|
+
});
|
|
91
95
|
});
|
|
92
96
|
return null;
|
|
93
97
|
} },
|
|
@@ -47,6 +47,6 @@ export class WYfmHtmlBlockNodeView {
|
|
|
47
47
|
this.view.dispatch(tr);
|
|
48
48
|
}
|
|
49
49
|
renderYfmHtmlBlock() {
|
|
50
|
-
return createPortal(React.createElement(YfmHtmlBlockView, { getPos: this.getPos, node: this.node, onChange: this.onChange.bind(this),
|
|
50
|
+
return createPortal(React.createElement(YfmHtmlBlockView, { getPos: this.getPos, node: this.node, onChange: this.onChange.bind(this), options: this.options, view: this.view }), this.dom);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { IHTMLIFrameElementConfig } from '@diplodoc/html-extension/runtime';
|
|
3
2
|
import { Node } from 'prosemirror-model';
|
|
4
3
|
import { EditorView } from 'prosemirror-view';
|
|
5
4
|
import { YfmHtmlBlockConsts } from '../YfmHtmlBlockSpecs/const';
|
|
5
|
+
import { YfmHtmlBlockOptions } from '../index';
|
|
6
|
+
import './YfmHtmlBlock.css';
|
|
6
7
|
export declare const cnYfmHtmlBlock: import("@bem-react/classname").ClassNameFormatter;
|
|
7
8
|
export declare const cnHelper: import("@bem-react/classname").ClassNameFormatter;
|
|
8
|
-
import './YfmHtmlBlock.css';
|
|
9
9
|
export declare function generateID(): string;
|
|
10
10
|
export declare const YfmHtmlBlockView: React.FC<{
|
|
11
11
|
getPos: () => number | undefined;
|
|
@@ -13,7 +13,6 @@ export declare const YfmHtmlBlockView: React.FC<{
|
|
|
13
13
|
onChange: (attrs: {
|
|
14
14
|
[YfmHtmlBlockConsts.NodeAttrs.srcdoc]: string;
|
|
15
15
|
}) => void;
|
|
16
|
-
|
|
17
|
-
useConfig?: () => IHTMLIFrameElementConfig | undefined;
|
|
16
|
+
options: YfmHtmlBlockOptions;
|
|
18
17
|
view: EditorView;
|
|
19
18
|
}>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { getStyles } from '@diplodoc/html-extension';
|
|
2
3
|
import { Ellipsis as DotsIcon, Eye } from '@gravity-ui/icons';
|
|
3
4
|
import { Button, Icon, Label, Menu, Popup } from '@gravity-ui/uikit';
|
|
4
5
|
import debounce from 'lodash/debounce';
|
|
@@ -8,9 +9,9 @@ import { i18n } from '../../../../i18n/common';
|
|
|
8
9
|
import { useBooleanState } from '../../../../react-utils/hooks';
|
|
9
10
|
import { removeNode } from '../../../../utils/remove-node';
|
|
10
11
|
import { YfmHtmlBlockConsts } from '../YfmHtmlBlockSpecs/const';
|
|
12
|
+
import './YfmHtmlBlock.css';
|
|
11
13
|
export const cnYfmHtmlBlock = cn('yfm-html-block');
|
|
12
14
|
export const cnHelper = cn('yfm-html-block-helper');
|
|
13
|
-
import './YfmHtmlBlock.css';
|
|
14
15
|
const b = cnYfmHtmlBlock;
|
|
15
16
|
export function generateID() {
|
|
16
17
|
return Math.random().toString(36).substr(2, 8);
|
|
@@ -133,7 +134,7 @@ const CodeEditMode = ({ initialText, onSave, onCancel }) => {
|
|
|
133
134
|
React.createElement(Button, { onClick: () => onSave(text), view: 'action' },
|
|
134
135
|
React.createElement("span", { className: cnHelper({ 'prosemirror-stop-event': true }) }, i18n('save'))))))));
|
|
135
136
|
};
|
|
136
|
-
export const YfmHtmlBlockView = ({ onChange, node, getPos, view, useConfig, sanitize }) => {
|
|
137
|
+
export const YfmHtmlBlockView = ({ onChange, node, getPos, view, options: { useConfig, sanitize, styles, baseTarget = '_' } }) => {
|
|
137
138
|
const [editing, setEditing, unsetEditing, toggleEditing] = useBooleanState(Boolean(node.attrs[YfmHtmlBlockConsts.NodeAttrs.newCreated]));
|
|
138
139
|
const config = useConfig === null || useConfig === void 0 ? void 0 : useConfig();
|
|
139
140
|
const [menuOpen, , , toggleMenuOpen] = useBooleanState(false);
|
|
@@ -147,7 +148,13 @@ export const YfmHtmlBlockView = ({ onChange, node, getPos, view, useConfig, sani
|
|
|
147
148
|
unsetEditing();
|
|
148
149
|
} }));
|
|
149
150
|
}
|
|
150
|
-
|
|
151
|
+
let dirtyHtml = `<base target="${baseTarget}">` + node.attrs[YfmHtmlBlockConsts.NodeAttrs.srcdoc];
|
|
152
|
+
if (styles) {
|
|
153
|
+
const stylesContent = typeof styles === 'string'
|
|
154
|
+
? `<link rel="stylesheet" href="${styles}" />`
|
|
155
|
+
: `<style>${getStyles(styles)}</style>`;
|
|
156
|
+
dirtyHtml = stylesContent + dirtyHtml;
|
|
157
|
+
}
|
|
151
158
|
const html = sanitize ? sanitize(dirtyHtml) : dirtyHtml;
|
|
152
159
|
return (React.createElement("div", { className: b(), onDoubleClick: setEditing },
|
|
153
160
|
React.createElement(Label, { className: b('label'), icon: React.createElement(Icon, { size: 16, data: Eye }) }, i18n('preview')),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SanitizeOptions } from '@diplodoc/transform/lib/sanitize';
|
|
2
|
+
export declare const getYfmHtmlBlockOptions: (defaultOptions: SanitizeOptions) => SanitizeOptions;
|
|
3
|
+
export interface GetSanitizeYfmHtmlBlockArgs {
|
|
4
|
+
options: SanitizeOptions;
|
|
5
|
+
sanitize?: (html: string, options?: SanitizeOptions) => string;
|
|
6
|
+
}
|
|
7
|
+
export declare const getSanitizeYfmHtmlBlock: ({ options, sanitize }: GetSanitizeYfmHtmlBlockArgs) => (content: string) => string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import diplodocSanitize from '@diplodoc/transform/lib/sanitize';
|
|
2
|
+
// yfmHtmlBlock additional css properties white list
|
|
3
|
+
const getYfmHtmlBlockWhiteList = () => {
|
|
4
|
+
const whiteList = {};
|
|
5
|
+
whiteList['align-content'] = true; // default: auto
|
|
6
|
+
whiteList['align-items'] = true; // default: auto
|
|
7
|
+
whiteList['align-self'] = true; // default: auto
|
|
8
|
+
whiteList.columns = true; // default: depending on individual properties
|
|
9
|
+
whiteList['column-count'] = true; // default: auto
|
|
10
|
+
whiteList['column-fill'] = true; // default: balance
|
|
11
|
+
whiteList['column-gap'] = true; // default: normal
|
|
12
|
+
whiteList['column-rule'] = true; // default: depending on individual properties
|
|
13
|
+
whiteList['column-rule-color'] = true; // default: current color
|
|
14
|
+
whiteList['column-rule-style'] = true; // default: medium
|
|
15
|
+
whiteList['column-rule-width'] = true; // default: medium
|
|
16
|
+
whiteList['column-span'] = true; // default: none
|
|
17
|
+
whiteList['column-width'] = true; // default: auto
|
|
18
|
+
whiteList.flex = true; // default: depending on individual properties
|
|
19
|
+
whiteList['flex-basis'] = true; // default: auto
|
|
20
|
+
whiteList['flex-direction'] = true; // default: row
|
|
21
|
+
whiteList['flex-flow'] = true; // default: depending on individual properties
|
|
22
|
+
whiteList['flex-grow'] = true; // default: 0
|
|
23
|
+
whiteList['flex-shrink'] = true; // default: 1
|
|
24
|
+
whiteList['flex-wrap'] = true; // default: nowrap
|
|
25
|
+
whiteList.gap = true; // default: normal normal
|
|
26
|
+
whiteList.grid = true; // default: depending on individual properties
|
|
27
|
+
whiteList['grid-area'] = true; // default: depending on individual properties
|
|
28
|
+
whiteList['grid-auto-columns'] = true; // default: auto
|
|
29
|
+
whiteList['grid-auto-flow'] = true; // default: none
|
|
30
|
+
whiteList['grid-auto-rows'] = true; // default: auto
|
|
31
|
+
whiteList['grid-column'] = true; // default: depending on individual properties
|
|
32
|
+
whiteList['grid-column-end'] = true; // default: auto
|
|
33
|
+
whiteList['grid-column-start'] = true; // default: auto
|
|
34
|
+
whiteList['grid-row'] = true; // default: depending on individual properties
|
|
35
|
+
whiteList['grid-row-end'] = true; // default: auto
|
|
36
|
+
whiteList['grid-row-start'] = true; // default: auto
|
|
37
|
+
whiteList['grid-template'] = true; // default: depending on individual properties
|
|
38
|
+
whiteList['grid-template-areas'] = true; // default: none
|
|
39
|
+
whiteList['grid-template-columns'] = true; // default: none
|
|
40
|
+
whiteList['grid-template-rows'] = true; // default: none
|
|
41
|
+
whiteList['justify-content'] = true; // default: auto
|
|
42
|
+
whiteList['justify-items'] = true; // default: auto
|
|
43
|
+
whiteList['justify-self'] = true; // default: auto
|
|
44
|
+
whiteList['line-height'] = true; // default: normal
|
|
45
|
+
whiteList['object-fit'] = true; // default: fill
|
|
46
|
+
whiteList['object-position'] = true; // default: 50% 50%
|
|
47
|
+
whiteList.order = true; // default: 0
|
|
48
|
+
whiteList.orphans = true; // default: 2
|
|
49
|
+
whiteList['row-gap'] = true;
|
|
50
|
+
return whiteList;
|
|
51
|
+
};
|
|
52
|
+
// yfmHtmlBlock additional allowedTags
|
|
53
|
+
const yfmHtmlBlockAllowedTags = ['link', 'base', 'style'];
|
|
54
|
+
// yfmHtmlBlock additional allowedTags
|
|
55
|
+
const yfmHtmlBlockAllowedAttributes = {
|
|
56
|
+
link: ['rel', 'href'],
|
|
57
|
+
base: ['target'],
|
|
58
|
+
style: [],
|
|
59
|
+
};
|
|
60
|
+
export const getYfmHtmlBlockOptions = (defaultOptions) => {
|
|
61
|
+
var _a;
|
|
62
|
+
const defaultAllowedAttributes = defaultOptions.allowedAttributes;
|
|
63
|
+
return Object.assign(Object.assign({}, defaultOptions), { allowedAttributes: Object.assign(Object.assign({}, defaultAllowedAttributes), yfmHtmlBlockAllowedAttributes), allowedTags: typeof defaultOptions.allowedTags === 'boolean'
|
|
64
|
+
? defaultOptions.allowedTags
|
|
65
|
+
: [...((_a = defaultOptions.allowedTags) !== null && _a !== void 0 ? _a : []), ...yfmHtmlBlockAllowedTags], cssWhiteList: Object.assign(Object.assign({}, defaultOptions.cssWhiteList), getYfmHtmlBlockWhiteList()) });
|
|
66
|
+
};
|
|
67
|
+
export const getSanitizeYfmHtmlBlock = ({ options, sanitize = diplodocSanitize }) => (content) => sanitize(content, getYfmHtmlBlockOptions(options));
|
package/build/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** During build process, the current version will be injected here */
|
|
2
|
-
export const VERSION = typeof '13.
|
|
2
|
+
export const VERSION = typeof '13.12.1' !== 'undefined' ? '13.12.1' : 'unknown';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/markdown-editor",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.12.1",
|
|
4
4
|
"description": "Markdown wysiwyg and markup editor",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
},
|
|
201
201
|
"devDependencies": {
|
|
202
202
|
"@diplodoc/folding-headings-extension": "0.1.0",
|
|
203
|
-
"@diplodoc/html-extension": "1.3.
|
|
203
|
+
"@diplodoc/html-extension": "1.3.3",
|
|
204
204
|
"@diplodoc/latex-extension": "1.0.3",
|
|
205
205
|
"@diplodoc/mermaid-extension": "1.2.1",
|
|
206
206
|
"@diplodoc/transform": "4.22.0",
|
|
@@ -223,6 +223,7 @@
|
|
|
223
223
|
"@types/react": "18.0.28",
|
|
224
224
|
"@types/react-dom": "18.0.11",
|
|
225
225
|
"@types/rimraf": "3.0.2",
|
|
226
|
+
"@types/sanitize-html": "2.11.0",
|
|
226
227
|
"bem-cn-lite": "4.1.0",
|
|
227
228
|
"esbuild-sass-plugin": "2.15.0",
|
|
228
229
|
"eslint": "8.56.0",
|