@atlaskit/editor-plugin-panel 0.1.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 +18 -0
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +13 -0
- package/README.md +30 -0
- package/dist/cjs/actions.js +125 -0
- package/dist/cjs/index.js +13 -0
- package/dist/cjs/message.js +44 -0
- package/dist/cjs/nodeviews/panel.js +94 -0
- package/dist/cjs/plugin.js +215 -0
- package/dist/cjs/pm-plugins/keymaps.js +81 -0
- package/dist/cjs/pm-plugins/main.js +28 -0
- package/dist/cjs/toolbar.js +293 -0
- package/dist/cjs/types.js +8 -0
- package/dist/cjs/utils.js +53 -0
- package/dist/es2019/actions.js +116 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/message.js +38 -0
- package/dist/es2019/nodeviews/panel.js +82 -0
- package/dist/es2019/plugin.js +191 -0
- package/dist/es2019/pm-plugins/keymaps.js +82 -0
- package/dist/es2019/pm-plugins/main.js +21 -0
- package/dist/es2019/toolbar.js +279 -0
- package/dist/es2019/types.js +2 -0
- package/dist/es2019/utils.js +48 -0
- package/dist/esm/actions.js +116 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/message.js +38 -0
- package/dist/esm/nodeviews/panel.js +87 -0
- package/dist/esm/plugin.js +208 -0
- package/dist/esm/pm-plugins/keymaps.js +74 -0
- package/dist/esm/pm-plugins/main.js +22 -0
- package/dist/esm/toolbar.js +286 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/utils.js +46 -0
- package/dist/types/actions.d.ts +12 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/message.d.ts +37 -0
- package/dist/types/nodeviews/panel.d.ts +36 -0
- package/dist/types/plugin.d.ts +17 -0
- package/dist/types/pm-plugins/keymaps.d.ts +3 -0
- package/dist/types/pm-plugins/main.d.ts +11 -0
- package/dist/types/toolbar.d.ts +15 -0
- package/dist/types/types.d.ts +21 -0
- package/dist/types/utils.d.ts +5 -0
- package/dist/types-ts4.5/actions.d.ts +12 -0
- package/dist/types-ts4.5/index.d.ts +3 -0
- package/dist/types-ts4.5/message.d.ts +37 -0
- package/dist/types-ts4.5/nodeviews/panel.d.ts +36 -0
- package/dist/types-ts4.5/plugin.d.ts +17 -0
- package/dist/types-ts4.5/pm-plugins/keymaps.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +11 -0
- package/dist/types-ts4.5/toolbar.d.ts +15 -0
- package/dist/types-ts4.5/types.d.ts +21 -0
- package/dist/types-ts4.5/utils.d.ts +5 -0
- package/package.json +102 -0
- package/report.api.md +74 -0
- package/tmp/api-report-tmp.d.ts +44 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { panel, PanelType } from '@atlaskit/adf-schema';
|
|
3
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
4
|
+
import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
5
|
+
import { IconCustomPanel, IconPanel, IconPanelError, IconPanelNote, IconPanelSuccess, IconPanelWarning } from '@atlaskit/editor-common/quick-insert';
|
|
6
|
+
import { createWrapSelectionTransaction } from '@atlaskit/editor-common/utils';
|
|
7
|
+
import { T50 } from '@atlaskit/theme/colors';
|
|
8
|
+
import { insertPanelWithAnalytics } from './actions';
|
|
9
|
+
import keymap from './pm-plugins/keymaps';
|
|
10
|
+
import { createPlugin } from './pm-plugins/main';
|
|
11
|
+
import { getToolbarConfig } from './toolbar';
|
|
12
|
+
const panelPlugin = ({
|
|
13
|
+
config: options = {},
|
|
14
|
+
api
|
|
15
|
+
}) => ({
|
|
16
|
+
name: 'panel',
|
|
17
|
+
nodes() {
|
|
18
|
+
const panelNode = panel(!!options.allowCustomPanel);
|
|
19
|
+
return [{
|
|
20
|
+
name: 'panel',
|
|
21
|
+
node: panelNode
|
|
22
|
+
}];
|
|
23
|
+
},
|
|
24
|
+
pmPlugins() {
|
|
25
|
+
return [{
|
|
26
|
+
name: 'panel',
|
|
27
|
+
plugin: ({
|
|
28
|
+
providerFactory,
|
|
29
|
+
dispatch
|
|
30
|
+
}) => createPlugin(dispatch, providerFactory, options)
|
|
31
|
+
}, {
|
|
32
|
+
name: 'panelKeyMap',
|
|
33
|
+
plugin: () => keymap()
|
|
34
|
+
}];
|
|
35
|
+
},
|
|
36
|
+
actions: {
|
|
37
|
+
insertPanel(inputMethod) {
|
|
38
|
+
var _api$analytics;
|
|
39
|
+
return insertPanelWithAnalytics(inputMethod, api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
pluginsOptions: {
|
|
43
|
+
quickInsert: ({
|
|
44
|
+
formatMessage
|
|
45
|
+
}) => {
|
|
46
|
+
let quickInsertOptions = [{
|
|
47
|
+
id: 'infopanel',
|
|
48
|
+
title: formatMessage(blockTypeMessages.infoPanel),
|
|
49
|
+
keywords: ['panel'],
|
|
50
|
+
description: formatMessage(blockTypeMessages.infoPanelDescription),
|
|
51
|
+
priority: 800,
|
|
52
|
+
icon: () => /*#__PURE__*/React.createElement(IconPanel, null),
|
|
53
|
+
action(insert, state) {
|
|
54
|
+
return createPanelAction({
|
|
55
|
+
state,
|
|
56
|
+
attributes: {
|
|
57
|
+
panelType: PanelType.INFO
|
|
58
|
+
},
|
|
59
|
+
api
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}, {
|
|
63
|
+
id: 'notepanel',
|
|
64
|
+
title: formatMessage(blockTypeMessages.notePanel),
|
|
65
|
+
description: formatMessage(blockTypeMessages.notePanelDescription),
|
|
66
|
+
priority: 1000,
|
|
67
|
+
icon: () => /*#__PURE__*/React.createElement(IconPanelNote, null),
|
|
68
|
+
action(insert, state) {
|
|
69
|
+
return createPanelAction({
|
|
70
|
+
state,
|
|
71
|
+
attributes: {
|
|
72
|
+
panelType: PanelType.NOTE
|
|
73
|
+
},
|
|
74
|
+
api
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}, {
|
|
78
|
+
id: 'successpanel',
|
|
79
|
+
title: formatMessage(blockTypeMessages.successPanel),
|
|
80
|
+
description: formatMessage(blockTypeMessages.successPanelDescription),
|
|
81
|
+
keywords: ['tip'],
|
|
82
|
+
priority: 1000,
|
|
83
|
+
icon: () => /*#__PURE__*/React.createElement(IconPanelSuccess, null),
|
|
84
|
+
action(insert, state) {
|
|
85
|
+
return createPanelAction({
|
|
86
|
+
state,
|
|
87
|
+
attributes: {
|
|
88
|
+
panelType: PanelType.SUCCESS
|
|
89
|
+
},
|
|
90
|
+
api
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}, {
|
|
94
|
+
id: 'warningpanel',
|
|
95
|
+
title: formatMessage(blockTypeMessages.warningPanel),
|
|
96
|
+
description: formatMessage(blockTypeMessages.warningPanelDescription),
|
|
97
|
+
priority: 1000,
|
|
98
|
+
icon: () => /*#__PURE__*/React.createElement(IconPanelWarning, null),
|
|
99
|
+
action(insert, state) {
|
|
100
|
+
return createPanelAction({
|
|
101
|
+
state,
|
|
102
|
+
attributes: {
|
|
103
|
+
panelType: PanelType.WARNING
|
|
104
|
+
},
|
|
105
|
+
api
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}, {
|
|
109
|
+
id: 'errorpanel',
|
|
110
|
+
title: formatMessage(blockTypeMessages.errorPanel),
|
|
111
|
+
description: formatMessage(blockTypeMessages.errorPanelDescription),
|
|
112
|
+
priority: 1000,
|
|
113
|
+
icon: () => /*#__PURE__*/React.createElement(IconPanelError, null),
|
|
114
|
+
action(insert, state) {
|
|
115
|
+
return createPanelAction({
|
|
116
|
+
state,
|
|
117
|
+
attributes: {
|
|
118
|
+
panelType: PanelType.ERROR
|
|
119
|
+
},
|
|
120
|
+
api
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}];
|
|
124
|
+
if (options.allowCustomPanel && options.allowCustomPanelEdit) {
|
|
125
|
+
quickInsertOptions.push({
|
|
126
|
+
id: 'custompanel',
|
|
127
|
+
title: formatMessage(blockTypeMessages.customPanel),
|
|
128
|
+
description: formatMessage(blockTypeMessages.customPanelDescription),
|
|
129
|
+
priority: 1000,
|
|
130
|
+
icon: () => /*#__PURE__*/React.createElement(IconCustomPanel, null),
|
|
131
|
+
action(insert, state) {
|
|
132
|
+
return createPanelAction({
|
|
133
|
+
state,
|
|
134
|
+
attributes: {
|
|
135
|
+
panelType: PanelType.CUSTOM,
|
|
136
|
+
panelIcon: ':rainbow:',
|
|
137
|
+
panelIconId: '1f308',
|
|
138
|
+
panelIconText: '🌈',
|
|
139
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-7268
|
|
140
|
+
// eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
|
|
141
|
+
panelColor: T50
|
|
142
|
+
},
|
|
143
|
+
api
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return quickInsertOptions;
|
|
149
|
+
},
|
|
150
|
+
floatingToolbar: (state, intl, providerFactory) => getToolbarConfig(state, intl, options, providerFactory, api)
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Creates panel action and wrap selection transaction with analytics for the panel insertion.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* const tr = createPanelAction({
|
|
159
|
+
* state: editorState,
|
|
160
|
+
* attributes: { panelType: 'info' },
|
|
161
|
+
* });
|
|
162
|
+
* if (tr) {
|
|
163
|
+
* applyTransaction(tr);
|
|
164
|
+
* }
|
|
165
|
+
*/
|
|
166
|
+
function createPanelAction({
|
|
167
|
+
state,
|
|
168
|
+
attributes,
|
|
169
|
+
api
|
|
170
|
+
}) {
|
|
171
|
+
const tr = createWrapSelectionTransaction({
|
|
172
|
+
state,
|
|
173
|
+
type: state.schema.nodes.panel,
|
|
174
|
+
nodeAttributes: attributes
|
|
175
|
+
});
|
|
176
|
+
if (tr) {
|
|
177
|
+
var _api$analytics2;
|
|
178
|
+
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.attachAnalyticsEvent({
|
|
179
|
+
action: ACTION.INSERTED,
|
|
180
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
181
|
+
actionSubjectId: ACTION_SUBJECT_ID.PANEL,
|
|
182
|
+
attributes: {
|
|
183
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT,
|
|
184
|
+
panelType: attributes.panelType
|
|
185
|
+
},
|
|
186
|
+
eventType: EVENT_TYPE.TRACK
|
|
187
|
+
})(tr);
|
|
188
|
+
}
|
|
189
|
+
return tr;
|
|
190
|
+
}
|
|
191
|
+
export default panelPlugin;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { isEmptyNode } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { keymap } from '@atlaskit/editor-prosemirror/keymap';
|
|
3
|
+
import { findParentNodeOfType, hasParentNodeOfType, setTextSelection } from '@atlaskit/editor-prosemirror/utils';
|
|
4
|
+
function findParentNode(selection, nodeType) {
|
|
5
|
+
const parentPosition = findParentNodeOfType(nodeType)(selection);
|
|
6
|
+
if (parentPosition) {
|
|
7
|
+
return parentPosition.node;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
function isInsideAnEmptyNode(selection, nodeType, schema) {
|
|
12
|
+
const parentNode = findParentNode(selection, nodeType);
|
|
13
|
+
return parentNode && isEmptyNode(schema)(parentNode);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Somewhat broken and subverted: https://product-fabric.atlassian.net/browse/ED-6504
|
|
17
|
+
export function keymapPlugin() {
|
|
18
|
+
const deleteCurrentItem = ($from, tr) => {
|
|
19
|
+
return tr.delete($from.before($from.depth) - 1, $from.end($from.depth) + 1);
|
|
20
|
+
};
|
|
21
|
+
const keymaps = {
|
|
22
|
+
Backspace: (state, dispatch) => {
|
|
23
|
+
var _nodeBeforePanel$type, _nodeBeforePanel$type2;
|
|
24
|
+
const {
|
|
25
|
+
selection,
|
|
26
|
+
schema: {
|
|
27
|
+
nodes
|
|
28
|
+
},
|
|
29
|
+
tr
|
|
30
|
+
} = state;
|
|
31
|
+
const {
|
|
32
|
+
panel,
|
|
33
|
+
blockquote
|
|
34
|
+
} = nodes;
|
|
35
|
+
const {
|
|
36
|
+
$from,
|
|
37
|
+
$to
|
|
38
|
+
} = selection;
|
|
39
|
+
// Don't do anything if selection is a range
|
|
40
|
+
if ($from.pos !== $to.pos) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If not at the start of a panel, no joining will happen so allow default behaviour (backspacing characters etc..)
|
|
45
|
+
if ($from.parentOffset !== 0) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const $previousPos = tr.doc.resolve(Math.max(0, $from.before($from.depth) - 1));
|
|
49
|
+
const previousNodeType = $previousPos.pos > 0 && $previousPos.parent && $previousPos.parent.type;
|
|
50
|
+
const parentNodeType = $from.parent.type;
|
|
51
|
+
const isPreviousNodeAPanel = previousNodeType === panel;
|
|
52
|
+
const isParentNodeAPanel = parentNodeType === panel;
|
|
53
|
+
const nodeBeforePanel = $previousPos === null || $previousPos === void 0 ? void 0 : $previousPos.nodeBefore;
|
|
54
|
+
|
|
55
|
+
// Stops merging panels when deleting empty paragraph in between
|
|
56
|
+
// Stops merging blockquotes with panels when deleting from start of blockquote
|
|
57
|
+
|
|
58
|
+
if (isPreviousNodeAPanel && !isParentNodeAPanel || isInsideAnEmptyNode(selection, panel, state.schema) || hasParentNodeOfType(blockquote)(selection) ||
|
|
59
|
+
// Lift line of panel content up and out of the panel, when backspacing
|
|
60
|
+
// at the start of a panel, if the node before the panel is an 'isolating' node
|
|
61
|
+
// (for e.g. a table, or an expand), otherwise the default prosemirror backspace
|
|
62
|
+
// behaviour will fallback to 'select node backward' logic because the node
|
|
63
|
+
// before is an isolating node.
|
|
64
|
+
nodeBeforePanel !== null && nodeBeforePanel !== void 0 && (_nodeBeforePanel$type = nodeBeforePanel.type) !== null && _nodeBeforePanel$type !== void 0 && (_nodeBeforePanel$type2 = _nodeBeforePanel$type.spec) !== null && _nodeBeforePanel$type2 !== void 0 && _nodeBeforePanel$type2.isolating && hasParentNodeOfType(panel)(selection)) {
|
|
65
|
+
const content = $from.node($from.depth).content;
|
|
66
|
+
const insertPos = $previousPos.pos;
|
|
67
|
+
deleteCurrentItem($from, tr).insert(insertPos, content);
|
|
68
|
+
if (dispatch) {
|
|
69
|
+
dispatch(setTextSelection(insertPos)(tr).scrollIntoView());
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const nodeType = $from.node().type;
|
|
74
|
+
if (nodeType !== panel) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return keymap(keymaps);
|
|
81
|
+
}
|
|
82
|
+
export default keymapPlugin;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PanelSharedCssClassName } from '@atlaskit/editor-common/panel';
|
|
2
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
3
|
+
import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
|
|
4
|
+
import { getPanelNodeView } from '../nodeviews/panel';
|
|
5
|
+
import { pluginKey } from '../types';
|
|
6
|
+
export const createPlugin = (dispatch, providerFactory, pluginOptions) => {
|
|
7
|
+
const {
|
|
8
|
+
useLongPressSelection = false
|
|
9
|
+
} = pluginOptions;
|
|
10
|
+
return new SafePlugin({
|
|
11
|
+
key: pluginKey,
|
|
12
|
+
props: {
|
|
13
|
+
nodeViews: {
|
|
14
|
+
panel: getPanelNodeView(pluginOptions, providerFactory)
|
|
15
|
+
},
|
|
16
|
+
handleClickOn: createSelectionClickHandler(['panel'], target => !!target.closest(`.${PanelSharedCssClassName.prefix}`), {
|
|
17
|
+
useLongPressSelection
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { PanelType } from '@atlaskit/adf-schema';
|
|
2
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
3
|
+
import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
|
|
4
|
+
import commonMessages from '@atlaskit/editor-common/messages';
|
|
5
|
+
import { getPanelTypeBackgroundNoTokens } from '@atlaskit/editor-common/panel';
|
|
6
|
+
import { DEFAULT_BORDER_COLOR, panelBackgroundPalette } from '@atlaskit/editor-common/ui-color';
|
|
7
|
+
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
8
|
+
import ErrorIcon from '@atlaskit/icon/glyph/editor/error';
|
|
9
|
+
import InfoIcon from '@atlaskit/icon/glyph/editor/info';
|
|
10
|
+
import NoteIcon from '@atlaskit/icon/glyph/editor/note';
|
|
11
|
+
import RemoveIcon from '@atlaskit/icon/glyph/editor/remove';
|
|
12
|
+
import RemoveEmojiIcon from '@atlaskit/icon/glyph/editor/remove-emoji';
|
|
13
|
+
import SuccessIcon from '@atlaskit/icon/glyph/editor/success';
|
|
14
|
+
import WarningIcon from '@atlaskit/icon/glyph/editor/warning';
|
|
15
|
+
import { changePanelType, removePanel } from './actions';
|
|
16
|
+
import { messages } from './message';
|
|
17
|
+
import { findPanel } from './utils';
|
|
18
|
+
export const panelIconMap = {
|
|
19
|
+
[PanelType.INFO]: {
|
|
20
|
+
shortName: ':info:',
|
|
21
|
+
id: 'atlassian-info'
|
|
22
|
+
},
|
|
23
|
+
[PanelType.NOTE]: {
|
|
24
|
+
shortName: ':note:',
|
|
25
|
+
id: 'atlassian-note'
|
|
26
|
+
},
|
|
27
|
+
[PanelType.WARNING]: {
|
|
28
|
+
shortName: ':warning:',
|
|
29
|
+
id: 'atlassian-warning'
|
|
30
|
+
},
|
|
31
|
+
[PanelType.ERROR]: {
|
|
32
|
+
shortName: ':cross_mark:',
|
|
33
|
+
id: 'atlassian-cross_mark'
|
|
34
|
+
},
|
|
35
|
+
[PanelType.SUCCESS]: {
|
|
36
|
+
shortName: ':check_mark:',
|
|
37
|
+
id: 'atlassian-check_mark'
|
|
38
|
+
},
|
|
39
|
+
[PanelType.TIP]: {
|
|
40
|
+
shortName: ':tip:',
|
|
41
|
+
id: 'atlassian-tip'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export const getToolbarItems = (formatMessage, panelNodeType, isCustomPanelEnabled, isCustomPanelEditable, providerFactory, hoverDecoration, editorAnalyticsAPI, activePanelType, activePanelColor, activePanelIcon, state) => {
|
|
45
|
+
// TODO: ED-14403 investigate why these titles are not getting translated for the tooltips
|
|
46
|
+
const items = [{
|
|
47
|
+
id: 'editor.panel.info',
|
|
48
|
+
type: 'button',
|
|
49
|
+
icon: InfoIcon,
|
|
50
|
+
onClick: changePanelType(editorAnalyticsAPI)(PanelType.INFO),
|
|
51
|
+
selected: activePanelType === PanelType.INFO,
|
|
52
|
+
title: formatMessage(messages.info),
|
|
53
|
+
tabIndex: null
|
|
54
|
+
}, {
|
|
55
|
+
id: 'editor.panel.note',
|
|
56
|
+
type: 'button',
|
|
57
|
+
icon: NoteIcon,
|
|
58
|
+
onClick: changePanelType(editorAnalyticsAPI)(PanelType.NOTE),
|
|
59
|
+
selected: activePanelType === PanelType.NOTE,
|
|
60
|
+
title: formatMessage(messages.note),
|
|
61
|
+
tabIndex: null
|
|
62
|
+
}, {
|
|
63
|
+
id: 'editor.panel.success',
|
|
64
|
+
type: 'button',
|
|
65
|
+
icon: SuccessIcon,
|
|
66
|
+
onClick: changePanelType(editorAnalyticsAPI)(PanelType.SUCCESS),
|
|
67
|
+
selected: activePanelType === PanelType.SUCCESS,
|
|
68
|
+
title: formatMessage(messages.success),
|
|
69
|
+
tabIndex: null
|
|
70
|
+
}, {
|
|
71
|
+
id: 'editor.panel.warning',
|
|
72
|
+
type: 'button',
|
|
73
|
+
icon: WarningIcon,
|
|
74
|
+
onClick: changePanelType(editorAnalyticsAPI)(PanelType.WARNING),
|
|
75
|
+
selected: activePanelType === PanelType.WARNING,
|
|
76
|
+
title: formatMessage(messages.warning),
|
|
77
|
+
tabIndex: null
|
|
78
|
+
}, {
|
|
79
|
+
id: 'editor.panel.error',
|
|
80
|
+
type: 'button',
|
|
81
|
+
icon: ErrorIcon,
|
|
82
|
+
onClick: changePanelType(editorAnalyticsAPI)(PanelType.ERROR),
|
|
83
|
+
selected: activePanelType === PanelType.ERROR,
|
|
84
|
+
title: formatMessage(messages.error),
|
|
85
|
+
tabIndex: null
|
|
86
|
+
}];
|
|
87
|
+
if (isCustomPanelEnabled) {
|
|
88
|
+
const changeColor = color => (state, dispatch) => {
|
|
89
|
+
const panelNode = findPanel(state);
|
|
90
|
+
if (panelNode === undefined) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
let previousColor = panelNode.node.attrs.panelType === 'custom' ? panelNode.node.attrs.panelColor || 'none' : getPanelTypeBackgroundNoTokens(panelNode.node.attrs.panelType);
|
|
94
|
+
const emojiInfo = panelNode.node.attrs.panelType;
|
|
95
|
+
const panelEmoji = panelIconMap[emojiInfo];
|
|
96
|
+
const previousEmoji = panelEmoji ? {
|
|
97
|
+
emoji: panelEmoji.shortName,
|
|
98
|
+
emojiId: panelEmoji.id
|
|
99
|
+
} : {};
|
|
100
|
+
if (previousColor === color) {
|
|
101
|
+
changePanelType(editorAnalyticsAPI)(PanelType.CUSTOM, {
|
|
102
|
+
color,
|
|
103
|
+
...previousEmoji
|
|
104
|
+
}, isCustomPanelEnabled)(state, dispatch);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const payload = {
|
|
108
|
+
action: ACTION.CHANGED_BACKGROUND_COLOR,
|
|
109
|
+
actionSubject: ACTION_SUBJECT.PANEL,
|
|
110
|
+
actionSubjectId: ACTION_SUBJECT_ID.PANEL,
|
|
111
|
+
attributes: {
|
|
112
|
+
newColor: color,
|
|
113
|
+
previousColor: previousColor
|
|
114
|
+
},
|
|
115
|
+
eventType: EVENT_TYPE.TRACK
|
|
116
|
+
};
|
|
117
|
+
withAnalytics(editorAnalyticsAPI, payload)(changePanelType(editorAnalyticsAPI)(PanelType.CUSTOM, {
|
|
118
|
+
color,
|
|
119
|
+
...previousEmoji
|
|
120
|
+
}, isCustomPanelEnabled))(state, dispatch);
|
|
121
|
+
return false;
|
|
122
|
+
};
|
|
123
|
+
const changeEmoji = emoji => (state, dispatch) => {
|
|
124
|
+
const panelNode = findPanel(state);
|
|
125
|
+
if (panelNode === undefined) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
let previousIcon = panelNode.node.attrs.panelIcon || '';
|
|
129
|
+
if (previousIcon === emoji.shortName) {
|
|
130
|
+
changePanelType(editorAnalyticsAPI)(PanelType.CUSTOM, {
|
|
131
|
+
emoji: emoji.shortName,
|
|
132
|
+
emojiId: emoji.id,
|
|
133
|
+
emojiText: emoji.fallback
|
|
134
|
+
}, true)(state, dispatch);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
const payload = {
|
|
138
|
+
action: ACTION.CHANGED_ICON,
|
|
139
|
+
actionSubject: ACTION_SUBJECT.PANEL,
|
|
140
|
+
actionSubjectId: ACTION_SUBJECT_ID.PANEL,
|
|
141
|
+
attributes: {
|
|
142
|
+
newIcon: emoji.shortName,
|
|
143
|
+
previousIcon: previousIcon
|
|
144
|
+
},
|
|
145
|
+
eventType: EVENT_TYPE.TRACK
|
|
146
|
+
};
|
|
147
|
+
withAnalytics(editorAnalyticsAPI, payload)(changePanelType(editorAnalyticsAPI)(PanelType.CUSTOM, {
|
|
148
|
+
emoji: emoji.shortName,
|
|
149
|
+
emojiId: emoji.id,
|
|
150
|
+
emojiText: emoji.fallback
|
|
151
|
+
}, true))(state, dispatch);
|
|
152
|
+
return false;
|
|
153
|
+
};
|
|
154
|
+
const removeEmoji = () => (state, dispatch) => {
|
|
155
|
+
const panelNode = findPanel(state);
|
|
156
|
+
if (activePanelType === PanelType.CUSTOM && !activePanelIcon) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
if (panelNode === undefined) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const payload = {
|
|
163
|
+
action: ACTION.REMOVE_ICON,
|
|
164
|
+
actionSubject: ACTION_SUBJECT.PANEL,
|
|
165
|
+
actionSubjectId: ACTION_SUBJECT_ID.PANEL,
|
|
166
|
+
attributes: {
|
|
167
|
+
icon: panelNode.node.attrs.panelIcon
|
|
168
|
+
},
|
|
169
|
+
eventType: EVENT_TYPE.TRACK
|
|
170
|
+
};
|
|
171
|
+
withAnalytics(editorAnalyticsAPI, payload)(changePanelType(editorAnalyticsAPI)(PanelType.CUSTOM, {
|
|
172
|
+
emoji: undefined,
|
|
173
|
+
emojiId: undefined,
|
|
174
|
+
emojiText: undefined
|
|
175
|
+
}, isCustomPanelEnabled))(state, dispatch);
|
|
176
|
+
return false;
|
|
177
|
+
};
|
|
178
|
+
const panelColor = activePanelType === PanelType.CUSTOM ? activePanelColor || getPanelTypeBackgroundNoTokens(PanelType.INFO) : getPanelTypeBackgroundNoTokens(activePanelType);
|
|
179
|
+
const defaultPalette = panelBackgroundPalette.find(item => item.value === panelColor) || {
|
|
180
|
+
label: 'Custom',
|
|
181
|
+
value: panelColor,
|
|
182
|
+
border: DEFAULT_BORDER_COLOR
|
|
183
|
+
};
|
|
184
|
+
if (isCustomPanelEditable) {
|
|
185
|
+
const colorPicker = {
|
|
186
|
+
id: 'editor.panel.colorPicker',
|
|
187
|
+
title: formatMessage(messages.backgroundColor),
|
|
188
|
+
type: 'select',
|
|
189
|
+
selectType: 'color',
|
|
190
|
+
defaultValue: defaultPalette,
|
|
191
|
+
options: panelBackgroundPalette,
|
|
192
|
+
onChange: option => changeColor(option.value)
|
|
193
|
+
};
|
|
194
|
+
const emojiPicker = {
|
|
195
|
+
id: 'editor.panel.emojiPicker',
|
|
196
|
+
title: formatMessage(messages.emoji),
|
|
197
|
+
type: 'select',
|
|
198
|
+
selectType: 'emoji',
|
|
199
|
+
options: [],
|
|
200
|
+
selected: activePanelType === PanelType.CUSTOM && !!activePanelIcon,
|
|
201
|
+
onChange: emoji => changeEmoji(emoji)
|
|
202
|
+
};
|
|
203
|
+
const removeEmojiButton = {
|
|
204
|
+
id: 'editor.panel.removeEmoji',
|
|
205
|
+
type: 'button',
|
|
206
|
+
icon: RemoveEmojiIcon,
|
|
207
|
+
onClick: removeEmoji(),
|
|
208
|
+
title: formatMessage(commonMessages.removeEmoji),
|
|
209
|
+
disabled: activePanelIcon ? false : true
|
|
210
|
+
};
|
|
211
|
+
items.push(emojiPicker, removeEmojiButton, {
|
|
212
|
+
type: 'separator'
|
|
213
|
+
}, colorPicker);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (state) {
|
|
217
|
+
items.push({
|
|
218
|
+
type: 'copy-button',
|
|
219
|
+
items: [{
|
|
220
|
+
type: 'separator'
|
|
221
|
+
}, {
|
|
222
|
+
state,
|
|
223
|
+
formatMessage,
|
|
224
|
+
nodeType: panelNodeType
|
|
225
|
+
}]
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
items.push({
|
|
229
|
+
type: 'separator'
|
|
230
|
+
}, {
|
|
231
|
+
id: 'editor.panel.delete',
|
|
232
|
+
type: 'button',
|
|
233
|
+
appearance: 'danger',
|
|
234
|
+
focusEditoronEnter: true,
|
|
235
|
+
icon: RemoveIcon,
|
|
236
|
+
onClick: removePanel(editorAnalyticsAPI),
|
|
237
|
+
onMouseEnter: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(panelNodeType, true),
|
|
238
|
+
onMouseLeave: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(panelNodeType, false),
|
|
239
|
+
onFocus: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(panelNodeType, true),
|
|
240
|
+
onBlur: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(panelNodeType, false),
|
|
241
|
+
title: formatMessage(commonMessages.remove),
|
|
242
|
+
tabIndex: null
|
|
243
|
+
});
|
|
244
|
+
return items;
|
|
245
|
+
};
|
|
246
|
+
export const getToolbarConfig = (state, intl, options = {}, providerFactory, api) => {
|
|
247
|
+
const {
|
|
248
|
+
formatMessage
|
|
249
|
+
} = intl;
|
|
250
|
+
const panelObject = findPanel(state);
|
|
251
|
+
if (panelObject) {
|
|
252
|
+
var _api$analytics;
|
|
253
|
+
const nodeType = state.schema.nodes.panel;
|
|
254
|
+
const {
|
|
255
|
+
panelType,
|
|
256
|
+
panelColor,
|
|
257
|
+
panelIcon
|
|
258
|
+
} = panelObject.node.attrs;
|
|
259
|
+
const isStandardPanel = panelType => {
|
|
260
|
+
return panelType !== PanelType.CUSTOM ? panelType : undefined;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// force toolbar to be turned on
|
|
264
|
+
const items = getToolbarItems(formatMessage, nodeType, options.allowCustomPanel || false, options.allowCustomPanel && options.allowCustomPanelEdit || false, providerFactory, api === null || api === void 0 ? void 0 : api.decorations.actions.hoverDecoration, api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, panelType, options.allowCustomPanel ? panelColor : undefined, options.allowCustomPanel ? panelIcon || isStandardPanel(panelType) : undefined, state);
|
|
265
|
+
const getDomRef = editorView => {
|
|
266
|
+
const domAtPos = editorView.domAtPos.bind(editorView);
|
|
267
|
+
const element = findDomRefAtPos(panelObject.pos, domAtPos);
|
|
268
|
+
return element;
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
title: 'Panel floating controls',
|
|
272
|
+
getDomRef,
|
|
273
|
+
nodeType,
|
|
274
|
+
items,
|
|
275
|
+
scrollable: true
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
279
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PanelType } from '@atlaskit/adf-schema';
|
|
2
|
+
import { PanelSharedCssClassName } from '@atlaskit/editor-common/panel';
|
|
3
|
+
import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
|
|
4
|
+
import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
export const findPanel = (state, selection) => {
|
|
6
|
+
const {
|
|
7
|
+
panel
|
|
8
|
+
} = state.schema.nodes;
|
|
9
|
+
return findSelectedNodeOfType(panel)(selection || state.selection) || findParentNodeOfType(panel)(selection || state.selection);
|
|
10
|
+
};
|
|
11
|
+
export const panelAttrsToDom = (attrs, allowCustomPanel) => {
|
|
12
|
+
const {
|
|
13
|
+
panelColor,
|
|
14
|
+
panelType,
|
|
15
|
+
panelIcon,
|
|
16
|
+
panelIconId,
|
|
17
|
+
panelIconText
|
|
18
|
+
} = attrs;
|
|
19
|
+
const isCustomPanel = panelType === PanelType.CUSTOM && allowCustomPanel;
|
|
20
|
+
const hasIcon = !isCustomPanel || !!panelIcon || !!panelIconId;
|
|
21
|
+
const tokenColor = panelColor && hexToEditorBackgroundPaletteColor(panelColor);
|
|
22
|
+
const panelBackgroundColor = tokenColor || panelColor;
|
|
23
|
+
const style = [`${panelColor && isCustomPanel ? `background-color: ${panelBackgroundColor};` : ''}`, `${hasIcon ? '' : 'padding-left: 12px;'}`].join('');
|
|
24
|
+
let panelAttrs = {
|
|
25
|
+
class: PanelSharedCssClassName.prefix,
|
|
26
|
+
'data-panel-type': panelType || PanelType.INFO,
|
|
27
|
+
style
|
|
28
|
+
};
|
|
29
|
+
if (panelColor && isCustomPanel) {
|
|
30
|
+
panelAttrs = {
|
|
31
|
+
...panelAttrs,
|
|
32
|
+
'data-panel-color': panelColor,
|
|
33
|
+
'data-panel-icon-id': panelIconId,
|
|
34
|
+
'data-panel-icon-text': panelIconText
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const iconDiv = ['div', {
|
|
38
|
+
class: PanelSharedCssClassName.icon
|
|
39
|
+
}];
|
|
40
|
+
const contentDiv = ['div', {
|
|
41
|
+
class: PanelSharedCssClassName.content
|
|
42
|
+
}, 0];
|
|
43
|
+
if (hasIcon) {
|
|
44
|
+
return ['div', panelAttrs, iconDiv, contentDiv];
|
|
45
|
+
} else {
|
|
46
|
+
return ['div', panelAttrs, contentDiv];
|
|
47
|
+
}
|
|
48
|
+
};
|