@gravity-ui/markdown-editor 13.4.1 → 13.5.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/build/cjs/bundle/Editor.d.ts +1 -2
- package/build/cjs/bundle/Editor.js +1 -0
- package/build/cjs/bundle/MarkdownEditorView.js +3 -1
- package/build/cjs/bundle/settings/MarkdownHints/MarkdownHints.js +1 -2
- package/build/cjs/extensions/markdown/Link/plugins/LinkTooltipPlugin/TooltipView.js +2 -2
- package/build/cjs/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImageForm/ImageForm.js +2 -2
- package/build/cjs/extensions/yfm/YfmTable/plugins/YfmTableControls/view.css +1 -0
- package/build/cjs/forms/FileForm.js +2 -2
- package/build/cjs/forms/ImageForm.js +2 -2
- package/build/cjs/forms/LinkForm.js +2 -2
- package/build/cjs/i18n/md-hints/en.json +2 -1
- package/build/cjs/i18n/md-hints/index.d.ts +2 -1
- package/build/cjs/i18n/md-hints/ru.json +2 -1
- package/build/cjs/i18n/search/en.json +5 -0
- package/build/cjs/i18n/search/index.d.ts +7 -0
- package/build/cjs/i18n/search/index.js +9 -0
- package/build/cjs/i18n/search/ru.json +5 -0
- package/build/cjs/markup/codemirror/create.d.ts +3 -0
- package/build/cjs/markup/codemirror/create.js +6 -1
- package/build/cjs/markup/codemirror/search-plugin/plugin.d.ts +42 -0
- package/build/cjs/markup/codemirror/search-plugin/plugin.js +100 -0
- package/build/cjs/markup/codemirror/search-plugin/view/SearchPopup.css +9 -0
- package/build/cjs/markup/codemirror/search-plugin/view/SearchPopup.d.ts +29 -0
- package/build/cjs/markup/codemirror/search-plugin/view/SearchPopup.js +85 -0
- package/build/cjs/utils/handlers.d.ts +4 -0
- package/build/cjs/utils/handlers.js +29 -0
- package/build/cjs/version.js +1 -1
- package/build/esm/bundle/Editor.d.ts +1 -2
- package/build/esm/bundle/Editor.js +1 -0
- package/build/esm/bundle/MarkdownEditorView.js +3 -1
- package/build/esm/bundle/settings/MarkdownHints/MarkdownHints.js +1 -2
- package/build/esm/extensions/markdown/Link/plugins/LinkTooltipPlugin/TooltipView.js +1 -1
- package/build/esm/extensions/yfm/ImgSize/plugins/ImgSizeNodeView/ImageForm/ImageForm.js +1 -1
- package/build/esm/extensions/yfm/YfmTable/plugins/YfmTableControls/view.css +1 -0
- package/build/esm/forms/FileForm.js +1 -1
- package/build/esm/forms/ImageForm.js +1 -1
- package/build/esm/forms/LinkForm.js +1 -1
- package/build/esm/i18n/md-hints/en.json +2 -1
- package/build/esm/i18n/md-hints/index.d.ts +2 -1
- package/build/esm/i18n/md-hints/ru.json +2 -1
- package/build/esm/i18n/search/en.json +5 -0
- package/build/esm/i18n/search/index.d.ts +7 -0
- package/build/esm/i18n/search/index.js +5 -0
- package/build/esm/i18n/search/ru.json +5 -0
- package/build/esm/markup/codemirror/create.d.ts +3 -0
- package/build/esm/markup/codemirror/create.js +6 -1
- package/build/esm/markup/codemirror/search-plugin/plugin.d.ts +42 -0
- package/build/esm/markup/codemirror/search-plugin/plugin.js +96 -0
- package/build/esm/markup/codemirror/search-plugin/view/SearchPopup.css +9 -0
- package/build/esm/markup/codemirror/search-plugin/view/SearchPopup.d.ts +30 -0
- package/build/esm/markup/codemirror/search-plugin/view/SearchPopup.js +80 -0
- package/build/esm/utils/handlers.d.ts +4 -0
- package/build/esm/utils/handlers.js +23 -0
- package/build/esm/version.js +1 -1
- package/build/styles.css +10 -0
- package/package.json +4 -3
- package/build/cjs/forms/utils.d.ts +0 -2
- package/build/cjs/forms/utils.js +0 -11
- package/build/esm/forms/utils.d.ts +0 -2
- package/build/esm/forms/utils.js +0 -7
|
@@ -4,7 +4,6 @@ import { i18n } from '.././../../i18n/md-hints';
|
|
|
4
4
|
import { cn } from '../../../classname';
|
|
5
5
|
import './MarkdownHints.css';
|
|
6
6
|
const b = cn('markdown-hints');
|
|
7
|
-
const YFM_DOCS_HREF = 'https://ydocs.tech';
|
|
8
7
|
export const MarkdownHints = React.memo(function MarkdownHints() {
|
|
9
8
|
const hints = [
|
|
10
9
|
{ title: i18n('header_title'), hint: i18n('header_hint') },
|
|
@@ -22,6 +21,6 @@ export const MarkdownHints = React.memo(function MarkdownHints() {
|
|
|
22
21
|
React.createElement("div", { className: b('grid') }, hints.map((hint, index) => (React.createElement(React.Fragment, { key: `md-hint-${index}` },
|
|
23
22
|
React.createElement("span", { className: b('title') }, hint.title),
|
|
24
23
|
React.createElement("span", { className: b('hint') }, hint.hint))))),
|
|
25
|
-
React.createElement(Link, { href:
|
|
24
|
+
React.createElement(Link, { href: i18n('documentation_link'), target: "_blank", className: b('docs-link') }, i18n('documentation'))));
|
|
26
25
|
});
|
|
27
26
|
MarkdownHints.displayName = 'MarkdownHints';
|
|
@@ -2,8 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { TextInputFixed } from '../../../../../forms/TextInput';
|
|
3
3
|
import { UrlInputRow } from '../../../../../forms/UrlInputRow';
|
|
4
4
|
import Form from '../../../../../forms/base';
|
|
5
|
-
import { enterKeyHandler } from '../../../../../forms/utils';
|
|
6
5
|
import { i18n } from '../../../../../i18n/forms';
|
|
6
|
+
import { enterKeyHandler } from '../../../../../utils/handlers';
|
|
7
7
|
export const LinkForm = React.memo(function LinkForm({ href, autoFocus, onChange, onCancel, }) {
|
|
8
8
|
const [url, setUrl] = React.useState(href);
|
|
9
9
|
const handleSubmit = () => {
|
|
@@ -4,9 +4,9 @@ import isNumber from 'is-number';
|
|
|
4
4
|
import { cn } from '../../../../../../classname';
|
|
5
5
|
import Form from '../../../../../../forms/base';
|
|
6
6
|
import { NumberInput } from '../../../../../../forms/components';
|
|
7
|
-
import { enterKeyHandler } from '../../../../../../forms/utils';
|
|
8
7
|
import { i18n } from '../../../../../../i18n/forms';
|
|
9
8
|
import { useAutoFocus } from '../../../../../../react-utils/useAutoFocus';
|
|
9
|
+
import { enterKeyHandler } from '../../../../../../utils/handlers';
|
|
10
10
|
import { LinkAttr, linkType } from '../../../../../markdown';
|
|
11
11
|
import { ImgSizeAttr } from '../../../../../specs';
|
|
12
12
|
import './ImageForm.css';
|
|
@@ -3,10 +3,10 @@ import { Tabs, TextInput } from '@gravity-ui/uikit';
|
|
|
3
3
|
import { cn } from '../classname';
|
|
4
4
|
import { i18n } from '../i18n/forms';
|
|
5
5
|
import { isFunction } from '../lodash';
|
|
6
|
+
import { enterKeyHandler } from '../utils/handlers';
|
|
6
7
|
import { TextInputFixed } from './TextInput';
|
|
7
8
|
import Form from './base';
|
|
8
9
|
import { ButtonAttach } from './components';
|
|
9
|
-
import { enterKeyHandler } from './utils';
|
|
10
10
|
const b = cn('file-form');
|
|
11
11
|
export const FileForm = ({ className, autoFocus, onCancel, onSubmit, onAttach, loading, }) => {
|
|
12
12
|
const [tabId, setTabId] = React.useState(() => isFunction(onAttach) ? "attach" /* TabId.Attach */ : "link" /* TabId.Link */);
|
|
@@ -3,10 +3,10 @@ import { Tabs, TextInput } from '@gravity-ui/uikit';
|
|
|
3
3
|
import { cn } from '../classname';
|
|
4
4
|
import { i18n } from '../i18n/forms';
|
|
5
5
|
import { isFunction } from '../lodash';
|
|
6
|
+
import { enterKeyHandler } from '../utils/handlers';
|
|
6
7
|
import { TextInputFixed } from './TextInput';
|
|
7
8
|
import Form from './base';
|
|
8
9
|
import { ButtonAttach, NumberInput } from './components';
|
|
9
|
-
import { enterKeyHandler } from './utils';
|
|
10
10
|
import './ImageForm.css';
|
|
11
11
|
const b = cn('image-form');
|
|
12
12
|
export const ImageForm = ({ className, autoFocus, onCancel, onSubmit, onAttach, loading, }) => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { TextInput } from '@gravity-ui/uikit';
|
|
3
3
|
import { i18n } from '../i18n/forms';
|
|
4
|
+
import { enterKeyHandler } from '../utils/handlers';
|
|
4
5
|
import { TextInputFixed } from './TextInput';
|
|
5
6
|
import { UrlInputRow } from './UrlInputRow';
|
|
6
7
|
import Form from './base';
|
|
7
|
-
import { enterKeyHandler } from './utils';
|
|
8
8
|
export const LinkForm = React.memo(function LinkForm({ className, autoFocus, initialUrl, initialText, readOnlyText, onSubmit, onCancel, }) {
|
|
9
9
|
const [url, setUrl] = React.useState(initialUrl !== null && initialUrl !== void 0 ? initialUrl : '');
|
|
10
10
|
const [text, setText] = React.useState(initialText !== null && initialText !== void 0 ? initialText : '');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const i18n: <G extends "header_title" | "header_hint" | "italic_title" | "italic_hint" | "bold_title" | "bold_hint" | "strikethrough_title" | "strikethrough_hint" | "blockquote_title" | "blockquote_hint" | "code_title" | "code_hint" | "link_title" | "link_hint" | "image_title" | "image_hint" | "list_title" | "list_hint" | "numbered-list_title" | "numbered-list_hint" | "documentation", S extends string>(key: G | (string extends S ? S : never), params?: {
|
|
1
|
+
export declare const i18n: <G extends "header_title" | "header_hint" | "italic_title" | "italic_hint" | "bold_title" | "bold_hint" | "strikethrough_title" | "strikethrough_hint" | "blockquote_title" | "blockquote_hint" | "code_title" | "code_hint" | "link_title" | "link_hint" | "image_title" | "image_hint" | "list_title" | "list_hint" | "numbered-list_title" | "numbered-list_hint" | "documentation" | "documentation_link", S extends string>(key: G | (string extends S ? S : never), params?: {
|
|
2
2
|
[key: string]: any;
|
|
3
3
|
} | undefined) => S extends G ? {
|
|
4
4
|
header_title: string;
|
|
@@ -22,4 +22,5 @@ export declare const i18n: <G extends "header_title" | "header_hint" | "italic_t
|
|
|
22
22
|
"numbered-list_title": string;
|
|
23
23
|
"numbered-list_hint": string;
|
|
24
24
|
documentation: string;
|
|
25
|
+
documentation_link: string;
|
|
25
26
|
}[G] : string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const i18n: <G extends "title" | "label_case-sensitive" | "label_whole-word", S extends string>(key: G | (string extends S ? S : never), params?: {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
} | undefined) => S extends G ? {
|
|
4
|
+
"label_case-sensitive": string;
|
|
5
|
+
"label_whole-word": string;
|
|
6
|
+
title: string;
|
|
7
|
+
}[G] : string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Extension, StateCommand } from '@codemirror/state';
|
|
2
2
|
import { EditorView, EditorViewConfig } from '@codemirror/view';
|
|
3
|
+
import { EventMap } from '../../bundle/Editor';
|
|
3
4
|
import { ReactRenderStorage } from '../../extensions';
|
|
5
|
+
import { Receiver } from '../../utils';
|
|
4
6
|
import { FileUploadHandler } from './files-upload-facet';
|
|
5
7
|
export declare type CreateCodemirrorParams = {
|
|
6
8
|
doc: EditorViewConfig['doc'];
|
|
@@ -14,6 +16,7 @@ export declare type CreateCodemirrorParams = {
|
|
|
14
16
|
uploadHandler?: FileUploadHandler;
|
|
15
17
|
needImgDimms?: boolean;
|
|
16
18
|
extraMarkupExtensions?: Extension[];
|
|
19
|
+
receiver?: Receiver<EventMap>;
|
|
17
20
|
};
|
|
18
21
|
export declare function createCodemirror(params: CreateCodemirrorParams): EditorView;
|
|
19
22
|
export declare function withLogger(action: string, command: StateCommand): StateCommand;
|
|
@@ -10,9 +10,10 @@ import { FileUploadHandlerFacet } from './files-upload-facet';
|
|
|
10
10
|
import { gravityHighlightStyle, gravityTheme } from './gravity';
|
|
11
11
|
import { PairingCharactersExtension } from './pairing-chars';
|
|
12
12
|
import { ReactRendererFacet } from './react-facet';
|
|
13
|
+
import { SearchPanelPlugin } from './search-plugin/plugin';
|
|
13
14
|
import { yfmLang } from './yfm';
|
|
14
15
|
export function createCodemirror(params) {
|
|
15
|
-
const { doc, placeholderText, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, extraMarkupExtensions, } = params;
|
|
16
|
+
const { doc, placeholderText, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, extraMarkupExtensions, receiver, } = params;
|
|
16
17
|
const extensions = [
|
|
17
18
|
gravityTheme,
|
|
18
19
|
placeholder(placeholderText),
|
|
@@ -66,6 +67,10 @@ export function createCodemirror(params) {
|
|
|
66
67
|
onScroll(event);
|
|
67
68
|
},
|
|
68
69
|
}),
|
|
70
|
+
SearchPanelPlugin({
|
|
71
|
+
anchorSelector: '.g-md-search-anchor',
|
|
72
|
+
receiver,
|
|
73
|
+
}),
|
|
69
74
|
];
|
|
70
75
|
if (params.uploadHandler) {
|
|
71
76
|
extensions.push(FileUploadHandlerFacet.of({
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view';
|
|
2
|
+
import { EditorMode, EventMap } from '../../../bundle/Editor';
|
|
3
|
+
import type { RendererItem } from '../../../extensions';
|
|
4
|
+
import { Receiver } from '../../../utils';
|
|
5
|
+
interface SearchQueryParams {
|
|
6
|
+
search: string;
|
|
7
|
+
caseSensitive?: boolean;
|
|
8
|
+
literal?: boolean;
|
|
9
|
+
regexp?: boolean;
|
|
10
|
+
replace?: string;
|
|
11
|
+
valid?: boolean;
|
|
12
|
+
wholeWord?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SearchPanelPluginParams {
|
|
15
|
+
anchorSelector: string;
|
|
16
|
+
inputDelay?: number;
|
|
17
|
+
receiver?: Receiver<EventMap>;
|
|
18
|
+
}
|
|
19
|
+
export declare const SearchPanelPlugin: (params: SearchPanelPluginParams) => ViewPlugin<{
|
|
20
|
+
readonly view: EditorView;
|
|
21
|
+
readonly params: SearchPanelPluginParams;
|
|
22
|
+
anchor: HTMLElement | null;
|
|
23
|
+
renderer: RendererItem | null;
|
|
24
|
+
searchQuery: SearchQueryParams;
|
|
25
|
+
receiver: Receiver<EventMap> | undefined;
|
|
26
|
+
setViewSearchWithDelay: (config: Partial<SearchQueryParams>) => void;
|
|
27
|
+
update(update: ViewUpdate): void;
|
|
28
|
+
destroy(): void;
|
|
29
|
+
setViewSearch(config: Partial<SearchQueryParams>): void;
|
|
30
|
+
handleEditorModeChange({ mode }: {
|
|
31
|
+
mode: EditorMode;
|
|
32
|
+
}): void;
|
|
33
|
+
handleChange(search: string): void;
|
|
34
|
+
handleClose(): void;
|
|
35
|
+
handleSearchNext(): void;
|
|
36
|
+
handleSearchPrev(): void;
|
|
37
|
+
handleSearchConfigChange({ isCaseSensitive, isWholeWord, }: {
|
|
38
|
+
isCaseSensitive?: boolean | undefined;
|
|
39
|
+
isWholeWord?: boolean | undefined;
|
|
40
|
+
}): void;
|
|
41
|
+
}>;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { SearchQuery, closeSearchPanel, findNext, findPrevious, search, searchKeymap, searchPanelOpen, setSearchQuery, } from '@codemirror/search';
|
|
2
|
+
import { ViewPlugin, keymap } from '@codemirror/view';
|
|
3
|
+
import { debounce } from '../../../lodash';
|
|
4
|
+
import { ReactRendererFacet } from '../react-facet';
|
|
5
|
+
import { renderSearchPopup } from './view/SearchPopup';
|
|
6
|
+
const INPUT_DELAY = 200;
|
|
7
|
+
export const SearchPanelPlugin = (params) => ViewPlugin.fromClass(class {
|
|
8
|
+
constructor(view) {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
this.searchQuery = {
|
|
11
|
+
search: '',
|
|
12
|
+
caseSensitive: false,
|
|
13
|
+
wholeWord: false,
|
|
14
|
+
};
|
|
15
|
+
this.view = view;
|
|
16
|
+
this.anchor = null;
|
|
17
|
+
this.renderer = null;
|
|
18
|
+
this.params = params;
|
|
19
|
+
this.receiver = params.receiver;
|
|
20
|
+
this.handleClose = this.handleClose.bind(this);
|
|
21
|
+
this.handleChange = this.handleChange.bind(this);
|
|
22
|
+
this.handleSearchNext = this.handleSearchNext.bind(this);
|
|
23
|
+
this.handleSearchPrev = this.handleSearchPrev.bind(this);
|
|
24
|
+
this.handleSearchConfigChange = this.handleSearchConfigChange.bind(this);
|
|
25
|
+
this.handleEditorModeChange = this.handleEditorModeChange.bind(this);
|
|
26
|
+
this.setViewSearchWithDelay = debounce(this.setViewSearch, (_a = this.params.inputDelay) !== null && _a !== void 0 ? _a : INPUT_DELAY);
|
|
27
|
+
(_b = this.receiver) === null || _b === void 0 ? void 0 : _b.on('change-editor-mode', this.handleEditorModeChange);
|
|
28
|
+
}
|
|
29
|
+
update(update) {
|
|
30
|
+
var _a;
|
|
31
|
+
const isPanelOpen = searchPanelOpen(update.state);
|
|
32
|
+
if (isPanelOpen && !this.renderer) {
|
|
33
|
+
this.anchor = document.querySelector(this.params.anchorSelector);
|
|
34
|
+
this.renderer = this.view.state
|
|
35
|
+
.facet(ReactRendererFacet)
|
|
36
|
+
.createItem('cm-search', () => renderSearchPopup({
|
|
37
|
+
open: true,
|
|
38
|
+
anchor: this.anchor,
|
|
39
|
+
onChange: this.handleChange,
|
|
40
|
+
onClose: this.handleClose,
|
|
41
|
+
onSearchNext: this.handleSearchNext,
|
|
42
|
+
onSearchPrev: this.handleSearchPrev,
|
|
43
|
+
onConfigChange: this.handleSearchConfigChange,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
else if (!isPanelOpen && this.renderer) {
|
|
47
|
+
(_a = this.renderer) === null || _a === void 0 ? void 0 : _a.remove();
|
|
48
|
+
this.renderer = null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
destroy() {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
(_a = this.renderer) === null || _a === void 0 ? void 0 : _a.remove();
|
|
54
|
+
this.renderer = null;
|
|
55
|
+
(_b = this.receiver) === null || _b === void 0 ? void 0 : _b.off('change-editor-mode', this.handleEditorModeChange);
|
|
56
|
+
}
|
|
57
|
+
setViewSearch(config) {
|
|
58
|
+
this.searchQuery = Object.assign(Object.assign({}, this.searchQuery), config);
|
|
59
|
+
const searchQuery = new SearchQuery(Object.assign({}, this.searchQuery));
|
|
60
|
+
this.view.dispatch({ effects: setSearchQuery.of(searchQuery) });
|
|
61
|
+
}
|
|
62
|
+
handleEditorModeChange({ mode }) {
|
|
63
|
+
if (mode === 'wysiwyg') {
|
|
64
|
+
closeSearchPanel(this.view);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
handleChange(search) {
|
|
68
|
+
this.setViewSearchWithDelay({ search });
|
|
69
|
+
}
|
|
70
|
+
handleClose() {
|
|
71
|
+
this.setViewSearch({ search: '' });
|
|
72
|
+
closeSearchPanel(this.view);
|
|
73
|
+
}
|
|
74
|
+
handleSearchNext() {
|
|
75
|
+
findNext(this.view);
|
|
76
|
+
}
|
|
77
|
+
handleSearchPrev() {
|
|
78
|
+
findPrevious(this.view);
|
|
79
|
+
}
|
|
80
|
+
handleSearchConfigChange({ isCaseSensitive, isWholeWord, }) {
|
|
81
|
+
this.setViewSearch({
|
|
82
|
+
caseSensitive: isCaseSensitive,
|
|
83
|
+
wholeWord: isWholeWord,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}, {
|
|
87
|
+
provide: () => [
|
|
88
|
+
keymap.of(searchKeymap),
|
|
89
|
+
search({
|
|
90
|
+
createPanel: () => ({
|
|
91
|
+
// Create an empty search panel
|
|
92
|
+
dom: document.createElement('div'),
|
|
93
|
+
}),
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './SearchPopup.css';
|
|
3
|
+
interface SearchConfig {
|
|
4
|
+
isCaseSensitive: boolean;
|
|
5
|
+
isWholeWord: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface SearchCardProps {
|
|
8
|
+
onSearchKeyDown?: (query: string) => void;
|
|
9
|
+
onChange?: (query: string) => void;
|
|
10
|
+
onClose?: (query: string) => void;
|
|
11
|
+
onSearchPrev?: (query: string) => void;
|
|
12
|
+
onSearchNext?: (query: string) => void;
|
|
13
|
+
onConfigChange?: (config: SearchConfig) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const SearchCard: React.FC<SearchCardProps>;
|
|
16
|
+
export interface SearchPopupProps {
|
|
17
|
+
anchor: HTMLElement;
|
|
18
|
+
onChange: (query: string) => void;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
onSearchNext: () => void;
|
|
21
|
+
onSearchPrev: () => void;
|
|
22
|
+
onConfigChange: (config: SearchConfig) => void;
|
|
23
|
+
open: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare const SearchPopup: React.FC<SearchPopupProps>;
|
|
26
|
+
interface SearchPopupWithRefProps extends Omit<SearchPopupProps, 'anchor'> {
|
|
27
|
+
anchor: HTMLElement | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function renderSearchPopup({ anchor, open, onClose, ...props }: SearchPopupWithRefProps): JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import React, { useRef, useState } from 'react';
|
|
3
|
+
import { ChevronDown, ChevronUp, Xmark } from '@gravity-ui/icons';
|
|
4
|
+
import { Button, Card, Checkbox, Icon, Popup, TextInput, sp, } from '@gravity-ui/uikit';
|
|
5
|
+
import { cn } from '../../../../classname';
|
|
6
|
+
import { i18n } from '../../../../i18n/search';
|
|
7
|
+
import { enterKeyHandler } from '../../../../utils/handlers';
|
|
8
|
+
import './SearchPopup.css';
|
|
9
|
+
const b = cn('search-card');
|
|
10
|
+
const noop = () => { };
|
|
11
|
+
export const SearchCard = ({ onChange = noop, onClose = noop, onSearchPrev = noop, onSearchNext = noop, onConfigChange = noop, }) => {
|
|
12
|
+
const [query, setQuery] = useState('');
|
|
13
|
+
const [isCaseSensitive, setIsCaseSensitive] = useState(false);
|
|
14
|
+
const [isWholeWord, setIsWholeWord] = useState(false);
|
|
15
|
+
const textInputRef = useRef(null);
|
|
16
|
+
const setInputFocus = () => {
|
|
17
|
+
var _a;
|
|
18
|
+
(_a = textInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
19
|
+
};
|
|
20
|
+
const handleInputChange = (event) => {
|
|
21
|
+
const { target: { value }, } = event;
|
|
22
|
+
setQuery(value);
|
|
23
|
+
onChange(value);
|
|
24
|
+
};
|
|
25
|
+
const handleClose = () => {
|
|
26
|
+
setQuery('');
|
|
27
|
+
onClose(query);
|
|
28
|
+
setInputFocus();
|
|
29
|
+
};
|
|
30
|
+
const handlePrev = () => {
|
|
31
|
+
onSearchPrev(query);
|
|
32
|
+
setInputFocus();
|
|
33
|
+
};
|
|
34
|
+
const handleNext = () => {
|
|
35
|
+
onSearchNext(query);
|
|
36
|
+
setInputFocus();
|
|
37
|
+
};
|
|
38
|
+
const handleIsCaseSensitive = () => {
|
|
39
|
+
onConfigChange({
|
|
40
|
+
isCaseSensitive: !isCaseSensitive,
|
|
41
|
+
isWholeWord,
|
|
42
|
+
});
|
|
43
|
+
setIsCaseSensitive((isCaseSensitive) => !isCaseSensitive);
|
|
44
|
+
setInputFocus();
|
|
45
|
+
};
|
|
46
|
+
const handleIsWholeWord = () => {
|
|
47
|
+
onConfigChange({
|
|
48
|
+
isCaseSensitive,
|
|
49
|
+
isWholeWord: !isWholeWord,
|
|
50
|
+
});
|
|
51
|
+
setIsWholeWord((isWholeWord) => !isWholeWord);
|
|
52
|
+
setInputFocus();
|
|
53
|
+
};
|
|
54
|
+
const handleSearchKeyPress = enterKeyHandler(handleNext);
|
|
55
|
+
return (React.createElement(Card, { className: b() },
|
|
56
|
+
React.createElement("div", { className: b('header') },
|
|
57
|
+
React.createElement("span", { className: b('title') },
|
|
58
|
+
" ",
|
|
59
|
+
i18n('title')),
|
|
60
|
+
React.createElement(Button, { onClick: handleClose, size: "s", view: "flat" },
|
|
61
|
+
React.createElement(Icon, { data: Xmark, size: 14 }))),
|
|
62
|
+
React.createElement(TextInput, { controlRef: textInputRef, className: sp({ mb: 2 }), size: "s", autoFocus: true, onKeyPress: handleSearchKeyPress, onChange: handleInputChange, value: query, endContent: React.createElement(React.Fragment, null,
|
|
63
|
+
React.createElement(Button, { onClick: handlePrev },
|
|
64
|
+
React.createElement(Icon, { data: ChevronUp, size: 12 })),
|
|
65
|
+
React.createElement(Button, { onClick: handleNext },
|
|
66
|
+
React.createElement(Icon, { data: ChevronDown, size: 12 }))) }),
|
|
67
|
+
React.createElement(Checkbox, { size: "m", onUpdate: handleIsCaseSensitive, checked: isCaseSensitive, className: sp({ mr: 4 }) }, i18n('label_case-sensitive')),
|
|
68
|
+
React.createElement(Checkbox, { size: "m", onUpdate: handleIsWholeWord, checked: isWholeWord }, i18n('label_whole-word'))));
|
|
69
|
+
};
|
|
70
|
+
export const SearchPopup = (_a) => {
|
|
71
|
+
var { open, anchor, onClose } = _a, props = __rest(_a, ["open", "anchor", "onClose"]);
|
|
72
|
+
const anchorRef = useRef(anchor);
|
|
73
|
+
return (React.createElement(Popup, { onEscapeKeyDown: onClose, open: anchorRef.current && open, anchorRef: anchorRef, placement: "bottom-end" },
|
|
74
|
+
React.createElement(SearchCard, Object.assign({ onClose: onClose }, props))));
|
|
75
|
+
};
|
|
76
|
+
SearchPopup.displayName = 'SearchPopup';
|
|
77
|
+
export function renderSearchPopup(_a) {
|
|
78
|
+
var { anchor, open, onClose } = _a, props = __rest(_a, ["anchor", "open", "onClose"]);
|
|
79
|
+
return (React.createElement(React.Fragment, null, anchor && React.createElement(SearchPopup, Object.assign({ open: open, onClose: onClose, anchor: anchor }, props))));
|
|
80
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare function enterKeyHandler<T>(handler: React.KeyboardEventHandler<T>): React.KeyboardEventHandler<T>;
|
|
3
|
+
export declare function escapeKeyHandler<T>(handler: React.KeyboardEventHandler<T>): React.KeyboardEventHandler<T>;
|
|
4
|
+
export declare function combinedKeyHandler<T>(handlers: Record<string, React.KeyboardEventHandler<T>>): React.KeyboardEventHandler<T>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Key } from '../shortcuts';
|
|
2
|
+
export function enterKeyHandler(handler) {
|
|
3
|
+
return (event) => {
|
|
4
|
+
if (event.key === Key.Enter) {
|
|
5
|
+
handler(event);
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function escapeKeyHandler(handler) {
|
|
10
|
+
return (event) => {
|
|
11
|
+
if (event.key === Key.Esc) {
|
|
12
|
+
handler(event);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function combinedKeyHandler(handlers) {
|
|
17
|
+
return (event) => {
|
|
18
|
+
const handler = handlers[event.key];
|
|
19
|
+
if (handler) {
|
|
20
|
+
handler(event);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
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.5.0' !== 'undefined' ? '13.5.0' : 'unknown';
|
package/build/styles.css
CHANGED
|
@@ -1290,6 +1290,15 @@ img.ProseMirror-separator {
|
|
|
1290
1290
|
.g-root_theme_dark .g-md-yfm-html-block_editing .g-text-area__content {
|
|
1291
1291
|
color: var(--g-color-text-primary);
|
|
1292
1292
|
}
|
|
1293
|
+
.g-md-search-card {
|
|
1294
|
+
padding: var(--g-spacing-2) var(--g-spacing-2) var(--g-spacing-3) var(--g-spacing-4);
|
|
1295
|
+
}
|
|
1296
|
+
.g-md-search-card__header {
|
|
1297
|
+
display: flex;
|
|
1298
|
+
justify-content: space-between;
|
|
1299
|
+
align-items: center;
|
|
1300
|
+
margin-bottom: var(--g-spacing-1);
|
|
1301
|
+
}
|
|
1293
1302
|
.g-md-code-block-toolbar {
|
|
1294
1303
|
margin: 2px 8px;
|
|
1295
1304
|
}
|
|
@@ -1477,6 +1486,7 @@ img.ProseMirror-separator {
|
|
|
1477
1486
|
|
|
1478
1487
|
.g-md-table-wrapper {
|
|
1479
1488
|
display: inline-block;
|
|
1489
|
+
width: 100%;
|
|
1480
1490
|
margin-right: 2px;
|
|
1481
1491
|
}
|
|
1482
1492
|
.g-md-table-cell-view__left-button {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/markdown-editor",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.5.0",
|
|
4
4
|
"description": "Markdown wysiwyg and markup editor",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -163,6 +163,7 @@
|
|
|
163
163
|
"@codemirror/commands": "6.5.0",
|
|
164
164
|
"@codemirror/lang-markdown": "6.2.5",
|
|
165
165
|
"@codemirror/language": "6.10.1",
|
|
166
|
+
"@codemirror/search": "6.5.6",
|
|
166
167
|
"@codemirror/state": "6.4.1",
|
|
167
168
|
"@codemirror/view": "6.26.3",
|
|
168
169
|
"@gravity-ui/i18n": "^1.1.0",
|
|
@@ -198,9 +199,9 @@
|
|
|
198
199
|
"tslib": "^2.3.1"
|
|
199
200
|
},
|
|
200
201
|
"devDependencies": {
|
|
202
|
+
"@diplodoc/html-extension": "1.2.7",
|
|
201
203
|
"@diplodoc/latex-extension": "1.0.3",
|
|
202
204
|
"@diplodoc/mermaid-extension": "1.2.1",
|
|
203
|
-
"@diplodoc/html-extension": "1.2.7",
|
|
204
205
|
"@diplodoc/transform": "4.5.0",
|
|
205
206
|
"@gravity-ui/components": "3.0.0",
|
|
206
207
|
"@gravity-ui/eslint-config": "3.1.1",
|
|
@@ -268,9 +269,9 @@
|
|
|
268
269
|
}
|
|
269
270
|
},
|
|
270
271
|
"peerDependencies": {
|
|
272
|
+
"@diplodoc/html-extension": "^1.2.7",
|
|
271
273
|
"@diplodoc/latex-extension": "^1.0.3",
|
|
272
274
|
"@diplodoc/mermaid-extension": "^1.0.0",
|
|
273
|
-
"@diplodoc/html-extension": "^1.2.7",
|
|
274
275
|
"@diplodoc/transform": "^4.5.0",
|
|
275
276
|
"@gravity-ui/components": "^3.0.0",
|
|
276
277
|
"@gravity-ui/uikit": "^6.11.0",
|
package/build/cjs/forms/utils.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.enterKeyHandler = void 0;
|
|
4
|
-
function enterKeyHandler(handler) {
|
|
5
|
-
return (event) => {
|
|
6
|
-
if (event.key === 'Enter') {
|
|
7
|
-
handler(event);
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
exports.enterKeyHandler = enterKeyHandler;
|