@atlaskit/editor-plugin-text-color 12.3.30 → 12.3.32

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,19 @@
1
1
  # @atlaskit/editor-plugin-text-color
2
2
 
3
+ ## 12.3.32
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 12.3.31
10
+
11
+ ### Patch Changes
12
+
13
+ - [`e74b3e9fc5c95`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e74b3e9fc5c95) -
14
+ Account for container backgrounds in text color contrast warnings
15
+ - Updated dependencies
16
+
3
17
  ## 12.3.30
4
18
 
5
19
  ### Patch Changes
@@ -12,7 +12,6 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
12
12
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
13
13
  var _uiColor = require("@atlaskit/editor-common/ui-color");
14
14
  var _state = require("@atlaskit/editor-prosemirror/state");
15
- var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
15
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
17
16
  var _color = require("./utils/color");
18
17
  var _constants = require("./utils/constants");
@@ -28,16 +27,13 @@ function createInitialPluginState(editorState, pluginConfig) {
28
27
  border: "var(--ds-border, #0B120E24)"
29
28
  }].concat((0, _toConsumableArray2.default)(paletteColors));
30
29
  var color = (0, _color.getActiveColor)(editorState);
31
- var state = _objectSpread({
30
+ var state = {
32
31
  color: color,
33
32
  disabled: (0, _disabled.getDisabledState)(editorState),
34
33
  palette: palette,
35
34
  defaultColor: defaultColor.color,
36
35
  isPaletteOpen: false
37
- }, (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1') && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
38
- colorInNonActiveTheme: (0, _uiColor.getTextColorInNonActiveTheme)(color, defaultColor.color),
39
- isMultiTextColor: (0, _color.isMultiTextColorSelection)(editorState)
40
- });
36
+ };
41
37
  return state;
42
38
  }
