@atlaskit/editor-common 107.0.6 → 107.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/editor-common
2
2
 
3
+ ## 107.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#173138](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/173138)
8
+ [`62d4e3ae11127`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/62d4e3ae11127) -
9
+ [ux] [ED-27997] Change text formatting state to only consider whole selections active for marks
10
+ - [#174738](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/174738)
11
+ [`d7706f10a7c4b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d7706f10a7c4b) -
12
+ [ux] Keyboard A11y Fix: Updated combo box experience for Insert Menu in Description section of the
13
+ Create Issue Modal. Now for empty state the focus will rotate between CTA and search field making
14
+ it easier to update search string.
15
+
3
16
  ## 107.0.6
4
17
 
5
18
  ### Patch Changes
@@ -338,9 +338,9 @@ function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore, it
338
338
  return;
339
339
  }
340
340
  if ((0, _platformFeatureFlags.fg)('jfp_a11y_fix_create_issue_no_results_link_focus')) {
341
- // Handle empty state navigation
341
+ // Handle empty state navigation and trap focus between search and CTA
342
342
  if (listSize === -1) {
343
- if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
343
+ if (e.key === 'Tab') {
344
344
  e.preventDefault();
345
345
  dispatch({
346
346
  type: ACTIONS.UPDATE_STATE,
@@ -57,5 +57,11 @@ Object.defineProperty(exports, "transformNonTextNodesToText", {
57
57
  return _commands.transformNonTextNodesToText;
58
58
  }
59
59
  });
60
+ Object.defineProperty(exports, "wholeSelectionHasMarks", {
61
+ enumerable: true,
62
+ get: function get() {
63
+ return _textFormatting.wholeSelectionHasMarks;
64
+ }
65
+ });
60
66
  var _commands = require("./commands");
61
67
  var _textFormatting = require("./text-formatting");
@@ -1,10 +1,16 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.isMarkExcluded = exports.isMarkAllowedInRange = exports.anyMarkActive = void 0;
7
+ exports.wholeSelectionHasMarks = exports.isMarkExcluded = exports.isMarkAllowedInRange = exports.anyMarkActive = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _model = require("@atlaskit/editor-prosemirror/model");
7
10
  var _cellSelection = require("@atlaskit/editor-tables/cell-selection");
11
+ 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; } } }; }
12
+ 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; } }
13
+ 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; }
8
14
  /**
9
15
  * Determine if a mark of a specific type exists anywhere in the selection.
10
16
  */
@@ -31,8 +37,143 @@ var anyMarkActive = exports.anyMarkActive = function anyMarkActive(state, markTy
31
37
  }
32
38
  return rangeHasMark;
33
39
  };
40
+ var allMarksAreRuledOut = function allMarksAreRuledOut(marks) {
41
+ return Array.from(marks.values()).every(function (mark) {
42
+ return !mark;
43
+ });
44
+ };
45
+
46
+ /**
47
+ * Check if a selection contains any of the specifiged marks. The whole selection
48
+ * must have the mark for it to be considered active.
49
+ * @param state The editor state
50
+ * @param markTypes The marks to check for
51
+ * @returns A map indicating which marks are present in the selection
52
+ * @example
53
+ * const markTypes = editorState.schema.marks;
54
+ * const activeMarks = wholeSelectionHasMarks(editorState, [markTypes.strong, markTypes.em, markTypes.etc]);
55
+ */
56
+ var wholeSelectionHasMarks = exports.wholeSelectionHasMarks = function wholeSelectionHasMarks(state, markTypes) {
57
+ var _state$selection2 = state.selection,
58
+ $from = _state$selection2.$from,
59
+ from = _state$selection2.from,
60
+ to = _state$selection2.to,
61
+ empty = _state$selection2.empty;
62
+ if (empty) {
63
+ return new Map(markTypes.map(function (markType) {
64
+ return [markType, !!markType.isInSet(state.storedMarks || $from.marks())];
65
+ }));
66
+ }
67
+ if (state.selection instanceof _cellSelection.CellSelection) {
68
+ return cellSelectionHasMarks(state.doc, state.selection, markTypes);
69
+ }
70
+ return wholeRangeHasMarks(from, to, state.doc, markTypes);
71
+ };
72
+ var cellSelectionHasMarks = function cellSelectionHasMarks(doc, selection, markTypes) {
73
+ // Warning: This is micro-optimized and is a total pain to actually read.
74
+ // Will attempt to explain in comments.
75
+
76
+ // Start with map of booleans for each mark
77
+ var cellsHaveMarks = new Map(markTypes.map(function (markType) {
78
+ return [markType, true];
79
+ }));
80
+ selection.forEachCell(function (cell, cellPos) {
81
+ // Early exit if all marks are already ruled out
82
+ if (allMarksAreRuledOut(cellsHaveMarks)) {
83
+ return;
84
+ }
85
+ var from = cellPos;
86
+ var to = cellPos + cell.nodeSize;
87
+
88
+ // On first cell just do a regular check
89
+ if (!cellsHaveMarks) {
90
+ cellsHaveMarks = wholeRangeHasMarks(from, to, doc, markTypes);
91
+ } else {
92
+ // Find the marks that are still true ie the ones that haven't been ruled out in
93
+ // previous cells. The idea here is to whittle down the list of marks so that we check
94
+ // less and less as we go, giving `wholeRangeHasMarks` more opportunities to exit early
95
+ var marksToCheck = [];
96
+ var _iterator = _createForOfIteratorHelper(cellsHaveMarks),
97
+ _step;
98
+ try {
99
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
100
+ var _step$value = (0, _slicedToArray2.default)(_step.value, 2),
101
+ markType = _step$value[0],
102
+ hasMark = _step$value[1];
103
+ if (hasMark) {
104
+ marksToCheck.push(markType);
105
+ }
106
+ }
107
+
108
+ // Look specifically for the marks that are not yet ruled out.
109
+ } catch (err) {
110
+ _iterator.e(err);
111
+ } finally {
112
+ _iterator.f();
113
+ }
114
+ var cellHasMarks = wholeRangeHasMarks(from, to, doc, marksToCheck);
115
+
116
+ // Map these results back into the original array of results and repeat!
117
+ var _iterator2 = _createForOfIteratorHelper(cellHasMarks),
118
+ _step2;
119
+ try {
120
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
121
+ var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2),
122
+ _markType = _step2$value[0],
123
+ _hasMark = _step2$value[1];
124
+ cellsHaveMarks.set(_markType, _hasMark);
125
+ }
126
+ } catch (err) {
127
+ _iterator2.e(err);
128
+ } finally {
129
+ _iterator2.f();
130
+ }
131
+ }
132
+ });
133
+ return cellsHaveMarks;
134
+ };
135
+ var wholeRangeHasMarks = function wholeRangeHasMarks(from, to, doc, markTypes) {
136
+ var hasMarks = new Map(markTypes.map(function (markType) {
137
+ return [markType, true];
138
+ }));
139
+ doc.nodesBetween(from, to, function (node) {
140
+ if (allMarksAreRuledOut(hasMarks)) {
141
+ // This won't be a true early exit, but will prevent diving into nodes and
142
+ // any checks further down the function.
143
+ return false;
144
+ }
145
+ if (!node.type.isText) {
146
+ return true; // continue traversing
147
+ }
148
+ var _iterator3 = _createForOfIteratorHelper(hasMarks),
149
+ _step3;
150
+ try {
151
+ var _loop = function _loop() {
152
+ var _step3$value = (0, _slicedToArray2.default)(_step3.value, 2),
153
+ markType = _step3$value[0],
154
+ hasMark = _step3$value[1];
155
+ if (!hasMark) {
156
+ return 1; // continue
157
+ // already ruled out the mark, skip further checks
158
+ }
159
+ var value = markType instanceof _model.Mark ? markType.isInSet(node.marks) : node.marks.some(function (mark) {
160
+ return mark.type === markType;
161
+ });
162
+ hasMarks.set(markType, value);
163
+ };
164
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
165
+ if (_loop()) continue;
166
+ }
167
+ } catch (err) {
168
+ _iterator3.e(err);
169
+ } finally {
170
+ _iterator3.f();
171
+ }
172
+ });
173
+ return hasMarks;
174
+ };
34
175
  var isMarkAllowedInRange = exports.isMarkAllowedInRange = function isMarkAllowedInRange(doc, ranges, type) {
35
- var _loop = function _loop() {
176
+ var _loop2 = function _loop2() {
36
177
  var _ranges$i = ranges[i],
37
178
  $from = _ranges$i.$from,
38
179
  $to = _ranges$i.$to;
@@ -52,7 +193,7 @@ var isMarkAllowedInRange = exports.isMarkAllowedInRange = function isMarkAllowed
52
193
  },
53
194
  _ret;
54
195
  for (var i = 0; i < ranges.length; i++) {
55
- _ret = _loop();
196
+ _ret = _loop2();
56
197
  if (_ret) return _ret.v;
57
198
  }
58
199
  return false;
@@ -16,7 +16,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
16
16
  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); }
17
17
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
18
18
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
19
- var packageVersion = "107.0.5";
19
+ var packageVersion = "107.0.6";
20
20
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
21
21
  // Remove URL as it has UGC
22
22
  // Ignored via go/ees007
@@ -23,7 +23,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
23
23
  * @jsx jsx
24
24
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
25
25
  var packageName = "@atlaskit/editor-common";
26
- var packageVersion = "107.0.5";
26
+ var packageVersion = "107.0.6";
27
27
  var halfFocusRing = 1;
28
28
  var dropOffset = '0, 8';
29
29
  // Ignored via go/ees005
@@ -342,9 +342,9 @@ function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore, it
342
342
  return;
343
343
  }
344
344
  if (fg('jfp_a11y_fix_create_issue_no_results_link_focus')) {
345
- // Handle empty state navigation
345
+ // Handle empty state navigation and trap focus between search and CTA
346
346
  if (listSize === -1) {
347
- if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
347
+ if (e.key === 'Tab') {
348
348
  e.preventDefault();
349
349
  dispatch({
350
350
  type: ACTIONS.UPDATE_STATE,
@@ -2,4 +2,4 @@
2
2
  /* eslint-disable @atlaskit/editor/no-re-export */
3
3
 
4
4
  export { transformNonTextNodesToText, applyMarkOnRange, filterChildrenBetween, toggleMark, removeMark, entireSelectionContainsMark } from './commands';
5
- export { anyMarkActive, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
5
+ export { anyMarkActive, wholeSelectionHasMarks, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
@@ -1,3 +1,4 @@
1
+ import { Mark } from '@atlaskit/editor-prosemirror/model';
1
2
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
2
3
 
3
4
  /**
@@ -27,6 +28,93 @@ export const anyMarkActive = (state, markType) => {
27
28
  }
28
29
  return rangeHasMark;
29
30
  };
31
+ const allMarksAreRuledOut = marks => Array.from(marks.values()).every(mark => !mark);
32
+
33
+ /**
34
+ * Check if a selection contains any of the specifiged marks. The whole selection
35
+ * must have the mark for it to be considered active.
36
+ * @param state The editor state
37
+ * @param markTypes The marks to check for
38
+ * @returns A map indicating which marks are present in the selection
39
+ * @example
40
+ * const markTypes = editorState.schema.marks;
41
+ * const activeMarks = wholeSelectionHasMarks(editorState, [markTypes.strong, markTypes.em, markTypes.etc]);
42
+ */
43
+ export const wholeSelectionHasMarks = (state, markTypes) => {
44
+ const {
45
+ $from,
46
+ from,
47
+ to,
48
+ empty
49
+ } = state.selection;
50
+ if (empty) {
51
+ return new Map(markTypes.map(markType => [markType, !!markType.isInSet(state.storedMarks || $from.marks())]));
52
+ }
53
+ if (state.selection instanceof CellSelection) {
54
+ return cellSelectionHasMarks(state.doc, state.selection, markTypes);
55
+ }
56
+ return wholeRangeHasMarks(from, to, state.doc, markTypes);
57
+ };
58
+ const cellSelectionHasMarks = (doc, selection, markTypes) => {
59
+ // Warning: This is micro-optimized and is a total pain to actually read.
60
+ // Will attempt to explain in comments.
61
+
62
+ // Start with map of booleans for each mark
63
+ let cellsHaveMarks = new Map(markTypes.map(markType => [markType, true]));
64
+ selection.forEachCell((cell, cellPos) => {
65
+ // Early exit if all marks are already ruled out
66
+ if (allMarksAreRuledOut(cellsHaveMarks)) {
67
+ return;
68
+ }
69
+ const from = cellPos;
70
+ const to = cellPos + cell.nodeSize;
71
+
72
+ // On first cell just do a regular check
73
+ if (!cellsHaveMarks) {
74
+ cellsHaveMarks = wholeRangeHasMarks(from, to, doc, markTypes);
75
+ } else {
76
+ // Find the marks that are still true ie the ones that haven't been ruled out in
77
+ // previous cells. The idea here is to whittle down the list of marks so that we check
78
+ // less and less as we go, giving `wholeRangeHasMarks` more opportunities to exit early
79
+ const marksToCheck = [];
80
+ for (const [markType, hasMark] of cellsHaveMarks) {
81
+ if (hasMark) {
82
+ marksToCheck.push(markType);
83
+ }
84
+ }
85
+
86
+ // Look specifically for the marks that are not yet ruled out.
87
+ const cellHasMarks = wholeRangeHasMarks(from, to, doc, marksToCheck);
88
+
89
+ // Map these results back into the original array of results and repeat!
90
+ for (const [markType, hasMark] of cellHasMarks) {
91
+ cellsHaveMarks.set(markType, hasMark);
92
+ }
93
+ }
94
+ });
95
+ return cellsHaveMarks;
96
+ };
97
+ const wholeRangeHasMarks = (from, to, doc, markTypes) => {
98
+ const hasMarks = new Map(markTypes.map(markType => [markType, true]));
99
+ doc.nodesBetween(from, to, node => {
100
+ if (allMarksAreRuledOut(hasMarks)) {
101
+ // This won't be a true early exit, but will prevent diving into nodes and
102
+ // any checks further down the function.
103
+ return false;
104
+ }
105
+ if (!node.type.isText) {
106
+ return true; // continue traversing
107
+ }
108
+ for (const [markType, hasMark] of hasMarks) {
109
+ if (!hasMark) {
110
+ continue; // already ruled out the mark, skip further checks
111
+ }
112
+ const value = markType instanceof Mark ? markType.isInSet(node.marks) : node.marks.some(mark => mark.type === markType);
113
+ hasMarks.set(markType, value);
114
+ }
115
+ });
116
+ return hasMarks;
117
+ };
30
118
  export const isMarkAllowedInRange = (doc, ranges, type) => {
31
119
  for (let i = 0; i < ranges.length; i++) {
32
120
  const {
@@ -1,7 +1,7 @@
1
1
  import { isFedRamp } from './environment';
2
2
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
3
3
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
4
- const packageVersion = "107.0.5";
4
+ const packageVersion = "107.0.6";
5
5
  const sanitiseSentryEvents = (data, _hint) => {
6
6
  // Remove URL as it has UGC
7
7
  // Ignored via go/ees007
@@ -13,7 +13,7 @@ import withAnalyticsContext from '@atlaskit/analytics-next/withAnalyticsContext'
13
13
  import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import Layer from '../Layer';
15
15
  const packageName = "@atlaskit/editor-common";
16
- const packageVersion = "107.0.5";
16
+ const packageVersion = "107.0.6";
17
17
  const halfFocusRing = 1;
18
18
  const dropOffset = '0, 8';
19
19
  // Ignored via go/ees005
@@ -333,9 +333,9 @@ function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore, it
333
333
  return;
334
334
  }
335
335
  if (fg('jfp_a11y_fix_create_issue_no_results_link_focus')) {
336
- // Handle empty state navigation
336
+ // Handle empty state navigation and trap focus between search and CTA
337
337
  if (listSize === -1) {
338
- if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
338
+ if (e.key === 'Tab') {
339
339
  e.preventDefault();
340
340
  dispatch({
341
341
  type: ACTIONS.UPDATE_STATE,
@@ -2,4 +2,4 @@
2
2
  /* eslint-disable @atlaskit/editor/no-re-export */
3
3
 
4
4
  export { transformNonTextNodesToText, applyMarkOnRange, filterChildrenBetween, toggleMark, removeMark, entireSelectionContainsMark } from './commands';
5
- export { anyMarkActive, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
5
+ export { anyMarkActive, wholeSelectionHasMarks, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
@@ -1,3 +1,8 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ 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; } } }; }
3
+ 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; } }
4
+ 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; }
5
+ import { Mark } from '@atlaskit/editor-prosemirror/model';
1
6
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
2
7
 
3
8
  /**
@@ -26,8 +31,143 @@ export var anyMarkActive = function anyMarkActive(state, markType) {
26
31
  }
27
32
  return rangeHasMark;
28
33
  };
34
+ var allMarksAreRuledOut = function allMarksAreRuledOut(marks) {
35
+ return Array.from(marks.values()).every(function (mark) {
36
+ return !mark;
37
+ });
38
+ };
39
+
40
+ /**
41
+ * Check if a selection contains any of the specifiged marks. The whole selection
42
+ * must have the mark for it to be considered active.
43
+ * @param state The editor state
44
+ * @param markTypes The marks to check for
45
+ * @returns A map indicating which marks are present in the selection
46
+ * @example
47
+ * const markTypes = editorState.schema.marks;
48
+ * const activeMarks = wholeSelectionHasMarks(editorState, [markTypes.strong, markTypes.em, markTypes.etc]);
49
+ */
50
+ export var wholeSelectionHasMarks = function wholeSelectionHasMarks(state, markTypes) {
51
+ var _state$selection2 = state.selection,
52
+ $from = _state$selection2.$from,
53
+ from = _state$selection2.from,
54
+ to = _state$selection2.to,
55
+ empty = _state$selection2.empty;
56
+ if (empty) {
57
+ return new Map(markTypes.map(function (markType) {
58
+ return [markType, !!markType.isInSet(state.storedMarks || $from.marks())];
59
+ }));
60
+ }
61
+ if (state.selection instanceof CellSelection) {
62
+ return cellSelectionHasMarks(state.doc, state.selection, markTypes);
63
+ }
64
+ return wholeRangeHasMarks(from, to, state.doc, markTypes);
65
+ };
66
+ var cellSelectionHasMarks = function cellSelectionHasMarks(doc, selection, markTypes) {
67
+ // Warning: This is micro-optimized and is a total pain to actually read.
68
+ // Will attempt to explain in comments.
69
+
70
+ // Start with map of booleans for each mark
71
+ var cellsHaveMarks = new Map(markTypes.map(function (markType) {
72
+ return [markType, true];
73
+ }));
74
+ selection.forEachCell(function (cell, cellPos) {
75
+ // Early exit if all marks are already ruled out
76
+ if (allMarksAreRuledOut(cellsHaveMarks)) {
77
+ return;
78
+ }
79
+ var from = cellPos;
80
+ var to = cellPos + cell.nodeSize;
81
+
82
+ // On first cell just do a regular check
83
+ if (!cellsHaveMarks) {
84
+ cellsHaveMarks = wholeRangeHasMarks(from, to, doc, markTypes);
85
+ } else {
86
+ // Find the marks that are still true ie the ones that haven't been ruled out in
87
+ // previous cells. The idea here is to whittle down the list of marks so that we check
88
+ // less and less as we go, giving `wholeRangeHasMarks` more opportunities to exit early
89
+ var marksToCheck = [];
90
+ var _iterator = _createForOfIteratorHelper(cellsHaveMarks),
91
+ _step;
92
+ try {
93
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
94
+ var _step$value = _slicedToArray(_step.value, 2),
95
+ markType = _step$value[0],
96
+ hasMark = _step$value[1];
97
+ if (hasMark) {
98
+ marksToCheck.push(markType);
99
+ }
100
+ }
101
+
102
+ // Look specifically for the marks that are not yet ruled out.
103
+ } catch (err) {
104
+ _iterator.e(err);
105
+ } finally {
106
+ _iterator.f();
107
+ }
108
+ var cellHasMarks = wholeRangeHasMarks(from, to, doc, marksToCheck);
109
+
110
+ // Map these results back into the original array of results and repeat!
111
+ var _iterator2 = _createForOfIteratorHelper(cellHasMarks),
112
+ _step2;
113
+ try {
114
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
115
+ var _step2$value = _slicedToArray(_step2.value, 2),
116
+ _markType = _step2$value[0],
117
+ _hasMark = _step2$value[1];
118
+ cellsHaveMarks.set(_markType, _hasMark);
119
+ }
120
+ } catch (err) {
121
+ _iterator2.e(err);
122
+ } finally {
123
+ _iterator2.f();
124
+ }
125
+ }
126
+ });
127
+ return cellsHaveMarks;
128
+ };
129
+ var wholeRangeHasMarks = function wholeRangeHasMarks(from, to, doc, markTypes) {
130
+ var hasMarks = new Map(markTypes.map(function (markType) {
131
+ return [markType, true];
132
+ }));
133
+ doc.nodesBetween(from, to, function (node) {
134
+ if (allMarksAreRuledOut(hasMarks)) {
135
+ // This won't be a true early exit, but will prevent diving into nodes and
136
+ // any checks further down the function.
137
+ return false;
138
+ }
139
+ if (!node.type.isText) {
140
+ return true; // continue traversing
141
+ }
142
+ var _iterator3 = _createForOfIteratorHelper(hasMarks),
143
+ _step3;
144
+ try {
145
+ var _loop = function _loop() {
146
+ var _step3$value = _slicedToArray(_step3.value, 2),
147
+ markType = _step3$value[0],
148
+ hasMark = _step3$value[1];
149
+ if (!hasMark) {
150
+ return 1; // continue
151
+ // already ruled out the mark, skip further checks
152
+ }
153
+ var value = markType instanceof Mark ? markType.isInSet(node.marks) : node.marks.some(function (mark) {
154
+ return mark.type === markType;
155
+ });
156
+ hasMarks.set(markType, value);
157
+ };
158
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
159
+ if (_loop()) continue;
160
+ }
161
+ } catch (err) {
162
+ _iterator3.e(err);
163
+ } finally {
164
+ _iterator3.f();
165
+ }
166
+ });
167
+ return hasMarks;
168
+ };
29
169
  export var isMarkAllowedInRange = function isMarkAllowedInRange(doc, ranges, type) {
30
- var _loop = function _loop() {
170
+ var _loop2 = function _loop2() {
31
171
  var _ranges$i = ranges[i],
32
172
  $from = _ranges$i.$from,
33
173
  $to = _ranges$i.$to;
@@ -47,7 +187,7 @@ export var isMarkAllowedInRange = function isMarkAllowedInRange(doc, ranges, typ
47
187
  },
48
188
  _ret;
49
189
  for (var i = 0; i < ranges.length; i++) {
50
- _ret = _loop();
190
+ _ret = _loop2();
51
191
  if (_ret) return _ret.v;
52
192
  }
53
193
  return false;
@@ -7,7 +7,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
7
7
  import { isFedRamp } from './environment';
8
8
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
9
9
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
10
- var packageVersion = "107.0.5";
10
+ var packageVersion = "107.0.6";
11
11
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
12
12
  // Remove URL as it has UGC
13
13
  // Ignored via go/ees007
@@ -20,7 +20,7 @@ import withAnalyticsContext from '@atlaskit/analytics-next/withAnalyticsContext'
20
20
  import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
21
21
  import Layer from '../Layer';
22
22
  var packageName = "@atlaskit/editor-common";
23
- var packageVersion = "107.0.5";
23
+ var packageVersion = "107.0.6";
24
24
  var halfFocusRing = 1;
25
25
  var dropOffset = '0, 8';
26
26
  // Ignored via go/ees005
@@ -1,2 +1,2 @@
1
1
  export { transformNonTextNodesToText, applyMarkOnRange, filterChildrenBetween, toggleMark, removeMark, entireSelectionContainsMark, } from './commands';
2
- export { anyMarkActive, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
2
+ export { anyMarkActive, wholeSelectionHasMarks, isMarkAllowedInRange, isMarkExcluded, } from './text-formatting';
@@ -1,8 +1,21 @@
1
- import type { Mark, MarkType, Node } from '@atlaskit/editor-prosemirror/model';
1
+ import { Mark, MarkType, Node } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { EditorState, SelectionRange } from '@atlaskit/editor-prosemirror/state';
3
3
  /**
4
4
  * Determine if a mark of a specific type exists anywhere in the selection.
5
5
  */
6
6
  export declare const anyMarkActive: (state: EditorState, markType: Mark | MarkType) => boolean;
7
+ type MarkMap = Map<Mark | MarkType, boolean>;
8
+ /**
9
+ * Check if a selection contains any of the specifiged marks. The whole selection
10
+ * must have the mark for it to be considered active.
11
+ * @param state The editor state
12
+ * @param markTypes The marks to check for
13
+ * @returns A map indicating which marks are present in the selection
14
+ * @example
15
+ * const markTypes = editorState.schema.marks;
16
+ * const activeMarks = wholeSelectionHasMarks(editorState, [markTypes.strong, markTypes.em, markTypes.etc]);
17
+ */
18
+ export declare const wholeSelectionHasMarks: (state: EditorState, markTypes: (MarkType | Mark)[]) => MarkMap;
7
19
  export declare const isMarkAllowedInRange: (doc: Node, ranges: readonly SelectionRange[], type: MarkType) => boolean;
8
20
  export declare const isMarkExcluded: (type: MarkType, marks?: readonly Mark[] | null) => boolean;
21
+ export {};
@@ -20,6 +20,7 @@ export interface TextFormattingState {
20
20
  emDisabled?: boolean;
21
21
  emHidden?: boolean;
22
22
  codeActive?: boolean;
23
+ codeInSelection?: boolean;
23
24
  codeDisabled?: boolean;
24
25
  codeHidden?: boolean;
25
26
  underlineActive?: boolean;
@@ -1,4 +1,4 @@
1
- import { ResolvedUserPreferences, UserPreferences } from './user-preferences';
1
+ import type { ResolvedUserPreferences, UserPreferences } from './user-preferences';
2
2
  export declare const mergeUserPreferences: (userPreferences: UserPreferences, defaultPreferences: ResolvedUserPreferences) => ResolvedUserPreferences;
3
3
  /**
4
4
  * Compare two user preferences objects
@@ -1,4 +1,4 @@
1
1
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
2
2
  import type { EditorAnalyticsAPI } from '../analytics';
3
- import { ACTION_SUBJECT_ID } from '../analytics';
3
+ import { type ACTION_SUBJECT_ID } from '../analytics';
4
4
  export declare const getDomRefFromSelection: (view: EditorView, actionSubjectId: ACTION_SUBJECT_ID.PICKER_MEDIA | ACTION_SUBJECT_ID.PICKER_TABLE_SIZE | ACTION_SUBJECT_ID.PICKER_EMOJI, editorAnalyticsAPI?: EditorAnalyticsAPI) => HTMLElement | undefined;
@@ -1,2 +1,2 @@
1
1
  export { transformNonTextNodesToText, applyMarkOnRange, filterChildrenBetween, toggleMark, removeMark, entireSelectionContainsMark, } from './commands';
2
- export { anyMarkActive, isMarkAllowedInRange, isMarkExcluded } from './text-formatting';
2
+ export { anyMarkActive, wholeSelectionHasMarks, isMarkAllowedInRange, isMarkExcluded, } from './text-formatting';
@@ -1,8 +1,21 @@
1
- import type { Mark, MarkType, Node } from '@atlaskit/editor-prosemirror/model';
1
+ import { Mark, MarkType, Node } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { EditorState, SelectionRange } from '@atlaskit/editor-prosemirror/state';
3
3
  /**
4
4
  * Determine if a mark of a specific type exists anywhere in the selection.
5
5
  */
6
6
  export declare const anyMarkActive: (state: EditorState, markType: Mark | MarkType) => boolean;
7
+ type MarkMap = Map<Mark | MarkType, boolean>;
8
+ /**
9
+ * Check if a selection contains any of the specifiged marks. The whole selection
10
+ * must have the mark for it to be considered active.
11
+ * @param state The editor state
12
+ * @param markTypes The marks to check for
13
+ * @returns A map indicating which marks are present in the selection
14
+ * @example
15
+ * const markTypes = editorState.schema.marks;
16
+ * const activeMarks = wholeSelectionHasMarks(editorState, [markTypes.strong, markTypes.em, markTypes.etc]);
17
+ */
18
+ export declare const wholeSelectionHasMarks: (state: EditorState, markTypes: (MarkType | Mark)[]) => MarkMap;
7
19
  export declare const isMarkAllowedInRange: (doc: Node, ranges: readonly SelectionRange[], type: MarkType) => boolean;
8
20
  export declare const isMarkExcluded: (type: MarkType, marks?: readonly Mark[] | null) => boolean;
21
+ export {};
@@ -20,6 +20,7 @@ export interface TextFormattingState {
20
20
  emDisabled?: boolean;
21
21
  emHidden?: boolean;
22
22
  codeActive?: boolean;
23
+ codeInSelection?: boolean;
23
24
  codeDisabled?: boolean;
24
25
  codeHidden?: boolean;
25
26
  underlineActive?: boolean;
@@ -1,4 +1,4 @@
1
- import { ResolvedUserPreferences, UserPreferences } from './user-preferences';
1
+ import type { ResolvedUserPreferences, UserPreferences } from './user-preferences';
2
2
  export declare const mergeUserPreferences: (userPreferences: UserPreferences, defaultPreferences: ResolvedUserPreferences) => ResolvedUserPreferences;
3
3
  /**
4
4
  * Compare two user preferences objects
@@ -1,4 +1,4 @@
1
1
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
2
2
  import type { EditorAnalyticsAPI } from '../analytics';
3
- import { ACTION_SUBJECT_ID } from '../analytics';
3
+ import { type ACTION_SUBJECT_ID } from '../analytics';
4
4
  export declare const getDomRefFromSelection: (view: EditorView, actionSubjectId: ACTION_SUBJECT_ID.PICKER_MEDIA | ACTION_SUBJECT_ID.PICKER_TABLE_SIZE | ACTION_SUBJECT_ID.PICKER_EMOJI, editorAnalyticsAPI?: EditorAnalyticsAPI) => HTMLElement | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-common",
3
- "version": "107.0.6",
3
+ "version": "107.1.0",
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/"
@@ -171,7 +171,7 @@
171
171
  "@atlaskit/textfield": "^8.0.0",
172
172
  "@atlaskit/theme": "^18.0.0",
173
173
  "@atlaskit/tmp-editor-statsig": "^8.0.0",
174
- "@atlaskit/tokens": "^5.3.0",
174
+ "@atlaskit/tokens": "^5.4.0",
175
175
  "@atlaskit/tooltip": "^20.3.0",
176
176
  "@atlaskit/width-detector": "^5.0.0",
177
177
  "@babel/runtime": "^7.0.0",