From 593f2c764a4354cc7c0e8a0623c69a7b155832a2 Mon Sep 17 00:00:00 2001 From: Ruslan Palkin Date: Mon, 16 Oct 2023 22:48:53 +0300 Subject: [PATCH] feat: add options for placeholders --- .../base/BaseSchema/BaseSchemaSpecs/index.ts | 14 +++++++++---- src/extensions/base/index.ts | 9 ++++++-- .../markdown/Deflist/DeflistSpecs/index.ts | 8 +++++++ .../markdown/Deflist/DeflistSpecs/spec.ts | 11 ++++++++-- .../markdown/Heading/HeadingSpecs/index.ts | 9 ++++++-- src/extensions/markdown/index.ts | 13 ++++++++---- .../yfm/Checkbox/CheckboxSpecs/index.ts | 5 +++++ .../yfm/Checkbox/CheckboxSpecs/spec.ts | 8 +++++-- src/extensions/yfm/Checkbox/index.ts | 5 ++++- .../yfm/ImgSize/ImgSizeSpecs/index.ts | 9 +++++++- .../yfm/YfmCut/YfmCutSpecs/index.ts | 8 +++++++ src/extensions/yfm/YfmCut/YfmCutSpecs/spec.ts | 11 ++++++++-- .../yfm/YfmHeading/YfmHeadingSpecs/index.ts | 12 +++++++++-- .../yfm/YfmNote/YfmNoteSpecs/index.ts | 5 +++++ .../yfm/YfmNote/YfmNoteSpecs/spec.ts | 6 +++++- .../yfm/YfmTable/YfmTableSpecs/index.ts | 5 +++++ .../yfm/YfmTable/YfmTableSpecs/spec.ts | 6 +++++- .../yfm/YfmTabs/YfmTabsSpecs/index.ts | 5 +++++ .../yfm/YfmTabs/YfmTabsSpecs/spec.ts | 6 +++++- src/extensions/yfm/index.ts | 21 ++++++++++++------- src/extensions/yfm/specs.ts | 2 ++ src/utils/placeholder.ts | 21 +++++++++++++++++++ 22 files changed, 166 insertions(+), 33 deletions(-) diff --git a/src/extensions/base/BaseSchema/BaseSchemaSpecs/index.ts b/src/extensions/base/BaseSchema/BaseSchemaSpecs/index.ts index f452d0f5..dbbe20cc 100644 --- a/src/extensions/base/BaseSchema/BaseSchemaSpecs/index.ts +++ b/src/extensions/base/BaseSchema/BaseSchemaSpecs/index.ts @@ -1,6 +1,7 @@ import type {NodeSpec} from 'prosemirror-model'; import type {ExtensionAuto} from '../../../../core'; import {nodeTypeFactory} from '../../../../utils/schema'; +import {processPlaceholderContent, PlaceholderOptions} from '../../../../utils/placeholder'; export enum BaseNode { Doc = 'doc', @@ -11,12 +12,17 @@ export enum BaseNode { export const pType = nodeTypeFactory(BaseNode.Paragraph); export type BaseSchemaSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ paragraphPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const BaseSchemaSpecs: ExtensionAuto = (builder, opts) => { - const {paragraphPlaceholder} = opts; - + const {placeholderOptions, paragraphPlaceholder} = opts; + const placeholderContent = + processPlaceholderContent(placeholderOptions?.[BaseNode.Paragraph]) ?? paragraphPlaceholder; builder .addNode(BaseNode.Doc, () => ({ spec: { @@ -45,9 +51,9 @@ export const BaseSchemaSpecs: ExtensionAuto = (builder, toDOM() { return ['p', 0]; }, - placeholder: paragraphPlaceholder + placeholder: placeholderContent ? { - content: paragraphPlaceholder, + content: placeholderContent, alwaysVisible: false, } : undefined, diff --git a/src/extensions/base/index.ts b/src/extensions/base/index.ts index c442452f..e67325ae 100644 --- a/src/extensions/base/index.ts +++ b/src/extensions/base/index.ts @@ -4,6 +4,7 @@ import {BaseSchema, BaseSchemaOptions} from './BaseSchema'; import {BaseInputRules} from './BaseInputRules'; import {BaseKeymap} from './BaseKeymap'; import {BaseStyles} from './BaseStyles'; +import {PlaceholderOptions} from '../../utils/placeholder'; export * from './BaseSchema'; export * from './BaseStyles'; @@ -12,11 +13,15 @@ export * from './BaseInputRules'; export type BasePresetOptions = { baseSchema?: BaseSchemaOptions; + placeholderOptions?: PlaceholderOptions; }; -export const BasePreset: ExtensionAuto = (builder, opts) => { +export const BasePreset: ExtensionAuto = ( + builder, + {placeholderOptions, ...opts}, +) => { builder - .use(BaseSchema, opts.baseSchema ?? {}) + .use(BaseSchema, {...opts.baseSchema, placeholderOptions}) .use(BaseKeymap) .use(BaseInputRules) .use(BaseStyles); diff --git a/src/extensions/markdown/Deflist/DeflistSpecs/index.ts b/src/extensions/markdown/Deflist/DeflistSpecs/index.ts index a64c5ab6..ecb34d25 100644 --- a/src/extensions/markdown/Deflist/DeflistSpecs/index.ts +++ b/src/extensions/markdown/Deflist/DeflistSpecs/index.ts @@ -6,6 +6,7 @@ import {DeflistNode} from './const'; import {fromYfm} from './fromYfm'; import {getSpec} from './spec'; import {toYfm} from './toYfm'; +import {PlaceholderOptions} from '../../../../utils/placeholder'; export {DeflistNode} from './const'; export const defListType = nodeTypeFactory(DeflistNode.List); @@ -13,8 +14,15 @@ export const defTermType = nodeTypeFactory(DeflistNode.Term); export const defDescType = nodeTypeFactory(DeflistNode.Desc); export type DeflistSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ deflistTermPlaceholder?: NonNullable['content']; + /** + * @deprecated: use placeholderOptions instead. + */ deflistDescPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const DeflistSpecs: ExtensionAuto = (builder, opts) => { diff --git a/src/extensions/markdown/Deflist/DeflistSpecs/spec.ts b/src/extensions/markdown/Deflist/DeflistSpecs/spec.ts index 51a5e5f7..a643412a 100644 --- a/src/extensions/markdown/Deflist/DeflistSpecs/spec.ts +++ b/src/extensions/markdown/Deflist/DeflistSpecs/spec.ts @@ -1,6 +1,7 @@ import type {NodeSpec} from 'prosemirror-model'; import type {DeflistSpecsOptions} from './index'; import {DeflistNode} from './const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_PLACEHOLDERS = { Term: 'Definition term', @@ -29,7 +30,10 @@ export const getSpec = (opts?: DeflistSpecsOptions): Record 'Heading ' + node.attrs[headingLevel export type HeadingSpecsOptions = { headingPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const HeadingSpecs: ExtensionAuto = (builder, opts) => { - const {headingPlaceholder} = opts ?? {}; + const {headingPlaceholder, placeholderOptions} = opts ?? {}; builder.addNode(headingNodeName, () => ({ spec: { @@ -33,7 +35,10 @@ export const HeadingSpecs: ExtensionAuto = (builder, opts) return ['h' + node.attrs[headingLevelAttr], 0]; }, placeholder: { - content: headingPlaceholder ?? DEFAULT_PLACEHOLDER, + content: + processPlaceholderContent(placeholderOptions?.heading) ?? + headingPlaceholder ?? + DEFAULT_PLACEHOLDER, alwaysVisible: true, }, }, diff --git a/src/extensions/markdown/index.ts b/src/extensions/markdown/index.ts index 7398b657..16674e20 100644 --- a/src/extensions/markdown/index.ts +++ b/src/extensions/markdown/index.ts @@ -21,6 +21,7 @@ import {HorizontalRule} from './HorizontalRule'; import {Heading, HeadingOptions} from './Heading'; import {CodeBlock, CodeBlockOptions} from './CodeBlock'; import {Blockquote, BlockquoteOptions} from './Blockquote'; +import {PlaceholderOptions} from '../../utils/placeholder'; export * from './Bold'; export * from './Code'; @@ -72,16 +73,20 @@ export type MarkdownBlocksPresetOptions = { codeBlock?: CodeBlockOptions; blockquote?: BlockquoteOptions; heading?: false | Extension | HeadingOptions; + placeholderOptions?: PlaceholderOptions; }; -export const MarkdownBlocksPreset: ExtensionAuto = (builder, opts) => { +export const MarkdownBlocksPreset: ExtensionAuto = ( + builder, + {placeholderOptions, ...opts}, +) => { builder .use(Html) .use(Table) .use(HorizontalRule) .use(Lists, opts.lists ?? {}) .use(Breaks, opts.breaks ?? {}) - .use(Deflist, opts.deflist ?? {}) + .use(Deflist, {...opts.deflist, placeholderOptions}) .use(CodeBlock, opts.codeBlock ?? {}) .use(Blockquote, opts.blockquote ?? {}); @@ -90,7 +95,7 @@ export const MarkdownBlocksPreset: ExtensionAuto = } if (opts.heading !== false) { - if (isFunction(opts.heading)) builder.use(opts.heading); - else builder.use(Heading, opts.heading ?? {}); + if (isFunction(opts.heading)) builder.use(opts.heading, {placeholderOptions}); + else builder.use(Heading, {...opts.heading, placeholderOptions}); } }; diff --git a/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts b/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts index 99cf0bc0..6339fa74 100644 --- a/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts +++ b/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts @@ -7,6 +7,7 @@ import {b, CheckboxNode, idPrefix} from './const'; import {fromYfm} from './fromYfm'; import {getSpec} from './spec'; import {toYfm} from './toYfm'; +import {PlaceholderOptions} from '../../../../utils/placeholder'; export {CheckboxNode} from './const'; export const checkboxType = nodeTypeFactory(CheckboxNode.Checkbox); @@ -14,10 +15,14 @@ export const checkboxLabelType = nodeTypeFactory(CheckboxNode.Label); export const checkboxInputType = nodeTypeFactory(CheckboxNode.Input); export type CheckboxSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ checkboxLabelPlaceholder?: NonNullable['content']; inputView?: YENodeSpec['view']; labelView?: YENodeSpec['view']; checkboxView?: YENodeSpec['view']; + placeholderOptions?: PlaceholderOptions; }; export const CheckboxSpecs: ExtensionAuto = (builder, opts) => { diff --git a/src/extensions/yfm/Checkbox/CheckboxSpecs/spec.ts b/src/extensions/yfm/Checkbox/CheckboxSpecs/spec.ts index de362778..99a60d4f 100644 --- a/src/extensions/yfm/Checkbox/CheckboxSpecs/spec.ts +++ b/src/extensions/yfm/Checkbox/CheckboxSpecs/spec.ts @@ -1,11 +1,12 @@ import type {NodeSpec} from 'prosemirror-model'; import type {CheckboxSpecsOptions} from './index'; import {b, CheckboxNode} from '../const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_LABEL_PLACEHOLDER = 'Checkbox'; export const getSpec = ( - opts?: Pick, + opts?: Pick, ): Record => ({ [CheckboxNode.Checkbox]: { group: 'block', @@ -54,7 +55,10 @@ export const getSpec = ( }, escapeText: false, placeholder: { - content: opts?.checkboxLabelPlaceholder ?? DEFAULT_LABEL_PLACEHOLDER, + content: + processPlaceholderContent(opts?.placeholderOptions?.[CheckboxNode.Label]) ?? + opts?.checkboxLabelPlaceholder ?? + DEFAULT_LABEL_PLACEHOLDER, alwaysVisible: true, }, toDOM(node) { diff --git a/src/extensions/yfm/Checkbox/index.ts b/src/extensions/yfm/Checkbox/index.ts index 0820c00f..e26edd0d 100644 --- a/src/extensions/yfm/Checkbox/index.ts +++ b/src/extensions/yfm/Checkbox/index.ts @@ -14,7 +14,10 @@ const checkboxAction = 'addCheckbox'; export {CheckboxNode, checkboxType, checkboxLabelType, checkboxInputType} from './CheckboxSpecs'; -export type CheckboxOptions = Pick & {}; +export type CheckboxOptions = Pick< + CheckboxSpecsOptions, + 'checkboxLabelPlaceholder' | 'placeholderOptions' +> & {}; export const Checkbox: ExtensionAuto = (builder, opts) => { builder.use(CheckboxSpecs, { diff --git a/src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts b/src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts index c962e080..d6b2830a 100644 --- a/src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts +++ b/src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts @@ -6,6 +6,7 @@ import log from '@doc-tools/transform/lib/log'; import type {ExtensionAuto} from '../../../../core'; import {imageNodeName} from '../../../markdown/Image/const'; +import {processPlaceholderContent, PlaceholderOptions} from '../../../../utils/placeholder'; type ImsizeTypedAttributes = { [ImgSizeAttr.Src]: string; @@ -18,10 +19,16 @@ type ImsizeTypedAttributes = { export {ImgSizeAttr}; export type ImgSizeSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ placeholder?: NodeSpec['placeholder']; + placeholderOptions?: PlaceholderOptions; }; export const ImgSizeSpecs: ExtensionAuto = (builder, opts) => { + const placeholderContent = processPlaceholderContent(opts?.placeholderOptions?.imgSize); + builder.configureMd((md) => md.use(imsize, {log})); builder.addNode(imageNodeName, () => ({ spec: { @@ -33,7 +40,7 @@ export const ImgSizeSpecs: ExtensionAuto = (builder, opts) [ImgSizeAttr.Height]: {default: null}, [ImgSizeAttr.Width]: {default: null}, }, - placeholder: opts.placeholder, + placeholder: placeholderContent ? {content: placeholderContent} : opts.placeholder, group: 'inline', draggable: true, parseDOM: [ diff --git a/src/extensions/yfm/YfmCut/YfmCutSpecs/index.ts b/src/extensions/yfm/YfmCut/YfmCutSpecs/index.ts index d861c577..ec7dc05b 100644 --- a/src/extensions/yfm/YfmCut/YfmCutSpecs/index.ts +++ b/src/extensions/yfm/YfmCut/YfmCutSpecs/index.ts @@ -8,6 +8,7 @@ import {CutNode} from './const'; import {fromYfm} from './fromYfm'; import {getSpec} from './spec'; import {toYfm} from './toYfm'; +import {PlaceholderOptions} from '../../../../utils/placeholder'; export {CutNode} from './const'; export const cutType = nodeTypeFactory(CutNode.Cut); @@ -18,8 +19,15 @@ export type YfmCutSpecsOptions = { cutView?: YENodeSpec['view']; cutTitleView?: YENodeSpec['view']; cutContentView?: YENodeSpec['view']; + /** + * @deprecated: use placeholderOptions instead. + */ yfmCutTitlePlaceholder?: NonNullable['content']; + /** + * @deprecated: use placeholderOptions instead. + */ yfmCutContentPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const YfmCutSpecs: ExtensionAuto = (builder, opts) => { diff --git a/src/extensions/yfm/YfmCut/YfmCutSpecs/spec.ts b/src/extensions/yfm/YfmCut/YfmCutSpecs/spec.ts index c9b30c94..0b0d662d 100644 --- a/src/extensions/yfm/YfmCut/YfmCutSpecs/spec.ts +++ b/src/extensions/yfm/YfmCut/YfmCutSpecs/spec.ts @@ -1,6 +1,7 @@ import type {NodeSpec} from 'prosemirror-model'; import type {YfmCutSpecsOptions} from './index'; import {CutNode} from '../const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_PLACEHOLDERS = { Title: 'Cut title', @@ -31,7 +32,10 @@ export const getSpec = (opts?: YfmCutSpecsOptions): Record => return ['div', node.attrs, 0]; }, placeholder: { - content: opts?.yfmCutTitlePlaceholder ?? DEFAULT_PLACEHOLDERS.Title, + content: + processPlaceholderContent(opts?.placeholderOptions?.[CutNode.CutTitle]) ?? + opts?.yfmCutTitlePlaceholder ?? + DEFAULT_PLACEHOLDERS.Title, alwaysVisible: true, }, selectable: false, @@ -48,7 +52,10 @@ export const getSpec = (opts?: YfmCutSpecsOptions): Record => return ['div', node.attrs, 0]; }, placeholder: { - content: opts?.yfmCutContentPlaceholder ?? DEFAULT_PLACEHOLDERS.Content, + content: + processPlaceholderContent(opts?.placeholderOptions?.[CutNode.CutContent]) ?? + opts?.yfmCutContentPlaceholder ?? + DEFAULT_PLACEHOLDERS.Content, alwaysVisible: true, }, selectable: false, diff --git a/src/extensions/yfm/YfmHeading/YfmHeadingSpecs/index.ts b/src/extensions/yfm/YfmHeading/YfmHeadingSpecs/index.ts index 16afb007..6bc43c02 100644 --- a/src/extensions/yfm/YfmHeading/YfmHeadingSpecs/index.ts +++ b/src/extensions/yfm/YfmHeading/YfmHeadingSpecs/index.ts @@ -2,18 +2,23 @@ import type {Node, NodeSpec} from 'prosemirror-model'; import type {ExtensionAuto} from '../../../../core'; import {headingNodeName, YfmHeadingAttr} from './const'; import {getNodeAttrs} from './utils'; +import {processPlaceholderContent, PlaceholderOptions} from '../../../../utils/placeholder'; const DEFAULT_PLACEHOLDER = (node: Node) => 'Heading ' + node.attrs[YfmHeadingAttr.Level]; export {YfmHeadingAttr} from './const'; export type YfmHeadingSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ headingPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; /** YfmHeading extension needs markdown-it-attrs plugin */ export const YfmHeadingSpecs: ExtensionAuto = (builder, opts) => { - const {headingPlaceholder} = opts ?? {}; + const {headingPlaceholder, placeholderOptions} = opts ?? {}; builder.addNode(headingNodeName, () => ({ spec: { @@ -52,7 +57,10 @@ export const YfmHeadingSpecs: ExtensionAuto = (builder, ]; }, placeholder: { - content: headingPlaceholder ?? DEFAULT_PLACEHOLDER, + content: + processPlaceholderContent(placeholderOptions?.heading) ?? + headingPlaceholder ?? + DEFAULT_PLACEHOLDER, alwaysVisible: true, }, }, diff --git a/src/extensions/yfm/YfmNote/YfmNoteSpecs/index.ts b/src/extensions/yfm/YfmNote/YfmNoteSpecs/index.ts index 08ddcc20..af9d41ff 100644 --- a/src/extensions/yfm/YfmNote/YfmNoteSpecs/index.ts +++ b/src/extensions/yfm/YfmNote/YfmNoteSpecs/index.ts @@ -7,12 +7,17 @@ import {toYfm} from './toYfm'; import {NoteNode} from './const'; import {fromYfm} from './fromYfm'; import {getSpec} from './spec'; +import {PlaceholderOptions} from '../../../../utils/placeholder'; export {NoteNode as YfmNoteNode} from './const'; export {noteType, noteTitleType} from './utils'; export type YfmNoteSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ yfmNoteTitlePlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const YfmNoteSpecs: ExtensionAuto = (builder, opts) => { diff --git a/src/extensions/yfm/YfmNote/YfmNoteSpecs/spec.ts b/src/extensions/yfm/YfmNote/YfmNoteSpecs/spec.ts index 3d12128b..ef807620 100644 --- a/src/extensions/yfm/YfmNote/YfmNoteSpecs/spec.ts +++ b/src/extensions/yfm/YfmNote/YfmNoteSpecs/spec.ts @@ -1,6 +1,7 @@ import type {NodeSpec} from 'prosemirror-model'; import {YfmNoteSpecsOptions} from './index'; import {NoteAttrs, NoteNode} from './const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_TITLE_PLACEHOLDER = 'Note'; @@ -45,7 +46,10 @@ export const getSpec = (opts?: YfmNoteSpecsOptions): Record selectable: false, allowSelection: false, placeholder: { - content: opts?.yfmNoteTitlePlaceholder ?? DEFAULT_TITLE_PLACEHOLDER, + content: + processPlaceholderContent(opts?.placeholderOptions?.[NoteNode.NoteTitle]) ?? + opts?.yfmNoteTitlePlaceholder ?? + DEFAULT_TITLE_PLACEHOLDER, alwaysVisible: true, }, complex: 'leaf', diff --git a/src/extensions/yfm/YfmTable/YfmTableSpecs/index.ts b/src/extensions/yfm/YfmTable/YfmTableSpecs/index.ts index 6aea3626..24ab1561 100644 --- a/src/extensions/yfm/YfmTable/YfmTableSpecs/index.ts +++ b/src/extensions/yfm/YfmTable/YfmTableSpecs/index.ts @@ -7,12 +7,17 @@ import {YfmTableNode} from './const'; import {fromYfm} from './fromYfm'; import {getSpec} from './spec'; import {toYfm} from './toYfm'; +import {PlaceholderOptions} from '../../../../utils/placeholder'; export {YfmTableNode} from './const'; export {yfmTableType, yfmTableBodyType, yfmTableRowType, yfmTableCellType} from './utils'; export type YfmTableSpecsOptions = { + /** + * @deprecated: use placeholderOptions instead. + */ yfmTableCellPlaceholder?: NonNullable['content']; + placeholderOptions?: PlaceholderOptions; }; export const YfmTableSpecs: ExtensionWithOptions = (builder, options) => { diff --git a/src/extensions/yfm/YfmTable/YfmTableSpecs/spec.ts b/src/extensions/yfm/YfmTable/YfmTableSpecs/spec.ts index 1cae6846..8754c28d 100644 --- a/src/extensions/yfm/YfmTable/YfmTableSpecs/spec.ts +++ b/src/extensions/yfm/YfmTable/YfmTableSpecs/spec.ts @@ -2,6 +2,7 @@ import type {NodeSpec} from 'prosemirror-model'; import {TableRole} from '../../../../table-utils'; import type {YfmTableSpecsOptions} from './index'; import {YfmTableNode} from './const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_CELL_PLACEHOLDER = 'Table cell'; @@ -67,7 +68,10 @@ export const getSpec = (opts?: YfmTableSpecsOptions): Record['content']; tabView?: YENodeSpec['view']; tabsListView?: YENodeSpec['view']; tabPanelView?: YENodeSpec['view']; tabsView?: YENodeSpec['view']; + placeholderOptions?: PlaceholderOptions; }; export const YfmTabsSpecs: ExtensionAuto = (builder, opts) => { diff --git a/src/extensions/yfm/YfmTabs/YfmTabsSpecs/spec.ts b/src/extensions/yfm/YfmTabs/YfmTabsSpecs/spec.ts index 071b38a3..6a4af017 100644 --- a/src/extensions/yfm/YfmTabs/YfmTabsSpecs/spec.ts +++ b/src/extensions/yfm/YfmTabs/YfmTabsSpecs/spec.ts @@ -1,6 +1,7 @@ import type {NodeSpec} from 'prosemirror-model'; import {YfmTabsSpecsOptions} from '.'; import {TabAttrs, TabPanelAttrs, TabsAttrs, TabsListAttrs, TabsNode} from './const'; +import {processPlaceholderContent} from '../../../../utils/placeholder'; const DEFAULT_PLACEHOLDERS = { TabTitle: 'Tab title', @@ -27,7 +28,10 @@ export const getSpec: (opts: YfmTabsSpecsOptions) => Record return ['div', node.attrs, 0]; }, placeholder: { - content: opts?.tabPlaceholder ?? DEFAULT_PLACEHOLDERS.TabTitle, + content: + processPlaceholderContent(opts?.placeholderOptions?.[TabsNode.Tab]) ?? + opts?.tabPlaceholder ?? + DEFAULT_PLACEHOLDERS.TabTitle, alwaysVisible: true, }, selectable: false, diff --git a/src/extensions/yfm/index.ts b/src/extensions/yfm/index.ts index 734e8b9c..77157c22 100644 --- a/src/extensions/yfm/index.ts +++ b/src/extensions/yfm/index.ts @@ -13,6 +13,7 @@ import {YfmHeading, YfmHeadingOptions} from './YfmHeading'; import {YfmNote, YfmNoteOptions} from './YfmNote'; import {YfmTable, YfmTableOptions} from './YfmTable'; import {YfmTabs} from './YfmTabs'; +import {PlaceholderOptions} from '../../utils/placeholder'; export * from './Checkbox'; export * from './Color'; @@ -36,21 +37,25 @@ export type YfmPresetOptions = { yfmNote?: YfmNoteOptions; yfmTable?: YfmTableOptions; yfmHeading?: YfmHeadingOptions; + placeholderOptions?: PlaceholderOptions; }; -export const YfmPreset: ExtensionAuto = (builder, opts) => { +export const YfmPreset: ExtensionAuto = ( + builder, + {placeholderOptions, ...opts}, +) => { builder - .use(Checkbox, opts.checkbox ?? {}) + .use(Checkbox, {...opts.checkbox, placeholderOptions}) .use(Color) - .use(ImgSize, opts.imgSize ?? {}) + .use(ImgSize, {...opts.imgSize, placeholderOptions}) .use(Math) .use(Monospace) .use(Video, opts.video ?? {}) .use(YfmDist) - .use(YfmCut, opts.yfmCut ?? {}) - .use(YfmNote, opts.yfmNote ?? {}) + .use(YfmCut, {...opts.yfmCut, placeholderOptions}) + .use(YfmNote, {...opts.yfmNote, placeholderOptions}) .use(YfmFile) - .use(YfmHeading, opts.yfmHeading ?? {}) - .use(YfmTable, opts.yfmTable ?? {}) - .use(YfmTabs); + .use(YfmHeading, {...opts.yfmHeading, placeholderOptions}) + .use(YfmTable, {...opts.yfmTable, placeholderOptions}) + .use(YfmTabs, {placeholderOptions}); }; diff --git a/src/extensions/yfm/specs.ts b/src/extensions/yfm/specs.ts index 24df26a7..b4829aa4 100644 --- a/src/extensions/yfm/specs.ts +++ b/src/extensions/yfm/specs.ts @@ -13,6 +13,7 @@ import {YfmHeadingSpecs, YfmHeadingSpecsOptions} from './YfmHeading/YfmHeadingSp import {YfmNoteSpecs, YfmNoteSpecsOptions} from './YfmNote/YfmNoteSpecs'; import {YfmTableSpecs, YfmTableSpecsOptions} from './YfmTable/YfmTableSpecs'; import {YfmTabsSpecs, YfmTabsSpecsOptions} from './YfmTabs/YfmTabsSpecs'; +import {PlaceholderOptions} from '../../utils/placeholder'; export * from './Checkbox/CheckboxSpecs'; export * from './Color/ColorSpecs'; @@ -38,6 +39,7 @@ export type YfmSpecsPresetOptions = { yfmTable?: YfmTableSpecsOptions; yfmTabs?: YfmTabsSpecsOptions; yfmHeading?: YfmHeadingSpecsOptions; + placeholderOptions?: PlaceholderOptions; }; export const YfmSpecsPreset: ExtensionAuto = (builder, opts) => { diff --git a/src/utils/placeholder.ts b/src/utils/placeholder.ts index c5bdee02..07a92662 100644 --- a/src/utils/placeholder.ts +++ b/src/utils/placeholder.ts @@ -1,5 +1,26 @@ import type {Node} from 'prosemirror-model'; import type {} from '../extensions/behavior/Placeholder'; +import isFunction from 'lodash/isFunction'; +import {BaseNode, CheckboxNode, CutNode, DeflistNode, TabsNode, YfmTableNode} from '../extensions'; +import {NoteNode} from '../extensions/yfm/YfmNote/YfmNoteSpecs/const'; + +type NeedPlaceholder = + | BaseNode.Paragraph + | CheckboxNode.Label + | DeflistNode.Term + | DeflistNode.Desc + | CutNode.CutTitle + | CutNode.CutContent + | TabsNode.Tab + | NoteNode.NoteTitle + | YfmTableNode.Cell + | 'imgSize' + | 'heading'; + +export type PlaceholderOptions = Partial string)>>; + +export const processPlaceholderContent = (placeholder: string | (() => string) | undefined) => + isFunction(placeholder) ? placeholder() : placeholder; export const getPlaceholderContent = (node: Node, parent?: Node | null) => { const content = node.type.spec.placeholder?.content || '';