43
39
  var ACTIONS = exports.ACTIONS = /*#__PURE__*/function (ACTIONS) {
@@ -62,9 +58,6 @@ function createPlugin(dispatch, pluginConfig) {
62
58
  case ACTIONS.RESET_COLOR:
63
59
  nextState = _objectSpread(_objectSpread({}, pluginState), {}, {
64
60
  color: pluginState.defaultColor
65
- }, (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1') && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
66
- colorInNonActiveTheme: (0, _uiColor.getTextColorInNonActiveTheme)(pluginState.defaultColor, pluginState.defaultColor),
67
- isMultiTextColor: false
68
61
  });
69
62
  break;
70
63
  case ACTIONS.SET_COLOR:
@@ -72,9 +65,6 @@ function createPlugin(dispatch, pluginConfig) {
72
65
  color: meta.color,
73
66
  disabled: false,
74
67
  isPaletteOpen: false
75
- }, (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1') && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
76
- colorInNonActiveTheme: (0, _uiColor.getTextColorInNonActiveTheme)(meta.color, pluginState.defaultColor),
77
- isMultiTextColor: false
78
68
  });
79
69
  break;
80
70
  case ACTIONS.DISABLE:
@@ -92,12 +82,9 @@ function createPlugin(dispatch, pluginConfig) {
92
82
  nextState = _objectSpread(_objectSpread({}, pluginState), {}, {
93
83
  color: color,
94
84
  disabled: (0, _disabled.getDisabledState)(newState)
95
- }, color !== pluginState.color && (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1') && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
96
- colorInNonActiveTheme: (0, _uiColor.getTextColorInNonActiveTheme)(color, pluginState.defaultColor),
97
- isMultiTextColor: (0, _color.isMultiTextColorSelection)(newState)
98
85
  });
99
86
  }
100
- if (pluginState && pluginState.color !== nextState.color || pluginState && pluginState.colorInNonActiveTheme !== nextState.colorInNonActiveTheme || pluginState && pluginState.disabled !== nextState.disabled || pluginState && pluginState.isMultiTextColor !== nextState.isMultiTextColor || pluginState && pluginState.isPaletteOpen !== nextState.isPaletteOpen) {
87
+ if (pluginState && pluginState.color !== nextState.color || pluginState && pluginState.disabled !== nextState.disabled || pluginState && pluginState.isPaletteOpen !== nextState.isPaletteOpen) {
101
88
  dispatch(pluginKey, nextState);
102
89
  return nextState;
103
90
  }
@@ -3,8 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isMultiTextColorSelection = exports.getActiveColorNew = exports.getActiveColor = void 0;
7
- var _state = require("@atlaskit/editor-prosemirror/state");
6
+ exports.getActiveColorNew = exports.getActiveColor = void 0;
8
7
  var _constants = require("./constants");
9
8
  /**
10
9
  * Use getDisabledStateNew instead and pass in `tr`
@@ -50,28 +49,6 @@ var getActiveColor = exports.getActiveColor = function getActiveColor(state) {
50
49
  }
51
50
  return marksWithColor.length ? marksWithColor[0].attrs.color : _constants.DEFAULT_COLOR.color;
52
51
  };
53
-
54
- /**
55
- * Returns true when the selection contains two or more distinct text colors,
56
- * counting unmarked text as the default color.
57
- */
58
- var isMultiTextColorSelection = exports.isMultiTextColorSelection = function isMultiTextColorSelection(state) {
59
- var selection = state.selection,
60
- doc = state.doc;
61
- if (!(selection instanceof _state.TextSelection)) {
62
- return false;
63
- }
64
- var textColor = doc.type.schema.marks.textColor;
65
- var colors = new Set();
66
- doc.nodesBetween(selection.from, selection.to, function (node) {
67
- if (node.isText) {
68
- var _mark$attrs$color;
69
- var mark = textColor.isInSet(node.marks);
70
- colors.add((_mark$attrs$color = mark === null || mark === void 0 ? void 0 : mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : _constants.DEFAULT_COLOR.color);
71
- }
72
- });
73
- return colors.size > 1;
74
- };
75
52
  var getActiveColorNew = exports.getActiveColorNew = function getActiveColorNew(tr) {
76
53
  var _ref3 = tr.selection,
77
54
  $from = _ref3.$from,
@@ -5,15 +5,18 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.ColorAccessibilityMenuItem = void 0;
8
+ exports.getResolvedBackgroundColorForTextNode = exports.getAccessibilityStatusForCurrentSelection = exports.ColorAccessibilityMenuItem = void 0;
9
9
  require("./ColorAccessibilityMenuItem.compiled.css");
10
10
  var _runtime = require("@compiled/react/runtime");
11
11
  var _react = _interopRequireDefault(require("react"));
12
12
  var _reactIntl = require("react-intl");
13
+ var _panel = require("@atlaskit/adf-schema/panel");
13
14
  var _new = require("@atlaskit/button/new");
14
15
  var _css = require("@atlaskit/css");
15
16
  var _hooks = require("@atlaskit/editor-common/hooks");
16
17
  var _messages = require("@atlaskit/editor-common/messages");
18
+ var _panel2 = require("@atlaskit/editor-common/panel");
19
+ var _toolbar = require("@atlaskit/editor-common/toolbar");
17
20
  var _uiColor = require("@atlaskit/editor-common/ui-color");
18
21
  var _editorPalette = require("@atlaskit/editor-palette");
19
22
  var _state = require("@atlaskit/editor-prosemirror/state");
@@ -37,30 +40,128 @@ var getForegroundColor = function getForegroundColor(textColor, defaultColor) {
37
40
  var colorValue = (0, _editorPalette.hexToEditorTextPaletteColor)(textColor) || textColor;
38
41
  return resolveColorValue(colorValue, textColor);
39
42
  };
40
- var getBackgroundColor = function getBackgroundColor(highlightColor) {
41
- if (!highlightColor || highlightColor === _constants.TRANSPARENT_HIGHLIGHT_COLOR) {
43
+ var getBackgroundColor = function getBackgroundColor(backgroundColor) {
44
+ var palette = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
45
+ if (!backgroundColor || backgroundColor === 'none') {
42
46
  return (0, _getTokenValue.getTokenValue)('elevation.surface', _constants.DEFAULT_BACKGROUND_COLOR);
43
47
  }
44
- var colorValue = (0, _editorPalette.hexToEditorTextBackgroundPaletteColor)(highlightColor) || highlightColor;
45
- return resolveColorValue(colorValue, highlightColor);
48
+ var colorValue = palette === 'element' ? (0, _editorPalette.hexToEditorBackgroundPaletteColor)(backgroundColor) || backgroundColor : (0, _editorPalette.hexToEditorTextBackgroundPaletteColor)(backgroundColor) || backgroundColor;
49
+ return resolveColorValue(colorValue, backgroundColor);
50
+ };
51
+ var getBackgroundColorInNonActiveTheme = function getBackgroundColorInNonActiveTheme(backgroundColor) {
52
+ var palette = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
53
+ if (!backgroundColor || backgroundColor === 'none') {
54
+ return (0, _uiColor.getTokenCSSVariableValueForNonActiveTheme)("var(--ds-surface, #FFFFFF)", _constants.DEFAULT_BACKGROUND_COLOR);
55
+ }
56
+ var colorValue = palette === 'element' ? (0, _editorPalette.hexToEditorBackgroundPaletteColor)(backgroundColor) || backgroundColor : (0, _editorPalette.hexToEditorTextBackgroundPaletteColor)(backgroundColor) || backgroundColor;
57
+ return (0, _uiColor.getTokenCSSVariableValueForNonActiveTheme)(colorValue, backgroundColor);
58
+ };
59
+ var STANDARD_PANEL_BACKGROUND_COLORS = new Map([[_panel.PanelType.INFO, (0, _panel2.getPanelTypeBackgroundNoTokens)(_panel.PanelType.INFO)], [_panel.PanelType.NOTE, (0, _panel2.getPanelTypeBackgroundNoTokens)(_panel.PanelType.NOTE)], [_panel.PanelType.SUCCESS, (0, _panel2.getPanelTypeBackgroundNoTokens)(_panel.PanelType.SUCCESS)], [_panel.PanelType.WARNING, (0, _panel2.getPanelTypeBackgroundNoTokens)(_panel.PanelType.WARNING)], [_panel.PanelType.ERROR, (0, _panel2.getPanelTypeBackgroundNoTokens)(_panel.PanelType.ERROR)]]);
60
+ var getResolvedBackgroundFromHighlight = function getResolvedBackgroundFromHighlight(highlightColor) {
61
+ if (!highlightColor) {
62
+ return {
63
+ color: null,
64
+ source: 'text'
65
+ };
66
+ }
67
+ return {
68
+ color: highlightColor,
69
+ source: 'text'
70
+ };
71
+ };
72
+
73
+ /**
74
+ * Resolves a background color from a container node that paints behind text.
75
+ * Callers walk ancestors so the nearest painted container wins.
76
+ */
77
+ var getSupportedAncestorBackgroundColor = function getSupportedAncestorBackgroundColor(node) {
78
+ var backgroundColor;
79
+ if (node.type.name === 'tableCell' || node.type.name === 'tableHeader') {
80
+ backgroundColor = node.attrs.background;
81
+ } else if (node.type.name === 'panel' || node.type.name === 'panel_c1') {
82
+ if (node.attrs.panelType === _panel.PanelType.CUSTOM) {
83
+ backgroundColor = node.attrs.panelColor;
84
+ } else {
85
+ backgroundColor = STANDARD_PANEL_BACKGROUND_COLORS.get(node.attrs.panelType);
86
+ }
87
+ }
88
+ return backgroundColor ? {
89
+ color: backgroundColor,
90
+ source: 'element'
91
+ } : null;
92
+ };
93
+
94
+ /**
95
+ * Resolves the visible background behind a text node.
96
+ * Text highlight wins before falling back to the nearest element background.
97
+ */
98
+ var getResolvedBackgroundColorForTextNode = exports.getResolvedBackgroundColorForTextNode = function getResolvedBackgroundColorForTextNode($pos, node) {
99
+ var _iterator = _createForOfIteratorHelper(node.marks),
100
+ _step;
101
+ try {
102
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
103
+ var mark = _step.value;
104
+ if (mark.type.name === 'backgroundColor' && mark.attrs.color) {
105
+ return {
106
+ color: mark.attrs.color,
107
+ source: 'text'
108
+ };
109
+ }
110
+ }
111
+ } catch (err) {
112
+ _iterator.e(err);
113
+ } finally {
114
+ _iterator.f();
115
+ }
116
+ for (var depth = $pos.depth; depth > 0; depth--) {
117
+ var resolvedBackgroundColor = getSupportedAncestorBackgroundColor($pos.node(depth));
118
+ if (resolvedBackgroundColor) {
119
+ return resolvedBackgroundColor;
120
+ }
121
+ }
122
+ return {
123
+ color: null,
124
+ source: 'text'
125
+ };
126
+ };
127
+ var getResolvedBackgroundColorForPosition = function getResolvedBackgroundColorForPosition($pos, highlightColor) {
128
+ var highlightBackground = getResolvedBackgroundFromHighlight(highlightColor);
129
+ if (highlightColor) {
130
+ return highlightBackground;
131
+ }
132
+ for (var depth = $pos.depth; depth > 0; depth--) {
133
+ var resolvedBackgroundColor = getSupportedAncestorBackgroundColor($pos.node(depth));
134
+ if (resolvedBackgroundColor) {
135
+ return resolvedBackgroundColor;
136
+ }
137
+ }
138
+ return highlightBackground;
139
+ };
140
+ var getResolvedBackgroundColorValue = function getResolvedBackgroundColorValue(backgroundColor) {
141
+ if (backgroundColor.source === 'element') {
142
+ return getBackgroundColor(backgroundColor.color, 'element');
143
+ }
144
+ return getBackgroundColor(backgroundColor.color);
145
+ };
146
+ var getResolvedBackgroundColorValueInNonActiveTheme = function getResolvedBackgroundColorValueInNonActiveTheme(backgroundColor) {
147
+ if (backgroundColor.source === 'element') {
148
+ return getBackgroundColorInNonActiveTheme(backgroundColor.color, 'element');
149
+ }
150
+ return getBackgroundColorInNonActiveTheme(backgroundColor.color);
46
151
  };
47
152
  var useColorAccessibilityState = function useColorAccessibilityState(api) {
48
153
  return (0, _hooks.useSharedPluginStateWithSelector)(api, ['textColor', 'highlight'], function (states) {
49
- var _states$textColorStat, _states$highlightStat, _states$highlightStat2, _states$highlightStat3, _states$textColorStat2, _states$textColorStat3, _states$textColorStat4;
154
+ var _states$textColorStat, _states$highlightStat, _states$textColorStat2;
50
155
  return {
51
156
  defaultColor: (_states$textColorStat = states.textColorState) === null || _states$textColorStat === void 0 ? void 0 : _states$textColorStat.defaultColor,
52
157
  highlightColor: (_states$highlightStat = states.highlightState) === null || _states$highlightStat === void 0 ? void 0 : _states$highlightStat.activeColor,
53
- highlightColorInNonActiveTheme: (_states$highlightStat2 = states.highlightState) === null || _states$highlightStat2 === void 0 ? void 0 : _states$highlightStat2.activeColorInNonActiveTheme,
54
- isMultiHighlightColor: (_states$highlightStat3 = states.highlightState) === null || _states$highlightStat3 === void 0 ? void 0 : _states$highlightStat3.isMultiHighlightColor,
55
- isMultiTextColor: (_states$textColorStat2 = states.textColorState) === null || _states$textColorStat2 === void 0 ? void 0 : _states$textColorStat2.isMultiTextColor,
56
- textColor: (_states$textColorStat3 = states.textColorState) === null || _states$textColorStat3 === void 0 ? void 0 : _states$textColorStat3.color,
57
- textColorInNonActiveTheme: (_states$textColorStat4 = states.textColorState) === null || _states$textColorStat4 === void 0 ? void 0 : _states$textColorStat4.colorInNonActiveTheme
158
+ textColor: (_states$textColorStat2 = states.textColorState) === null || _states$textColorStat2 === void 0 ? void 0 : _states$textColorStat2.color
58
159
  };
59
160
  });
60
161
  };
61
- var getContrastRatio = function getContrastRatio(defaultColor, highlightColor, textColor) {
162
+ var getContrastRatio = function getContrastRatio(defaultColor, backgroundColor, textColor) {
62
163
  try {
63
- var contrastRatio = (0, _colorContrast.getContrastRatio)(getForegroundColor(textColor, defaultColor), getBackgroundColor(highlightColor));
164
+ var contrastRatio = (0, _colorContrast.getContrastRatio)(getForegroundColor(textColor, defaultColor), getResolvedBackgroundColorValue(backgroundColor));
64
165
  return contrastRatio;
65
166
  } catch (_unused) {
66
167
  // if we failed to calculate the contrast ratio, return null
@@ -68,16 +169,10 @@ var getContrastRatio = function getContrastRatio(defaultColor, highlightColor, t
68
169
  }
69
170
  };
70
171
 
71
- // Computes the contrast ratio for a (textColor, highlightColor) pair as it would
72
- // appear in the non-active theme, using the shared resolvers so the walker
73
- // evaluates the same colors the single-pair plugin-state path does. Returns null
74
- // if it cannot be calculated.
75
- var getNonActiveThemeContrastRatio = function getNonActiveThemeContrastRatio(defaultColor, highlightColor, textColor) {
172
+ // Computes the contrast ratio as it would appear in the non-active theme.
173
+ var getNonActiveThemeContrastRatio = function getNonActiveThemeContrastRatio(defaultColor, backgroundColor, textColor) {
76
174
  try {
77
- return (0, _colorContrast.getContrastRatio)((0, _uiColor.getTextColorInNonActiveTheme)(textColor !== null && textColor !== void 0 ? textColor : null, defaultColor || _constants.DEFAULT_COLOR.color), (0, _uiColor.getHighlightColorInNonActiveTheme)(highlightColor !== null && highlightColor !== void 0 ? highlightColor : null, {
78
- defaultBackgroundColor: _constants.DEFAULT_BACKGROUND_COLOR,
79
- transparentColor: _constants.TRANSPARENT_HIGHLIGHT_COLOR
80
- }));
175
+ return (0, _colorContrast.getContrastRatio)((0, _uiColor.getTextColorInNonActiveTheme)(textColor !== null && textColor !== void 0 ? textColor : null, defaultColor || _constants.DEFAULT_COLOR.color), getResolvedBackgroundColorValueInNonActiveTheme(backgroundColor));
81
176
  } catch (_unused2) {
82
177
  // if we failed to calculate the contrast ratio, return null
83
178
  return null;
@@ -94,96 +189,103 @@ var getAccessibilityStatus = function getAccessibilityStatus(contrastRatio) {
94
189
  };
95
190
 
96
191
  /**
97
- * Collects the worst accessibility status across all unique (textColor, highlightColor)
192
+ * Computes status from active foreground/background colors only.
193
+ * Used by the gate-off path so legacy behavior stays isolated.
194
+ */
195
+ var getAccessibilityStatusFromColorPair = function getAccessibilityStatusFromColorPair(defaultColor, backgroundColor, textColor) {
196
+ var contrastRatio = getContrastRatio(defaultColor, backgroundColor, textColor);
197
+ return contrastRatio === null ? null : getAccessibilityStatus(contrastRatio);
198
+ };
199
+
200
+ /**
201
+ * Returns the lowest contrast ratio across active and non-active themes.
202
+ */
203
+ var getMostCriticalContrastRatioAcrossThemes = function getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor) {
204
+ var contrastRatio = getContrastRatio(defaultColor, backgroundColor, textColor);
205
+ var nonActiveThemeContrastRatio = getNonActiveThemeContrastRatio(defaultColor, backgroundColor, textColor);
206
+ if (contrastRatio !== null && nonActiveThemeContrastRatio !== null) {
207
+ return Math.min(contrastRatio, nonActiveThemeContrastRatio);
208
+ }
209
+ return contrastRatio;
210
+ };
211
+ var getAccessibilityStatusFromColorPairAcrossThemes = function getAccessibilityStatusFromColorPairAcrossThemes(defaultColor, backgroundColor, textColor) {
212
+ var mostCriticalContrastRatio = getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor);
213
+ return mostCriticalContrastRatio === null ? null : getAccessibilityStatus(mostCriticalContrastRatio);
214
+ };
215
+
216
+ /**
217
+ * Collects the worst accessibility status across all unique foreground/background
98
218
  * combinations in the current selection.
99
219
  *
100
- * When the selection spans multiple text colors and/or highlight colors,
101
- * this walks the document between selection boundaries and checks every
102
- * text node's color marks, computing the contrast ratio for each unique pair
103
- * (across both the active and non-active theme) and returning the worst
104
- * status found.
220
+ * When the selection spans multiple text colors and/or resolved backgrounds,
221
+ * this checks each unique pair across both the active and non-active theme and
222
+ * returns the worst status found.
105
223
  */
106
- var getWorstAccessibilityStatusFromSelection = function getWorstAccessibilityStatusFromSelection(api, defaultColor) {
107
- if (!(api !== null && api !== void 0 && api.core)) {
224
+ var getWorstAccessibilityStatusFromEditorState = function getWorstAccessibilityStatusFromEditorState(state, defaultColor) {
225
+ var worstContrastRatio = null;
226
+
227
+ // Text/highlight colors only apply to a text range. If the selection is
228
+ // not a text selection (e.g. a node, cell or all selection) there is no
229
+ // meaningful range of colored text to evaluate.
230
+ if (!(state.selection instanceof _state.TextSelection) || state.selection.empty) {
108
231
  return null;
109
232
  }
110
-
111
- // Track the lowest (worst) contrast ratio across all pairs; a lower ratio
112
- // means a worse accessibility status, so a single numeric comparison is
113
- // enough to find the worst pair.
114
- var worstContrastRatio = null;
115
- api.core.actions.execute(function (_ref) {
116
- var tr = _ref.tr;
117
- // Text/highlight colors only apply to a text range. If the selection is
118
- // not a text selection (e.g. a node, cell or all selection) there is no
119
- // meaningful range of colored text to evaluate.
120
- if (!(tr.selection instanceof _state.TextSelection)) {
121
- return null;
233
+ var _state$selection = state.selection,
234
+ from = _state$selection.from,
235
+ to = _state$selection.to;
236
+ var seen = new Set();
237
+ state.doc.nodesBetween(from, to, function (node, pos) {
238
+ var _backgroundColor$colo;
239
+ if (!node.isText) {
240
+ return !node.isLeaf;
122
241
  }
123
- var _tr$selection = tr.selection,
124
- from = _tr$selection.from,
125
- to = _tr$selection.to;
126
- var seen = new Set();
127
- tr.doc.nodesBetween(from, to, function (node) {
128
- // Text and highlight color marks only apply to text nodes, so skip
129
- // any non-text leaves (e.g. emoji, mentions, inline cards). Continue
130
- // descending into container nodes to reach their text children.
131
- if (!node.isText) {
132
- return !node.isLeaf;
133
- }
134
-
135
- // Extract both color marks in a single pass over the node's marks
136
- // rather than two `Array.find` scans.
137
- var textColor = null;
138
- var highlightColor = null;
139
- var _iterator = _createForOfIteratorHelper(node.marks),
140
- _step;
141
- try {
142
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
143
- var mark = _step.value;
144
- if (mark.type.name === 'textColor') {
145
- var _mark$attrs$color;
146
- textColor = (_mark$attrs$color = mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : null;
147
- } else if (mark.type.name === 'backgroundColor') {
148
- var _mark$attrs$color2;
149
- highlightColor = (_mark$attrs$color2 = mark.attrs.color) !== null && _mark$attrs$color2 !== void 0 ? _mark$attrs$color2 : null;
150
- }
242
+ var textColor = null;
243
+ var _iterator2 = _createForOfIteratorHelper(node.marks),
244
+ _step2;
245
+ try {
246
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
247
+ var mark = _step2.value;
248
+ if (mark.type.name === 'textColor') {
249
+ var _mark$attrs$color;
250
+ textColor = (_mark$attrs$color = mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : null;
151
251
  }
152
- } catch (err) {
153
- _iterator.e(err);
154
- } finally {
155
- _iterator.f();
156
- }
157
- var pairKey = "".concat(textColor !== null && textColor !== void 0 ? textColor : 'default', "|").concat(highlightColor !== null && highlightColor !== void 0 ? highlightColor : 'default');
158
- // Skip pairs we have already evaluated so the expensive contrast
159
- // calculations run at most once per unique (text, highlight) pair.
160
- if (seen.has(pairKey)) {
161
- return;
162
- }
163
- seen.add(pairKey);
164
- var contrastRatio = getContrastRatio(defaultColor, highlightColor, textColor);
165
- if (contrastRatio === null) {
166
- return;
167
- }
168
-
169
- // Account for the non-active theme so the worst-case (least
170
- // accessible) contrast across both themes is used for each pair,
171
- // keeping multi-color selections consistent with the single-pair path.
172
- var nonActiveThemeContrastRatio = getNonActiveThemeContrastRatio(defaultColor, highlightColor, textColor);
173
- var mostCriticalContrastRatio = nonActiveThemeContrastRatio !== null ? Math.min(contrastRatio, nonActiveThemeContrastRatio) : contrastRatio;
174
- if (worstContrastRatio === null || mostCriticalContrastRatio < worstContrastRatio) {
175
- worstContrastRatio = mostCriticalContrastRatio;
176
252
  }
177
- });
178
-
179
- // Read-only operation — do not dispatch
180
- return null;
253
+ } catch (err) {
254
+ _iterator2.e(err);
255
+ } finally {
256
+ _iterator2.f();
257
+ }
258
+ var backgroundColor = getResolvedBackgroundColorForTextNode(state.doc.resolve(pos), node);
259
+ var pairKey = "".concat(textColor !== null && textColor !== void 0 ? textColor : 'default', "|").concat(backgroundColor.source, "|").concat((_backgroundColor$colo = backgroundColor.color) !== null && _backgroundColor$colo !== void 0 ? _backgroundColor$colo : 'default');
260
+ // Skip foreground/background pairs already evaluated. The source is
261
+ // part of the key because text highlights and element backgrounds use
262
+ // different editor palettes.
263
+ if (seen.has(pairKey)) {
264
+ return;
265
+ }
266
+ seen.add(pairKey);
267
+ var mostCriticalContrastRatio = getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor);
268
+ if (mostCriticalContrastRatio === null) {
269
+ return;
270
+ }
271
+ if (worstContrastRatio === null || mostCriticalContrastRatio < worstContrastRatio) {
272
+ worstContrastRatio = mostCriticalContrastRatio;
273
+ }
181
274
  });
182
275
  return worstContrastRatio === null ? null : getAccessibilityStatus(worstContrastRatio);
183
276
  };
184
- var AccessibilityStatus = function AccessibilityStatus(_ref2) {
185
- var accessibilityStatus = _ref2.accessibilityStatus,
186
- formatMessage = _ref2.formatMessage;
277
+ var getAccessibilityStatusForCurrentSelection = exports.getAccessibilityStatusForCurrentSelection = function getAccessibilityStatusForCurrentSelection(state, defaultColor, highlightColor, textColor) {
278
+ if (state.selection instanceof _state.TextSelection) {
279
+ if (!state.selection.empty) {
280
+ return getWorstAccessibilityStatusFromEditorState(state, defaultColor);
281
+ }
282
+ return getAccessibilityStatusFromColorPairAcrossThemes(defaultColor, getResolvedBackgroundColorForPosition(state.selection.$from, highlightColor), textColor);
283
+ }
284
+ return null;
285
+ };
286
+ var AccessibilityStatus = function AccessibilityStatus(_ref) {
287
+ var accessibilityStatus = _ref.accessibilityStatus,
288
+ formatMessage = _ref.formatMessage;
187
289
  if (accessibilityStatus === 'accessible') {
188
290
  return /*#__PURE__*/_react.default.createElement(_compiled.Text, {
189
291
  as: "span",
@@ -208,62 +310,20 @@ var styles = {
208
310
  container: "_19itglyw _19pku2gc _ca0q1b66 _n3td1b66 _19bvu2gc _u5f31b66 _1e0c1txw _4cvr1h6o _1bah1yb4",
209
311
  containerPatch: "_19pkze3t _ca0qze3t _n3tdze3t _19bvze3t _u5f3ze3t"
210
312
  };
211
- var ColorAccessibilityMenuItem = exports.ColorAccessibilityMenuItem = function ColorAccessibilityMenuItem(_ref3) {
212
- var api = _ref3.api;
313
+ var ColorAccessibilityMenuItem = exports.ColorAccessibilityMenuItem = function ColorAccessibilityMenuItem(_ref2) {
314
+ var api = _ref2.api;
213
315
  var _useIntl = (0, _reactIntl.useIntl)(),
214
316
  formatMessage = _useIntl.formatMessage;
215
317
  var _useColorAccessibilit = useColorAccessibilityState(api),
216
318
  defaultColor = _useColorAccessibilit.defaultColor,
217
319
  highlightColor = _useColorAccessibilit.highlightColor,
218
- highlightColorInNonActiveTheme = _useColorAccessibilit.highlightColorInNonActiveTheme,
219
- isMultiHighlightColor = _useColorAccessibilit.isMultiHighlightColor,
220
- isMultiTextColor = _useColorAccessibilit.isMultiTextColor,
221
- textColor = _useColorAccessibilit.textColor,
222
- textColorInNonActiveTheme = _useColorAccessibilit.textColorInNonActiveTheme;
223
- // The multi-color selection handling (walking every unique text/highlight
224
- // pair across the active and non-active theme) is only performed when the
225
- // patch gate is on. When the gate is off we fall back to the legacy behavior
226
- // of only evaluating the single active text/highlight color in the current
227
- // active theme
228
- var isMultiColorSelection = Boolean(isMultiTextColor || isMultiHighlightColor) && (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1');
229
-
230
- // The complement of `isMultiColorSelection`: the single active text/highlight
231
- // pair is evaluated whenever we are not walking a multi-color selection. This
232
- // covers both a genuinely single-color selection (gate on) and every
233
- // selection when the gate is off (legacy behavior).
234
- var isSingleColorSelection = !isMultiColorSelection;
235
-
236
- // Memoize the selection walk so we don't re-traverse the entire ProseMirror
237
- // document on every render. It only needs to recompute when the multi-color
238
- // selection state or the inputs to the walk change (the selection flags,
239
- // default color, or the plugin api).
240
- var multiColorStatus = _react.default.useMemo(function () {
241
- return isMultiColorSelection ? getWorstAccessibilityStatusFromSelection(api, defaultColor) : null;
242
- },
243
- // eslint-disable-next-line react-hooks/exhaustive-deps
244
- [isMultiColorSelection, isMultiTextColor, isMultiHighlightColor, defaultColor, api]);
245
-
246
- // The single active text/highlight pair path. Everything below only applies
247
- // when we are not walking a multi-color selection
248
- var singleColorStatus = null;
249
- if (isSingleColorSelection) {
250
- var singleColorContrastRatio = getContrastRatio(defaultColor, highlightColor, textColor);
251
-
252
- // Also account for the non-active theme (gate on only) so the worst-case
253
- // (least accessible) status across both themes is shown.
254
- var nonActiveThemeSingleColorRatio = null;
255
- if (textColorInNonActiveTheme && highlightColorInNonActiveTheme && (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1')) {
256
- try {
257
- nonActiveThemeSingleColorRatio = (0, _colorContrast.getContrastRatio)(textColorInNonActiveTheme, highlightColorInNonActiveTheme);
258
- } catch (_unused3) {
259
- // if we failed to calculate the contrast ratio, leave as null
260
- nonActiveThemeSingleColorRatio = null;
261
- }
262
- }
263
- var mostCriticalContrastRatio = singleColorContrastRatio !== null && nonActiveThemeSingleColorRatio !== null ? Math.min(singleColorContrastRatio, nonActiveThemeSingleColorRatio) : singleColorContrastRatio;
264
- singleColorStatus = mostCriticalContrastRatio !== null ? getAccessibilityStatus(mostCriticalContrastRatio) : null;
265
- }
266
- var accessibilityStatus = isSingleColorSelection ? singleColorStatus : multiColorStatus;
320
+ textColor = _useColorAccessibilit.textColor;
321
+ var _useEditorToolbar = (0, _toolbar.useEditorToolbar)(),
322
+ editorView = _useEditorToolbar.editorView;
323
+ var editorState = editorView === null || editorView === void 0 ? void 0 : editorView.state;
324
+ var accessibilityStatus = _react.default.useMemo(function () {
325
+ return editorState && (0, _platformFeatureFlags.fg)('platform_editor_lovability_text_bg_color_patch_1') ? getAccessibilityStatusForCurrentSelection(editorState, defaultColor, highlightColor, textColor) : getAccessibilityStatusFromColorPair(defaultColor, getResolvedBackgroundFromHighlight(highlightColor), textColor);
326
+ }, [defaultColor, editorState, highlightColor, textColor]);
267
327
  if (accessibilityStatus === null) {
268
328
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
269
329
  }
@@ -1,9 +1,8 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
- import { getTextColorInNonActiveTheme, textColorPalette, textColorPaletteNew } from '@atlaskit/editor-common/ui-color';
2
+ import { textColorPalette, textColorPaletteNew } from '@atlaskit/editor-common/ui-color';
3
3
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
- import { fg } from '@atlaskit/platform-feature-flags';
5
4
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
6
- import { getActiveColor, isMultiTextColorSelection } from './utils/color';
5
+ import { getActiveColor } from './utils/color';
7
6
  import { DEFAULT_COLOR } from './utils/constants';
8
7
  import { getDisabledState } from './utils/disabled';
9
8
  function createInitialPluginState(editorState, pluginConfig) {
@@ -20,12 +19,7 @@ function createInitialPluginState(editorState, pluginConfig) {
20
19
  disabled: getDisabledState(editorState),
21
20
  palette,
22
21
  defaultColor: defaultColor.color,
23
- isPaletteOpen: false,
24
- // eslint-disable-next-line @atlaskit/platform/no-preconditioning
25
- ...(fg('platform_editor_lovability_text_bg_color_patch_1') && expValEqualsNoExposure('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
26
- colorInNonActiveTheme: getTextColorInNonActiveTheme(color, defaultColor.color),
27
- isMultiTextColor: isMultiTextColorSelection(editorState)
28
- })
22
+ isPaletteOpen: false
29
23
  };
30
24
  return state;
31
25
  }
@@ -51,12 +45,7 @@ export function createPlugin(dispatch, pluginConfig) {
51
45
  case ACTIONS.RESET_COLOR:
52
46
  nextState = {
53
47
  ...pluginState,
54
- color: pluginState.defaultColor,
55
- // eslint-disable-next-line @atlaskit/platform/no-preconditioning
56
- ...(fg('platform_editor_lovability_text_bg_color_patch_1') && expValEqualsNoExposure('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
57
- colorInNonActiveTheme: getTextColorInNonActiveTheme(pluginState.defaultColor, pluginState.defaultColor),
58
- isMultiTextColor: false
59
- })
48
+ color: pluginState.defaultColor
60
49
  };
61
50
  break;
62
51
  case ACTIONS.SET_COLOR:
@@ -64,12 +53,7 @@ export function createPlugin(dispatch, pluginConfig) {
64
53
  ...pluginState,
65
54
  color: meta.color,
66
55
  disabled: false,
67
- isPaletteOpen: false,
68
- // eslint-disable-next-line @atlaskit/platform/no-preconditioning
69
- ...(fg('platform_editor_lovability_text_bg_color_patch_1') && expValEqualsNoExposure('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
70
- colorInNonActiveTheme: getTextColorInNonActiveTheme(meta.color, pluginState.defaultColor),
71
- isMultiTextColor: false
72
- })
56
+ isPaletteOpen: false
73
57
  };
74
58
  break;
75
59
  case ACTIONS.DISABLE:
@@ -89,15 +73,10 @@ export function createPlugin(dispatch, pluginConfig) {
89
73
  nextState = {
90
74
  ...pluginState,
91
75
  color,
92
- disabled: getDisabledState(newState),
93
- // eslint-disable-next-line @atlaskit/platform/no-preconditioning
94
- ...(color !== pluginState.color && fg('platform_editor_lovability_text_bg_color_patch_1') && expValEqualsNoExposure('platform_editor_lovability_text_bg_color', 'isEnabled', true) && {
95
- colorInNonActiveTheme: getTextColorInNonActiveTheme(color, pluginState.defaultColor),
96
- isMultiTextColor: isMultiTextColorSelection(newState)
97
- })
76
+ disabled: getDisabledState(newState)
98
77
  };
99
78
  }
100
- if (pluginState && pluginState.color !== nextState.color || pluginState && pluginState.colorInNonActiveTheme !== nextState.colorInNonActiveTheme || pluginState && pluginState.disabled !== nextState.disabled || pluginState && pluginState.isMultiTextColor !== nextState.isMultiTextColor || pluginState && pluginState.isPaletteOpen !== nextState.isPaletteOpen) {
79
+ if (pluginState && pluginState.color !== nextState.color || pluginState && pluginState.disabled !== nextState.disabled || pluginState && pluginState.isPaletteOpen !== nextState.isPaletteOpen) {
101
80
  dispatch(pluginKey, nextState);
102
81
  return nextState;
103
82
  }