@atlaskit/editor-plugin-block-type 1.0.0
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/.eslintrc.js +14 -0
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +13 -0
- package/README.md +32 -0
- package/consts/package.json +15 -0
- package/dist/cjs/consts.js +66 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/messages.js +19 -0
- package/dist/cjs/plugin/block-types.js +106 -0
- package/dist/cjs/plugin/commands/block-type.js +183 -0
- package/dist/cjs/plugin/commands/delete-and-move-cursor.js +56 -0
- package/dist/cjs/plugin/commands/delete-block-content.js +45 -0
- package/dist/cjs/plugin/commands/index.js +69 -0
- package/dist/cjs/plugin/consts.js +15 -0
- package/dist/cjs/plugin/index.js +217 -0
- package/dist/cjs/plugin/messages.js +160 -0
- package/dist/cjs/plugin/pm-plugins/input-rule.js +104 -0
- package/dist/cjs/plugin/pm-plugins/keymap.js +34 -0
- package/dist/cjs/plugin/pm-plugins/main.js +151 -0
- package/dist/cjs/plugin/styles.js +15 -0
- package/dist/cjs/plugin/types.js +5 -0
- package/dist/cjs/plugin/ui/ToolbarBlockType/blocktype-button.js +60 -0
- package/dist/cjs/plugin/ui/ToolbarBlockType/index.js +208 -0
- package/dist/cjs/plugin/ui/ToolbarBlockType/styled.js +34 -0
- package/dist/cjs/plugin/ui/ToolbarBlockType/toolbar-messages.js +15 -0
- package/dist/cjs/plugin/utils.js +87 -0
- package/dist/cjs/styles.js +12 -0
- package/dist/es2019/consts.js +1 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/messages.js +2 -0
- package/dist/es2019/plugin/block-types.js +84 -0
- package/dist/es2019/plugin/commands/block-type.js +170 -0
- package/dist/es2019/plugin/commands/delete-and-move-cursor.js +55 -0
- package/dist/es2019/plugin/commands/delete-block-content.js +42 -0
- package/dist/es2019/plugin/commands/index.js +8 -0
- package/dist/es2019/plugin/consts.js +8 -0
- package/dist/es2019/plugin/index.js +204 -0
- package/dist/es2019/plugin/messages.js +153 -0
- package/dist/es2019/plugin/pm-plugins/input-rule.js +93 -0
- package/dist/es2019/plugin/pm-plugins/keymap.js +25 -0
- package/dist/es2019/plugin/pm-plugins/main.js +137 -0
- package/dist/es2019/plugin/styles.js +8 -0
- package/dist/es2019/plugin/types.js +1 -0
- package/dist/es2019/plugin/ui/ToolbarBlockType/blocktype-button.js +50 -0
- package/dist/es2019/plugin/ui/ToolbarBlockType/index.js +185 -0
- package/dist/es2019/plugin/ui/ToolbarBlockType/styled.js +49 -0
- package/dist/es2019/plugin/ui/ToolbarBlockType/toolbar-messages.js +8 -0
- package/dist/es2019/plugin/utils.js +76 -0
- package/dist/es2019/styles.js +1 -0
- package/dist/esm/consts.js +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/messages.js +2 -0
- package/dist/esm/plugin/block-types.js +84 -0
- package/dist/esm/plugin/commands/block-type.js +169 -0
- package/dist/esm/plugin/commands/delete-and-move-cursor.js +50 -0
- package/dist/esm/plugin/commands/delete-block-content.js +39 -0
- package/dist/esm/plugin/commands/index.js +8 -0
- package/dist/esm/plugin/consts.js +8 -0
- package/dist/esm/plugin/index.js +205 -0
- package/dist/esm/plugin/messages.js +153 -0
- package/dist/esm/plugin/pm-plugins/input-rule.js +96 -0
- package/dist/esm/plugin/pm-plugins/keymap.js +25 -0
- package/dist/esm/plugin/pm-plugins/main.js +142 -0
- package/dist/esm/plugin/styles.js +7 -0
- package/dist/esm/plugin/types.js +1 -0
- package/dist/esm/plugin/ui/ToolbarBlockType/blocktype-button.js +50 -0
- package/dist/esm/plugin/ui/ToolbarBlockType/index.js +201 -0
- package/dist/esm/plugin/ui/ToolbarBlockType/styled.js +20 -0
- package/dist/esm/plugin/ui/ToolbarBlockType/toolbar-messages.js +8 -0
- package/dist/esm/plugin/utils.js +77 -0
- package/dist/esm/styles.js +1 -0
- package/dist/types/consts.d.ts +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/messages.d.ts +2 -0
- package/dist/types/plugin/block-types.d.ts +19 -0
- package/dist/types/plugin/commands/block-type.d.ts +18 -0
- package/dist/types/plugin/commands/delete-and-move-cursor.d.ts +12 -0
- package/dist/types/plugin/commands/delete-block-content.d.ts +10 -0
- package/dist/types/plugin/commands/index.d.ts +9 -0
- package/dist/types/plugin/consts.d.ts +1 -0
- package/dist/types/plugin/index.d.ts +18 -0
- package/dist/types/plugin/messages.d.ts +152 -0
- package/dist/types/plugin/pm-plugins/input-rule.d.ts +6 -0
- package/dist/types/plugin/pm-plugins/keymap.d.ts +5 -0
- package/dist/types/plugin/pm-plugins/main.d.ts +17 -0
- package/dist/types/plugin/styles.d.ts +2 -0
- package/dist/types/plugin/types.d.ts +22 -0
- package/dist/types/plugin/ui/ToolbarBlockType/blocktype-button.d.ts +22 -0
- package/dist/types/plugin/ui/ToolbarBlockType/index.d.ts +29 -0
- package/dist/types/plugin/ui/ToolbarBlockType/styled.d.ts +8 -0
- package/dist/types/plugin/ui/ToolbarBlockType/toolbar-messages.d.ts +7 -0
- package/dist/types/plugin/utils.d.ts +16 -0
- package/dist/types/styles.d.ts +1 -0
- package/dist/types-ts4.5/consts.d.ts +1 -0
- package/dist/types-ts4.5/index.d.ts +6 -0
- package/dist/types-ts4.5/messages.d.ts +2 -0
- package/dist/types-ts4.5/plugin/block-types.d.ts +19 -0
- package/dist/types-ts4.5/plugin/commands/block-type.d.ts +18 -0
- package/dist/types-ts4.5/plugin/commands/delete-and-move-cursor.d.ts +12 -0
- package/dist/types-ts4.5/plugin/commands/delete-block-content.d.ts +10 -0
- package/dist/types-ts4.5/plugin/commands/index.d.ts +9 -0
- package/dist/types-ts4.5/plugin/consts.d.ts +1 -0
- package/dist/types-ts4.5/plugin/index.d.ts +20 -0
- package/dist/types-ts4.5/plugin/messages.d.ts +152 -0
- package/dist/types-ts4.5/plugin/pm-plugins/input-rule.d.ts +6 -0
- package/dist/types-ts4.5/plugin/pm-plugins/keymap.d.ts +5 -0
- package/dist/types-ts4.5/plugin/pm-plugins/main.d.ts +17 -0
- package/dist/types-ts4.5/plugin/styles.d.ts +2 -0
- package/dist/types-ts4.5/plugin/types.d.ts +22 -0
- package/dist/types-ts4.5/plugin/ui/ToolbarBlockType/blocktype-button.d.ts +22 -0
- package/dist/types-ts4.5/plugin/ui/ToolbarBlockType/index.d.ts +29 -0
- package/dist/types-ts4.5/plugin/ui/ToolbarBlockType/styled.d.ts +8 -0
- package/dist/types-ts4.5/plugin/ui/ToolbarBlockType/toolbar-messages.d.ts +7 -0
- package/dist/types-ts4.5/plugin/utils.d.ts +16 -0
- package/dist/types-ts4.5/styles.d.ts +1 -0
- package/messages/package.json +15 -0
- package/package.json +105 -0
- package/report.api.md +108 -0
- package/styles/package.json +15 -0
- package/tmp/api-report-tmp.d.ts +75 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { setHeading } from '@atlaskit/editor-common/commands';
|
|
3
|
+
import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
|
|
4
|
+
import { filterChildrenBetween, wrapSelectionIn } from '@atlaskit/editor-common/utils';
|
|
5
|
+
import { CellSelection } from '@atlaskit/editor-tables';
|
|
6
|
+
import { HEADINGS_BY_NAME, NORMAL_TEXT } from '../block-types';
|
|
7
|
+
export function setBlockType(name) {
|
|
8
|
+
return (state, dispatch) => {
|
|
9
|
+
const {
|
|
10
|
+
nodes
|
|
11
|
+
} = state.schema;
|
|
12
|
+
if (name === NORMAL_TEXT.name && nodes.paragraph) {
|
|
13
|
+
return setNormalText()(state, dispatch);
|
|
14
|
+
}
|
|
15
|
+
const headingBlockType = HEADINGS_BY_NAME[name];
|
|
16
|
+
if (headingBlockType && nodes.heading && headingBlockType.level) {
|
|
17
|
+
return setHeading(headingBlockType.level)(state, dispatch);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function setBlockTypeWithAnalytics(name, inputMethod, editorAnalyticsApi) {
|
|
23
|
+
return (state, dispatch) => {
|
|
24
|
+
const {
|
|
25
|
+
nodes
|
|
26
|
+
} = state.schema;
|
|
27
|
+
if (name === NORMAL_TEXT.name && nodes.paragraph) {
|
|
28
|
+
return setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi)(state, dispatch);
|
|
29
|
+
}
|
|
30
|
+
const headingBlockType = HEADINGS_BY_NAME[name];
|
|
31
|
+
if (headingBlockType && nodes.heading && headingBlockType.level) {
|
|
32
|
+
return setHeadingWithAnalytics(headingBlockType.level, inputMethod, editorAnalyticsApi)(state, dispatch);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function setNormalText() {
|
|
38
|
+
return function (state, dispatch) {
|
|
39
|
+
const {
|
|
40
|
+
selection,
|
|
41
|
+
schema,
|
|
42
|
+
tr
|
|
43
|
+
} = state;
|
|
44
|
+
const ranges = selection instanceof CellSelection ? selection.ranges : [selection];
|
|
45
|
+
ranges.forEach(({
|
|
46
|
+
$from,
|
|
47
|
+
$to
|
|
48
|
+
}) => {
|
|
49
|
+
tr.setBlockType($from.pos, $to.pos, schema.nodes.paragraph);
|
|
50
|
+
});
|
|
51
|
+
if (dispatch) {
|
|
52
|
+
dispatch(tr);
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function withCurrentHeadingLevel(fn) {
|
|
58
|
+
return (state, dispatch, view) => {
|
|
59
|
+
// Find all headings and paragraphs of text
|
|
60
|
+
const {
|
|
61
|
+
heading,
|
|
62
|
+
paragraph
|
|
63
|
+
} = state.schema.nodes;
|
|
64
|
+
const nodes = filterChildrenBetween(state.doc, state.selection.from, state.selection.to, node => {
|
|
65
|
+
return node.type === heading || node.type === paragraph;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Check each paragraph and/or heading and check for consistent level
|
|
69
|
+
let level;
|
|
70
|
+
for (let node of nodes) {
|
|
71
|
+
const nodeLevel = node.node.type === heading ? node.node.attrs.level : 0;
|
|
72
|
+
if (!level) {
|
|
73
|
+
level = nodeLevel;
|
|
74
|
+
} else if (nodeLevel !== level) {
|
|
75
|
+
// Conflict in level, therefore inconsistent and undefined
|
|
76
|
+
level = undefined;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return fn(level)(state, dispatch, view);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function setNormalTextWithAnalytics(inputMethod, editorAnalyticsApi) {
|
|
84
|
+
return withCurrentHeadingLevel(previousHeadingLevel => withAnalytics(editorAnalyticsApi, {
|
|
85
|
+
action: ACTION.FORMATTED,
|
|
86
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
87
|
+
eventType: EVENT_TYPE.TRACK,
|
|
88
|
+
actionSubjectId: ACTION_SUBJECT_ID.FORMAT_HEADING,
|
|
89
|
+
attributes: {
|
|
90
|
+
inputMethod,
|
|
91
|
+
newHeadingLevel: 0,
|
|
92
|
+
previousHeadingLevel
|
|
93
|
+
}
|
|
94
|
+
})(setNormalText()));
|
|
95
|
+
}
|
|
96
|
+
export const setHeadingWithAnalytics = (newHeadingLevel, inputMethod, editorAnalyticsApi) => {
|
|
97
|
+
return withCurrentHeadingLevel(previousHeadingLevel => withAnalytics(editorAnalyticsApi, {
|
|
98
|
+
action: ACTION.FORMATTED,
|
|
99
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
100
|
+
eventType: EVENT_TYPE.TRACK,
|
|
101
|
+
actionSubjectId: ACTION_SUBJECT_ID.FORMAT_HEADING,
|
|
102
|
+
attributes: {
|
|
103
|
+
inputMethod,
|
|
104
|
+
newHeadingLevel,
|
|
105
|
+
previousHeadingLevel
|
|
106
|
+
}
|
|
107
|
+
})(setHeading(newHeadingLevel)));
|
|
108
|
+
};
|
|
109
|
+
function insertBlockQuote() {
|
|
110
|
+
return function (state, dispatch) {
|
|
111
|
+
const {
|
|
112
|
+
nodes
|
|
113
|
+
} = state.schema;
|
|
114
|
+
if (nodes.paragraph && nodes.blockquote) {
|
|
115
|
+
return wrapSelectionIn(nodes.blockquote)(state, dispatch);
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
*
|
|
123
|
+
* @param name - block type name
|
|
124
|
+
* @param inputMethod - input method
|
|
125
|
+
* @param editorAnalyticsApi - analytics api, undefined if not available either because it failed to load or wasn't added
|
|
126
|
+
* otherwise Editor becomes very sad and crashes
|
|
127
|
+
* @returns - command that inserts block type
|
|
128
|
+
*/
|
|
129
|
+
export const insertBlockQuoteWithAnalytics = (inputMethod, editorAnalyticsApi) => {
|
|
130
|
+
return withAnalytics(editorAnalyticsApi, {
|
|
131
|
+
action: ACTION.FORMATTED,
|
|
132
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
133
|
+
eventType: EVENT_TYPE.TRACK,
|
|
134
|
+
actionSubjectId: ACTION_SUBJECT_ID.FORMAT_BLOCK_QUOTE,
|
|
135
|
+
attributes: {
|
|
136
|
+
inputMethod: inputMethod
|
|
137
|
+
}
|
|
138
|
+
})(insertBlockQuote());
|
|
139
|
+
};
|
|
140
|
+
export const cleanUpAtTheStartOfDocument = (state, dispatch) => {
|
|
141
|
+
const {
|
|
142
|
+
$cursor
|
|
143
|
+
} = state.selection;
|
|
144
|
+
if ($cursor && !$cursor.nodeBefore && !$cursor.nodeAfter && $cursor.pos === 1) {
|
|
145
|
+
const {
|
|
146
|
+
tr,
|
|
147
|
+
schema
|
|
148
|
+
} = state;
|
|
149
|
+
const {
|
|
150
|
+
paragraph
|
|
151
|
+
} = schema.nodes;
|
|
152
|
+
const {
|
|
153
|
+
parent
|
|
154
|
+
} = $cursor;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Use cases:
|
|
158
|
+
* 1. Change `heading` to `paragraph`
|
|
159
|
+
* 2. Remove block marks
|
|
160
|
+
*
|
|
161
|
+
* NOTE: We already know it's an empty doc so it's safe to use 0
|
|
162
|
+
*/
|
|
163
|
+
tr.setNodeMarkup(0, paragraph, parent.attrs, []);
|
|
164
|
+
if (dispatch) {
|
|
165
|
+
dispatch(tr);
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
|
|
3
|
+
// We should override default behaviour when selection spans node depths or
|
|
4
|
+
// ends at a node junction
|
|
5
|
+
const shouldMoveCursorAfterDelete = state => {
|
|
6
|
+
const {
|
|
7
|
+
selection: {
|
|
8
|
+
$from,
|
|
9
|
+
$to
|
|
10
|
+
}
|
|
11
|
+
} = state;
|
|
12
|
+
const nodeRange = $from.blockRange($to);
|
|
13
|
+
if (!nodeRange) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const hasSameAncestor = $from.depth === $to.depth && $from.depth - 1 === nodeRange.depth;
|
|
17
|
+
const toPositionHasNodeAfter = !!$to.nodeAfter;
|
|
18
|
+
if (hasSameAncestor || toPositionHasNodeAfter) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Fixes cursor position after delete for list/task in panel and table
|
|
26
|
+
*
|
|
27
|
+
* ED-13873 fixes a bug where after deleting a list the cursor would move
|
|
28
|
+
* to the cell to the right. Uses setSelection to position the cursor as expected after deleting.
|
|
29
|
+
*
|
|
30
|
+
* @param state EditorState
|
|
31
|
+
* @param dispatch CommandDispatch
|
|
32
|
+
* @returns boolean
|
|
33
|
+
*/
|
|
34
|
+
export const deleteAndMoveCursor = (state, dispatch) => {
|
|
35
|
+
if (state.selection.empty || !(state.selection instanceof TextSelection)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (!shouldMoveCursorAfterDelete(state)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const {
|
|
42
|
+
tr
|
|
43
|
+
} = state;
|
|
44
|
+
tr.deleteSelection();
|
|
45
|
+
|
|
46
|
+
// Make sure the next position is not out of boundaries
|
|
47
|
+
const previousPosition = Math.min(Math.max(state.selection.$from.pos, 0), tr.doc.content.size);
|
|
48
|
+
// Override default delete behaviour that moves the cursor to first suitable position after selection (postive bias).
|
|
49
|
+
// See. selectionToInsertionEnd. We will override behavior with negative bias (search for suitable cursor position backwards).
|
|
50
|
+
tr.setSelection(Selection.near(tr.doc.resolve(previousPosition), -1));
|
|
51
|
+
if (dispatch) {
|
|
52
|
+
dispatch(tr.scrollIntoView());
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prevent removing the block when deleting block content
|
|
3
|
+
*
|
|
4
|
+
* @param state EditorState
|
|
5
|
+
* @param dispatch CommandDispatch
|
|
6
|
+
* @returns boolean
|
|
7
|
+
*/
|
|
8
|
+
export function deleteBlockContent(isNodeAWrappingBlockNode) {
|
|
9
|
+
return (state, dispatch) => {
|
|
10
|
+
const {
|
|
11
|
+
tr,
|
|
12
|
+
selection: {
|
|
13
|
+
$from,
|
|
14
|
+
$to
|
|
15
|
+
},
|
|
16
|
+
doc
|
|
17
|
+
} = state;
|
|
18
|
+
if ($from.pos === $to.pos) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
let selectionCrossesWrappingBlockNode = false;
|
|
22
|
+
doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
|
|
23
|
+
// Optimisation. If selection crosses wrapping block node
|
|
24
|
+
// short circuit the loop by returning false
|
|
25
|
+
if (selectionCrossesWrappingBlockNode) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (isNodeAWrappingBlockNode(node)) {
|
|
29
|
+
selectionCrossesWrappingBlockNode = true;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
if (!selectionCrossesWrappingBlockNode) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
tr.delete($from.pos, $to.pos);
|
|
37
|
+
if (dispatch) {
|
|
38
|
+
dispatch(tr);
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { cleanUpAtTheStartOfDocument, insertBlockQuoteWithAnalytics, setBlockType, setBlockTypeWithAnalytics, setHeadingWithAnalytics, setNormalText, setNormalTextWithAnalytics } from './block-type';
|
|
2
|
+
export { deleteAndMoveCursor } from './delete-and-move-cursor';
|
|
3
|
+
export { deleteBlockContent } from './delete-block-content';
|
|
4
|
+
/**
|
|
5
|
+
* @private
|
|
6
|
+
* @deprecated use import from @atlaskit/editor-common/commands
|
|
7
|
+
*/
|
|
8
|
+
export { setHeading } from '@atlaskit/editor-common/commands';
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { blockquote, hardBreak, heading } from '@atlaskit/adf-schema';
|
|
3
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
4
|
+
import { keymap, toggleBlockQuote, tooltip } from '@atlaskit/editor-common/keymaps';
|
|
5
|
+
import { IconHeading, IconQuote } from '@atlaskit/editor-common/quick-insert';
|
|
6
|
+
import { ToolbarSize } from '@atlaskit/editor-common/types';
|
|
7
|
+
import { WithPluginState } from '@atlaskit/editor-common/with-plugin-state';
|
|
8
|
+
import { setBlockTypeWithAnalytics } from './commands';
|
|
9
|
+
import { insertBlockQuoteWithAnalytics } from './commands/block-type';
|
|
10
|
+
import { messages } from './messages';
|
|
11
|
+
import inputRulePlugin from './pm-plugins/input-rule';
|
|
12
|
+
import keymapPlugin from './pm-plugins/keymap';
|
|
13
|
+
import { createPlugin, pluginKey } from './pm-plugins/main';
|
|
14
|
+
import ToolbarBlockType from './ui/ToolbarBlockType';
|
|
15
|
+
const headingPluginOptions = ({
|
|
16
|
+
formatMessage
|
|
17
|
+
}, isAllowed, editorAnalyticsApi) => {
|
|
18
|
+
if (!isAllowed) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return Array.from({
|
|
22
|
+
length: 6
|
|
23
|
+
}, (_v, idx) => {
|
|
24
|
+
const level = idx + 1;
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
const descriptionDescriptor = messages[`heading${level}Description`];
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const keyshortcut = tooltip(keymap[`toggleHeading${level}`]);
|
|
29
|
+
const id = `heading${level}`;
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
title: formatMessage(messages[id]),
|
|
34
|
+
description: formatMessage(descriptionDescriptor),
|
|
35
|
+
priority: 1300,
|
|
36
|
+
keywords: [`h${level}`],
|
|
37
|
+
keyshortcut,
|
|
38
|
+
icon: () => /*#__PURE__*/React.createElement(IconHeading, {
|
|
39
|
+
level: level
|
|
40
|
+
}),
|
|
41
|
+
action(insert, state) {
|
|
42
|
+
const tr = insert(state.schema.nodes.heading.createChecked({
|
|
43
|
+
level
|
|
44
|
+
}));
|
|
45
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
46
|
+
action: ACTION.FORMATTED,
|
|
47
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
48
|
+
eventType: EVENT_TYPE.TRACK,
|
|
49
|
+
actionSubjectId: ACTION_SUBJECT_ID.FORMAT_HEADING,
|
|
50
|
+
attributes: {
|
|
51
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT,
|
|
52
|
+
newHeadingLevel: level
|
|
53
|
+
}
|
|
54
|
+
})(tr);
|
|
55
|
+
return tr;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const blockquotePluginOptions = ({
|
|
61
|
+
formatMessage
|
|
62
|
+
}, isAllowed, editorAnalyticsApi) => {
|
|
63
|
+
if (!isAllowed) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
return [{
|
|
67
|
+
id: 'blockquote',
|
|
68
|
+
title: formatMessage(messages.blockquote),
|
|
69
|
+
description: formatMessage(messages.blockquoteDescription),
|
|
70
|
+
priority: 1300,
|
|
71
|
+
keyshortcut: tooltip(toggleBlockQuote),
|
|
72
|
+
icon: () => /*#__PURE__*/React.createElement(IconQuote, null),
|
|
73
|
+
action(insert, state) {
|
|
74
|
+
const tr = insert(state.schema.nodes.blockquote.createChecked({}, state.schema.nodes.paragraph.createChecked()));
|
|
75
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
76
|
+
action: ACTION.FORMATTED,
|
|
77
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
78
|
+
eventType: EVENT_TYPE.TRACK,
|
|
79
|
+
actionSubjectId: ACTION_SUBJECT_ID.FORMAT_BLOCK_QUOTE,
|
|
80
|
+
attributes: {
|
|
81
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT
|
|
82
|
+
}
|
|
83
|
+
})(tr);
|
|
84
|
+
return tr;
|
|
85
|
+
}
|
|
86
|
+
}];
|
|
87
|
+
};
|
|
88
|
+
const blockTypePlugin = ({
|
|
89
|
+
config: options,
|
|
90
|
+
api
|
|
91
|
+
}) => ({
|
|
92
|
+
name: 'blockType',
|
|
93
|
+
nodes() {
|
|
94
|
+
const nodes = [{
|
|
95
|
+
name: 'heading',
|
|
96
|
+
node: heading
|
|
97
|
+
}, {
|
|
98
|
+
name: 'blockquote',
|
|
99
|
+
node: blockquote
|
|
100
|
+
}, {
|
|
101
|
+
name: 'hardBreak',
|
|
102
|
+
node: hardBreak
|
|
103
|
+
}];
|
|
104
|
+
if (options && options.allowBlockType) {
|
|
105
|
+
const exclude = options.allowBlockType.exclude ? options.allowBlockType.exclude : [];
|
|
106
|
+
return nodes.filter(node => exclude.indexOf(node.name) === -1);
|
|
107
|
+
}
|
|
108
|
+
return nodes;
|
|
109
|
+
},
|
|
110
|
+
pmPlugins() {
|
|
111
|
+
return [{
|
|
112
|
+
name: 'blockType',
|
|
113
|
+
plugin: ({
|
|
114
|
+
dispatch
|
|
115
|
+
}) => {
|
|
116
|
+
var _api$analytics;
|
|
117
|
+
return createPlugin(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, dispatch, options && options.lastNodeMustBeParagraph);
|
|
118
|
+
}
|
|
119
|
+
}, {
|
|
120
|
+
name: 'blockTypeInputRule',
|
|
121
|
+
plugin: ({
|
|
122
|
+
schema,
|
|
123
|
+
featureFlags
|
|
124
|
+
}) => {
|
|
125
|
+
var _api$analytics2;
|
|
126
|
+
return inputRulePlugin(api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, schema, featureFlags);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
// Needs to be lower priority than editor-tables.tableEditing
|
|
130
|
+
// plugin as it is currently swallowing right/down arrow events inside tables
|
|
131
|
+
{
|
|
132
|
+
name: 'blockTypeKeyMap',
|
|
133
|
+
plugin: ({
|
|
134
|
+
schema,
|
|
135
|
+
featureFlags
|
|
136
|
+
}) => {
|
|
137
|
+
var _api$analytics3;
|
|
138
|
+
return keymapPlugin(api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions, schema, featureFlags);
|
|
139
|
+
}
|
|
140
|
+
}];
|
|
141
|
+
},
|
|
142
|
+
actions: {
|
|
143
|
+
insertBlockQuote(inputMethod) {
|
|
144
|
+
var _api$analytics4;
|
|
145
|
+
return insertBlockQuoteWithAnalytics(inputMethod, api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions);
|
|
146
|
+
},
|
|
147
|
+
setBlockType(name, inputMethod) {
|
|
148
|
+
var _api$analytics5;
|
|
149
|
+
return setBlockTypeWithAnalytics(name, inputMethod, api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
getSharedState(editorState) {
|
|
153
|
+
if (!editorState) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
return pluginKey.getState(editorState);
|
|
157
|
+
},
|
|
158
|
+
primaryToolbarComponent({
|
|
159
|
+
editorView,
|
|
160
|
+
popupsMountPoint,
|
|
161
|
+
popupsBoundariesElement,
|
|
162
|
+
popupsScrollableElement,
|
|
163
|
+
toolbarSize,
|
|
164
|
+
disabled,
|
|
165
|
+
isToolbarReducedSpacing,
|
|
166
|
+
eventDispatcher
|
|
167
|
+
}) {
|
|
168
|
+
const isSmall = options && options.isUndoRedoButtonsEnabled ? toolbarSize < ToolbarSize.XXL : toolbarSize < ToolbarSize.XL;
|
|
169
|
+
const boundSetBlockType = name => {
|
|
170
|
+
var _api$analytics6;
|
|
171
|
+
return setBlockTypeWithAnalytics(name, INPUT_METHOD.TOOLBAR, api === null || api === void 0 ? void 0 : (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : _api$analytics6.actions)(editorView.state, editorView.dispatch);
|
|
172
|
+
};
|
|
173
|
+
return /*#__PURE__*/React.createElement(WithPluginState, {
|
|
174
|
+
editorView: editorView,
|
|
175
|
+
eventDispatcher: eventDispatcher,
|
|
176
|
+
plugins: {
|
|
177
|
+
pluginState: pluginKey
|
|
178
|
+
},
|
|
179
|
+
render: ({
|
|
180
|
+
pluginState
|
|
181
|
+
}) => {
|
|
182
|
+
return /*#__PURE__*/React.createElement(ToolbarBlockType, {
|
|
183
|
+
isSmall: isSmall,
|
|
184
|
+
isDisabled: disabled,
|
|
185
|
+
isReducedSpacing: isToolbarReducedSpacing,
|
|
186
|
+
setBlockType: boundSetBlockType,
|
|
187
|
+
pluginState: pluginState,
|
|
188
|
+
popupsMountPoint: popupsMountPoint,
|
|
189
|
+
popupsBoundariesElement: popupsBoundariesElement,
|
|
190
|
+
popupsScrollableElement: popupsScrollableElement
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
pluginsOptions: {
|
|
196
|
+
quickInsert: intl => {
|
|
197
|
+
var _api$analytics7, _api$analytics8;
|
|
198
|
+
const exclude = options && options.allowBlockType && options.allowBlockType.exclude ? options.allowBlockType.exclude : [];
|
|
199
|
+
return [...blockquotePluginOptions(intl, exclude.indexOf('blockquote') === -1, api === null || api === void 0 ? void 0 : (_api$analytics7 = api.analytics) === null || _api$analytics7 === void 0 ? void 0 : _api$analytics7.actions), ...headingPluginOptions(intl, exclude.indexOf('heading') === -1, api === null || api === void 0 ? void 0 : (_api$analytics8 = api.analytics) === null || _api$analytics8 === void 0 ? void 0 : _api$analytics8.actions)];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
export { blockTypePlugin };
|
|
204
|
+
export { pluginKey } from './pm-plugins/main';
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl-next';
|
|
2
|
+
export const messages = defineMessages({
|
|
3
|
+
normal: {
|
|
4
|
+
id: 'fabric.editor.normal',
|
|
5
|
+
defaultMessage: 'Normal text',
|
|
6
|
+
description: 'This is the default text style'
|
|
7
|
+
},
|
|
8
|
+
heading1: {
|
|
9
|
+
id: 'fabric.editor.heading1',
|
|
10
|
+
defaultMessage: 'Heading 1',
|
|
11
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
12
|
+
},
|
|
13
|
+
heading1Description: {
|
|
14
|
+
id: 'fabric.editor.heading1Description',
|
|
15
|
+
defaultMessage: 'Use this for a top level heading',
|
|
16
|
+
description: 'Description of the main heading, heading 1'
|
|
17
|
+
},
|
|
18
|
+
heading2: {
|
|
19
|
+
id: 'fabric.editor.heading2',
|
|
20
|
+
defaultMessage: 'Heading 2',
|
|
21
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
22
|
+
},
|
|
23
|
+
heading2Description: {
|
|
24
|
+
id: 'fabric.editor.heading2Description',
|
|
25
|
+
defaultMessage: 'Use this for key sections',
|
|
26
|
+
description: 'Description of a subtitle heading or secondary heading'
|
|
27
|
+
},
|
|
28
|
+
heading3: {
|
|
29
|
+
id: 'fabric.editor.heading3',
|
|
30
|
+
defaultMessage: 'Heading 3',
|
|
31
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
32
|
+
},
|
|
33
|
+
heading3Description: {
|
|
34
|
+
id: 'fabric.editor.heading3Description',
|
|
35
|
+
defaultMessage: 'Use this for sub sections and group headings',
|
|
36
|
+
description: ''
|
|
37
|
+
},
|
|
38
|
+
heading4: {
|
|
39
|
+
id: 'fabric.editor.heading4',
|
|
40
|
+
defaultMessage: 'Heading 4',
|
|
41
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
42
|
+
},
|
|
43
|
+
heading4Description: {
|
|
44
|
+
id: 'fabric.editor.heading4Description',
|
|
45
|
+
defaultMessage: 'Use this for deep headings',
|
|
46
|
+
description: ''
|
|
47
|
+
},
|
|
48
|
+
heading5: {
|
|
49
|
+
id: 'fabric.editor.heading5',
|
|
50
|
+
defaultMessage: 'Heading 5',
|
|
51
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
52
|
+
},
|
|
53
|
+
heading5Description: {
|
|
54
|
+
id: 'fabric.editor.heading5Description',
|
|
55
|
+
defaultMessage: 'Use this for grouping list items',
|
|
56
|
+
description: ''
|
|
57
|
+
},
|
|
58
|
+
heading6: {
|
|
59
|
+
id: 'fabric.editor.heading6',
|
|
60
|
+
defaultMessage: 'Heading 6',
|
|
61
|
+
description: 'Used for the title of a section of your document, headings run from 1 (largest size) to 6 (smallest size)'
|
|
62
|
+
},
|
|
63
|
+
heading6Description: {
|
|
64
|
+
id: 'fabric.editor.heading6Description',
|
|
65
|
+
defaultMessage: 'Use this for low level headings',
|
|
66
|
+
description: ''
|
|
67
|
+
},
|
|
68
|
+
blockquote: {
|
|
69
|
+
id: 'fabric.editor.blockquote2',
|
|
70
|
+
defaultMessage: 'Quote',
|
|
71
|
+
description: 'Quote some text'
|
|
72
|
+
},
|
|
73
|
+
blockquoteDescription: {
|
|
74
|
+
id: 'fabric.editor.blockquote.description',
|
|
75
|
+
defaultMessage: 'Insert a quote or citation',
|
|
76
|
+
description: 'Quote some text'
|
|
77
|
+
},
|
|
78
|
+
codeblock: {
|
|
79
|
+
id: 'fabric.editor.codeblock',
|
|
80
|
+
defaultMessage: 'Code snippet',
|
|
81
|
+
description: 'Insert a snippet/segment of code (code block)'
|
|
82
|
+
},
|
|
83
|
+
codeblockDescription: {
|
|
84
|
+
id: 'fabric.editor.codeblock.description',
|
|
85
|
+
defaultMessage: 'Display code with syntax highlighting',
|
|
86
|
+
description: 'Insert a snippet/segment of code (code block)'
|
|
87
|
+
},
|
|
88
|
+
infoPanel: {
|
|
89
|
+
id: 'fabric.editor.infoPanel',
|
|
90
|
+
defaultMessage: 'Info panel',
|
|
91
|
+
description: 'Visually distinguishes your text by adding a background colour (blue, purple, yellow, green, red)'
|
|
92
|
+
},
|
|
93
|
+
infoPanelDescription: {
|
|
94
|
+
id: 'fabric.editor.infoPanel.description',
|
|
95
|
+
defaultMessage: 'Highlight information in a colored panel',
|
|
96
|
+
description: 'Visually distinguishes your text by adding a background colour (blue, purple, yellow, green, red)'
|
|
97
|
+
},
|
|
98
|
+
notePanel: {
|
|
99
|
+
id: 'fabric.editor.notePanel',
|
|
100
|
+
defaultMessage: 'Note panel',
|
|
101
|
+
description: 'Visually distinguishes your text by adding a note panel'
|
|
102
|
+
},
|
|
103
|
+
notePanelDescription: {
|
|
104
|
+
id: 'fabric.editor.notePanel.description',
|
|
105
|
+
defaultMessage: 'Add a note in a colored panel',
|
|
106
|
+
description: 'Visually distinguishes your text by adding a note panel'
|
|
107
|
+
},
|
|
108
|
+
successPanel: {
|
|
109
|
+
id: 'fabric.editor.successPanel',
|
|
110
|
+
defaultMessage: 'Success panel',
|
|
111
|
+
description: 'Visually distinguishes your text by adding a success panel'
|
|
112
|
+
},
|
|
113
|
+
successPanelDescription: {
|
|
114
|
+
id: 'fabric.editor.successPanel.description',
|
|
115
|
+
defaultMessage: 'Add tips in a colored panel',
|
|
116
|
+
description: 'Visually distinguishes your text by adding a success panel'
|
|
117
|
+
},
|
|
118
|
+
warningPanel: {
|
|
119
|
+
id: 'fabric.editor.warningPanel',
|
|
120
|
+
defaultMessage: 'Warning panel',
|
|
121
|
+
description: 'Visually distinguishes your text by adding a warning panel'
|
|
122
|
+
},
|
|
123
|
+
warningPanelDescription: {
|
|
124
|
+
id: 'fabric.editor.warningPanel.description',
|
|
125
|
+
defaultMessage: 'Add a note of caution in a colored panel',
|
|
126
|
+
description: 'Visually distinguishes your text by adding a warning panel'
|
|
127
|
+
},
|
|
128
|
+
errorPanel: {
|
|
129
|
+
id: 'fabric.editor.errorPanel',
|
|
130
|
+
defaultMessage: 'Error panel',
|
|
131
|
+
description: 'Visually distinguishes your text by adding a error panel'
|
|
132
|
+
},
|
|
133
|
+
errorPanelDescription: {
|
|
134
|
+
id: 'fabric.editor.errorPanel.description',
|
|
135
|
+
defaultMessage: 'Call out errors in a colored panel',
|
|
136
|
+
description: 'Visually distinguishes your text by adding a error panel'
|
|
137
|
+
},
|
|
138
|
+
customPanel: {
|
|
139
|
+
id: 'fabric.editor.customPanel',
|
|
140
|
+
defaultMessage: 'Custom panel',
|
|
141
|
+
description: 'Visually distinguishes your panel by adding a emoji icon and background color'
|
|
142
|
+
},
|
|
143
|
+
customPanelDescription: {
|
|
144
|
+
id: 'fabric.editor.customPanel.description',
|
|
145
|
+
defaultMessage: 'Add a note with an emoji and colored background',
|
|
146
|
+
description: 'Visually distinguishes your panel by adding a emoji icon and background color '
|
|
147
|
+
},
|
|
148
|
+
other: {
|
|
149
|
+
id: 'fabric.editor.other',
|
|
150
|
+
defaultMessage: 'Others...',
|
|
151
|
+
description: 'Other text formatting'
|
|
152
|
+
}
|
|
153
|
+
});
|