From 9d982c06dc3557cc2bdf15a33e80374c6d58ef8c Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 27 Nov 2025 12:48:20 +0300 Subject: [PATCH 1/9] add ff & components --- .../EnableDashColorPickersByTheme.ts | 10 ++ src/shared/types/feature.ts | 2 + .../ColorInputsGroup/ColorInputsGroup.scss | 18 +++ .../ColorInputsGroup/ColorInputsGroup.tsx | 80 ++++++++++++ .../ColorPickerInputWithPreset.scss | 122 ++++++++++++++++++ .../ColorPickerInputWithPreset.tsx | 92 +++++++++++++ 6 files changed, 324 insertions(+) create mode 100644 src/server/components/features/features-list/EnableDashColorPickersByTheme.ts create mode 100644 src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.scss create mode 100644 src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx create mode 100644 src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.scss create mode 100644 src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.tsx diff --git a/src/server/components/features/features-list/EnableDashColorPickersByTheme.ts b/src/server/components/features/features-list/EnableDashColorPickersByTheme.ts new file mode 100644 index 0000000000..18250ec468 --- /dev/null +++ b/src/server/components/features/features-list/EnableDashColorPickersByTheme.ts @@ -0,0 +1,10 @@ +import {Feature} from '../../../../shared'; +import {createFeatureConfig} from '../utils'; + +export default createFeatureConfig({ + name: Feature.EnableDashColorPickersByTheme, + state: { + development: true, + production: false, + }, +}); diff --git a/src/shared/types/feature.ts b/src/shared/types/feature.ts index c5ad8f987e..1ac3abad8b 100644 --- a/src/shared/types/feature.ts +++ b/src/shared/types/feature.ts @@ -99,6 +99,8 @@ export enum Feature { EnableGlobalSelectors = 'EnableGlobalSelectors', /** enables new dash & widgets settings */ EnableNewDashSettings = 'EnableNewDashSettings', + /** Enable color pickers with customization of values for light & dark themes separately */ + EnableDashColorPickersByTheme = 'EnableDashColorPickersByTheme', /** Shows updated settings page */ EnableNewServiceSettings = 'EnableNewServiceSettings', } diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.scss b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.scss new file mode 100644 index 0000000000..7124553d5b --- /dev/null +++ b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.scss @@ -0,0 +1,18 @@ +.color-inputs-group { + display: flex; + gap: var(--g-spacing-4); + + &__item { + display: flex; + align-items: center; + gap: var(--g-spacing-2); + } + + &__theme-icon { + color: var(--g-color-text-hint); + } + + &__color-input { + flex: 0 1 200px; + } +} diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx new file mode 100644 index 0000000000..8b6e45af23 --- /dev/null +++ b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx @@ -0,0 +1,80 @@ +import React from 'react'; + +import {Moon, Sun} from '@gravity-ui/icons'; +import type {FlexProps, RealTheme} from '@gravity-ui/uikit'; +import {Flex, Icon} from '@gravity-ui/uikit'; +import block from 'bem-cn-lite'; +import ColorPickerInputWithPreset from 'ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset'; + +import {type ColorByTheme} from '../../../../../../../shared'; +import {ColorPickerInput} from '../../../../../../components/ColorPickerInput/ColorPickerInput'; + +import './ColorInputsGroup.scss'; +const b = block('color-inputs-group'); + +export interface ColorInputsGroupProps { + theme?: RealTheme; + value: ColorByTheme | undefined; + onUpdate: (value: ColorByTheme) => void; + isSingleColorSelector?: boolean; + direction?: FlexProps['direction']; + className?: string; + mainPresetOptions?: string[]; + paletteOptions?: string[]; +} + +export function ColorInputsGroup({ + theme, + value, + onUpdate, + className, + isSingleColorSelector = false, + direction = 'row', + mainPresetOptions, + paletteOptions, +}: ColorInputsGroupProps) { + return ( + + {isSingleColorSelector ? ( + onUpdate({common: color ?? undefined})} + hasOpacityInput + /> + ) : ( + +
+ + + onUpdate({light: color ?? undefined, dark: value?.dark}) + } + hasOpacityInput + /> +
+
+ + + onUpdate({dark: color ?? undefined, light: value?.light}) + } + hasOpacityInput + /> +
+
+ )} +
+ ); +} diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.scss b/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.scss new file mode 100644 index 0000000000..dcfc0b9326 --- /dev/null +++ b/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.scss @@ -0,0 +1,122 @@ +@import '~@gravity-ui/uikit/styles/mixins'; + +.color-picker-input-with-preset { + $class: &; + display: inline-block; + position: relative; + width: 100%; + + $color-item-size: 28px; + + &__palette-list { + display: flex; + flex-direction: column; + padding: var(--g-spacing-4); + } + + &__preset { + margin-block-end: var(--g-spacing-2); + } + + &__palette { + margin-block-start: var(--g-spacing-5); + } + + &__color-picker { + display: block; + width: 140px; + min-width: 100%; + } + + &__custom-palette-bg-btn, + &__highlight-wrapper { + width: $color-item-size; + height: $color-item-size; + flex-grow: 0; + flex-shrink: 0; + } + + &__custom-palette-bg-btn, + &__palette-list-btn { + // disable inheritance from theme + --g-button-border-radius: 6px; + } + + &__palette-list-btn, + &__custom-palette-bg-btn { + // disable selected additional background on button + --g-button-background-color: transparent; + --g-button-background-color-hover: transparent; + } + + &__highlight-wrapper { + --_--color-item-border-color: transparent; + position: relative; + border-radius: 6px; + + &_with-border { + --_--color-item-border-color: var(--g-color-line-generic); + } + + &::before { + content: ''; + position: absolute; + inset: 0; + border: 1px solid var(--_--color-item-border-color); + border-radius: 6px; + } + + &_selected, + &:hover { + --_--color-item-border-color: transparent; + } + + &:not(&_selected):hover::before { + content: ''; + position: absolute; + inset: -3px; + border: 2px solid var(--g-color-line-generic-hover); + border-radius: 9px; + } + + &_selected::before { + content: ''; + position: absolute; + inset: -3px; + border: 2px solid var(--g-color-line-brand); + border-radius: 9px; + } + } + + &__color-item { + display: inline-block; + width: $color-item-size; + height: $color-item-size; + background-clip: padding-box; + + &_transparent { + background-image: repeating-conic-gradient( + var(--g-color-base-generic) 0 25%, + var(--g-color-base-background) 0 50% + ); + border: 1px solid transparent; + } + + &_widget-bg { + background-color: var(--g-color-base-float); + } + } + + &__theme { + background-clip: padding-box; + background-color: var(--g-color-base-float); + width: $color-item-size; + height: $color-item-size; + overflow: hidden; + } + + &__theme, + &__color-item { + border-radius: 6px; + } +} diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.tsx b/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.tsx new file mode 100644 index 0000000000..60dfc82ab8 --- /dev/null +++ b/src/ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset.tsx @@ -0,0 +1,92 @@ +import React from 'react'; + +import {Popup} from '@gravity-ui/uikit'; +import block from 'bem-cn-lite'; + +import { + ColorPickerInput, + type ColorPickerInputProps, +} from '../../../../../../components/ColorPickerInput/ColorPickerInput'; +import {ColorPalette} from '../ColorPalette/ColorPalette'; + +import './ColorPickerInputWithPreset.scss'; + +const b = block('color-picker-input-with-preset'); + +export interface ColorPickerInputWithPresetProps extends ColorPickerInputProps { + mainPresetOptions?: string[]; + paletteOptions?: string[]; +} + +export function ColorPickerInputWithPreset({ + mainPresetOptions, + paletteOptions, + value, + onUpdate, + theme, + ...colorPickerInputProps +}: ColorPickerInputWithPresetProps) { + const [isPopupOpen, setIsPopupOpen] = React.useState(false); + const inputRef = React.useRef(null); + + const handleSelectColor = React.useCallback( + (color: string) => { + onUpdate(color || null); + setIsPopupOpen(false); + }, + [onUpdate], + ); + + const handleFocus = React.useCallback(() => { + setIsPopupOpen(true); + }, []); + + const handleClosePopup = React.useCallback((open: boolean) => { + if (!open) { + setIsPopupOpen(false); + } + }, []); + + if (!mainPresetOptions?.length && !paletteOptions?.length) { + return ( + + ); + } + + return ( + + + + + + + ); +} + +export default ColorPickerInputWithPreset; From d79806ec47fe14d6707c51aae44d602f134b6306 Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 27 Nov 2025 12:53:18 +0300 Subject: [PATCH 2/9] types & plugins settings --- src/shared/types/dash.ts | 56 ++++++++++++++----- src/ui/components/DashKit/DashKit.ts | 24 +++++--- .../DashKit/plugins/Image/Image.tsx | 17 ++++-- .../components/DashKit/plugins/Text/Text.tsx | 15 +++-- .../DashKit/plugins/Title/Title.tsx | 21 ++++--- .../DashKit/plugins/Widget/WidgetPlugin.tsx | 18 +++--- .../DashKit/plugins/Widget/types.ts | 14 +++-- 7 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/shared/types/dash.ts b/src/shared/types/dash.ts index 55ebcd88dd..0280a8fbb9 100644 --- a/src/shared/types/dash.ts +++ b/src/shared/types/dash.ts @@ -1,4 +1,5 @@ import type {ItemDropProps} from '@gravity-ui/dashkit'; +import type {ThemeType} from '@gravity-ui/uikit'; import type {Operations} from '../modules'; @@ -92,7 +93,7 @@ export type DashSettings = { loadOnlyVisibleCharts?: boolean; margins?: [number, number]; enableAssistant?: boolean; - background?: BackgroundSettings; + backgroundSettings?: BackgroundSettings; }; export interface DashData { @@ -113,9 +114,12 @@ export type DashDragOptions = ItemDropProps; // schemeVersion comes from server export type FakeDashData = Omit & { settings: Required< - Omit + Omit< + DashSettings, + 'margins' | 'enableAssistant' | 'signedGlobalParams' | 'backgroundSettings' + > > & - Pick; + Pick; }; export interface DashTabSettings { @@ -143,14 +147,17 @@ export type DashTabItem = | DashTabItemGroupControl | DashTabItemImage; -export type ColorSettings = string; +export type ColorByTheme = Partial>; -export type BackgroundSettings = { +export type OldBackgroundSettings = { enabled?: boolean; - color: ColorSettings; + color: string; }; -export function isBackgroundSettings(value: unknown): value is BackgroundSettings { +export type ColorSettings = ColorByTheme | string; +export type BackgroundSettings = {color?: ColorSettings}; + +export function isOldBackgroundSettings(value: unknown): value is OldBackgroundSettings { return ( typeof value === 'object' && value !== null && @@ -162,6 +169,17 @@ export function isBackgroundSettings(value: unknown): value is BackgroundSetting ); } +export function isColorByTheme(value: unknown): value is ColorByTheme { + return ( + typeof value === 'object' && + value !== null && + Object.entries(value).every( + ([key, val]) => + ['light', 'dark'].includes(key) && ['string', 'undefined'].includes(typeof val), + ) + ); +} + export interface DashTabItemBase { id: string; namespace: string; @@ -171,12 +189,16 @@ export interface DashTabItemBase { title?: string; } +export interface DahsTabItemBaseData { + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; +} + export interface DashTabItemText extends DashTabItemBase { type: DashTabItemType.Text; - data: { + data: DahsTabItemBaseData & { text: string; autoHeight?: boolean; - background?: BackgroundSettings; }; } @@ -189,20 +211,23 @@ export type DashTitleSize = export interface DashTabItemTitle extends DashTabItemBase { type: DashTabItemType.Title; - data: { + data: DahsTabItemBaseData & { text: string; size: DashTitleSize; showInTOC: boolean; autoHeight?: boolean; - background?: BackgroundSettings; - textColor?: ColorSettings; + textColor?: string; + textColorSettings?: ColorSettings; hint?: HintSettings; }; } export interface DashTabItemWidget extends DashTabItemBase { type: DashTabItemType.Widget; - data: {hideTitle: boolean; tabs: DashTabItemWidgetTab[]; background?: BackgroundSettings}; + data: DahsTabItemBaseData & { + hideTitle: boolean; + tabs: DashTabItemWidgetTab[]; + }; } export interface DashTabItemWidgetTab { @@ -217,7 +242,7 @@ export interface DashTabItemWidgetTab { params: StringParams; autoHeight?: boolean; enableActionParams?: boolean; - background?: BackgroundSettings; + background?: OldBackgroundSettings; } export interface DashTabItemControl extends DashTabItemBase { @@ -402,7 +427,8 @@ export interface DashTabItemImage extends DashTabItemBase { data: { src: string; alt?: string; - background?: BackgroundSettings; + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; preserveAspectRatio?: boolean; }; } diff --git a/src/ui/components/DashKit/DashKit.ts b/src/ui/components/DashKit/DashKit.ts index 905f6048f4..353fcd9d8a 100644 --- a/src/ui/components/DashKit/DashKit.ts +++ b/src/ui/components/DashKit/DashKit.ts @@ -1,6 +1,6 @@ import type {Plugin, PluginDefaultLayout} from '@gravity-ui/dashkit'; import {DashKit} from '@gravity-ui/dashkit'; -import type {BackgroundSettings} from 'shared'; +import type {BackgroundSettings, OldBackgroundSettings} from 'shared'; import {registry} from 'ui/registry'; import {DL} from '../../constants'; @@ -37,10 +37,13 @@ const wrapPlugins = (plugins: Plugin[], pluginDefaultsGetter?: typeof currentDef export interface CommonPluginSettings { scope?: string; + globalBackground?: OldBackgroundSettings; + globalBackgroundSettings?: BackgroundSettings; } export interface CommonPluginProps { - background?: BackgroundSettings; + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; } export const getConfiguredDashKit = ( @@ -49,22 +52,29 @@ export const getConfiguredDashKit = ( disableHashNavigation?: boolean; disableTitleHints?: boolean; scope?: string; + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; }, ) => { if (currentDefaultsGetter !== pluginDefaultsGetter || !isConfigured) { - const titleSettings = { + const commonSettings: CommonPluginSettings = { scope: options?.scope, + globalBackground: options?.background, + globalBackgroundSettings: options?.backgroundSettings, + }; + const titleSettings = { + ...commonSettings, hideAnchor: options?.disableHashNavigation, hideHint: options?.disableTitleHints, }; const textSettings = { - scope: options?.scope, + ...commonSettings, apiHandler: MarkdownProvider.getMarkdown, }; const controlSettings = { - scope: options?.scope, + ...commonSettings, getDistincts: getDistinctsAction(), }; @@ -74,8 +84,8 @@ export const getConfiguredDashKit = ( textPlugin.setSettings(textSettings), pluginControl.setSettings(controlSettings), pluginGroupControl.setSettings(controlSettings), - widgetPlugin.setSettings({scope: options?.scope}), - pluginImage.setSettings({scope: options?.scope}), + widgetPlugin.setSettings(commonSettings), + pluginImage.setSettings(commonSettings), ], pluginDefaultsGetter, ); diff --git a/src/ui/components/DashKit/plugins/Image/Image.tsx b/src/ui/components/DashKit/plugins/Image/Image.tsx index b183804605..5647e9af5c 100644 --- a/src/ui/components/DashKit/plugins/Image/Image.tsx +++ b/src/ui/components/DashKit/plugins/Image/Image.tsx @@ -22,14 +22,17 @@ type Props = PluginWidgetProps & type PluginImageObjectSettings = CommonPluginSettings; -type PluginImage = Plugin & { - setSettings: (settings: PluginImageObjectSettings) => PluginImage; -}; +type PluginImage = Plugin & + CommonPluginSettings & { + setSettings: (settings: PluginImageObjectSettings) => PluginImage; + }; export const pluginImage: PluginImage = { type: DashTabItemType.Image, defaultLayout: {w: 12, h: 12, minH: 1, minW: 1}, - setSettings: (_settings: PluginImageObjectSettings) => { + setSettings: (settings: PluginImageObjectSettings) => { + pluginImage.globalBackground = settings.globalBackground; + pluginImage.globalBackgroundSettings = settings.globalBackgroundSettings; return pluginImage; }, renderer: PluginImageRenderer, @@ -38,7 +41,7 @@ export const pluginImage: PluginImage = { function PluginImageRenderer(props: Props, _ref?: React.LegacyRef) { const { id, - data: {alt, background, src, preserveAspectRatio}, + data: {alt, background, backgroundSettings, src, preserveAspectRatio}, layout, } = props; @@ -58,7 +61,9 @@ function PluginImageRenderer(props: Props, _ref?: React.LegacyRef & { - setSettings: (settings: PluginTextObjectSettings) => PluginText; -}; +type PluginText = Plugin & + CommonPluginSettings & { + setSettings: (settings: PluginTextObjectSettings) => PluginText; + }; const textPlugin: PluginText = { ...pluginText, setSettings(settings: PluginTextObjectSettings) { - const {apiHandler} = settings; + const {apiHandler, globalBackground, globalBackgroundSettings} = settings; pluginText._apiHandler = apiHandler; + textPlugin.globalBackground = globalBackground; + textPlugin.globalBackgroundSettings = globalBackgroundSettings; return textPlugin; }, renderer: function Wrapper( @@ -193,7 +196,9 @@ const textPlugin: PluginText = { const {style, hasBgColor} = usePreparedWrapSettings({ widgetBackground: data.background, - globalBackground: props.background, + globalBackground: textPlugin.globalBackground, + widgetBackgroundSettings: data.backgroundSettings, + globalBackgroundSettings: textPlugin.globalBackgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, }); diff --git a/src/ui/components/DashKit/plugins/Title/Title.tsx b/src/ui/components/DashKit/plugins/Title/Title.tsx index ea70c22ba9..cead8bb825 100644 --- a/src/ui/components/DashKit/plugins/Title/Title.tsx +++ b/src/ui/components/DashKit/plugins/Title/Title.tsx @@ -42,11 +42,12 @@ type PluginTitleObjectSettings = CommonPluginSettings & { type Props = PluginTitleProps & PluginTitleObjectSettings & CommonPluginProps; -type PluginTitle = Plugin & { - setSettings: (settings: PluginTitleObjectSettings) => PluginTitle; - hideAnchor?: boolean; - hideHint?: boolean; -}; +type PluginTitle = Plugin & + CommonPluginSettings & { + setSettings: (settings: PluginTitleObjectSettings) => PluginTitle; + hideAnchor?: boolean; + hideHint?: boolean; + }; const WIDGET_RESIZE_DEBOUNCE_TIMEOUT = 100; @@ -57,10 +58,12 @@ const MIN_AVAILABLE_TOP_OFFSET = -5; const titlePlugin: PluginTitle = { ...pluginTitle, setSettings(settings: PluginTitleObjectSettings) { - const {hideAnchor, hideHint} = settings; + const {hideAnchor, hideHint, globalBackground, globalBackgroundSettings} = settings; titlePlugin.hideAnchor = hideAnchor; titlePlugin.hideHint = hideHint; + titlePlugin.globalBackground = globalBackground; + titlePlugin.globalBackgroundSettings = globalBackgroundSettings; return titlePlugin; }, renderer: function PluginTitleRenderer( @@ -132,11 +135,13 @@ const titlePlugin: PluginTitle = { const {style, hasBgColor} = usePreparedWrapSettings({ widgetBackground: data.background, - globalBackground: props.background, + widgetBackgroundSettings: data.backgroundSettings, + globalBackground: titlePlugin.globalBackground, + globalBackgroundSettings: titlePlugin.globalBackgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, }); - const textColorStyles = useTextColorStyles(data.textColor); + const textColorStyles = useTextColorStyles(data.textColor, data.textColorSettings); const wrapperStyles = {...style, ...textColorStyles}; const currentLayout = props.layout.find(({i}) => i === props.id) || { diff --git a/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx b/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx index dc7ea5fdba..346fd16c08 100644 --- a/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx +++ b/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type {Plugin} from '@gravity-ui/dashkit'; -import {CustomPaletteBgColors, isBackgroundSettings} from 'shared'; +import {CustomPaletteBgColors, isOldBackgroundSettings} from 'shared'; import type {ChartWidgetWithWrapRefProps} from 'ui/components/Widgets/Chart/types'; import MarkdownProvider from '../../../../modules/markdownProvider'; @@ -17,16 +17,18 @@ type Props = WidgetPluginProps & CommonPluginProps; type PluginWidgetObjectSettings = CommonPluginSettings; -type PluginWidget = Plugin & { - setSettings: (settings: PluginWidgetObjectSettings) => PluginWidget; - scope?: string; -}; +type PluginWidget = Plugin & + CommonPluginSettings & { + setSettings: (settings: PluginWidgetObjectSettings) => PluginWidget; + }; const widgetPlugin: PluginWidget = { type: 'widget', defaultLayout: {w: 12, h: 12}, setSettings: (settings: PluginWidgetObjectSettings) => { widgetPlugin.scope = settings.scope; + widgetPlugin.globalBackground = settings.globalBackground; + widgetPlugin.globalBackgroundSettings = settings.globalBackgroundSettings; return widgetPlugin; }, renderer: function Wrapper( @@ -46,8 +48,10 @@ const widgetPlugin: PluginWidget = { ? {color: CustomPaletteBgColors.LIKE_CHART} : props.data.tabs?.[0]?.background; const {style} = usePreparedWrapSettings({ - widgetBackground: isBackgroundSettings(propsBg) ? propsBg : undefined, - globalBackground: props.background, + widgetBackground: isOldBackgroundSettings(propsBg) ? propsBg : undefined, + globalBackground: widgetPlugin.globalBackground, + widgetBackgroundSettings: props.backgroundSettings, + globalBackgroundSettings: widgetPlugin.globalBackgroundSettings, defaultOldColor: widgetPlugin.scope === 'dash' ? CustomPaletteBgColors.LIKE_CHART diff --git a/src/ui/components/DashKit/plugins/Widget/types.ts b/src/ui/components/DashKit/plugins/Widget/types.ts index 48fc8b1481..eb908baa55 100644 --- a/src/ui/components/DashKit/plugins/Widget/types.ts +++ b/src/ui/components/DashKit/plugins/Widget/types.ts @@ -9,6 +9,7 @@ import type {ChartKit} from 'ui/libs/DatalensChartkit/ChartKit/ChartKit'; import type {ChartKitBaseOnLoadProps} from '../../../../libs/DatalensChartkit/components/ChartKitBase/ChartKitBase'; import type {ChartsData} from '../../../../libs/DatalensChartkit/modules/data-provider/charts'; import type {Widget} from '../../../../libs/DatalensChartkit/types'; +import type {CommonPluginProps} from '../../DashKit'; import type {AdjustWidgetLayoutProps} from '../../utils'; import type {DashkitMetaDataItemBase} from '../types'; @@ -34,12 +35,13 @@ export type CurrentTab = { export type WidgetPluginData = ConfigItem['data']; export type WidgetPluginDataWithTabs = ConfigItemWithTabs['data'] & {tabs: Array}; -export type WidgetPluginProps = Omit & { - forwardedRef: React.RefObject; - data: WidgetPluginDataWithTabs | WidgetPluginData; - getMarkdown?: (props: {text: string}) => Promise<{result: string; meta?: object}>; - debouncedAdjustWidgetLayout: DebouncedFunc<(props: AdjustWidgetLayoutProps) => void>; -}; +export type WidgetPluginProps = Omit & + CommonPluginProps & { + forwardedRef: React.RefObject; + data: WidgetPluginDataWithTabs | WidgetPluginData; + getMarkdown?: (props: {text: string}) => Promise<{result: string; meta?: object}>; + debouncedAdjustWidgetLayout: DebouncedFunc<(props: AdjustWidgetLayoutProps) => void>; + }; export type WidgetLoadedData = ChartKitBaseOnLoadProps & { data?: {loadedData?: DashkitMetaDataItemBase & ChartsData & Widget}; From fc44dba5e053dd753d0b9e80827ff4a5f7392b68 Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 27 Nov 2025 12:57:10 +0300 Subject: [PATCH 3/9] fix components --- .../ColorInputsGroup/ColorInputsGroup.tsx | 26 +++++----- .../PaletteBackground/PaletteBackground.tsx | 52 +++++++++++++++++-- .../components/PaletteText/PaletteText.tsx | 31 +++++++++-- 3 files changed, 86 insertions(+), 23 deletions(-) diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx index 8b6e45af23..79ebcdab3b 100644 --- a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx +++ b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx @@ -6,7 +6,7 @@ import {Flex, Icon} from '@gravity-ui/uikit'; import block from 'bem-cn-lite'; import ColorPickerInputWithPreset from 'ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset'; -import {type ColorByTheme} from '../../../../../../../shared'; +import {type ColorSettings, isColorByTheme} from '../../../../../../../shared'; import {ColorPickerInput} from '../../../../../../components/ColorPickerInput/ColorPickerInput'; import './ColorInputsGroup.scss'; @@ -14,8 +14,8 @@ const b = block('color-inputs-group'); export interface ColorInputsGroupProps { theme?: RealTheme; - value: ColorByTheme | undefined; - onUpdate: (value: ColorByTheme) => void; + value: ColorSettings | undefined; + onUpdate: (value: ColorSettings | undefined) => void; isSingleColorSelector?: boolean; direction?: FlexProps['direction']; className?: string; @@ -33,14 +33,18 @@ export function ColorInputsGroup({ mainPresetOptions, paletteOptions, }: ColorInputsGroupProps) { + const {light, dark, common} = isColorByTheme(value) + ? {...value, common: undefined} + : {common: value}; + return ( {isSingleColorSelector ? ( onUpdate({common: color ?? undefined})} + value={common} + onUpdate={(color) => onUpdate(color ?? undefined)} hasOpacityInput /> ) : ( @@ -51,11 +55,9 @@ export function ColorInputsGroup({ mainPresetOptions={mainPresetOptions} paletteOptions={paletteOptions} className={b('color-input')} - value={value?.light} + value={light} theme="light" - onUpdate={(color) => - onUpdate({light: color ?? undefined, dark: value?.dark}) - } + onUpdate={(color) => onUpdate({light: color ?? undefined, dark})} hasOpacityInput /> @@ -65,11 +67,9 @@ export function ColorInputsGroup({ mainPresetOptions={mainPresetOptions} paletteOptions={paletteOptions} className={b('color-input')} - value={value?.dark} + value={dark} theme="dark" - onUpdate={(color) => - onUpdate({dark: color ?? undefined, light: value?.light}) - } + onUpdate={(color) => onUpdate({dark: color ?? undefined, light})} hasOpacityInput /> diff --git a/src/ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground.tsx b/src/ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground.tsx index 005d2754f4..bd4fa43364 100644 --- a/src/ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground.tsx +++ b/src/ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground.tsx @@ -1,27 +1,55 @@ import React from 'react'; -import {type RealTheme} from '@gravity-ui/uikit'; +import type {FlexProps, RealTheme} from '@gravity-ui/uikit'; +import type {ColorSettings} from 'shared'; +import {Feature} from 'shared'; import { BASE_GREY_BACKGROUND_COLOR, CustomPaletteBgColors, WIDGET_BG_COLORS_PRESET, WIDGET_BG_HEAVY_COLORS_PRESET, } from 'shared/constants/widgets'; +import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; +import {computeColorFromToken} from 'ui/utils/widgetColors'; +import {ColorInputsGroup} from '../ColorInputsGroup/ColorInputsGroup'; import {ColorPicker} from '../ColorPicker/ColorPicker'; type PaletteBackgroundProps = { - color?: string; - onSelect: (color: string) => void; + color: ColorSettings | undefined; + oldColor: string | undefined; + onSelect: (color: ColorSettings | undefined) => void; + onSelectOldColor: (color: string) => void; enableCustomBgColorSelector?: boolean; theme?: RealTheme; + enableSeparateThemeColorSelector?: boolean; + direction?: FlexProps['direction']; }; +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + +const MAIN_PRESET_OPTIONS = [ + 'var(--g-color-base-background)', + CustomPaletteBgColors.NONE, + 'var(--g-color-private-cool-grey-20-solid)', +]; + +const PALETTE_OPTIONS = [ + 'var(--g-color-private-blue-50)', + 'var(--g-color-private-green-50)', + 'var(--g-color-private-yellow-50)', + 'var(--g-color-private-red-50)', + 'var(--g-color-private-purple-50)', +]; export const PaletteBackground = ({ onSelect, + onSelectOldColor, color, + oldColor, enableCustomBgColorSelector, theme, + enableSeparateThemeColorSelector = true, + direction = 'row', }: PaletteBackgroundProps) => { const mainPresetOptions = [ CustomPaletteBgColors.NONE, @@ -37,10 +65,24 @@ export const PaletteBackground = ({ [enableCustomBgColorSelector], ); + if (isDashColorPickersByThemeEnabled || color) { + return ( + + ); + } + return ( void; + color: ColorSettings | undefined; + oldColor: string | undefined; + onSelect: (color: ColorSettings | undefined) => void; + onSelectOldColor: (color: string) => void; theme?: RealTheme; enableCustomColorSelector?: boolean; + enableSeparateThemeColorSelector?: boolean; }; const mainPresetOptions = [ CustomPaletteTextColors.PRIMARY, @@ -18,17 +25,31 @@ const mainPresetOptions = [ CustomPaletteTextColors.HINT, CustomPaletteTextColors.INVERTED_PRIMARY, ]; - +const isCommonDashSettingsEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); export const PaletteText = ({ onSelect, + onSelectOldColor, color, + oldColor, theme, enableCustomColorSelector, + enableSeparateThemeColorSelector = true, }: PaletteTextProps) => { + if (isCommonDashSettingsEnabled || color) { + return ( + + ); + } + return ( Date: Thu, 27 Nov 2025 15:22:38 +0300 Subject: [PATCH 4/9] selector in widgets settings --- src/ui/components/DashKit/utils.ts | 84 ++++++++--- .../DialogChartWidget/DialogChartWidget.scss | 1 - .../DialogChartWidget/DialogChartWidget.tsx | 61 ++++---- .../DialogImageWidget/DialogImageWidget.tsx | 37 ++++- .../DialogTextWidget/DialogTextWidget.tsx | 47 ++++-- src/ui/components/DialogTextWidget/index.tsx | 2 +- .../DialogTitleWidget/DialogTitleWidget.tsx | 102 ++++++++----- .../DialogTitleWidget/useColorSettings.ts | 142 ++++++++++++++++++ 8 files changed, 366 insertions(+), 110 deletions(-) create mode 100644 src/ui/components/DialogTitleWidget/useColorSettings.ts diff --git a/src/ui/components/DashKit/utils.ts b/src/ui/components/DashKit/utils.ts index c738691e25..6092fdc0fc 100644 --- a/src/ui/components/DashKit/utils.ts +++ b/src/ui/components/DashKit/utils.ts @@ -2,7 +2,14 @@ import React from 'react'; import type {CSSProperties} from 'react'; import type {PluginWidgetProps} from '@gravity-ui/dashkit'; -import type {BackgroundSettings, DashTabItemControlElement} from 'shared'; +import type {ThemeType} from '@gravity-ui/uikit'; +import {useThemeType} from '@gravity-ui/uikit'; +import type { + BackgroundSettings, + ColorSettings, + DashTabItemControlElement, + OldBackgroundSettings, +} from 'shared'; import {CustomPaletteBgColors, LIKE_CHART_COLOR_TOKEN} from 'shared/constants/widgets'; import {getResultedOldBgColor} from 'shared/modules/dash-scheme-converter'; @@ -271,7 +278,7 @@ export function getControlHint(source: DashTabItemControlElement) { return source.showHint ? source.hint : undefined; } -export function getPreparedWrapSettings( +function getPreparedWrapSettings( backgroundColor: string | undefined, additionalStyle?: CSSProperties, ) { @@ -295,34 +302,69 @@ export function getPreparedWrapSettings( }; } -export function useTextColorStyles(textColor?: string) { - // const theme = useThemeType(); // it would be used in next PR - return React.useMemo( - () => ({ - color: textColor, - }), - [textColor /* , theme */], - ); +export function useTextColorStyles(oldTextColor?: string, textColorSettings?: ColorSettings) { + const theme = useThemeType(); + return React.useMemo(() => { + const resultedNewTextColor = + typeof textColorSettings === 'string' ? textColorSettings : textColorSettings?.[theme]; + + return { + color: typeof oldTextColor === 'string' ? oldTextColor : resultedNewTextColor, + }; + }, [oldTextColor, textColorSettings, theme]); } export function usePreparedWrapSettings({ widgetBackground, globalBackground, + widgetBackgroundSettings, + globalBackgroundSettings, additionalStyle, defaultOldColor, }: { - widgetBackground: BackgroundSettings | undefined; - globalBackground: BackgroundSettings | undefined; + widgetBackground: OldBackgroundSettings | undefined; + globalBackground: OldBackgroundSettings | undefined; + widgetBackgroundSettings: BackgroundSettings | undefined; + globalBackgroundSettings: BackgroundSettings | undefined; additionalStyle?: CSSProperties; defaultOldColor: string; }) { - return React.useMemo( - () => - getPreparedWrapSettings( - getResultedOldBgColor(widgetBackground, defaultOldColor) ?? - getResultedOldBgColor(globalBackground, defaultOldColor), - additionalStyle, - ), - [widgetBackground, globalBackground, additionalStyle, defaultOldColor], - ); + const theme = useThemeType(); + return React.useMemo(() => { + return getPreparedWrapSettings( + getResultedBgColor( + widgetBackground, + theme, + defaultOldColor, + widgetBackgroundSettings, + ) ?? + getResultedBgColor( + globalBackground, + theme, + defaultOldColor, + globalBackgroundSettings, + ), + additionalStyle, + ); + }, [ + widgetBackground, + globalBackground, + widgetBackgroundSettings, + globalBackgroundSettings, + additionalStyle, + defaultOldColor, + theme, + ]); +} + +export function getResultedBgColor( + oldBgColor: OldBackgroundSettings | undefined, + theme: ThemeType, + defaultColor: string, + newBgColor: BackgroundSettings | undefined, +): string | undefined { + if (newBgColor?.color) { + return typeof newBgColor.color === 'string' ? newBgColor.color : newBgColor.color?.[theme]; + } + return getResultedOldBgColor(oldBgColor, defaultColor); } diff --git a/src/ui/components/DialogChartWidget/DialogChartWidget.scss b/src/ui/components/DialogChartWidget/DialogChartWidget.scss index 301410b482..c765b8c748 100644 --- a/src/ui/components/DialogChartWidget/DialogChartWidget.scss +++ b/src/ui/components/DialogChartWidget/DialogChartWidget.scss @@ -17,7 +17,6 @@ position: relative; display: flex; flex-direction: column; - gap: var(--g-spacing-4); &:after { content: ''; diff --git a/src/ui/components/DialogChartWidget/DialogChartWidget.tsx b/src/ui/components/DialogChartWidget/DialogChartWidget.tsx index a5879470f4..bbe1c86239 100644 --- a/src/ui/components/DialogChartWidget/DialogChartWidget.tsx +++ b/src/ui/components/DialogChartWidget/DialogChartWidget.tsx @@ -45,6 +45,7 @@ import type {UpdateState} from 'ui/components/TabMenu/types'; import {TabActionType} from 'ui/components/TabMenu/types'; import {DL, URL_OPTIONS} from 'ui/constants/common'; import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; +import type {ValuesType} from 'utility-types'; import {registry} from '../../registry'; import NavigationInput from '../../units/dash/components/NavigationInput/NavigationInput'; @@ -60,6 +61,7 @@ import {PaletteBackground} from '../../units/dash/containers/Dialogs/components/ import {isEntryTypeWithFiltering} from '../../units/dash/containers/Dialogs/utils'; import {DASH_WIDGET_TYPES, EntryTypeNode} from '../../units/dash/modules/constants'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; +import {useBackgroundColorSettings} from '../DialogTitleWidget/useColorSettings'; import './DialogChartWidget.scss'; @@ -95,6 +97,7 @@ export interface DialogChartWidgetFeatureProps { enableAutoheight?: boolean; enableBackgroundColor?: boolean; enableCustomBgColorSelector?: boolean; + enableSeparateThemeColorSelector?: boolean; enableFilteringSetting?: boolean; } export interface DialogChartWidgetProps extends DialogChartWidgetFeatureProps { @@ -132,6 +135,7 @@ type DialogChartWidgetState = { legacyChanged: number; visualizationType?: WizardVisualizationId; + activeTab: ValuesType; }; const INPUT_FILTERING_ID = 'chartFilteringField'; @@ -165,6 +169,7 @@ function DialogChartWidget({ enableAutoheight = true, enableBackgroundColor = false, enableCustomBgColorSelector = false, + enableSeparateThemeColorSelector = true, enableFilteringSetting = true, openedItemData = DEFAULT_OPENED_ITEM_DATA, dialogIsVisible, @@ -186,6 +191,22 @@ function DialogChartWidget({ isManualTitle: false, tabParams: {}, legacyChanged: 0, + activeTab: TAB_TYPE.TABS, + }); + + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + } = useBackgroundColorSettings({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: enableCustomBgColorSelector + ? CustomPaletteBgColors.NONE + : CustomPaletteBgColors.LIKE_CHART, + enableSeparateThemeColorSelector, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -239,7 +260,7 @@ function DialogChartWidget({ ); const onApply = React.useCallback( - (argState: DialogChartWidgetState) => { + (argState: DialogChartWidgetState, resultedBg: typeof resultedBackgroundSettings) => { const isValidateParamTitle = isEnabledFeature( Feature.DashBoardWidgetParamsStrictValidation, ); @@ -254,6 +275,7 @@ function DialogChartWidget({ if (tabWithoutChartIdIndex === -1) { const newData = { + ...resultedBg, hideTitle: tabs.length === 1 && hideTitle, tabs: tabs.map(({title, params, ...rest}, index) => { let resultTabParams = @@ -405,23 +427,6 @@ function DialogChartWidget({ [handleUpdateField], ); - const handleBackgroundColorSelected = React.useCallback((color: string) => { - setState((prevState) => ({ - ...prevState, - data: update(prevState.data, { - tabs: { - [prevState.tabIndex]: { - background: { - $set: { - color: color, - }, - }, - }, - }, - }), - })); - }, []); - const isEnabledFilteringOnCurrentTab = Boolean( state.data.tabs[state.tabIndex].enableActionParams, ); @@ -587,16 +592,8 @@ function DialogChartWidget({ ); - const { - title, - chartId, - description, - autoHeight, - background, - hint, - enableHint, - enableDescription, - } = data.tabs[tabIndex]; + const {title, chartId, description, autoHeight, hint, enableHint, enableDescription} = + data.tabs[tabIndex]; const hasDesc = enableDescription === undefined ? Boolean(description) : Boolean(enableDescription); @@ -777,8 +774,10 @@ function DialogChartWidget({ } > @@ -855,7 +854,7 @@ function DialogChartWidget({ onApply(state)} + onClickButtonApply={() => onApply(state, resultedBackgroundSettings)} textButtonApply={ isEdit ? i18n('dash.widget-dialog.edit', 'button_save') diff --git a/src/ui/components/DialogImageWidget/DialogImageWidget.tsx b/src/ui/components/DialogImageWidget/DialogImageWidget.tsx index 3d31f30d7d..de3014d9ff 100644 --- a/src/ui/components/DialogImageWidget/DialogImageWidget.tsx +++ b/src/ui/components/DialogImageWidget/DialogImageWidget.tsx @@ -13,6 +13,7 @@ import {registry} from 'ui/registry'; import {PaletteBackground} from '../..//units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; +import {useBackgroundColorSettings} from '../DialogTitleWidget/useColorSettings'; import './DialogImageWidget.scss'; @@ -26,10 +27,13 @@ const DEFAULT_ITEM_DATA: DashTabItemImage['data'] = { background: { color: CustomPaletteBgColors.NONE, }, + backgroundSettings: undefined, preserveAspectRatio: true, }; -export type DialogImageWidgetFeatureProps = {}; +export type DialogImageWidgetFeatureProps = { + enableSeparateThemeColorSelector?: boolean; +}; type Props = { openedItemId: string | null; @@ -59,6 +63,8 @@ export function DialogImageWidget(props: Props) { onClose, onApply, scope, + theme, + enableSeparateThemeColorSelector, } = props; const [data, setData] = React.useState(openedItemData); const [validationErrors, setValidationErrors] = React.useState>({}); @@ -68,6 +74,19 @@ export function DialogImageWidget(props: Props) { setData(resultData); }; + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + } = useBackgroundColorSettings({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + }); + const handleSrcUpdate = (nextSrc: string) => { setValidationErrors({ ...validationErrors, @@ -77,14 +96,18 @@ export function DialogImageWidget(props: Props) { }; const handleApply = () => { - const nextValidationErrors = getValidationErrors(data); + const newData = { + ...data, + ...resultedBackgroundSettings, + }; + const nextValidationErrors = getValidationErrors(newData); if (Object.keys(nextValidationErrors).length) { setValidationErrors(nextValidationErrors); return; } - onApply({data}); + onApply({data: newData}); onClose(); }; @@ -151,9 +174,13 @@ export function DialogImageWidget(props: Props) { label={i18n('dash.dashkit-plugin-common.view', 'label_background-checkbox')} > updateData({background: {color}})} + color={backgroundColorSettings} + oldColor={oldBackgroundColor} + theme={theme} + onSelect={setBackgroundColorSettings} + onSelectOldColor={setOldBackgroundColor} enableCustomBgColorSelector + enableSeparateThemeColorSelector={enableSeparateThemeColorSelector} /> diff --git a/src/ui/components/DialogTextWidget/DialogTextWidget.tsx b/src/ui/components/DialogTextWidget/DialogTextWidget.tsx index a92bc8fc94..96b52295a8 100644 --- a/src/ui/components/DialogTextWidget/DialogTextWidget.tsx +++ b/src/ui/components/DialogTextWidget/DialogTextWidget.tsx @@ -10,6 +10,7 @@ import {CustomPaletteBgColors, DialogDashWidgetItemQA, DialogDashWidgetQA} from import {PaletteBackground} from 'ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; +import {useBackgroundColorSettings} from '../DialogTitleWidget/useColorSettings'; import {TextEditor} from '../TextEditor/TextEditor'; import './DialogTextWidget.scss'; @@ -19,6 +20,7 @@ const b = block('dialog-text'); export interface DialogTextWidgetFeatureProps { enableAutoheight?: boolean; enableCustomBgColorSelector?: boolean; + enableSeparateThemeColorSelector?: boolean; } export interface DialogTextWidgetProps extends DialogTextWidgetFeatureProps { @@ -36,7 +38,6 @@ interface DialogTextWidgetState { text?: string; prevVisible?: boolean; autoHeight?: boolean; - backgroundColor?: string; } const INPUT_TEXT_ID = 'widgetTextField'; @@ -52,6 +53,7 @@ function DialogTextWidget(props: DialogTextWidgetProps) { const { enableAutoheight = true, enableCustomBgColorSelector, + enableSeparateThemeColorSelector, openedItemData = DEFAULT_OPENED_ITEM_DATA, dialogIsVisible, closeDialog, @@ -62,7 +64,19 @@ function DialogTextWidget(props: DialogTextWidgetProps) { const [state, setState] = React.useState({ text: openedItemData.text, autoHeight: Boolean(openedItemData.autoHeight), - backgroundColor: openedItemData.background?.color, + }); + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + updateStateByProps, + } = useBackgroundColorSettings({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -72,13 +86,18 @@ function DialogTextWidget(props: DialogTextWidgetProps) { } setPrevDialogIsVisible(dialogIsVisible); + updateStateByProps({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector, + }); setState((prevState) => ({ ...prevState, text: openedItemData.text, autoHeight: Boolean(openedItemData.autoHeight), - backgroundColor: openedItemData.background?.color, })); - }, [openedItemData, dialogIsVisible, prevDialogIsVisible]); + }, [openedItemData, dialogIsVisible, prevDialogIsVisible, enableSeparateThemeColorSelector]); const timeoutRef = React.useRef(null); @@ -116,29 +135,23 @@ function DialogTextWidget(props: DialogTextWidgetProps) { }, []); const onApply = React.useCallback(() => { - const {text, autoHeight, backgroundColor} = state; + const {text, autoHeight} = state; setItemData({ data: { text, autoHeight, - background: { - color: backgroundColor, - }, + ...resultedBackgroundSettings, }, }); closeDialog(); - }, [state, setItemData, closeDialog]); + }, [state, setItemData, closeDialog, resultedBackgroundSettings]); const handleAutoHeightChanged = React.useCallback(() => { setState((prevState) => ({...prevState, autoHeight: !prevState.autoHeight})); }, []); - const handleHasBackgroundSelected = React.useCallback((color: string) => { - setState((prevState) => ({...prevState, backgroundColor: color})); - }, []); - - const {text, autoHeight, backgroundColor} = state; + const {text, autoHeight} = state; return ( diff --git a/src/ui/components/DialogTextWidget/index.tsx b/src/ui/components/DialogTextWidget/index.tsx index 8b84290527..a1f6117927 100644 --- a/src/ui/components/DialogTextWidget/index.tsx +++ b/src/ui/components/DialogTextWidget/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {registry} from '../../registry'; -import type {DialogTextWidgetProps} from './DialogTextWidget'; +import type {DialogTextWidgetProps} from './_DialogTextWidget'; export const DialogTextWidgetWrapper = (props: DialogTextWidgetProps) => { const {DialogTextWidget} = registry.dash.components.getAll(); diff --git a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx index a08ebd2cc0..10a5c0d133 100644 --- a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx +++ b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx @@ -21,22 +21,28 @@ import { import block from 'bem-cn-lite'; import {FieldWrapper} from 'components/FieldWrapper/FieldWrapper'; import {i18n} from 'i18n'; -import type {DashTabItemTitle, DashTabItemTitleSize, HintSettings} from 'shared'; +import type {ColorSettings, DashTabItemTitle, DashTabItemTitleSize, HintSettings} from 'shared'; import { DashTabItemTitleSizes, DialogDashTitleQA, DialogDashWidgetItemQA, DialogDashWidgetQA, + Feature, } from 'shared'; -import {CustomPaletteBgColors, CustomPaletteTextColors} from 'shared/constants/widgets'; +import {CustomPaletteBgColors} from 'shared/constants/widgets'; import {registry} from 'ui/registry'; import {PaletteBackground} from 'ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; import {PaletteText} from 'ui/units/dash/containers/Dialogs/components/PaletteText/PaletteText'; +import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; +import {useBackgroundColorSettings, useColorSettings} from './useColorSettings'; + import './DialogTitleWidget.scss'; +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + type RadioButtonFontSizeOption = DashTabItemTitleSize | 'custom'; const FONT_SIZE_OPTIONS: RadioButtonOptionProps[] = [ @@ -75,8 +81,8 @@ interface DialogTitleWidgetState { previousSelectedFontSize: number; showInTOC?: boolean; autoHeight?: boolean; - backgroundColor?: string; textColor?: string; + textColorSettings?: ColorSettings; hint?: HintSettings; } @@ -85,6 +91,7 @@ export interface DialogTitleWidgetFeatureProps { enableShowInTOC?: boolean; enableCustomFontSize?: boolean; enableCustomBgColorSelector?: boolean; + enableSeparateThemeColorSelector?: boolean; enableCustomTextColorSelector?: boolean; } interface DialogTitleWidgetProps extends DialogTitleWidgetFeatureProps { @@ -111,7 +118,8 @@ const defaultOpenedItemData: DashTabItemTitle['data'] = { showInTOC: true, autoHeight: false, background: {color: CustomPaletteBgColors.NONE}, - textColor: CustomPaletteTextColors.PRIMARY, + backgroundSettings: undefined, + textColor: undefined, }; function DialogTitleWidget(props: DialogTitleWidgetProps) { @@ -121,6 +129,7 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { enableAutoheight = true, enableShowInTOC = true, enableCustomBgColorSelector, + enableSeparateThemeColorSelector = true, enableCustomTextColorSelector = false, theme, closeDialog, @@ -145,10 +154,33 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { }), showInTOC: openedItemData.showInTOC, autoHeight: Boolean(openedItemData.autoHeight), - backgroundColor: openedItemData.background?.color || '', - textColor: openedItemData.textColor || CustomPaletteTextColors.PRIMARY, + hint: openedItemData.hint, }); + + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + } = useBackgroundColorSettings({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + }); + + const { + oldColor: oldTextColor, + colorSettings: textColorSettings, + setOldColor: setOldTextColor, + setColorSettings: setTextColorSettings, + } = useColorSettings({ + color: openedItemData.textColor, + colorSettings: openedItemData.textColorSettings, + }); + const { text, fontSize, @@ -157,8 +189,6 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { validation, hint, autoHeight, - backgroundColor, - textColor, previousSelectedFontSize, } = state; @@ -225,6 +255,14 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { const validationErrors: DialogTitleWidgetState['validation'] = { text: text?.trim() ? undefined : i18n('dash.title-dialog.edit', 'toast_required-field'), }; + + const resultTextColorSettings: Pick< + DashTabItemTitle['data'], + 'textColor' | 'textColorSettings' + > = + textColorSettings || isDashColorPickersByThemeEnabled + ? {textColorSettings} + : {textColor: oldTextColor}; if (Object.values(validationErrors).filter(Boolean).length === 0) { const resultedCustomFontSize = customFontSize ?? previousSelectedFontSize; setItemData({ @@ -241,10 +279,8 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { : fontSize, showInTOC, autoHeight, - background: { - color: backgroundColor, - }, - textColor, + ...resultedBackgroundSettings, + ...resultTextColorSettings, hint, }, }); @@ -263,8 +299,9 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { previousSelectedFontSize, showInTOC, autoHeight, - backgroundColor, - textColor, + resultedBackgroundSettings, + oldTextColor, + textColorSettings, closeDialog, hint, ]); @@ -291,28 +328,17 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { setState((prevState) => ({...prevState, autoHeight: !prevState.autoHeight})); }, []); - const handleHasBackgroundSelected = React.useCallback((color: string) => { - setState((prevState) => ({...prevState, backgroundColor: color})); - }, []); - - const handleTextColorChanged = React.useCallback((color: string) => { - setState((prevState) => ({...prevState, textColor: color})); - }, []); - const inputRef: React.Ref = React.useRef(null); const {MarkdownControl} = registry.common.components.getAll(); - React.useEffect(() => { - // TODO remove and use "initialFocus={inputRef}" in Dialog props when switch to uikit7 - // delay is needed so that the autofocus of the dialog does not interrupt the focus on the input - setTimeout(() => { - inputRef.current?.focus(); - }); - }, []); - return ( - + diff --git a/src/ui/components/DialogTitleWidget/useColorSettings.ts b/src/ui/components/DialogTitleWidget/useColorSettings.ts new file mode 100644 index 0000000000..6b80733707 --- /dev/null +++ b/src/ui/components/DialogTitleWidget/useColorSettings.ts @@ -0,0 +1,142 @@ +import React from 'react'; + +import type {BackgroundSettings, ColorSettings, OldBackgroundSettings} from 'shared'; +import {CustomPaletteBgColors, Feature} from 'shared'; +import {getResultedOldBgColor} from 'shared/modules/dash-scheme-converter'; +import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; +import {getWidgetColorSettings} from 'ui/utils/widgetColors'; + +type UseColorSettingsProps = { + color?: string; + colorSettings?: ColorSettings; + defaultOldColor?: string; + enableSeparateThemeColorSelector?: boolean; +}; + +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + +export function useColorSettings(props: UseColorSettingsProps) { + const getPartialStateFromProps = React.useCallback((propsLocal: UseColorSettingsProps) => { + return { + oldColor: propsLocal.color ?? propsLocal.defaultOldColor, + colorSettings: getWidgetColorSettings({ + colorSettings: propsLocal.colorSettings, + oldColor: propsLocal.color, + defaultOldColor: propsLocal.defaultOldColor ?? CustomPaletteBgColors.NONE, + enableMultiThemeColors: propsLocal.enableSeparateThemeColorSelector ?? true, + }), + }; + }, []); + + const [{oldColor, colorSettings}, setBgSettings] = React.useState<{ + oldColor?: string; + colorSettings?: ColorSettings; + }>(getPartialStateFromProps(props)); + + const updateStateByProps = React.useCallback( + (propsLocal: UseColorSettingsProps) => { + setBgSettings(getPartialStateFromProps(propsLocal)); + }, + [getPartialStateFromProps], + ); + + const setOldColor = React.useCallback((color?: string) => { + setBgSettings((prev) => ({ + ...prev, + oldColor: color, + })); + }, []); + + const setColorSettings = React.useCallback((settings?: ColorSettings) => { + setBgSettings({ + oldColor: undefined, + colorSettings: settings, + }); + }, []); + + return { + oldColor, + colorSettings, + setOldColor, + setColorSettings, + updateStateByProps, + }; +} + +type UseBackgroundColorSettingsProps = { + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; + defaultOldColor?: string; + enableSeparateThemeColorSelector?: boolean; +}; + +function getColorSettingsProps(propsLocal: UseBackgroundColorSettingsProps): UseColorSettingsProps { + return { + color: getResultedOldBgColor(propsLocal.background, propsLocal.defaultOldColor), + colorSettings: propsLocal.backgroundSettings?.color, + defaultOldColor: propsLocal.defaultOldColor, + enableSeparateThemeColorSelector: propsLocal.enableSeparateThemeColorSelector, + }; +} + +export function useBackgroundColorSettings({ + background, + backgroundSettings, + defaultOldColor = CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector = true, +}: UseBackgroundColorSettingsProps) { + const { + oldColor: oldBackgroundColor, + colorSettings: backgroundColorSettings, + setOldColor: setOldBackgroundColor, + setColorSettings: setBackgroundColorSettings, + updateStateByProps: updateStateByPropsColorSettings, + } = useColorSettings( + getColorSettingsProps({ + background, + backgroundSettings, + defaultOldColor, + enableSeparateThemeColorSelector, + }), + ); + + const resultedBackgroundSettings = React.useMemo( + () => + getResultedBackgroundSettings({ + oldBackgroundColor, + backgroundColorSettings, + }), + [oldBackgroundColor, backgroundColorSettings], + ); + + const updateStateByProps = React.useCallback( + (propsLocal: UseBackgroundColorSettingsProps) => { + updateStateByPropsColorSettings(getColorSettingsProps(propsLocal)); + }, + [updateStateByPropsColorSettings], + ); + + return { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + updateStateByProps, + resultedBackgroundSettings, + }; +} + +export function getResultedBackgroundSettings({ + oldBackgroundColor, + backgroundColorSettings, +}: { + oldBackgroundColor?: string; + backgroundColorSettings?: ColorSettings; +}): { + backgroundSettings?: BackgroundSettings; + background?: Omit; +} { + return backgroundColorSettings || isDashColorPickersByThemeEnabled + ? {backgroundSettings: {color: backgroundColorSettings}} + : {background: oldBackgroundColor ? {color: oldBackgroundColor} : undefined}; +} From 6b3888ce4a80fc99638edd2ea6c5f07189ba4b49 Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 27 Nov 2025 15:53:15 +0300 Subject: [PATCH 5/9] dashkit settings --- src/ui/units/dash/containers/Body/Body.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/units/dash/containers/Body/Body.tsx b/src/ui/units/dash/containers/Body/Body.tsx index eda0e5585a..7a3af9abf9 100644 --- a/src/ui/units/dash/containers/Body/Body.tsx +++ b/src/ui/units/dash/containers/Body/Body.tsx @@ -1210,6 +1210,7 @@ class Body extends React.PureComponent { const DashKit = getConfiguredDashKit(undefined, { disableHashNavigation, scope: 'dash', + backgroundSettings: settings.backgroundSettings, }); const hasFixedHeaderControlsElements = Boolean( From 1fc742344691f245c991ee2b8bfa9e517ba7cc0a Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 27 Nov 2025 16:03:40 +0300 Subject: [PATCH 6/9] fix --- src/shared/constants/widgets.ts | 13 +-- src/shared/modules/dash-scheme-converter.ts | 15 ++-- src/shared/types/dash.ts | 30 +++++-- .../DashKit/plugins/Widget/WidgetPlugin.tsx | 13 +-- .../DialogChartWidget/DialogChartWidget.tsx | 69 +++++++++----- .../DialogImageWidget/DialogImageWidget.tsx | 27 ++++-- .../DialogTextWidget/DialogTextWidget.tsx | 34 +++++-- src/ui/components/DialogTextWidget/index.tsx | 2 +- .../DialogTitleWidget/DialogTitleWidget.tsx | 23 ++++- .../DialogTitleWidget/useColorSettings.ts | 65 +++++++++----- .../ColorInputsGroup/ColorInputsGroup.tsx | 5 +- .../components/PaletteText/PaletteText.tsx | 5 +- src/ui/units/dash/store/reducers/dash.js | 20 +++-- src/ui/utils/copyItems.ts | 89 +++++++++++++++---- src/ui/utils/widgetColors.ts | 80 +++++++++++++++++ 15 files changed, 373 insertions(+), 117 deletions(-) create mode 100644 src/ui/utils/widgetColors.ts diff --git a/src/shared/constants/widgets.ts b/src/shared/constants/widgets.ts index ca14aebffe..071b0a0118 100644 --- a/src/shared/constants/widgets.ts +++ b/src/shared/constants/widgets.ts @@ -11,12 +11,6 @@ export const TRANSPARENT_COLOR_HEX = '#00000000'; export const LIKE_CHART_COLOR_TOKEN = 'var(--g-color-base-float)'; export const BASE_GREY_BACKGROUND_COLOR = 'var(--g-color-base-generic)'; -export type CustomPaletteBgColor = ValueOf; - -export function isCustomPaletteBgColor(color: string): color is CustomPaletteBgColor { - return Object.values(CustomPaletteBgColors).includes(color as CustomPaletteBgColor); -} - export const WIDGET_BG_HEAVY_COLORS_PRESET = [ 'var(--g-color-base-info-heavy)', 'var(--g-color-base-positive-heavy)', @@ -108,3 +102,10 @@ export function getDefaultDashWidgetBgColorByType(type: DashTabItemType) { ? CustomPaletteBgColors.LIKE_CHART : CustomPaletteBgColors.NONE; } + +export function getColorSettingsWithValue( + color: string | undefined, + enableSeparateThemeColorSelector: boolean, +) { + return enableSeparateThemeColorSelector ? {light: color, dark: color} : color; +} diff --git a/src/shared/modules/dash-scheme-converter.ts b/src/shared/modules/dash-scheme-converter.ts index 9a5affa5fc..0111b7a044 100644 --- a/src/shared/modules/dash-scheme-converter.ts +++ b/src/shared/modules/dash-scheme-converter.ts @@ -7,18 +7,18 @@ import { DUPLICATED_WIDGET_BG_COLORS_PRESET, getDefaultDashWidgetBgColorByType, } from '../constants/widgets'; -import type {BackgroundSettings, DashData, DashTab, DashTabItem} from '../types'; +import type {DashData, DashTab, DashTabItem, OldBackgroundSettings} from '../types'; import { DashTabConnectionKind, DashTabItemControlElementType, DashTabItemType, - isBackgroundSettings, + isOldBackgroundSettings, } from '../types'; const DATE_FORMAT_V7 = 'YYYY-MM-DD'; export function getResultedOldBgColor( - oldBgColor: BackgroundSettings | undefined, + oldBgColor: OldBackgroundSettings | undefined, defaultColor: string | undefined, ): string | undefined { if (!oldBgColor) { @@ -42,12 +42,12 @@ export function getResultedOldBgColor( } export function getActualOldBackground( - background: BackgroundSettings | undefined, + background: OldBackgroundSettings | undefined, defaultColor: string | undefined, -): Omit | undefined { +): Omit | undefined { if ( background && - isBackgroundSettings(background) && + isOldBackgroundSettings(background) && background.color && DUPLICATED_WIDGET_BG_COLORS_PRESET.includes(background.color) ) { @@ -60,6 +60,9 @@ export function getActualOldBackground( } export function migrateBgColor(item: DashTabItem, defaultOldColor?: string): DashTabItem { + if (DashTabItemType.GroupControl === item.type || DashTabItemType.Control === item.type) { + return item; + } const newItem: DashTabItem = Object.assign({...item}, {data: Object.assign({}, item.data)}); if ('background' in newItem.data) { diff --git a/src/shared/types/dash.ts b/src/shared/types/dash.ts index 0280a8fbb9..95a92733e5 100644 --- a/src/shared/types/dash.ts +++ b/src/shared/types/dash.ts @@ -180,6 +180,21 @@ export function isColorByTheme(value: unknown): value is ColorByTheme { ); } +export function isColorSettings(value: unknown): value is ColorSettings { + return typeof value === 'string' || isColorByTheme(value); +} + +export function isBackgroundSettings(value: unknown): value is BackgroundSettings { + return ( + typeof value === 'object' && + value !== null && + 'color' in value && + (value.color === undefined || + typeof value.color === 'string' || + isColorSettings(value.color)) + ); +} + export interface DashTabItemBase { id: string; namespace: string; @@ -189,14 +204,14 @@ export interface DashTabItemBase { title?: string; } -export interface DahsTabItemBaseData { +export type DashTabItemBaseData = { background?: OldBackgroundSettings; backgroundSettings?: BackgroundSettings; -} +}; export interface DashTabItemText extends DashTabItemBase { type: DashTabItemType.Text; - data: DahsTabItemBaseData & { + data: DashTabItemBaseData & { text: string; autoHeight?: boolean; }; @@ -211,7 +226,7 @@ export type DashTitleSize = export interface DashTabItemTitle extends DashTabItemBase { type: DashTabItemType.Title; - data: DahsTabItemBaseData & { + data: DashTabItemBaseData & { text: string; size: DashTitleSize; showInTOC: boolean; @@ -224,9 +239,10 @@ export interface DashTabItemTitle extends DashTabItemBase { export interface DashTabItemWidget extends DashTabItemBase { type: DashTabItemType.Widget; - data: DahsTabItemBaseData & { + data: { hideTitle: boolean; tabs: DashTabItemWidgetTab[]; + backgroundSettings?: BackgroundSettings; }; } @@ -424,11 +440,9 @@ export interface DashStats { export interface DashTabItemImage extends DashTabItemBase { type: DashTabItemType.Image; - data: { + data: DashTabItemBaseData & { src: string; alt?: string; - background?: OldBackgroundSettings; - backgroundSettings?: BackgroundSettings; preserveAspectRatio?: boolean; }; } diff --git a/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx b/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx index 346fd16c08..16d054b7bf 100644 --- a/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx +++ b/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx @@ -43,12 +43,15 @@ const widgetPlugin: PluginWidget = { const workbookId = props.context.workbookId; const enableAssistant = props.context.enableAssistant; - const propsBg = - widgetPlugin.scope === 'dash' - ? {color: CustomPaletteBgColors.LIKE_CHART} - : props.data.tabs?.[0]?.background; + const propsBg = props.data.tabs?.[0]?.background; + + let oldWidgetBg = isOldBackgroundSettings(propsBg) ? propsBg : undefined; + if (widgetPlugin.scope === 'dash' && !props.data.backgroundSettings) { + oldWidgetBg = {color: CustomPaletteBgColors.LIKE_CHART}; + } + const {style} = usePreparedWrapSettings({ - widgetBackground: isOldBackgroundSettings(propsBg) ? propsBg : undefined, + widgetBackground: oldWidgetBg, globalBackground: widgetPlugin.globalBackground, widgetBackgroundSettings: props.backgroundSettings, globalBackgroundSettings: widgetPlugin.globalBackgroundSettings, diff --git a/src/ui/components/DialogChartWidget/DialogChartWidget.tsx b/src/ui/components/DialogChartWidget/DialogChartWidget.tsx index bbe1c86239..68070f88db 100644 --- a/src/ui/components/DialogChartWidget/DialogChartWidget.tsx +++ b/src/ui/components/DialogChartWidget/DialogChartWidget.tsx @@ -145,8 +145,17 @@ const INPUT_DESCRIPTION_ID = 'chartDescriptionField'; const INPUT_AUTOHEIGHT_ID = 'chartAutoheightField'; const INPUT_HINT_ID = 'chartHintField'; +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableCommonChartDashSettings); + const DEFAULT_OPENED_ITEM_DATA: DashTabItemWidget['data'] = { hideTitle: false, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : {}), tabs: [ { get title() { @@ -154,9 +163,13 @@ const DEFAULT_OPENED_ITEM_DATA: DashTabItemWidget['data'] = { }, isDefault: true, description: '', - background: { - color: CustomPaletteBgColors.NONE, - }, + ...(isDashColorPickersByThemeEnabled + ? {} + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), enableHint: false, hint: '', enableDescription: false, @@ -165,23 +178,24 @@ const DEFAULT_OPENED_ITEM_DATA: DashTabItemWidget['data'] = { } as DashTabItemWidget['data']; // TODO: put in defaultPath navigation key from entry -function DialogChartWidget({ - enableAutoheight = true, - enableBackgroundColor = false, - enableCustomBgColorSelector = false, - enableSeparateThemeColorSelector = true, - enableFilteringSetting = true, - openedItemData = DEFAULT_OPENED_ITEM_DATA, - dialogIsVisible, - widgetsCurrentTab, - withoutSidebar, - changeNavigationPath, - workbookId, - navigationPath, - closeDialog, - setItemData, - openedItemId, -}: DialogChartWidgetProps) { +function DialogChartWidget(props: DialogChartWidgetProps) { + const { + enableAutoheight = true, + enableBackgroundColor = false, + enableCustomBgColorSelector = false, + enableSeparateThemeColorSelector = true, + enableFilteringSetting = true, + openedItemData = DEFAULT_OPENED_ITEM_DATA, + dialogIsVisible, + widgetsCurrentTab, + withoutSidebar, + changeNavigationPath, + workbookId, + navigationPath, + closeDialog, + setItemData, + openedItemId, + } = props; const [state, setState] = React.useState({ hideTitle: true, prevVisible: false, @@ -194,6 +208,8 @@ function DialogChartWidget({ activeTab: TAB_TYPE.TABS, }); + const couldChangeOldBg = enableCustomBgColorSelector; + const { oldBackgroundColor, backgroundColorSettings, @@ -201,12 +217,15 @@ function DialogChartWidget({ setBackgroundColorSettings, resultedBackgroundSettings, } = useBackgroundColorSettings({ - background: openedItemData.background, + background: couldChangeOldBg + ? openedItemData.tabs[0]?.background + : {color: CustomPaletteBgColors.LIKE_CHART}, backgroundSettings: openedItemData.backgroundSettings, - defaultOldColor: enableCustomBgColorSelector + defaultOldColor: couldChangeOldBg ? CustomPaletteBgColors.NONE : CustomPaletteBgColors.LIKE_CHART, enableSeparateThemeColorSelector, + isNewWidget: !props.openedItemData, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -275,7 +294,10 @@ function DialogChartWidget({ if (tabWithoutChartIdIndex === -1) { const newData = { - ...resultedBg, + ...(resultedBg?.backgroundSettings + ? {backgroundSettings: resultedBg.backgroundSettings} + : {}), + hideTitle: tabs.length === 1 && hideTitle, tabs: tabs.map(({title, params, ...rest}, index) => { let resultTabParams = @@ -300,6 +322,7 @@ function DialogChartWidget({ }), params: resultTabParams, ...rest, + ...(resultedBg?.background ? {background: resultedBg.background} : {}), }; return tab; }), diff --git a/src/ui/components/DialogImageWidget/DialogImageWidget.tsx b/src/ui/components/DialogImageWidget/DialogImageWidget.tsx index de3014d9ff..371b4f9601 100644 --- a/src/ui/components/DialogImageWidget/DialogImageWidget.tsx +++ b/src/ui/components/DialogImageWidget/DialogImageWidget.tsx @@ -7,9 +7,10 @@ import block from 'bem-cn-lite'; import {i18n} from 'i18n'; import cloneDeep from 'lodash/cloneDeep'; import merge from 'lodash/merge'; -import {CustomPaletteBgColors, DialogDashWidgetItemQA, DialogDashWidgetQA} from 'shared'; +import {CustomPaletteBgColors, DialogDashWidgetItemQA, DialogDashWidgetQA, Feature} from 'shared'; import type {DashTabItemImage, EntryScope, RecursivePartial} from 'shared'; import {registry} from 'ui/registry'; +import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; import {PaletteBackground} from '../..//units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; @@ -21,13 +22,23 @@ const b = block('dialog-image'); const INPUT_SRC_ID = 'dialog-image-input-src'; const INPUT_ALT_ID = 'dialog-image-input-alt'; const INPUT_PRESERVE_ASPECT_RATIO_ID = 'dialog-image-input-preserve-aspect-ratio'; + +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + const DEFAULT_ITEM_DATA: DashTabItemImage['data'] = { src: '', alt: '', - background: { - color: CustomPaletteBgColors.NONE, - }, - backgroundSettings: undefined, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), preserveAspectRatio: true, }; @@ -64,8 +75,9 @@ export function DialogImageWidget(props: Props) { onApply, scope, theme, - enableSeparateThemeColorSelector, + enableSeparateThemeColorSelector = true, } = props; + const isNewWidget = !props.openedItemData; const [data, setData] = React.useState(openedItemData); const [validationErrors, setValidationErrors] = React.useState>({}); const {DialogImageWidgetLinkHint} = registry.common.components.getAll(); @@ -84,7 +96,8 @@ export function DialogImageWidget(props: Props) { background: openedItemData.background, backgroundSettings: openedItemData.backgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, - enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + enableSeparateThemeColorSelector, + isNewWidget, }); const handleSrcUpdate = (nextSrc: string) => { diff --git a/src/ui/components/DialogTextWidget/DialogTextWidget.tsx b/src/ui/components/DialogTextWidget/DialogTextWidget.tsx index 96b52295a8..c4077258c4 100644 --- a/src/ui/components/DialogTextWidget/DialogTextWidget.tsx +++ b/src/ui/components/DialogTextWidget/DialogTextWidget.tsx @@ -6,8 +6,9 @@ import {Checkbox, Dialog} from '@gravity-ui/uikit'; import block from 'bem-cn-lite'; import {i18n} from 'i18n'; import type {DashTabItemText} from 'shared'; -import {CustomPaletteBgColors, DialogDashWidgetItemQA, DialogDashWidgetQA} from 'shared'; +import {CustomPaletteBgColors, DialogDashWidgetItemQA, DialogDashWidgetQA, Feature} from 'shared'; import {PaletteBackground} from 'ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; +import {isEnabledFeature} from 'ui/utils/isEnabledFeature'; import type {SetItemDataArgs} from '../../units/dash/store/actions/dashTyped'; import {useBackgroundColorSettings} from '../DialogTitleWidget/useColorSettings'; @@ -43,17 +44,29 @@ interface DialogTextWidgetState { const INPUT_TEXT_ID = 'widgetTextField'; const INPUT_AUTOHEIGHT_ID = 'widgetAutoHeightField'; +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + const DEFAULT_OPENED_ITEM_DATA: DashTabItemText['data'] = { text: '', autoHeight: false, - background: {color: CustomPaletteBgColors.NONE}, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), }; function DialogTextWidget(props: DialogTextWidgetProps) { const { enableAutoheight = true, - enableCustomBgColorSelector, - enableSeparateThemeColorSelector, + enableCustomBgColorSelector = false, + enableSeparateThemeColorSelector = true, openedItemData = DEFAULT_OPENED_ITEM_DATA, dialogIsVisible, closeDialog, @@ -61,6 +74,8 @@ function DialogTextWidget(props: DialogTextWidgetProps) { openedItemId, } = props; + const isNewWidget = !props.openedItemData; + const [state, setState] = React.useState({ text: openedItemData.text, autoHeight: Boolean(openedItemData.autoHeight), @@ -77,6 +92,7 @@ function DialogTextWidget(props: DialogTextWidgetProps) { backgroundSettings: openedItemData.backgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, enableSeparateThemeColorSelector, + isNewWidget, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -91,13 +107,21 @@ function DialogTextWidget(props: DialogTextWidgetProps) { backgroundSettings: openedItemData.backgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, enableSeparateThemeColorSelector, + isNewWidget, }); setState((prevState) => ({ ...prevState, text: openedItemData.text, autoHeight: Boolean(openedItemData.autoHeight), })); - }, [openedItemData, dialogIsVisible, prevDialogIsVisible, enableSeparateThemeColorSelector]); + }, [ + openedItemData, + dialogIsVisible, + prevDialogIsVisible, + enableSeparateThemeColorSelector, + updateStateByProps, + isNewWidget, + ]); const timeoutRef = React.useRef(null); diff --git a/src/ui/components/DialogTextWidget/index.tsx b/src/ui/components/DialogTextWidget/index.tsx index a1f6117927..8b84290527 100644 --- a/src/ui/components/DialogTextWidget/index.tsx +++ b/src/ui/components/DialogTextWidget/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {registry} from '../../registry'; -import type {DialogTextWidgetProps} from './_DialogTextWidget'; +import type {DialogTextWidgetProps} from './DialogTextWidget'; export const DialogTextWidgetWrapper = (props: DialogTextWidgetProps) => { const {DialogTextWidget} = registry.dash.components.getAll(); diff --git a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx index 10a5c0d133..fd0250991c 100644 --- a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx +++ b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx @@ -29,7 +29,7 @@ import { DialogDashWidgetQA, Feature, } from 'shared'; -import {CustomPaletteBgColors} from 'shared/constants/widgets'; +import {CustomPaletteBgColors, CustomPaletteTextColors} from 'shared/constants/widgets'; import {registry} from 'ui/registry'; import {PaletteBackground} from 'ui/units/dash/containers/Dialogs/components/PaletteBackground/PaletteBackground'; import {PaletteText} from 'ui/units/dash/containers/Dialogs/components/PaletteText/PaletteText'; @@ -117,8 +117,17 @@ const defaultOpenedItemData: DashTabItemTitle['data'] = { size: FONT_SIZE_OPTIONS[0].value, showInTOC: true, autoHeight: false, - background: {color: CustomPaletteBgColors.NONE}, - backgroundSettings: undefined, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), textColor: undefined, }; @@ -128,7 +137,7 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { dialogIsVisible, enableAutoheight = true, enableShowInTOC = true, - enableCustomBgColorSelector, + enableCustomBgColorSelector = false, enableSeparateThemeColorSelector = true, enableCustomTextColorSelector = false, theme, @@ -137,6 +146,8 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { openedItemData = defaultOpenedItemData, } = props; + const isNewWidget = !props.openedItemData; + const [state, setState] = React.useState({ validation: {}, text: openedItemData.text, @@ -169,6 +180,7 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { backgroundSettings: openedItemData.backgroundSettings, defaultOldColor: CustomPaletteBgColors.NONE, enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + isNewWidget, }); const { @@ -179,6 +191,9 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { } = useColorSettings({ color: openedItemData.textColor, colorSettings: openedItemData.textColorSettings, + defaultOldColor: CustomPaletteTextColors.PRIMARY, + enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + isNewWidget, }); const { diff --git a/src/ui/components/DialogTitleWidget/useColorSettings.ts b/src/ui/components/DialogTitleWidget/useColorSettings.ts index 6b80733707..4a4a237ebd 100644 --- a/src/ui/components/DialogTitleWidget/useColorSettings.ts +++ b/src/ui/components/DialogTitleWidget/useColorSettings.ts @@ -11,22 +11,29 @@ type UseColorSettingsProps = { colorSettings?: ColorSettings; defaultOldColor?: string; enableSeparateThemeColorSelector?: boolean; + isNewWidget: boolean; }; const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); export function useColorSettings(props: UseColorSettingsProps) { - const getPartialStateFromProps = React.useCallback((propsLocal: UseColorSettingsProps) => { - return { - oldColor: propsLocal.color ?? propsLocal.defaultOldColor, - colorSettings: getWidgetColorSettings({ - colorSettings: propsLocal.colorSettings, - oldColor: propsLocal.color, - defaultOldColor: propsLocal.defaultOldColor ?? CustomPaletteBgColors.NONE, - enableMultiThemeColors: propsLocal.enableSeparateThemeColorSelector ?? true, - }), - }; - }, []); + const getPartialStateFromProps = React.useCallback( + (propsLocal: UseColorSettingsProps) => { + return { + oldColor: + props.isNewWidget && isDashColorPickersByThemeEnabled + ? undefined + : propsLocal.color ?? propsLocal.defaultOldColor, + colorSettings: getWidgetColorSettings({ + colorSettings: propsLocal.colorSettings, + oldColor: propsLocal.color, + defaultOldColor: propsLocal.defaultOldColor ?? CustomPaletteBgColors.NONE, + enableMultiThemeColors: propsLocal.enableSeparateThemeColorSelector ?? true, + }), + }; + }, + [props.isNewWidget], + ); const [{oldColor, colorSettings}, setBgSettings] = React.useState<{ oldColor?: string; @@ -41,10 +48,9 @@ export function useColorSettings(props: UseColorSettingsProps) { ); const setOldColor = React.useCallback((color?: string) => { - setBgSettings((prev) => ({ - ...prev, + setBgSettings({ oldColor: color, - })); + }); }, []); const setColorSettings = React.useCallback((settings?: ColorSettings) => { @@ -64,18 +70,29 @@ export function useColorSettings(props: UseColorSettingsProps) { } type UseBackgroundColorSettingsProps = { - background?: OldBackgroundSettings; - backgroundSettings?: BackgroundSettings; - defaultOldColor?: string; - enableSeparateThemeColorSelector?: boolean; + background: OldBackgroundSettings | undefined; + backgroundSettings: BackgroundSettings | undefined; + defaultOldColor: string | undefined; + enableSeparateThemeColorSelector: boolean; + isNewWidget: boolean; }; -function getColorSettingsProps(propsLocal: UseBackgroundColorSettingsProps): UseColorSettingsProps { +function getColorSettingsProps({ + background, + backgroundSettings, + defaultOldColor, + enableSeparateThemeColorSelector, + isNewWidget, +}: UseBackgroundColorSettingsProps): UseColorSettingsProps { return { - color: getResultedOldBgColor(propsLocal.background, propsLocal.defaultOldColor), - colorSettings: propsLocal.backgroundSettings?.color, - defaultOldColor: propsLocal.defaultOldColor, - enableSeparateThemeColorSelector: propsLocal.enableSeparateThemeColorSelector, + color: + isNewWidget && isDashColorPickersByThemeEnabled + ? undefined + : getResultedOldBgColor(background, defaultOldColor), + colorSettings: backgroundSettings?.color, + defaultOldColor, + enableSeparateThemeColorSelector, + isNewWidget, }; } @@ -84,6 +101,7 @@ export function useBackgroundColorSettings({ backgroundSettings, defaultOldColor = CustomPaletteBgColors.NONE, enableSeparateThemeColorSelector = true, + isNewWidget, }: UseBackgroundColorSettingsProps) { const { oldColor: oldBackgroundColor, @@ -97,6 +115,7 @@ export function useBackgroundColorSettings({ backgroundSettings, defaultOldColor, enableSeparateThemeColorSelector, + isNewWidget, }), ); diff --git a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx index 79ebcdab3b..4454061cde 100644 --- a/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx +++ b/src/ui/units/dash/containers/Dialogs/components/ColorInputsGroup/ColorInputsGroup.tsx @@ -7,7 +7,6 @@ import block from 'bem-cn-lite'; import ColorPickerInputWithPreset from 'ui/units/dash/containers/Dialogs/components/ColorPickerInputWithPreset/ColorPickerInputWithPreset'; import {type ColorSettings, isColorByTheme} from '../../../../../../../shared'; -import {ColorPickerInput} from '../../../../../../components/ColorPickerInput/ColorPickerInput'; import './ColorInputsGroup.scss'; const b = block('color-inputs-group'); @@ -40,7 +39,9 @@ export function ColorInputsGroup({ return ( {isSingleColorSelector ? ( - { if (isCommonDashSettingsEnabled || color) { return ( @@ -42,6 +44,7 @@ export const PaletteText = ({ value={color ?? computeColorFromToken(oldColor)} onUpdate={onSelect} isSingleColorSelector={!enableSeparateThemeColorSelector} + direction={direction} /> ); } diff --git a/src/ui/units/dash/store/reducers/dash.js b/src/ui/units/dash/store/reducers/dash.js index 29fc2f4f23..61a00e7bdd 100644 --- a/src/ui/units/dash/store/reducers/dash.js +++ b/src/ui/units/dash/store/reducers/dash.js @@ -9,7 +9,7 @@ import { getDefaultDashWidgetBgColorByType, } from 'shared/constants/widgets'; import {migrateConnectionsForGroupControl} from 'ui/store/utils/controlDialog'; -import {getUpdatedBackgroundValue, getUpdatedConnections} from 'ui/utils/copyItems'; +import {getUpdatedBackgroundData, getUpdatedConnections} from 'ui/utils/copyItems'; import {EMBEDDED_MODE} from '../../../../constants/embedded'; import {Mode} from '../../modules/constants'; @@ -263,16 +263,18 @@ function dash(state = initialState, action) { ) { delete itemData.textColor; } + const defaultBgColorValue = getDefaultDashWidgetBgColorByType(itemData.type); const backgroundData = - 'background' in itemData - ? { - background: getUpdatedBackgroundValue( - itemData.background, - false, - defaultBgColorValue, - ), - } + action.payload.item.type !== DashTabItemType.Control && + action.payload.item.type !== DashTabItemType.GroupControl + ? getUpdatedBackgroundData({ + background: itemData.background, + backgroundSettings: itemData.backgroundSettings, + allowCustomValues: false, + enableSeparateThemeColorSelector: true, + defaultOldColor: defaultBgColorValue, + }) : {}; const newItem = { ...action.payload.item, diff --git a/src/ui/utils/copyItems.ts b/src/ui/utils/copyItems.ts index 487fe20f32..120729b51c 100644 --- a/src/ui/utils/copyItems.ts +++ b/src/ui/utils/copyItems.ts @@ -1,10 +1,23 @@ import type {ConfigItem, ConfigItemData} from '@gravity-ui/dashkit'; -import {CustomPaletteBgColors, WIDGET_BG_COLORS_PRESET} from 'shared'; +import { + CustomPaletteBgColors, + WIDGET_BG_COLORS_PRESET, + getColorSettingsWithValue, +} from 'shared/constants'; import {getActualOldBackground} from 'shared/modules/dash-scheme-converter'; -import type {BackgroundSettings} from 'shared/types'; -import {DashTabItemType, isBackgroundSettings} from 'shared/types'; +import type {BackgroundSettings, ColorSettings, OldBackgroundSettings} from 'shared/types'; +import { + DashTabItemType, + Feature, + isBackgroundSettings, + isColorByTheme, + isOldBackgroundSettings, +} from 'shared/types'; import type {ConnectionsData} from 'ui/components/DialogRelations/types'; +import {isEnabledFeature} from './isEnabledFeature'; +import {computeColorFromToken} from './widgetColors'; + // targetId - item is copied data from localStorage // id - item is already created via DashKit.setItem type TargetWidgetId = {id: string} | {targetId?: string}; @@ -95,25 +108,67 @@ export const getUpdatedConnections = ({ return [...connections, ...copiedConnections]; }; -export function getUpdatedBackgroundValue( - background: unknown, - allowCusomValues?: boolean, - defaultOldColor?: string, -): Omit | undefined { - if (isBackgroundSettings(background)) { - const newBg = getActualOldBackground(background, defaultOldColor); +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + +export function getUpdatedBackgroundData({ + background, + backgroundSettings, + allowCustomValues = false, + enableSeparateThemeColorSelector = true, + defaultOldColor, +}: { + background: unknown; + backgroundSettings: unknown; + allowCustomValues: boolean; + enableSeparateThemeColorSelector: boolean; + defaultOldColor: string; +}): { + backgroundSettings: BackgroundSettings | undefined; + background: OldBackgroundSettings | undefined; +} { + let oldColor: string | undefined; + let newColor: ColorSettings | undefined; + + const isOldBackground = isOldBackgroundSettings(background); + const isBgSettings = isBackgroundSettings(backgroundSettings); + + if (isOldBackground) { + oldColor = getActualOldBackground(background, defaultOldColor)?.color; if ( - allowCusomValues || - WIDGET_BG_COLORS_PRESET.includes(background.color) || - Object.values(CustomPaletteBgColors).includes(background.color) + !isDashColorPickersByThemeEnabled && + !allowCustomValues && + oldColor && + !WIDGET_BG_COLORS_PRESET.includes(oldColor) && + !Object.values(CustomPaletteBgColors).includes(oldColor) ) { - return newBg; + oldColor = defaultOldColor; } } - return defaultOldColor + + if (isBgSettings) { + const color = backgroundSettings.color; + if ( + !color || + (isColorByTheme(color) && enableSeparateThemeColorSelector) || + (!isColorByTheme(color) && !enableSeparateThemeColorSelector) + ) { + newColor = color; + } + } else if (isDashColorPickersByThemeEnabled) { + newColor = getColorSettingsWithValue( + computeColorFromToken(oldColor ?? defaultOldColor), + enableSeparateThemeColorSelector, + ); + } + + return isBgSettings ? { - color: defaultOldColor, + background: undefined, + backgroundSettings: {color: newColor}, } - : undefined; + : { + background: oldColor ? {color: oldColor} : undefined, + backgroundSettings: undefined, + }; } diff --git a/src/ui/utils/widgetColors.ts b/src/ui/utils/widgetColors.ts new file mode 100644 index 0000000000..65f902392e --- /dev/null +++ b/src/ui/utils/widgetColors.ts @@ -0,0 +1,80 @@ +import type {RealTheme} from '@gravity-ui/uikit'; +import {color as d3Color} from 'd3-color'; +import type {ColorSettings} from 'shared'; +import { + CustomPaletteBgColors, + Feature, + LIKE_CHART_COLOR_TOKEN, + TRANSPARENT_COLOR_HEX, + getColorSettingsWithValue, +} from 'shared'; + +import {isEnabledFeature} from './isEnabledFeature'; + +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + +export function computeColorFromToken(externalToken?: string, theme?: RealTheme) { + if (!externalToken) { + return undefined; + } + + let token = externalToken; + + if (token === CustomPaletteBgColors.LIKE_CHART) { + token = LIKE_CHART_COLOR_TOKEN; + } else if (token === CustomPaletteBgColors.NONE) { + token = TRANSPARENT_COLOR_HEX; + } else if (d3Color(token)) { + return d3Color(token)?.formatHex8(); + } + + const div = document.createElement('div'); + div.style.backgroundColor = token; + div.style.position = 'absolute'; + div.style.top = '-1000px'; + div.style.left = '-1000px'; + div.style.width = '0'; + div.style.height = '0'; + + let elem = div; + + if (theme) { + elem = document.createElement('div'); + const classList = document.body.className + .split(' ') + .map((cls) => (cls.trim().startsWith('g-root_theme_') ? `g-root_theme_${theme}` : cls)) + .filter(Boolean); + elem.classList.add('g-root', ...classList); + + elem.appendChild(div); + } + document.body.appendChild(elem); + const color = getComputedStyle(div).backgroundColor; + document.body.removeChild(elem); + const d3ColorResult = d3Color(color); + return d3ColorResult ? d3ColorResult.formatHex8() : undefined; +} + +export function getWidgetColorSettings(args: { + colorSettings?: ColorSettings; + oldColor?: string; + defaultOldColor: string; + enableMultiThemeColors: boolean; +}): ColorSettings | undefined { + const {colorSettings, oldColor, defaultOldColor, enableMultiThemeColors = true} = args; + if (!isDashColorPickersByThemeEnabled && !colorSettings) { + return undefined; + } + + if (colorSettings) { + return colorSettings; + } + + if (oldColor) { + return getColorSettingsWithValue(computeColorFromToken(oldColor), enableMultiThemeColors); + } + return getColorSettingsWithValue( + computeColorFromToken(defaultOldColor), + enableMultiThemeColors, + ); +} From 96cbe78ef8318a403ca9c0cffae1a8728b772549 Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Thu, 11 Dec 2025 22:48:31 +0300 Subject: [PATCH 7/9] change text color field --- src/shared/types/dash.ts | 2 +- .../DashKit/plugins/Title/Title.tsx | 2 +- .../DialogTitleWidget/DialogTitleWidget.tsx | 6 +++--- src/ui/units/dash/containers/App/App.tsx | 5 ++++- src/ui/units/dash/containers/Dash/Dash.tsx | 9 +++++++-- src/ui/units/dash/store/actions/dashTyped.ts | 4 ++++ src/ui/units/dash/store/reducers/dash.js | 1 + src/ui/utils/copyItems.ts | 20 +++++++++++++------ 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/shared/types/dash.ts b/src/shared/types/dash.ts index 95a92733e5..53403e07e6 100644 --- a/src/shared/types/dash.ts +++ b/src/shared/types/dash.ts @@ -232,7 +232,7 @@ export interface DashTabItemTitle extends DashTabItemBase { showInTOC: boolean; autoHeight?: boolean; textColor?: string; - textColorSettings?: ColorSettings; + textSettings?: {color?: ColorSettings}; hint?: HintSettings; }; } diff --git a/src/ui/components/DashKit/plugins/Title/Title.tsx b/src/ui/components/DashKit/plugins/Title/Title.tsx index cead8bb825..2b06b6ee3c 100644 --- a/src/ui/components/DashKit/plugins/Title/Title.tsx +++ b/src/ui/components/DashKit/plugins/Title/Title.tsx @@ -141,7 +141,7 @@ const titlePlugin: PluginTitle = { defaultOldColor: CustomPaletteBgColors.NONE, }); - const textColorStyles = useTextColorStyles(data.textColor, data.textColorSettings); + const textColorStyles = useTextColorStyles(data.textColor, data.textSettings?.color); const wrapperStyles = {...style, ...textColorStyles}; const currentLayout = props.layout.find(({i}) => i === props.id) || { diff --git a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx index fd0250991c..d6be084c3d 100644 --- a/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx +++ b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx @@ -190,7 +190,7 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { setColorSettings: setTextColorSettings, } = useColorSettings({ color: openedItemData.textColor, - colorSettings: openedItemData.textColorSettings, + colorSettings: openedItemData.textSettings?.color, defaultOldColor: CustomPaletteTextColors.PRIMARY, enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, isNewWidget, @@ -273,10 +273,10 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { const resultTextColorSettings: Pick< DashTabItemTitle['data'], - 'textColor' | 'textColorSettings' + 'textColor' | 'textSettings' > = textColorSettings || isDashColorPickersByThemeEnabled - ? {textColorSettings} + ? {textSettings: {color: textColorSettings}} : {textColor: oldTextColor}; if (Object.values(validationErrors).filter(Boolean).length === 0) { const resultedCustomFontSize = customFontSize ?? previousSelectedFontSize; diff --git a/src/ui/units/dash/containers/App/App.tsx b/src/ui/units/dash/containers/App/App.tsx index cec11dbb88..704fb0b29f 100644 --- a/src/ui/units/dash/containers/App/App.tsx +++ b/src/ui/units/dash/containers/App/App.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import {useThemeType} from '@gravity-ui/uikit'; import block from 'bem-cn-lite'; import LocationChange from 'components/LocationChange/LocationChange'; import {usePrevious} from 'hooks/usePrevious'; @@ -59,6 +60,8 @@ export function App({...routeProps}: RouteComponentProps) { const showAsideHeader = !isEmbedded && !isFullscreenMode && isAsideHeaderEnabled; const showMobileHeader = !isFullscreenMode && DL.IS_MOBILE; + const themeType = useThemeType(); + React.useMemo(() => { dispatch(initDashEditHistory()); }, []); @@ -111,7 +114,7 @@ export function App({...routeProps}: RouteComponentProps) { >
- +
{showFooter &&