@modusoperandi/licit-vignette 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +4 -0
- package/.eslintrc.js +107 -0
- package/.prettierignore +6 -0
- package/.prettierrc +5 -0
- package/.stylelintignore +3 -0
- package/.stylelintrc.json +10 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/babel.config.json +53 -0
- package/dist/Constants.d.ts +6 -0
- package/dist/Constants.js +18 -0
- package/dist/CreateCommand.d.ts +7 -0
- package/dist/CreateCommand.js +30 -0
- package/dist/TableBackgroundColorCommand.d.ts +5 -0
- package/dist/TableBackgroundColorCommand.js +21 -0
- package/dist/TableBorderColorCommand.d.ts +5 -0
- package/dist/TableBorderColorCommand.js +21 -0
- package/dist/VignetteCommand.d.ts +12 -0
- package/dist/VignetteCommand.js +104 -0
- package/dist/VignetteMenuPlugin.d.ts +19 -0
- package/dist/VignetteMenuPlugin.js +120 -0
- package/dist/VignetteNodeSpec.d.ts +34 -0
- package/dist/VignetteNodeSpec.js +83 -0
- package/dist/VignettePlugin.d.ts +12 -0
- package/dist/VignettePlugin.js +49 -0
- package/dist/VignettePlugins.d.ts +4 -0
- package/dist/VignettePlugins.js +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/dist/index.test.js +48 -0
- package/dist/ui/TableColorCommand.d.ts +14 -0
- package/dist/ui/TableColorCommand.js +64 -0
- package/jest.config.ts +208 -0
- package/jest.setup.js +2 -0
- package/lint.sh +4 -0
- package/package.json +132 -0
- package/sonar-project.properties +11 -0
- package/src/Constants.ts +6 -0
- package/src/CreateCommand.ts +38 -0
- package/src/TableBackgroundColorCommand.ts +9 -0
- package/src/TableBorderColorCommand.ts +9 -0
- package/src/VignetteCommand.ts +103 -0
- package/src/VignetteMenuPlugin.ts +151 -0
- package/src/VignetteNodeSpec.ts +74 -0
- package/src/VignettePlugin.ts +53 -0
- package/src/VignettePlugins.ts +7 -0
- package/src/index.test.ts +59 -0
- package/src/index.ts +3 -0
- package/src/ui/TableColorCommand.tsx +79 -0
- package/tsconfig.json +38 -0
- package/webpack.config.js +89 -0
package/src/Constants.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {EditorState, Transaction} from 'prosemirror-state';
|
|
2
|
+
import {Transform} from 'prosemirror-transform';
|
|
3
|
+
import {EditorView} from 'prosemirror-view';
|
|
4
|
+
|
|
5
|
+
import {UICommand} from '@modusoperandi/licit-doc-attrs-step';
|
|
6
|
+
|
|
7
|
+
type ExecuteCall = (
|
|
8
|
+
state: EditorState,
|
|
9
|
+
dispatch?: (tr: Transform) => void,
|
|
10
|
+
view?: EditorView
|
|
11
|
+
) => boolean;
|
|
12
|
+
|
|
13
|
+
export default function createCommand(execute: ExecuteCall): UICommand {
|
|
14
|
+
class CustomCommand extends UICommand {
|
|
15
|
+
isEnabled = (state: EditorState): boolean => {
|
|
16
|
+
return this.execute(state);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
execute = (
|
|
20
|
+
state: EditorState,
|
|
21
|
+
dispatch?: (tr: Transform) => void,
|
|
22
|
+
view?: EditorView
|
|
23
|
+
): boolean => {
|
|
24
|
+
const tr = state.tr;
|
|
25
|
+
let endTr = tr;
|
|
26
|
+
execute(
|
|
27
|
+
state,
|
|
28
|
+
(nextTr) => {
|
|
29
|
+
endTr = nextTr as Transaction;
|
|
30
|
+
dispatch && dispatch(endTr);
|
|
31
|
+
},
|
|
32
|
+
view
|
|
33
|
+
);
|
|
34
|
+
return endTr.docChanged || tr !== endTr;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return new CustomCommand();
|
|
38
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {Fragment, Schema} from 'prosemirror-model';
|
|
2
|
+
import {EditorState, Transaction, TextSelection} from 'prosemirror-state';
|
|
3
|
+
import {EditorView} from 'prosemirror-view';
|
|
4
|
+
import {UICommand} from '@modusoperandi/licit-doc-attrs-step';
|
|
5
|
+
import {DEF_BORDER_COLOR, PARAGRAPH, TABLE, TABLE_CELL} from './Constants';
|
|
6
|
+
|
|
7
|
+
class VignetteCommand extends UICommand {
|
|
8
|
+
isEnabled = (state: EditorState, view?: EditorView): boolean => {
|
|
9
|
+
return this.__isEnabled(state, view);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
execute = (
|
|
13
|
+
state: EditorState,
|
|
14
|
+
dispatch?: (tr: Transaction) => void,
|
|
15
|
+
view?: EditorView
|
|
16
|
+
): boolean => {
|
|
17
|
+
if (dispatch) {
|
|
18
|
+
const {schema} = state;
|
|
19
|
+
let {tr} = state;
|
|
20
|
+
tr = this.insertTable(tr, schema, 1, 1);
|
|
21
|
+
tr = this.insertParagraph(state, tr);
|
|
22
|
+
dispatch(tr);
|
|
23
|
+
view && view.focus();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
__isEnabled = (_state: EditorState, _view?: EditorView): boolean => {
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
insertTable(
|
|
34
|
+
tr: Transaction,
|
|
35
|
+
schema: Schema,
|
|
36
|
+
rows: number,
|
|
37
|
+
cols: number
|
|
38
|
+
): Transaction {
|
|
39
|
+
if (!tr.selection || !tr.doc) {
|
|
40
|
+
return tr;
|
|
41
|
+
}
|
|
42
|
+
const {from, to} = tr.selection;
|
|
43
|
+
if (from !== to) {
|
|
44
|
+
return tr;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const {nodes} = schema;
|
|
48
|
+
const cell = nodes[TABLE_CELL];
|
|
49
|
+
const paragraph = nodes[PARAGRAPH];
|
|
50
|
+
const row = nodes['table_row'];
|
|
51
|
+
const table = nodes[TABLE];
|
|
52
|
+
if (!(cell && paragraph && row && table)) {
|
|
53
|
+
return tr;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const rowNodes = [];
|
|
57
|
+
for (let rr = 0; rr < rows; rr++) {
|
|
58
|
+
const cellNodes = [];
|
|
59
|
+
for (let cc = 0; cc < cols; cc++) {
|
|
60
|
+
// [FS] IRAD-950 2020-05-25
|
|
61
|
+
// Fix:Extra arrow key required for cell navigation using arrow right/Left
|
|
62
|
+
const cellNode = cell.create(
|
|
63
|
+
{
|
|
64
|
+
borderColor: DEF_BORDER_COLOR,
|
|
65
|
+
background: '#dce6f2',
|
|
66
|
+
vignette: true,
|
|
67
|
+
},
|
|
68
|
+
Fragment.fromArray([paragraph.create()])
|
|
69
|
+
);
|
|
70
|
+
cellNodes.push(cellNode);
|
|
71
|
+
}
|
|
72
|
+
const rowNode = row.create({}, Fragment.from(cellNodes));
|
|
73
|
+
rowNodes.push(rowNode);
|
|
74
|
+
}
|
|
75
|
+
const tableNode = table.create({vignette: true}, Fragment.from(rowNodes));
|
|
76
|
+
tr = tr.insert(from, Fragment.from(tableNode));
|
|
77
|
+
|
|
78
|
+
const selection = TextSelection.create(tr.doc, from + 5, from + 5);
|
|
79
|
+
|
|
80
|
+
tr = tr.setSelection(selection);
|
|
81
|
+
return tr;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// [FS] 2021-04-01
|
|
85
|
+
// Add empty line after table drop
|
|
86
|
+
// To make easier to enter a line after table
|
|
87
|
+
insertParagraph(state: EditorState, tr: Transaction) {
|
|
88
|
+
const paragraph = state.schema.nodes[PARAGRAPH];
|
|
89
|
+
const textNode = state.schema.text(' ');
|
|
90
|
+
const {from, to} = tr.selection;
|
|
91
|
+
if (from !== to) {
|
|
92
|
+
return tr;
|
|
93
|
+
}
|
|
94
|
+
const paragraphNode = paragraph.create({}, textNode, null);
|
|
95
|
+
tr = tr.insert(
|
|
96
|
+
from + tr.selection.$head.node(1).nodeSize - 4,
|
|
97
|
+
Fragment.from(paragraphNode)
|
|
98
|
+
);
|
|
99
|
+
return tr;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default VignetteCommand;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {EditorState, Plugin, PluginKey} from 'prosemirror-state';
|
|
2
|
+
import {EditorView} from 'prosemirror-view';
|
|
3
|
+
import {Node} from 'prosemirror-model';
|
|
4
|
+
|
|
5
|
+
import {UICommand} from '@modusoperandi/licit-doc-attrs-step';
|
|
6
|
+
import TableBackgroundColorCommand from './TableBackgroundColorCommand';
|
|
7
|
+
import TableBorderColorCommand from './TableBorderColorCommand';
|
|
8
|
+
import createCommand from './CreateCommand';
|
|
9
|
+
import {CellSelection, deleteTable, TableView} from 'prosemirror-tables';
|
|
10
|
+
import {TABLE} from './Constants';
|
|
11
|
+
|
|
12
|
+
export const TABLE_BACKGROUND_COLOR = new TableBackgroundColorCommand();
|
|
13
|
+
export const TABLE_BORDER_COLOR = new TableBorderColorCommand();
|
|
14
|
+
export const TABLE_DELETE_TABLE = createCommand(deleteTable);
|
|
15
|
+
|
|
16
|
+
export const VIGNETTE_COMMANDS_GROUP = [
|
|
17
|
+
{
|
|
18
|
+
'Fill Color...': TABLE_BACKGROUND_COLOR,
|
|
19
|
+
'Border Color....': TABLE_BORDER_COLOR,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
'Delete Vignette': TABLE_DELETE_TABLE,
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
class VignetteView {
|
|
27
|
+
constructor(editorView: EditorView) {
|
|
28
|
+
this.setCustomMenu(editorView);
|
|
29
|
+
this.setCustomTableNodeViewUpdate(editorView);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setCustomMenu(editorView: EditorView) {
|
|
33
|
+
editorView['pluginViews'].forEach((pluginView) => {
|
|
34
|
+
if (
|
|
35
|
+
// 'TableCellTooltipView' has property _cellElement
|
|
36
|
+
Object.prototype.hasOwnProperty.call(pluginView, '_cellElement')
|
|
37
|
+
) {
|
|
38
|
+
pluginView['getMenu'] = this.getMenu.bind(this);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setCustomTableNodeViewUpdate(editorView: EditorView) {
|
|
44
|
+
const tableNodeView = editorView['nodeViews']['table'];
|
|
45
|
+
const tableNodeViewEx = this.tableNodeViewEx.bind(this, tableNodeView);
|
|
46
|
+
editorView['nodeViews'][TABLE] = tableNodeViewEx;
|
|
47
|
+
const index = editorView.state.plugins.findIndex((plugin) => {
|
|
48
|
+
let found = false;
|
|
49
|
+
if (plugin.spec.key) {
|
|
50
|
+
found = plugin.spec.key['key'].includes('tableColumnResizing$');
|
|
51
|
+
}
|
|
52
|
+
return found;
|
|
53
|
+
});
|
|
54
|
+
if (-1 != index) {
|
|
55
|
+
editorView.state.plugins[index].spec.props.nodeViews[TABLE] =
|
|
56
|
+
tableNodeViewEx;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
tableNodeViewEx(
|
|
61
|
+
tableNodeView: (node: Node, view: EditorView) => TableView,
|
|
62
|
+
node: Node,
|
|
63
|
+
view: EditorView
|
|
64
|
+
): TableView {
|
|
65
|
+
const base = tableNodeView && tableNodeView(node, view);
|
|
66
|
+
if (base && base.update && node.attrs.vignette) {
|
|
67
|
+
base.update = this.updateEx.bind(base, base.update, this);
|
|
68
|
+
this.updateBorder(base);
|
|
69
|
+
}
|
|
70
|
+
return base;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
updateEx(
|
|
74
|
+
update: (node: Node) => boolean,
|
|
75
|
+
self: VignetteView,
|
|
76
|
+
node: Node
|
|
77
|
+
): boolean {
|
|
78
|
+
const result = update.call(this, node);
|
|
79
|
+
if (result) {
|
|
80
|
+
self.updateBorder(this as unknown as TableView);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
updateBorder(tableView: TableView) {
|
|
86
|
+
tableView.table.style.border = 'none';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static isVignette(state: EditorState, actionNode: Node) {
|
|
90
|
+
let vignette = false;
|
|
91
|
+
if (state.selection instanceof CellSelection) {
|
|
92
|
+
if (state.selection.$anchorCell.node(-1).attrs.vignette) {
|
|
93
|
+
vignette = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (actionNode && actionNode.attrs.vignette) {
|
|
97
|
+
vignette = true;
|
|
98
|
+
}
|
|
99
|
+
if (state.selection.$anchor.node(1).attrs.vignette) {
|
|
100
|
+
vignette = true;
|
|
101
|
+
}
|
|
102
|
+
return vignette;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getMenu(
|
|
106
|
+
state: EditorState,
|
|
107
|
+
actionNode: Node,
|
|
108
|
+
cmdGrps: Array<{[key: string]: UICommand}>
|
|
109
|
+
): Array<{[key: string]: UICommand}> {
|
|
110
|
+
let vignette = VignetteView.isVignette(state, actionNode);
|
|
111
|
+
|
|
112
|
+
cmdGrps.forEach((cmdGrp) => {
|
|
113
|
+
Object.entries(cmdGrp).forEach((entry) => {
|
|
114
|
+
entry[1].isEnabled = this.isEnabledEx.bind(
|
|
115
|
+
entry[1],
|
|
116
|
+
entry[1].isEnabled
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
return vignette ? VIGNETTE_COMMANDS_GROUP : cmdGrps;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
isEnabledEx(
|
|
124
|
+
isEnabled: (state: EditorState, view?: EditorView) => boolean,
|
|
125
|
+
state: EditorState,
|
|
126
|
+
view?: EditorView
|
|
127
|
+
): boolean {
|
|
128
|
+
return VignetteView.isVignette(state, null)
|
|
129
|
+
? false
|
|
130
|
+
: isEnabled.call(this as UICommand, state, view);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
destroy = (): void => {
|
|
134
|
+
// do nothing.
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const SPEC = {
|
|
139
|
+
key: new PluginKey('VignetteMenuPlugin'),
|
|
140
|
+
view(editorView: EditorView) {
|
|
141
|
+
return new VignetteView(editorView);
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
class VignetteMenuPlugin extends Plugin {
|
|
146
|
+
constructor() {
|
|
147
|
+
super(SPEC);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default VignetteMenuPlugin;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {Node, NodeSpec} from 'prosemirror-model';
|
|
2
|
+
import {TABLE, VIGNETTE} from './Constants';
|
|
3
|
+
|
|
4
|
+
// Override the default table node spec to support custom attributes.
|
|
5
|
+
export const VignetteTableNodeSpec = (nodespec: NodeSpec) =>
|
|
6
|
+
Object.assign({}, nodespec, {
|
|
7
|
+
attrs: {
|
|
8
|
+
marginLeft: {default: null},
|
|
9
|
+
vignette: {default: false},
|
|
10
|
+
},
|
|
11
|
+
parseDOM: [
|
|
12
|
+
{
|
|
13
|
+
tag: TABLE,
|
|
14
|
+
getAttrs(dom: HTMLElement): unknown | null {
|
|
15
|
+
const {marginLeft} = dom.style;
|
|
16
|
+
const vignette = dom.getAttribute(VIGNETTE) === 'true' || false;
|
|
17
|
+
if (marginLeft && /\d+px/.test(marginLeft)) {
|
|
18
|
+
return {marginLeft: parseFloat(marginLeft), vignette};
|
|
19
|
+
}
|
|
20
|
+
return {vignette};
|
|
21
|
+
},
|
|
22
|
+
style: 'border',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
toDOM(node: Node): Array<unknown> {
|
|
26
|
+
// Normally, the DOM structure of the table node is rendered by
|
|
27
|
+
// `TableNodeView`. This method is only called when user selects a
|
|
28
|
+
// table node and copies it, which triggers the "serialize to HTML" flow
|
|
29
|
+
// that calles this method.
|
|
30
|
+
const {marginLeft, vignette} = node.attrs;
|
|
31
|
+
const domAttrs = {vignette};
|
|
32
|
+
let style = 'border: none';
|
|
33
|
+
if (marginLeft) {
|
|
34
|
+
style += `margin-left: ${marginLeft}px`;
|
|
35
|
+
}
|
|
36
|
+
domAttrs['style'] = style;
|
|
37
|
+
return [TABLE, domAttrs, 0];
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const VignetteTableCellNodeSpec = (nodespec: NodeSpec) =>
|
|
42
|
+
Object.assign({}, nodespec, {
|
|
43
|
+
attrs: Object.assign({}, nodespec.attrs, {
|
|
44
|
+
vignette: {default: false},
|
|
45
|
+
}),
|
|
46
|
+
parseDOM: [
|
|
47
|
+
{
|
|
48
|
+
tag: 'td',
|
|
49
|
+
getAttrs: (dom: HTMLElement) => {
|
|
50
|
+
return Object.assign({}, nodespec.parseDOM[0].getAttrs(dom), {
|
|
51
|
+
vignette: dom.getAttribute(VIGNETTE) || false,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
toDOM(node: Node): Array<unknown> {
|
|
57
|
+
const base = nodespec.toDOM(node);
|
|
58
|
+
if (
|
|
59
|
+
node.attrs.vignette &&
|
|
60
|
+
Array.isArray(base) &&
|
|
61
|
+
1 < base.length &&
|
|
62
|
+
base[1].style
|
|
63
|
+
) {
|
|
64
|
+
base[1].style +=
|
|
65
|
+
'border-radius: 10px; border-style: solid; border-width: thin';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
base[1].vignette = node.attrs.vignette;
|
|
69
|
+
|
|
70
|
+
return base as unknown as Array<unknown>;
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export default VignetteTableNodeSpec;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Plugin to handle Citation.
|
|
2
|
+
import {Plugin, PluginKey} from 'prosemirror-state';
|
|
3
|
+
import {EditorView} from 'prosemirror-view';
|
|
4
|
+
import {Schema} from 'prosemirror-model';
|
|
5
|
+
import VignetteCommand from './VignetteCommand';
|
|
6
|
+
import {
|
|
7
|
+
VignetteTableCellNodeSpec,
|
|
8
|
+
VignetteTableNodeSpec,
|
|
9
|
+
} from './VignetteNodeSpec';
|
|
10
|
+
import {TABLE, TABLE_CELL} from './Constants';
|
|
11
|
+
|
|
12
|
+
export class VignettePlugin extends Plugin {
|
|
13
|
+
_view: EditorView = null;
|
|
14
|
+
constructor() {
|
|
15
|
+
super({
|
|
16
|
+
key: new PluginKey('VignettePlugin'),
|
|
17
|
+
state: {
|
|
18
|
+
init(_config, _state) {
|
|
19
|
+
// do nothing
|
|
20
|
+
},
|
|
21
|
+
apply(_tr, _set) {
|
|
22
|
+
//do nothing
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
props: {
|
|
26
|
+
nodeViews: {},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getEffectiveSchema(schema: Schema): Schema {
|
|
32
|
+
let nodes = schema.spec.nodes.update(
|
|
33
|
+
TABLE,
|
|
34
|
+
VignetteTableNodeSpec(schema.spec.nodes.get(TABLE))
|
|
35
|
+
);
|
|
36
|
+
nodes = nodes.update(
|
|
37
|
+
TABLE_CELL,
|
|
38
|
+
VignetteTableCellNodeSpec(schema.spec.nodes.get(TABLE_CELL))
|
|
39
|
+
);
|
|
40
|
+
const marks = schema.spec.marks;
|
|
41
|
+
|
|
42
|
+
return new Schema({
|
|
43
|
+
nodes: nodes,
|
|
44
|
+
marks: marks,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
initButtonCommands() {
|
|
49
|
+
return {
|
|
50
|
+
'[crop] Insert Vignette': new VignetteCommand(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {createEditor, doc, p, table, tr, td} from 'jest-prosemirror';
|
|
2
|
+
import {TABLE} from './Constants';
|
|
3
|
+
import VignetteCommand from './VignetteCommand';
|
|
4
|
+
import {VignettePlugin} from './VignettePlugin';
|
|
5
|
+
import VignettePlugins from './VignettePlugins';
|
|
6
|
+
import createCommand from './CreateCommand';
|
|
7
|
+
import {deleteTable} from 'prosemirror-tables';
|
|
8
|
+
|
|
9
|
+
export {};
|
|
10
|
+
|
|
11
|
+
describe('VignettePlugin', () => {
|
|
12
|
+
it('should handle VignetteCommand', () => {
|
|
13
|
+
createEditor(doc(p('<cursor>')), {plugins: [...VignettePlugins]})
|
|
14
|
+
.command((state, dispatch) => {
|
|
15
|
+
if (dispatch) {
|
|
16
|
+
new VignetteCommand().execute(state, dispatch);
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
})
|
|
20
|
+
.callback((content) => {
|
|
21
|
+
expect(content.state.doc).toEqualProsemirrorNode(
|
|
22
|
+
doc(
|
|
23
|
+
p(),
|
|
24
|
+
table(
|
|
25
|
+
tr(
|
|
26
|
+
td(
|
|
27
|
+
{
|
|
28
|
+
colspan: 1,
|
|
29
|
+
rowspan: 1,
|
|
30
|
+
colwidth: null,
|
|
31
|
+
pretty: true,
|
|
32
|
+
ugly: false,
|
|
33
|
+
},
|
|
34
|
+
p()
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
),
|
|
38
|
+
p(' ')
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle getEffectiveSchema', () => {
|
|
45
|
+
const schema = createEditor(doc(p('<cursor>'))).schema;
|
|
46
|
+
expect(schema.spec.nodes.get(TABLE)?.attrs?.vignette).toBeFalsy();
|
|
47
|
+
const newSchema = new VignettePlugin().getEffectiveSchema(schema);
|
|
48
|
+
expect(newSchema.spec.nodes.get(TABLE)?.attrs?.vignette).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should handle createCommand', () => {
|
|
52
|
+
createEditor(doc(p('<cursor>')), {plugins: [...VignettePlugins]}).command(
|
|
53
|
+
(state, _dispatch) => {
|
|
54
|
+
createCommand(deleteTable).isEnabled(state);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import nullthrows from 'nullthrows';
|
|
4
|
+
import {EditorState} from 'prosemirror-state';
|
|
5
|
+
import {setCellAttr} from 'prosemirror-tables';
|
|
6
|
+
import {Transform} from 'prosemirror-transform';
|
|
7
|
+
import {EditorView} from 'prosemirror-view';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ColorEditor,
|
|
11
|
+
atAnchorRight,
|
|
12
|
+
createPopUp,
|
|
13
|
+
} from '@modusoperandi/licit-ui-commands';
|
|
14
|
+
import {UICommand} from '@modusoperandi/licit-doc-attrs-step';
|
|
15
|
+
|
|
16
|
+
class TableColorCommand extends UICommand {
|
|
17
|
+
_popUp = null;
|
|
18
|
+
|
|
19
|
+
getAttrName = (): string => {
|
|
20
|
+
return '';
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
isEnabled = (_state: EditorState): boolean => {
|
|
24
|
+
return true;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
shouldRespondToUIEvent = (e: React.SyntheticEvent | MouseEvent): boolean => {
|
|
28
|
+
return e.type === UICommand.EventType.MOUSEENTER;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
waitForUserInput = (
|
|
32
|
+
_state: EditorState,
|
|
33
|
+
_dispatch?: (tr: Transform) => void,
|
|
34
|
+
_view?: EditorView,
|
|
35
|
+
event?: React.SyntheticEvent
|
|
36
|
+
): Promise<unknown> => {
|
|
37
|
+
if (this._popUp) {
|
|
38
|
+
return Promise.resolve(undefined);
|
|
39
|
+
}
|
|
40
|
+
const target = nullthrows(event).currentTarget;
|
|
41
|
+
if (!(target instanceof HTMLElement)) {
|
|
42
|
+
return Promise.resolve(undefined);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const anchor = event ? event.currentTarget : null;
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
this._popUp = createPopUp(ColorEditor, null, {
|
|
48
|
+
anchor,
|
|
49
|
+
position: atAnchorRight,
|
|
50
|
+
onClose: (val) => {
|
|
51
|
+
if (this._popUp) {
|
|
52
|
+
this._popUp = null;
|
|
53
|
+
resolve(val);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
executeWithUserInput = (
|
|
61
|
+
state: EditorState,
|
|
62
|
+
dispatch?: (tr: Transform) => void,
|
|
63
|
+
view?: EditorView,
|
|
64
|
+
color?: string
|
|
65
|
+
): boolean => {
|
|
66
|
+
if (dispatch && color !== undefined) {
|
|
67
|
+
const cmd = setCellAttr(this.getAttrName(), color);
|
|
68
|
+
cmd(state, dispatch, view);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
cancel(): void {
|
|
75
|
+
this._popUp && this._popUp.close(undefined);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default TableColorCommand;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"jsx": "react",
|
|
4
|
+
"target": "es6",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"lib": [
|
|
8
|
+
"es2017",
|
|
9
|
+
"dom",
|
|
10
|
+
"dom.Iterable"
|
|
11
|
+
],
|
|
12
|
+
"outDir": "dist",
|
|
13
|
+
"pretty": false,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"types": [
|
|
17
|
+
"jest",
|
|
18
|
+
"node",
|
|
19
|
+
"jest-prosemirror"
|
|
20
|
+
],
|
|
21
|
+
// Ensure that .d.ts files are created by tsc, but not .js files
|
|
22
|
+
"declaration": true,
|
|
23
|
+
"emitDeclarationOnly": true,
|
|
24
|
+
// Ensure that Babel can safely transpile files in the TypeScript project
|
|
25
|
+
"isolatedModules": true
|
|
26
|
+
},
|
|
27
|
+
"typeAcquisition": {
|
|
28
|
+
"enable": true
|
|
29
|
+
},
|
|
30
|
+
"include": [
|
|
31
|
+
"src/**/*.ts",
|
|
32
|
+
"src/**/*.tsx"
|
|
33
|
+
],
|
|
34
|
+
"exclude": [
|
|
35
|
+
"node_modules",
|
|
36
|
+
"**/*.test.ts"
|
|
37
|
+
]
|
|
38
|
+
}
|