fix(table): минус красный и в нередактируемых ячейках строки ввода (AURORA-1892)
Возврат тестирования 06.11, критерий «любое отрицательное число выделено цветом»: NOT_EDITABLE_INPUT_STYLES (AURORA-1890) разворачивался после цвета текста и перекрашивал минус в серый #5F6B7A — в расчётных колонках вне перечня отрицательные значения оставались серыми. Цвет текста теперь решает resolveCellTextColor (utils/cellTextColor.js, с тестами): минус — красный всегда, серый — только для неотрицательных значений. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5690b756e9
commit
20f1bed336
@ -1,6 +1,7 @@
|
|||||||
import { Tooltip } from '@mui/material';
|
import { Tooltip } from '@mui/material';
|
||||||
import React, { useMemo, useCallback, useState } from 'react';
|
import React, { useMemo, useCallback, useState } from 'react';
|
||||||
import { useCellLock } from '../../contexts/RealtimeContext';
|
import { useCellLock } from '../../contexts/RealtimeContext';
|
||||||
|
import { resolveCellTextColor } from '../../utils/cellTextColor';
|
||||||
import { formatNumber } from '../../utils/numberFormat';
|
import { formatNumber } from '../../utils/numberFormat';
|
||||||
import { TEXT_COLUMN_IDS } from '../../utils/moneyUtils';
|
import { TEXT_COLUMN_IDS } from '../../utils/moneyUtils';
|
||||||
|
|
||||||
@ -33,11 +34,6 @@ const INVALID_STYLES = {
|
|||||||
color: '#C60C0C',
|
color: '#C60C0C',
|
||||||
};
|
};
|
||||||
|
|
||||||
// AURORA-1892: отрицательные суммы должны быть явно отличимы от нуля и обычных чисел,
|
|
||||||
// в том числе на тёмных фонах палитры (например ROOT красной палитры #933634).
|
|
||||||
const NEGATIVE_COLOR_ON_LIGHT = '#C62828';
|
|
||||||
const NEGATIVE_COLOR_ON_DARK = '#FFCDD2';
|
|
||||||
|
|
||||||
// AURORA-1890: редактируемая ячейка строки INPUT — белый фон и заметная
|
// AURORA-1890: редактируемая ячейка строки INPUT — белый фон и заметная
|
||||||
// синяя рамка (вместо прежней почти незаметной полупрозрачной 2px #d8e4ea94).
|
// синяя рамка (вместо прежней почти незаметной полупрозрачной 2px #d8e4ea94).
|
||||||
// Толщина рамки растёт при наведении (1px → 2px, см. isHovered в CellComponent), курсор — text.
|
// Толщина рамки растёт при наведении (1px → 2px, см. isHovered в CellComponent), курсор — text.
|
||||||
@ -50,10 +46,11 @@ const EDITABLE_BORDER_COLOR = '#7FA7C9';
|
|||||||
// AURORA-1890: нередактируемая ячейка строки INPUT (вычисляемая или вне
|
// AURORA-1890: нередактируемая ячейка строки INPUT (вычисляемая или вне
|
||||||
// текущего этапа) — приглушённый фон и текст, чтобы визуально отличаться от
|
// текущего этапа) — приглушённый фон и текст, чтобы визуально отличаться от
|
||||||
// редактируемой белой ячейки без отдельной палитры цветов.
|
// редактируемой белой ячейки без отдельной палитры цветов.
|
||||||
|
// Цвет текста (в т.ч. приглушённый серый) задаёт resolveCellTextColor: здесь его нет,
|
||||||
|
// чтобы стиль не перекрывал красный цвет отрицательных значений (AURORA-1892).
|
||||||
const NOT_EDITABLE_INPUT_STYLES = {
|
const NOT_EDITABLE_INPUT_STYLES = {
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
backgroundColor: '#F4F5F7',
|
backgroundColor: '#F4F5F7',
|
||||||
color: '#5F6B7A',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Строки ITEM/GROUP/ROOT: вне скоупа AURORA-1890 — сохраняем прежнее поведение.
|
// Строки ITEM/GROUP/ROOT: вне скоупа AURORA-1890 — сохраняем прежнее поведение.
|
||||||
@ -104,26 +101,6 @@ const OVER_LIMIT_CHIP_STYLES = {
|
|||||||
|
|
||||||
const NAME_COLUMN_IDS = new Set(['data.header.name', 'data.name']);
|
const NAME_COLUMN_IDS = new Set(['data.header.name', 'data.name']);
|
||||||
|
|
||||||
const getColorBrightness = (hexColor) => {
|
|
||||||
if (!hexColor) return 255;
|
|
||||||
const color = hexColor.replace('#', '');
|
|
||||||
let r;
|
|
||||||
let g;
|
|
||||||
let b;
|
|
||||||
if (color.length === 3) {
|
|
||||||
r = Number.parseInt(color[0] + color[0], 16);
|
|
||||||
g = Number.parseInt(color[1] + color[1], 16);
|
|
||||||
b = Number.parseInt(color[2] + color[2], 16);
|
|
||||||
} else if (color.length === 6) {
|
|
||||||
r = Number.parseInt(color.substring(0, 2), 16);
|
|
||||||
g = Number.parseInt(color.substring(2, 4), 16);
|
|
||||||
b = Number.parseInt(color.substring(4, 6), 16);
|
|
||||||
} else {
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
return 0.299 * r + 0.587 * g + 0.114 * b;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Оптимизированная функция подсветки
|
// Оптимизированная функция подсветки
|
||||||
const createHighlightedContent = (originalValue, displayValue, searchQueries) => {
|
const createHighlightedContent = (originalValue, displayValue, searchQueries) => {
|
||||||
const cleanQueries = searchQueries.filter(Boolean);
|
const cleanQueries = searchQueries.filter(Boolean);
|
||||||
@ -213,11 +190,11 @@ const CellComponent = ({
|
|||||||
|
|
||||||
// AURORA-1890: занятая коллегой ячейка больше не красится в серый —
|
// AURORA-1890: занятая коллегой ячейка больше не красится в серый —
|
||||||
// обычный brightness-based цвет текста, отличие только в рамке/бейдже.
|
// обычный brightness-based цвет текста, отличие только в рамке/бейдже.
|
||||||
const textColor = useMemo(() => {
|
const isMutedInput = isInputRow && !isEditable;
|
||||||
const brightness = getColorBrightness(backgroundColor);
|
const textColor = useMemo(
|
||||||
if (isNegative) return brightness < 128 ? NEGATIVE_COLOR_ON_DARK : NEGATIVE_COLOR_ON_LIGHT;
|
() => resolveCellTextColor({ backgroundColor, isNegative, isMutedInput }),
|
||||||
return brightness < 128 ? '#ffffff' : '#000000';
|
[backgroundColor, isNegative, isMutedInput],
|
||||||
}, [backgroundColor, isNegative]);
|
);
|
||||||
|
|
||||||
// AURORA-1890: нередактируемый стиль зависит от типа строки (INPUT получает
|
// AURORA-1890: нередактируемый стиль зависит от типа строки (INPUT получает
|
||||||
// приглушённую заливку, ITEM/GROUP/ROOT — прежнее поведение без изменений).
|
// приглушённую заливку, ITEM/GROUP/ROOT — прежнее поведение без изменений).
|
||||||
|
|||||||
40
web/src/components/RealtimeTable/utils/cellTextColor.js
Normal file
40
web/src/components/RealtimeTable/utils/cellTextColor.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Цвет текста ячейки таблицы (вынесено из Cell.jsx, чтобы покрыть тестами без DOM).
|
||||||
|
|
||||||
|
// AURORA-1892: отрицательные суммы должны быть явно отличимы от нуля и обычных чисел,
|
||||||
|
// в том числе на тёмных фонах палитры (например ROOT красной палитры #933634).
|
||||||
|
export const NEGATIVE_COLOR_ON_LIGHT = '#C62828';
|
||||||
|
export const NEGATIVE_COLOR_ON_DARK = '#FFCDD2';
|
||||||
|
|
||||||
|
// AURORA-1890: приглушённый текст нередактируемой ячейки строки ввода (фон #F4F5F7).
|
||||||
|
export const MUTED_INPUT_TEXT_COLOR = '#5F6B7A';
|
||||||
|
|
||||||
|
export const getColorBrightness = (hexColor) => {
|
||||||
|
if (!hexColor) return 255;
|
||||||
|
const color = hexColor.replace('#', '');
|
||||||
|
let r;
|
||||||
|
let g;
|
||||||
|
let b;
|
||||||
|
if (color.length === 3) {
|
||||||
|
r = Number.parseInt(color[0] + color[0], 16);
|
||||||
|
g = Number.parseInt(color[1] + color[1], 16);
|
||||||
|
b = Number.parseInt(color[2] + color[2], 16);
|
||||||
|
} else if (color.length === 6) {
|
||||||
|
r = Number.parseInt(color.substring(0, 2), 16);
|
||||||
|
g = Number.parseInt(color.substring(2, 4), 16);
|
||||||
|
b = Number.parseInt(color.substring(4, 6), 16);
|
||||||
|
} else {
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
return 0.299 * r + 0.587 * g + 0.114 * b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// AURORA-1892 (возврат 06.11): минус красный в любой ячейке. Раньше серый цвет
|
||||||
|
// нередактируемой ячейки строки ввода (AURORA-1890) перекрывал красный, и в расчётных
|
||||||
|
// колонках отрицательные значения оставались серыми. Фон такой ячейки всегда светлый
|
||||||
|
// (#F4F5F7), поэтому для неё — красный для светлого фона.
|
||||||
|
export const resolveCellTextColor = ({ backgroundColor, isNegative, isMutedInput }) => {
|
||||||
|
if (isMutedInput) return isNegative ? NEGATIVE_COLOR_ON_LIGHT : MUTED_INPUT_TEXT_COLOR;
|
||||||
|
const isDark = getColorBrightness(backgroundColor) < 128;
|
||||||
|
if (isNegative) return isDark ? NEGATIVE_COLOR_ON_DARK : NEGATIVE_COLOR_ON_LIGHT;
|
||||||
|
return isDark ? '#ffffff' : '#000000';
|
||||||
|
};
|
||||||
29
web/src/components/RealtimeTable/utils/cellTextColor.test.js
Normal file
29
web/src/components/RealtimeTable/utils/cellTextColor.test.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import {
|
||||||
|
MUTED_INPUT_TEXT_COLOR,
|
||||||
|
NEGATIVE_COLOR_ON_DARK,
|
||||||
|
NEGATIVE_COLOR_ON_LIGHT,
|
||||||
|
resolveCellTextColor,
|
||||||
|
} from './cellTextColor.js';
|
||||||
|
|
||||||
|
// AURORA-1892 (возврат 06.11): в расчётных (нередактируемых) ячейках строки ввода
|
||||||
|
// минус оставался серым — серый цвет AURORA-1890 перекрывал красный.
|
||||||
|
test('a negative value in a non-editable input cell is red, not muted grey', () => {
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#FFFFFF', isNegative: true, isMutedInput: true }), NEGATIVE_COLOR_ON_LIGHT);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a non-negative value in a non-editable input cell keeps the muted grey', () => {
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#FFFFFF', isNegative: false, isMutedInput: true }), MUTED_INPUT_TEXT_COLOR);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('negative values follow background brightness outside muted input cells', () => {
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#FFFFFF', isNegative: true, isMutedInput: false }), NEGATIVE_COLOR_ON_LIGHT);
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#933634', isNegative: true, isMutedInput: false }), NEGATIVE_COLOR_ON_DARK);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('regular values are black on light and white on dark backgrounds', () => {
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#FFFFFF', isNegative: false, isMutedInput: false }), '#000000');
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: '#933634', isNegative: false, isMutedInput: false }), '#ffffff');
|
||||||
|
assert.equal(resolveCellTextColor({ backgroundColor: undefined, isNegative: false, isMutedInput: false }), '#000000');
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user