-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useThemeVars): added hook useThemeVars (#1042)
issue - #1046
- Loading branch information
Showing
5 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# useThemeVars | ||
|
||
хук позволяет получить css переменные темы в JS - обьекте | ||
|
||
- [Переменные](#переменные) | ||
- [Дополнительные зависимости](#дополнительные-зависимости) | ||
|
||
## Переменные | ||
|
||
возможно указать какие переменные мы хотим получить из темы, | ||
по умолчанию вернуться все переменные темы входящей в пакет consta-uikit. | ||
|
||
Это полезно когда у вам либо не нужен весь список переменных, | ||
либо в ващей теме есть отличные от темы по умолчанию переменные | ||
|
||
```tsx | ||
const varsMap = { | ||
color: { | ||
primary: { | ||
... | ||
} | ||
accent: { | ||
... | ||
} | ||
invert: { | ||
... | ||
} | ||
}; | ||
control: { | ||
... | ||
}; | ||
font: { | ||
... | ||
}; | ||
size: { | ||
... | ||
}; | ||
space: { | ||
... | ||
}; | ||
} as const; | ||
|
||
const vars = useThemeVars({vars: varsMap}); | ||
``` | ||
|
||
## Дополнительные зависимости | ||
|
||
Пересчет переменных всегда зависит от [модификаторов темы](/?path=/docs/components-theme--playground#пресеты) | ||
если они не изменны от пересчет не происходит. Вы можете добавить свои зависимости, | ||
чтобы пересчет проиходил когда вам это требуется. | ||
|
||
Это полезно на пример когда у вас в теме используются медиа запросы, и размеры шрифта зависят от ширины экрана, | ||
тогда вам нужно прописать в `useThemeVars` текущий брейкпонит как зависимость | ||
|
||
```tsx | ||
const breakPoint = useBreakPoint(); | ||
const vars = useThemeVars({ deps: [breakPoint] }); | ||
``` | ||
|
||
## Свойства | ||
|
||
```tsx | ||
export type Vars = { | ||
readonly color: { | ||
readonly primary: readonly string[]; | ||
readonly accent: readonly string[]; | ||
readonly invert: readonly string[]; | ||
}; | ||
readonly control: readonly string[]; | ||
readonly font: readonly string[]; | ||
readonly size: readonly string[]; | ||
readonly space: readonly string[]; | ||
}; | ||
``` | ||
|
||
| Свойство | Тип | По умолчанию | Описание | | ||
| ---------------------- | ------ | ------------------------------------- | -------------------------- | | ||
| [`vars?`](#переменные) | `Vars` | набор переменных из темы по умолчанию | Переменные | | ||
| `deps?` | `[]` | - | Дополнительные зависимости | |
56 changes: 56 additions & 0 deletions
56
src/hooks/useThemeVars/__stories__/useThemeVars.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import './useThemeVarsStories.css'; | ||
|
||
import React from 'react'; | ||
|
||
import { Text } from '../../../components/Text/Text'; | ||
import { cn } from '../../../utils/bem'; | ||
import { createMetadata } from '../../../utils/storybook'; | ||
import { useThemeVars } from '../useThemeVars'; | ||
|
||
import mdx from './useThemeVars.mdx'; | ||
|
||
const cnUseThemeVars = cn('useThemeVars'); | ||
|
||
const Vars = (props: { vars: { [key: string]: string }; title: string }) => { | ||
const { vars, title } = props; | ||
return ( | ||
<div className={cnUseThemeVars('Section')}> | ||
<Text size="3xl" className={cnUseThemeVars('Title')}> | ||
{title} | ||
</Text> | ||
{Object.keys(vars).map((index) => ( | ||
<Text> | ||
{index}: {vars[index]} | ||
</Text> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
const Default = () => { | ||
const vars = useThemeVars(); | ||
|
||
return ( | ||
<> | ||
<Vars vars={vars.color.primary} title="Color" /> | ||
<Vars vars={vars.control} title="Control" /> | ||
<Vars vars={vars.font} title="Font" /> | ||
<Vars vars={vars.size} title="Size" /> | ||
<Vars vars={vars.space} title="Space" /> | ||
</> | ||
); | ||
}; | ||
|
||
export function Playground() { | ||
return <Default />; | ||
} | ||
|
||
export default createMetadata({ | ||
title: 'Hooks|/useThemeVars', | ||
id: 'Hooks|/useThemeVars', | ||
parameters: { | ||
docs: { | ||
page: mdx, | ||
}, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.useThemeVars { | ||
&-Title { | ||
margin-bottom: var(--space-m); | ||
} | ||
|
||
&-Section { | ||
margin-bottom: var(--space-l); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
const cssColorVars = [ | ||
'--color-bg-default', | ||
'--color-bg-secondary', | ||
'--color-bg-brand', | ||
'--color-bg-link', | ||
'--color-bg-border', | ||
'--color-bg-stripe', | ||
'--color-bg-ghost', | ||
'--color-bg-tone', | ||
'--color-bg-soft', | ||
'--color-bg-system', | ||
'--color-bg-normal', | ||
'--color-bg-success', | ||
'--color-bg-caution', | ||
'--color-bg-warning', | ||
'--color-bg-alert', | ||
'--color-bg-critical', | ||
'--color-typo-primary', | ||
'--color-typo-secondary', | ||
'--color-typo-ghost', | ||
'--color-typo-brand', | ||
'--color-typo-system', | ||
'--color-typo-normal', | ||
'--color-typo-success', | ||
'--color-typo-caution', | ||
'--color-typo-warning', | ||
'--color-typo-alert', | ||
'--color-typo-critical', | ||
'--color-typo-link', | ||
'--color-typo-link-minor', | ||
'--color-typo-link-hover', | ||
'--color-nums-shadow', | ||
'--color-scroll-bg', | ||
'--color-scroll-thumb', | ||
'--color-scroll-thumb-hover', | ||
'--color-control-bg-default', | ||
'--color-control-typo-default', | ||
'--color-control-typo-placeholder', | ||
'--color-control-bg-border-default', | ||
'--color-control-bg-border-default-hover', | ||
'--color-control-bg-border-focus', | ||
'--color-control-bg-focus', | ||
'--color-control-bg-active', | ||
'--color-control-bg-primary', | ||
'--color-control-bg-primary-hover', | ||
'--color-control-typo-primary', | ||
'--color-control-typo-primary-hover', | ||
'--color-control-bg-secondary', | ||
'--color-control-bg-border-secondary', | ||
'--color-control-bg-border-secondary-hover:', | ||
'--color-control-typo-secondary', | ||
'--color-control-typo-secondary-hover', | ||
'--color-control-bg-ghost', | ||
'--color-control-bg-ghost-hover', | ||
'--color-control-typo-ghost', | ||
'--color-control-typo-ghost-hover', | ||
'--color-control-bg-clear', | ||
'--color-control-bg-clear-hover', | ||
'--color-control-typo-clear', | ||
'--color-control-typo-clear-hover', | ||
'--color-control-bg-disable', | ||
'--color-control-bg-border-disable', | ||
'--color-control-typo-disable', | ||
] as const; | ||
|
||
const cssControlVars = [ | ||
'--control-radius', | ||
'--control-border-width', | ||
'--control-height-l', | ||
'--control-height-m', | ||
'--control-height-s', | ||
'--control-height-xs', | ||
'--control-box-size-m', | ||
'--control-box-size-l', | ||
'--control-space-l', | ||
'--control-space-m', | ||
'--control-space-s', | ||
'--control-space-xs', | ||
'--control-text-size-l', | ||
'--control-text-size-m', | ||
'--control-text-size-s', | ||
'--control-text-size-xs', | ||
] as const; | ||
|
||
const cssFontVars = ['--font-primary', '--font-mono'] as const; | ||
|
||
const cssSizeVars = [ | ||
'--size-text-2xs', | ||
'--size-text-xs', | ||
'--size-text-s', | ||
'--size-text-m', | ||
'--size-text-l', | ||
'--size-text-xl', | ||
'--size-text-2xl', | ||
'--size-text-3xl', | ||
'--size-text-4xl', | ||
'--size-text-5xl', | ||
'--size-text-6xl', | ||
'--line-height-text-2xs', | ||
'--line-height-text-xs', | ||
'--line-height-text-s', | ||
'--line-height-text-m', | ||
'--line-height-text-l', | ||
] as const; | ||
|
||
const cssSpaceVars = [ | ||
'--space-3xs', | ||
'--space-2xs', | ||
'--space-xs', | ||
'--space-s', | ||
'--space-m', | ||
'--space-l', | ||
'--space-xl', | ||
'--space-2xl', | ||
'--space-3xl', | ||
'--space-4xl', | ||
'--space-5xl', | ||
'--space-6xl', | ||
] as const; | ||
|
||
export const defaultVars = { | ||
color: { | ||
primary: cssColorVars, | ||
accent: cssColorVars, | ||
invert: cssColorVars, | ||
}, | ||
control: cssControlVars, | ||
font: cssFontVars, | ||
size: cssSizeVars, | ||
space: cssSpaceVars, | ||
} as const; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { useMemo } from 'react'; | ||
|
||
import { cnTheme, useTheme } from '../../components/Theme/Theme'; | ||
|
||
import { defaultVars } from './helpers'; | ||
|
||
export { defaultVars } from './helpers'; | ||
|
||
export type Vars = { | ||
readonly color: { | ||
readonly primary: readonly string[]; | ||
readonly accent: readonly string[]; | ||
readonly invert: readonly string[]; | ||
}; | ||
readonly control: readonly string[]; | ||
readonly font: readonly string[]; | ||
readonly size: readonly string[]; | ||
readonly space: readonly string[]; | ||
}; | ||
|
||
const getVars = <T extends string>( | ||
cssVars: readonly T[], | ||
element: HTMLDivElement, | ||
): { [key in T]: string } => { | ||
const vars: { [key in T]: string } = {} as { [key in T]: string }; | ||
|
||
const style = getComputedStyle(element); | ||
|
||
for (let i = 0; i < cssVars.length; i++) { | ||
vars[cssVars[i]] = style.getPropertyValue(cssVars[i]).trim(); | ||
} | ||
|
||
return vars; | ||
}; | ||
|
||
const addElement = (mods: {}): HTMLDivElement => { | ||
const element = document.createElement('div'); | ||
element.setAttribute('class', cnTheme(mods)); | ||
document.body.append(element); | ||
return element; | ||
}; | ||
|
||
type UseThemeVarsOptions<T> = { | ||
vars?: T; | ||
deps?: []; | ||
}; | ||
|
||
export const useThemeVars = <T extends Vars = typeof defaultVars>( | ||
options?: UseThemeVarsOptions<T>, | ||
) => { | ||
const variables = options?.vars || defaultVars; | ||
|
||
const { theme } = useTheme(); | ||
|
||
type ThemeVars = { | ||
color: { | ||
primary: { [key in T['color']['primary'][number]]: string }; | ||
accent: { [key in T['color']['accent'][number]]: string }; | ||
invert: { [key in T['color']['invert'][number]]: string }; | ||
}; | ||
control: { [key in T['control'][number]]: string }; | ||
font: { [key in T['font'][number]]: string }; | ||
size: { [key in T['size'][number]]: string }; | ||
space: { [key in T['space'][number]]: string }; | ||
}; | ||
|
||
return useMemo(() => { | ||
const elementPrimary = addElement({ | ||
...theme, | ||
color: theme.color.primary, | ||
}); | ||
const elementAccent = addElement({ color: theme.color.accent }); | ||
const elementInvert = addElement({ color: theme.color.invert }); | ||
|
||
const themeVars: ThemeVars = { | ||
color: { | ||
primary: getVars<T['color']['primary'][number]>(variables.color.primary, elementPrimary), | ||
accent: getVars<T['color']['accent'][number]>(variables.color.accent, elementAccent), | ||
invert: getVars<T['color']['invert'][number]>(variables.color.invert, elementInvert), | ||
}, | ||
control: getVars<T['control'][number]>(variables.control, elementPrimary), | ||
font: getVars<T['font'][number]>(variables.font, elementPrimary), | ||
size: getVars<T['size'][number]>(variables.size, elementPrimary), | ||
space: getVars<T['space'][number]>(variables.space, elementPrimary), | ||
}; | ||
|
||
document.body.removeChild(elementPrimary); | ||
document.body.removeChild(elementAccent); | ||
document.body.removeChild(elementInvert); | ||
|
||
return themeVars; | ||
}, [ | ||
theme.color.primary, | ||
theme.color.accent, | ||
theme.color.invert, | ||
theme.control, | ||
theme.font, | ||
theme.size, | ||
theme.space, | ||
...(options?.deps ? options.deps : []), | ||
]); | ||
}; |