@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 +14 -0
- package/dist/cjs/pm-plugins/main.js +3 -16
- package/dist/cjs/pm-plugins/utils/color.js +1 -24
- package/dist/cjs/ui/ColorAccessibilityMenuItem.js +212 -152
- package/dist/es2019/pm-plugins/main.js +7 -28
- package/dist/es2019/pm-plugins/utils/color.js +0 -27
- package/dist/es2019/ui/ColorAccessibilityMenuItem.js +190 -142
- package/dist/esm/pm-plugins/main.js +5 -18
- package/dist/esm/pm-plugins/utils/color.js +0 -23
- package/dist/esm/ui/ColorAccessibilityMenuItem.js +214 -154
- package/dist/types/pm-plugins/main.d.ts +0 -6
- package/dist/types/pm-plugins/utils/color.d.ts +0 -5
- package/dist/types/ui/ColorAccessibilityMenuItem.d.ts +15 -0
- package/package.json +6 -6
|
@@ -6,12 +6,15 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
6
6
|
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; }
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { useIntl } from 'react-intl';
|
|
9
|
+
import { PanelType } from '@atlaskit/adf-schema/panel';
|
|
9
10
|
import { IconButton } from '@atlaskit/button/new';
|
|
10
11
|
import { cx } from '@atlaskit/css';
|
|
11
12
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
12
13
|
import { colorAccessibilityMessages as messages } from '@atlaskit/editor-common/messages';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
14
|
+
import { getPanelTypeBackgroundNoTokens } from '@atlaskit/editor-common/panel';
|
|
15
|
+
import { useEditorToolbar } from '@atlaskit/editor-common/toolbar';
|
|
16
|
+
import { getTextColorInNonActiveTheme, getTokenCSSVariableValue, getTokenCSSVariableValueForNonActiveTheme } from '@atlaskit/editor-common/ui-color';
|
|
17
|
+
import { hexToEditorBackgroundPaletteColor, hexToEditorTextBackgroundPaletteColor, hexToEditorTextPaletteColor } from '@atlaskit/editor-palette';
|
|
15
18
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
16
19
|
import AccessibilityIcon from '@atlaskit/icon/core/accessibility';
|
|
17
20
|
import QuestionCircleIcon from '@atlaskit/icon/core/question-circle';
|
|
@@ -19,7 +22,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
19
22
|
import { Box, Inline, Text } from '@atlaskit/primitives/compiled';
|
|
20
23
|
import { getTokenValue } from '@atlaskit/tokens/get-token-value';
|
|
21
24
|
import { getContrastRatio as calcContrastRatio } from '../pm-plugins/utils/color-contrast';
|
|
22
|
-
import { DEFAULT_COLOR, DEFAULT_BACKGROUND_COLOR,
|
|
25
|
+
import { DEFAULT_COLOR, DEFAULT_BACKGROUND_COLOR, ACCESSIBLE_CONTRAST_RATIO, DIFFICULT_CONTRAST_RATIO } from '../pm-plugins/utils/constants';
|
|
23
26
|
var resolveColorValue = function resolveColorValue(color, fallback) {
|
|
24
27
|
return getTokenCSSVariableValue(color) || (color.startsWith('var(') ? fallback : color);
|
|
25
28
|
};
|
|
@@ -30,30 +33,128 @@ var getForegroundColor = function getForegroundColor(textColor, defaultColor) {
|
|
|
30
33
|
var colorValue = hexToEditorTextPaletteColor(textColor) || textColor;
|
|
31
34
|
return resolveColorValue(colorValue, textColor);
|
|
32
35
|
};
|
|
33
|
-
var getBackgroundColor = function getBackgroundColor(
|
|
34
|
-
|
|
36
|
+
var getBackgroundColor = function getBackgroundColor(backgroundColor) {
|
|
37
|
+
var palette = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
|
38
|
+
if (!backgroundColor || backgroundColor === 'none') {
|
|
35
39
|
return getTokenValue('elevation.surface', DEFAULT_BACKGROUND_COLOR);
|
|
36
40
|
}
|
|
37
|
-
var colorValue = hexToEditorTextBackgroundPaletteColor(
|
|
38
|
-
return resolveColorValue(colorValue,
|
|
41
|
+
var colorValue = palette === 'element' ? hexToEditorBackgroundPaletteColor(backgroundColor) || backgroundColor : hexToEditorTextBackgroundPaletteColor(backgroundColor) || backgroundColor;
|
|
42
|
+
return resolveColorValue(colorValue, backgroundColor);
|
|
43
|
+
};
|
|
44
|
+
var getBackgroundColorInNonActiveTheme = function getBackgroundColorInNonActiveTheme(backgroundColor) {
|
|
45
|
+
var palette = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
|
46
|
+
if (!backgroundColor || backgroundColor === 'none') {
|
|
47
|
+
return getTokenCSSVariableValueForNonActiveTheme("var(--ds-surface, #FFFFFF)", DEFAULT_BACKGROUND_COLOR);
|
|
48
|
+
}
|
|
49
|
+
var colorValue = palette === 'element' ? hexToEditorBackgroundPaletteColor(backgroundColor) || backgroundColor : hexToEditorTextBackgroundPaletteColor(backgroundColor) || backgroundColor;
|
|
50
|
+
return getTokenCSSVariableValueForNonActiveTheme(colorValue, backgroundColor);
|
|
51
|
+
};
|
|
52
|
+
var STANDARD_PANEL_BACKGROUND_COLORS = new Map([[PanelType.INFO, getPanelTypeBackgroundNoTokens(PanelType.INFO)], [PanelType.NOTE, getPanelTypeBackgroundNoTokens(PanelType.NOTE)], [PanelType.SUCCESS, getPanelTypeBackgroundNoTokens(PanelType.SUCCESS)], [PanelType.WARNING, getPanelTypeBackgroundNoTokens(PanelType.WARNING)], [PanelType.ERROR, getPanelTypeBackgroundNoTokens(PanelType.ERROR)]]);
|
|
53
|
+
var getResolvedBackgroundFromHighlight = function getResolvedBackgroundFromHighlight(highlightColor) {
|
|
54
|
+
if (!highlightColor) {
|
|
55
|
+
return {
|
|
56
|
+
color: null,
|
|
57
|
+
source: 'text'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
color: highlightColor,
|
|
62
|
+
source: 'text'
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolves a background color from a container node that paints behind text.
|
|
68
|
+
* Callers walk ancestors so the nearest painted container wins.
|
|
69
|
+
*/
|
|
70
|
+
var getSupportedAncestorBackgroundColor = function getSupportedAncestorBackgroundColor(node) {
|
|
71
|
+
var backgroundColor;
|
|
72
|
+
if (node.type.name === 'tableCell' || node.type.name === 'tableHeader') {
|
|
73
|
+
backgroundColor = node.attrs.background;
|
|
74
|
+
} else if (node.type.name === 'panel' || node.type.name === 'panel_c1') {
|
|
75
|
+
if (node.attrs.panelType === PanelType.CUSTOM) {
|
|
76
|
+
backgroundColor = node.attrs.panelColor;
|
|
77
|
+
} else {
|
|
78
|
+
backgroundColor = STANDARD_PANEL_BACKGROUND_COLORS.get(node.attrs.panelType);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return backgroundColor ? {
|
|
82
|
+
color: backgroundColor,
|
|
83
|
+
source: 'element'
|
|
84
|
+
} : null;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolves the visible background behind a text node.
|
|
89
|
+
* Text highlight wins before falling back to the nearest element background.
|
|
90
|
+
*/
|
|
91
|
+
export var getResolvedBackgroundColorForTextNode = function getResolvedBackgroundColorForTextNode($pos, node) {
|
|
92
|
+
var _iterator = _createForOfIteratorHelper(node.marks),
|
|
93
|
+
_step;
|
|
94
|
+
try {
|
|
95
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
96
|
+
var mark = _step.value;
|
|
97
|
+
if (mark.type.name === 'backgroundColor' && mark.attrs.color) {
|
|
98
|
+
return {
|
|
99
|
+
color: mark.attrs.color,
|
|
100
|
+
source: 'text'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
_iterator.e(err);
|
|
106
|
+
} finally {
|
|
107
|
+
_iterator.f();
|
|
108
|
+
}
|
|
109
|
+
for (var depth = $pos.depth; depth > 0; depth--) {
|
|
110
|
+
var resolvedBackgroundColor = getSupportedAncestorBackgroundColor($pos.node(depth));
|
|
111
|
+
if (resolvedBackgroundColor) {
|
|
112
|
+
return resolvedBackgroundColor;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
color: null,
|
|
117
|
+
source: 'text'
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
var getResolvedBackgroundColorForPosition = function getResolvedBackgroundColorForPosition($pos, highlightColor) {
|
|
121
|
+
var highlightBackground = getResolvedBackgroundFromHighlight(highlightColor);
|
|
122
|
+
if (highlightColor) {
|
|
123
|
+
return highlightBackground;
|
|
124
|
+
}
|
|
125
|
+
for (var depth = $pos.depth; depth > 0; depth--) {
|
|
126
|
+
var resolvedBackgroundColor = getSupportedAncestorBackgroundColor($pos.node(depth));
|
|
127
|
+
if (resolvedBackgroundColor) {
|
|
128
|
+
return resolvedBackgroundColor;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return highlightBackground;
|
|
132
|
+
};
|
|
133
|
+
var getResolvedBackgroundColorValue = function getResolvedBackgroundColorValue(backgroundColor) {
|
|
134
|
+
if (backgroundColor.source === 'element') {
|
|
135
|
+
return getBackgroundColor(backgroundColor.color, 'element');
|
|
136
|
+
}
|
|
137
|
+
return getBackgroundColor(backgroundColor.color);
|
|
138
|
+
};
|
|
139
|
+
var getResolvedBackgroundColorValueInNonActiveTheme = function getResolvedBackgroundColorValueInNonActiveTheme(backgroundColor) {
|
|
140
|
+
if (backgroundColor.source === 'element') {
|
|
141
|
+
return getBackgroundColorInNonActiveTheme(backgroundColor.color, 'element');
|
|
142
|
+
}
|
|
143
|
+
return getBackgroundColorInNonActiveTheme(backgroundColor.color);
|
|
39
144
|
};
|
|
40
145
|
var useColorAccessibilityState = function useColorAccessibilityState(api) {
|
|
41
146
|
return useSharedPluginStateWithSelector(api, ['textColor', 'highlight'], function (states) {
|
|
42
|
-
var _states$textColorStat, _states$highlightStat, _states$
|
|
147
|
+
var _states$textColorStat, _states$highlightStat, _states$textColorStat2;
|
|
43
148
|
return {
|
|
44
149
|
defaultColor: (_states$textColorStat = states.textColorState) === null || _states$textColorStat === void 0 ? void 0 : _states$textColorStat.defaultColor,
|
|
45
150
|
highlightColor: (_states$highlightStat = states.highlightState) === null || _states$highlightStat === void 0 ? void 0 : _states$highlightStat.activeColor,
|
|
46
|
-
|
|
47
|
-
isMultiHighlightColor: (_states$highlightStat3 = states.highlightState) === null || _states$highlightStat3 === void 0 ? void 0 : _states$highlightStat3.isMultiHighlightColor,
|
|
48
|
-
isMultiTextColor: (_states$textColorStat2 = states.textColorState) === null || _states$textColorStat2 === void 0 ? void 0 : _states$textColorStat2.isMultiTextColor,
|
|
49
|
-
textColor: (_states$textColorStat3 = states.textColorState) === null || _states$textColorStat3 === void 0 ? void 0 : _states$textColorStat3.color,
|
|
50
|
-
textColorInNonActiveTheme: (_states$textColorStat4 = states.textColorState) === null || _states$textColorStat4 === void 0 ? void 0 : _states$textColorStat4.colorInNonActiveTheme
|
|
151
|
+
textColor: (_states$textColorStat2 = states.textColorState) === null || _states$textColorStat2 === void 0 ? void 0 : _states$textColorStat2.color
|
|
51
152
|
};
|
|
52
153
|
});
|
|
53
154
|
};
|
|
54
|
-
var getContrastRatio = function getContrastRatio(defaultColor,
|
|
155
|
+
var getContrastRatio = function getContrastRatio(defaultColor, backgroundColor, textColor) {
|
|
55
156
|
try {
|
|
56
|
-
var contrastRatio = calcContrastRatio(getForegroundColor(textColor, defaultColor),
|
|
157
|
+
var contrastRatio = calcContrastRatio(getForegroundColor(textColor, defaultColor), getResolvedBackgroundColorValue(backgroundColor));
|
|
57
158
|
return contrastRatio;
|
|
58
159
|
} catch (_unused) {
|
|
59
160
|
// if we failed to calculate the contrast ratio, return null
|
|
@@ -61,16 +162,10 @@ var getContrastRatio = function getContrastRatio(defaultColor, highlightColor, t
|
|
|
61
162
|
}
|
|
62
163
|
};
|
|
63
164
|
|
|
64
|
-
// Computes the contrast ratio
|
|
65
|
-
|
|
66
|
-
// evaluates the same colors the single-pair plugin-state path does. Returns null
|
|
67
|
-
// if it cannot be calculated.
|
|
68
|
-
var getNonActiveThemeContrastRatio = function getNonActiveThemeContrastRatio(defaultColor, highlightColor, textColor) {
|
|
165
|
+
// Computes the contrast ratio as it would appear in the non-active theme.
|
|
166
|
+
var getNonActiveThemeContrastRatio = function getNonActiveThemeContrastRatio(defaultColor, backgroundColor, textColor) {
|
|
69
167
|
try {
|
|
70
|
-
return calcContrastRatio(getTextColorInNonActiveTheme(textColor !== null && textColor !== void 0 ? textColor : null, defaultColor || DEFAULT_COLOR.color),
|
|
71
|
-
defaultBackgroundColor: DEFAULT_BACKGROUND_COLOR,
|
|
72
|
-
transparentColor: TRANSPARENT_HIGHLIGHT_COLOR
|
|
73
|
-
}));
|
|
168
|
+
return calcContrastRatio(getTextColorInNonActiveTheme(textColor !== null && textColor !== void 0 ? textColor : null, defaultColor || DEFAULT_COLOR.color), getResolvedBackgroundColorValueInNonActiveTheme(backgroundColor));
|
|
74
169
|
} catch (_unused2) {
|
|
75
170
|
// if we failed to calculate the contrast ratio, return null
|
|
76
171
|
return null;
|
|
@@ -87,96 +182,103 @@ var getAccessibilityStatus = function getAccessibilityStatus(contrastRatio) {
|
|
|
87
182
|
};
|
|
88
183
|
|
|
89
184
|
/**
|
|
90
|
-
*
|
|
185
|
+
* Computes status from active foreground/background colors only.
|
|
186
|
+
* Used by the gate-off path so legacy behavior stays isolated.
|
|
187
|
+
*/
|
|
188
|
+
var getAccessibilityStatusFromColorPair = function getAccessibilityStatusFromColorPair(defaultColor, backgroundColor, textColor) {
|
|
189
|
+
var contrastRatio = getContrastRatio(defaultColor, backgroundColor, textColor);
|
|
190
|
+
return contrastRatio === null ? null : getAccessibilityStatus(contrastRatio);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Returns the lowest contrast ratio across active and non-active themes.
|
|
195
|
+
*/
|
|
196
|
+
var getMostCriticalContrastRatioAcrossThemes = function getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor) {
|
|
197
|
+
var contrastRatio = getContrastRatio(defaultColor, backgroundColor, textColor);
|
|
198
|
+
var nonActiveThemeContrastRatio = getNonActiveThemeContrastRatio(defaultColor, backgroundColor, textColor);
|
|
199
|
+
if (contrastRatio !== null && nonActiveThemeContrastRatio !== null) {
|
|
200
|
+
return Math.min(contrastRatio, nonActiveThemeContrastRatio);
|
|
201
|
+
}
|
|
202
|
+
return contrastRatio;
|
|
203
|
+
};
|
|
204
|
+
var getAccessibilityStatusFromColorPairAcrossThemes = function getAccessibilityStatusFromColorPairAcrossThemes(defaultColor, backgroundColor, textColor) {
|
|
205
|
+
var mostCriticalContrastRatio = getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor);
|
|
206
|
+
return mostCriticalContrastRatio === null ? null : getAccessibilityStatus(mostCriticalContrastRatio);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Collects the worst accessibility status across all unique foreground/background
|
|
91
211
|
* combinations in the current selection.
|
|
92
212
|
*
|
|
93
|
-
* When the selection spans multiple text colors and/or
|
|
94
|
-
* this
|
|
95
|
-
*
|
|
96
|
-
* (across both the active and non-active theme) and returning the worst
|
|
97
|
-
* status found.
|
|
213
|
+
* When the selection spans multiple text colors and/or resolved backgrounds,
|
|
214
|
+
* this checks each unique pair across both the active and non-active theme and
|
|
215
|
+
* returns the worst status found.
|
|
98
216
|
*/
|
|
99
|
-
var
|
|
100
|
-
|
|
217
|
+
var getWorstAccessibilityStatusFromEditorState = function getWorstAccessibilityStatusFromEditorState(state, defaultColor) {
|
|
218
|
+
var worstContrastRatio = null;
|
|
219
|
+
|
|
220
|
+
// Text/highlight colors only apply to a text range. If the selection is
|
|
221
|
+
// not a text selection (e.g. a node, cell or all selection) there is no
|
|
222
|
+
// meaningful range of colored text to evaluate.
|
|
223
|
+
if (!(state.selection instanceof TextSelection) || state.selection.empty) {
|
|
101
224
|
return null;
|
|
102
225
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// not a text selection (e.g. a node, cell or all selection) there is no
|
|
112
|
-
// meaningful range of colored text to evaluate.
|
|
113
|
-
if (!(tr.selection instanceof TextSelection)) {
|
|
114
|
-
return null;
|
|
226
|
+
var _state$selection = state.selection,
|
|
227
|
+
from = _state$selection.from,
|
|
228
|
+
to = _state$selection.to;
|
|
229
|
+
var seen = new Set();
|
|
230
|
+
state.doc.nodesBetween(from, to, function (node, pos) {
|
|
231
|
+
var _backgroundColor$colo;
|
|
232
|
+
if (!node.isText) {
|
|
233
|
+
return !node.isLeaf;
|
|
115
234
|
}
|
|
116
|
-
var
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return !node.isLeaf;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Extract both color marks in a single pass over the node's marks
|
|
129
|
-
// rather than two `Array.find` scans.
|
|
130
|
-
var textColor = null;
|
|
131
|
-
var highlightColor = null;
|
|
132
|
-
var _iterator = _createForOfIteratorHelper(node.marks),
|
|
133
|
-
_step;
|
|
134
|
-
try {
|
|
135
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
136
|
-
var mark = _step.value;
|
|
137
|
-
if (mark.type.name === 'textColor') {
|
|
138
|
-
var _mark$attrs$color;
|
|
139
|
-
textColor = (_mark$attrs$color = mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : null;
|
|
140
|
-
} else if (mark.type.name === 'backgroundColor') {
|
|
141
|
-
var _mark$attrs$color2;
|
|
142
|
-
highlightColor = (_mark$attrs$color2 = mark.attrs.color) !== null && _mark$attrs$color2 !== void 0 ? _mark$attrs$color2 : null;
|
|
143
|
-
}
|
|
235
|
+
var textColor = null;
|
|
236
|
+
var _iterator2 = _createForOfIteratorHelper(node.marks),
|
|
237
|
+
_step2;
|
|
238
|
+
try {
|
|
239
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
240
|
+
var mark = _step2.value;
|
|
241
|
+
if (mark.type.name === 'textColor') {
|
|
242
|
+
var _mark$attrs$color;
|
|
243
|
+
textColor = (_mark$attrs$color = mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : null;
|
|
144
244
|
}
|
|
145
|
-
} catch (err) {
|
|
146
|
-
_iterator.e(err);
|
|
147
|
-
} finally {
|
|
148
|
-
_iterator.f();
|
|
149
|
-
}
|
|
150
|
-
var pairKey = "".concat(textColor !== null && textColor !== void 0 ? textColor : 'default', "|").concat(highlightColor !== null && highlightColor !== void 0 ? highlightColor : 'default');
|
|
151
|
-
// Skip pairs we have already evaluated so the expensive contrast
|
|
152
|
-
// calculations run at most once per unique (text, highlight) pair.
|
|
153
|
-
if (seen.has(pairKey)) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
seen.add(pairKey);
|
|
157
|
-
var contrastRatio = getContrastRatio(defaultColor, highlightColor, textColor);
|
|
158
|
-
if (contrastRatio === null) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Account for the non-active theme so the worst-case (least
|
|
163
|
-
// accessible) contrast across both themes is used for each pair,
|
|
164
|
-
// keeping multi-color selections consistent with the single-pair path.
|
|
165
|
-
var nonActiveThemeContrastRatio = getNonActiveThemeContrastRatio(defaultColor, highlightColor, textColor);
|
|
166
|
-
var mostCriticalContrastRatio = nonActiveThemeContrastRatio !== null ? Math.min(contrastRatio, nonActiveThemeContrastRatio) : contrastRatio;
|
|
167
|
-
if (worstContrastRatio === null || mostCriticalContrastRatio < worstContrastRatio) {
|
|
168
|
-
worstContrastRatio = mostCriticalContrastRatio;
|
|
169
245
|
}
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
246
|
+
} catch (err) {
|
|
247
|
+
_iterator2.e(err);
|
|
248
|
+
} finally {
|
|
249
|
+
_iterator2.f();
|
|
250
|
+
}
|
|
251
|
+
var backgroundColor = getResolvedBackgroundColorForTextNode(state.doc.resolve(pos), node);
|
|
252
|
+
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');
|
|
253
|
+
// Skip foreground/background pairs already evaluated. The source is
|
|
254
|
+
// part of the key because text highlights and element backgrounds use
|
|
255
|
+
// different editor palettes.
|
|
256
|
+
if (seen.has(pairKey)) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
seen.add(pairKey);
|
|
260
|
+
var mostCriticalContrastRatio = getMostCriticalContrastRatioAcrossThemes(defaultColor, backgroundColor, textColor);
|
|
261
|
+
if (mostCriticalContrastRatio === null) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (worstContrastRatio === null || mostCriticalContrastRatio < worstContrastRatio) {
|
|
265
|
+
worstContrastRatio = mostCriticalContrastRatio;
|
|
266
|
+
}
|
|
174
267
|
});
|
|
175
268
|
return worstContrastRatio === null ? null : getAccessibilityStatus(worstContrastRatio);
|
|
176
269
|
};
|
|
177
|
-
var
|
|
178
|
-
|
|
179
|
-
|
|
270
|
+
export var getAccessibilityStatusForCurrentSelection = function getAccessibilityStatusForCurrentSelection(state, defaultColor, highlightColor, textColor) {
|
|
271
|
+
if (state.selection instanceof TextSelection) {
|
|
272
|
+
if (!state.selection.empty) {
|
|
273
|
+
return getWorstAccessibilityStatusFromEditorState(state, defaultColor);
|
|
274
|
+
}
|
|
275
|
+
return getAccessibilityStatusFromColorPairAcrossThemes(defaultColor, getResolvedBackgroundColorForPosition(state.selection.$from, highlightColor), textColor);
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
};
|
|
279
|
+
var AccessibilityStatus = function AccessibilityStatus(_ref) {
|
|
280
|
+
var accessibilityStatus = _ref.accessibilityStatus,
|
|
281
|
+
formatMessage = _ref.formatMessage;
|
|
180
282
|
if (accessibilityStatus === 'accessible') {
|
|
181
283
|
return /*#__PURE__*/React.createElement(Text, {
|
|
182
284
|
as: "span",
|
|
@@ -201,62 +303,20 @@ var styles = {
|
|
|
201
303
|
container: "_19itglyw _19pku2gc _ca0q1b66 _n3td1b66 _19bvu2gc _u5f31b66 _1e0c1txw _4cvr1h6o _1bah1yb4",
|
|
202
304
|
containerPatch: "_19pkze3t _ca0qze3t _n3tdze3t _19bvze3t _u5f3ze3t"
|
|
203
305
|
};
|
|
204
|
-
export var ColorAccessibilityMenuItem = function ColorAccessibilityMenuItem(
|
|
205
|
-
var api =
|
|
306
|
+
export var ColorAccessibilityMenuItem = function ColorAccessibilityMenuItem(_ref2) {
|
|
307
|
+
var api = _ref2.api;
|
|
206
308
|
var _useIntl = useIntl(),
|
|
207
309
|
formatMessage = _useIntl.formatMessage;
|
|
208
310
|
var _useColorAccessibilit = useColorAccessibilityState(api),
|
|
209
311
|
defaultColor = _useColorAccessibilit.defaultColor,
|
|
210
312
|
highlightColor = _useColorAccessibilit.highlightColor,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// patch gate is on. When the gate is off we fall back to the legacy behavior
|
|
219
|
-
// of only evaluating the single active text/highlight color in the current
|
|
220
|
-
// active theme
|
|
221
|
-
var isMultiColorSelection = Boolean(isMultiTextColor || isMultiHighlightColor) && fg('platform_editor_lovability_text_bg_color_patch_1');
|
|
222
|
-
|
|
223
|
-
// The complement of `isMultiColorSelection`: the single active text/highlight
|
|
224
|
-
// pair is evaluated whenever we are not walking a multi-color selection. This
|
|
225
|
-
// covers both a genuinely single-color selection (gate on) and every
|
|
226
|
-
// selection when the gate is off (legacy behavior).
|
|
227
|
-
var isSingleColorSelection = !isMultiColorSelection;
|
|
228
|
-
|
|
229
|
-
// Memoize the selection walk so we don't re-traverse the entire ProseMirror
|
|
230
|
-
// document on every render. It only needs to recompute when the multi-color
|
|
231
|
-
// selection state or the inputs to the walk change (the selection flags,
|
|
232
|
-
// default color, or the plugin api).
|
|
233
|
-
var multiColorStatus = React.useMemo(function () {
|
|
234
|
-
return isMultiColorSelection ? getWorstAccessibilityStatusFromSelection(api, defaultColor) : null;
|
|
235
|
-
},
|
|
236
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
237
|
-
[isMultiColorSelection, isMultiTextColor, isMultiHighlightColor, defaultColor, api]);
|
|
238
|
-
|
|
239
|
-
// The single active text/highlight pair path. Everything below only applies
|
|
240
|
-
// when we are not walking a multi-color selection
|
|
241
|
-
var singleColorStatus = null;
|
|
242
|
-
if (isSingleColorSelection) {
|
|
243
|
-
var singleColorContrastRatio = getContrastRatio(defaultColor, highlightColor, textColor);
|
|
244
|
-
|
|
245
|
-
// Also account for the non-active theme (gate on only) so the worst-case
|
|
246
|
-
// (least accessible) status across both themes is shown.
|
|
247
|
-
var nonActiveThemeSingleColorRatio = null;
|
|
248
|
-
if (textColorInNonActiveTheme && highlightColorInNonActiveTheme && fg('platform_editor_lovability_text_bg_color_patch_1')) {
|
|
249
|
-
try {
|
|
250
|
-
nonActiveThemeSingleColorRatio = calcContrastRatio(textColorInNonActiveTheme, highlightColorInNonActiveTheme);
|
|
251
|
-
} catch (_unused3) {
|
|
252
|
-
// if we failed to calculate the contrast ratio, leave as null
|
|
253
|
-
nonActiveThemeSingleColorRatio = null;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
var mostCriticalContrastRatio = singleColorContrastRatio !== null && nonActiveThemeSingleColorRatio !== null ? Math.min(singleColorContrastRatio, nonActiveThemeSingleColorRatio) : singleColorContrastRatio;
|
|
257
|
-
singleColorStatus = mostCriticalContrastRatio !== null ? getAccessibilityStatus(mostCriticalContrastRatio) : null;
|
|
258
|
-
}
|
|
259
|
-
var accessibilityStatus = isSingleColorSelection ? singleColorStatus : multiColorStatus;
|
|
313
|
+
textColor = _useColorAccessibilit.textColor;
|
|
314
|
+
var _useEditorToolbar = useEditorToolbar(),
|
|
315
|
+
editorView = _useEditorToolbar.editorView;
|
|
316
|
+
var editorState = editorView === null || editorView === void 0 ? void 0 : editorView.state;
|
|
317
|
+
var accessibilityStatus = React.useMemo(function () {
|
|
318
|
+
return editorState && fg('platform_editor_lovability_text_bg_color_patch_1') ? getAccessibilityStatusForCurrentSelection(editorState, defaultColor, highlightColor, textColor) : getAccessibilityStatusFromColorPair(defaultColor, getResolvedBackgroundFromHighlight(highlightColor), textColor);
|
|
319
|
+
}, [defaultColor, editorState, highlightColor, textColor]);
|
|
260
320
|
if (accessibilityStatus === null) {
|
|
261
321
|
return /*#__PURE__*/React.createElement(React.Fragment, null);
|
|
262
322
|
}
|
|
@@ -5,14 +5,8 @@ import type { PaletteColor } from '@atlaskit/editor-common/ui-color';
|
|
|
5
5
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
export type TextColorPluginState = {
|
|
7
7
|
color: string | null;
|
|
8
|
-
colorInNonActiveTheme?: string;
|
|
9
8
|
defaultColor: string;
|
|
10
9
|
disabled?: boolean;
|
|
11
|
-
/**
|
|
12
|
-
* True when the current selection spans more than one text color. Only
|
|
13
|
-
* populated behind the lovability text/bg color patch gate + experiment.
|
|
14
|
-
*/
|
|
15
|
-
isMultiTextColor?: boolean;
|
|
16
10
|
isPaletteOpen?: boolean;
|
|
17
11
|
palette: Array<PaletteColor>;
|
|
18
12
|
};
|
|
@@ -3,9 +3,4 @@ import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/stat
|
|
|
3
3
|
* Use getDisabledStateNew instead and pass in `tr`
|
|
4
4
|
*/
|
|
5
5
|
export declare const getActiveColor: (state: EditorState) => string | null;
|
|
6
|
-
/**
|
|
7
|
-
* Returns true when the selection contains two or more distinct text colors,
|
|
8
|
-
* counting unmarked text as the default color.
|
|
9
|
-
*/
|
|
10
|
-
export declare const isMultiTextColorSelection: (state: EditorState) => boolean;
|
|
11
6
|
export declare const getActiveColorNew: (tr: Transaction) => string | null;
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
3
|
+
import type { Node, ResolvedPos } from '@atlaskit/editor-prosemirror/model';
|
|
4
|
+
import type { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
3
5
|
import type { TextColorPlugin } from '../textColorPluginType';
|
|
4
6
|
type ColorAccessibilityMenuItemProps = {
|
|
5
7
|
api: ExtractInjectionAPI<TextColorPlugin> | undefined;
|
|
6
8
|
};
|
|
9
|
+
type BackgroundColorSource = 'element' | 'text';
|
|
10
|
+
export type ResolvedBackgroundColor = {
|
|
11
|
+
color: string | null;
|
|
12
|
+
source: BackgroundColorSource;
|
|
13
|
+
};
|
|
14
|
+
type ColorAccessibilityEditorState = Pick<EditorState, 'doc' | 'selection'>;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the visible background behind a text node.
|
|
17
|
+
* Text highlight wins before falling back to the nearest element background.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getResolvedBackgroundColorForTextNode: ($pos: ResolvedPos, node: Node) => ResolvedBackgroundColor;
|
|
20
|
+
type AccessibilityStatusKey = 'accessible' | 'difficultToRead' | 'inaccessible';
|
|
21
|
+
export declare const getAccessibilityStatusForCurrentSelection: (state: ColorAccessibilityEditorState, defaultColor: string | undefined, highlightColor: string | null | undefined, textColor: string | null | undefined) => AccessibilityStatusKey | null;
|
|
7
22
|
export declare const ColorAccessibilityMenuItem: ({ api, }: ColorAccessibilityMenuItemProps) => React.JSX.Element;
|
|
8
23
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-text-color",
|
|
3
|
-
"version": "12.3.
|
|
3
|
+
"version": "12.3.32",
|
|
4
4
|
"description": "Text color plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -38,16 +38,16 @@
|
|
|
38
38
|
"@atlaskit/heading": "^6.2.0",
|
|
39
39
|
"@atlaskit/icon": "^37.1.0",
|
|
40
40
|
"@atlaskit/icon-lab": "^7.4.0",
|
|
41
|
-
"@atlaskit/platform-feature-flags": "^2.
|
|
41
|
+
"@atlaskit/platform-feature-flags": "^2.1.0",
|
|
42
42
|
"@atlaskit/platform-feature-flags-react": "^1.1.0",
|
|
43
|
-
"@atlaskit/primitives": "^22.
|
|
44
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
45
|
-
"@atlaskit/tokens": "^16.
|
|
43
|
+
"@atlaskit/primitives": "^22.1.0",
|
|
44
|
+
"@atlaskit/tmp-editor-statsig": "^131.0.0",
|
|
45
|
+
"@atlaskit/tokens": "^16.2.0",
|
|
46
46
|
"@babel/runtime": "^7.0.0",
|
|
47
47
|
"@emotion/react": "^11.7.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@atlaskit/editor-common": "^116.
|
|
50
|
+
"@atlaskit/editor-common": "^116.35.0",
|
|
51
51
|
"react": "^18.2.0",
|
|
52
52
|
"react-dom": "^18.2.0",
|
|
53
53
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|