@atlaskit/editor-common 112.8.4 → 112.9.1
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 +22 -0
- package/dist/cjs/lists/index.js +7 -0
- package/dist/cjs/lists/narrow-replacement-range.js +82 -0
- package/dist/cjs/media-single/ExternalImageBadge.js +7 -0
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/transforms/list-transforms.js +122 -16
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/es2019/lists/index.js +1 -0
- package/dist/es2019/lists/narrow-replacement-range.js +74 -0
- package/dist/es2019/media-single/ExternalImageBadge.js +5 -0
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/transforms/list-transforms.js +107 -12
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/esm/lists/index.js +1 -0
- package/dist/esm/lists/narrow-replacement-range.js +76 -0
- package/dist/esm/media-single/ExternalImageBadge.js +7 -0
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/transforms/list-transforms.js +122 -16
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/types/lists/index.d.ts +2 -0
- package/dist/types/lists/narrow-replacement-range.d.ts +19 -0
- package/dist/types-ts4.5/lists/index.d.ts +2 -0
- package/dist/types-ts4.5/lists/narrow-replacement-range.d.ts +19 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @atlaskit/editor-common
|
|
2
2
|
|
|
3
|
+
## 112.9.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`9b33b26d69865`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9b33b26d69865) -
|
|
8
|
+
Narrow list replacement range during indent/outdent for collab-friendly cursor preservation
|
|
9
|
+
- [`3f6f3c13a6033`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3f6f3c13a6033) -
|
|
10
|
+
Fix fontSize mark preservation during list type conversions (bullet/ordered ↔ task list) and
|
|
11
|
+
blockTaskItem handling when toggling task list off
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
14
|
+
## 112.9.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- [`9f5fba61d4c9d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9f5fba61d4c9d) -
|
|
19
|
+
do not show external badge for images hosted on bitbucket.org
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
|
|
3
25
|
## 112.8.4
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/cjs/lists/index.js
CHANGED
|
@@ -99,6 +99,12 @@ Object.defineProperty(exports, "moveTargetIntoList", {
|
|
|
99
99
|
return _replaceContent.moveTargetIntoList;
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
|
+
Object.defineProperty(exports, "narrowReplacementRange", {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
get: function get() {
|
|
105
|
+
return _narrowReplacementRange.narrowReplacementRange;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
102
108
|
Object.defineProperty(exports, "normalizeListItemsSelection", {
|
|
103
109
|
enumerable: true,
|
|
104
110
|
get: function get() {
|
|
@@ -124,6 +130,7 @@ var _analytics = require("./analytics");
|
|
|
124
130
|
var _indentation = require("./indentation");
|
|
125
131
|
var _restoreSelection = require("./restore-selection");
|
|
126
132
|
var _buildReplacementFragment = require("./build-replacement-fragment");
|
|
133
|
+
var _narrowReplacementRange = require("./narrow-replacement-range");
|
|
127
134
|
var _flattenList = require("./flatten-list");
|
|
128
135
|
var _utils = require("../utils");
|
|
129
136
|
var _messages = require("./messages");
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.narrowReplacementRange = narrowReplacementRange;
|
|
7
|
+
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
8
|
+
/**
|
|
9
|
+
* Narrows a full-list replacement to the minimal changed range.
|
|
10
|
+
*
|
|
11
|
+
* Compares the old root list node with the new replacement fragment
|
|
12
|
+
* from both ends to find the first and last positions where they differ,
|
|
13
|
+
* then returns only the changed subrange.
|
|
14
|
+
*
|
|
15
|
+
* This reduces the scope of `tr.replaceWith()` so that remote cursors
|
|
16
|
+
* on unchanged items are preserved during collaborative editing.
|
|
17
|
+
*/
|
|
18
|
+
function narrowReplacementRange(doc, rootListStart, rootListEnd, fragment, contentStartOffsets) {
|
|
19
|
+
var oldNode = doc.nodeAt(rootListStart);
|
|
20
|
+
var newNode = fragment.childCount === 1 ? fragment.firstChild : null;
|
|
21
|
+
if (!oldNode || !newNode || newNode.type !== oldNode.type) {
|
|
22
|
+
return {
|
|
23
|
+
start: rootListStart,
|
|
24
|
+
end: rootListEnd,
|
|
25
|
+
fragment: fragment,
|
|
26
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
var minChildCount = Math.min(oldNode.childCount, newNode.childCount);
|
|
30
|
+
var commonPrefixChildren = 0;
|
|
31
|
+
var prefixSize = 0;
|
|
32
|
+
for (var i = 0; i < minChildCount; i++) {
|
|
33
|
+
var oldChild = oldNode.child(i);
|
|
34
|
+
var newChild = newNode.child(i);
|
|
35
|
+
if (oldChild.eq(newChild)) {
|
|
36
|
+
commonPrefixChildren++;
|
|
37
|
+
prefixSize += oldChild.nodeSize;
|
|
38
|
+
} else {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
var commonSuffixChildren = 0;
|
|
43
|
+
var suffixSize = 0;
|
|
44
|
+
for (var _i = 0; _i < minChildCount - commonPrefixChildren; _i++) {
|
|
45
|
+
var _oldChild = oldNode.child(oldNode.childCount - 1 - _i);
|
|
46
|
+
var _newChild = newNode.child(newNode.childCount - 1 - _i);
|
|
47
|
+
if (_oldChild.eq(_newChild)) {
|
|
48
|
+
commonSuffixChildren++;
|
|
49
|
+
suffixSize += _oldChild.nodeSize;
|
|
50
|
+
} else {
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var totalCommon = commonPrefixChildren + commonSuffixChildren;
|
|
55
|
+
if (totalCommon >= oldNode.childCount && totalCommon >= newNode.childCount) {
|
|
56
|
+
return {
|
|
57
|
+
start: rootListStart,
|
|
58
|
+
end: rootListStart,
|
|
59
|
+
fragment: _model.Fragment.empty,
|
|
60
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var narrowedStart = rootListStart + 1 + prefixSize;
|
|
64
|
+
var narrowedEnd = rootListEnd - 1 - suffixSize;
|
|
65
|
+
var changedChildStart = commonPrefixChildren;
|
|
66
|
+
var changedChildEnd = newNode.childCount - commonSuffixChildren;
|
|
67
|
+
var changedNodes = [];
|
|
68
|
+
for (var _i2 = changedChildStart; _i2 < changedChildEnd; _i2++) {
|
|
69
|
+
changedNodes.push(newNode.child(_i2));
|
|
70
|
+
}
|
|
71
|
+
var narrowedFragment = _model.Fragment.from(changedNodes);
|
|
72
|
+
var prefixOffset = 1 + prefixSize;
|
|
73
|
+
var adjustedContentStartOffsets = contentStartOffsets.map(function (offset) {
|
|
74
|
+
return offset - prefixOffset;
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
start: narrowedStart,
|
|
78
|
+
end: narrowedEnd,
|
|
79
|
+
fragment: narrowedFragment,
|
|
80
|
+
adjustedContentStartOffsets: adjustedContentStartOffsets
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -9,6 +9,7 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
9
9
|
var _reactIntlNext = require("react-intl-next");
|
|
10
10
|
var _statusInformation = _interopRequireDefault(require("@atlaskit/icon/core/status-information"));
|
|
11
11
|
var _primitives = require("@atlaskit/primitives");
|
|
12
|
+
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
12
13
|
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
13
14
|
var _media = require("../media");
|
|
14
15
|
// eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
|
|
@@ -21,6 +22,7 @@ var baseStyles = (0, _primitives.xcss)({
|
|
|
21
22
|
cursor: 'pointer'
|
|
22
23
|
});
|
|
23
24
|
var NO_EXTERNAL_BADGE_HOSTS = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com'];
|
|
25
|
+
var NO_EXTERNAL_BADGE_HOSTS_NEW = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com', 'bitbucket.org'];
|
|
24
26
|
var isUnbadgedUrl = exports.isUnbadgedUrl = function isUnbadgedUrl(url) {
|
|
25
27
|
if (!url) {
|
|
26
28
|
return false;
|
|
@@ -38,6 +40,11 @@ var isUnbadgedUrl = exports.isUnbadgedUrl = function isUnbadgedUrl(url) {
|
|
|
38
40
|
if (protocol === 'data:') {
|
|
39
41
|
return pathname === null || pathname === void 0 ? void 0 : pathname.startsWith('image/');
|
|
40
42
|
}
|
|
43
|
+
if ((0, _expValEquals.expValEquals)('platform_editor_media_external_badge_bbc_fix', 'isEnable', true)) {
|
|
44
|
+
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS_NEW.some(function (host) {
|
|
45
|
+
return hostname === host || hostname.endsWith(".".concat(host));
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
41
48
|
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS.some(function (host) {
|
|
42
49
|
return hostname === host || hostname.endsWith(".".concat(host));
|
|
43
50
|
}));
|
|
@@ -19,7 +19,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
19
19
|
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); }
|
|
20
20
|
var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
21
21
|
var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
22
|
-
var packageVersion = "
|
|
22
|
+
var packageVersion = "0.0.0-development";
|
|
23
23
|
var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
|
|
24
24
|
// Remove URL as it has UGC
|
|
25
25
|
// Ignored via go/ees007
|
|
@@ -9,7 +9,11 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
|
|
|
9
9
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
10
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
11
11
|
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
12
|
+
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
12
13
|
var _listUtils = require("./list-utils");
|
|
14
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
15
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
16
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
13
17
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
18
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
15
19
|
var getContentSupportChecker = function getContentSupportChecker(targetNodeType) {
|
|
@@ -21,6 +25,16 @@ var getContentSupportChecker = function getContentSupportChecker(targetNodeType)
|
|
|
21
25
|
}
|
|
22
26
|
};
|
|
23
27
|
};
|
|
28
|
+
var createBlockTaskItemWithMarks = function createBlockTaskItemWithMarks(content, marks, schema) {
|
|
29
|
+
var _schema$nodes = schema.nodes,
|
|
30
|
+
blockTaskItem = _schema$nodes.blockTaskItem,
|
|
31
|
+
paragraph = _schema$nodes.paragraph;
|
|
32
|
+
var allowedMarks = marks.filter(function (mark) {
|
|
33
|
+
return blockTaskItem.allowsMarkType(mark.type);
|
|
34
|
+
});
|
|
35
|
+
var newParagraph = paragraph.create(null, content.length > 0 ? content : null, allowedMarks);
|
|
36
|
+
return blockTaskItem.create(null, newParagraph);
|
|
37
|
+
};
|
|
24
38
|
var _transformListRecursively = exports.transformListRecursively = function transformListRecursively(props, onhandleUnsupportedContent) {
|
|
25
39
|
var transformedItems = [];
|
|
26
40
|
var listNode = props.listNode,
|
|
@@ -31,17 +45,36 @@ var _transformListRecursively = exports.transformListRecursively = function tran
|
|
|
31
45
|
supportedListTypes = props.supportedListTypes,
|
|
32
46
|
schema = props.schema,
|
|
33
47
|
targetNodeType = props.targetNodeType;
|
|
34
|
-
var _schema$
|
|
35
|
-
taskList = _schema$
|
|
36
|
-
listItem = _schema$
|
|
37
|
-
taskItem = _schema$
|
|
38
|
-
paragraph = _schema$
|
|
48
|
+
var _schema$nodes2 = schema.nodes,
|
|
49
|
+
taskList = _schema$nodes2.taskList,
|
|
50
|
+
listItem = _schema$nodes2.listItem,
|
|
51
|
+
taskItem = _schema$nodes2.taskItem,
|
|
52
|
+
paragraph = _schema$nodes2.paragraph,
|
|
53
|
+
blockTaskItem = _schema$nodes2.blockTaskItem;
|
|
54
|
+
|
|
55
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
56
|
+
// but keep this solution general
|
|
57
|
+
var isBlockTaskEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extracts paragraph children from a blockTaskItem, preserving their marks.
|
|
61
|
+
*/
|
|
62
|
+
var extractParagraphsFromBlockTaskItem = function extractParagraphsFromBlockTaskItem(node) {
|
|
63
|
+
var paragraphs = [];
|
|
64
|
+
node.forEach(function (child) {
|
|
65
|
+
if (child.type === paragraph) {
|
|
66
|
+
paragraphs.push(child);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return paragraphs;
|
|
70
|
+
};
|
|
39
71
|
listNode.forEach(function (child) {
|
|
40
72
|
if (isSourceBulletOrOrdered && isTargetTask) {
|
|
41
73
|
// Convert bullet/ordered => task
|
|
42
74
|
if (child.type === listItem) {
|
|
43
75
|
var inlineContent = [];
|
|
44
76
|
var nestedTaskLists = [];
|
|
77
|
+
var blockMarks = [];
|
|
45
78
|
child.forEach(function (grandChild) {
|
|
46
79
|
if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
|
|
47
80
|
nestedTaskLists.push(_transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
|
|
@@ -50,18 +83,39 @@ var _transformListRecursively = exports.transformListRecursively = function tran
|
|
|
50
83
|
} else if (!getContentSupportChecker(taskItem)(grandChild) && !grandChild.isTextblock) {
|
|
51
84
|
onhandleUnsupportedContent === null || onhandleUnsupportedContent === void 0 || onhandleUnsupportedContent(grandChild);
|
|
52
85
|
} else {
|
|
86
|
+
if (isBlockTaskEnabled && grandChild.type === paragraph && grandChild.marks.length > 0) {
|
|
87
|
+
blockMarks = grandChild.marks;
|
|
88
|
+
}
|
|
53
89
|
inlineContent.push.apply(inlineContent, (0, _toConsumableArray2.default)((0, _listUtils.convertBlockToInlineContent)(grandChild, schema)));
|
|
54
90
|
}
|
|
55
91
|
});
|
|
56
|
-
|
|
92
|
+
if (isBlockTaskEnabled && blockMarks.length > 0) {
|
|
93
|
+
transformedItems.push(createBlockTaskItemWithMarks(inlineContent, blockMarks, schema));
|
|
94
|
+
} else {
|
|
95
|
+
transformedItems.push(taskItem.create(null, inlineContent.length > 0 ? inlineContent : null));
|
|
96
|
+
}
|
|
57
97
|
transformedItems.push.apply(transformedItems, nestedTaskLists);
|
|
58
98
|
}
|
|
59
99
|
} else if (isSourceTask && isTargetBulletOrOrdered) {
|
|
60
100
|
// Convert task => bullet/ordered
|
|
61
101
|
if (child.type === taskItem) {
|
|
62
102
|
var _inlineContent = (0, _toConsumableArray2.default)(child.content.content);
|
|
63
|
-
|
|
103
|
+
|
|
104
|
+
// Transfer taskItem's block marks to the paragraph.
|
|
105
|
+
// Use listItem.allowsMarkType since the paragraph will be inside a listItem
|
|
106
|
+
// (which uses ParagraphWithFontSizeStage0 that allows fontSize).
|
|
107
|
+
var paragraphMarks = isBlockTaskEnabled && child.marks.length > 0 ? child.marks.filter(function (mark) {
|
|
108
|
+
return listItem.allowsMarkType(mark.type);
|
|
109
|
+
}) : undefined;
|
|
110
|
+
var paragraphNode = paragraph.create(null, _inlineContent.length > 0 ? _inlineContent : null, paragraphMarks);
|
|
64
111
|
transformedItems.push(listItem.create(null, [paragraphNode]));
|
|
112
|
+
} else if (isBlockTaskEnabled && child.type === blockTaskItem) {
|
|
113
|
+
// blockTaskItem wraps content in paragraphs — extract them directly,
|
|
114
|
+
// preserving their fontSize marks
|
|
115
|
+
var paragraphs = extractParagraphsFromBlockTaskItem(child);
|
|
116
|
+
if (paragraphs.length > 0) {
|
|
117
|
+
transformedItems.push(listItem.create(null, paragraphs));
|
|
118
|
+
}
|
|
65
119
|
} else if (child.type === taskList) {
|
|
66
120
|
var transformedNestedList = _transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
|
|
67
121
|
listNode: child
|
|
@@ -195,21 +249,27 @@ var transformBetweenListTypes = exports.transformBetweenListTypes = function tra
|
|
|
195
249
|
*/
|
|
196
250
|
var transformToTaskList = exports.transformToTaskList = function transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes) {
|
|
197
251
|
try {
|
|
198
|
-
var taskItem = nodes.taskItem
|
|
252
|
+
var taskItem = nodes.taskItem,
|
|
253
|
+
paragraph = nodes.paragraph,
|
|
254
|
+
blockTaskItem = nodes.blockTaskItem;
|
|
255
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
256
|
+
// but keep this solution general
|
|
257
|
+
var isBlockTaskItemEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
|
|
199
258
|
var listItems = [];
|
|
200
259
|
|
|
201
260
|
// Process each block in the range
|
|
202
261
|
tr.doc.nodesBetween(range.start, range.end, function (node) {
|
|
203
262
|
if (node.isBlock) {
|
|
204
|
-
// For block nodes like paragraphs, directly use their inline content
|
|
205
263
|
var inlineContent = (0, _toConsumableArray2.default)(node.content.content);
|
|
206
264
|
if (inlineContent.length > 0) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
265
|
+
if (isBlockTaskItemEnabled && node.type === paragraph && node.marks.length > 0) {
|
|
266
|
+
listItems.push(createBlockTaskItemWithMarks(inlineContent, node.marks, tr.doc.type.schema));
|
|
267
|
+
} else {
|
|
268
|
+
listItems.push(taskItem.create(targetAttrs, inlineContent));
|
|
269
|
+
}
|
|
210
270
|
}
|
|
211
271
|
}
|
|
212
|
-
return false;
|
|
272
|
+
return false;
|
|
213
273
|
});
|
|
214
274
|
if (listItems.length === 0) {
|
|
215
275
|
return null;
|
|
@@ -233,6 +293,44 @@ var transformTaskListToBlockNodes = exports.transformTaskListToBlockNodes = func
|
|
|
233
293
|
sourcePos = context.sourcePos;
|
|
234
294
|
var selection = tr.selection;
|
|
235
295
|
var schema = selection.$from.doc.type.schema;
|
|
296
|
+
var blockTaskItem = schema.nodes.blockTaskItem;
|
|
297
|
+
|
|
298
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
299
|
+
// but keep this solution general
|
|
300
|
+
var isBlockTaskItemEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
|
|
301
|
+
if (isBlockTaskItemEnabled) {
|
|
302
|
+
var blockTaskItemsResult = (0, _utils.findChildrenByType)(sourceNode, blockTaskItem);
|
|
303
|
+
if (blockTaskItemsResult.length > 0 && targetNodeType === schema.nodes.paragraph) {
|
|
304
|
+
// blockTaskItem content is (paragraph | extension)+
|
|
305
|
+
// Extract paragraph children directly — they may carry block marks (e.g. fontSize)
|
|
306
|
+
var _targetNodes = [];
|
|
307
|
+
var _iterator = _createForOfIteratorHelper(blockTaskItemsResult),
|
|
308
|
+
_step;
|
|
309
|
+
try {
|
|
310
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
311
|
+
var blockItem = _step.value.node;
|
|
312
|
+
blockItem.forEach(function (child) {
|
|
313
|
+
if (child.type === schema.nodes.paragraph) {
|
|
314
|
+
_targetNodes.push(child);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
} catch (err) {
|
|
319
|
+
_iterator.e(err);
|
|
320
|
+
} finally {
|
|
321
|
+
_iterator.f();
|
|
322
|
+
}
|
|
323
|
+
if (_targetNodes.length === 0) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
var _slice = new _model.Slice(_model.Fragment.fromArray(_targetNodes), 0, 0);
|
|
327
|
+
var _rangeStart = sourcePos !== null ? sourcePos : selection.from;
|
|
328
|
+
tr.replaceRange(_rangeStart, _rangeStart + sourceNode.nodeSize, _slice);
|
|
329
|
+
return tr;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Original logic for regular taskItem children
|
|
236
334
|
var taskItemsResult = (0, _utils.findChildrenByType)(sourceNode, schema.nodes.taskItem);
|
|
237
335
|
var taskItems = taskItemsResult.map(function (item) {
|
|
238
336
|
return item.node;
|
|
@@ -280,6 +378,10 @@ var getFormattedNode = exports.getFormattedNode = function getFormattedNode(tr)
|
|
|
280
378
|
var selection = tr.selection;
|
|
281
379
|
var nodes = tr.doc.type.schema.nodes;
|
|
282
380
|
|
|
381
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
382
|
+
// but keep this solution general
|
|
383
|
+
var isBlockTaskItemEnabled = !!nodes.blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
|
|
384
|
+
|
|
283
385
|
// Find the node to format from the current selection
|
|
284
386
|
var nodeToFormat;
|
|
285
387
|
var nodePos = selection.from;
|
|
@@ -291,13 +393,17 @@ var getFormattedNode = exports.getFormattedNode = function getFormattedNode(tr)
|
|
|
291
393
|
nodePos = selectedNode.pos;
|
|
292
394
|
} else {
|
|
293
395
|
// Try to find parent node (including list parents)
|
|
294
|
-
var
|
|
396
|
+
var parentNodeTypes = [nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection];
|
|
397
|
+
if (isBlockTaskItemEnabled) {
|
|
398
|
+
parentNodeTypes.push(nodes.blockTaskItem);
|
|
399
|
+
}
|
|
400
|
+
var parentNode = (0, _utils.findParentNodeOfType)(parentNodeTypes)(selection);
|
|
295
401
|
if (parentNode) {
|
|
296
402
|
nodeToFormat = parentNode.node;
|
|
297
403
|
nodePos = parentNode.pos;
|
|
298
404
|
var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
|
|
299
|
-
// Special case: if we found a listItem, check if we need the parent list instead
|
|
300
|
-
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
|
|
405
|
+
// Special case: if we found a listItem/taskItem/blockTaskItem, check if we need the parent list instead
|
|
406
|
+
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem || isBlockTaskItemEnabled && parentNode.node.type === nodes.blockTaskItem) {
|
|
301
407
|
var listParent = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
|
|
302
408
|
if (listParent) {
|
|
303
409
|
// For list transformations, we want the list parent, not the listItem
|
|
@@ -24,7 +24,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
|
|
|
24
24
|
* @jsx jsx
|
|
25
25
|
*/ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
26
26
|
var packageName = "@atlaskit/editor-common";
|
|
27
|
-
var packageVersion = "
|
|
27
|
+
var packageVersion = "0.0.0-development";
|
|
28
28
|
var halfFocusRing = 1;
|
|
29
29
|
var dropOffset = '0, 8';
|
|
30
30
|
var fadeIn = (0, _react2.keyframes)({
|
|
@@ -8,6 +8,7 @@ export { getCommonListAnalyticsAttributes, countListItemsInSelection } from './a
|
|
|
8
8
|
export { hasValidListIndentationLevel } from './indentation';
|
|
9
9
|
export { restoreSelection, computeSelectionOffsets } from './restore-selection';
|
|
10
10
|
export { buildReplacementFragment } from './build-replacement-fragment';
|
|
11
|
+
export { narrowReplacementRange } from './narrow-replacement-range';
|
|
11
12
|
export { flattenList } from './flatten-list';
|
|
12
13
|
export { isListNode, isListItemNode, isBulletList, isParagraphNode } from '../utils';
|
|
13
14
|
export { messages } from './messages';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
/**
|
|
3
|
+
* Narrows a full-list replacement to the minimal changed range.
|
|
4
|
+
*
|
|
5
|
+
* Compares the old root list node with the new replacement fragment
|
|
6
|
+
* from both ends to find the first and last positions where they differ,
|
|
7
|
+
* then returns only the changed subrange.
|
|
8
|
+
*
|
|
9
|
+
* This reduces the scope of `tr.replaceWith()` so that remote cursors
|
|
10
|
+
* on unchanged items are preserved during collaborative editing.
|
|
11
|
+
*/
|
|
12
|
+
export function narrowReplacementRange(doc, rootListStart, rootListEnd, fragment, contentStartOffsets) {
|
|
13
|
+
const oldNode = doc.nodeAt(rootListStart);
|
|
14
|
+
const newNode = fragment.childCount === 1 ? fragment.firstChild : null;
|
|
15
|
+
if (!oldNode || !newNode || newNode.type !== oldNode.type) {
|
|
16
|
+
return {
|
|
17
|
+
start: rootListStart,
|
|
18
|
+
end: rootListEnd,
|
|
19
|
+
fragment,
|
|
20
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const minChildCount = Math.min(oldNode.childCount, newNode.childCount);
|
|
24
|
+
let commonPrefixChildren = 0;
|
|
25
|
+
let prefixSize = 0;
|
|
26
|
+
for (let i = 0; i < minChildCount; i++) {
|
|
27
|
+
const oldChild = oldNode.child(i);
|
|
28
|
+
const newChild = newNode.child(i);
|
|
29
|
+
if (oldChild.eq(newChild)) {
|
|
30
|
+
commonPrefixChildren++;
|
|
31
|
+
prefixSize += oldChild.nodeSize;
|
|
32
|
+
} else {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let commonSuffixChildren = 0;
|
|
37
|
+
let suffixSize = 0;
|
|
38
|
+
for (let i = 0; i < minChildCount - commonPrefixChildren; i++) {
|
|
39
|
+
const oldChild = oldNode.child(oldNode.childCount - 1 - i);
|
|
40
|
+
const newChild = newNode.child(newNode.childCount - 1 - i);
|
|
41
|
+
if (oldChild.eq(newChild)) {
|
|
42
|
+
commonSuffixChildren++;
|
|
43
|
+
suffixSize += oldChild.nodeSize;
|
|
44
|
+
} else {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const totalCommon = commonPrefixChildren + commonSuffixChildren;
|
|
49
|
+
if (totalCommon >= oldNode.childCount && totalCommon >= newNode.childCount) {
|
|
50
|
+
return {
|
|
51
|
+
start: rootListStart,
|
|
52
|
+
end: rootListStart,
|
|
53
|
+
fragment: Fragment.empty,
|
|
54
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const narrowedStart = rootListStart + 1 + prefixSize;
|
|
58
|
+
const narrowedEnd = rootListEnd - 1 - suffixSize;
|
|
59
|
+
const changedChildStart = commonPrefixChildren;
|
|
60
|
+
const changedChildEnd = newNode.childCount - commonSuffixChildren;
|
|
61
|
+
const changedNodes = [];
|
|
62
|
+
for (let i = changedChildStart; i < changedChildEnd; i++) {
|
|
63
|
+
changedNodes.push(newNode.child(i));
|
|
64
|
+
}
|
|
65
|
+
const narrowedFragment = Fragment.from(changedNodes);
|
|
66
|
+
const prefixOffset = 1 + prefixSize;
|
|
67
|
+
const adjustedContentStartOffsets = contentStartOffsets.map(offset => offset - prefixOffset);
|
|
68
|
+
return {
|
|
69
|
+
start: narrowedStart,
|
|
70
|
+
end: narrowedEnd,
|
|
71
|
+
fragment: narrowedFragment,
|
|
72
|
+
adjustedContentStartOffsets
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -3,6 +3,7 @@ import { useIntl } from 'react-intl-next';
|
|
|
3
3
|
import InfoIcon from '@atlaskit/icon/core/status-information';
|
|
4
4
|
// eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
|
|
5
5
|
import { Box, xcss } from '@atlaskit/primitives';
|
|
6
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
6
7
|
import Tooltip from '@atlaskit/tooltip';
|
|
7
8
|
import { externalMediaMessages } from '../media';
|
|
8
9
|
const baseStyles = xcss({
|
|
@@ -13,6 +14,7 @@ const baseStyles = xcss({
|
|
|
13
14
|
cursor: 'pointer'
|
|
14
15
|
});
|
|
15
16
|
const NO_EXTERNAL_BADGE_HOSTS = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com'];
|
|
17
|
+
const NO_EXTERNAL_BADGE_HOSTS_NEW = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com', 'bitbucket.org'];
|
|
16
18
|
export const isUnbadgedUrl = url => {
|
|
17
19
|
if (!url) {
|
|
18
20
|
return false;
|
|
@@ -32,6 +34,9 @@ export const isUnbadgedUrl = url => {
|
|
|
32
34
|
if (protocol === 'data:') {
|
|
33
35
|
return pathname === null || pathname === void 0 ? void 0 : pathname.startsWith('image/');
|
|
34
36
|
}
|
|
37
|
+
if (expValEquals('platform_editor_media_external_badge_bbc_fix', 'isEnable', true)) {
|
|
38
|
+
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS_NEW.some(host => hostname === host || hostname.endsWith(`.${host}`)));
|
|
39
|
+
}
|
|
35
40
|
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS.some(host => hostname === host || hostname.endsWith(`.${host}`)));
|
|
36
41
|
};
|
|
37
42
|
export const ExternalImageBadge = ({
|
|
@@ -4,7 +4,7 @@ import { isFedRamp } from './environment';
|
|
|
4
4
|
import { normaliseSentryBreadcrumbs, SERIALIZABLE_ATTRIBUTES } from './normalise-sentry-breadcrumbs';
|
|
5
5
|
const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
6
6
|
const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
7
|
-
const packageVersion = "
|
|
7
|
+
const packageVersion = "0.0.0-development";
|
|
8
8
|
const sanitiseSentryEvents = (data, _hint) => {
|
|
9
9
|
// Remove URL as it has UGC
|
|
10
10
|
// Ignored via go/ees007
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
2
2
|
import { findChildrenByType, findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
3
4
|
import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList, convertBlockToInlineContent } from './list-utils';
|
|
4
5
|
const getContentSupportChecker = targetNodeType => {
|
|
5
6
|
return node => {
|
|
@@ -10,6 +11,15 @@ const getContentSupportChecker = targetNodeType => {
|
|
|
10
11
|
}
|
|
11
12
|
};
|
|
12
13
|
};
|
|
14
|
+
const createBlockTaskItemWithMarks = (content, marks, schema) => {
|
|
15
|
+
const {
|
|
16
|
+
blockTaskItem,
|
|
17
|
+
paragraph
|
|
18
|
+
} = schema.nodes;
|
|
19
|
+
const allowedMarks = marks.filter(mark => blockTaskItem.allowsMarkType(mark.type));
|
|
20
|
+
const newParagraph = paragraph.create(null, content.length > 0 ? content : null, allowedMarks);
|
|
21
|
+
return blockTaskItem.create(null, newParagraph);
|
|
22
|
+
};
|
|
13
23
|
export const transformListRecursively = (props, onhandleUnsupportedContent) => {
|
|
14
24
|
const transformedItems = [];
|
|
15
25
|
const {
|
|
@@ -26,14 +36,33 @@ export const transformListRecursively = (props, onhandleUnsupportedContent) => {
|
|
|
26
36
|
taskList,
|
|
27
37
|
listItem,
|
|
28
38
|
taskItem,
|
|
29
|
-
paragraph
|
|
39
|
+
paragraph,
|
|
40
|
+
blockTaskItem
|
|
30
41
|
} = schema.nodes;
|
|
42
|
+
|
|
43
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
44
|
+
// but keep this solution general
|
|
45
|
+
const isBlockTaskEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Extracts paragraph children from a blockTaskItem, preserving their marks.
|
|
49
|
+
*/
|
|
50
|
+
const extractParagraphsFromBlockTaskItem = node => {
|
|
51
|
+
const paragraphs = [];
|
|
52
|
+
node.forEach(child => {
|
|
53
|
+
if (child.type === paragraph) {
|
|
54
|
+
paragraphs.push(child);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return paragraphs;
|
|
58
|
+
};
|
|
31
59
|
listNode.forEach(child => {
|
|
32
60
|
if (isSourceBulletOrOrdered && isTargetTask) {
|
|
33
61
|
// Convert bullet/ordered => task
|
|
34
62
|
if (child.type === listItem) {
|
|
35
63
|
const inlineContent = [];
|
|
36
64
|
const nestedTaskLists = [];
|
|
65
|
+
let blockMarks = [];
|
|
37
66
|
child.forEach(grandChild => {
|
|
38
67
|
if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
|
|
39
68
|
nestedTaskLists.push(transformListRecursively({
|
|
@@ -43,18 +72,37 @@ export const transformListRecursively = (props, onhandleUnsupportedContent) => {
|
|
|
43
72
|
} else if (!getContentSupportChecker(taskItem)(grandChild) && !grandChild.isTextblock) {
|
|
44
73
|
onhandleUnsupportedContent === null || onhandleUnsupportedContent === void 0 ? void 0 : onhandleUnsupportedContent(grandChild);
|
|
45
74
|
} else {
|
|
75
|
+
if (isBlockTaskEnabled && grandChild.type === paragraph && grandChild.marks.length > 0) {
|
|
76
|
+
blockMarks = grandChild.marks;
|
|
77
|
+
}
|
|
46
78
|
inlineContent.push(...convertBlockToInlineContent(grandChild, schema));
|
|
47
79
|
}
|
|
48
80
|
});
|
|
49
|
-
|
|
81
|
+
if (isBlockTaskEnabled && blockMarks.length > 0) {
|
|
82
|
+
transformedItems.push(createBlockTaskItemWithMarks(inlineContent, blockMarks, schema));
|
|
83
|
+
} else {
|
|
84
|
+
transformedItems.push(taskItem.create(null, inlineContent.length > 0 ? inlineContent : null));
|
|
85
|
+
}
|
|
50
86
|
transformedItems.push(...nestedTaskLists);
|
|
51
87
|
}
|
|
52
88
|
} else if (isSourceTask && isTargetBulletOrOrdered) {
|
|
53
89
|
// Convert task => bullet/ordered
|
|
54
90
|
if (child.type === taskItem) {
|
|
55
91
|
const inlineContent = [...child.content.content];
|
|
56
|
-
|
|
92
|
+
|
|
93
|
+
// Transfer taskItem's block marks to the paragraph.
|
|
94
|
+
// Use listItem.allowsMarkType since the paragraph will be inside a listItem
|
|
95
|
+
// (which uses ParagraphWithFontSizeStage0 that allows fontSize).
|
|
96
|
+
const paragraphMarks = isBlockTaskEnabled && child.marks.length > 0 ? child.marks.filter(mark => listItem.allowsMarkType(mark.type)) : undefined;
|
|
97
|
+
const paragraphNode = paragraph.create(null, inlineContent.length > 0 ? inlineContent : null, paragraphMarks);
|
|
57
98
|
transformedItems.push(listItem.create(null, [paragraphNode]));
|
|
99
|
+
} else if (isBlockTaskEnabled && child.type === blockTaskItem) {
|
|
100
|
+
// blockTaskItem wraps content in paragraphs — extract them directly,
|
|
101
|
+
// preserving their fontSize marks
|
|
102
|
+
const paragraphs = extractParagraphsFromBlockTaskItem(child);
|
|
103
|
+
if (paragraphs.length > 0) {
|
|
104
|
+
transformedItems.push(listItem.create(null, paragraphs));
|
|
105
|
+
}
|
|
58
106
|
} else if (child.type === taskList) {
|
|
59
107
|
const transformedNestedList = transformListRecursively({
|
|
60
108
|
...props,
|
|
@@ -199,22 +247,28 @@ export const transformBetweenListTypes = context => {
|
|
|
199
247
|
export const transformToTaskList = (tr, range, targetNodeType, targetAttrs, nodes) => {
|
|
200
248
|
try {
|
|
201
249
|
const {
|
|
202
|
-
taskItem
|
|
250
|
+
taskItem,
|
|
251
|
+
paragraph,
|
|
252
|
+
blockTaskItem
|
|
203
253
|
} = nodes;
|
|
254
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
255
|
+
// but keep this solution general
|
|
256
|
+
const isBlockTaskItemEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
204
257
|
const listItems = [];
|
|
205
258
|
|
|
206
259
|
// Process each block in the range
|
|
207
260
|
tr.doc.nodesBetween(range.start, range.end, node => {
|
|
208
261
|
if (node.isBlock) {
|
|
209
|
-
// For block nodes like paragraphs, directly use their inline content
|
|
210
262
|
const inlineContent = [...node.content.content];
|
|
211
263
|
if (inlineContent.length > 0) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
264
|
+
if (isBlockTaskItemEnabled && node.type === paragraph && node.marks.length > 0) {
|
|
265
|
+
listItems.push(createBlockTaskItemWithMarks(inlineContent, node.marks, tr.doc.type.schema));
|
|
266
|
+
} else {
|
|
267
|
+
listItems.push(taskItem.create(targetAttrs, inlineContent));
|
|
268
|
+
}
|
|
215
269
|
}
|
|
216
270
|
}
|
|
217
|
-
return false;
|
|
271
|
+
return false;
|
|
218
272
|
});
|
|
219
273
|
if (listItems.length === 0) {
|
|
220
274
|
return null;
|
|
@@ -242,6 +296,39 @@ export const transformTaskListToBlockNodes = context => {
|
|
|
242
296
|
selection
|
|
243
297
|
} = tr;
|
|
244
298
|
const schema = selection.$from.doc.type.schema;
|
|
299
|
+
const {
|
|
300
|
+
blockTaskItem
|
|
301
|
+
} = schema.nodes;
|
|
302
|
+
|
|
303
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
304
|
+
// but keep this solution general
|
|
305
|
+
const isBlockTaskItemEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
306
|
+
if (isBlockTaskItemEnabled) {
|
|
307
|
+
const blockTaskItemsResult = findChildrenByType(sourceNode, blockTaskItem);
|
|
308
|
+
if (blockTaskItemsResult.length > 0 && targetNodeType === schema.nodes.paragraph) {
|
|
309
|
+
// blockTaskItem content is (paragraph | extension)+
|
|
310
|
+
// Extract paragraph children directly — they may carry block marks (e.g. fontSize)
|
|
311
|
+
const targetNodes = [];
|
|
312
|
+
for (const {
|
|
313
|
+
node: blockItem
|
|
314
|
+
} of blockTaskItemsResult) {
|
|
315
|
+
blockItem.forEach(child => {
|
|
316
|
+
if (child.type === schema.nodes.paragraph) {
|
|
317
|
+
targetNodes.push(child);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
if (targetNodes.length === 0) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
const slice = new Slice(Fragment.fromArray(targetNodes), 0, 0);
|
|
325
|
+
const rangeStart = sourcePos !== null ? sourcePos : selection.from;
|
|
326
|
+
tr.replaceRange(rangeStart, rangeStart + sourceNode.nodeSize, slice);
|
|
327
|
+
return tr;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Original logic for regular taskItem children
|
|
245
332
|
const taskItemsResult = findChildrenByType(sourceNode, schema.nodes.taskItem);
|
|
246
333
|
const taskItems = taskItemsResult.map(item => item.node);
|
|
247
334
|
const taskItemFragments = taskItems.map(taskItem => taskItem.content);
|
|
@@ -283,6 +370,10 @@ export const getFormattedNode = tr => {
|
|
|
283
370
|
nodes
|
|
284
371
|
} = tr.doc.type.schema;
|
|
285
372
|
|
|
373
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
374
|
+
// but keep this solution general
|
|
375
|
+
const isBlockTaskItemEnabled = !!nodes.blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
376
|
+
|
|
286
377
|
// Find the node to format from the current selection
|
|
287
378
|
let nodeToFormat;
|
|
288
379
|
let nodePos = selection.from;
|
|
@@ -294,13 +385,17 @@ export const getFormattedNode = tr => {
|
|
|
294
385
|
nodePos = selectedNode.pos;
|
|
295
386
|
} else {
|
|
296
387
|
// Try to find parent node (including list parents)
|
|
297
|
-
const
|
|
388
|
+
const parentNodeTypes = [nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection];
|
|
389
|
+
if (isBlockTaskItemEnabled) {
|
|
390
|
+
parentNodeTypes.push(nodes.blockTaskItem);
|
|
391
|
+
}
|
|
392
|
+
const parentNode = findParentNodeOfType(parentNodeTypes)(selection);
|
|
298
393
|
if (parentNode) {
|
|
299
394
|
nodeToFormat = parentNode.node;
|
|
300
395
|
nodePos = parentNode.pos;
|
|
301
396
|
const paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
|
|
302
|
-
// Special case: if we found a listItem, check if we need the parent list instead
|
|
303
|
-
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
|
|
397
|
+
// Special case: if we found a listItem/taskItem/blockTaskItem, check if we need the parent list instead
|
|
398
|
+
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem || isBlockTaskItemEnabled && parentNode.node.type === nodes.blockTaskItem) {
|
|
304
399
|
const listParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
|
|
305
400
|
if (listParent) {
|
|
306
401
|
// For list transformations, we want the list parent, not the listItem
|
|
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
|
|
|
14
14
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
15
15
|
import Layer from '../Layer';
|
|
16
16
|
const packageName = "@atlaskit/editor-common";
|
|
17
|
-
const packageVersion = "
|
|
17
|
+
const packageVersion = "0.0.0-development";
|
|
18
18
|
const halfFocusRing = 1;
|
|
19
19
|
const dropOffset = '0, 8';
|
|
20
20
|
const fadeIn = keyframes({
|
package/dist/esm/lists/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { getCommonListAnalyticsAttributes, countListItemsInSelection } from './a
|
|
|
8
8
|
export { hasValidListIndentationLevel } from './indentation';
|
|
9
9
|
export { restoreSelection, computeSelectionOffsets } from './restore-selection';
|
|
10
10
|
export { buildReplacementFragment } from './build-replacement-fragment';
|
|
11
|
+
export { narrowReplacementRange } from './narrow-replacement-range';
|
|
11
12
|
export { flattenList } from './flatten-list';
|
|
12
13
|
export { isListNode, isListItemNode, isBulletList, isParagraphNode } from '../utils';
|
|
13
14
|
export { messages } from './messages';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
/**
|
|
3
|
+
* Narrows a full-list replacement to the minimal changed range.
|
|
4
|
+
*
|
|
5
|
+
* Compares the old root list node with the new replacement fragment
|
|
6
|
+
* from both ends to find the first and last positions where they differ,
|
|
7
|
+
* then returns only the changed subrange.
|
|
8
|
+
*
|
|
9
|
+
* This reduces the scope of `tr.replaceWith()` so that remote cursors
|
|
10
|
+
* on unchanged items are preserved during collaborative editing.
|
|
11
|
+
*/
|
|
12
|
+
export function narrowReplacementRange(doc, rootListStart, rootListEnd, fragment, contentStartOffsets) {
|
|
13
|
+
var oldNode = doc.nodeAt(rootListStart);
|
|
14
|
+
var newNode = fragment.childCount === 1 ? fragment.firstChild : null;
|
|
15
|
+
if (!oldNode || !newNode || newNode.type !== oldNode.type) {
|
|
16
|
+
return {
|
|
17
|
+
start: rootListStart,
|
|
18
|
+
end: rootListEnd,
|
|
19
|
+
fragment: fragment,
|
|
20
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
var minChildCount = Math.min(oldNode.childCount, newNode.childCount);
|
|
24
|
+
var commonPrefixChildren = 0;
|
|
25
|
+
var prefixSize = 0;
|
|
26
|
+
for (var i = 0; i < minChildCount; i++) {
|
|
27
|
+
var oldChild = oldNode.child(i);
|
|
28
|
+
var newChild = newNode.child(i);
|
|
29
|
+
if (oldChild.eq(newChild)) {
|
|
30
|
+
commonPrefixChildren++;
|
|
31
|
+
prefixSize += oldChild.nodeSize;
|
|
32
|
+
} else {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
var commonSuffixChildren = 0;
|
|
37
|
+
var suffixSize = 0;
|
|
38
|
+
for (var _i = 0; _i < minChildCount - commonPrefixChildren; _i++) {
|
|
39
|
+
var _oldChild = oldNode.child(oldNode.childCount - 1 - _i);
|
|
40
|
+
var _newChild = newNode.child(newNode.childCount - 1 - _i);
|
|
41
|
+
if (_oldChild.eq(_newChild)) {
|
|
42
|
+
commonSuffixChildren++;
|
|
43
|
+
suffixSize += _oldChild.nodeSize;
|
|
44
|
+
} else {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var totalCommon = commonPrefixChildren + commonSuffixChildren;
|
|
49
|
+
if (totalCommon >= oldNode.childCount && totalCommon >= newNode.childCount) {
|
|
50
|
+
return {
|
|
51
|
+
start: rootListStart,
|
|
52
|
+
end: rootListStart,
|
|
53
|
+
fragment: Fragment.empty,
|
|
54
|
+
adjustedContentStartOffsets: contentStartOffsets
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
var narrowedStart = rootListStart + 1 + prefixSize;
|
|
58
|
+
var narrowedEnd = rootListEnd - 1 - suffixSize;
|
|
59
|
+
var changedChildStart = commonPrefixChildren;
|
|
60
|
+
var changedChildEnd = newNode.childCount - commonSuffixChildren;
|
|
61
|
+
var changedNodes = [];
|
|
62
|
+
for (var _i2 = changedChildStart; _i2 < changedChildEnd; _i2++) {
|
|
63
|
+
changedNodes.push(newNode.child(_i2));
|
|
64
|
+
}
|
|
65
|
+
var narrowedFragment = Fragment.from(changedNodes);
|
|
66
|
+
var prefixOffset = 1 + prefixSize;
|
|
67
|
+
var adjustedContentStartOffsets = contentStartOffsets.map(function (offset) {
|
|
68
|
+
return offset - prefixOffset;
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
start: narrowedStart,
|
|
72
|
+
end: narrowedEnd,
|
|
73
|
+
fragment: narrowedFragment,
|
|
74
|
+
adjustedContentStartOffsets: adjustedContentStartOffsets
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -3,6 +3,7 @@ import { useIntl } from 'react-intl-next';
|
|
|
3
3
|
import InfoIcon from '@atlaskit/icon/core/status-information';
|
|
4
4
|
// eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
|
|
5
5
|
import { Box, xcss } from '@atlaskit/primitives';
|
|
6
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
6
7
|
import Tooltip from '@atlaskit/tooltip';
|
|
7
8
|
import { externalMediaMessages } from '../media';
|
|
8
9
|
var baseStyles = xcss({
|
|
@@ -13,6 +14,7 @@ var baseStyles = xcss({
|
|
|
13
14
|
cursor: 'pointer'
|
|
14
15
|
});
|
|
15
16
|
var NO_EXTERNAL_BADGE_HOSTS = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com'];
|
|
17
|
+
var NO_EXTERNAL_BADGE_HOSTS_NEW = ['atlassian.com', 'loom.com', 'dam-cdn.atl.orangelogic.com', 'bitbucket.org'];
|
|
16
18
|
export var isUnbadgedUrl = function isUnbadgedUrl(url) {
|
|
17
19
|
if (!url) {
|
|
18
20
|
return false;
|
|
@@ -30,6 +32,11 @@ export var isUnbadgedUrl = function isUnbadgedUrl(url) {
|
|
|
30
32
|
if (protocol === 'data:') {
|
|
31
33
|
return pathname === null || pathname === void 0 ? void 0 : pathname.startsWith('image/');
|
|
32
34
|
}
|
|
35
|
+
if (expValEquals('platform_editor_media_external_badge_bbc_fix', 'isEnable', true)) {
|
|
36
|
+
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS_NEW.some(function (host) {
|
|
37
|
+
return hostname === host || hostname.endsWith(".".concat(host));
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
33
40
|
return Boolean(hostname && NO_EXTERNAL_BADGE_HOSTS.some(function (host) {
|
|
34
41
|
return hostname === host || hostname.endsWith(".".concat(host));
|
|
35
42
|
}));
|
|
@@ -10,7 +10,7 @@ import { isFedRamp } from './environment';
|
|
|
10
10
|
import { normaliseSentryBreadcrumbs, SERIALIZABLE_ATTRIBUTES } from './normalise-sentry-breadcrumbs';
|
|
11
11
|
var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
12
12
|
var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
13
|
-
var packageVersion = "
|
|
13
|
+
var packageVersion = "0.0.0-development";
|
|
14
14
|
var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
|
|
15
15
|
// Remove URL as it has UGC
|
|
16
16
|
// Ignored via go/ees007
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
4
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
5
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
3
6
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
7
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
8
|
import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
6
9
|
import { findChildrenByType, findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
10
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
11
|
import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList, convertBlockToInlineContent } from './list-utils';
|
|
8
12
|
var getContentSupportChecker = function getContentSupportChecker(targetNodeType) {
|
|
9
13
|
return function (node) {
|
|
@@ -14,6 +18,16 @@ var getContentSupportChecker = function getContentSupportChecker(targetNodeType)
|
|
|
14
18
|
}
|
|
15
19
|
};
|
|
16
20
|
};
|
|
21
|
+
var createBlockTaskItemWithMarks = function createBlockTaskItemWithMarks(content, marks, schema) {
|
|
22
|
+
var _schema$nodes = schema.nodes,
|
|
23
|
+
blockTaskItem = _schema$nodes.blockTaskItem,
|
|
24
|
+
paragraph = _schema$nodes.paragraph;
|
|
25
|
+
var allowedMarks = marks.filter(function (mark) {
|
|
26
|
+
return blockTaskItem.allowsMarkType(mark.type);
|
|
27
|
+
});
|
|
28
|
+
var newParagraph = paragraph.create(null, content.length > 0 ? content : null, allowedMarks);
|
|
29
|
+
return blockTaskItem.create(null, newParagraph);
|
|
30
|
+
};
|
|
17
31
|
var _transformListRecursively = function transformListRecursively(props, onhandleUnsupportedContent) {
|
|
18
32
|
var transformedItems = [];
|
|
19
33
|
var listNode = props.listNode,
|
|
@@ -24,17 +38,36 @@ var _transformListRecursively = function transformListRecursively(props, onhandl
|
|
|
24
38
|
supportedListTypes = props.supportedListTypes,
|
|
25
39
|
schema = props.schema,
|
|
26
40
|
targetNodeType = props.targetNodeType;
|
|
27
|
-
var _schema$
|
|
28
|
-
taskList = _schema$
|
|
29
|
-
listItem = _schema$
|
|
30
|
-
taskItem = _schema$
|
|
31
|
-
paragraph = _schema$
|
|
41
|
+
var _schema$nodes2 = schema.nodes,
|
|
42
|
+
taskList = _schema$nodes2.taskList,
|
|
43
|
+
listItem = _schema$nodes2.listItem,
|
|
44
|
+
taskItem = _schema$nodes2.taskItem,
|
|
45
|
+
paragraph = _schema$nodes2.paragraph,
|
|
46
|
+
blockTaskItem = _schema$nodes2.blockTaskItem;
|
|
47
|
+
|
|
48
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
49
|
+
// but keep this solution general
|
|
50
|
+
var isBlockTaskEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extracts paragraph children from a blockTaskItem, preserving their marks.
|
|
54
|
+
*/
|
|
55
|
+
var extractParagraphsFromBlockTaskItem = function extractParagraphsFromBlockTaskItem(node) {
|
|
56
|
+
var paragraphs = [];
|
|
57
|
+
node.forEach(function (child) {
|
|
58
|
+
if (child.type === paragraph) {
|
|
59
|
+
paragraphs.push(child);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return paragraphs;
|
|
63
|
+
};
|
|
32
64
|
listNode.forEach(function (child) {
|
|
33
65
|
if (isSourceBulletOrOrdered && isTargetTask) {
|
|
34
66
|
// Convert bullet/ordered => task
|
|
35
67
|
if (child.type === listItem) {
|
|
36
68
|
var inlineContent = [];
|
|
37
69
|
var nestedTaskLists = [];
|
|
70
|
+
var blockMarks = [];
|
|
38
71
|
child.forEach(function (grandChild) {
|
|
39
72
|
if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
|
|
40
73
|
nestedTaskLists.push(_transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
|
|
@@ -43,18 +76,39 @@ var _transformListRecursively = function transformListRecursively(props, onhandl
|
|
|
43
76
|
} else if (!getContentSupportChecker(taskItem)(grandChild) && !grandChild.isTextblock) {
|
|
44
77
|
onhandleUnsupportedContent === null || onhandleUnsupportedContent === void 0 || onhandleUnsupportedContent(grandChild);
|
|
45
78
|
} else {
|
|
79
|
+
if (isBlockTaskEnabled && grandChild.type === paragraph && grandChild.marks.length > 0) {
|
|
80
|
+
blockMarks = grandChild.marks;
|
|
81
|
+
}
|
|
46
82
|
inlineContent.push.apply(inlineContent, _toConsumableArray(convertBlockToInlineContent(grandChild, schema)));
|
|
47
83
|
}
|
|
48
84
|
});
|
|
49
|
-
|
|
85
|
+
if (isBlockTaskEnabled && blockMarks.length > 0) {
|
|
86
|
+
transformedItems.push(createBlockTaskItemWithMarks(inlineContent, blockMarks, schema));
|
|
87
|
+
} else {
|
|
88
|
+
transformedItems.push(taskItem.create(null, inlineContent.length > 0 ? inlineContent : null));
|
|
89
|
+
}
|
|
50
90
|
transformedItems.push.apply(transformedItems, nestedTaskLists);
|
|
51
91
|
}
|
|
52
92
|
} else if (isSourceTask && isTargetBulletOrOrdered) {
|
|
53
93
|
// Convert task => bullet/ordered
|
|
54
94
|
if (child.type === taskItem) {
|
|
55
95
|
var _inlineContent = _toConsumableArray(child.content.content);
|
|
56
|
-
|
|
96
|
+
|
|
97
|
+
// Transfer taskItem's block marks to the paragraph.
|
|
98
|
+
// Use listItem.allowsMarkType since the paragraph will be inside a listItem
|
|
99
|
+
// (which uses ParagraphWithFontSizeStage0 that allows fontSize).
|
|
100
|
+
var paragraphMarks = isBlockTaskEnabled && child.marks.length > 0 ? child.marks.filter(function (mark) {
|
|
101
|
+
return listItem.allowsMarkType(mark.type);
|
|
102
|
+
}) : undefined;
|
|
103
|
+
var paragraphNode = paragraph.create(null, _inlineContent.length > 0 ? _inlineContent : null, paragraphMarks);
|
|
57
104
|
transformedItems.push(listItem.create(null, [paragraphNode]));
|
|
105
|
+
} else if (isBlockTaskEnabled && child.type === blockTaskItem) {
|
|
106
|
+
// blockTaskItem wraps content in paragraphs — extract them directly,
|
|
107
|
+
// preserving their fontSize marks
|
|
108
|
+
var paragraphs = extractParagraphsFromBlockTaskItem(child);
|
|
109
|
+
if (paragraphs.length > 0) {
|
|
110
|
+
transformedItems.push(listItem.create(null, paragraphs));
|
|
111
|
+
}
|
|
58
112
|
} else if (child.type === taskList) {
|
|
59
113
|
var transformedNestedList = _transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
|
|
60
114
|
listNode: child
|
|
@@ -189,21 +243,27 @@ export var transformBetweenListTypes = function transformBetweenListTypes(contex
|
|
|
189
243
|
*/
|
|
190
244
|
export var transformToTaskList = function transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes) {
|
|
191
245
|
try {
|
|
192
|
-
var taskItem = nodes.taskItem
|
|
246
|
+
var taskItem = nodes.taskItem,
|
|
247
|
+
paragraph = nodes.paragraph,
|
|
248
|
+
blockTaskItem = nodes.blockTaskItem;
|
|
249
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
250
|
+
// but keep this solution general
|
|
251
|
+
var isBlockTaskItemEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
193
252
|
var listItems = [];
|
|
194
253
|
|
|
195
254
|
// Process each block in the range
|
|
196
255
|
tr.doc.nodesBetween(range.start, range.end, function (node) {
|
|
197
256
|
if (node.isBlock) {
|
|
198
|
-
// For block nodes like paragraphs, directly use their inline content
|
|
199
257
|
var inlineContent = _toConsumableArray(node.content.content);
|
|
200
258
|
if (inlineContent.length > 0) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
259
|
+
if (isBlockTaskItemEnabled && node.type === paragraph && node.marks.length > 0) {
|
|
260
|
+
listItems.push(createBlockTaskItemWithMarks(inlineContent, node.marks, tr.doc.type.schema));
|
|
261
|
+
} else {
|
|
262
|
+
listItems.push(taskItem.create(targetAttrs, inlineContent));
|
|
263
|
+
}
|
|
204
264
|
}
|
|
205
265
|
}
|
|
206
|
-
return false;
|
|
266
|
+
return false;
|
|
207
267
|
});
|
|
208
268
|
if (listItems.length === 0) {
|
|
209
269
|
return null;
|
|
@@ -227,6 +287,44 @@ export var transformTaskListToBlockNodes = function transformTaskListToBlockNode
|
|
|
227
287
|
sourcePos = context.sourcePos;
|
|
228
288
|
var selection = tr.selection;
|
|
229
289
|
var schema = selection.$from.doc.type.schema;
|
|
290
|
+
var blockTaskItem = schema.nodes.blockTaskItem;
|
|
291
|
+
|
|
292
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
293
|
+
// but keep this solution general
|
|
294
|
+
var isBlockTaskItemEnabled = !!blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
295
|
+
if (isBlockTaskItemEnabled) {
|
|
296
|
+
var blockTaskItemsResult = findChildrenByType(sourceNode, blockTaskItem);
|
|
297
|
+
if (blockTaskItemsResult.length > 0 && targetNodeType === schema.nodes.paragraph) {
|
|
298
|
+
// blockTaskItem content is (paragraph | extension)+
|
|
299
|
+
// Extract paragraph children directly — they may carry block marks (e.g. fontSize)
|
|
300
|
+
var _targetNodes = [];
|
|
301
|
+
var _iterator = _createForOfIteratorHelper(blockTaskItemsResult),
|
|
302
|
+
_step;
|
|
303
|
+
try {
|
|
304
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
305
|
+
var blockItem = _step.value.node;
|
|
306
|
+
blockItem.forEach(function (child) {
|
|
307
|
+
if (child.type === schema.nodes.paragraph) {
|
|
308
|
+
_targetNodes.push(child);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
} catch (err) {
|
|
313
|
+
_iterator.e(err);
|
|
314
|
+
} finally {
|
|
315
|
+
_iterator.f();
|
|
316
|
+
}
|
|
317
|
+
if (_targetNodes.length === 0) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
var _slice = new Slice(Fragment.fromArray(_targetNodes), 0, 0);
|
|
321
|
+
var _rangeStart = sourcePos !== null ? sourcePos : selection.from;
|
|
322
|
+
tr.replaceRange(_rangeStart, _rangeStart + sourceNode.nodeSize, _slice);
|
|
323
|
+
return tr;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Original logic for regular taskItem children
|
|
230
328
|
var taskItemsResult = findChildrenByType(sourceNode, schema.nodes.taskItem);
|
|
231
329
|
var taskItems = taskItemsResult.map(function (item) {
|
|
232
330
|
return item.node;
|
|
@@ -274,6 +372,10 @@ export var getFormattedNode = function getFormattedNode(tr) {
|
|
|
274
372
|
var selection = tr.selection;
|
|
275
373
|
var nodes = tr.doc.type.schema.nodes;
|
|
276
374
|
|
|
375
|
+
// gating behind platform_editor_small_font_size to support task lists with font size applied,
|
|
376
|
+
// but keep this solution general
|
|
377
|
+
var isBlockTaskItemEnabled = !!nodes.blockTaskItem && expValEquals('platform_editor_small_font_size', 'isEnabled', true);
|
|
378
|
+
|
|
277
379
|
// Find the node to format from the current selection
|
|
278
380
|
var nodeToFormat;
|
|
279
381
|
var nodePos = selection.from;
|
|
@@ -285,13 +387,17 @@ export var getFormattedNode = function getFormattedNode(tr) {
|
|
|
285
387
|
nodePos = selectedNode.pos;
|
|
286
388
|
} else {
|
|
287
389
|
// Try to find parent node (including list parents)
|
|
288
|
-
var
|
|
390
|
+
var parentNodeTypes = [nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection];
|
|
391
|
+
if (isBlockTaskItemEnabled) {
|
|
392
|
+
parentNodeTypes.push(nodes.blockTaskItem);
|
|
393
|
+
}
|
|
394
|
+
var parentNode = findParentNodeOfType(parentNodeTypes)(selection);
|
|
289
395
|
if (parentNode) {
|
|
290
396
|
nodeToFormat = parentNode.node;
|
|
291
397
|
nodePos = parentNode.pos;
|
|
292
398
|
var paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
|
|
293
|
-
// Special case: if we found a listItem, check if we need the parent list instead
|
|
294
|
-
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
|
|
399
|
+
// Special case: if we found a listItem/taskItem/blockTaskItem, check if we need the parent list instead
|
|
400
|
+
if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem || isBlockTaskItemEnabled && parentNode.node.type === nodes.blockTaskItem) {
|
|
295
401
|
var listParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
|
|
296
402
|
if (listParent) {
|
|
297
403
|
// For list transformations, we want the list parent, not the listItem
|
|
@@ -21,7 +21,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
|
|
|
21
21
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
22
22
|
import Layer from '../Layer';
|
|
23
23
|
var packageName = "@atlaskit/editor-common";
|
|
24
|
-
var packageVersion = "
|
|
24
|
+
var packageVersion = "0.0.0-development";
|
|
25
25
|
var halfFocusRing = 1;
|
|
26
26
|
var dropOffset = '0, 8';
|
|
27
27
|
var fadeIn = keyframes({
|
|
@@ -6,6 +6,8 @@ export { hasValidListIndentationLevel } from './indentation';
|
|
|
6
6
|
export { restoreSelection, computeSelectionOffsets } from './restore-selection';
|
|
7
7
|
export { buildReplacementFragment } from './build-replacement-fragment';
|
|
8
8
|
export type { BuildResult } from './build-replacement-fragment';
|
|
9
|
+
export { narrowReplacementRange } from './narrow-replacement-range';
|
|
10
|
+
export type { NarrowedReplacement } from './narrow-replacement-range';
|
|
9
11
|
export type { FlattenedItem } from './flatten-list';
|
|
10
12
|
export { flattenList } from './flatten-list';
|
|
11
13
|
export type { FlattenListOptions, FlattenListResult } from './flatten-list';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
export type NarrowedReplacement = {
|
|
4
|
+
adjustedContentStartOffsets: number[];
|
|
5
|
+
end: number;
|
|
6
|
+
fragment: Fragment;
|
|
7
|
+
start: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Narrows a full-list replacement to the minimal changed range.
|
|
11
|
+
*
|
|
12
|
+
* Compares the old root list node with the new replacement fragment
|
|
13
|
+
* from both ends to find the first and last positions where they differ,
|
|
14
|
+
* then returns only the changed subrange.
|
|
15
|
+
*
|
|
16
|
+
* This reduces the scope of `tr.replaceWith()` so that remote cursors
|
|
17
|
+
* on unchanged items are preserved during collaborative editing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function narrowReplacementRange(doc: PMNode, rootListStart: number, rootListEnd: number, fragment: Fragment, contentStartOffsets: number[]): NarrowedReplacement;
|
|
@@ -6,6 +6,8 @@ export { hasValidListIndentationLevel } from './indentation';
|
|
|
6
6
|
export { restoreSelection, computeSelectionOffsets } from './restore-selection';
|
|
7
7
|
export { buildReplacementFragment } from './build-replacement-fragment';
|
|
8
8
|
export type { BuildResult } from './build-replacement-fragment';
|
|
9
|
+
export { narrowReplacementRange } from './narrow-replacement-range';
|
|
10
|
+
export type { NarrowedReplacement } from './narrow-replacement-range';
|
|
9
11
|
export type { FlattenedItem } from './flatten-list';
|
|
10
12
|
export { flattenList } from './flatten-list';
|
|
11
13
|
export type { FlattenListOptions, FlattenListResult } from './flatten-list';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
export type NarrowedReplacement = {
|
|
4
|
+
adjustedContentStartOffsets: number[];
|
|
5
|
+
end: number;
|
|
6
|
+
fragment: Fragment;
|
|
7
|
+
start: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Narrows a full-list replacement to the minimal changed range.
|
|
11
|
+
*
|
|
12
|
+
* Compares the old root list node with the new replacement fragment
|
|
13
|
+
* from both ends to find the first and last positions where they differ,
|
|
14
|
+
* then returns only the changed subrange.
|
|
15
|
+
*
|
|
16
|
+
* This reduces the scope of `tr.replaceWith()` so that remote cursors
|
|
17
|
+
* on unchanged items are preserved during collaborative editing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function narrowReplacementRange(doc: PMNode, rootListStart: number, rootListEnd: number, fragment: Fragment, contentStartOffsets: number[]): NarrowedReplacement;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-common",
|
|
3
|
-
"version": "112.
|
|
3
|
+
"version": "112.9.1",
|
|
4
4
|
"description": "A package that contains common classes and components for editor and renderer",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"@atlaskit/afm-i18n-platform-editor-editor-common": "2.18.0",
|
|
36
36
|
"@atlaskit/analytics-listeners": "^10.0.0",
|
|
37
37
|
"@atlaskit/analytics-namespaced-context": "^7.2.0",
|
|
38
|
-
"@atlaskit/analytics-next": "^11.
|
|
38
|
+
"@atlaskit/analytics-next": "^11.2.0",
|
|
39
39
|
"@atlaskit/atlassian-context": "^0.6.0",
|
|
40
40
|
"@atlaskit/browser-apis": "^0.0.1",
|
|
41
41
|
"@atlaskit/button": "^23.10.0",
|
|
42
42
|
"@atlaskit/codemod-utils": "^4.2.0",
|
|
43
43
|
"@atlaskit/css": "^0.19.0",
|
|
44
44
|
"@atlaskit/custom-steps": "^0.16.0",
|
|
45
|
-
"@atlaskit/dropdown-menu": "^16.
|
|
45
|
+
"@atlaskit/dropdown-menu": "^16.8.0",
|
|
46
46
|
"@atlaskit/editor-json-transformer": "^8.31.0",
|
|
47
47
|
"@atlaskit/editor-palette": "^2.1.0",
|
|
48
48
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
71
71
|
"@atlaskit/platform-feature-flags-react": "^0.4.0",
|
|
72
72
|
"@atlaskit/popper": "^7.1.0",
|
|
73
|
-
"@atlaskit/primitives": "^18.
|
|
73
|
+
"@atlaskit/primitives": "^18.1.0",
|
|
74
74
|
"@atlaskit/profilecard": "^24.44.0",
|
|
75
75
|
"@atlaskit/prosemirror-history": "^0.2.0",
|
|
76
76
|
"@atlaskit/react-ufo": "^5.5.0",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@atlaskit/status": "^3.1.0",
|
|
82
82
|
"@atlaskit/task-decision": "^19.3.0",
|
|
83
83
|
"@atlaskit/textfield": "^8.2.0",
|
|
84
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
84
|
+
"@atlaskit/tmp-editor-statsig": "^46.0.0",
|
|
85
85
|
"@atlaskit/tokens": "^11.2.0",
|
|
86
86
|
"@atlaskit/tooltip": "^21.0.0",
|
|
87
87
|
"@atlaskit/width-detector": "^5.0.0",
|