Skip to content

Commit 875d025

Browse files
authored
feat: add options for placeholders (#141)
1 parent 8f7f013 commit 875d025

File tree

19 files changed

+129
-34
lines changed

19 files changed

+129
-34
lines changed

src/extensions/base/BaseSchema/BaseSchemaSpecs/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ export enum BaseNode {
1111
export const pType = nodeTypeFactory(BaseNode.Paragraph);
1212

1313
export type BaseSchemaSpecsOptions = {
14+
// This cannot be passed through placeholder option of BehaviorPreset because BasePreset initializes first
1415
paragraphPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
1516
};
1617

1718
export const BaseSchemaSpecs: ExtensionAuto<BaseSchemaSpecsOptions> = (builder, opts) => {
18-
const {paragraphPlaceholder} = opts;
19-
2019
builder
2120
.addNode(BaseNode.Doc, () => ({
2221
spec: {
@@ -45,9 +44,9 @@ export const BaseSchemaSpecs: ExtensionAuto<BaseSchemaSpecsOptions> = (builder,
4544
toDOM() {
4645
return ['p', 0];
4746
},
48-
placeholder: paragraphPlaceholder
47+
placeholder: opts.paragraphPlaceholder
4948
? {
50-
content: paragraphPlaceholder,
49+
content: opts.paragraphPlaceholder,
5150
alwaysVisible: false,
5251
}
5352
: undefined,

src/extensions/behavior/Placeholder/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {cn} from '../../../classname';
77
import type {ExtensionAuto} from '../../../core';
88
import {isNodeEmpty} from '../../../utils/nodes';
99
import {isTextSelection} from '../../../utils/selection';
10-
import {getPlaceholderContent} from '../../../utils/placeholder';
10+
import {getPlaceholderContent, PlaceholderOptions} from '../../../utils/placeholder';
1111

1212
import './index.scss';
1313

@@ -97,7 +97,8 @@ type WidgetsMap = Record<number, WidgetSpec | PluginKey>;
9797

9898
const pluginKey = new PluginKey<PlaceholderPluginState>('placeholder_plugin');
9999

100-
export const Placeholder: ExtensionAuto = (builder) => {
100+
export const Placeholder: ExtensionAuto<PlaceholderOptions> = (builder, opts) => {
101+
builder.context.set('placeholder', opts);
101102
builder.addPlugin(
102103
() =>
103104
new Plugin<PlaceholderPluginState>({
@@ -120,6 +121,7 @@ export const Placeholder: ExtensionAuto = (builder) => {
120121
apply: applyState,
121122
},
122123
}),
124+
builder.Priority.VeryHigh,
123125
);
124126
};
125127

@@ -231,3 +233,11 @@ declare module 'prosemirror-model' {
231233
};
232234
}
233235
}
236+
237+
declare global {
238+
namespace YfmEditor {
239+
interface Context {
240+
placeholder: PlaceholderOptions;
241+
}
242+
}
243+
}

src/extensions/behavior/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {Cursor, CursorOptions} from './Cursor';
66
import {History, HistoryOptions} from './History';
77
import {Clipboard, ClipboardOptions} from './Clipboard';
88
import {ReactRendererExtension, ReactRenderer} from './ReactRenderer';
9+
import {PlaceholderOptions} from '../../utils/placeholder';
910

1011
export * from './Cursor';
1112
export * from './History';
@@ -18,13 +19,14 @@ export type BehaviorPresetOptions = {
1819
cursor?: CursorOptions;
1920
history?: HistoryOptions;
2021
clipboard?: ClipboardOptions;
22+
placeholder?: PlaceholderOptions;
2123
reactRenderer: ReactRenderer;
2224
};
2325

2426
export const BehaviorPreset: ExtensionAuto<BehaviorPresetOptions> = (builder, opts) => {
2527
builder
2628
.use(Selection)
27-
.use(Placeholder)
29+
.use(Placeholder, opts.placeholder ?? {})
2830
.use(Cursor, opts.cursor ?? {})
2931
.use(History, opts.history ?? {})
3032
.use(Clipboard, opts.clipboard ?? {})

src/extensions/markdown/Deflist/DeflistSpecs/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ export const defTermType = nodeTypeFactory(DeflistNode.Term);
1313
export const defDescType = nodeTypeFactory(DeflistNode.Desc);
1414

1515
export type DeflistSpecsOptions = {
16+
/**
17+
* @deprecated: use placeholder option in BehaviorPreset instead.
18+
*/
1619
deflistTermPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
20+
/**
21+
* @deprecated: use placeholder option in BehaviorPreset instead.
22+
*/
1723
deflistDescPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
1824
};
1925

2026
export const DeflistSpecs: ExtensionAuto<DeflistSpecsOptions> = (builder, opts) => {
21-
const spec = getSpec(opts);
27+
const spec = getSpec(opts, builder.context.get('placeholder'));
2228

2329
builder.configureMd((md) => md.use(deflistPlugin));
2430
builder

src/extensions/markdown/Deflist/DeflistSpecs/spec.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import type {NodeSpec} from 'prosemirror-model';
22
import type {DeflistSpecsOptions} from './index';
33
import {DeflistNode} from './const';
4+
import {PlaceholderOptions} from '../../../../utils/placeholder';
45

56
const DEFAULT_PLACEHOLDERS = {
67
Term: 'Definition term',
78
Desc: 'Definition description',
89
};
910

10-
export const getSpec = (opts?: DeflistSpecsOptions): Record<DeflistNode, NodeSpec> => ({
11+
export const getSpec = (
12+
opts?: DeflistSpecsOptions,
13+
placeholder?: PlaceholderOptions,
14+
): Record<DeflistNode, NodeSpec> => ({
1115
[DeflistNode.List]: {
1216
group: 'block',
1317
content: `(${DeflistNode.Term} ${DeflistNode.Desc})+`,
@@ -29,7 +33,10 @@ export const getSpec = (opts?: DeflistSpecsOptions): Record<DeflistNode, NodeSpe
2933
return ['dt', 0];
3034
},
3135
placeholder: {
32-
content: opts?.deflistTermPlaceholder ?? DEFAULT_PLACEHOLDERS.Term,
36+
content:
37+
placeholder?.[DeflistNode.Term] ??
38+
opts?.deflistTermPlaceholder ??
39+
DEFAULT_PLACEHOLDERS.Term,
3340
alwaysVisible: true,
3441
},
3542
selectable: false,
@@ -46,7 +53,10 @@ export const getSpec = (opts?: DeflistSpecsOptions): Record<DeflistNode, NodeSpe
4653
return ['dd', 0];
4754
},
4855
placeholder: {
49-
content: opts?.deflistDescPlaceholder ?? DEFAULT_PLACEHOLDERS.Desc,
56+
content:
57+
placeholder?.[DeflistNode.Desc] ??
58+
opts?.deflistDescPlaceholder ??
59+
DEFAULT_PLACEHOLDERS.Desc,
5060
alwaysVisible: true,
5161
},
5262
selectable: false,

src/extensions/markdown/Heading/HeadingSpecs/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ export const headingType = nodeTypeFactory(headingNodeName);
99
const DEFAULT_PLACEHOLDER = (node: Node) => 'Heading ' + node.attrs[headingLevelAttr];
1010

1111
export type HeadingSpecsOptions = {
12+
/**
13+
* @deprecated: use placeholder option in BehaviorPreset instead.
14+
*/
1215
headingPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
1316
};
1417

1518
export const HeadingSpecs: ExtensionAuto<HeadingSpecsOptions> = (builder, opts) => {
16-
const {headingPlaceholder} = opts ?? {};
17-
1819
builder.addNode(headingNodeName, () => ({
1920
spec: {
2021
attrs: {[headingLevelAttr]: {default: 1}},
@@ -33,7 +34,10 @@ export const HeadingSpecs: ExtensionAuto<HeadingSpecsOptions> = (builder, opts)
3334
return ['h' + node.attrs[headingLevelAttr], 0];
3435
},
3536
placeholder: {
36-
content: headingPlaceholder ?? DEFAULT_PLACEHOLDER,
37+
content:
38+
builder.context.get('placeholder')?.heading ??
39+
opts.headingPlaceholder ??
40+
DEFAULT_PLACEHOLDER,
3741
alwaysVisible: true,
3842
},
3943
},

src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ export const checkboxLabelType = nodeTypeFactory(CheckboxNode.Label);
1414
export const checkboxInputType = nodeTypeFactory(CheckboxNode.Input);
1515

1616
export type CheckboxSpecsOptions = {
17+
/**
18+
* @deprecated: use placeholder option in BehaviorPreset instead.
19+
*/
1720
checkboxLabelPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
1821
inputView?: YENodeSpec['view'];
1922
labelView?: YENodeSpec['view'];
2023
checkboxView?: YENodeSpec['view'];
2124
};
2225

2326
export const CheckboxSpecs: ExtensionAuto<CheckboxSpecsOptions> = (builder, opts) => {
24-
const spec = getSpec(opts);
27+
const spec = getSpec(opts, builder.context.get('placeholder'));
2528

2629
builder
2730
.configureMd((md) => checkboxPlugin(md, {idPrefix, divClass: b()}))

src/extensions/yfm/Checkbox/CheckboxSpecs/spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import type {NodeSpec} from 'prosemirror-model';
22
import type {CheckboxSpecsOptions} from './index';
33
import {b, CheckboxNode} from '../const';
4+
import {PlaceholderOptions} from '../../../../utils/placeholder';
45

56
const DEFAULT_LABEL_PLACEHOLDER = 'Checkbox';
67

78
export const getSpec = (
89
opts?: Pick<CheckboxSpecsOptions, 'checkboxLabelPlaceholder'>,
10+
placeholder?: PlaceholderOptions,
911
): Record<CheckboxNode, NodeSpec> => ({
1012
[CheckboxNode.Checkbox]: {
1113
group: 'block',
@@ -54,7 +56,10 @@ export const getSpec = (
5456
},
5557
escapeText: false,
5658
placeholder: {
57-
content: opts?.checkboxLabelPlaceholder ?? DEFAULT_LABEL_PLACEHOLDER,
59+
content:
60+
placeholder?.[CheckboxNode.Label] ??
61+
opts?.checkboxLabelPlaceholder ??
62+
DEFAULT_LABEL_PLACEHOLDER,
5863
alwaysVisible: true,
5964
},
6065
toDOM(node) {

src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ type ImsizeTypedAttributes = {
1818
export {ImgSizeAttr};
1919

2020
export type ImgSizeSpecsOptions = {
21+
/**
22+
* @deprecated: use placeholder option in BehaviorPreset instead.
23+
*/
2124
placeholder?: NodeSpec['placeholder'];
2225
};
2326

2427
export const ImgSizeSpecs: ExtensionAuto<ImgSizeSpecsOptions> = (builder, opts) => {
28+
const placeholderContent = builder.context.get('placeholder')?.imgSize;
29+
2530
builder.configureMd((md) => md.use(imsize, {log}));
2631
builder.addNode(imageNodeName, () => ({
2732
spec: {
@@ -33,7 +38,7 @@ export const ImgSizeSpecs: ExtensionAuto<ImgSizeSpecsOptions> = (builder, opts)
3338
[ImgSizeAttr.Height]: {default: null},
3439
[ImgSizeAttr.Width]: {default: null},
3540
},
36-
placeholder: opts.placeholder,
41+
placeholder: placeholderContent ? {content: placeholderContent} : opts.placeholder,
3742
group: 'inline',
3843
draggable: true,
3944
parseDOM: [

src/extensions/yfm/YfmCut/YfmCutSpecs/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ export type YfmCutSpecsOptions = {
1818
cutView?: YENodeSpec['view'];
1919
cutTitleView?: YENodeSpec['view'];
2020
cutContentView?: YENodeSpec['view'];
21+
/**
22+
* @deprecated: use placeholder option in BehaviorPreset instead.
23+
*/
2124
yfmCutTitlePlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
25+
/**
26+
* @deprecated: use placeholder option in BehaviorPreset instead.
27+
*/
2228
yfmCutContentPlaceholder?: NonNullable<NodeSpec['placeholder']>['content'];
2329
};
2430

2531
export const YfmCutSpecs: ExtensionAuto<YfmCutSpecsOptions> = (builder, opts) => {
26-
const spec = getSpec(opts);
32+
const spec = getSpec(opts, builder.context.get('placeholder'));
2733

2834
builder
2935
.configureMd((md) => md.use(yfmPlugin, {log}))

0 commit comments

Comments
 (0)