Skip to content

Commit 96cf1d3

Browse files
authored
feat(Placeholder): pass the parent node to the placeholder's content callback (#59)
1 parent 1d00bbe commit 96cf1d3

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

demo/Playground.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {useUpdate} from 'react-use';
44
import {Button, RadioButton, TextInput} from '@gravity-ui/uikit';
55

66
import {
7+
BaseNode,
78
BasePreset,
89
BehaviorPreset,
910
MarkdownBlocksPreset,
@@ -51,7 +52,15 @@ export const Playground = React.memo<PlaygroundProps>((props) => {
5152
const extensions = React.useMemo<Extension>(
5253
() => (builder) =>
5354
builder
54-
.use(BasePreset, {})
55+
.use(BasePreset, {
56+
baseSchema: {
57+
paragraphPlaceholder(_node, parent) {
58+
return parent?.type.name === BaseNode.Doc && parent.childCount === 1
59+
? 'Now... start typing'
60+
: 'Empty paragraph';
61+
},
62+
},
63+
})
5564
.use(BehaviorPreset, {
5665
history: {
5766
undoKey: keys.undo,

src/extensions/behavior/Cursor/gapcursor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const toDOM: WidgetConstructor = (view, getPos) => {
5858
const node = pType(view.state.schema).create();
5959

6060
const element = DOMSerializer.fromSchema(view.state.schema).serializeNode(node);
61-
element.appendChild(createPlaceholder(node, true));
61+
element.appendChild(createPlaceholder(node, null, true));
6262
(element as Element).classList.add('ye-gapcursor');
6363
(element as HTMLElement).addEventListener('mousedown', () => {
6464
const pos = getPos();

src/extensions/behavior/Placeholder/index.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import {isTextSelection} from '../../../utils/selection';
99

1010
import './index.scss';
1111

12-
export const getPlaceholderContent = (node: Node) => {
12+
export const getPlaceholderContent = (node: Node, parent?: Node | null) => {
1313
const content = node.type.spec.placeholder?.content || '';
1414

15-
return typeof content === 'function' ? content(node) : content;
15+
return typeof content === 'function' ? content(node, parent) : content;
1616
};
1717

1818
const getPlaceholderPluginKeys = (schema: Schema) => {
@@ -31,10 +31,10 @@ const getPlaceholderPluginKeys = (schema: Schema) => {
3131

3232
const b = cn('placeholder');
3333

34-
export const createPlaceholder = (node: Node, focus?: boolean) => {
34+
export const createPlaceholder = (node: Node, parent: Node | null, focus?: boolean) => {
3535
const placeholder = document.createElement('div');
3636
placeholder.classList.add(...b({focus}).split(' '));
37-
placeholder.textContent = getPlaceholderContent(node);
37+
placeholder.textContent = getPlaceholderContent(node, parent);
3838

3939
return placeholder;
4040
};
@@ -55,6 +55,7 @@ const addDecoration = (
5555
decorationsMap: Record<number, Decoration | PluginKey>,
5656
node: Node,
5757
pos: number,
58+
parent: Node | null,
5859
cursorPos: number | null | undefined,
5960
globalState: ApplyGlobalState,
6061
) => {
@@ -77,7 +78,7 @@ const addDecoration = (
7778

7879
decorationsMap[decorationPosition] = Decoration.widget(
7980
decorationPosition,
80-
createPlaceholder(node, focus),
81+
createPlaceholder(node, parent, focus),
8182
);
8283
};
8384

@@ -133,11 +134,11 @@ function applyState(state: EditorState): PlaceholderPluginState {
133134
});
134135

135136
// Рисуем плэйсхолдеры для всех нод у которых плэйсхолдер alwaysVisible
136-
const decorate = (node: Node, pos: number) => {
137+
const decorate = (node: Node, pos: number, parent: Node | null) => {
137138
const placeholderSpec = node.type.spec.placeholder;
138139

139140
if (placeholderSpec && placeholderSpec.alwaysVisible && placeholderNeeded(node)) {
140-
addDecoration(decorationsMap, node, pos, cursorPos, globalState);
141+
addDecoration(decorationsMap, node, pos, parent, cursorPos, globalState);
141142
}
142143
};
143144

@@ -156,7 +157,9 @@ function applyState(state: EditorState): PlaceholderPluginState {
156157
placeholderSpec &&
157158
!placeholderSpec.alwaysVisible
158159
) {
159-
addDecoration(decorationsMap, parentNode.node, parentNode.pos, cursorPos, globalState);
160+
const {node, pos, depth} = parentNode;
161+
const parent = depth > 0 ? state.selection.$from.node(depth - 1) : null;
162+
addDecoration(decorationsMap, node, pos, parent, cursorPos, globalState);
160163
}
161164

162165
const decorations = Object.values(decorationsMap).filter(
@@ -169,7 +172,7 @@ function applyState(state: EditorState): PlaceholderPluginState {
169172
declare module 'prosemirror-model' {
170173
interface NodeSpec {
171174
placeholder?: {
172-
content: string | ((node: Node) => string);
175+
content: string | ((node: Node, parent?: Node | null) => string);
173176
customPlugin?: PluginKey<DecorationSet>;
174177
alwaysVisible?: boolean;
175178
};

0 commit comments

Comments
 (0)