Skip to content

Commit d4097c2

Browse files
authored
feat(bundle): group editor settings by scope (#433)
1 parent 40d4a98 commit d4097c2

File tree

16 files changed

+372
-162
lines changed

16 files changed

+372
-162
lines changed

demo/Playground.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,21 @@ import {Button, DropdownMenu} from '@gravity-ui/uikit';
55
import {toaster} from '@gravity-ui/uikit/toaster-singleton-react-18';
66

77
import {
8-
MarkdownEditorMode,
8+
type EscapeConfig,
9+
type MarkdownEditorMode,
910
MarkdownEditorView,
10-
MarkdownEditorViewProps,
11-
MarkupString,
11+
type MarkdownEditorViewProps,
12+
type MarkupString,
1213
NumberInput,
13-
RenderPreview,
14-
ToolbarGroupData,
15-
UseMarkdownEditorProps,
14+
type RenderPreview,
15+
type ToolbarGroupData,
16+
type UseMarkdownEditorProps,
1617
logger,
1718
markupToolbarConfigs,
1819
useMarkdownEditor,
1920
wysiwygToolbarConfigs,
2021
} from '../src';
21-
import type {EscapeConfig, ToolbarActionData} from '../src/bundle/Editor';
22+
import type {ToolbarActionData} from '../src/bundle/Editor';
2223
import {Extension} from '../src/cm/state';
2324
import {FoldingHeading} from '../src/extensions/yfm/FoldingHeading';
2425
import {Math} from '../src/extensions/yfm/Math';

demo/RememberMode.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, {useEffect, useState} from 'react';
33
// eslint-disable-next-line import/no-extraneous-dependencies
44
import type {Meta, StoryFn} from '@storybook/react';
55

6-
import {EditorMode} from '../src/bundle/Editor';
6+
import type {MarkdownEditorMode} from '../src/bundle';
77

88
import {Playground as PlaygroundComponent, PlaygroundProps} from './Playground';
99

@@ -167,10 +167,10 @@ const args: Partial<PlaygroundStoryProps> = {
167167
};
168168

169169
export const RememberMode: StoryFn<PlaygroundStoryProps> = (props) => {
170-
const [mode, setMode] = useState<EditorMode>();
170+
const [mode, setMode] = useState<MarkdownEditorMode>();
171171
const [splitModeEnabled, setSplitModeEnabled] = useState<boolean>();
172172

173-
const handleChangeEditorType = (mode: EditorMode) => {
173+
const handleChangeEditorType = (mode: MarkdownEditorMode) => {
174174
localStorage.setItem('markdownEditorMode', mode);
175175
};
176176

@@ -183,7 +183,7 @@ export const RememberMode: StoryFn<PlaygroundStoryProps> = (props) => {
183183
const storedSplitModeEnabled = localStorage.getItem('markdownEditorSplitModeEnabled');
184184

185185
if (storedMode) {
186-
setMode(storedMode as EditorMode);
186+
setMode(storedMode as MarkdownEditorMode);
187187
setSplitModeEnabled(storedSplitModeEnabled === 'true');
188188
}
189189
}, []);

src/bundle/Editor.ts

Lines changed: 47 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
import type {ReactNode} from 'react';
22

3-
import type {Extension as CodemirrorExtension} from '@codemirror/state';
43
import {EditorView as CMEditorView} from '@codemirror/view';
54
import {TextSelection} from 'prosemirror-state';
65
import {EditorView as PMEditorView} from 'prosemirror-view';
76

8-
import {CommonEditor, MarkupString} from '../common';
9-
import {ActionStorage, WysiwygEditor, WysiwygEditorOptions} from '../core';
10-
import {ReactRenderStorage, RenderStorage} from '../extensions';
7+
import type {CommonEditor, MarkupString} from '../common';
8+
import {
9+
type ActionStorage,
10+
type EscapeConfig,
11+
WysiwygEditor,
12+
type WysiwygEditorOptions,
13+
} from '../core';
14+
import {ReactRenderStorage, type RenderStorage} from '../extensions';
1115
import {i18n} from '../i18n/bundle';
1216
import {logger} from '../logger';
13-
import {type CreateCodemirrorParams, createCodemirror} from '../markup/codemirror';
14-
import type {YfmLangOptions} from '../markup/codemirror/yfm';
15-
import {CodeEditor, Editor as MarkupEditor} from '../markup/editor';
16-
import {Emitter, Receiver, SafeEventEmitter} from '../utils/event-emitter';
17+
import {createCodemirror} from '../markup/codemirror';
18+
import {type CodeEditor, Editor as MarkupEditor} from '../markup/editor';
19+
import {type Emitter, type Receiver, SafeEventEmitter} from '../utils/event-emitter';
1720
import type {FileUploadHandler} from '../utils/upload';
1821

19-
export type EditorMode = 'wysiwyg' | 'markup';
20-
export type SplitMode = false | 'horizontal' | 'vertical';
21-
export type EditorPreset = 'zero' | 'commonmark' | 'default' | 'yfm' | 'full';
22-
export type RenderPreview = ({
23-
getValue,
24-
mode,
25-
}: {
26-
getValue: () => MarkupString;
27-
mode: 'preview' | 'split';
28-
}) => ReactNode;
22+
import type {
23+
MarkdownEditorMode as EditorMode,
24+
MarkdownEditorPreset as EditorPreset,
25+
MarkdownEditorOptions,
26+
MarkdownEditorMarkupConfig as MarkupConfig,
27+
RenderPreview,
28+
MarkdownEditorSplitMode as SplitMode,
29+
} from './types';
2930

3031
export type ToolbarActionData = {
3132
editorMode: EditorMode;
@@ -105,72 +106,18 @@ export interface EditorInt
105106

106107
type SetEditorModeOptions = Pick<ChangeEditorModeOptions, 'emit'>;
107108

108-
type ChangeEditorModeOptions = {
109+
export type ChangeEditorModeOptions = {
109110
mode: EditorMode;
110111
reason: 'error-boundary' | 'settings' | 'manually';
111112
emit?: boolean;
112113
};
113114

114-
export type MarkupConfig = {
115-
/** Additional extensions for codemirror instance. */
116-
extensions?: CreateCodemirrorParams['extensions'];
117-
/** Can be used to disable some of the default extensions */
118-
disabledExtensions?: CreateCodemirrorParams['disabledExtensions'];
119-
/** Additional keymaps for codemirror instance */
120-
keymaps?: CreateCodemirrorParams['keymaps'];
121-
/** Overrides the default placeholder content. */
122-
placeholder?: CreateCodemirrorParams['placeholder'];
123-
/**
124-
* Additional language data for markdown language in codemirror.
125-
* Can be used to configure additional autocompletions and others.
126-
* See more https://codemirror.net/docs/ref/#state.EditorState.languageDataAt
127-
*/
128-
languageData?: YfmLangOptions['languageData'];
129-
/** Config for @codemirror/autocomplete https://codemirror.net/docs/ref/#autocomplete.autocompletion%5Econfig */
130-
autocompletion?: CreateCodemirrorParams['autocompletion'];
131-
};
132-
133-
export type EscapeConfig = {
134-
commonEscape?: RegExp;
135-
startOfLineEscape?: RegExp;
136-
};
137-
138115
export type EditorOptions = Pick<
139-
WysiwygEditorOptions,
140-
'allowHTML' | 'linkify' | 'linkifyTlds' | 'extensions'
116+
MarkdownEditorOptions,
117+
'md' | 'initial' | 'handlers' | 'experimental' | 'markupConfig' | 'wysiwygConfig'
141118
> & {
142-
initialMarkup?: MarkupString;
143-
/** @default 'wysiwyg' */
144-
initialEditorMode?: EditorMode;
145-
/** @default true */
146-
initialToolbarVisible?: boolean;
147-
/** @default false
148-
* Has no effect if splitMode is false or undefined
149-
*/
150-
initialSplitModeEnabled?: boolean;
151119
renderStorage: ReactRenderStorage;
152-
fileUploadHandler?: FileUploadHandler;
153-
/**
154-
* If we need to set dimensions for uploaded images
155-
*
156-
* @default false
157-
*/
158-
needToSetDimensionsForUploadedImages?: boolean;
159-
/**
160-
* Called before switching from the markup editor to the wysiwyg editor.
161-
* You can use it to pre-process the value from the markup editor before it gets into the wysiwyg editor.
162-
*/
163-
prepareRawMarkup?: (value: MarkupString) => MarkupString;
164-
experimental_beforeEditorModeChange?: (
165-
options: Pick<ChangeEditorModeOptions, 'mode' | 'reason'>,
166-
) => boolean | undefined;
167-
splitMode?: SplitMode;
168-
renderPreview?: RenderPreview;
169120
preset: EditorPreset;
170-
/** @deprecated Put extra extensions via MarkdownEditorMarkupConfig */
171-
extraMarkupExtensions?: CodemirrorExtension[];
172-
markupConfig?: MarkupConfig;
173-
escapeConfig?: EscapeConfig;
174121
};
175122

176123
/** @internal */
@@ -337,30 +284,39 @@ export class EditorImpl extends SafeEventEmitter<EventMapInt> implements EditorI
337284

338285
constructor(opts: EditorOptions) {
339286
super({onError: logger.error.bind(logger)});
340-
this.#editorMode = opts.initialEditorMode ?? 'wysiwyg';
341-
this.#toolbarVisible = Boolean(opts.initialToolbarVisible);
342-
this.#splitMode = (opts.renderPreview && opts.splitMode) ?? false;
343-
this.#splitModeEnabled = (this.#splitMode && opts.initialSplitModeEnabled) ?? false;
344-
this.#renderPreview = opts.renderPreview;
345287

346-
this.#markup = opts.initialMarkup ?? '';
288+
const {
289+
md = {},
290+
initial = {},
291+
handlers = {},
292+
experimental = {},
293+
markupConfig = {},
294+
wysiwygConfig = {},
295+
} = opts;
296+
297+
this.#editorMode = initial.mode ?? 'wysiwyg';
298+
this.#toolbarVisible = initial.toolbarVisible ?? true;
299+
this.#splitMode = (markupConfig.renderPreview && markupConfig.splitMode) ?? false;
300+
this.#splitModeEnabled = (this.#splitMode && initial.splitModeEnabled) ?? false;
301+
this.#renderPreview = markupConfig.renderPreview;
302+
303+
this.#markup = initial.markup ?? '';
347304

348305
this.#preset = opts.preset ?? 'full';
349-
this.#linkify = opts.linkify;
350-
this.#linkifyTlds = opts.linkifyTlds;
351-
this.#allowHTML = opts.allowHTML;
352-
this.#extensions = opts.extensions;
306+
this.#linkify = md.linkify;
307+
this.#linkifyTlds = md.linkifyTlds;
308+
this.#allowHTML = md.html;
309+
this.#extensions = wysiwygConfig.extensions;
353310
this.#markupConfig = {...opts.markupConfig};
354-
this.#markupConfig.extensions ??= opts.extraMarkupExtensions;
355311

356312
this.#renderStorage = opts.renderStorage;
357-
this.#fileUploadHandler = opts.fileUploadHandler;
313+
this.#fileUploadHandler = handlers.uploadFile;
358314
this.#needToSetDimensionsForUploadedImages = Boolean(
359-
opts.needToSetDimensionsForUploadedImages,
315+
experimental.needToSetDimensionsForUploadedImages,
360316
);
361-
this.#prepareRawMarkup = opts.prepareRawMarkup;
362-
this.#escapeConfig = opts.escapeConfig;
363-
this.#beforeEditorModeChange = opts.experimental_beforeEditorModeChange;
317+
this.#prepareRawMarkup = experimental.prepareRawMarkup;
318+
this.#escapeConfig = wysiwygConfig.escapeConfig;
319+
this.#beforeEditorModeChange = experimental.beforeEditorModeChange;
364320
}
365321

366322
// ---> implements CodeEditor

src/bundle/MarkdownEditorView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {logger} from '../logger';
1010
import {ToasterContext, useBooleanState, useSticky} from '../react-utils';
1111
import {isMac} from '../utils';
1212

13-
import type {Editor, EditorInt, EditorMode} from './Editor';
13+
import type {Editor, EditorInt} from './Editor';
1414
import {HorizontalDrag} from './HorizontalDrag';
1515
import {MarkupEditorView} from './MarkupEditorView';
1616
import {SplitModeView} from './SplitModeView';
@@ -28,6 +28,7 @@ import {
2828
import {useMarkdownEditorContext} from './context';
2929
import {EditorSettings, EditorSettingsProps} from './settings';
3030
import {stickyCn} from './sticky';
31+
import type {MarkdownEditorMode} from './types';
3132

3233
import '../styles/styles.scss';
3334
import './MarkdownEditorView.scss'; // eslint-disable-line import/order
@@ -91,7 +92,7 @@ export const MarkdownEditorView = React.forwardRef<HTMLDivElement, MarkdownEdito
9192
}, [editor, rerender]);
9293

9394
const onModeChange = React.useCallback(
94-
(type: EditorMode) => {
95+
(type: MarkdownEditorMode) => {
9596
editor.changeEditorMode({mode: type, reason: 'settings'});
9697
unsetShowPreview();
9798
},

src/bundle/MarkupEditorView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import {ReactRendererComponent} from '../extensions';
55
import {logger} from '../logger';
66
import {useRenderTime} from '../react-utils/hooks';
77

8-
import type {EditorInt, SplitMode} from './Editor';
8+
import type {EditorInt} from './Editor';
99
import {MarkupEditorComponent} from './MarkupEditorComponent';
1010
import {ToolbarView} from './ToolbarView';
1111
import type {MToolbarData, MToolbarItemData} from './config/markup';
1212
import {MarkupToolbarContextProvider} from './toolbar/markup/context';
13+
import type {MarkdownEditorSplitMode} from './types';
1314

1415
import './MarkupEditorView.scss';
1516

@@ -23,7 +24,7 @@ export type MarkupEditorViewProps = ClassNameProps & {
2324
toolbarVisible?: boolean;
2425
stickyToolbar?: boolean;
2526
toolbarClassName?: string;
26-
splitMode?: SplitMode;
27+
splitMode?: MarkdownEditorSplitMode;
2728
splitModeEnabled: boolean;
2829
hiddenActionsConfig?: MToolbarItemData[];
2930
children?: React.ReactNode;

src/bundle/ToolbarView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ import {i18n} from '../i18n/menubar';
77
import {useSticky} from '../react-utils/useSticky';
88
import {FlexToolbar, ToolbarData, ToolbarItemData} from '../toolbar';
99

10-
import type {EditorInt, EditorMode} from './Editor';
10+
import type {EditorInt} from './Editor';
1111
import {stickyCn} from './sticky';
12+
import type {MarkdownEditorMode} from './types';
1213

1314
export type ToolbarViewProps<T> = ClassNameProps & {
1415
editor: EditorInt;
15-
editorMode: EditorMode;
16+
editorMode: MarkdownEditorMode;
1617
toolbarEditor: T;
1718
toolbarFocus: () => void;
1819
toolbarConfig: ToolbarData<T>;

src/bundle/config/markup.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ import {
5050
ToolbarReactComponentData,
5151
ToolbarSingleItemData,
5252
} from '../../toolbar/types';
53-
import type {EditorPreset} from '../Editor';
5453
import {MToolbarColors} from '../toolbar/markup/MToolbarColors';
5554
import {MToolbarFilePopup} from '../toolbar/markup/MToolbarFilePopup';
5655
import {MToolbarImagePopup} from '../toolbar/markup/MToolbarImagePopup';
56+
import type {MarkdownEditorPreset} from '../types';
5757

5858
import {ActionName} from './action-names';
5959
import {icons} from './icons';
@@ -545,7 +545,7 @@ export const mTabsItemData: MToolbarSingleItemData = {
545545

546546
export const mHiddenData = [mHruleItemData, mTabsItemData];
547547

548-
export const mToolbarConfigByPreset: Record<EditorPreset, MToolbarData> = {
548+
export const mToolbarConfigByPreset: Record<MarkdownEditorPreset, MToolbarData> = {
549549
zero: [mHistoryGroupConfig],
550550
commonmark: [
551551
mHistoryGroupConfig,
@@ -592,7 +592,7 @@ export const mToolbarConfigByPreset: Record<EditorPreset, MToolbarData> = {
592592
full: mToolbarConfig.slice(),
593593
};
594594

595-
export const mHiddenDataByPreset: Record<EditorPreset, MToolbarItemData[]> = {
595+
export const mHiddenDataByPreset: Record<MarkdownEditorPreset, MToolbarItemData[]> = {
596596
zero: [],
597597
commonmark: [
598598
...mHeadingListConfig.data,

src/bundle/config/wysiwyg.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import {
2222
ToolbarListItemData,
2323
ToolbarSingleItemData,
2424
} from '../../toolbar/types';
25-
import type {EditorPreset} from '../Editor';
2625
import {WToolbarColors} from '../toolbar/wysiwyg/WToolbarColors';
2726
import {WToolbarTextSelect} from '../toolbar/wysiwyg/WToolbarTextSelect';
27+
import type {MarkdownEditorPreset} from '../types';
2828

2929
import {ActionName} from './action-names';
3030
import {icons} from './icons';
@@ -581,7 +581,7 @@ export const wMermaidItemData: WToolbarSingleItemData = {
581581
isEnable: (e) => e.actions.createMermaid.isEnable(),
582582
};
583583

584-
export const wToolbarConfigByPreset: Record<EditorPreset, WToolbarData> = {
584+
export const wToolbarConfigByPreset: Record<MarkdownEditorPreset, WToolbarData> = {
585585
zero: [wHistoryGroupConfig],
586586
commonmark: [
587587
wHistoryGroupConfig,
@@ -652,7 +652,7 @@ export const wToolbarConfigByPreset: Record<EditorPreset, WToolbarData> = {
652652
full: wToolbarConfig.slice(),
653653
};
654654

655-
export const wCommandMenuConfigByPreset: Record<EditorPreset, WToolbarItemData[]> = {
655+
export const wCommandMenuConfigByPreset: Record<MarkdownEditorPreset, WToolbarItemData[]> = {
656656
zero: [],
657657
commonmark: [
658658
...wHeadingListConfig.data,
@@ -688,15 +688,15 @@ export const wCommandMenuConfigByPreset: Record<EditorPreset, WToolbarItemData[]
688688
full: wCommandMenuConfig.slice(),
689689
};
690690

691-
export const wHiddenDataByPreset: Record<EditorPreset, WToolbarItemData[]> = {
691+
export const wHiddenDataByPreset: Record<MarkdownEditorPreset, WToolbarItemData[]> = {
692692
zero: wCommandMenuConfigByPreset.zero.slice(),
693693
commonmark: wCommandMenuConfigByPreset.commonmark.slice(),
694694
default: wCommandMenuConfigByPreset.default.slice(),
695695
yfm: wCommandMenuConfigByPreset.yfm.slice(),
696696
full: wCommandMenuConfigByPreset.full.slice(),
697697
};
698698

699-
export const wSelectionMenuConfigByPreset: Record<EditorPreset, SelectionContextConfig> = {
699+
export const wSelectionMenuConfigByPreset: Record<MarkdownEditorPreset, SelectionContextConfig> = {
700700
zero: [],
701701
commonmark: [
702702
[textContextItemData],

src/bundle/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
export type {
2-
Editor as MarkdownEditorInstance,
3-
EditorMode as MarkdownEditorMode,
4-
EditorPreset as MarkdownEditorPreset,
5-
MarkupConfig as MarkdownEditorMarkupConfig,
6-
RenderPreview,
7-
SplitMode,
8-
} from './Editor';
1+
export * from './types';
92
export {MarkdownEditorProvider, useMarkdownEditorContext} from './context';
103
export {useMarkdownEditor} from './useMarkdownEditor';
114
export type {UseMarkdownEditorProps} from './useMarkdownEditor';

0 commit comments

Comments
 (0)