@atlaskit/editor-plugin-block-menu 5.2.6 → 5.2.8
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 +15 -0
- package/afm-cc/tsconfig.json +3 -0
- package/afm-jira/tsconfig.json +3 -0
- package/afm-products/tsconfig.json +3 -0
- package/dist/cjs/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js +91 -0
- package/dist/cjs/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +1 -5
- package/dist/cjs/editor-commands/transform-node-utils/transform.js +11 -3
- package/dist/cjs/editor-commands/transform-node-utils/utils.js +17 -1
- package/dist/cjs/editor-commands/transform-node-utils/wrapIntoListStep.js +17 -0
- package/dist/cjs/editor-commands/transformNode.js +13 -4
- package/dist/cjs/ui/block-menu-provider.js +0 -11
- package/dist/cjs/ui/move-down.js +4 -8
- package/dist/cjs/ui/move-up.js +5 -9
- package/dist/es2019/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js +88 -0
- package/dist/es2019/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +1 -5
- package/dist/es2019/editor-commands/transform-node-utils/transform.js +11 -3
- package/dist/es2019/editor-commands/transform-node-utils/utils.js +17 -1
- package/dist/es2019/editor-commands/transform-node-utils/wrapIntoListStep.js +13 -0
- package/dist/es2019/editor-commands/transformNode.js +15 -4
- package/dist/es2019/ui/block-menu-provider.js +0 -11
- package/dist/es2019/ui/move-down.js +4 -8
- package/dist/es2019/ui/move-up.js +5 -9
- package/dist/esm/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js +86 -0
- package/dist/esm/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +1 -5
- package/dist/esm/editor-commands/transform-node-utils/transform.js +11 -3
- package/dist/esm/editor-commands/transform-node-utils/utils.js +17 -1
- package/dist/esm/editor-commands/transform-node-utils/wrapIntoListStep.js +11 -0
- package/dist/esm/editor-commands/transformNode.js +13 -4
- package/dist/esm/ui/block-menu-provider.js +0 -11
- package/dist/esm/ui/move-down.js +4 -8
- package/dist/esm/ui/move-up.js +5 -9
- package/dist/types/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.d.ts +15 -0
- package/dist/types/editor-commands/transform-node-utils/wrapIntoListStep.d.ts +3 -0
- package/dist/types/ui/block-menu-provider.d.ts +0 -5
- package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.d.ts +15 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/wrapIntoListStep.d.ts +3 -0
- package/dist/types-ts4.5/ui/block-menu-provider.d.ts +0 -5
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-menu
|
|
2
2
|
|
|
3
|
+
## 5.2.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`0006edf16b3a3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0006edf16b3a3) -
|
|
8
|
+
Editor-2778: Media wrap in container
|
|
9
|
+
|
|
10
|
+
## 5.2.7
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [`b2e5262017fa8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b2e5262017fa8) -
|
|
15
|
+
Editor-2676: Remove moveFocusTo in block menu provider
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
|
|
3
18
|
## 5.2.6
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/afm-cc/tsconfig.json
CHANGED
package/afm-jira/tsconfig.json
CHANGED
package/dist/cjs/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wrapBlockquoteToDecisionListStep = void 0;
|
|
7
|
+
var _types = require("../types");
|
|
8
|
+
/**
|
|
9
|
+
* Determines if a node is a text node (heading or paragraph).
|
|
10
|
+
* Only text nodes should have their inline content extracted for decisionItem.
|
|
11
|
+
* All other nodes should break out.
|
|
12
|
+
*/
|
|
13
|
+
var isTextNode = function isTextNode(node) {
|
|
14
|
+
var category = _types.NODE_CATEGORY_BY_TYPE[node.type.name];
|
|
15
|
+
return category === 'text';
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a decisionItem with the given inline content.
|
|
20
|
+
*/
|
|
21
|
+
var createDecisionItem = function createDecisionItem(inlineContent, schema) {
|
|
22
|
+
var decisionItemType = schema.nodes.decisionItem;
|
|
23
|
+
if (!decisionItemType) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
var canContentBeWrappedInDecisionItem = decisionItemType.validContent(inlineContent);
|
|
27
|
+
|
|
28
|
+
// Check if the content is valid for decisionItem
|
|
29
|
+
if (!canContentBeWrappedInDecisionItem) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return decisionItemType.createAndFill({}, inlineContent);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a decisionList containing the given decisionItems.
|
|
37
|
+
*/
|
|
38
|
+
var createDecisionListWithItems = function createDecisionListWithItems(decisionItems, schema) {
|
|
39
|
+
var decisionListType = schema.nodes.decisionList;
|
|
40
|
+
if (!decisionListType || decisionItems.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return decisionListType.createAndFill({}, decisionItems);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Wraps blockquote content into decisionList:
|
|
48
|
+
* - Text nodes (paragraph, heading) have their inline content extracted and wrapped in decisionItems
|
|
49
|
+
* - Consecutive text nodes are grouped into a single decisionList with multiple decisionItems
|
|
50
|
+
* - All other nodes break out (lists, code blocks, media, tables, macros, containers, etc.)
|
|
51
|
+
*
|
|
52
|
+
* The logic follows the transform rules:
|
|
53
|
+
* - Only flatten text nodes into decisionItem (since that's the intent - converting text to decisions)
|
|
54
|
+
* - Structures that can't be represented in a decisionItem should break out unchanged
|
|
55
|
+
* - When a break-out node is encountered, flush accumulated decisionItems into a decisionList
|
|
56
|
+
*
|
|
57
|
+
* Example: blockquote(p('a'), p('b'), ul(...), p('c')) → [decisionList(decisionItem('a'), decisionItem('b')), ul(...), decisionList(decisionItem('c'))]
|
|
58
|
+
*/
|
|
59
|
+
var wrapBlockquoteToDecisionListStep = exports.wrapBlockquoteToDecisionListStep = function wrapBlockquoteToDecisionListStep(nodes, context) {
|
|
60
|
+
var schema = context.schema;
|
|
61
|
+
var decisionItemType = schema.nodes.decisionItem;
|
|
62
|
+
if (!decisionItemType) {
|
|
63
|
+
return nodes;
|
|
64
|
+
}
|
|
65
|
+
var result = [];
|
|
66
|
+
var currentDecisionItems = [];
|
|
67
|
+
var flushCurrentDecisionList = function flushCurrentDecisionList() {
|
|
68
|
+
if (currentDecisionItems.length > 0) {
|
|
69
|
+
var decisionList = createDecisionListWithItems(currentDecisionItems, schema);
|
|
70
|
+
if (decisionList) {
|
|
71
|
+
result.push(decisionList);
|
|
72
|
+
}
|
|
73
|
+
currentDecisionItems = [];
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
nodes.forEach(function (node) {
|
|
77
|
+
var decisionItem = isTextNode(node) ? createDecisionItem(node.content, schema) : null;
|
|
78
|
+
if (decisionItem) {
|
|
79
|
+
// Accumulate consecutive decisionItems
|
|
80
|
+
currentDecisionItems.push(decisionItem);
|
|
81
|
+
} else {
|
|
82
|
+
// Content can't be wrapped in decisionItem - break out the node
|
|
83
|
+
flushCurrentDecisionList();
|
|
84
|
+
result.push(node);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Flush any remaining decisionItems
|
|
89
|
+
flushCurrentDecisionList();
|
|
90
|
+
return result.length > 0 ? result : nodes;
|
|
91
|
+
};
|
|
@@ -45,11 +45,7 @@ var canWrapInTarget = function canWrapInTarget(node, targetNodeType, targetNodeT
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// Use the schema to determine if this node can be contained in the target
|
|
48
|
-
|
|
49
|
-
return targetNodeType.validContent(_model.Fragment.from(node));
|
|
50
|
-
} catch (_unused) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
48
|
+
return targetNodeType.validContent(_model.Fragment.from(node));
|
|
53
49
|
};
|
|
54
50
|
|
|
55
51
|
/**
|
|
@@ -12,12 +12,14 @@ var _listToDecisionListStep = require("./steps/listToDecisionListStep");
|
|
|
12
12
|
var _listToListStep = require("./steps/listToListStep");
|
|
13
13
|
var _unwrapLayoutStep = require("./steps/unwrapLayoutStep");
|
|
14
14
|
var _unwrapListStep = require("./steps/unwrapListStep");
|
|
15
|
+
var _wrapBlockquoteToDecisionListStep = require("./steps/wrapBlockquoteToDecisionListStep");
|
|
15
16
|
var _wrapMixedContentStep = require("./steps/wrapMixedContentStep");
|
|
16
17
|
var _stubStep = require("./stubStep");
|
|
17
18
|
var _types = require("./types");
|
|
18
19
|
var _unwrapExpandStep = require("./unwrapExpandStep");
|
|
19
20
|
var _unwrapStep = require("./unwrapStep");
|
|
20
21
|
var _wrapIntoLayoutStep = require("./wrapIntoLayoutStep");
|
|
22
|
+
var _wrapIntoListStep = require("./wrapIntoListStep");
|
|
21
23
|
var _wrapStep = require("./wrapStep");
|
|
22
24
|
// Exampled step for overrides:
|
|
23
25
|
// - open Block menu on a paragraph, click 'Panel' in the Turn into'
|
|
@@ -32,7 +34,7 @@ var TRANSFORM_STEPS = {
|
|
|
32
34
|
atomic: {
|
|
33
35
|
atomic: undefined,
|
|
34
36
|
container: [_wrapStep.wrapStep],
|
|
35
|
-
list:
|
|
37
|
+
list: [_wrapIntoListStep.wrapIntoListStep],
|
|
36
38
|
text: undefined
|
|
37
39
|
},
|
|
38
40
|
container: {
|
|
@@ -83,7 +85,8 @@ var TRANSFORM_STEPS_OVERRIDE = {
|
|
|
83
85
|
expand: [_wrapStep.wrapStep],
|
|
84
86
|
nestedExpand: [_wrapStep.wrapStep],
|
|
85
87
|
layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep],
|
|
86
|
-
codeBlock: [_unwrapStep.unwrapStep, _flattenStep.flattenStep, _wrapStep.wrapStep]
|
|
88
|
+
codeBlock: [_unwrapStep.unwrapStep, _flattenStep.flattenStep, _wrapStep.wrapStep],
|
|
89
|
+
decisionList: [_unwrapStep.unwrapStep, _wrapBlockquoteToDecisionListStep.wrapBlockquoteToDecisionListStep]
|
|
87
90
|
},
|
|
88
91
|
layoutSection: {
|
|
89
92
|
blockquote: [_unwrapLayoutStep.unwrapLayoutStep, _wrapStep.wrapStep],
|
|
@@ -119,7 +122,12 @@ var TRANSFORM_STEPS_OVERRIDE = {
|
|
|
119
122
|
decisionList: [_flattenListStep.flattenListStep, _listToDecisionListStep.listToDecisionListStep]
|
|
120
123
|
},
|
|
121
124
|
table: {
|
|
122
|
-
|
|
125
|
+
layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
|
|
126
|
+
},
|
|
127
|
+
mediaSingle: {
|
|
128
|
+
layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
|
|
129
|
+
},
|
|
130
|
+
mediaGroup: {
|
|
123
131
|
layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
|
|
124
132
|
},
|
|
125
133
|
decisionList: {
|
|
@@ -76,13 +76,29 @@ var expandSelectionToBlockRange = exports.expandSelectionToBlockRange = function
|
|
|
76
76
|
var table = (0, _utils2.findTable)(selection);
|
|
77
77
|
if (table) {
|
|
78
78
|
var $from = selection.$from.doc.resolve(table.pos);
|
|
79
|
-
var $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize
|
|
79
|
+
var $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize);
|
|
80
80
|
return {
|
|
81
81
|
$from: $from,
|
|
82
82
|
$to: $to
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
// when selecting a file, selection is on media
|
|
88
|
+
// need to find media group and return its pos
|
|
89
|
+
if (selection instanceof _state.NodeSelection) {
|
|
90
|
+
if (selection.node.type === nodes.media) {
|
|
91
|
+
var mediaGroup = (0, _utils.findParentNodeOfType)(nodes.mediaGroup)(selection);
|
|
92
|
+
if (mediaGroup) {
|
|
93
|
+
var _$from = selection.$from.doc.resolve(mediaGroup.pos);
|
|
94
|
+
var _$to = selection.$from.doc.resolve(mediaGroup.pos + mediaGroup.node.nodeSize);
|
|
95
|
+
return {
|
|
96
|
+
$from: _$from,
|
|
97
|
+
$to: _$to
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
86
102
|
return (0, _selection.expandToBlockRange)(selection.$from, selection.$to, function (node) {
|
|
87
103
|
if (nodesNeedToExpandRange.includes(node.type)) {
|
|
88
104
|
return false;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wrapIntoListStep = void 0;
|
|
7
|
+
/** wrap nodes into bullet list or numbered list, does not work for task list */
|
|
8
|
+
var wrapIntoListStep = exports.wrapIntoListStep = function wrapIntoListStep(nodes, context) {
|
|
9
|
+
var schema = context.schema,
|
|
10
|
+
targetNodeTypeName = context.targetNodeTypeName;
|
|
11
|
+
var listItemNode = schema.nodes.listItem.createAndFill({}, nodes);
|
|
12
|
+
var outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, listItemNode);
|
|
13
|
+
if (outputNode) {
|
|
14
|
+
return [outputNode];
|
|
15
|
+
}
|
|
16
|
+
return nodes;
|
|
17
|
+
};
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.transformNode = void 0;
|
|
7
7
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
8
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
9
|
var _isNestedNode = require("../ui/utils/isNestedNode");
|
|
9
10
|
var _transform = require("./transform-node-utils/transform");
|
|
10
11
|
var _utils = require("./transform-node-utils/utils");
|
|
@@ -20,7 +21,9 @@ var transformNode = exports.transformNode = function transformNode(api) {
|
|
|
20
21
|
if (!preservedSelection) {
|
|
21
22
|
return tr;
|
|
22
23
|
}
|
|
23
|
-
var
|
|
24
|
+
var schema = tr.doc.type.schema;
|
|
25
|
+
var nodes = schema.nodes;
|
|
26
|
+
var _expandSelectionToBlo = (0, _utils.expandSelectionToBlockRange)(preservedSelection, schema),
|
|
24
27
|
$from = _expandSelectionToBlo.$from,
|
|
25
28
|
$to = _expandSelectionToBlo.$to;
|
|
26
29
|
var isNested = (0, _isNestedNode.isNestedNode)(preservedSelection, '');
|
|
@@ -39,9 +42,15 @@ var transformNode = exports.transformNode = function transformNode(api) {
|
|
|
39
42
|
fragment = fragment.append(_model.Fragment.fromArray(outputNode));
|
|
40
43
|
}
|
|
41
44
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
var nodesToDeleteAndInsert = [nodes.mediaSingle];
|
|
46
|
+
if (preservedSelection instanceof _state.NodeSelection && nodesToDeleteAndInsert.includes(preservedSelection.node.type)) {
|
|
47
|
+
// when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
|
|
48
|
+
tr.deleteRange($from.pos, $to.pos);
|
|
49
|
+
tr.insert($from.pos, fragment);
|
|
50
|
+
} else {
|
|
51
|
+
// TODO: ED-12345 - selection is broken post transaction, to fix.
|
|
52
|
+
tr.replaceWith(isList ? $from.pos - 1 : $from.pos, $to.pos, fragment);
|
|
53
|
+
}
|
|
45
54
|
return tr;
|
|
46
55
|
};
|
|
47
56
|
}
|
|
@@ -9,7 +9,6 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
9
9
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
10
10
|
var BlockMenuContext = /*#__PURE__*/(0, _react.createContext)({
|
|
11
11
|
onDropdownOpenChanged: function onDropdownOpenChanged() {},
|
|
12
|
-
moveFocusTo: function moveFocusTo() {},
|
|
13
12
|
moveDownRef: /*#__PURE__*/_react.default.createRef(),
|
|
14
13
|
moveUpRef: /*#__PURE__*/_react.default.createRef()
|
|
15
14
|
});
|
|
@@ -37,19 +36,9 @@ var BlockMenuProvider = exports.BlockMenuProvider = function BlockMenuProvider(_
|
|
|
37
36
|
}, 1);
|
|
38
37
|
}
|
|
39
38
|
}, [api]);
|
|
40
|
-
var moveFocusTo = (0, _react.useCallback)(function (direction) {
|
|
41
|
-
if (direction === 'moveUp') {
|
|
42
|
-
var _moveUpRef$current;
|
|
43
|
-
(_moveUpRef$current = moveUpRef.current) === null || _moveUpRef$current === void 0 || _moveUpRef$current.focus();
|
|
44
|
-
} else if (direction === 'moveDown') {
|
|
45
|
-
var _moveDownRef$current;
|
|
46
|
-
(_moveDownRef$current = moveDownRef.current) === null || _moveDownRef$current === void 0 || _moveDownRef$current.focus();
|
|
47
|
-
}
|
|
48
|
-
}, []);
|
|
49
39
|
return /*#__PURE__*/_react.default.createElement(BlockMenuContext.Provider, {
|
|
50
40
|
value: {
|
|
51
41
|
onDropdownOpenChanged: onDropdownOpenChanged,
|
|
52
|
-
moveFocusTo: moveFocusTo,
|
|
53
42
|
moveDownRef: moveDownRef,
|
|
54
43
|
moveUpRef: moveUpRef
|
|
55
44
|
}
|
package/dist/cjs/ui/move-down.js
CHANGED
|
@@ -22,7 +22,7 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
22
22
|
var _useIntl = (0, _reactIntlNext.useIntl)(),
|
|
23
23
|
formatMessage = _useIntl.formatMessage;
|
|
24
24
|
var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
|
|
25
|
-
|
|
25
|
+
moveUpRef = _useBlockMenu.moveUpRef,
|
|
26
26
|
moveDownRef = _useBlockMenu.moveDownRef;
|
|
27
27
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
|
|
28
28
|
var _blockControlsState$b;
|
|
@@ -33,14 +33,10 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
33
33
|
}),
|
|
34
34
|
canMoveDown = _useSharedPluginState.canMoveDown;
|
|
35
35
|
(0, _react.useEffect)(function () {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return;
|
|
36
|
+
if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
|
|
37
|
+
moveUpRef.current.focus();
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
moveFocusTo('moveUp');
|
|
42
|
-
}
|
|
43
|
-
}, [canMoveDown, moveFocusTo, moveDownRef]);
|
|
39
|
+
}, [canMoveDown, moveUpRef, moveDownRef]);
|
|
44
40
|
var handleClick = function handleClick() {
|
|
45
41
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
46
42
|
var _api$analytics, _api$blockControls;
|
package/dist/cjs/ui/move-up.js
CHANGED
|
@@ -22,8 +22,8 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
22
22
|
var _useIntl = (0, _reactIntlNext.useIntl)(),
|
|
23
23
|
formatMessage = _useIntl.formatMessage;
|
|
24
24
|
var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
moveUpRef = _useBlockMenu.moveUpRef,
|
|
26
|
+
moveDownRef = _useBlockMenu.moveDownRef;
|
|
27
27
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
|
|
28
28
|
var _blockControlsState$b;
|
|
29
29
|
var blockControlsState = _ref2.blockControlsState;
|
|
@@ -33,14 +33,10 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
33
33
|
}),
|
|
34
34
|
canMoveUp = _useSharedPluginState.canMoveUp;
|
|
35
35
|
(0, _react.useEffect)(function () {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return;
|
|
36
|
+
if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
|
|
37
|
+
moveDownRef.current.focus();
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
moveFocusTo('moveDown');
|
|
42
|
-
}
|
|
43
|
-
}, [canMoveUp, moveFocusTo, moveUpRef]);
|
|
39
|
+
}, [canMoveUp, moveDownRef, moveUpRef]);
|
|
44
40
|
var handleClick = function handleClick() {
|
|
45
41
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
46
42
|
var _api$analytics, _api$blockControls;
|
package/dist/es2019/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { NODE_CATEGORY_BY_TYPE } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Determines if a node is a text node (heading or paragraph).
|
|
5
|
+
* Only text nodes should have their inline content extracted for decisionItem.
|
|
6
|
+
* All other nodes should break out.
|
|
7
|
+
*/
|
|
8
|
+
const isTextNode = node => {
|
|
9
|
+
const category = NODE_CATEGORY_BY_TYPE[node.type.name];
|
|
10
|
+
return category === 'text';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a decisionItem with the given inline content.
|
|
15
|
+
*/
|
|
16
|
+
const createDecisionItem = (inlineContent, schema) => {
|
|
17
|
+
const decisionItemType = schema.nodes.decisionItem;
|
|
18
|
+
if (!decisionItemType) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const canContentBeWrappedInDecisionItem = decisionItemType.validContent(inlineContent);
|
|
22
|
+
|
|
23
|
+
// Check if the content is valid for decisionItem
|
|
24
|
+
if (!canContentBeWrappedInDecisionItem) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return decisionItemType.createAndFill({}, inlineContent);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a decisionList containing the given decisionItems.
|
|
32
|
+
*/
|
|
33
|
+
const createDecisionListWithItems = (decisionItems, schema) => {
|
|
34
|
+
const decisionListType = schema.nodes.decisionList;
|
|
35
|
+
if (!decisionListType || decisionItems.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return decisionListType.createAndFill({}, decisionItems);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Wraps blockquote content into decisionList:
|
|
43
|
+
* - Text nodes (paragraph, heading) have their inline content extracted and wrapped in decisionItems
|
|
44
|
+
* - Consecutive text nodes are grouped into a single decisionList with multiple decisionItems
|
|
45
|
+
* - All other nodes break out (lists, code blocks, media, tables, macros, containers, etc.)
|
|
46
|
+
*
|
|
47
|
+
* The logic follows the transform rules:
|
|
48
|
+
* - Only flatten text nodes into decisionItem (since that's the intent - converting text to decisions)
|
|
49
|
+
* - Structures that can't be represented in a decisionItem should break out unchanged
|
|
50
|
+
* - When a break-out node is encountered, flush accumulated decisionItems into a decisionList
|
|
51
|
+
*
|
|
52
|
+
* Example: blockquote(p('a'), p('b'), ul(...), p('c')) → [decisionList(decisionItem('a'), decisionItem('b')), ul(...), decisionList(decisionItem('c'))]
|
|
53
|
+
*/
|
|
54
|
+
export const wrapBlockquoteToDecisionListStep = (nodes, context) => {
|
|
55
|
+
const {
|
|
56
|
+
schema
|
|
57
|
+
} = context;
|
|
58
|
+
const decisionItemType = schema.nodes.decisionItem;
|
|
59
|
+
if (!decisionItemType) {
|
|
60
|
+
return nodes;
|
|
61
|
+
}
|
|
62
|
+
const result = [];
|
|
63
|
+
let currentDecisionItems = [];
|
|
64
|
+
const flushCurrentDecisionList = () => {
|
|
65
|
+
if (currentDecisionItems.length > 0) {
|
|
66
|
+
const decisionList = createDecisionListWithItems(currentDecisionItems, schema);
|
|
67
|
+
if (decisionList) {
|
|
68
|
+
result.push(decisionList);
|
|
69
|
+
}
|
|
70
|
+
currentDecisionItems = [];
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
nodes.forEach(node => {
|
|
74
|
+
const decisionItem = isTextNode(node) ? createDecisionItem(node.content, schema) : null;
|
|
75
|
+
if (decisionItem) {
|
|
76
|
+
// Accumulate consecutive decisionItems
|
|
77
|
+
currentDecisionItems.push(decisionItem);
|
|
78
|
+
} else {
|
|
79
|
+
// Content can't be wrapped in decisionItem - break out the node
|
|
80
|
+
flushCurrentDecisionList();
|
|
81
|
+
result.push(node);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Flush any remaining decisionItems
|
|
86
|
+
flushCurrentDecisionList();
|
|
87
|
+
return result.length > 0 ? result : nodes;
|
|
88
|
+
};
|
|
@@ -40,11 +40,7 @@ const canWrapInTarget = (node, targetNodeType, targetNodeTypeName) => {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Use the schema to determine if this node can be contained in the target
|
|
43
|
-
|
|
44
|
-
return targetNodeType.validContent(Fragment.from(node));
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
43
|
+
return targetNodeType.validContent(Fragment.from(node));
|
|
48
44
|
};
|
|
49
45
|
|
|
50
46
|
/**
|
|
@@ -6,12 +6,14 @@ import { listToDecisionListStep } from './steps/listToDecisionListStep';
|
|
|
6
6
|
import { listToListStep } from './steps/listToListStep';
|
|
7
7
|
import { unwrapLayoutStep } from './steps/unwrapLayoutStep';
|
|
8
8
|
import { unwrapListStep } from './steps/unwrapListStep';
|
|
9
|
+
import { wrapBlockquoteToDecisionListStep } from './steps/wrapBlockquoteToDecisionListStep';
|
|
9
10
|
import { wrapMixedContentStep } from './steps/wrapMixedContentStep';
|
|
10
11
|
import { stubStep } from './stubStep';
|
|
11
12
|
import { NODE_CATEGORY_BY_TYPE, toNodeTypeValue } from './types';
|
|
12
13
|
import { unwrapExpandStep } from './unwrapExpandStep';
|
|
13
14
|
import { unwrapStep } from './unwrapStep';
|
|
14
15
|
import { wrapIntoLayoutStep } from './wrapIntoLayoutStep';
|
|
16
|
+
import { wrapIntoListStep } from './wrapIntoListStep';
|
|
15
17
|
import { wrapStep } from './wrapStep';
|
|
16
18
|
|
|
17
19
|
// Exampled step for overrides:
|
|
@@ -27,7 +29,7 @@ const TRANSFORM_STEPS = {
|
|
|
27
29
|
atomic: {
|
|
28
30
|
atomic: undefined,
|
|
29
31
|
container: [wrapStep],
|
|
30
|
-
list:
|
|
32
|
+
list: [wrapIntoListStep],
|
|
31
33
|
text: undefined
|
|
32
34
|
},
|
|
33
35
|
container: {
|
|
@@ -78,7 +80,8 @@ const TRANSFORM_STEPS_OVERRIDE = {
|
|
|
78
80
|
expand: [wrapStep],
|
|
79
81
|
nestedExpand: [wrapStep],
|
|
80
82
|
layoutSection: [wrapIntoLayoutStep],
|
|
81
|
-
codeBlock: [unwrapStep, flattenStep, wrapStep]
|
|
83
|
+
codeBlock: [unwrapStep, flattenStep, wrapStep],
|
|
84
|
+
decisionList: [unwrapStep, wrapBlockquoteToDecisionListStep]
|
|
82
85
|
},
|
|
83
86
|
layoutSection: {
|
|
84
87
|
blockquote: [unwrapLayoutStep, wrapStep],
|
|
@@ -114,7 +117,12 @@ const TRANSFORM_STEPS_OVERRIDE = {
|
|
|
114
117
|
decisionList: [flattenListStep, listToDecisionListStep]
|
|
115
118
|
},
|
|
116
119
|
table: {
|
|
117
|
-
|
|
120
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
121
|
+
},
|
|
122
|
+
mediaSingle: {
|
|
123
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
124
|
+
},
|
|
125
|
+
mediaGroup: {
|
|
118
126
|
layoutSection: [wrapIntoLayoutStep]
|
|
119
127
|
},
|
|
120
128
|
decisionList: {
|
|
@@ -73,13 +73,29 @@ export const expandSelectionToBlockRange = (selection, schema) => {
|
|
|
73
73
|
const table = findTable(selection);
|
|
74
74
|
if (table) {
|
|
75
75
|
const $from = selection.$from.doc.resolve(table.pos);
|
|
76
|
-
const $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize
|
|
76
|
+
const $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize);
|
|
77
77
|
return {
|
|
78
78
|
$from,
|
|
79
79
|
$to
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
// when selecting a file, selection is on media
|
|
85
|
+
// need to find media group and return its pos
|
|
86
|
+
if (selection instanceof NodeSelection) {
|
|
87
|
+
if (selection.node.type === nodes.media) {
|
|
88
|
+
const mediaGroup = findParentNodeOfType(nodes.mediaGroup)(selection);
|
|
89
|
+
if (mediaGroup) {
|
|
90
|
+
const $from = selection.$from.doc.resolve(mediaGroup.pos);
|
|
91
|
+
const $to = selection.$from.doc.resolve(mediaGroup.pos + mediaGroup.node.nodeSize);
|
|
92
|
+
return {
|
|
93
|
+
$from,
|
|
94
|
+
$to
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
83
99
|
return expandToBlockRange(selection.$from, selection.$to, node => {
|
|
84
100
|
if (nodesNeedToExpandRange.includes(node.type)) {
|
|
85
101
|
return false;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** wrap nodes into bullet list or numbered list, does not work for task list */
|
|
2
|
+
export const wrapIntoListStep = (nodes, context) => {
|
|
3
|
+
const {
|
|
4
|
+
schema,
|
|
5
|
+
targetNodeTypeName
|
|
6
|
+
} = context;
|
|
7
|
+
const listItemNode = schema.nodes.listItem.createAndFill({}, nodes);
|
|
8
|
+
const outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, listItemNode);
|
|
9
|
+
if (outputNode) {
|
|
10
|
+
return [outputNode];
|
|
11
|
+
}
|
|
12
|
+
return nodes;
|
|
13
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
3
|
import { isNestedNode } from '../ui/utils/isNestedNode';
|
|
3
4
|
import { getOutputNodes } from './transform-node-utils/transform';
|
|
4
5
|
import { expandSelectionToBlockRange } from './transform-node-utils/utils';
|
|
@@ -14,10 +15,14 @@ export const transformNode = api =>
|
|
|
14
15
|
if (!preservedSelection) {
|
|
15
16
|
return tr;
|
|
16
17
|
}
|
|
18
|
+
const schema = tr.doc.type.schema;
|
|
19
|
+
const {
|
|
20
|
+
nodes
|
|
21
|
+
} = schema;
|
|
17
22
|
const {
|
|
18
23
|
$from,
|
|
19
24
|
$to
|
|
20
|
-
} = expandSelectionToBlockRange(preservedSelection,
|
|
25
|
+
} = expandSelectionToBlockRange(preservedSelection, schema);
|
|
21
26
|
const isNested = isNestedNode(preservedSelection, '');
|
|
22
27
|
const selectedParent = $from.parent;
|
|
23
28
|
let fragment = Fragment.empty;
|
|
@@ -34,9 +39,15 @@ export const transformNode = api =>
|
|
|
34
39
|
fragment = fragment.append(Fragment.fromArray(outputNode));
|
|
35
40
|
}
|
|
36
41
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
const nodesToDeleteAndInsert = [nodes.mediaSingle];
|
|
43
|
+
if (preservedSelection instanceof NodeSelection && nodesToDeleteAndInsert.includes(preservedSelection.node.type)) {
|
|
44
|
+
// when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
|
|
45
|
+
tr.deleteRange($from.pos, $to.pos);
|
|
46
|
+
tr.insert($from.pos, fragment);
|
|
47
|
+
} else {
|
|
48
|
+
// TODO: ED-12345 - selection is broken post transaction, to fix.
|
|
49
|
+
tr.replaceWith(isList ? $from.pos - 1 : $from.pos, $to.pos, fragment);
|
|
50
|
+
}
|
|
40
51
|
return tr;
|
|
41
52
|
};
|
|
42
53
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, createContext, useContext, useRef } from 'react';
|
|
2
2
|
const BlockMenuContext = /*#__PURE__*/createContext({
|
|
3
3
|
onDropdownOpenChanged: () => {},
|
|
4
|
-
moveFocusTo: () => {},
|
|
5
4
|
moveDownRef: /*#__PURE__*/React.createRef(),
|
|
6
5
|
moveUpRef: /*#__PURE__*/React.createRef()
|
|
7
6
|
});
|
|
@@ -28,19 +27,9 @@ export const BlockMenuProvider = ({
|
|
|
28
27
|
}), 1);
|
|
29
28
|
}
|
|
30
29
|
}, [api]);
|
|
31
|
-
const moveFocusTo = useCallback(direction => {
|
|
32
|
-
if (direction === 'moveUp') {
|
|
33
|
-
var _moveUpRef$current;
|
|
34
|
-
(_moveUpRef$current = moveUpRef.current) === null || _moveUpRef$current === void 0 ? void 0 : _moveUpRef$current.focus();
|
|
35
|
-
} else if (direction === 'moveDown') {
|
|
36
|
-
var _moveDownRef$current;
|
|
37
|
-
(_moveDownRef$current = moveDownRef.current) === null || _moveDownRef$current === void 0 ? void 0 : _moveDownRef$current.focus();
|
|
38
|
-
}
|
|
39
|
-
}, []);
|
|
40
30
|
return /*#__PURE__*/React.createElement(BlockMenuContext.Provider, {
|
|
41
31
|
value: {
|
|
42
32
|
onDropdownOpenChanged,
|
|
43
|
-
moveFocusTo,
|
|
44
33
|
moveDownRef,
|
|
45
34
|
moveUpRef
|
|
46
35
|
}
|
|
@@ -15,7 +15,7 @@ const MoveDownDropdownItemContent = ({
|
|
|
15
15
|
formatMessage
|
|
16
16
|
} = useIntl();
|
|
17
17
|
const {
|
|
18
|
-
|
|
18
|
+
moveUpRef,
|
|
19
19
|
moveDownRef
|
|
20
20
|
} = useBlockMenu();
|
|
21
21
|
const {
|
|
@@ -29,14 +29,10 @@ const MoveDownDropdownItemContent = ({
|
|
|
29
29
|
};
|
|
30
30
|
});
|
|
31
31
|
useEffect(() => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return;
|
|
32
|
+
if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
|
|
33
|
+
moveUpRef.current.focus();
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
moveFocusTo('moveUp');
|
|
38
|
-
}
|
|
39
|
-
}, [canMoveDown, moveFocusTo, moveDownRef]);
|
|
35
|
+
}, [canMoveDown, moveUpRef, moveDownRef]);
|
|
40
36
|
const handleClick = () => {
|
|
41
37
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
42
38
|
tr
|
|
@@ -15,8 +15,8 @@ const MoveUpDropdownItemContent = ({
|
|
|
15
15
|
formatMessage
|
|
16
16
|
} = useIntl();
|
|
17
17
|
const {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
moveUpRef,
|
|
19
|
+
moveDownRef
|
|
20
20
|
} = useBlockMenu();
|
|
21
21
|
const {
|
|
22
22
|
canMoveUp
|
|
@@ -29,14 +29,10 @@ const MoveUpDropdownItemContent = ({
|
|
|
29
29
|
};
|
|
30
30
|
});
|
|
31
31
|
useEffect(() => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return;
|
|
32
|
+
if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
|
|
33
|
+
moveDownRef.current.focus();
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
moveFocusTo('moveDown');
|
|
38
|
-
}
|
|
39
|
-
}, [canMoveUp, moveFocusTo, moveUpRef]);
|
|
35
|
+
}, [canMoveUp, moveDownRef, moveUpRef]);
|
|
40
36
|
const handleClick = () => {
|
|
41
37
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
42
38
|
tr
|
package/dist/esm/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { NODE_CATEGORY_BY_TYPE } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Determines if a node is a text node (heading or paragraph).
|
|
5
|
+
* Only text nodes should have their inline content extracted for decisionItem.
|
|
6
|
+
* All other nodes should break out.
|
|
7
|
+
*/
|
|
8
|
+
var isTextNode = function isTextNode(node) {
|
|
9
|
+
var category = NODE_CATEGORY_BY_TYPE[node.type.name];
|
|
10
|
+
return category === 'text';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a decisionItem with the given inline content.
|
|
15
|
+
*/
|
|
16
|
+
var createDecisionItem = function createDecisionItem(inlineContent, schema) {
|
|
17
|
+
var decisionItemType = schema.nodes.decisionItem;
|
|
18
|
+
if (!decisionItemType) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
var canContentBeWrappedInDecisionItem = decisionItemType.validContent(inlineContent);
|
|
22
|
+
|
|
23
|
+
// Check if the content is valid for decisionItem
|
|
24
|
+
if (!canContentBeWrappedInDecisionItem) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return decisionItemType.createAndFill({}, inlineContent);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a decisionList containing the given decisionItems.
|
|
32
|
+
*/
|
|
33
|
+
var createDecisionListWithItems = function createDecisionListWithItems(decisionItems, schema) {
|
|
34
|
+
var decisionListType = schema.nodes.decisionList;
|
|
35
|
+
if (!decisionListType || decisionItems.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return decisionListType.createAndFill({}, decisionItems);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Wraps blockquote content into decisionList:
|
|
43
|
+
* - Text nodes (paragraph, heading) have their inline content extracted and wrapped in decisionItems
|
|
44
|
+
* - Consecutive text nodes are grouped into a single decisionList with multiple decisionItems
|
|
45
|
+
* - All other nodes break out (lists, code blocks, media, tables, macros, containers, etc.)
|
|
46
|
+
*
|
|
47
|
+
* The logic follows the transform rules:
|
|
48
|
+
* - Only flatten text nodes into decisionItem (since that's the intent - converting text to decisions)
|
|
49
|
+
* - Structures that can't be represented in a decisionItem should break out unchanged
|
|
50
|
+
* - When a break-out node is encountered, flush accumulated decisionItems into a decisionList
|
|
51
|
+
*
|
|
52
|
+
* Example: blockquote(p('a'), p('b'), ul(...), p('c')) → [decisionList(decisionItem('a'), decisionItem('b')), ul(...), decisionList(decisionItem('c'))]
|
|
53
|
+
*/
|
|
54
|
+
export var wrapBlockquoteToDecisionListStep = function wrapBlockquoteToDecisionListStep(nodes, context) {
|
|
55
|
+
var schema = context.schema;
|
|
56
|
+
var decisionItemType = schema.nodes.decisionItem;
|
|
57
|
+
if (!decisionItemType) {
|
|
58
|
+
return nodes;
|
|
59
|
+
}
|
|
60
|
+
var result = [];
|
|
61
|
+
var currentDecisionItems = [];
|
|
62
|
+
var flushCurrentDecisionList = function flushCurrentDecisionList() {
|
|
63
|
+
if (currentDecisionItems.length > 0) {
|
|
64
|
+
var decisionList = createDecisionListWithItems(currentDecisionItems, schema);
|
|
65
|
+
if (decisionList) {
|
|
66
|
+
result.push(decisionList);
|
|
67
|
+
}
|
|
68
|
+
currentDecisionItems = [];
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
nodes.forEach(function (node) {
|
|
72
|
+
var decisionItem = isTextNode(node) ? createDecisionItem(node.content, schema) : null;
|
|
73
|
+
if (decisionItem) {
|
|
74
|
+
// Accumulate consecutive decisionItems
|
|
75
|
+
currentDecisionItems.push(decisionItem);
|
|
76
|
+
} else {
|
|
77
|
+
// Content can't be wrapped in decisionItem - break out the node
|
|
78
|
+
flushCurrentDecisionList();
|
|
79
|
+
result.push(node);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Flush any remaining decisionItems
|
|
84
|
+
flushCurrentDecisionList();
|
|
85
|
+
return result.length > 0 ? result : nodes;
|
|
86
|
+
};
|
|
@@ -40,11 +40,7 @@ var canWrapInTarget = function canWrapInTarget(node, targetNodeType, targetNodeT
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Use the schema to determine if this node can be contained in the target
|
|
43
|
-
|
|
44
|
-
return targetNodeType.validContent(Fragment.from(node));
|
|
45
|
-
} catch (_unused) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
43
|
+
return targetNodeType.validContent(Fragment.from(node));
|
|
48
44
|
};
|
|
49
45
|
|
|
50
46
|
/**
|
|
@@ -6,12 +6,14 @@ import { listToDecisionListStep } from './steps/listToDecisionListStep';
|
|
|
6
6
|
import { listToListStep } from './steps/listToListStep';
|
|
7
7
|
import { unwrapLayoutStep } from './steps/unwrapLayoutStep';
|
|
8
8
|
import { unwrapListStep } from './steps/unwrapListStep';
|
|
9
|
+
import { wrapBlockquoteToDecisionListStep } from './steps/wrapBlockquoteToDecisionListStep';
|
|
9
10
|
import { wrapMixedContentStep } from './steps/wrapMixedContentStep';
|
|
10
11
|
import { stubStep } from './stubStep';
|
|
11
12
|
import { NODE_CATEGORY_BY_TYPE, toNodeTypeValue } from './types';
|
|
12
13
|
import { unwrapExpandStep } from './unwrapExpandStep';
|
|
13
14
|
import { unwrapStep } from './unwrapStep';
|
|
14
15
|
import { wrapIntoLayoutStep } from './wrapIntoLayoutStep';
|
|
16
|
+
import { wrapIntoListStep } from './wrapIntoListStep';
|
|
15
17
|
import { wrapStep } from './wrapStep';
|
|
16
18
|
|
|
17
19
|
// Exampled step for overrides:
|
|
@@ -27,7 +29,7 @@ var TRANSFORM_STEPS = {
|
|
|
27
29
|
atomic: {
|
|
28
30
|
atomic: undefined,
|
|
29
31
|
container: [wrapStep],
|
|
30
|
-
list:
|
|
32
|
+
list: [wrapIntoListStep],
|
|
31
33
|
text: undefined
|
|
32
34
|
},
|
|
33
35
|
container: {
|
|
@@ -78,7 +80,8 @@ var TRANSFORM_STEPS_OVERRIDE = {
|
|
|
78
80
|
expand: [wrapStep],
|
|
79
81
|
nestedExpand: [wrapStep],
|
|
80
82
|
layoutSection: [wrapIntoLayoutStep],
|
|
81
|
-
codeBlock: [unwrapStep, flattenStep, wrapStep]
|
|
83
|
+
codeBlock: [unwrapStep, flattenStep, wrapStep],
|
|
84
|
+
decisionList: [unwrapStep, wrapBlockquoteToDecisionListStep]
|
|
82
85
|
},
|
|
83
86
|
layoutSection: {
|
|
84
87
|
blockquote: [unwrapLayoutStep, wrapStep],
|
|
@@ -114,7 +117,12 @@ var TRANSFORM_STEPS_OVERRIDE = {
|
|
|
114
117
|
decisionList: [flattenListStep, listToDecisionListStep]
|
|
115
118
|
},
|
|
116
119
|
table: {
|
|
117
|
-
|
|
120
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
121
|
+
},
|
|
122
|
+
mediaSingle: {
|
|
123
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
124
|
+
},
|
|
125
|
+
mediaGroup: {
|
|
118
126
|
layoutSection: [wrapIntoLayoutStep]
|
|
119
127
|
},
|
|
120
128
|
decisionList: {
|
|
@@ -70,13 +70,29 @@ export var expandSelectionToBlockRange = function expandSelectionToBlockRange(se
|
|
|
70
70
|
var table = findTable(selection);
|
|
71
71
|
if (table) {
|
|
72
72
|
var $from = selection.$from.doc.resolve(table.pos);
|
|
73
|
-
var $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize
|
|
73
|
+
var $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize);
|
|
74
74
|
return {
|
|
75
75
|
$from: $from,
|
|
76
76
|
$to: $to
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
// when selecting a file, selection is on media
|
|
82
|
+
// need to find media group and return its pos
|
|
83
|
+
if (selection instanceof NodeSelection) {
|
|
84
|
+
if (selection.node.type === nodes.media) {
|
|
85
|
+
var mediaGroup = findParentNodeOfType(nodes.mediaGroup)(selection);
|
|
86
|
+
if (mediaGroup) {
|
|
87
|
+
var _$from = selection.$from.doc.resolve(mediaGroup.pos);
|
|
88
|
+
var _$to = selection.$from.doc.resolve(mediaGroup.pos + mediaGroup.node.nodeSize);
|
|
89
|
+
return {
|
|
90
|
+
$from: _$from,
|
|
91
|
+
$to: _$to
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
80
96
|
return expandToBlockRange(selection.$from, selection.$to, function (node) {
|
|
81
97
|
if (nodesNeedToExpandRange.includes(node.type)) {
|
|
82
98
|
return false;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** wrap nodes into bullet list or numbered list, does not work for task list */
|
|
2
|
+
export var wrapIntoListStep = function wrapIntoListStep(nodes, context) {
|
|
3
|
+
var schema = context.schema,
|
|
4
|
+
targetNodeTypeName = context.targetNodeTypeName;
|
|
5
|
+
var listItemNode = schema.nodes.listItem.createAndFill({}, nodes);
|
|
6
|
+
var outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, listItemNode);
|
|
7
|
+
if (outputNode) {
|
|
8
|
+
return [outputNode];
|
|
9
|
+
}
|
|
10
|
+
return nodes;
|
|
11
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
3
|
import { isNestedNode } from '../ui/utils/isNestedNode';
|
|
3
4
|
import { getOutputNodes } from './transform-node-utils/transform';
|
|
4
5
|
import { expandSelectionToBlockRange } from './transform-node-utils/utils';
|
|
@@ -14,7 +15,9 @@ export var transformNode = function transformNode(api) {
|
|
|
14
15
|
if (!preservedSelection) {
|
|
15
16
|
return tr;
|
|
16
17
|
}
|
|
17
|
-
var
|
|
18
|
+
var schema = tr.doc.type.schema;
|
|
19
|
+
var nodes = schema.nodes;
|
|
20
|
+
var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection, schema),
|
|
18
21
|
$from = _expandSelectionToBlo.$from,
|
|
19
22
|
$to = _expandSelectionToBlo.$to;
|
|
20
23
|
var isNested = isNestedNode(preservedSelection, '');
|
|
@@ -33,9 +36,15 @@ export var transformNode = function transformNode(api) {
|
|
|
33
36
|
fragment = fragment.append(Fragment.fromArray(outputNode));
|
|
34
37
|
}
|
|
35
38
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
var nodesToDeleteAndInsert = [nodes.mediaSingle];
|
|
40
|
+
if (preservedSelection instanceof NodeSelection && nodesToDeleteAndInsert.includes(preservedSelection.node.type)) {
|
|
41
|
+
// when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
|
|
42
|
+
tr.deleteRange($from.pos, $to.pos);
|
|
43
|
+
tr.insert($from.pos, fragment);
|
|
44
|
+
} else {
|
|
45
|
+
// TODO: ED-12345 - selection is broken post transaction, to fix.
|
|
46
|
+
tr.replaceWith(isList ? $from.pos - 1 : $from.pos, $to.pos, fragment);
|
|
47
|
+
}
|
|
39
48
|
return tr;
|
|
40
49
|
};
|
|
41
50
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, createContext, useContext, useRef } from 'react';
|
|
2
2
|
var BlockMenuContext = /*#__PURE__*/createContext({
|
|
3
3
|
onDropdownOpenChanged: function onDropdownOpenChanged() {},
|
|
4
|
-
moveFocusTo: function moveFocusTo() {},
|
|
5
4
|
moveDownRef: /*#__PURE__*/React.createRef(),
|
|
6
5
|
moveUpRef: /*#__PURE__*/React.createRef()
|
|
7
6
|
});
|
|
@@ -29,19 +28,9 @@ export var BlockMenuProvider = function BlockMenuProvider(_ref) {
|
|
|
29
28
|
}, 1);
|
|
30
29
|
}
|
|
31
30
|
}, [api]);
|
|
32
|
-
var moveFocusTo = useCallback(function (direction) {
|
|
33
|
-
if (direction === 'moveUp') {
|
|
34
|
-
var _moveUpRef$current;
|
|
35
|
-
(_moveUpRef$current = moveUpRef.current) === null || _moveUpRef$current === void 0 || _moveUpRef$current.focus();
|
|
36
|
-
} else if (direction === 'moveDown') {
|
|
37
|
-
var _moveDownRef$current;
|
|
38
|
-
(_moveDownRef$current = moveDownRef.current) === null || _moveDownRef$current === void 0 || _moveDownRef$current.focus();
|
|
39
|
-
}
|
|
40
|
-
}, []);
|
|
41
31
|
return /*#__PURE__*/React.createElement(BlockMenuContext.Provider, {
|
|
42
32
|
value: {
|
|
43
33
|
onDropdownOpenChanged: onDropdownOpenChanged,
|
|
44
|
-
moveFocusTo: moveFocusTo,
|
|
45
34
|
moveDownRef: moveDownRef,
|
|
46
35
|
moveUpRef: moveUpRef
|
|
47
36
|
}
|
package/dist/esm/ui/move-down.js
CHANGED
|
@@ -13,7 +13,7 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
13
13
|
var _useIntl = useIntl(),
|
|
14
14
|
formatMessage = _useIntl.formatMessage;
|
|
15
15
|
var _useBlockMenu = useBlockMenu(),
|
|
16
|
-
|
|
16
|
+
moveUpRef = _useBlockMenu.moveUpRef,
|
|
17
17
|
moveDownRef = _useBlockMenu.moveDownRef;
|
|
18
18
|
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls'], function (_ref2) {
|
|
19
19
|
var _blockControlsState$b;
|
|
@@ -24,14 +24,10 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
24
24
|
}),
|
|
25
25
|
canMoveDown = _useSharedPluginState.canMoveDown;
|
|
26
26
|
useEffect(function () {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return;
|
|
27
|
+
if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
|
|
28
|
+
moveUpRef.current.focus();
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
moveFocusTo('moveUp');
|
|
33
|
-
}
|
|
34
|
-
}, [canMoveDown, moveFocusTo, moveDownRef]);
|
|
30
|
+
}, [canMoveDown, moveUpRef, moveDownRef]);
|
|
35
31
|
var handleClick = function handleClick() {
|
|
36
32
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
37
33
|
var _api$analytics, _api$blockControls;
|
package/dist/esm/ui/move-up.js
CHANGED
|
@@ -13,8 +13,8 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
13
13
|
var _useIntl = useIntl(),
|
|
14
14
|
formatMessage = _useIntl.formatMessage;
|
|
15
15
|
var _useBlockMenu = useBlockMenu(),
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
moveUpRef = _useBlockMenu.moveUpRef,
|
|
17
|
+
moveDownRef = _useBlockMenu.moveDownRef;
|
|
18
18
|
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls'], function (_ref2) {
|
|
19
19
|
var _blockControlsState$b;
|
|
20
20
|
var blockControlsState = _ref2.blockControlsState;
|
|
@@ -24,14 +24,10 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
24
24
|
}),
|
|
25
25
|
canMoveUp = _useSharedPluginState.canMoveUp;
|
|
26
26
|
useEffect(function () {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return;
|
|
27
|
+
if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
|
|
28
|
+
moveDownRef.current.focus();
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
moveFocusTo('moveDown');
|
|
33
|
-
}
|
|
34
|
-
}, [canMoveUp, moveFocusTo, moveUpRef]);
|
|
30
|
+
}, [canMoveUp, moveDownRef, moveUpRef]);
|
|
35
31
|
var handleClick = function handleClick() {
|
|
36
32
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
37
33
|
var _api$analytics, _api$blockControls;
|
package/dist/types/editor-commands/transform-node-utils/steps/wrapBlockquoteToDecisionListStep.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TransformStep } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps blockquote content into decisionList:
|
|
4
|
+
* - Text nodes (paragraph, heading) have their inline content extracted and wrapped in decisionItems
|
|
5
|
+
* - Consecutive text nodes are grouped into a single decisionList with multiple decisionItems
|
|
6
|
+
* - All other nodes break out (lists, code blocks, media, tables, macros, containers, etc.)
|
|
7
|
+
*
|
|
8
|
+
* The logic follows the transform rules:
|
|
9
|
+
* - Only flatten text nodes into decisionItem (since that's the intent - converting text to decisions)
|
|
10
|
+
* - Structures that can't be represented in a decisionItem should break out unchanged
|
|
11
|
+
* - When a break-out node is encountered, flush accumulated decisionItems into a decisionList
|
|
12
|
+
*
|
|
13
|
+
* Example: blockquote(p('a'), p('b'), ul(...), p('c')) → [decisionList(decisionItem('a'), decisionItem('b')), ul(...), decisionList(decisionItem('c'))]
|
|
14
|
+
*/
|
|
15
|
+
export declare const wrapBlockquoteToDecisionListStep: TransformStep;
|
|
@@ -8,11 +8,6 @@ type BlockMenuProviderProps = {
|
|
|
8
8
|
};
|
|
9
9
|
export type BlockMenuContextType = {
|
|
10
10
|
moveDownRef: React.MutableRefObject<HTMLButtonElement | null>;
|
|
11
|
-
/**
|
|
12
|
-
* Function to move focus between move up and move down items.
|
|
13
|
-
* Used when one item is disabled and focused.
|
|
14
|
-
*/
|
|
15
|
-
moveFocusTo: (direction: Direction) => void;
|
|
16
11
|
moveUpRef: React.MutableRefObject<HTMLButtonElement | null>;
|
|
17
12
|
/**
|
|
18
13
|
* Callback for when the dropdown is open/closed. Receives an object with `isOpen` state.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TransformStep } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps blockquote content into decisionList:
|
|
4
|
+
* - Text nodes (paragraph, heading) have their inline content extracted and wrapped in decisionItems
|
|
5
|
+
* - Consecutive text nodes are grouped into a single decisionList with multiple decisionItems
|
|
6
|
+
* - All other nodes break out (lists, code blocks, media, tables, macros, containers, etc.)
|
|
7
|
+
*
|
|
8
|
+
* The logic follows the transform rules:
|
|
9
|
+
* - Only flatten text nodes into decisionItem (since that's the intent - converting text to decisions)
|
|
10
|
+
* - Structures that can't be represented in a decisionItem should break out unchanged
|
|
11
|
+
* - When a break-out node is encountered, flush accumulated decisionItems into a decisionList
|
|
12
|
+
*
|
|
13
|
+
* Example: blockquote(p('a'), p('b'), ul(...), p('c')) → [decisionList(decisionItem('a'), decisionItem('b')), ul(...), decisionList(decisionItem('c'))]
|
|
14
|
+
*/
|
|
15
|
+
export declare const wrapBlockquoteToDecisionListStep: TransformStep;
|
|
@@ -8,11 +8,6 @@ type BlockMenuProviderProps = {
|
|
|
8
8
|
};
|
|
9
9
|
export type BlockMenuContextType = {
|
|
10
10
|
moveDownRef: React.MutableRefObject<HTMLButtonElement | null>;
|
|
11
|
-
/**
|
|
12
|
-
* Function to move focus between move up and move down items.
|
|
13
|
-
* Used when one item is disabled and focused.
|
|
14
|
-
*/
|
|
15
|
-
moveFocusTo: (direction: Direction) => void;
|
|
16
11
|
moveUpRef: React.MutableRefObject<HTMLButtonElement | null>;
|
|
17
12
|
/**
|
|
18
13
|
* Callback for when the dropdown is open/closed. Receives an object with `isOpen` state.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-block-menu",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.8",
|
|
4
4
|
"description": "BlockMenu plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,25 +31,25 @@
|
|
|
31
31
|
"@atlaskit/css": "^0.17.0",
|
|
32
32
|
"@atlaskit/dropdown-menu": "^16.3.0",
|
|
33
33
|
"@atlaskit/editor-plugin-analytics": "^6.2.0",
|
|
34
|
-
"@atlaskit/editor-plugin-block-controls": "^7.
|
|
34
|
+
"@atlaskit/editor-plugin-block-controls": "^7.14.0",
|
|
35
35
|
"@atlaskit/editor-plugin-decorations": "^6.1.0",
|
|
36
36
|
"@atlaskit/editor-plugin-selection": "^6.1.0",
|
|
37
37
|
"@atlaskit/editor-plugin-user-intent": "^4.0.0",
|
|
38
|
-
"@atlaskit/editor-prosemirror": "7.
|
|
38
|
+
"@atlaskit/editor-prosemirror": "^7.2.0",
|
|
39
39
|
"@atlaskit/editor-shared-styles": "^3.10.0",
|
|
40
40
|
"@atlaskit/editor-tables": "^2.9.0",
|
|
41
41
|
"@atlaskit/editor-toolbar": "^0.18.0",
|
|
42
42
|
"@atlaskit/flag": "^17.6.0",
|
|
43
|
-
"@atlaskit/icon": "^29.
|
|
43
|
+
"@atlaskit/icon": "^29.1.0",
|
|
44
44
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
45
45
|
"@atlaskit/platform-feature-flags-react": "^0.4.0",
|
|
46
46
|
"@atlaskit/primitives": "^16.4.0",
|
|
47
|
-
"@atlaskit/tmp-editor-statsig": "^15.
|
|
47
|
+
"@atlaskit/tmp-editor-statsig": "^15.10.0",
|
|
48
48
|
"@atlaskit/tokens": "^8.4.0",
|
|
49
49
|
"@babel/runtime": "^7.0.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@atlaskit/editor-common": "^110.
|
|
52
|
+
"@atlaskit/editor-common": "^110.42.0",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
55
55
|
},
|