From c5fe2490f408d9fb8e0f7dd648050b913fe4fdb8 Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Fri, 29 Nov 2024 12:20:15 +0300 Subject: [PATCH 1/6] add empty row placeholder --- demo/components/Playground.tsx | 5 +++++ src/bundle/types.ts | 1 + src/bundle/useMarkdownEditor.ts | 1 + src/bundle/wysiwyg-preset.ts | 6 +++++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/demo/components/Playground.tsx b/demo/components/Playground.tsx index 3492b81f..b78f117a 100644 --- a/demo/components/Playground.tsx +++ b/demo/components/Playground.tsx @@ -79,6 +79,7 @@ export type PlaygroundProps = { breaks?: boolean; linkify?: boolean; linkifyTlds?: string | string[]; + emptyRowPlaceholder?: boolean; sanitizeHtml?: boolean; prepareRawMarkup?: boolean; splitModeOrientation?: 'horizontal' | 'vertical' | false; @@ -124,6 +125,7 @@ export const Playground = React.memo((props) => { initialSplitModeEnabled, settingsVisible, allowHTML, + emptyRowPlaceholder, breaks, linkify, linkifyTlds, @@ -185,6 +187,9 @@ export const Playground = React.memo((props) => { needToSetDimensionsForUploadedImages, renderPreview: renderPreviewDefined ? renderPreview : undefined, fileUploadHandler, + md: { + emptyRowPlaceholder: emptyRowPlaceholder, + }, experimental: { ...experimental, directiveSyntax, diff --git a/src/bundle/types.ts b/src/bundle/types.ts index 34d17136..e23a66b8 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -28,6 +28,7 @@ export type ParseInsertedUrlAsImage = (text: string) => {imageUrl: string; title export type MarkdownEditorMdOptions = { html?: boolean; + emptyRowPlaceholder?: boolean; breaks?: boolean; linkify?: boolean; linkifyTlds?: string | string[]; diff --git a/src/bundle/useMarkdownEditor.ts b/src/bundle/useMarkdownEditor.ts index b44cb463..1ac732fd 100644 --- a/src/bundle/useMarkdownEditor.ts +++ b/src/bundle/useMarkdownEditor.ts @@ -59,6 +59,7 @@ export function useMarkdownEditor( editor.emit('submit', null); return true; }, + emptyRowPlaceholder: md.emptyRowPlaceholder, mdBreaks: breaks, fileUploadHandler: uploadFile, needToSetDimensionsForUploadedImages, diff --git a/src/bundle/wysiwyg-preset.ts b/src/bundle/wysiwyg-preset.ts index 42874148..dccd6b12 100644 --- a/src/bundle/wysiwyg-preset.ts +++ b/src/bundle/wysiwyg-preset.ts @@ -27,6 +27,7 @@ export type BundlePresetOptions = ExtensionsOptions & preset: MarkdownEditorPreset; mdBreaks?: boolean; fileUploadHandler?: FileUploadHandler; + emptyRowPlaceholder?: boolean; /** * If we need to set dimensions for uploaded images * @@ -64,7 +65,10 @@ export const BundlePreset: ExtensionAuto = (builder, opts) paragraphKey: f.toPM(A.Text), paragraphPlaceholder: (node: Node, parent?: Node | null) => { const isDocEmpty = - !node.text && parent?.type.name === BaseNode.Doc && parent.childCount === 1; + !node.text && + ((opts.emptyRowPlaceholder && parent?.type.name === 'doc') || + (parent?.type.name === BaseNode.Doc && parent.childCount === 1)); + return isDocEmpty ? i18nPlaceholder('doc_empty') : null; }, ...opts.baseSchema, From 27605b6f94ee4b01e8555850b539fc88cb0f3aac Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Fri, 29 Nov 2024 18:10:54 +0300 Subject: [PATCH 2/6] fix PR --- demo/components/Playground.tsx | 9 +++++---- src/bundle/types.ts | 7 ++++++- src/bundle/useMarkdownEditor.ts | 2 +- src/bundle/wysiwyg-preset.ts | 30 ++++++++++++++++++++++-------- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/demo/components/Playground.tsx b/demo/components/Playground.tsx index b78f117a..bf9c6d5b 100644 --- a/demo/components/Playground.tsx +++ b/demo/components/Playground.tsx @@ -16,6 +16,7 @@ import { type RenderPreview, type ToolbarGroupData, type UseMarkdownEditorProps, + WysywigPlaceholderOptions, logger, markupToolbarConfigs, useMarkdownEditor, @@ -79,7 +80,7 @@ export type PlaygroundProps = { breaks?: boolean; linkify?: boolean; linkifyTlds?: string | string[]; - emptyRowPlaceholder?: boolean; + placeholderOptions?: WysywigPlaceholderOptions; sanitizeHtml?: boolean; prepareRawMarkup?: boolean; splitModeOrientation?: 'horizontal' | 'vertical' | false; @@ -125,7 +126,6 @@ export const Playground = React.memo((props) => { initialSplitModeEnabled, settingsVisible, allowHTML, - emptyRowPlaceholder, breaks, linkify, linkifyTlds, @@ -141,6 +141,7 @@ export const Playground = React.memo((props) => { wysiwygCommandMenuConfig, markupConfigExtensions, markupToolbarConfig, + placeholderOptions, escapeConfig, enableSubmitInPreview, hidePreviewAfterSubmit, @@ -187,8 +188,8 @@ export const Playground = React.memo((props) => { needToSetDimensionsForUploadedImages, renderPreview: renderPreviewDefined ? renderPreview : undefined, fileUploadHandler, - md: { - emptyRowPlaceholder: emptyRowPlaceholder, + wysiwygConfig: { + placeholderOptions: placeholderOptions, }, experimental: { ...experimental, diff --git a/src/bundle/types.ts b/src/bundle/types.ts index e23a66b8..2d4382f7 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -26,9 +26,13 @@ export type RenderPreview = (params: RenderPreviewParams) => ReactNode; export type ParseInsertedUrlAsImage = (text: string) => {imageUrl: string; title?: string} | null; +export type WysywigPlaceholderOptions = { + value?: string | (() => string); + behavior: 'empty-doc' | 'empty-row'; +}; + export type MarkdownEditorMdOptions = { html?: boolean; - emptyRowPlaceholder?: boolean; breaks?: boolean; linkify?: boolean; linkifyTlds?: string | string[]; @@ -149,6 +153,7 @@ export type MarkdownEditorWysiwygConfig = { extensions?: Extension; extensionOptions?: ExtensionsOptions; escapeConfig?: EscapeConfig; + placeholderOptions?: WysywigPlaceholderOptions; }; // [major] TODO: remove generic type diff --git a/src/bundle/useMarkdownEditor.ts b/src/bundle/useMarkdownEditor.ts index 1ac732fd..6cdb1a7c 100644 --- a/src/bundle/useMarkdownEditor.ts +++ b/src/bundle/useMarkdownEditor.ts @@ -59,7 +59,7 @@ export function useMarkdownEditor( editor.emit('submit', null); return true; }, - emptyRowPlaceholder: md.emptyRowPlaceholder, + placeholderOptions: wysiwygConfig.placeholderOptions, mdBreaks: breaks, fileUploadHandler: uploadFile, needToSetDimensionsForUploadedImages, diff --git a/src/bundle/wysiwyg-preset.ts b/src/bundle/wysiwyg-preset.ts index dccd6b12..e35097d6 100644 --- a/src/bundle/wysiwyg-preset.ts +++ b/src/bundle/wysiwyg-preset.ts @@ -16,7 +16,7 @@ import type {FileUploadHandler} from '../utils/upload'; import {wCommandMenuConfigByPreset, wSelectionMenuConfigByPreset} from './config/wysiwyg'; import {emojiDefs} from './emoji'; -import type {MarkdownEditorPreset} from './types'; +import type {MarkdownEditorPreset, WysywigPlaceholderOptions} from './types'; const DEFAULT_IGNORED_KEYS = ['Tab', 'Shift-Tab'] as const; @@ -27,7 +27,7 @@ export type BundlePresetOptions = ExtensionsOptions & preset: MarkdownEditorPreset; mdBreaks?: boolean; fileUploadHandler?: FileUploadHandler; - emptyRowPlaceholder?: boolean; + placeholderOptions?: WysywigPlaceholderOptions; /** * If we need to set dimensions for uploaded images * @@ -64,12 +64,26 @@ export const BundlePreset: ExtensionAuto = (builder, opts) baseSchema: { paragraphKey: f.toPM(A.Text), paragraphPlaceholder: (node: Node, parent?: Node | null) => { - const isDocEmpty = - !node.text && - ((opts.emptyRowPlaceholder && parent?.type.name === 'doc') || - (parent?.type.name === BaseNode.Doc && parent.childCount === 1)); - - return isDocEmpty ? i18nPlaceholder('doc_empty') : null; + let isPlaceholderShown = false; + + if (opts.placeholderOptions?.behavior === 'empty-row') { + isPlaceholderShown = !node.text && parent?.type.name === 'doc'; + } else { + isPlaceholderShown = + !node.text && parent?.type.name === BaseNode.Doc && parent.childCount === 1; + } + + let text = i18nPlaceholder('doc_empty'); + + if (opts.placeholderOptions?.value) { + if (typeof opts.placeholderOptions?.value === 'string') { + text = opts.placeholderOptions?.value; + } else { + text = opts.placeholderOptions?.value(); + } + } + + return isPlaceholderShown ? text : null; }, ...opts.baseSchema, }, From 3dddf77d39b560844b0738bd10c9179bf0873b31 Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Tue, 3 Dec 2024 10:40:10 +0300 Subject: [PATCH 3/6] fix PR --- demo/components/Playground.tsx | 4 ++-- src/bundle/types.ts | 7 ++++--- src/bundle/wysiwyg-preset.ts | 35 +++++++++++++--------------------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/demo/components/Playground.tsx b/demo/components/Playground.tsx index bf9c6d5b..b6c5708f 100644 --- a/demo/components/Playground.tsx +++ b/demo/components/Playground.tsx @@ -16,7 +16,7 @@ import { type RenderPreview, type ToolbarGroupData, type UseMarkdownEditorProps, - WysywigPlaceholderOptions, + WysiwygPlaceholderOptions, logger, markupToolbarConfigs, useMarkdownEditor, @@ -80,7 +80,7 @@ export type PlaygroundProps = { breaks?: boolean; linkify?: boolean; linkifyTlds?: string | string[]; - placeholderOptions?: WysywigPlaceholderOptions; + placeholderOptions?: WysiwygPlaceholderOptions; sanitizeHtml?: boolean; prepareRawMarkup?: boolean; splitModeOrientation?: 'horizontal' | 'vertical' | false; diff --git a/src/bundle/types.ts b/src/bundle/types.ts index 2d4382f7..25a7ba2e 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -26,9 +26,10 @@ export type RenderPreview = (params: RenderPreviewParams) => ReactNode; export type ParseInsertedUrlAsImage = (text: string) => {imageUrl: string; title?: string} | null; -export type WysywigPlaceholderOptions = { +export type WysiwygPlaceholderOptions = { value?: string | (() => string); - behavior: 'empty-doc' | 'empty-row'; + /** Default – empty-doc */ + behavior?: 'empty-doc' | 'empty-row'; }; export type MarkdownEditorMdOptions = { @@ -153,7 +154,7 @@ export type MarkdownEditorWysiwygConfig = { extensions?: Extension; extensionOptions?: ExtensionsOptions; escapeConfig?: EscapeConfig; - placeholderOptions?: WysywigPlaceholderOptions; + placeholderOptions?: WysiwygPlaceholderOptions; }; // [major] TODO: remove generic type diff --git a/src/bundle/wysiwyg-preset.ts b/src/bundle/wysiwyg-preset.ts index e35097d6..4dad8a43 100644 --- a/src/bundle/wysiwyg-preset.ts +++ b/src/bundle/wysiwyg-preset.ts @@ -16,7 +16,7 @@ import type {FileUploadHandler} from '../utils/upload'; import {wCommandMenuConfigByPreset, wSelectionMenuConfigByPreset} from './config/wysiwyg'; import {emojiDefs} from './emoji'; -import type {MarkdownEditorPreset, WysywigPlaceholderOptions} from './types'; +import type {MarkdownEditorPreset, WysiwygPlaceholderOptions} from './types'; const DEFAULT_IGNORED_KEYS = ['Tab', 'Shift-Tab'] as const; @@ -27,7 +27,7 @@ export type BundlePresetOptions = ExtensionsOptions & preset: MarkdownEditorPreset; mdBreaks?: boolean; fileUploadHandler?: FileUploadHandler; - placeholderOptions?: WysywigPlaceholderOptions; + placeholderOptions?: WysiwygPlaceholderOptions; /** * If we need to set dimensions for uploaded images * @@ -64,26 +64,17 @@ export const BundlePreset: ExtensionAuto = (builder, opts) baseSchema: { paragraphKey: f.toPM(A.Text), paragraphPlaceholder: (node: Node, parent?: Node | null) => { - let isPlaceholderShown = false; - - if (opts.placeholderOptions?.behavior === 'empty-row') { - isPlaceholderShown = !node.text && parent?.type.name === 'doc'; - } else { - isPlaceholderShown = - !node.text && parent?.type.name === BaseNode.Doc && parent.childCount === 1; - } - - let text = i18nPlaceholder('doc_empty'); - - if (opts.placeholderOptions?.value) { - if (typeof opts.placeholderOptions?.value === 'string') { - text = opts.placeholderOptions?.value; - } else { - text = opts.placeholderOptions?.value(); - } - } - - return isPlaceholderShown ? text : null; + const {value, behavior} = opts.placeholderOptions || {}; + + const isRowEmpty = !node.text && parent?.type.name === BaseNode.Doc; + const isDocEmpty = isRowEmpty && parent.childCount === 1; + const showPlaceholder = behavior === 'empty-row' ? isRowEmpty : isDocEmpty; + + if (!showPlaceholder) return null; + + return typeof value === 'function' + ? value() + : value ?? i18nPlaceholder('doc_empty'); }, ...opts.baseSchema, }, From a74661f0a6dc583f2508ac5196075101ae55b3dd Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Tue, 3 Dec 2024 16:59:57 +0300 Subject: [PATCH 4/6] add third condition --- src/bundle/types.ts | 2 +- src/bundle/wysiwyg-preset.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/bundle/types.ts b/src/bundle/types.ts index 25a7ba2e..0c538870 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -29,7 +29,7 @@ export type ParseInsertedUrlAsImage = (text: string) => {imageUrl: string; title export type WysiwygPlaceholderOptions = { value?: string | (() => string); /** Default – empty-doc */ - behavior?: 'empty-doc' | 'empty-row'; + behavior?: 'empty-doc' | 'empty-doc-row' | 'empty-row'; }; export type MarkdownEditorMdOptions = { diff --git a/src/bundle/wysiwyg-preset.ts b/src/bundle/wysiwyg-preset.ts index 4dad8a43..e5bd8f79 100644 --- a/src/bundle/wysiwyg-preset.ts +++ b/src/bundle/wysiwyg-preset.ts @@ -66,9 +66,14 @@ export const BundlePreset: ExtensionAuto = (builder, opts) paragraphPlaceholder: (node: Node, parent?: Node | null) => { const {value, behavior} = opts.placeholderOptions || {}; - const isRowEmpty = !node.text && parent?.type.name === BaseNode.Doc; - const isDocEmpty = isRowEmpty && parent.childCount === 1; - const showPlaceholder = behavior === 'empty-row' ? isRowEmpty : isDocEmpty; + const emptyList = { + 'empty-row': !node.text, + 'empty-doc-row': !node.text && parent?.type.name === BaseNode.Doc, + 'empty-doc': + !node.text && parent?.type.name === BaseNode.Doc && parent.childCount === 1, + }; + + const showPlaceholder = emptyList[behavior || 'empty-doc']; if (!showPlaceholder) return null; From e70b7cbbd45b75973b5a0005108ccbc0a597f1bf Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Mon, 16 Dec 2024 15:57:58 +0300 Subject: [PATCH 5/6] fix --- src/bundle/types.ts | 9 +++++++-- src/bundle/wysiwyg-preset.ts | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/bundle/types.ts b/src/bundle/types.ts index 0c538870..6eed222f 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -28,8 +28,13 @@ export type ParseInsertedUrlAsImage = (text: string) => {imageUrl: string; title export type WysiwygPlaceholderOptions = { value?: string | (() => string); - /** Default – empty-doc */ - behavior?: 'empty-doc' | 'empty-doc-row' | 'empty-row'; + /** Default – empty-doc + Values: + - 'empty-doc' – the placeholder will only be shown in an empty document; + - 'empty-row-top-level' – the placeholder will be displayed in an empty line, which is located at the top level of the document; + - 'empty-row' – Заполнитель будет отображаться в любой пустой строке документа; + */ + behavior?: 'empty-doc' | 'empty-row-top-level' | 'empty-row'; }; export type MarkdownEditorMdOptions = { diff --git a/src/bundle/wysiwyg-preset.ts b/src/bundle/wysiwyg-preset.ts index e5bd8f79..af43bc4a 100644 --- a/src/bundle/wysiwyg-preset.ts +++ b/src/bundle/wysiwyg-preset.ts @@ -66,14 +66,14 @@ export const BundlePreset: ExtensionAuto = (builder, opts) paragraphPlaceholder: (node: Node, parent?: Node | null) => { const {value, behavior} = opts.placeholderOptions || {}; - const emptyList = { + const emptyEntries = { 'empty-row': !node.text, - 'empty-doc-row': !node.text && parent?.type.name === BaseNode.Doc, + 'empty-row-top-level': !node.text && parent?.type.name === BaseNode.Doc, 'empty-doc': !node.text && parent?.type.name === BaseNode.Doc && parent.childCount === 1, }; - const showPlaceholder = emptyList[behavior || 'empty-doc']; + const showPlaceholder = emptyEntries[behavior || 'empty-doc']; if (!showPlaceholder) return null; From 8e91f688ab9d057e918f7ba4b9251936b47ff30f Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Tue, 17 Dec 2024 15:49:23 +0300 Subject: [PATCH 6/6] fix description --- src/bundle/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bundle/types.ts b/src/bundle/types.ts index 6eed222f..b25ad335 100644 --- a/src/bundle/types.ts +++ b/src/bundle/types.ts @@ -30,9 +30,9 @@ export type WysiwygPlaceholderOptions = { value?: string | (() => string); /** Default – empty-doc Values: - - 'empty-doc' – the placeholder will only be shown in an empty document; - - 'empty-row-top-level' – the placeholder will be displayed in an empty line, which is located at the top level of the document; - - 'empty-row' – Заполнитель будет отображаться в любой пустой строке документа; + - 'empty-doc' – The placeholder will only be shown when the document is completely empty; + - 'empty-row-top-level' – The placeholder will be displayed in an empty line that is at the top level of the document structure; + - 'empty-row' – The placeholder will be shown in any empty line within the document, regardless of its nesting level. */ behavior?: 'empty-doc' | 'empty-row-top-level' | 'empty-row'; };