From a2afd17ef491782106ff0229910dad85086f81f1 Mon Sep 17 00:00:00 2001 From: Neretin Artem Date: Wed, 20 Mar 2024 22:16:01 +0500 Subject: [PATCH] feat(plasma-theme-builder): Add generate tokens state value --- .../src/builder/createTheme.ts | 69 +++++++++++++++++-- .../src/components/TokenForm/TokenForm.tsx | 29 +++++++- .../plasma-theme-builder/src/utils/themes.tsx | 10 ++- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/website/plasma-theme-builder/src/builder/createTheme.ts b/website/plasma-theme-builder/src/builder/createTheme.ts index 6750365213..8b6211dfbc 100644 --- a/website/plasma-theme-builder/src/builder/createTheme.ts +++ b/website/plasma-theme-builder/src/builder/createTheme.ts @@ -16,33 +16,89 @@ import { } from './themeTokenGetters'; import type { TextIconsTokenName, ControlsSurfacesName, BackgroundName, OverlayName } from './themeTokenGetters'; -import type { Theme } from '../types'; +import type { Theme, TokenData } from '../types'; +import { sectionToFormulaMap, getStateToken } from '../utils'; + +const getStatTokens = ( + section: string, + name: string, + mode: ThemeMode, + tokens?: Record>>, +) => { + let defaultStateTokens = undefined; + let onDarkStateTokens = undefined; + let onLightStateTokens = undefined; + let inverseStateTokens = undefined; + const sectionName = sectionToFormulaMap[section]; + + if (!sectionName || !tokens) { + return { defaultStateTokens, onDarkStateTokens, onLightStateTokens, inverseStateTokens }; + } + + const getDefaultStateToken = getStateToken(sectionName, mode, tokens[mode].default); + defaultStateTokens = { + [`${name}Hover`]: getDefaultStateToken('hover'), + [`${name}Active`]: getDefaultStateToken('active'), + }; + + const getOnDarkStateToken = getStateToken(sectionName, mode, tokens[mode].onDark); + onDarkStateTokens = { + [`${name}Hover`]: getOnDarkStateToken('hover'), + [`${name}Active`]: getOnDarkStateToken('active'), + }; + + const getOnLightStateToken = getStateToken(sectionName, mode, tokens[mode].onLight); + onLightStateTokens = { + [`${name}Hover`]: getOnLightStateToken('hover'), + [`${name}Active`]: getOnLightStateToken('active'), + }; + + const getInverseStateToken = getStateToken(sectionName, mode, tokens[mode].inverse); + inverseStateTokens = { + [`${name}Hover`]: getInverseStateToken('hover'), + [`${name}Active`]: getInverseStateToken('active'), + }; + + return { defaultStateTokens, onDarkStateTokens, onLightStateTokens, inverseStateTokens }; +}; const getTokensByGroups = ( tokenGetters: Record, config: ThemeConfig, mode: ThemeMode, + section: string, ): TokensByType => { return Object.entries(tokenGetters).reduce( (tokensByGroup, [name, getter]) => { const tokens = getter(config); + const { defaultStateTokens, onDarkStateTokens, onLightStateTokens, inverseStateTokens } = getStatTokens( + section, + name, + mode, + tokens, + ); + return { default: { ...tokensByGroup.default, [name]: tokens[mode].default, + ...defaultStateTokens, }, onDark: { ...tokensByGroup.onDark, [name]: tokens[mode].onDark, + ...onDarkStateTokens, }, onLight: { ...tokensByGroup.onLight, [name]: tokens[mode].onLight, + ...onLightStateTokens, }, inverse: { ...tokensByGroup.inverse, [name]: tokens[mode].inverse, + ...inverseStateTokens, }, }; }, @@ -59,6 +115,7 @@ const getTokensBackgroundByGroups = ( tokenGetters: Record, config: ThemeConfig, mode: ThemeMode, + section: string, ): TokensBackgroundByType => { return Object.entries(tokenGetters).reduce( (tokensByGroup, [name, getter]) => { @@ -94,11 +151,11 @@ const getTokensBackgroundByGroups = ( const getThemeModeTokens = (config: ThemeConfig, mode: T): Theme[T] => { return { - text: getTokensByGroups(textTokenGetters, config, mode), - surface: getTokensByGroups(surfaceTokenGetters, config, mode), - background: getTokensBackgroundByGroups(backgroundTokenGetters, config, mode), - overlay: getTokensByGroups(overlayTokenGetters, config, mode), - outline: getTokensByGroups(outlineTokenGetters, config, mode), + text: getTokensByGroups(textTokenGetters, config, mode, 'text'), + surface: getTokensByGroups(surfaceTokenGetters, config, mode, 'surface'), + background: getTokensBackgroundByGroups(backgroundTokenGetters, config, mode, 'background'), + overlay: getTokensByGroups(overlayTokenGetters, config, mode, 'overlay'), + outline: getTokensByGroups(outlineTokenGetters, config, mode, 'outline'), }; }; diff --git a/website/plasma-theme-builder/src/components/TokenForm/TokenForm.tsx b/website/plasma-theme-builder/src/components/TokenForm/TokenForm.tsx index 7cd839068b..6e82e350bf 100644 --- a/website/plasma-theme-builder/src/components/TokenForm/TokenForm.tsx +++ b/website/plasma-theme-builder/src/components/TokenForm/TokenForm.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent, useCallback, useState } from 'react'; import styled from 'styled-components'; import { Button, H3, Modal, Switch, TextField } from '@salutejs/plasma-b2c'; import { surfaceLiquid01 } from '@salutejs/plasma-tokens-b2c'; -import type { ThemeMode } from '@salutejs/plasma-tokens-utils'; +import { ThemeMode } from '@salutejs/plasma-tokens-utils'; import { FormField } from '../FormField/FormField'; import { SolidTokenValue } from '../SolidTokenValue/SolidTokenValue'; @@ -10,7 +10,8 @@ import { TypeTabs } from '../TypeTabs/TypeTabs'; import { GradientTokenValue } from '../GradientTokenValue/GradientTokenValue'; import { SBSansTextMono } from '../mixins'; -import type { MultiplatformValue, InputData, Theme as ThemeType } from '../../types'; +import type { MultiplatformValue, InputData, Theme as ThemeType, TokenData } from '../../types'; +import { sectionToFormulaMap, getStateToken } from '../../utils'; const Form = styled.form``; @@ -149,9 +150,32 @@ export const TokenForm = ({ const hasToken = themeData[themeMode][section.value][subsection.value][tokenName]; const cleanedValue = typeof value.value === 'string' ? value.value.replace(/[\s;]*/gm, '') : value.value; + const getStateTokens = (section: string, themeMode: ThemeMode): Record | undefined => { + const sectionName = sectionToFormulaMap[section]; + + if (!sectionName) { + return undefined; + } + + const data = { + value: cleanedValue, + comment: comment?.value, + enabled: enabled?.value, + }; + + const getStateTokenFunc = getStateToken(sectionName, themeMode, data); + + return { + [`${tokenName}Hover`]: getStateTokenFunc('hover'), + [`${tokenName}Active`]: getStateTokenFunc('active'), + }; + }; + const getDataByThemeMode = (themeMode: ThemeMode) => { delete themeData[themeMode][section.value][subsection.value][prevName.value]; + const stateTokens = getStateTokens(section.value, themeMode); + return { ...themeData[themeMode], [section.value]: { @@ -163,6 +187,7 @@ export const TokenForm = ({ comment: comment?.value, enabled: enabled?.value, }, + ...stateTokens, }, }, }; diff --git a/website/plasma-theme-builder/src/utils/themes.tsx b/website/plasma-theme-builder/src/utils/themes.tsx index 88264330f6..3c183473da 100644 --- a/website/plasma-theme-builder/src/utils/themes.tsx +++ b/website/plasma-theme-builder/src/utils/themes.tsx @@ -5,7 +5,7 @@ import { createTheme } from '../builder/createTheme'; import { getFilesSource } from '../api'; import { getFormatDate, loadTheme } from '.'; import { THEME_BUILDER_PREFIX, BASE_PREFIX } from '../types'; -import type { Theme as ThemeType } from '../types'; +import type { FormulaMode, Theme as ThemeType } from '../types'; const StyledDate = styled.div` opacity: 0.5; @@ -144,3 +144,11 @@ export const getPrefix = (themeName?: string, branchName?: string) => { export const getFullThemeName = (themeName?: string, branchName?: string) => `${getPrefix(themeName, branchName)}${themeName}`; + +// TODO: Подумать как сделать этот список динамическим, либо добавить механизм к группе +// который будет указывать как применять формулы для генерации active и hover состояний +export const sectionToFormulaMap: Record = { + text: 'stroke', + outline: 'stroke', + surface: 'fill', +};