Skip to content

Commit 14bf513

Browse files
authored
feat(YfmCut): support diplodoc/cut-extension v1.x.x (#869)
1 parent d03f6c9 commit 14bf513

File tree

12 files changed

+109
-71
lines changed

12 files changed

+109
-71
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@
318318
}
319319
},
320320
"peerDependencies": {
321-
"@diplodoc/cut-extension": "^0.5.0 || ^0.6.1 || ^0.7.1",
321+
"@diplodoc/cut-extension": "^0.5.0 || ^0.6.1 || ^0.7.1 || ^1.0.0",
322322
"@diplodoc/file-extension": "^0.2.1",
323323
"@diplodoc/folding-headings-extension": "^0.1.0",
324324
"@diplodoc/html-extension": "^2.3.2",

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {nodeTypeFactory} from '../../../../utils/schema';
1+
import {nodeTypeFactory} from 'src/utils/schema';
22

33
export enum CutNode {
44
Cut = 'yfm_cut',
@@ -14,3 +14,9 @@ export enum CutAttr {
1414
export const cutType = nodeTypeFactory(CutNode.Cut);
1515
export const cutTitleType = nodeTypeFactory(CutNode.CutTitle);
1616
export const cutContentType = nodeTypeFactory(CutNode.CutContent);
17+
18+
export const YfmCutClassName = {
19+
Cut: 'yfm-cut',
20+
Title: 'yfm-cut-title',
21+
Content: 'yfm-cut-content',
22+
} as const;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {transform as yfmCut} from '@diplodoc/cut-extension';
22

3-
import type {ExtensionAuto, ExtensionNodeSpec} from '../../../../core';
3+
import type {ExtensionAuto, ExtensionNodeSpec} from '#core';
44

55
import {CutNode} from './const';
66
import {parserTokens} from './parser';
77
import {type YfmCutSchemaOptions, getSchemaSpecs} from './schema';
88
import {getSerializerTokens} from './serializer';
99

10-
export {CutAttr, CutNode, cutType, cutTitleType, cutContentType} from './const';
10+
export {CutAttr, CutNode, cutType, cutTitleType, cutContentType, YfmCutClassName} from './const';
1111

1212
declare global {
1313
namespace MarkdownEditor {

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import type {NodeSpec} from 'prosemirror-model';
1+
import type {NodeSpec} from '#pm/model';
2+
import type {PlaceholderOptions} from 'src/utils/placeholder';
23

3-
import type {PlaceholderOptions} from '../../../../utils/placeholder';
4-
5-
import {CutAttr, CutNode} from './const';
4+
import {CutAttr, CutNode, YfmCutClassName} from './const';
65

76
export type YfmCutSchemaOptions = {
87
/**
@@ -25,12 +24,12 @@ export const getSchemaSpecs = (
2524
placeholder?: PlaceholderOptions,
2625
): Record<CutNode, NodeSpec> => ({
2726
[CutNode.Cut]: {
28-
attrs: {class: {default: 'yfm-cut'}, [CutAttr.Markup]: {default: null}},
27+
attrs: {class: {default: YfmCutClassName.Cut}, [CutAttr.Markup]: {default: null}},
2928
content: `${CutNode.CutTitle} ${CutNode.CutContent}`,
3029
group: 'block yfm-cut',
3130
parseDOM: [
3231
{
33-
tag: '.yfm-cut',
32+
tag: `.${YfmCutClassName.Cut}`,
3433
getAttrs: (node) => ({[CutAttr.Markup]: node.getAttribute(CutAttr.Markup)}),
3534
},
3635
],
@@ -44,10 +43,10 @@ export const getSchemaSpecs = (
4443
},
4544

4645
[CutNode.CutTitle]: {
47-
attrs: {class: {default: 'yfm-cut-title'}},
46+
attrs: {class: {default: YfmCutClassName.Title}},
4847
content: 'inline*',
4948
group: 'block yfm-cut',
50-
parseDOM: [{tag: '.yfm-cut-title'}],
49+
parseDOM: [{tag: `.${YfmCutClassName.Title}`}],
5150
toDOM(node) {
5251
return ['div', node.attrs, 0];
5352
},
@@ -65,10 +64,10 @@ export const getSchemaSpecs = (
6564
},
6665

6766
[CutNode.CutContent]: {
68-
attrs: {class: {default: 'yfm-cut-content'}},
67+
attrs: {class: {default: YfmCutClassName.Content}},
6968
content: '(block | paragraph)+',
7069
group: 'block yfm-cut',
71-
parseDOM: [{tag: '.yfm-cut-content'}],
70+
parseDOM: [{tag: `.${YfmCutClassName.Content}`}],
7271
toDOM(node) {
7372
return ['div', node.attrs, 0];
7473
},

src/extensions/yfm/YfmCut/actions/toYfmCut.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import type {Fragment, Node, Schema} from 'prosemirror-model';
2-
import {type Command, TextSelection} from 'prosemirror-state';
3-
// @ts-ignore // TODO: fix cjs build
4-
import {findParentNodeClosestToPos} from 'prosemirror-utils';
1+
import type {ActionSpec} from '#core';
2+
import type {Fragment, Node, Schema} from '#pm/model';
3+
import {type Command, TextSelection} from '#pm/state';
4+
import {findParentNodeClosestToPos} from '#pm/utils';
55

6-
import type {ActionSpec} from '../../../../core';
7-
import {cutContentType, cutTitleType, cutType} from '../const';
6+
import {YfmCutClassName, cutContentType, cutTitleType, cutType} from '../const';
87

98
const createYfmCutNode = (schema: Schema) => (content?: Node | Node[] | Fragment) => {
10-
return cutType(schema).create({class: 'yfm-cut open'}, [
9+
const className = `${YfmCutClassName.Cut} ${YfmCutClassName.Open}` as const;
10+
return cutType(schema).create({class: className}, [
1111
cutTitleType(schema).create(null),
1212
cutContentType(schema).create(null, content),
1313
]);

src/extensions/yfm/YfmCut/const.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
export {CutNode, cutType, cutTitleType, cutContentType} from './YfmCutSpecs';
1+
import {YfmCutClassName as YfmCutClassNameSpecs} from './YfmCutSpecs/const';
2+
3+
export {CutNode, cutType, cutTitleType, cutContentType} from './YfmCutSpecs/const';
4+
5+
export const YfmCutClassName = {
6+
...YfmCutClassNameSpecs,
7+
TitleInner: 'g-md-yfm-cut-title-inner',
8+
Open: 'yfm-cut-open',
9+
Active: 'yfm-cut-active',
10+
} as const;

src/extensions/yfm/YfmCut/index.scss

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,4 @@
1111
outline: 0;
1212
}
1313
}
14-
.yfm-cut.open > .yfm-cut-title:before {
15-
transform: translateY(-50%);
16-
}
1714
}
Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1-
.yfm-cut-title .g-md-yfm-cut-title-inner {
2-
cursor: text;
3-
}
1+
.ProseMirror.yfm {
2+
.yfm-cut-title > .g-md-yfm-cut-title-inner {
3+
cursor: text;
4+
}
45

5-
// FIXME: Restore the cut-extension mapping after the fix:
6-
// when using <details> and <summary> tags, the click does
7-
// not work correctly on the placeholder
6+
// FIXME: Restore the cut-extension mapping after the fix:
7+
// when using <details> and <summary> tags, the click does
8+
// not work correctly on the placeholder
89

9-
.yfm-cut-content {
10-
display: none;
11-
overflow: hidden;
10+
.yfm-cut-content {
11+
display: none;
12+
overflow: hidden;
1213

13-
transition: height 0.3s ease-in-out;
14-
}
14+
transition: height 0.3s ease-in-out;
15+
}
16+
17+
.yfm-cut.yfm-cut-open > {
18+
.yfm-cut-title:before {
19+
transform: translateY(-50%);
20+
}
1521

16-
.open > .yfm-cut-content {
17-
display: revert;
22+
.yfm-cut-content {
23+
display: revert;
24+
}
25+
}
1826
}
Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import type {Node} from 'prosemirror-model';
2-
import type {NodeView} from 'prosemirror-view';
1+
import type {Node} from '#pm/model';
2+
import type {NodeView} from '#pm/view';
3+
4+
import {YfmCutClassName} from '../const';
35

46
import './yfm-cut-title.scss';
57

@@ -13,20 +15,40 @@ export class YfmCutTitleNodeView implements NodeView {
1315
this.node = node;
1416

1517
this.dom = document.createElement('div');
16-
this.dom.classList.add('yfm-cut-title');
17-
this.dom.replaceChildren((this.contentDOM = document.createElement('div')));
18-
this.contentDOM.classList.add('g-md-yfm-cut-title-inner');
19-
this.contentDOM.addEventListener('click', (e) => {
20-
// ignore clicking on the title content
21-
// you can open/close yfm-cut by clicking on the arrow icon
22-
e.stopPropagation();
23-
e.preventDefault();
24-
});
18+
this.dom.classList.add(YfmCutClassName.Title);
19+
this.dom.addEventListener('click', this._onTitleClick);
20+
21+
this.contentDOM = this.dom.appendChild(document.createElement('div'));
22+
this.contentDOM.classList.add(YfmCutClassName.TitleInner);
23+
this.contentDOM.addEventListener('click', this._onTitleInnerClick);
2524
}
2625

2726
update(node: Node): boolean {
2827
if (this.node.type !== node.type) return false;
2928
this.node = node;
3029
return true;
3130
}
31+
32+
destroy() {
33+
this.dom.removeEventListener('click', this._onTitleClick);
34+
this.contentDOM.removeEventListener('click', this._onTitleInnerClick);
35+
}
36+
37+
private _onTitleClick = (e: MouseEvent) => {
38+
const {currentTarget} = e;
39+
if (currentTarget instanceof HTMLElement) {
40+
const parent = currentTarget.parentElement;
41+
if (parent?.classList.contains(YfmCutClassName.Cut)) {
42+
// TODO: toggle open classname via prosemirror decoration
43+
parent.classList.toggle(YfmCutClassName.Open);
44+
}
45+
}
46+
};
47+
48+
private _onTitleInnerClick = (e: MouseEvent) => {
49+
// ignore clicking on the title content
50+
// you can open/close yfm-cut by clicking on the arrow icon
51+
e.stopPropagation();
52+
e.preventDefault();
53+
};
3254
}

0 commit comments

Comments
 (0)