@atlaskit/editor-common 74.5.2 → 74.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/analytics/index.js +26 -1
  3. package/dist/cjs/analytics/linking-utils.js +84 -0
  4. package/dist/cjs/card/MediaAndEmbedsToolbar/index.js +156 -0
  5. package/dist/cjs/card/index.js +9 -1
  6. package/dist/cjs/messages/index.js +14 -0
  7. package/dist/cjs/messages/link-toolbar.js +60 -0
  8. package/dist/cjs/messages/media-and-embed-toolbar.js +20 -0
  9. package/dist/cjs/monitoring/error.js +1 -1
  10. package/dist/cjs/react-node-view/getInlineNodeViewProducer.js +225 -0
  11. package/dist/cjs/react-node-view/index.js +13 -0
  12. package/dist/cjs/{ui/Resizer/index.js → resizer/Resizer.js} +1 -1
  13. package/dist/cjs/{resizer.js → resizer/index.js} +1 -1
  14. package/dist/cjs/resizer/utils.js +21 -0
  15. package/dist/cjs/types/hyperlink.js +5 -0
  16. package/dist/cjs/types/resizable-media-single.js +5 -0
  17. package/dist/cjs/ui/DropList/index.js +1 -1
  18. package/dist/cjs/ui/LinkSearch/const.js +14 -0
  19. package/dist/cjs/ui/ResizerLegacy/index.js +210 -0
  20. package/dist/cjs/ui/ResizerLegacy/styled.js +15 -0
  21. package/dist/cjs/ui/ResizerLegacy/types.js +5 -0
  22. package/dist/cjs/ui/ResizerLegacy/utils.js +21 -0
  23. package/dist/cjs/ui/index.js +58 -0
  24. package/dist/cjs/utils/document.js +258 -0
  25. package/dist/cjs/utils/editor-core-utils.js +7 -2
  26. package/dist/cjs/utils/filter/privacy-filter.js +55 -0
  27. package/dist/cjs/utils/index.js +75 -0
  28. package/dist/cjs/utils/rich-media-utils.js +131 -0
  29. package/dist/cjs/version.json +1 -1
  30. package/dist/es2019/analytics/index.js +2 -1
  31. package/dist/es2019/analytics/linking-utils.js +74 -0
  32. package/dist/es2019/card/MediaAndEmbedsToolbar/index.js +161 -0
  33. package/dist/es2019/card/index.js +2 -1
  34. package/dist/es2019/messages/index.js +2 -0
  35. package/dist/es2019/messages/link-toolbar.js +53 -0
  36. package/dist/es2019/messages/media-and-embed-toolbar.js +13 -0
  37. package/dist/es2019/monitoring/error.js +1 -1
  38. package/dist/es2019/react-node-view/getInlineNodeViewProducer.js +219 -0
  39. package/dist/es2019/react-node-view/index.js +1 -0
  40. package/dist/es2019/{ui/Resizer/index.js → resizer/Resizer.js} +1 -1
  41. package/dist/es2019/resizer/index.js +1 -0
  42. package/dist/es2019/resizer/utils.js +12 -0
  43. package/dist/es2019/types/resizable-media-single.js +1 -0
  44. package/dist/es2019/ui/DropList/index.js +1 -1
  45. package/dist/es2019/ui/LinkSearch/const.js +4 -0
  46. package/dist/es2019/ui/ResizerLegacy/index.js +191 -0
  47. package/dist/es2019/ui/ResizerLegacy/styled.js +15 -0
  48. package/dist/es2019/ui/ResizerLegacy/types.js +1 -0
  49. package/dist/es2019/ui/ResizerLegacy/utils.js +12 -0
  50. package/dist/es2019/ui/index.js +5 -1
  51. package/dist/es2019/utils/document.js +253 -0
  52. package/dist/es2019/utils/editor-core-utils.js +4 -0
  53. package/dist/es2019/utils/filter/privacy-filter.js +47 -0
  54. package/dist/es2019/utils/index.js +5 -2
  55. package/dist/es2019/utils/rich-media-utils.js +109 -0
  56. package/dist/es2019/version.json +1 -1
  57. package/dist/esm/analytics/index.js +2 -1
  58. package/dist/esm/analytics/linking-utils.js +74 -0
  59. package/dist/esm/card/MediaAndEmbedsToolbar/index.js +146 -0
  60. package/dist/esm/card/index.js +2 -1
  61. package/dist/esm/messages/index.js +2 -0
  62. package/dist/esm/messages/link-toolbar.js +53 -0
  63. package/dist/esm/messages/media-and-embed-toolbar.js +13 -0
  64. package/dist/esm/monitoring/error.js +1 -1
  65. package/dist/esm/react-node-view/getInlineNodeViewProducer.js +215 -0
  66. package/dist/esm/react-node-view/index.js +1 -0
  67. package/dist/esm/{ui/Resizer/index.js → resizer/Resizer.js} +1 -1
  68. package/dist/esm/resizer/index.js +1 -0
  69. package/dist/esm/resizer/types.js +1 -0
  70. package/dist/esm/resizer/utils.js +12 -0
  71. package/dist/esm/types/hyperlink.js +1 -0
  72. package/dist/esm/types/resizable-media-single.js +1 -0
  73. package/dist/esm/ui/DropList/index.js +1 -1
  74. package/dist/esm/ui/LinkSearch/const.js +4 -0
  75. package/dist/esm/ui/ResizerLegacy/index.js +203 -0
  76. package/dist/esm/ui/ResizerLegacy/styled.js +7 -0
  77. package/dist/esm/ui/ResizerLegacy/types.js +1 -0
  78. package/dist/esm/ui/ResizerLegacy/utils.js +12 -0
  79. package/dist/esm/ui/index.js +5 -1
  80. package/dist/esm/utils/document.js +246 -0
  81. package/dist/esm/utils/editor-core-utils.js +4 -0
  82. package/dist/esm/utils/filter/privacy-filter.js +48 -0
  83. package/dist/esm/utils/index.js +5 -2
  84. package/dist/esm/utils/rich-media-utils.js +118 -0
  85. package/dist/esm/version.json +1 -1
  86. package/dist/types/analytics/index.d.ts +2 -0
  87. package/dist/types/analytics/linking-utils.d.ts +14 -0
  88. package/dist/types/card/MediaAndEmbedsToolbar/index.d.ts +11 -0
  89. package/dist/types/card/index.d.ts +1 -0
  90. package/dist/types/messages/index.d.ts +2 -0
  91. package/dist/types/messages/link-toolbar.d.ts +52 -0
  92. package/dist/types/messages/media-and-embed-toolbar.d.ts +12 -0
  93. package/dist/types/react-node-view/getInlineNodeViewProducer.d.ts +25 -0
  94. package/dist/types/react-node-view/index.d.ts +3 -0
  95. package/dist/types/resizer/index.d.ts +2 -0
  96. package/dist/types/resizer/utils.d.ts +6 -0
  97. package/dist/types/types/hyperlink.d.ts +35 -0
  98. package/dist/types/types/index.d.ts +2 -0
  99. package/dist/types/types/resizable-media-single.d.ts +15 -0
  100. package/dist/types/ui/DropList/index.d.ts +1 -1
  101. package/dist/types/ui/LinkSearch/const.d.ts +4 -0
  102. package/dist/types/ui/ResizerLegacy/index.d.ts +40 -0
  103. package/dist/types/ui/ResizerLegacy/styled.d.ts +2 -0
  104. package/dist/types/ui/ResizerLegacy/types.d.ts +26 -0
  105. package/dist/types/ui/ResizerLegacy/utils.d.ts +6 -0
  106. package/dist/types/ui/index.d.ts +6 -0
  107. package/dist/types/utils/document.d.ts +19 -0
  108. package/dist/types/utils/editor-core-utils.d.ts +1 -0
  109. package/dist/types/utils/filter/privacy-filter.d.ts +9 -0
  110. package/dist/types/utils/index.d.ts +4 -1
  111. package/dist/types/utils/rich-media-utils.d.ts +8 -0
  112. package/dist/types-ts4.5/analytics/index.d.ts +2 -0
  113. package/dist/types-ts4.5/analytics/linking-utils.d.ts +14 -0
  114. package/dist/types-ts4.5/card/MediaAndEmbedsToolbar/index.d.ts +11 -0
  115. package/dist/types-ts4.5/card/index.d.ts +1 -0
  116. package/dist/types-ts4.5/messages/index.d.ts +2 -0
  117. package/dist/types-ts4.5/messages/link-toolbar.d.ts +52 -0
  118. package/dist/types-ts4.5/messages/media-and-embed-toolbar.d.ts +12 -0
  119. package/dist/types-ts4.5/react-node-view/getInlineNodeViewProducer.d.ts +25 -0
  120. package/dist/types-ts4.5/react-node-view/index.d.ts +3 -0
  121. package/dist/types-ts4.5/resizer/index.d.ts +2 -0
  122. package/dist/types-ts4.5/resizer/utils.d.ts +6 -0
  123. package/dist/types-ts4.5/types/hyperlink.d.ts +35 -0
  124. package/dist/types-ts4.5/types/index.d.ts +2 -0
  125. package/dist/types-ts4.5/types/resizable-media-single.d.ts +15 -0
  126. package/dist/types-ts4.5/ui/DropList/index.d.ts +1 -1
  127. package/dist/types-ts4.5/ui/LinkSearch/const.d.ts +4 -0
  128. package/dist/types-ts4.5/ui/ResizerLegacy/index.d.ts +40 -0
  129. package/dist/types-ts4.5/ui/ResizerLegacy/styled.d.ts +2 -0
  130. package/dist/types-ts4.5/ui/ResizerLegacy/types.d.ts +26 -0
  131. package/dist/types-ts4.5/ui/ResizerLegacy/utils.d.ts +6 -0
  132. package/dist/types-ts4.5/ui/index.d.ts +6 -0
  133. package/dist/types-ts4.5/utils/document.d.ts +19 -0
  134. package/dist/types-ts4.5/utils/editor-core-utils.d.ts +1 -0
  135. package/dist/types-ts4.5/utils/filter/privacy-filter.d.ts +9 -0
  136. package/dist/types-ts4.5/utils/index.d.ts +4 -1
  137. package/dist/types-ts4.5/utils/rich-media-utils.d.ts +8 -0
  138. package/package.json +7 -6
  139. package/resizer/package.json +5 -5
  140. package/dist/cjs/ui/Resizer/utils.js +0 -8
  141. package/dist/es2019/resizer.js +0 -1
  142. package/dist/es2019/ui/Resizer/utils.js +0 -1
  143. package/dist/esm/resizer.js +0 -1
  144. package/dist/esm/ui/Resizer/utils.js +0 -1
  145. package/dist/types/resizer.d.ts +0 -2
  146. package/dist/types/ui/Resizer/utils.d.ts +0 -1
  147. package/dist/types-ts4.5/resizer.d.ts +0 -2
  148. package/dist/types-ts4.5/ui/Resizer/utils.d.ts +0 -1
  149. /package/dist/cjs/{ui/Resizer → resizer}/types.js +0 -0
  150. /package/dist/es2019/{ui/Resizer → resizer}/types.js +0 -0
  151. /package/dist/{esm/ui/Resizer/types.js → es2019/types/hyperlink.js} +0 -0
  152. /package/dist/types/{ui/Resizer/index.d.ts → resizer/Resizer.d.ts} +0 -0
  153. /package/dist/types/{ui/Resizer → resizer}/types.d.ts +0 -0
  154. /package/dist/types-ts4.5/{ui/Resizer/index.d.ts → resizer/Resizer.d.ts} +0 -0
  155. /package/dist/types-ts4.5/{ui/Resizer → resizer}/types.d.ts +0 -0
