@atlaskit/editor-core 179.0.3 → 179.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/CHANGELOG.md +28 -0
- package/dist/cjs/create-editor/ReactEditorView.js +1 -1
- package/dist/cjs/create-editor/create-plugins-list.js +6 -287
- package/dist/cjs/{plugins/feature-flags-context → create-editor}/feature-flags-from-props.js +0 -0
- package/dist/cjs/editor.js +41 -8
- package/dist/cjs/labs/next/presets/universal.js +313 -0
- package/dist/cjs/plugins/card/ui/EditLinkToolbar.js +24 -5
- package/dist/cjs/plugins/floating-toolbar/index.js +6 -0
- package/dist/cjs/plugins/floating-toolbar/pm-plugins/force-focus/index.js +72 -0
- package/dist/cjs/plugins/floating-toolbar/ui/Toolbar.js +12 -9
- package/dist/cjs/plugins/insert-block/ui/ToolbarInsertBlock/block-insert-element-browser.js +3 -1
- package/dist/cjs/plugins/insert-block/ui/ToolbarInsertBlock/index.js +3 -2
- package/dist/cjs/plugins/list/actions/outdent-list-items-selected.js +40 -1
- package/dist/cjs/plugins/list/commands/outdent-list.js +22 -9
- package/dist/cjs/plugins/list/pm-plugins/input-rules/create-list-input-rule.js +30 -12
- package/dist/cjs/plugins/list/utils/analytics.js +18 -2
- package/dist/cjs/plugins/media/commands/linking.js +2 -2
- package/dist/cjs/plugins/media/pm-plugins/alt-text/index.js +1 -12
- package/dist/cjs/plugins/media/toolbar/alt-text.js +14 -3
- package/dist/cjs/plugins/media/toolbar/linking-toolbar-appearance.js +6 -6
- package/dist/cjs/plugins/media/toolbar/linking.js +7 -1
- package/dist/cjs/plugins/paste/handlers.js +7 -5
- package/dist/cjs/plugins/toolbar-lists-indentation/ui/Toolbar.js +17 -0
- package/dist/cjs/plugins/type-ahead/ui/InputQuery.js +13 -13
- package/dist/cjs/test-utils.js +13 -1
- package/dist/cjs/utils/document.js +3 -2
- package/dist/cjs/utils/input-rules.js +3 -2
- package/dist/cjs/utils/lists.js +31 -0
- package/dist/cjs/utils/prepare-quick-insert-provider.js +22 -0
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/create-editor/ReactEditorView.js +1 -1
- package/dist/es2019/create-editor/create-plugins-list.js +5 -293
- package/dist/es2019/{plugins/feature-flags-context → create-editor}/feature-flags-from-props.js +0 -0
- package/dist/es2019/editor.js +41 -7
- package/dist/es2019/labs/next/presets/universal.js +311 -0
- package/dist/es2019/plugins/card/ui/EditLinkToolbar.js +19 -2
- package/dist/es2019/plugins/floating-toolbar/index.js +4 -0
- package/dist/es2019/plugins/floating-toolbar/pm-plugins/force-focus/index.js +59 -0
- package/dist/es2019/plugins/floating-toolbar/ui/Toolbar.js +6 -3
- package/dist/es2019/plugins/insert-block/ui/ToolbarInsertBlock/block-insert-element-browser.js +3 -1
- package/dist/es2019/plugins/insert-block/ui/ToolbarInsertBlock/index.js +3 -2
- package/dist/es2019/plugins/list/actions/outdent-list-items-selected.js +41 -1
- package/dist/es2019/plugins/list/commands/outdent-list.js +16 -1
- package/dist/es2019/plugins/list/pm-plugins/input-rules/create-list-input-rule.js +29 -11
- package/dist/es2019/plugins/list/utils/analytics.js +12 -0
- package/dist/es2019/plugins/media/commands/linking.js +2 -2
- package/dist/es2019/plugins/media/pm-plugins/alt-text/index.js +1 -12
- package/dist/es2019/plugins/media/toolbar/alt-text.js +14 -3
- package/dist/es2019/plugins/media/toolbar/linking-toolbar-appearance.js +6 -6
- package/dist/es2019/plugins/media/toolbar/linking.js +9 -1
- package/dist/es2019/plugins/paste/handlers.js +8 -6
- package/dist/es2019/plugins/toolbar-lists-indentation/ui/Toolbar.js +17 -0
- package/dist/es2019/plugins/type-ahead/ui/InputQuery.js +13 -13
- package/dist/es2019/test-utils.js +11 -1
- package/dist/es2019/utils/document.js +3 -2
- package/dist/es2019/utils/input-rules.js +3 -2
- package/dist/es2019/utils/lists.js +26 -0
- package/dist/es2019/utils/prepare-quick-insert-provider.js +17 -0
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/es2019/version.json +1 -1
- package/dist/esm/create-editor/ReactEditorView.js +1 -1
- package/dist/esm/create-editor/create-plugins-list.js +6 -287
- package/dist/esm/{plugins/feature-flags-context → create-editor}/feature-flags-from-props.js +0 -0
- package/dist/esm/editor.js +41 -8
- package/dist/esm/labs/next/presets/universal.js +306 -0
- package/dist/esm/plugins/card/ui/EditLinkToolbar.js +24 -5
- package/dist/esm/plugins/floating-toolbar/index.js +6 -0
- package/dist/esm/plugins/floating-toolbar/pm-plugins/force-focus/index.js +62 -0
- package/dist/esm/plugins/floating-toolbar/ui/Toolbar.js +12 -9
- package/dist/esm/plugins/insert-block/ui/ToolbarInsertBlock/block-insert-element-browser.js +3 -1
- package/dist/esm/plugins/insert-block/ui/ToolbarInsertBlock/index.js +3 -2
- package/dist/esm/plugins/list/actions/outdent-list-items-selected.js +40 -1
- package/dist/esm/plugins/list/commands/outdent-list.js +15 -2
- package/dist/esm/plugins/list/pm-plugins/input-rules/create-list-input-rule.js +30 -12
- package/dist/esm/plugins/list/utils/analytics.js +12 -0
- package/dist/esm/plugins/media/commands/linking.js +2 -2
- package/dist/esm/plugins/media/pm-plugins/alt-text/index.js +1 -12
- package/dist/esm/plugins/media/toolbar/alt-text.js +14 -3
- package/dist/esm/plugins/media/toolbar/linking-toolbar-appearance.js +6 -6
- package/dist/esm/plugins/media/toolbar/linking.js +7 -1
- package/dist/esm/plugins/paste/handlers.js +8 -6
- package/dist/esm/plugins/toolbar-lists-indentation/ui/Toolbar.js +17 -0
- package/dist/esm/plugins/type-ahead/ui/InputQuery.js +13 -13
- package/dist/esm/test-utils.js +11 -1
- package/dist/esm/utils/document.js +3 -2
- package/dist/esm/utils/input-rules.js +3 -2
- package/dist/esm/utils/lists.js +24 -0
- package/dist/esm/utils/prepare-quick-insert-provider.js +17 -0
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/esm/version.json +1 -1
- package/dist/types/create-editor/create-plugins-list.d.ts +5 -4
- package/dist/types/{plugins/feature-flags-context → create-editor}/feature-flags-from-props.d.ts +2 -2
- package/dist/types/editor.d.ts +42 -0
- package/dist/types/labs/next/presets/universal.d.ts +30 -0
- package/dist/types/plugins/card/ui/EditLinkToolbar.d.ts +4 -0
- package/dist/types/plugins/expand/index.d.ts +4 -1
- package/dist/types/plugins/floating-toolbar/pm-plugins/force-focus/index.d.ts +18 -0
- package/dist/types/plugins/list/utils/analytics.d.ts +5 -2
- package/dist/types/plugins/media/commands/linking.d.ts +1 -1
- package/dist/types/test-utils.d.ts +7 -0
- package/dist/types/types/editor-props.d.ts +96 -92
- package/dist/types/utils/input-rules.d.ts +2 -1
- package/dist/types/utils/lists.d.ts +2 -0
- package/dist/types/utils/prepare-quick-insert-provider.d.ts +16 -0
- package/package.json +8 -8
- package/report.api.md +89 -79
|
@@ -1,27 +1,45 @@
|
|
|
1
1
|
import { ruleWithAnalytics, createWrappingJoinRule } from '../../../../utils/input-rules';
|
|
2
2
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '../../../analytics';
|
|
3
|
+
import { JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST } from '@atlaskit/editor-common/analytics';
|
|
4
|
+
const getOrder = matchResult => Number(matchResult[1]);
|
|
3
5
|
export function createRuleForListType({
|
|
4
6
|
listType,
|
|
5
7
|
expression,
|
|
6
8
|
featureFlags
|
|
7
9
|
}) {
|
|
10
|
+
let joinScenario = JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.NO_JOIN;
|
|
8
11
|
const isBulletList = listType.name === 'bulletList';
|
|
9
12
|
const actionSubjectId = isBulletList ? ACTION_SUBJECT_ID.FORMAT_LIST_BULLET : ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const getAnalyticsPayload = (state, matchResult) => {
|
|
14
|
+
const analyticsPayload = {
|
|
15
|
+
action: ACTION.INSERTED,
|
|
16
|
+
actionSubject: ACTION_SUBJECT.LIST,
|
|
17
|
+
actionSubjectId,
|
|
18
|
+
eventType: EVENT_TYPE.TRACK,
|
|
19
|
+
attributes: {
|
|
20
|
+
inputMethod: INPUT_METHOD.FORMATTING
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists && listType === state.schema.nodes.orderedList && analyticsPayload.attributes) {
|
|
24
|
+
analyticsPayload.attributes.listStartNumber = getOrder(matchResult);
|
|
25
|
+
analyticsPayload.attributes.joinScenario = joinScenario;
|
|
26
|
+
// we reset the tracked joinScenario after storing it in the event payload
|
|
27
|
+
joinScenario = JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.NO_JOIN;
|
|
28
|
+
}
|
|
29
|
+
return analyticsPayload;
|
|
30
|
+
};
|
|
31
|
+
const joinToNeighbourIfSameListType = (_, node, scenario) => {
|
|
32
|
+
const shouldJoin = node.type === listType;
|
|
33
|
+
if (shouldJoin) {
|
|
34
|
+
joinScenario = scenario;
|
|
17
35
|
}
|
|
36
|
+
return shouldJoin;
|
|
18
37
|
};
|
|
19
|
-
const shouldJoinNextNodeWhen = (_, node) => node.type === listType;
|
|
20
38
|
let getAttrs = {};
|
|
21
39
|
if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
|
|
22
40
|
getAttrs = matchResult => {
|
|
23
41
|
return {
|
|
24
|
-
order:
|
|
42
|
+
order: getOrder(matchResult)
|
|
25
43
|
};
|
|
26
44
|
};
|
|
27
45
|
}
|
|
@@ -29,7 +47,7 @@ export function createRuleForListType({
|
|
|
29
47
|
match: expression,
|
|
30
48
|
nodeType: listType,
|
|
31
49
|
getAttrs,
|
|
32
|
-
joinPredicate:
|
|
50
|
+
joinPredicate: joinToNeighbourIfSameListType
|
|
33
51
|
});
|
|
34
|
-
return ruleWithAnalytics(
|
|
52
|
+
return ruleWithAnalytics(getAnalyticsPayload)(inputRule);
|
|
35
53
|
}
|
|
@@ -33,4 +33,16 @@ export const countListItemsInSelection = state => {
|
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
return count;
|
|
36
|
+
};
|
|
37
|
+
export const RESTART_LISTS_ANALYTICS_KEY = 'restartListsAnalytics';
|
|
38
|
+
export const getRestartListsAttributes = tr => {
|
|
39
|
+
var _tr$getMeta;
|
|
40
|
+
return (_tr$getMeta = tr.getMeta(RESTART_LISTS_ANALYTICS_KEY)) !== null && _tr$getMeta !== void 0 ? _tr$getMeta : {};
|
|
41
|
+
};
|
|
42
|
+
export const storeRestartListsAttributes = (tr, attributes) => {
|
|
43
|
+
const meta = getRestartListsAttributes(tr);
|
|
44
|
+
tr.setMeta(RESTART_LISTS_ANALYTICS_KEY, {
|
|
45
|
+
...meta,
|
|
46
|
+
...attributes
|
|
47
|
+
});
|
|
36
48
|
};
|
|
@@ -45,11 +45,11 @@ export const showLinkingToolbarWithMediaTypeCheck = (editorState, dispatch, edit
|
|
|
45
45
|
const hideLinkingToolbarCommand = createMediaLinkingCommand({
|
|
46
46
|
type: MediaLinkingActionsTypes.hideToolbar
|
|
47
47
|
});
|
|
48
|
-
export const hideLinkingToolbar = (state, dispatch, view) => {
|
|
48
|
+
export const hideLinkingToolbar = (state, dispatch, view, focusFloatingToolbar) => {
|
|
49
49
|
hideLinkingToolbarCommand(state, dispatch, view);
|
|
50
50
|
|
|
51
51
|
// restore focus on the editor so keyboard shortcuts aren't lost to the browser
|
|
52
|
-
if (view) {
|
|
52
|
+
if (view && !focusFloatingToolbar) {
|
|
53
53
|
view.focus();
|
|
54
54
|
}
|
|
55
55
|
};
|
|
@@ -27,18 +27,7 @@ export const createPlugin = ({
|
|
|
27
27
|
state: createPluginState(dispatch, {
|
|
28
28
|
isAltTextEditorOpen: false
|
|
29
29
|
}),
|
|
30
|
-
key: pluginKey
|
|
31
|
-
view: () => {
|
|
32
|
-
return {
|
|
33
|
-
update: (view, prev) => {
|
|
34
|
-
const pluginState = getPluginState(view.state);
|
|
35
|
-
const oldPluginState = getPluginState(prev);
|
|
36
|
-
if (pluginState && oldPluginState && oldPluginState.isAltTextEditorOpen && !pluginState.isAltTextEditorOpen && !view.hasFocus()) {
|
|
37
|
-
view.focus();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
30
|
+
key: pluginKey
|
|
42
31
|
});
|
|
43
32
|
};
|
|
44
33
|
export { createCommand, getPluginState };
|
|
@@ -6,6 +6,9 @@ import AltTextEdit from '../pm-plugins/alt-text/ui/AltTextEdit';
|
|
|
6
6
|
import { CONTAINER_WIDTH_IN_PX } from '../pm-plugins/alt-text/ui/AltTextEdit';
|
|
7
7
|
import { getMediaNodeFromSelection } from '../utils/media-common';
|
|
8
8
|
import { ClassNames } from '../pm-plugins/alt-text/style';
|
|
9
|
+
import { withOuterListeners } from '@atlaskit/editor-common/ui';
|
|
10
|
+
import { forceFocusSelector } from '../../floating-toolbar/pm-plugins/force-focus';
|
|
11
|
+
const testId = 'alt-text-edit-button';
|
|
9
12
|
export const altTextButton = (intl, state) => {
|
|
10
13
|
const mediaNode = getMediaNodeFromSelection(state);
|
|
11
14
|
const message = mediaNode && mediaNode.attrs.alt ? messages.editAltText : messages.altText;
|
|
@@ -16,13 +19,14 @@ export const altTextButton = (intl, state) => {
|
|
|
16
19
|
type: 'button',
|
|
17
20
|
onClick: openMediaAltTextMenu,
|
|
18
21
|
showTitle: true,
|
|
19
|
-
testId
|
|
22
|
+
testId,
|
|
20
23
|
tooltipContent: /*#__PURE__*/React.createElement(ToolTipContent, {
|
|
21
24
|
description: title,
|
|
22
25
|
keymap: addAltText
|
|
23
26
|
})
|
|
24
27
|
};
|
|
25
28
|
};
|
|
29
|
+
const AltTextEditWithListeners = withOuterListeners(AltTextEdit);
|
|
26
30
|
export const altTextEditComponent = options => {
|
|
27
31
|
return {
|
|
28
32
|
type: 'custom',
|
|
@@ -36,11 +40,18 @@ export const altTextEditComponent = options => {
|
|
|
36
40
|
if (!mediaNode) {
|
|
37
41
|
return null;
|
|
38
42
|
}
|
|
39
|
-
|
|
43
|
+
/** Focus should move to the 'Alt text' button when the toolbar closes
|
|
44
|
+
* and not close the floating toolbar.
|
|
45
|
+
*/
|
|
46
|
+
const handleEsc = e => {
|
|
47
|
+
forceFocusSelector(`[data-testid="${testId}"]`, view);
|
|
48
|
+
};
|
|
49
|
+
return /*#__PURE__*/React.createElement(AltTextEditWithListeners, {
|
|
40
50
|
view: view,
|
|
41
51
|
key: idx,
|
|
42
52
|
value: mediaNode.attrs.alt,
|
|
43
|
-
altTextValidator: options && options.altTextValidator
|
|
53
|
+
altTextValidator: options && options.altTextValidator,
|
|
54
|
+
handleEscapeKeydown: handleEsc
|
|
44
55
|
});
|
|
45
56
|
}
|
|
46
57
|
};
|
|
@@ -25,22 +25,21 @@ export const LinkToolbarAppearance = ({
|
|
|
25
25
|
onEditLink,
|
|
26
26
|
onOpenLink
|
|
27
27
|
}) => {
|
|
28
|
-
const [showLinkingControls, setShowLinkingControls] = useState(
|
|
28
|
+
const [showLinkingControls, setShowLinkingControls] = useState(true);
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
var _stateKey$getState;
|
|
31
|
-
setShowLinkingControls(false);
|
|
32
31
|
const mediaNode = currentMediaNode(editorState);
|
|
33
32
|
if (!mediaNode) {
|
|
33
|
+
setShowLinkingControls(false);
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
const mediaClientConfig = (_stateKey$getState = stateKey.getState(editorState)) === null || _stateKey$getState === void 0 ? void 0 : _stateKey$getState.mediaClientConfig;
|
|
37
37
|
if (!mediaClientConfig) {
|
|
38
|
+
setShowLinkingControls(false);
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
checkMediaType(mediaNode, mediaClientConfig).then(mediaType => {
|
|
41
|
-
|
|
42
|
-
setShowLinkingControls(true);
|
|
43
|
-
}
|
|
42
|
+
setShowLinkingControls(mediaType === 'external' || mediaType === 'image');
|
|
44
43
|
});
|
|
45
44
|
}, [editorState]);
|
|
46
45
|
if (!showLinkingControls) {
|
|
@@ -58,7 +57,8 @@ export const LinkToolbarAppearance = ({
|
|
|
58
57
|
tooltipContent: jsx(ToolTipContent, {
|
|
59
58
|
description: title,
|
|
60
59
|
keymap: addLink
|
|
61
|
-
})
|
|
60
|
+
}),
|
|
61
|
+
testId: "edit-link-button"
|
|
62
62
|
}, title)), jsx("div", {
|
|
63
63
|
css: wrapper
|
|
64
64
|
}, jsx(Separator, null)), jsx(ToolbarButton, {
|
|
@@ -3,6 +3,8 @@ import { hideLinkingToolbar, setUrlToMedia, unlink } from '../commands/linking';
|
|
|
3
3
|
import { getMediaLinkingState } from '../pm-plugins/linking';
|
|
4
4
|
import MediaLinkingToolbar from '../ui/MediaLinkingToolbar';
|
|
5
5
|
import { RECENT_SEARCH_HEIGHT_IN_PX, RECENT_SEARCH_WIDTH_IN_PX } from '../../../ui/LinkSearch/ToolbarComponents';
|
|
6
|
+
import { forceFocusSelector } from '../../floating-toolbar/pm-plugins/force-focus';
|
|
7
|
+
const FORCE_FOCUS_SELECTOR = '[data-testid="add-link-button"],[data-testid="edit-link-button"]';
|
|
6
8
|
export function shouldShowMediaLinkToolbar(editorState) {
|
|
7
9
|
const mediaLinkingState = getMediaLinkingState(editorState);
|
|
8
10
|
if (!mediaLinkingState || mediaLinkingState.mediaPos === null) {
|
|
@@ -61,7 +63,13 @@ export const getLinkingToolbar = (toolbarBaseConfig, mediaLinkingState, state, i
|
|
|
61
63
|
}
|
|
62
64
|
hideLinkingToolbar(view.state, view.dispatch, view);
|
|
63
65
|
},
|
|
64
|
-
onCancel: () =>
|
|
66
|
+
onCancel: () => {
|
|
67
|
+
hideLinkingToolbar(view.state, view.dispatch, view, true);
|
|
68
|
+
/** Focus should move to the 'Add link' button when the toolbar closes
|
|
69
|
+
* and not close the floating toolbar.
|
|
70
|
+
*/
|
|
71
|
+
forceFocusSelector(FORCE_FOCUS_SELECTOR, view);
|
|
72
|
+
},
|
|
65
73
|
onSubmit: (href, meta) => {
|
|
66
74
|
setUrlToMedia(href, meta.inputMethod)(view.state, view.dispatch, view);
|
|
67
75
|
hideLinkingToolbar(view.state, view.dispatch, view);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { closeHistory } from 'prosemirror-history';
|
|
2
2
|
import { Fragment, Node as PMNode, Slice } from 'prosemirror-model';
|
|
3
3
|
import { TextSelection, NodeSelection } from 'prosemirror-state';
|
|
4
|
-
import { findParentNodeOfType, hasParentNodeOfType, safeInsert } from 'prosemirror-utils';
|
|
4
|
+
import { canInsert, findParentNodeOfType, hasParentNodeOfType, safeInsert } from 'prosemirror-utils';
|
|
5
5
|
import uuid from 'uuid/v4';
|
|
6
6
|
import { replaceSelectedTable } from '@atlaskit/editor-tables/utils';
|
|
7
7
|
import { compose, insideTable, isParagraph, isText, isLinkMark, insideTableCell, isInListItem } from '../../utils';
|
|
@@ -19,6 +19,7 @@ import { canLinkBeCreatedInRange } from '../hyperlink/pm-plugins/main';
|
|
|
19
19
|
import { insertSliceForLists } from './edge-cases';
|
|
20
20
|
import { startTrackingPastedMacroPositions, stopTrackingPastedMacroPositions } from './commands';
|
|
21
21
|
import { getPluginState as getPastePluginState } from './pm-plugins/plugin-factory';
|
|
22
|
+
import { doesSelectionWhichStartsOrEndsInListContainEntireList } from '../../utils/lists';
|
|
22
23
|
|
|
23
24
|
// remove text attribute from mention for copy/paste (GDPR)
|
|
24
25
|
export function handleMention(slice, schema) {
|
|
@@ -93,7 +94,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice) {
|
|
|
93
94
|
}
|
|
94
95
|
const transformedSlice = compose.apply(null, filters)(slice);
|
|
95
96
|
const tr = closeHistory(state.tr);
|
|
96
|
-
const transformedSliceIsValidNode = transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskList', 'taskItem', 'panel'].includes(transformedSlice.content.firstChild.type.name);
|
|
97
|
+
const transformedSliceIsValidNode = transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskList', 'taskItem', 'panel'].includes(transformedSlice.content.firstChild.type.name) && !isInListItem(state);
|
|
97
98
|
// If the slice or the selection are valid nodes to handle,
|
|
98
99
|
// and the slice is not a whole node (i.e. openStart is 1 and openEnd is 0)
|
|
99
100
|
// or the slice's first node is a paragraph,
|
|
@@ -120,11 +121,12 @@ export function handlePastePanelIntoList(slice) {
|
|
|
120
121
|
const {
|
|
121
122
|
selection
|
|
122
123
|
} = tr;
|
|
123
|
-
|
|
124
124
|
// Check this pasting action is related to copy content from panel node into a selected the list node
|
|
125
|
-
const selectionParentListNode = selection.$to.node(selection.$to.depth - 1);
|
|
126
125
|
const panelNode = slice.content.firstChild;
|
|
127
|
-
|
|
126
|
+
const isSliceWholeNode = slice.openStart === 0 && slice.openEnd === 0;
|
|
127
|
+
const selectionParentListItemNode = selection.$to.node(selection.$to.depth - 1);
|
|
128
|
+
const sliceIsWholeNodeButShouldNotReplaceSelection = isSliceWholeNode && !doesSelectionWhichStartsOrEndsInListContainEntireList(selection);
|
|
129
|
+
if (!dispatch || !selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !panelNode || (panelNode === null || panelNode === void 0 ? void 0 : panelNode.type) !== schema.nodes.panel || (panelNode === null || panelNode === void 0 ? void 0 : panelNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
|
|
128
130
|
return false;
|
|
129
131
|
}
|
|
130
132
|
|
|
@@ -679,7 +681,7 @@ export function handleRichText(slice) {
|
|
|
679
681
|
return false;
|
|
680
682
|
}
|
|
681
683
|
});
|
|
682
|
-
if (insideTableCell(state) && (!doesBlockNodeExist || isInListItem(state)) || sliceHasList) {
|
|
684
|
+
if (insideTableCell(state) && (!doesBlockNodeExist || isInListItem(state) && canInsert(selection.$from, slice.content) && canInsert(selection.$to, slice.content)) || sliceHasList) {
|
|
683
685
|
tr.replaceSelection(slice);
|
|
684
686
|
} else {
|
|
685
687
|
// need safeInsert rather than replaceSelection, so that nodes aren't split in half
|
|
@@ -11,10 +11,13 @@ import { messages } from '../../list/messages';
|
|
|
11
11
|
import { messages as indentationMessages } from '../../indentation/messages';
|
|
12
12
|
import { buttonGroupStyle, separatorStyles } from '../../../ui/styles';
|
|
13
13
|
import { getAriaKeyshortcuts } from '@atlaskit/editor-common/keymaps';
|
|
14
|
+
import { useEffect, useRef } from 'react';
|
|
14
15
|
export function Toolbar(props) {
|
|
15
16
|
const {
|
|
16
17
|
formatMessage
|
|
17
18
|
} = useIntl();
|
|
19
|
+
const indentButtonRef = useRef(null);
|
|
20
|
+
const outdentButtonRef = useRef(null);
|
|
18
21
|
const {
|
|
19
22
|
disabled,
|
|
20
23
|
isReducedSpacing,
|
|
@@ -31,10 +34,22 @@ export function Toolbar(props) {
|
|
|
31
34
|
const labelOrderedList = formatMessage(messages.orderedList);
|
|
32
35
|
const indentMessage = formatMessage(indentationMessages.indent);
|
|
33
36
|
const outdentMessage = formatMessage(indentationMessages.outdent);
|
|
37
|
+
const isIndentButtonFocused = document.activeElement === indentButtonRef.current;
|
|
38
|
+
const isOutdentButtonFocused = document.activeElement === outdentButtonRef.current;
|
|
34
39
|
const handleOnItemActivated = buttonName => event => onItemActivated({
|
|
35
40
|
editorView: props.editorView,
|
|
36
41
|
buttonName
|
|
37
42
|
});
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (isIndentButtonFocused && indentDisabled && outdentButtonRef.current) {
|
|
45
|
+
outdentButtonRef.current.focus();
|
|
46
|
+
}
|
|
47
|
+
}, [indentButtonRef, indentDisabled, isIndentButtonFocused]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (isOutdentButtonFocused && outdentDisabled && indentButtonRef.current) {
|
|
50
|
+
indentButtonRef.current.focus();
|
|
51
|
+
}
|
|
52
|
+
}, [outdentButtonRef, outdentDisabled, isOutdentButtonFocused]);
|
|
38
53
|
return jsx("span", {
|
|
39
54
|
css: buttonGroupStyle
|
|
40
55
|
}, jsx(ToolbarButton, {
|
|
@@ -74,6 +89,7 @@ export function Toolbar(props) {
|
|
|
74
89
|
}), showIndentationButtons && jsx(ToolbarButton, {
|
|
75
90
|
buttonId: TOOLBAR_BUTTON.OUTDENT,
|
|
76
91
|
testId: TOOLBAR_BUTTON.OUTDENT,
|
|
92
|
+
ref: outdentButtonRef,
|
|
77
93
|
spacing: isReducedSpacing ? 'none' : 'default',
|
|
78
94
|
onClick: handleOnItemActivated('outdent'),
|
|
79
95
|
iconBefore: jsx(OutdentIcon, {
|
|
@@ -89,6 +105,7 @@ export function Toolbar(props) {
|
|
|
89
105
|
}), showIndentationButtons && jsx(ToolbarButton, {
|
|
90
106
|
buttonId: TOOLBAR_BUTTON.INDENT,
|
|
91
107
|
testId: TOOLBAR_BUTTON.INDENT,
|
|
108
|
+
ref: indentButtonRef,
|
|
92
109
|
spacing: isReducedSpacing ? 'none' : 'default',
|
|
93
110
|
onClick: handleOnItemActivated('indent'),
|
|
94
111
|
iconBefore: jsx(IndentIcon, {
|
|
@@ -184,20 +184,20 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
184
184
|
return false;
|
|
185
185
|
}, [onQueryFocus]);
|
|
186
186
|
const queryStyle = css({
|
|
187
|
-
outline: 'none',
|
|
188
|
-
position: 'absolute',
|
|
189
|
-
fontFamily: 'inherit',
|
|
190
|
-
fontSize: 'inherit',
|
|
191
|
-
fontWeight: 'inherit',
|
|
192
|
-
letterSpacing: 'inherit',
|
|
193
|
-
padding: 0,
|
|
194
|
-
height: '100%',
|
|
195
|
-
width: '100%',
|
|
196
|
-
top: 0,
|
|
197
|
-
left: 0,
|
|
198
|
-
background: 'transparent',
|
|
199
|
-
border: 'none',
|
|
200
187
|
'&&': {
|
|
188
|
+
outline: 'none',
|
|
189
|
+
position: 'absolute',
|
|
190
|
+
fontFamily: 'inherit',
|
|
191
|
+
fontSize: 'inherit',
|
|
192
|
+
fontWeight: 'inherit',
|
|
193
|
+
letterSpacing: 'inherit',
|
|
194
|
+
padding: 0,
|
|
195
|
+
height: '100%',
|
|
196
|
+
width: '100%',
|
|
197
|
+
top: 0,
|
|
198
|
+
left: 0,
|
|
199
|
+
background: 'transparent',
|
|
200
|
+
border: 'none',
|
|
201
201
|
color: `${`var(--ds-link, ${colors.B400})`}`
|
|
202
202
|
}
|
|
203
203
|
});
|
|
@@ -79,4 +79,14 @@ export function setTextSelection(view, anchor, head) {
|
|
|
79
79
|
} = view;
|
|
80
80
|
const tr = state.tr.setSelection(TextSelection.create(state.doc, anchor, head));
|
|
81
81
|
view.dispatch(tr);
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Given a selector, checks if an element matching the selector exists in the
|
|
86
|
+
* document.
|
|
87
|
+
* @param selector
|
|
88
|
+
* @returns true if element matching selector exists in document, false otherwise
|
|
89
|
+
*/
|
|
90
|
+
export const isElementBySelectorInDocument = selector => {
|
|
91
|
+
return Boolean(document.querySelector(selector));
|
|
92
|
+
};
|
|
@@ -28,7 +28,8 @@ export function hasVisibleContent(node) {
|
|
|
28
28
|
}
|
|
29
29
|
for (let index = 0; index < node.childCount; index++) {
|
|
30
30
|
const child = node.child(index);
|
|
31
|
-
|
|
31
|
+
const invisibleNodeTypes = ['paragraph', 'text', 'hardBreak'];
|
|
32
|
+
if (!invisibleNodeTypes.includes(child.type.name) || hasVisibleContent(child)) {
|
|
32
33
|
return true;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
@@ -269,7 +270,7 @@ export function processRawValue(schema, value, providerFactory, sanitizePrivateC
|
|
|
269
270
|
action: ACTION.DOCUMENT_PROCESSING_ERROR,
|
|
270
271
|
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
271
272
|
eventType: EVENT_TYPE.OPERATIONAL,
|
|
272
|
-
|
|
273
|
+
nonPrivacySafeAttributes: {
|
|
273
274
|
errorStack: e instanceof Error ? e.stack : String(e)
|
|
274
275
|
}
|
|
275
276
|
});
|
|
@@ -3,6 +3,7 @@ import { canJoin, findWrapping } from 'prosemirror-transform';
|
|
|
3
3
|
import { GapCursorSelection } from '@atlaskit/editor-common/selection';
|
|
4
4
|
import { createInputRulePlugin } from '@atlaskit/prosemirror-input-rules';
|
|
5
5
|
import { addAnalytics } from '../plugins/analytics';
|
|
6
|
+
import { JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST } from '@atlaskit/editor-common/analytics';
|
|
6
7
|
import { closeHistory } from 'prosemirror-history';
|
|
7
8
|
import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
|
|
8
9
|
import { getFeatureFlags } from '../plugins/feature-flags-context';
|
|
@@ -121,13 +122,13 @@ export const createWrappingJoinRule = ({
|
|
|
121
122
|
if (node) {
|
|
122
123
|
const nodeEnd = node.pos + node.node.nodeSize;
|
|
123
124
|
const after = tr.doc.resolve(nodeEnd).nodeAfter;
|
|
124
|
-
if (after && after.type === nodeType && canJoin(tr.doc, nodeEnd) && (!joinPredicate || joinPredicate(match, after))) {
|
|
125
|
+
if (after && after.type === nodeType && canJoin(tr.doc, nodeEnd) && (!joinPredicate || joinPredicate(match, after, JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.JOINED_TO_LIST_BELOW))) {
|
|
125
126
|
tr.join(nodeEnd);
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
const before = tr.doc.resolve(fixedStart - 1).nodeBefore;
|
|
130
|
-
if (before && before.type === nodeType && canJoin(tr.doc, fixedStart - 1) && (!joinPredicate || joinPredicate(match, before))) {
|
|
131
|
+
if (before && before.type === nodeType && canJoin(tr.doc, fixedStart - 1) && (!joinPredicate || joinPredicate(match, before, JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.JOINED_TO_LIST_ABOVE))) {
|
|
131
132
|
tr.join(fixedStart - 1);
|
|
132
133
|
}
|
|
133
134
|
return tr;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { findRootParentListNode } from '../plugins/list/utils/find';
|
|
2
|
+
export const doesSelectionWhichStartsOrEndsInListContainEntireList = selection => {
|
|
3
|
+
const {
|
|
4
|
+
$from,
|
|
5
|
+
$to,
|
|
6
|
+
from,
|
|
7
|
+
to
|
|
8
|
+
} = selection;
|
|
9
|
+
const selectionParentListItemNodeResolvedPos = findRootParentListNode($from) || findRootParentListNode($to);
|
|
10
|
+
const selectionParentListNode = selectionParentListItemNodeResolvedPos === null || selectionParentListItemNodeResolvedPos === void 0 ? void 0 : selectionParentListItemNodeResolvedPos.parent;
|
|
11
|
+
if (!selectionParentListItemNodeResolvedPos || !selectionParentListNode) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const startOfEntireList = $from.pos < $to.pos ? selectionParentListItemNodeResolvedPos.pos + $from.depth - 1 : selectionParentListItemNodeResolvedPos.pos + $to.depth - 1;
|
|
15
|
+
const endOfEntireList = $from.pos < $to.pos ? selectionParentListItemNodeResolvedPos.pos + selectionParentListNode.nodeSize - $to.depth - 1 : selectionParentListItemNodeResolvedPos.pos + selectionParentListNode.nodeSize - $from.depth - 1;
|
|
16
|
+
if (!startOfEntireList || !endOfEntireList) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (from < to) {
|
|
20
|
+
return startOfEntireList >= $from.pos && endOfEntireList <= $to.pos;
|
|
21
|
+
} else if (from > to) {
|
|
22
|
+
return startOfEntireList >= $to.pos && endOfEntireList <= $from.pos;
|
|
23
|
+
} else {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { extensionProviderToQuickInsertProvider, combineQuickInsertProviders } from './extensions';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Used to combine the quickInsert provider and extension provider (if available)
|
|
6
|
+
* Or return a provider that is available (quickInsertProvider preferred)
|
|
7
|
+
* @param editorActions
|
|
8
|
+
* @param extensionProvider
|
|
9
|
+
* @param quickInsert
|
|
10
|
+
* @param createAnalyticsEvent
|
|
11
|
+
* @returns Quick insert provider if available
|
|
12
|
+
*/
|
|
13
|
+
export default function prepareQuickInsertProvider(editorActions, extensionProvider, quickInsert, createAnalyticsEvent) {
|
|
14
|
+
const quickInsertProvider = quickInsert && typeof quickInsert !== 'boolean' && quickInsert.provider;
|
|
15
|
+
const extensionQuickInsertProvider = extensionProvider && extensionProviderToQuickInsertProvider(extensionProvider, editorActions, createAnalyticsEvent);
|
|
16
|
+
return quickInsertProvider && extensionQuickInsertProvider ? combineQuickInsertProviders([quickInsertProvider, extensionQuickInsertProvider]) : quickInsertProvider || extensionQuickInsertProvider;
|
|
17
|
+
}
|
package/dist/es2019/version.json
CHANGED
|
@@ -26,7 +26,7 @@ import { RenderTracking } from '../utils/performance/components/RenderTracking';
|
|
|
26
26
|
import { findChangedNodesFromTransaction, validateNodes, validNode } from '../utils/nodes';
|
|
27
27
|
import createPluginList from './create-plugins-list';
|
|
28
28
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent, FULL_WIDTH_MODE, getAnalyticsEventsFromTransaction, PLATFORMS } from '../plugins/analytics';
|
|
29
|
-
import { createFeatureFlagsFromProps } from '
|
|
29
|
+
import { createFeatureFlagsFromProps } from './feature-flags-from-props';
|
|
30
30
|
import { getEnabledFeatureFlagKeys } from '../plugins/feature-flags-context/get-enabled-feature-flag-keys';
|
|
31
31
|
import { createErrorReporter, createPMPlugins, processPluginsList } from './create-editor';
|
|
32
32
|
import { getDocStructure } from '../utils/document-logger';
|