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/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..3133f9e042 100644 --- a/src/shared/modules/dash-scheme-converter.ts +++ b/src/shared/modules/dash-scheme-converter.ts @@ -7,18 +7,14 @@ import { DUPLICATED_WIDGET_BG_COLORS_PRESET, getDefaultDashWidgetBgColorByType, } from '../constants/widgets'; -import type {BackgroundSettings, DashData, DashTab, DashTabItem} from '../types'; -import { - DashTabConnectionKind, - DashTabItemControlElementType, - DashTabItemType, - isBackgroundSettings, -} from '../types'; +import type {DashData, DashTab, DashTabItem, OldBackgroundSettings} from '../types'; +import {DashTabConnectionKind, DashTabItemControlElementType, DashTabItemType} from '../types'; +import {isOldBackgroundSettings} from '../utils/dash'; 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 +38,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 +56,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 55ebcd88dd..4bcda586b7 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,24 +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 { - return ( - typeof value === 'object' && - value !== null && - 'color' in value && - typeof value.color === 'string' && - ('enabled' in value - ? typeof value.enabled === 'boolean' || value.enabled === undefined - : true) - ); -} +export type ColorSettings = ColorByTheme | string; +export type BackgroundSettings = {color?: ColorSettings}; + +export type TitleTextSettings = {color?: ColorSettings}; export interface DashTabItemBase { id: string; @@ -171,12 +168,16 @@ export interface DashTabItemBase { title?: string; } +export type DashTabItemBaseData = { + background?: OldBackgroundSettings; + backgroundSettings?: BackgroundSettings; +}; + export interface DashTabItemText extends DashTabItemBase { type: DashTabItemType.Text; - data: { + data: DashTabItemBaseData & { text: string; autoHeight?: boolean; - background?: BackgroundSettings; }; } @@ -189,20 +190,24 @@ export type DashTitleSize = export interface DashTabItemTitle extends DashTabItemBase { type: DashTabItemType.Title; - data: { + data: DashTabItemBaseData & { text: string; size: DashTitleSize; showInTOC: boolean; autoHeight?: boolean; - background?: BackgroundSettings; - textColor?: ColorSettings; + textColor?: string; + textSettings?: TitleTextSettings; hint?: HintSettings; }; } export interface DashTabItemWidget extends DashTabItemBase { type: DashTabItemType.Widget; - data: {hideTitle: boolean; tabs: DashTabItemWidgetTab[]; background?: BackgroundSettings}; + data: { + hideTitle: boolean; + tabs: DashTabItemWidgetTab[]; + backgroundSettings?: BackgroundSettings; + }; } export interface DashTabItemWidgetTab { @@ -217,7 +222,7 @@ export interface DashTabItemWidgetTab { params: StringParams; autoHeight?: boolean; enableActionParams?: boolean; - background?: BackgroundSettings; + background?: OldBackgroundSettings; } export interface DashTabItemControl extends DashTabItemBase { @@ -399,10 +404,9 @@ export interface DashStats { export interface DashTabItemImage extends DashTabItemBase { type: DashTabItemType.Image; - data: { + data: DashTabItemBaseData & { src: string; alt?: string; - background?: BackgroundSettings; preserveAspectRatio?: boolean; }; } 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/shared/utils/dash.ts b/src/shared/utils/dash.ts new file mode 100644 index 0000000000..27706e636d --- /dev/null +++ b/src/shared/utils/dash.ts @@ -0,0 +1,52 @@ +import type { + BackgroundSettings, + ColorByTheme, + ColorSettings, + OldBackgroundSettings, + TitleTextSettings, +} from '../types/dash'; + +export function isOldBackgroundSettings(value: unknown): value is OldBackgroundSettings { + return ( + typeof value === 'object' && + value !== null && + 'color' in value && + typeof value.color === 'string' && + ('enabled' in value + ? typeof value.enabled === 'boolean' || value.enabled === undefined + : true) + ); +} + +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 function isColorSettings(value: unknown): value is ColorSettings { + return typeof value === 'string' || isColorByTheme(value); +} +function isSettingsWithColor(value: unknown): value is {color?: ColorSettings} { + return ( + typeof value === 'object' && + value !== null && + 'color' in value && + (value.color === undefined || + typeof value.color === 'string' || + isColorSettings(value.color)) + ); +} + +export function isBackgroundSettings(value: unknown): value is BackgroundSettings { + return isSettingsWithColor(value); +} + +export function isTextSettings(value: unknown): value is TitleTextSettings { + return isSettingsWithColor(value); +} diff --git a/src/shared/utils/index.ts b/src/shared/utils/index.ts index 46fc69056e..4bdf36e1f3 100644 --- a/src/shared/utils/index.ts +++ b/src/shared/utils/index.ts @@ -5,3 +5,4 @@ export * from './date-time'; export * from './markup'; export * from './markdown'; export * from './dataset'; +export * from './dash'; 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..2b06b6ee3c 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.textSettings?.color); 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..593d779dbb 100644 --- a/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx +++ b/src/ui/components/DashKit/plugins/Widget/WidgetPlugin.tsx @@ -1,7 +1,8 @@ import React from 'react'; import type {Plugin} from '@gravity-ui/dashkit'; -import {CustomPaletteBgColors, isBackgroundSettings} from 'shared'; +import {CustomPaletteBgColors} from 'shared/constants'; +import {isOldBackgroundSettings} from 'shared/utils'; import type {ChartWidgetWithWrapRefProps} from 'ui/components/Widgets/Chart/types'; import MarkdownProvider from '../../../../modules/markdownProvider'; @@ -17,16 +18,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( @@ -41,13 +44,18 @@ 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: isBackgroundSettings(propsBg) ? propsBg : undefined, - globalBackground: props.background, + widgetBackground: oldWidgetBg, + 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}; 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..68070f88db 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'; @@ -141,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() { @@ -150,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, @@ -161,22 +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, - 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, @@ -186,6 +205,27 @@ function DialogChartWidget({ isManualTitle: false, tabParams: {}, legacyChanged: 0, + activeTab: TAB_TYPE.TABS, + }); + + const couldChangeOldBg = enableCustomBgColorSelector; + + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + } = useBackgroundColorSettings({ + background: couldChangeOldBg + ? openedItemData.tabs[0]?.background + : {color: CustomPaletteBgColors.LIKE_CHART}, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: couldChangeOldBg + ? CustomPaletteBgColors.NONE + : CustomPaletteBgColors.LIKE_CHART, + enableSeparateThemeColorSelector, + isNewWidget: !props.openedItemData, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -239,7 +279,7 @@ function DialogChartWidget({ ); const onApply = React.useCallback( - (argState: DialogChartWidgetState) => { + (argState: DialogChartWidgetState, resultedBg: typeof resultedBackgroundSettings) => { const isValidateParamTitle = isEnabledFeature( Feature.DashBoardWidgetParamsStrictValidation, ); @@ -254,6 +294,10 @@ function DialogChartWidget({ if (tabWithoutChartIdIndex === -1) { const newData = { + ...(resultedBg?.backgroundSettings + ? {backgroundSettings: resultedBg.backgroundSettings} + : {}), + hideTitle: tabs.length === 1 && hideTitle, tabs: tabs.map(({title, params, ...rest}, index) => { let resultTabParams = @@ -278,6 +322,7 @@ function DialogChartWidget({ }), params: resultTabParams, ...rest, + ...(resultedBg?.background ? {background: resultedBg.background} : {}), }; return tab; }), @@ -405,23 +450,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 +615,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 +797,10 @@ function DialogChartWidget({ } > @@ -855,7 +877,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..371b4f9601 100644 --- a/src/ui/components/DialogImageWidget/DialogImageWidget.tsx +++ b/src/ui/components/DialogImageWidget/DialogImageWidget.tsx @@ -7,12 +7,14 @@ 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'; +import {useBackgroundColorSettings} from '../DialogTitleWidget/useColorSettings'; import './DialogImageWidget.scss'; @@ -20,16 +22,29 @@ 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, - }, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), preserveAspectRatio: true, }; -export type DialogImageWidgetFeatureProps = {}; +export type DialogImageWidgetFeatureProps = { + enableSeparateThemeColorSelector?: boolean; +}; type Props = { openedItemId: string | null; @@ -59,7 +74,10 @@ export function DialogImageWidget(props: Props) { onClose, onApply, scope, + theme, + enableSeparateThemeColorSelector = true, } = props; + const isNewWidget = !props.openedItemData; const [data, setData] = React.useState(openedItemData); const [validationErrors, setValidationErrors] = React.useState>({}); const {DialogImageWidgetLinkHint} = registry.common.components.getAll(); @@ -68,6 +86,20 @@ export function DialogImageWidget(props: Props) { setData(resultData); }; + const { + oldBackgroundColor, + backgroundColorSettings, + setOldBackgroundColor, + setBackgroundColorSettings, + resultedBackgroundSettings, + } = useBackgroundColorSettings({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector, + isNewWidget, + }); + const handleSrcUpdate = (nextSrc: string) => { setValidationErrors({ ...validationErrors, @@ -77,14 +109,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 +187,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..c4077258c4 100644 --- a/src/ui/components/DialogTextWidget/DialogTextWidget.tsx +++ b/src/ui/components/DialogTextWidget/DialogTextWidget.tsx @@ -6,10 +6,12 @@ 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'; import {TextEditor} from '../TextEditor/TextEditor'; import './DialogTextWidget.scss'; @@ -19,6 +21,7 @@ const b = block('dialog-text'); export interface DialogTextWidgetFeatureProps { enableAutoheight?: boolean; enableCustomBgColorSelector?: boolean; + enableSeparateThemeColorSelector?: boolean; } export interface DialogTextWidgetProps extends DialogTextWidgetFeatureProps { @@ -36,22 +39,34 @@ interface DialogTextWidgetState { text?: string; prevVisible?: boolean; autoHeight?: boolean; - backgroundColor?: string; } 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, + enableCustomBgColorSelector = false, + enableSeparateThemeColorSelector = true, openedItemData = DEFAULT_OPENED_ITEM_DATA, dialogIsVisible, closeDialog, @@ -59,10 +74,25 @@ function DialogTextWidget(props: DialogTextWidgetProps) { openedItemId, } = props; + const isNewWidget = !props.openedItemData; + 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, + isNewWidget, }); const [prevDialogIsVisible, setPrevDialogIsVisible] = React.useState(); @@ -72,13 +102,26 @@ function DialogTextWidget(props: DialogTextWidgetProps) { } setPrevDialogIsVisible(dialogIsVisible); + updateStateByProps({ + background: openedItemData.background, + backgroundSettings: openedItemData.backgroundSettings, + defaultOldColor: CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector, + isNewWidget, + }); setState((prevState) => ({ ...prevState, text: openedItemData.text, autoHeight: Boolean(openedItemData.autoHeight), - backgroundColor: openedItemData.background?.color, })); - }, [openedItemData, dialogIsVisible, prevDialogIsVisible]); + }, [ + openedItemData, + dialogIsVisible, + prevDialogIsVisible, + enableSeparateThemeColorSelector, + updateStateByProps, + isNewWidget, + ]); const timeoutRef = React.useRef(null); @@ -116,29 +159,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/DialogTitleWidget/DialogTitleWidget.tsx b/src/ui/components/DialogTitleWidget/DialogTitleWidget.tsx index a08ebd2cc0..d6be084c3d 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 {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 { @@ -110,8 +117,18 @@ const defaultOpenedItemData: DashTabItemTitle['data'] = { size: FONT_SIZE_OPTIONS[0].value, showInTOC: true, autoHeight: false, - background: {color: CustomPaletteBgColors.NONE}, - textColor: CustomPaletteTextColors.PRIMARY, + ...(isDashColorPickersByThemeEnabled + ? { + backgroundSettings: { + color: undefined, + }, + } + : { + background: { + color: CustomPaletteBgColors.NONE, + }, + }), + textColor: undefined, }; function DialogTitleWidget(props: DialogTitleWidgetProps) { @@ -120,7 +137,8 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { dialogIsVisible, enableAutoheight = true, enableShowInTOC = true, - enableCustomBgColorSelector, + enableCustomBgColorSelector = false, + enableSeparateThemeColorSelector = true, enableCustomTextColorSelector = false, theme, closeDialog, @@ -128,6 +146,8 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { openedItemData = defaultOpenedItemData, } = props; + const isNewWidget = !props.openedItemData; + const [state, setState] = React.useState({ validation: {}, text: openedItemData.text, @@ -145,10 +165,37 @@ 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, + isNewWidget, + }); + + const { + oldColor: oldTextColor, + colorSettings: textColorSettings, + setOldColor: setOldTextColor, + setColorSettings: setTextColorSettings, + } = useColorSettings({ + color: openedItemData.textColor, + colorSettings: openedItemData.textSettings?.color, + defaultOldColor: CustomPaletteTextColors.PRIMARY, + enableSeparateThemeColorSelector: enableSeparateThemeColorSelector, + isNewWidget, + }); + const { text, fontSize, @@ -157,8 +204,6 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { validation, hint, autoHeight, - backgroundColor, - textColor, previousSelectedFontSize, } = state; @@ -225,6 +270,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' | 'textSettings' + > = + textColorSettings || isDashColorPickersByThemeEnabled + ? {textSettings: {color: textColorSettings}} + : {textColor: oldTextColor}; if (Object.values(validationErrors).filter(Boolean).length === 0) { const resultedCustomFontSize = customFontSize ?? previousSelectedFontSize; setItemData({ @@ -241,10 +294,8 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { : fontSize, showInTOC, autoHeight, - background: { - color: backgroundColor, - }, - textColor, + ...resultedBackgroundSettings, + ...resultTextColorSettings, hint, }, }); @@ -263,8 +314,9 @@ function DialogTitleWidget(props: DialogTitleWidgetProps) { previousSelectedFontSize, showInTOC, autoHeight, - backgroundColor, - textColor, + resultedBackgroundSettings, + oldTextColor, + textColorSettings, closeDialog, hint, ]); @@ -291,28 +343,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..4a4a237ebd --- /dev/null +++ b/src/ui/components/DialogTitleWidget/useColorSettings.ts @@ -0,0 +1,161 @@ +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; + isNewWidget: boolean; +}; + +const isDashColorPickersByThemeEnabled = isEnabledFeature(Feature.EnableDashColorPickersByTheme); + +export function useColorSettings(props: UseColorSettingsProps) { + 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; + colorSettings?: ColorSettings; + }>(getPartialStateFromProps(props)); + + const updateStateByProps = React.useCallback( + (propsLocal: UseColorSettingsProps) => { + setBgSettings(getPartialStateFromProps(propsLocal)); + }, + [getPartialStateFromProps], + ); + + const setOldColor = React.useCallback((color?: string) => { + setBgSettings({ + oldColor: color, + }); + }, []); + + const setColorSettings = React.useCallback((settings?: ColorSettings) => { + setBgSettings({ + oldColor: undefined, + colorSettings: settings, + }); + }, []); + + return { + oldColor, + colorSettings, + setOldColor, + setColorSettings, + updateStateByProps, + }; +} + +type UseBackgroundColorSettingsProps = { + background: OldBackgroundSettings | undefined; + backgroundSettings: BackgroundSettings | undefined; + defaultOldColor: string | undefined; + enableSeparateThemeColorSelector: boolean; + isNewWidget: boolean; +}; + +function getColorSettingsProps({ + background, + backgroundSettings, + defaultOldColor, + enableSeparateThemeColorSelector, + isNewWidget, +}: UseBackgroundColorSettingsProps): UseColorSettingsProps { + return { + color: + isNewWidget && isDashColorPickersByThemeEnabled + ? undefined + : getResultedOldBgColor(background, defaultOldColor), + colorSettings: backgroundSettings?.color, + defaultOldColor, + enableSeparateThemeColorSelector, + isNewWidget, + }; +} + +export function useBackgroundColorSettings({ + background, + backgroundSettings, + defaultOldColor = CustomPaletteBgColors.NONE, + enableSeparateThemeColorSelector = true, + isNewWidget, +}: UseBackgroundColorSettingsProps) { + const { + oldColor: oldBackgroundColor, + colorSettings: backgroundColorSettings, + setOldColor: setOldBackgroundColor, + setColorSettings: setBackgroundColorSettings, + updateStateByProps: updateStateByPropsColorSettings, + } = useColorSettings( + getColorSettingsProps({ + background, + backgroundSettings, + defaultOldColor, + enableSeparateThemeColorSelector, + isNewWidget, + }), + ); + + 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}; +} 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 &&