@@ -0,0 +1,191 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import React from 'react';
3
+ import classnames from 'classnames';
4
+ import { Resizable } from 're-resizable';
5
+ import { akRichMediaResizeZIndex } from '@atlaskit/editor-shared-styles';
6
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../../analytics';
7
+ import { richMediaClassName } from '../../styles';
8
+ import { gridTypeForLayout } from '../../utils';
9
+ import { handleSides, snapTo } from './utils';
10
+ const getResizeAnalyticsEvent = (type, size, layout) => {
11
+ const actionSubject = type === 'embed' ? ACTION_SUBJECT.EMBEDS : ACTION_SUBJECT.MEDIA_SINGLE;
12
+ return {
13
+ action: ACTION.EDITED,
14
+ actionSubject,
15
+ actionSubjectId: ACTION_SUBJECT_ID.RESIZED,
16
+ attributes: {
17
+ size,
18
+ layout
19
+ },
20
+ eventType: EVENT_TYPE.UI
21
+ };
22
+ };
23
+ const getWidthFromSnapPoints = (width, snapPoints) => {
24
+ if (snapPoints.length) {
25
+ return Math.min(Math.max(width, snapPoints[0]), snapPoints[snapPoints.length - 1]);
26
+ }
27
+ return width;
28
+ };
29
+ export default class Resizer extends React.Component {
30
+ constructor(...args) {
31
+ super(...args);
32
+ _defineProperty(this, "resizable", /*#__PURE__*/React.createRef());
33
+ _defineProperty(this, "state", {
34
+ isResizing: false
35
+ });
36
+ _defineProperty(this, "handleResizeStart", event => {
37
+ const {
38
+ innerPadding = 0,
39
+ highlights,
40
+ displayGrid,
41
+ layout,
42
+ width,
43
+ snapPoints
44
+ } = this.props;
45
+
46
+ // prevent creating a drag event on Firefox
47
+ event.preventDefault();
48
+ this.setState({
49
+ isResizing: true
50
+ }, () => {
51
+ const newHighlights = highlights(width + innerPadding, snapPoints);
52
+ displayGrid === null || displayGrid === void 0 ? void 0 : displayGrid(newHighlights.length > 0, gridTypeForLayout(layout), newHighlights);
53
+ });
54
+ });
55
+ _defineProperty(this, "handleResize", (_event, _direction, _elementRef, delta) => {
56
+ const {
57
+ highlights,
58
+ calcNewSize,
59
+ scaleFactor,
60
+ snapPoints,
61
+ displayGrid,
62
+ layout,
63
+ updateSize,
64
+ innerPadding = 0
65
+ } = this.props;
66
+ const resizable = this.resizable.current;
67
+ const {
68
+ isResizing
69
+ } = this.state;
70
+ if (!resizable || !resizable.state.original || !isResizing) {
71
+ return;
72
+ }
73
+ const newWidth = getWidthFromSnapPoints(resizable.state.original.width + delta.width * (scaleFactor || 1), snapPoints);
74
+ const newSize = calcNewSize(newWidth + innerPadding, false);
75
+ if (newSize.layout !== layout) {
76
+ updateSize(newSize.width, newSize.layout);
77
+ }
78
+ const newHighlights = highlights(newWidth, snapPoints);
79
+ displayGrid === null || displayGrid === void 0 ? void 0 : displayGrid(newHighlights.length > 0, gridTypeForLayout(newSize.layout), newHighlights);
80
+ resizable.updateSize({
81
+ width: newWidth,
82
+ height: 'auto'
83
+ });
84
+ resizable.setState({
85
+ isResizing: true
86
+ });
87
+ });
88
+ _defineProperty(this, "handleResizeStop", (_event, _direction, _elementRef, delta) => {
89
+ const {
90
+ highlights,
91
+ calcNewSize,
92
+ snapPoints,
93
+ displayGrid,
94
+ layout,
95
+ updateSize,
96
+ dispatchAnalyticsEvent,
97
+ nodeType
98
+ } = this.props;
99
+ const resizable = this.resizable.current;
100
+ const {
101
+ isResizing
102
+ } = this.state;
103
+ if (!resizable || !resizable.state.original || !isResizing) {
104
+ return;
105
+ }
106
+ const newWidth = getWidthFromSnapPoints(resizable.state.original.width + delta.width, snapPoints);
107
+ const snapWidth = snapTo(newWidth, snapPoints);
108
+ const newSize = calcNewSize(snapWidth, true);
109
+ const newHighlights = highlights(newWidth, snapPoints);
110
+ if (dispatchAnalyticsEvent) {
111
+ dispatchAnalyticsEvent(getResizeAnalyticsEvent(nodeType, newSize.width, newSize.layout));
112
+ }
113
+ // show committed grid size
114
+ displayGrid === null || displayGrid === void 0 ? void 0 : displayGrid(newHighlights.length > 0, gridTypeForLayout(newSize.layout), newHighlights);
115
+ this.setState({
116
+ isResizing: false
117
+ }, () => {
118
+ updateSize(newSize.width, newSize.layout);
119
+ displayGrid === null || displayGrid === void 0 ? void 0 : displayGrid(false, gridTypeForLayout(layout), []);
120
+ });
121
+ });
122
+ }
123
+ render() {
124
+ const handleStyles = {};
125
+ const handles = {};
126
+ const handleComponent = {};
127
+ const {
128
+ innerPadding = 0,
129
+ width,
130
+ pctWidth,
131
+ selected,
132
+ layout,
133
+ enable,
134
+ children,
135
+ ratio,
136
+ handleComponentFunc
137
+ } = this.props;
138
+ const {
139
+ isResizing
140
+ } = this.state;
141
+ handleSides.forEach(side => {
142
+ handles[side] = `richMedia-resize-handle-${side}`;
143
+ handleStyles[side] = {
144
+ width: '24px',
145
+ [side]: `${-13 - innerPadding}px`,
146
+ zIndex: akRichMediaResizeZIndex,
147
+ pointerEvents: 'auto'
148
+ };
149
+ const sideHandleComponent = handleComponentFunc && handleComponentFunc(side);
150
+ if (sideHandleComponent) {
151
+ handleComponent[side] = sideHandleComponent;
152
+ }
153
+ });
154
+ const className = classnames(richMediaClassName, `image-${layout}`, this.props.className, {
155
+ 'is-resizing': isResizing,
156
+ 'not-resized': !pctWidth,
157
+ 'richMedia-selected': selected,
158
+ 'rich-media-wrapped': layout === 'wrap-left' || layout === 'wrap-right'
159
+ });
160
+ let handleWrapperStyle;
161
+ if (ratio) {
162
+ handleWrapperStyle = {
163
+ position: 'absolute',
164
+ width: '100%',
165
+ paddingBottom: `${ratio}%`,
166
+ top: 0,
167
+ pointerEvents: 'none'
168
+ };
169
+ }
170
+
171
+ // Ideally, Resizable would let you pass in the component rather than
172
+ // the div. For now, we just apply the same styles using CSS
173
+ return /*#__PURE__*/React.createElement(Resizable, {
174
+ ref: this.resizable,
175
+ size: {
176
+ width,
177
+ // just content itself (no paddings)
178
+ height: 'auto'
179
+ },
180
+ className: className,
181
+ handleClasses: handles,
182
+ handleStyles: handleStyles,
183
+ handleWrapperStyle: handleWrapperStyle,
184
+ handleComponent: handleComponent,
185
+ enable: enable,
186
+ onResize: this.handleResize,
187
+ onResizeStop: this.handleResizeStop,
188
+ onResizeStart: this.handleResizeStart
189
+ }, children);
190
+ }
191
+ }
@@ -0,0 +1,15 @@
1
+ import { css } from '@emotion/react';
2
+ import { MediaSingleDimensionHelper } from '../MediaSingle/styled';
3
+ export const wrapperStyle = props => css`
4
+ & > div {
5
+ ${MediaSingleDimensionHelper(props)};
6
+ position: relative;
7
+ clear: both;
8
+
9
+ > div {
10
+ position: absolute;
11
+ height: 100%;
12
+ width: 100%;
13
+ }
14
+ }
15
+ `;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ export const snapTo = (target, points) => {
2
+ return points.length === 0 ?
3
+ // extreme last case if there are no points somehow
4
+ target : points.reduce((point, closest) => {
5
+ return Math.abs(closest - target) < Math.abs(point - target) ? closest : point;
6
+ });
7
+ };
8
+ export const handleSides = ['left', 'right'];
9
+ export const imageAlignmentMap = {
10
+ left: 'start',
11
+ right: 'end'
12
+ };
@@ -18,4 +18,8 @@ export { clearNextSiblingMarginTopStyle, clearNextSiblingBlockMarkMarginTopStyle
18
18
  export { IntlErrorBoundary, REACT_INTL_ERROR_MESSAGE } from './IntlErrorBoundary';
19
19
  export { default as IntlProviderIfMissingWrapper } from './IntlProviderIfMissingWrapper';
20
20
  export { default as FloatingToolbarButton } from './FloatingToolbar/Button';
21
- export { ContextPanelProvider, ContextPanelWidthProvider, ContextPanelConsumer, ContextPanel } from './ContextPanel/context';
21
+ export { RECENT_SEARCH_WIDTH_IN_PX, RECENT_SEARCH_WIDTH_WITHOUT_ITEMS_IN_PX, RECENT_SEARCH_HEIGHT_IN_PX, LINKPICKER_HEIGHT_IN_PX } from './LinkSearch/const';
22
+ export { ContextPanelProvider, ContextPanelWidthProvider, ContextPanelConsumer, ContextPanel } from './ContextPanel/context';
23
+ export { default as Resizer } from './ResizerLegacy';
24
+ export { snapTo, handleSides, imageAlignmentMap } from './ResizerLegacy/utils';
25
+ export { wrapperStyle } from './ResizerLegacy/styled';
@@ -0,0 +1,253 @@
1
+ import { Node } from 'prosemirror-model';
2
+ import { transformDedupeMarks, transformIndentationMarks, transformInvalidMediaContent, transformMediaLinkMarks, transformNodesMissingContent, transformTextLinkCodeMarks } from '@atlaskit/adf-utils/transforms';
3
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '../analytics';
4
+ import { isEmptyParagraph } from './editor-core-utils';
5
+ import { sanitizeNodeForPrivacy } from './filter/privacy-filter';
6
+ import { findAndTrackUnsupportedContentNodes } from './track-unsupported-content';
7
+ import { validateADFEntity } from './validate-using-spec';
8
+ export const getStepRange = transaction => {
9
+ let from = -1;
10
+ let to = -1;
11
+ transaction.mapping.maps.forEach((stepMap, index) => {
12
+ stepMap.forEach((oldStart, oldEnd) => {
13
+ const newStart = transaction.mapping.slice(index).map(oldStart, -1);
14
+ const newEnd = transaction.mapping.slice(index).map(oldEnd);
15
+ from = newStart < from || from === -1 ? newStart : from;
16
+ to = newEnd > to || to === -1 ? newEnd : to;
17
+ });
18
+ });
19
+ if (from !== -1) {
20
+ return {
21
+ from,
22
+ to
23
+ };
24
+ }
25
+ return null;
26
+ };
27
+
28
+ // Checks to see if the parent node is the document, ie not contained within another entity
29
+ export function hasDocAsParent($anchor) {
30
+ return $anchor.depth === 1;
31
+ }
32
+
33
+ /**
34
+ * Checks if a node looks like an empty document
35
+ */
36
+ export function isEmptyDocument(node) {
37
+ const nodeChild = node.content.firstChild;
38
+ if (node.childCount !== 1 || !nodeChild) {
39
+ return false;
40
+ }
41
+ return isEmptyParagraph(nodeChild);
42
+ }
43
+ export function bracketTyped(state) {
44
+ const {
45
+ selection
46
+ } = state;
47
+ const {
48
+ $cursor,
49
+ $anchor
50
+ } = selection;
51
+ if (!$cursor) {
52
+ return false;
53
+ }
54
+ const node = $cursor.nodeBefore;
55
+ if (!node) {
56
+ return false;
57
+ }
58
+ if (node.type.name === 'text' && node.text === '{') {
59
+ const paragraphNode = $anchor.node();
60
+ return paragraphNode.marks.length === 0 && hasDocAsParent($anchor);
61
+ }
62
+ return false;
63
+ }
64
+ export function nodesBetweenChanged(tr, f, startPos) {
65
+ const stepRange = getStepRange(tr);
66
+ if (!stepRange) {
67
+ return;
68
+ }
69
+ tr.doc.nodesBetween(stepRange.from, stepRange.to, f, startPos);
70
+ }
71
+ export function processRawValue(schema, value, providerFactory, sanitizePrivateContent, contentTransformer, dispatchAnalyticsEvent) {
72
+ if (!value) {
73
+ return;
74
+ }
75
+ let node;
76
+ if (typeof value === 'string') {
77
+ try {
78
+ if (contentTransformer) {
79
+ const doc = contentTransformer.parse(value);
80
+ node = doc.toJSON();
81
+ } else {
82
+ node = JSON.parse(value);
83
+ }
84
+ } catch (e) {
85
+ // eslint-disable-next-line no-console
86
+ console.error(`Error processing value: ${value} isn't a valid JSON`);
87
+ return;
88
+ }
89
+ } else {
90
+ node = value;
91
+ }
92
+ if (Array.isArray(node)) {
93
+ // eslint-disable-next-line no-console
94
+ console.error(`Error processing value: ${node} is an array, but it must be an object.`);
95
+ return;
96
+ }
97
+ try {
98
+ // ProseMirror always require a child under doc
99
+ if (node.type === 'doc') {
100
+ if (Array.isArray(node.content) && node.content.length === 0) {
101
+ node.content.push({
102
+ type: 'paragraph',
103
+ content: []
104
+ });
105
+ }
106
+ // Just making sure doc is always valid
107
+ if (!node.version) {
108
+ node.version = 1;
109
+ }
110
+ }
111
+ if (contentTransformer) {
112
+ return Node.fromJSON(schema, node);
113
+ }
114
+
115
+ // link mark on mediaSingle is deprecated, need to move link mark to child media node
116
+ // https://product-fabric.atlassian.net/browse/ED-14043
117
+ let {
118
+ transformedAdf,
119
+ isTransformed
120
+ } = transformMediaLinkMarks(node);
121
+ if (isTransformed && dispatchAnalyticsEvent) {
122
+ dispatchAnalyticsEvent({
123
+ action: ACTION.MEDIA_LINK_TRANSFORMED,
124
+ actionSubject: ACTION_SUBJECT.EDITOR,
125
+ eventType: EVENT_TYPE.OPERATIONAL
126
+ });
127
+ }
128
+
129
+ // See: HOT-97965 https://product-fabric.atlassian.net/browse/ED-14400
130
+ // We declared in code mark spec that links and marks should not co-exist on
131
+ // text nodes. This util strips code marks from bad text nodes and preserves links.
132
+ // Otherwise, prosemirror will try to repair the invalid document by stripping links
133
+ // and preserving code marks during content changes.
134
+ ({
135
+ transformedAdf,
136
+ isTransformed
137
+ } = transformTextLinkCodeMarks(transformedAdf));
138
+ if (isTransformed && dispatchAnalyticsEvent) {
139
+ dispatchAnalyticsEvent({
140
+ action: ACTION.TEXT_LINK_MARK_TRANSFORMED,
141
+ actionSubject: ACTION_SUBJECT.EDITOR,
142
+ eventType: EVENT_TYPE.OPERATIONAL
143
+ });
144
+ }
145
+ let discardedMarks = [];
146
+ ({
147
+ transformedAdf,
148
+ isTransformed,
149
+ discardedMarks
150
+ } = transformDedupeMarks(transformedAdf));
151
+ if (isTransformed && dispatchAnalyticsEvent) {
152
+ dispatchAnalyticsEvent({
153
+ action: ACTION.DEDUPE_MARKS_TRANSFORMED_V2,
154
+ actionSubject: ACTION_SUBJECT.EDITOR,
155
+ eventType: EVENT_TYPE.OPERATIONAL,
156
+ attributes: {
157
+ /** UGC WARNING
158
+ *
159
+ * DO NOT include the `mark` attributes inside, we map here to only
160
+ * extract the mark type as that is the only non-UGC safe information
161
+ * that we can add to event-attributes
162
+ *
163
+ */
164
+ discardedMarkTypes: discardedMarks.map(mark => mark.type)
165
+ }
166
+ });
167
+ }
168
+ ({
169
+ transformedAdf,
170
+ isTransformed
171
+ } = transformNodesMissingContent(transformedAdf));
172
+ if (isTransformed && dispatchAnalyticsEvent) {
173
+ dispatchAnalyticsEvent({
174
+ action: ACTION.NODES_MISSING_CONTENT_TRANSFORMED,
175
+ actionSubject: ACTION_SUBJECT.EDITOR,
176
+ eventType: EVENT_TYPE.OPERATIONAL
177
+ });
178
+ }
179
+ ({
180
+ transformedAdf,
181
+ isTransformed
182
+ } = transformIndentationMarks(transformedAdf));
183
+ if (isTransformed && dispatchAnalyticsEvent) {
184
+ dispatchAnalyticsEvent({
185
+ action: ACTION.INDENTATION_MARKS_TRANSFORMED,
186
+ actionSubject: ACTION_SUBJECT.EDITOR,
187
+ eventType: EVENT_TYPE.OPERATIONAL
188
+ });
189
+ }
190
+ ({
191
+ transformedAdf,
192
+ isTransformed
193
+ } = transformInvalidMediaContent(transformedAdf));
194
+ if (isTransformed && dispatchAnalyticsEvent) {
195
+ dispatchAnalyticsEvent({
196
+ action: ACTION.INVALID_MEDIA_CONTENT_TRANSFORMED,
197
+ actionSubject: ACTION_SUBJECT.EDITOR,
198
+ eventType: EVENT_TYPE.OPERATIONAL
199
+ });
200
+ }
201
+ const entity = validateADFEntity(schema, transformedAdf || node, dispatchAnalyticsEvent);
202
+ let newEntity = maySanitizePrivateContent(entity, providerFactory, sanitizePrivateContent);
203
+ const parsedDoc = Node.fromJSON(schema, newEntity);
204
+
205
+ // throws an error if the document is invalid
206
+ try {
207
+ parsedDoc.check();
208
+ } catch (err) {
209
+ if (dispatchAnalyticsEvent) {
210
+ dispatchAnalyticsEvent({
211
+ action: ACTION.INVALID_PROSEMIRROR_DOCUMENT,
212
+ actionSubject: ACTION_SUBJECT.EDITOR,
213
+ eventType: EVENT_TYPE.OPERATIONAL,
214
+ attributes: {
215
+ errorStack: err instanceof Error ? err.stack : String(err)
216
+ }
217
+ });
218
+ }
219
+ throw err;
220
+ }
221
+ if (dispatchAnalyticsEvent) {
222
+ findAndTrackUnsupportedContentNodes(parsedDoc, schema, dispatchAnalyticsEvent);
223
+ }
224
+ return parsedDoc;
225
+ } catch (e) {
226
+ if (dispatchAnalyticsEvent) {
227
+ dispatchAnalyticsEvent({
228
+ action: ACTION.DOCUMENT_PROCESSING_ERROR,
229
+ actionSubject: ACTION_SUBJECT.EDITOR,
230
+ eventType: EVENT_TYPE.OPERATIONAL,
231
+ nonPrivacySafeAttributes: {
232
+ errorStack: e instanceof Error ? e.stack : String(e)
233
+ }
234
+ });
235
+ }
236
+
237
+ // eslint-disable-next-line no-console
238
+ console.error(`Error processing document:\n${e instanceof Error ? e.message : String(e)}\n\n`, JSON.stringify(node));
239
+ if (isProseMirrorSchemaCheckError(e)) {
240
+ throw e;
241
+ }
242
+ return;
243
+ }
244
+ }
245
+ function isProseMirrorSchemaCheckError(error) {
246
+ return error instanceof RangeError && (!!error.message.match(/^Invalid collection of marks for node/) || !!error.message.match(/^Invalid content for node/));
247
+ }
248
+ const maySanitizePrivateContent = (entity, providerFactory, sanitizePrivateContent) => {
249
+ if (sanitizePrivateContent && providerFactory) {
250
+ return sanitizeNodeForPrivacy(entity, providerFactory);
251
+ }
252
+ return entity;
253
+ };
@@ -1,5 +1,6 @@
1
1
  import { NodeSelection, TextSelection } from 'prosemirror-state';
2
2
  import { ReplaceAroundStep, ReplaceStep } from 'prosemirror-transform';
3
+ import { hasParentNodeOfType } from 'prosemirror-utils';
3
4
  import { closest } from './dom';
4
5
 
5
6
  /**
@@ -78,4 +79,7 @@ export const isValidPosition = (pos, state) => {
78
79
  return true;
79
80
  }
80
81
  return false;
82
+ };
83
+ export const isInLayoutColumn = state => {
84
+ return hasParentNodeOfType(state.schema.nodes.layoutSection)(state.selection);
81
85
  };
@@ -0,0 +1,47 @@
1
+ import { traverse } from '@atlaskit/adf-utils/traverse';
2
+ import { isResolvingMentionProvider } from '@atlaskit/mention/resource';
3
+ /**
4
+ * Sanitises a document where some content should not be in the document (e.g. mention names).
5
+ *
6
+ * It is expected that these names we be resolved separately (e.g. when rendering
7
+ * a node view).
8
+ */
9
+ export function sanitizeNodeForPrivacy(json, providerFactory) {
10
+ const mentionNames = new Map();
11
+ let hasCacheableMentions = false;
12
+ const sanitizedJSON = traverse(json, {
13
+ mention: node => {
14
+ if (node.attrs && node.attrs.text) {
15
+ hasCacheableMentions = true;
16
+ // Remove @ prefix
17
+ const text = node.attrs.text;
18
+ const name = text.startsWith('@') ? text.slice(1) : text;
19
+ mentionNames.set(node.attrs.id, name);
20
+ }
21
+ return {
22
+ ...node,
23
+ attrs: {
24
+ ...node.attrs,
25
+ text: ''
26
+ }
27
+ };
28
+ }
29
+ });
30
+ if (hasCacheableMentions && providerFactory) {
31
+ const handler = (_name, providerPromise) => {
32
+ if (providerPromise) {
33
+ providerPromise.then(provider => {
34
+ if (isResolvingMentionProvider(provider)) {
35
+ mentionNames.forEach((name, id) => {
36
+ provider.cacheMentionName(id, name);
37
+ });
38
+ mentionNames.clear();
39
+ providerFactory.unsubscribe('mentionProvider', handler);
40
+ }
41
+ });
42
+ }
43
+ };
44
+ providerFactory.subscribe('mentionProvider', handler);
45
+ }
46
+ return sanitizedJSON;
47
+ }
@@ -3,7 +3,7 @@ export { getExtensionLozengeData } from './macro';
3
3
  export { default as browser } from './browser';
4
4
  export { default as ErrorReporter } from './error-reporter';
5
5
  export { isPastDate, timestampToIsoFormat, timestampToString, timestampToTaskContext, timestampToUTCDate, todayTimestampInUTC } from './date';
6
- export { isElementInTableCell, isTextSelection, isLastItemMediaGroup, setNodeSelection, setTextSelection, nonNullable, stepAddsOneOf, stepHasSlice, extractSliceFromStep, isValidPosition, isEmptyParagraph } from './editor-core-utils';
6
+ export { isElementInTableCell, isTextSelection, isLastItemMediaGroup, setNodeSelection, setTextSelection, nonNullable, stepAddsOneOf, stepHasSlice, extractSliceFromStep, isValidPosition, isEmptyParagraph, isInLayoutColumn } from './editor-core-utils';
7
7
  export { withImageLoader } from './imageLoader';
8
8
  export { absoluteBreakoutWidth, calcBreakoutWidth, calcWideWidth, breakoutConsts, calculateBreakoutStyles, calcBreakoutWidthPx } from './breakout';
9
9
  export { findChangedNodesFromTransaction, validNode, validateNodes, isType, isParagraph, isText, isLinkMark, SelectedState, isNodeSelectedOrInRange, isSupportedInParent, isMediaNode, isNodeBeforeMediaNode } from './nodes';
@@ -39,4 +39,7 @@ export { isFromCurrentDomain, LinkMatcher, normalizeUrl, linkifyContent, getLink
39
39
 
40
40
  // prosemirror-history does not export its plugin key
41
41
  export const pmHistoryPluginKey = 'history$';
42
- export { gridTypeForLayout } from './grid';
42
+ export { gridTypeForLayout } from './grid';
43
+ export { nodesBetweenChanged, getStepRange, isEmptyDocument, processRawValue, hasDocAsParent, bracketTyped } from './document';
44
+ export { floatingLayouts, isRichMediaInsideOfBlockNode, calculateSnapPoints, alignAttributes } from './rich-media-utils';
45
+ export { sanitizeNodeForPrivacy } from './filter/privacy-filter';
@@ -0,0 +1,109 @@
1
+ import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
2
+ import { akEditorBreakoutPadding } from '@atlaskit/editor-shared-styles';
3
+ import { shouldAddDefaultWrappedWidth } from '../ui/MediaSingle';
4
+ import { calcPxFromColumns, wrappedLayouts } from '../ui/MediaSingle/grid';
5
+ export const nonWrappedLayouts = ['center', 'wide', 'full-width'];
6
+ export const floatingLayouts = ['wrap-left', 'wrap-right'];
7
+ export const isRichMediaInsideOfBlockNode = (view, pos) => {
8
+ if (typeof pos !== 'number' || isNaN(pos) || !view) {
9
+ return false;
10
+ }
11
+ const $pos = view.state.doc.resolve(pos);
12
+ const {
13
+ expand,
14
+ nestedExpand,
15
+ layoutColumn
16
+ } = view.state.schema.nodes;
17
+ return !!findParentNodeOfTypeClosestToPos($pos, [expand, nestedExpand, layoutColumn]);
18
+ };
19
+ export const alignAttributes = (layout, oldAttrs, gridSize = 12, originalWidth, lineLength) => {
20
+ let width = oldAttrs.width;
21
+ const oldLayout = oldAttrs.layout;
22
+ const oldLayoutIsNonWrapped = nonWrappedLayouts.indexOf(oldLayout) > -1;
23
+ const newLayoutIsNonWrapped = nonWrappedLayouts.indexOf(layout) > -1;
24
+ const newLayoutIsWrapped = wrappedLayouts.indexOf(layout) > -1;
25
+ const oldLayoutIsWrapped = wrappedLayouts.indexOf(oldLayout) > -1;
26
+ if (oldLayoutIsNonWrapped && shouldAddDefaultWrappedWidth(layout, originalWidth, lineLength)) {
27
+ // 'full-width' or 'wide' or 'center' -> 'wrap-left' or 'wrap-right' or 'align-end' or 'align-start'
28
+ if (!width || width >= 100 || oldLayout !== 'center' // == 'full-width' or 'wide'
29
+ ) {
30
+ width = 50;
31
+ }
32
+ } else if (layout !== oldLayout && ['full-width', 'wide'].indexOf(oldLayout) > -1) {
33
+ // 'full-width' -> 'center' or 'wide'
34
+ // 'wide' -> 'center' or 'full-width'
35
+ // unset width
36
+ width = undefined;
37
+ } else if (width) {
38
+ const cols = Math.round(width / 100 * gridSize);
39
+ let targetCols = cols;
40
+ if (oldLayoutIsWrapped && newLayoutIsNonWrapped) {
41
+ // wrap -> center needs to align to even grid
42
+ targetCols = Math.floor(targetCols / 2) * 2;
43
+ width = undefined;
44
+ } else if (oldLayoutIsNonWrapped && newLayoutIsWrapped) {
45
+ // Can be here only if
46
+ // 'full-width' or 'wide' or 'center' -> 'wrap-left' or 'wrap-right' or 'align-end' or 'align-start'
47
+ // AND
48
+ // !originalWidth || !lineLength || small image
49
+ // AND
50
+ // width defined!
51
+
52
+ // cannot resize to full column width, and cannot resize to 1 column
53
+ if (cols <= 1) {
54
+ targetCols = 2;
55
+ } else if (cols >= gridSize) {
56
+ targetCols = 10;
57
+ }
58
+ }
59
+ if (targetCols !== cols) {
60
+ width = targetCols / gridSize * 100;
61
+ }
62
+ }
63
+ return {
64
+ ...oldAttrs,
65
+ layout,
66
+ width
67
+ };
68
+ };
69
+ export function calculateSnapPoints({
70
+ $pos,
71
+ akEditorWideLayoutWidth,
72
+ allowBreakoutSnapPoints,
73
+ containerWidth,
74
+ gridSize,
75
+ gridWidth,
76
+ insideInlineLike,
77
+ insideLayout,
78
+ isVideoFile,
79
+ lineLength,
80
+ offsetLeft,
81
+ wrappedLayout
82
+ }) {
83
+ const snapTargets = [];
84
+ for (let i = 0; i < gridWidth; i++) {
85
+ const pxFromColumns = calcPxFromColumns(i, lineLength, gridWidth);
86
+ snapTargets.push(insideLayout ? pxFromColumns : pxFromColumns - offsetLeft);
87
+ }
88
+ // full width
89
+ snapTargets.push(lineLength - offsetLeft);
90
+ const columns = wrappedLayout || insideInlineLike ? 1 : 2;
91
+ const minimumWidth = calcPxFromColumns(columns, lineLength, gridSize);
92
+ let snapPoints = snapTargets.filter(width => width >= minimumWidth);
93
+ if (!$pos) {
94
+ return snapPoints;
95
+ }
96
+ snapPoints = isVideoFile ? snapPoints.filter(width => width > 320) : snapPoints;
97
+ const isTopLevel = $pos.parent.type.name === 'doc';
98
+ if (isTopLevel && allowBreakoutSnapPoints) {
99
+ snapPoints.push(akEditorWideLayoutWidth);
100
+ const fullWidthPoint = containerWidth - akEditorBreakoutPadding;
101
+ if (fullWidthPoint > akEditorWideLayoutWidth) {
102
+ snapPoints.push(fullWidthPoint);
103
+ }
104
+ }
105
+
106
+ // EDM-1107: Ensure new snapPoints are sorted with existing points
107
+ snapPoints = snapPoints.sort((a, b) => a - b);
108
+ return snapPoints;
109
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-common",
3
- "version": "74.5.2",
3
+ "version": "74.6.0",
4
4
  "sideEffects": false
5
5
  }