Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rm BEM #7655

Merged
merged 3 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
50 changes: 24 additions & 26 deletions docs/ADAPTIVITY_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import { useAdaptivity } from '../../hooks/useAdaptivity';
import styles from './Component.module.css';

const sizeXClassNames = {
none: styles['Component--sizeX-none'], // означает, что sizeX не определён в AdaptivityProvider – используем `@media`
compact: styles['Component--sizeX-compact'],
none: styles.hostSizeXNone, // означает, что sizeX не определён в AdaptivityProvider – используем `@media`
compact: styles.hostSizeXCompact,
};

const Component = () => {
Expand All @@ -42,7 +42,7 @@ const Component = () => {
return (
<div
className={classNames(
styles.Component,
styles.host,
// компонент слушает только compact
sizeX !== 'regular' && sizeXClassNames[sizeX],
)}
Expand All @@ -54,18 +54,18 @@ const Component = () => {
_Component.module.css_

```css
/* Равносильно модификатору `Component--sizeX-regular` */
.Component {
/* Равносильно модификатору `sizeXRegular` */
.host {
color: red;
padding: 20px;
}

.Component--sizeX-compact {
.sizeXCompact {
padding: 10px;
}

@media (--sizeX-compact) {
.Component--sizeX-none {
.sizeXNone {
padding: 10px;
}
}
Expand All @@ -91,9 +91,9 @@ import { ViewWidth, viewWidthToClassName } from '../../../lib/adaptivity';
import styles from './Component.module.css';

const viewWidthClassNames = {
none: styles['Component--viewWidth-none'], // означает, что viewWidth не определён в AdaptivityProvider – используем `@media`
smallTabletMinus: styles['Component--viewWidth-smallTabletMinus'],
smallTabletPlus: styles['Component--viewWidth-smallTabletPlus'],
none: styles.viewWidthNone, // означает, что viewWidth не определён в AdaptivityProvider – используем `@media`
smallTabletMinus: styles.viewWidthSmallTabletMinus,
smallTabletPlus: styles.viewWidthSmallTabletPlus,
};

const Component = () => {
Expand All @@ -110,26 +110,26 @@ const Component = () => {
_Component.module.css_

```css
.Component {
.host {
color: red;
}

.Component--viewWidth-smallTabletPlus {
.viewWidthSmallTabletPlus {
color: blue;
}

@media (--viewWidth-smallTabletPlus) {
.Component--viewWidth-none {
.viewWidthNone {
color: blue;
}
}

.Component--viewWidth-smallTabletMinus {
.viewWidthSmallTabletMinus {
color: green;
}

@media (--viewWidth-smallTabletMinus) {
.Component--viewWidth-none {
.viewWidthNone {
color: green;
}
}
Expand All @@ -148,23 +148,21 @@ _Component.module.css_
В процессе перевода существующих компонентов на новую систему адаптивности возникли места, в которых пришлось отступить
от стандартного поведения.

- `.Group--mode-none`
- `.modeNone`

В компоненте [Group](../packages/vkui/src/components/Group/Group.tsx) появился класс `.Group--mode-none`. Он означает, что у `Group`
не передан `mode` и не удалось вычислить его автоматически. `.Group--mode-none` должен вести себя как
`.Group--mode-card` при `sizeX=regular` и как `.Group--mode-plain` при `sizeX=compact`. Пример использования:
В компоненте [Group](../packages/vkui/src/components/Group/Group.tsx) появился класс `.modeNone`. Он означает, что у `Group`
не передан `mode` и не удалось вычислить его автоматически. `.modeNone` должен вести себя как
`.modeCard` при `sizeX=regular` и как `.modePlain` при `sizeX=compact`. Пример использования:

```css
.Group--mode-card .CardGrid {
padding-left: 8px;
padding-right: 8px;
.modeCard .сomponent {
padding-inline: 8px;
}

@media (--sizeX-regular) {
/* Применяем стили `.Group--mode-card`, если не задан `mode` и `sizeX=regular` */
.Group--mode-none .CardGrid {
padding-left: 8px;
padding-right: 8px;
/* Применяем стили `.modeCard`, если не задан `mode` и `sizeX=regular` */
.modeNone .in {
padding-inline: 8px;
}
}
```
Expand Down
14 changes: 3 additions & 11 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ git config blame.ignoreRevsFile .git-blame-ignore-revs
> Не используем композицию, т.к. в ней нет необходимости,
> а также в будущем она может усложнить переход на другое решение.

- CSS-классы названы по БЭМ: `.Component__element-name--modificator`. [Гайд по написанию стилей](https://github.com/VKCOM/VKUI/blob/master/docs/CSS_GUIDE.md)
- CSS-классы должны быть в формате camelCase: `elementNameModification`. [Гайд по написанию стилей](https://github.com/VKCOM/VKUI/blob/master/docs/CSS_GUIDE.md)
- Свойства `className` и `style` навешиваются на корневой элемент компонента
- Свойства, не используемые в коде компонента, навешиваются на **главный** элемент компонента. По умолчанию главным является корневой элемент:

Expand All @@ -58,11 +58,7 @@ git config blame.ignoreRevsFile .git-blame-ignore-revs
const Input = ({ mode, style, className, ...restProps }) => {
return (
<div
className={classNames(
className,
styles.Input,
mode === 'default' && styles['Input--mode-default'],
)}
className={classNames(className, styles.host, mode === 'default' && styles.modeDefault)}
style={style}
>
<input {...restProps} />
Expand All @@ -78,11 +74,7 @@ git config blame.ignoreRevsFile .git-blame-ignore-revs

const Component = ({ mode = 'default', className, ...restProps }) => (
<div
className={classNames(
className,
styles.Component,
mode === 'default' && styles['Component--mode-default'],
)}
className={classNames(className, styles.host, mode === 'default' && styles.modeDefault)}
{...restProps}
/>
);
Expand Down
87 changes: 41 additions & 46 deletions docs/CSS_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@

## Соглашения

- Используем БЭМ-нотацию
- Блок начинается с заглавной буквы: `.Checkbox`
- Многословный блок разделяется через camelCase: `.ButtonGroup`
- Элемент от блока отделяется двумя подчеркиваниями: `.Checkbox__in`
- Многословные элементы разделяются через kebab-case: `.Banner__before-title`
- Модификатор отделяется двумя дефисами: `.Input--plain` (см. **Работа с модификаторами**)
- Многословные модификаторы разделяются через kebab-case или camelCase: `.Checkbox--sizeX-regular`
### Используйте camelCase для имён классов

Для всех `.module.css` файлов активирован линтер, который проверяет, чтобы локальные классы были в camelCase. Именно эти классы затем будут импортироваться в JS и именно они затем будут отображаться в инспекторе браузера, если вы решите посмотреть какой-то элемент. Такой формат выбран в том числе для удобства написания и отладки кода.

### Модификаторы

У модификаторов элемента должен быть префикс с названием этого элемента. Например,

```css
.container {
}
.containerPrimary {
}
.containerSecondary {
}

.text {
}
.textWithShadow {
}
```

### Работа с модификаторами

Expand All @@ -21,17 +35,17 @@ import { useCSSKeyframesAnimationController } from '../../lib/animation';
import styles from './Component.module.css';

const animationStateClassNames = {
enter: styles['Component--enter'],
entering: styles['Component--enter'],
entered: styles['Component--entered'],
exit: styles['Component--exit'],
exiting: styles['Component--exit'],
exited: styles['Component--exited'],
enter: styles.hostEnter,
entering: styles.hostEnter,
entered: styles.hostEntered,
exit: styles.hostExit,
exiting: styles.hostExit,
exited: styles.hostExited,
};

const platformClassNames = {
android: styles['Component--android'],
vkcom: styles['Component--vkcom'],
android: styles.hostAndroid,
vkcom: styles.hostVKCOM,
};

const Component = ({ className, children }) => {
Expand All @@ -41,7 +55,7 @@ const Component = ({ className, children }) => {
<div
className={classNames(
className,
styles.Component,
styles.host,
animationStateClassNames[animationState],
platform !== 'ios' && platformClassNames[platform],
)}
Expand All @@ -63,7 +77,7 @@ import styles from './Component.module.css';
const Component = ({ objectFit, children }) => {
return (
<div
className={classNames(className, styles.Component)}
className={classNames(className, styles.host)}
style={objectFit ? { '--vkui_internal_Component_object-fit': objectFit } : undefined}
>
{children}
Expand All @@ -73,31 +87,13 @@ const Component = ({ objectFit, children }) => {
```

```css
.Component {
.host {
--vkui_internal_Component_object-fit: initial;

object-fit: var(--vkui_internal_Component_object-fit);
}
```

## Связность стилей

Если компонент состоит из других компонентов, то для их модификации используем БЭМ-миксин. Пример:

```tsx
// Button.tsx
<button className={styles.Button}>
<Text className={styles.Button__text}>{children}</Text>
</button>
```

```css
/* Button.module.css */
.Button__text {
padding: 8px;
}
```

## Глобальные классы

Класс, который начинается с `vkui` и `vkuiInternal`, обозначает, что он глобальный. Например,
Expand All @@ -110,7 +106,7 @@ const Component = ({ objectFit, children }) => {

```jsx
// Cell.tsx
<div className={classNames(styles.Cell, 'vkuiInternalCell')}>{before}</div>
<div className={classNames(styles.host, 'vkuiInternalCell')}>{before}</div>
```

В `before` может быть `<Avatar />` или иконка из библиотеки `@vkontakte/icons`. И нам необходимо
Expand All @@ -121,7 +117,7 @@ const Component = ({ objectFit, children }) => {

```css
/* Avatar.module.css */
:global(.vkuiInternalCell) .Avatar {
:global(.vkuiInternalCell) .host {
margin-inline-end: 8px;
}
```
Expand All @@ -131,7 +127,7 @@ const Component = ({ objectFit, children }) => {

```css
/* Cell.module.css */
.Cell :global(.vkuiIcon) {
.host :global(.vkuiIcon) {
margin-inline-end: 10px;
}
```
Expand All @@ -142,14 +138,14 @@ const Component = ({ objectFit, children }) => {

```css
/* Text.module.css */
.Text {
.host {
margin: 0;
}
```

```css
/* Button.module.css */
.Button__text {
.text {
margin: 4px 0;
}
```
Expand All @@ -175,7 +171,7 @@ const Component = ({ objectFit, children }) => {

```css
/* Placeholder.module.css */
.Placeholder {
.host {
padding: 16px;
}
```
Expand All @@ -195,8 +191,7 @@ Button мы тоже наделяем возможностью рендерит

```css
/* Button.module.css */

.Button {
.host {
/* ... */
display: inline-block;
}
Expand All @@ -213,8 +208,8 @@ Button мы тоже наделяем возможностью рендерит
### Обращения к элементам другого блока

```css
/* Banner.css */
.Banner .Button__in {
/* Banner.module.css */
.host .vkuiButton__in {
padding-top: 4px;
}
```
Expand Down
2 changes: 1 addition & 1 deletion packages/vkui/package.swcrc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
[
"swc-plugin-css-modules",
{
"generate_scoped_name": "vkui[local]"
"generate_scoped_name": "vkui[folder]__[local]"
}
],
[
Expand Down
Loading
Loading