Skip to content

Commit 3669009

Browse files
committed
tech: mv breakpoints from js to ts
Т.к. `/src/shared/breakpoints.js` нужен только для `/scripts/generateCSSCustomMedias.js` внёс следующие изменения: 1. `/src/shared/breakpoints.js` -> `/src/lib/adaptivity/breakpoints.ts`; 2. `/scripts/generateCSSCustomMedias.js` -> `/scripts/generateCSSCustomMedias.mjs`; 3. перенёс `getCustomMedias()` из `shared.config.js` в `/scripts/generateCSSCustomMedias.mjs`; 4. `/src/lib/adaptivity/breakpoints.ts` в `/scripts/generateCSSCustomMedias.mjs` мы импортируем через `fs.readFileSync()` и последующий [ts.transpileModule()](https://github.com/Microsoft/TypeScript-wiki/blob/main/Using-the-Compiler-API.md#a-simple-transform-function). Выполняем код через [import()](https://2ality.com/2019/10/eval-via-import.html#evaluating-simple-code-via-import()). 5. в `/src/lib/adaptivity/types.ts` создал тип `CSSCustomMedias` и применяю его через JSDoc в `getCustomMedias()` – теперь `yarn workspace @vkontakte/vkui run lint:generated-files` будет падать с ошибкой если поменяли брейкпоинты, а в `getCustomMedias()` поправить забыли; 6. в `/styleguide/Components/Preview` заменил импорт `@vkui/shared/breakpoints` на `@vkui/lib/adaptivity`; 7. поправил `docs/ADAPTIVITY_GUIDE.md`
1 parent e728d24 commit 3669009

File tree

14 files changed

+145
-202
lines changed

14 files changed

+145
-202
lines changed

docs/ADAPTIVITY_GUIDE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
Изначально писать адаптивность стоит через **CSS Media Queries**.
1313

1414
Для медиа запросов мы используем [custom-media-queries](https://preset-env.cssdb.org/features/#custom-media-queries).
15-
Значения определяются в функции `getCustomMedias()` в [./packages/vkui/shared.config.js](../packages/vkui/shared.config.js).
15+
Текущие медиа запросы можно посмотреть в типе [CSSCustomMedias](../packages/vkui/src/lib/adaptivity/types.ts).
1616

1717
При разработке следует предусмотреть возможность переопределения параметров адаптивности через `AdaptivityProvider`.
1818

@@ -33,7 +33,7 @@ import styles from './Component.module.css';
3333

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

3939
const Component = () => {
@@ -136,7 +136,7 @@ _Component.module.css_
136136
```
137137

138138
По историческим причинам, в JS (см. [AdaptivityProvider](../packages/vkui/src/components/AdaptivityProvider/AdaptivityProvider.tsx))
139-
и в CSS (см. [getCustomMedias().js](../packages/vkui/shared.config.js)) по-разному определяются брейкпоинты. В CSS они
139+
и в CSS (см. [customMedias.generated.css](../packages/vkui/src/styles/customMedias.generated.css)) по-разному определяются брейкпоинты. В CSS они
140140
выходят более расширенными, а в JS ограничиваются точечными значениями. Для конвертации этой разницы создана функция [viewWidthToClassName](../packages/vkui/src/lib/adaptivity/functions.ts).
141141

142142
### Хук [useAdaptivityConditionalRender](../packages/vkui/src/hooks/useAdaptivityConditionalRender/useAdaptivityConditionalRender.tsx)

packages/vkui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656
"test:e2e-update": "./scripts/generate_env_docker.sh -u && docker compose --env-file=./.env.docker up --abort-on-container-exit",
5757
"test:e2e:ci": "yarn run -T playwright test --config playwright-ct.config.ts",
5858
"test:e2e-update:ci": "yarn run test:e2e:ci --update-snapshots",
59-
"lint:generated-files": "yarn run generate:css-custom-medias && git diff --exit-code src/styles/customMedias.generated.css",
59+
"lint:generated-files": "yarn run -T tsc scripts/generateCSSCustomMedias.mjs --checkJs --module ESNext --moduleResolution node --resolveJsonModule --allowSyntheticDefaultImports --noEmit && yarn run generate:css-custom-medias && git diff --exit-code src/styles/customMedias.generated.css",
6060
"storybook": "bash -c 'source .env && yarn run -T cross-env SANDBOX=\\.storybook storybook dev -p ${STORYBOOK_DEV_PORT:=6006}'",
6161
"storybook:build": "yarn run -T cross-env SANDBOX=\\.storybook FROM_STORYBOOK=1 storybook build",
62-
"generate:css-custom-medias": "node scripts/generateCSSCustomMedias.js"
62+
"generate:css-custom-medias": "node scripts/generateCSSCustomMedias.mjs"
6363
},
6464
"peerDependencies": {
6565
"react": "^18.2.0",

packages/vkui/scripts/generateCSSCustomMedias.js

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* eslint no-console: 0 */
2+
import fs from 'node:fs';
3+
import path from 'path';
4+
import ts from 'typescript';
5+
import { PATHS } from '../shared.config.js';
6+
7+
const inputSourceFilePath = path.resolve(
8+
import.meta.dirname,
9+
PATHS.JS_BREAKPOINTS.replace(PATHS.ROOT_DIR, '../'),
10+
);
11+
12+
const outputSourceFilePath = path.resolve(
13+
import.meta.dirname,
14+
PATHS.CSS_CUSTOM_MEDIAS.replace(PATHS.ROOT_DIR, '../'),
15+
);
16+
17+
/**
18+
* Возвращает медиа выражения необходимые по дизайн-системе. У ключей синтаксис должен быть как у CSS Custom Properties.
19+
*
20+
* > ❗️IMPORTANT❗️
21+
* > При изменении функции следует вызвать команду `yarn workspace @vkontakte/vkui run generate:css-custom-medias`,
22+
* > для обновления CSS файла, и закоммитить изменения.
23+
*
24+
* @link https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-media
25+
* @link https://github.com/Microsoft/TypeScript-wiki/blob/main/Using-the-Compiler-API.md#a-simple-transform-function
26+
* @link https://2ality.com/2019/10/eval-via-import.html#evaluating-simple-code-via-import()
27+
*
28+
* @returns {Promise<import('../src/lib/adaptivity').CSSCustomMedias>}
29+
*/
30+
export const getCustomMedias = async () => {
31+
const sourceTS = fs.readFileSync(inputSourceFilePath, 'utf-8').toString();
32+
const { outputText: sourceJS } = ts.transpileModule(sourceTS, {
33+
compilerOptions: { module: ts.ModuleKind.ESNext },
34+
});
35+
const { BREAKPOINTS, MEDIA_QUERIES, widthPlus, widthMinus, heightMinus, heightPlus } =
36+
await import(`data:text/javascript;charset=utf-8,${encodeURIComponent(sourceJS)}`);
37+
38+
return {
39+
'--sizeX-regular': widthPlus(BREAKPOINTS.SMALL_TABLET),
40+
'--sizeX-compact': widthMinus(BREAKPOINTS.SMALL_TABLET),
41+
42+
'--sizeY-compact': `(pointer: fine) and ${widthPlus(BREAKPOINTS.SMALL_TABLET)}, ${heightMinus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}`, // prettier-ignore
43+
'--sizeY-regular': `(pointer: coarse) and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}, (pointer: none) and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}, ${widthMinus(BREAKPOINTS.SMALL_TABLET)} and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}`, // prettier-ignore
44+
45+
'--hover-has': '(hover: hover) and (pointer: fine)', // см. https://github.com/VKCOM/VKUI/issues/3469
46+
'--hover-has-not': '(hover: none)',
47+
48+
'--pointer-has': '(pointer: fine)',
49+
'--pointer-has-not': '(pointer: coarse), (pointer: none)',
50+
51+
'--reduce-motion': 'screen and (prefers-reduced-motion: reduce)',
52+
53+
'--desktop': `${widthPlus(BREAKPOINTS.SMALL_TABLET)} and (pointer: fine), ${widthPlus(BREAKPOINTS.SMALL_TABLET)} and ${heightPlus(BREAKPOINTS.MEDIUM_HEIGHT)}`, // prettier-ignore
54+
'--mobile': `${widthMinus(BREAKPOINTS.SMALL_TABLET)}, (pointer: none) and ${heightMinus(BREAKPOINTS.MEDIUM_HEIGHT)}, (pointer: coarse) and ${heightMinus(BREAKPOINTS.MEDIUM_HEIGHT)}`, // prettier-ignore
55+
56+
'--viewWidth-desktopPlus': MEDIA_QUERIES.DESKTOP_PLUS,
57+
58+
'--viewWidth-tabletPlus': widthPlus(BREAKPOINTS.TABLET),
59+
'--viewWidth-tablet': MEDIA_QUERIES.TABLET,
60+
'--viewWidth-tabletMinus': widthMinus(BREAKPOINTS.TABLET),
61+
62+
'--viewWidth-smallTabletPlus': MEDIA_QUERIES.SMALL_TABLET_PLUS,
63+
'--viewWidth-smallTablet': MEDIA_QUERIES.SMALL_TABLET,
64+
'--viewWidth-smallTabletMinus': widthMinus(BREAKPOINTS.SMALL_TABLET),
65+
66+
'--viewWidth-mobilePlus': widthPlus(BREAKPOINTS.MOBILE),
67+
'--viewWidth-mobile': MEDIA_QUERIES.MOBILE,
68+
69+
'--viewWidth-smallMobileMinus': widthMinus(BREAKPOINTS.MOBILE),
70+
};
71+
};
72+
73+
async function main() {
74+
console.log('🔄 Processing...');
75+
76+
const customMedias = await getCustomMedias();
77+
const dataRaw = [];
78+
79+
dataRaw.push('/* ⚠️ Документ сгенерирован автоматически */');
80+
dataRaw.push('/* 📝 Если требуется изменения, то запустите команду `yarn workspace @vkontakte/vkui run generate:css-custom-medias` */'); // prettier-ignore
81+
dataRaw.push('');
82+
dataRaw.push('/* stylelint-disable */');
83+
dataRaw.push(
84+
Object.entries(customMedias)
85+
.map(([key, value]) => {
86+
return ['/* prettier-ignore */', `@custom-media ${key} ${value};`].join('\n');
87+
})
88+
.join('\n'),
89+
);
90+
dataRaw.push('');
91+
92+
const data = dataRaw.join('\n');
93+
94+
fs.writeFileSync(outputSourceFilePath, data, 'utf-8');
95+
96+
console.log(`✅ ${outputSourceFilePath}`);
97+
}
98+
99+
void main();

packages/vkui/shared.config.js

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
const iconPkg = require('../../node_modules/@vkontakte/icons/package.json');
22
const tokensPkg = require('../../node_modules/@vkontakte/vkui-tokens/package.json');
33
const pkg = require('./package.json');
4-
const {
5-
BREAKPOINTS,
6-
MEDIA_QUERIES,
7-
widthPlus,
8-
widthMinus,
9-
heightMinus,
10-
heightPlus,
11-
} = require('./src/shared/breakpoints');
124

135
module.exports.VERSION = pkg.version;
146

@@ -21,59 +13,11 @@ module.exports.URLS = {
2113
ICONS: iconPkg.homepage,
2214
};
2315

24-
/**
25-
* Возвращает медиа выражения необходимые по дизайн-системе. У ключей синтаксис должен быть как у CSS Custom Properties.
26-
*
27-
* > ❗️IMPORTANT❗️
28-
* > При изменении функции следует вызвать команду `yarn workspace @vkontakte/vkui run generate:css-custom-medias`,
29-
* > для обновления CSS файла, и закоммитить изменения.
30-
*
31-
* {@link https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-media}
32-
*/
33-
const getCustomMedias = () => {
34-
const customMedia = {
35-
'--sizeX-regular': widthPlus(BREAKPOINTS.SMALL_TABLET),
36-
'--sizeX-compact': widthMinus(BREAKPOINTS.SMALL_TABLET),
37-
38-
'--sizeY-compact': `(pointer: fine) and ${widthPlus(BREAKPOINTS.SMALL_TABLET)}, ${heightMinus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}`, // prettier-ignore
39-
'--sizeY-regular': `(pointer: coarse) and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}, (pointer: none) and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}, ${widthMinus(BREAKPOINTS.SMALL_TABLET)} and ${heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT)}`, // prettier-ignore
40-
41-
'--hover-has': '(hover: hover) and (pointer: fine)', // см. https://github.com/VKCOM/VKUI/issues/3469
42-
'--hover-has-not': '(hover: none)',
43-
44-
'--pointer-has': '(pointer: fine)',
45-
'--pointer-has-not': '(pointer: coarse), (pointer: none)',
46-
47-
'--reduce-motion': 'screen and (prefers-reduced-motion: reduce)',
48-
49-
'--desktop': `${widthPlus(BREAKPOINTS.SMALL_TABLET)} and (pointer: fine), ${widthPlus(BREAKPOINTS.SMALL_TABLET)} and ${heightPlus(BREAKPOINTS.MEDIUM_HEIGHT)}`, // prettier-ignore
50-
'--mobile': `${widthMinus(BREAKPOINTS.SMALL_TABLET)}, (pointer: none) and ${heightMinus(BREAKPOINTS.MEDIUM_HEIGHT)}, (pointer: coarse) and ${heightMinus(BREAKPOINTS.MEDIUM_HEIGHT)}`, // prettier-ignore
51-
52-
'--viewWidth-desktopPlus': MEDIA_QUERIES.DESKTOP_PLUS,
53-
54-
'--viewWidth-tabletPlus': widthPlus(BREAKPOINTS.TABLET),
55-
'--viewWidth-tablet': MEDIA_QUERIES.TABLET,
56-
'--viewWidth-tabletMinus': widthMinus(BREAKPOINTS.TABLET),
57-
58-
'--viewWidth-smallTabletPlus': MEDIA_QUERIES.SMALL_TABLET_PLUS,
59-
'--viewWidth-smallTablet': MEDIA_QUERIES.SMALL_TABLET,
60-
'--viewWidth-smallTabletMinus': widthMinus(BREAKPOINTS.SMALL_TABLET),
61-
62-
'--viewWidth-mobilePlus': widthPlus(BREAKPOINTS.MOBILE),
63-
'--viewWidth-mobile': MEDIA_QUERIES.MOBILE,
64-
65-
'--viewWidth-smallMobileMinus': widthMinus(BREAKPOINTS.MOBILE),
66-
};
67-
68-
return { customMedia };
69-
};
70-
71-
module.exports.getCustomMedias = getCustomMedias;
72-
7316
const ROOT_DIR = 'packages/vkui';
7417
const TS_CONFIG_FOR_DIST = `${ROOT_DIR}/tsconfig.dist.json`;
7518
const SRC_DIR = `${ROOT_DIR}/src`;
7619
const JS_MAIN_EXPORT = `${SRC_DIR}/vkui.js`;
20+
const JS_BREAKPOINTS = `${SRC_DIR}/lib/adaptivity/breakpoints.ts`;
7721
const COMPONENTS_DIR = `${SRC_DIR}/components`;
7822
const STYLES_DIR = `${SRC_DIR}/styles`;
7923
const CSS_CONSTANTS = `${STYLES_DIR}/constants.css`;
@@ -86,6 +30,7 @@ module.exports.PATHS = {
8630
ROOT_DIR,
8731
SRC_DIR,
8832
JS_MAIN_EXPORT,
33+
JS_BREAKPOINTS,
8934
TS_CONFIG_FOR_DIST,
9035
COMPONENTS_DIR,
9136
STYLES_DIR,

packages/vkui/src/components/Textarea/Textarea.e2e-playground.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ComponentPlayground, type ComponentPlaygroundProps } from '@vkui-e2e/playground-helpers';
2-
import { BREAKPOINTS } from '../../shared/breakpoints';
2+
import { BREAKPOINTS } from '../../lib/adaptivity';
33
import { AdaptivityProvider } from '../AdaptivityProvider/AdaptivityProvider';
44
import { AppRoot } from '../AppRoot/AppRoot';
55
import { AppearanceProvider } from '../AppearanceProvider/AppearanceProvider';
Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,59 @@
1-
/**
2-
* Храним брейкпоинты в JS файле для синхронизации значений между TS и CSS.
3-
*
4-
* @type {{
5-
* DESKTOP: 1280,
6-
* TABLET: 1024,
7-
* SMALL_TABLET: 768,
8-
* MOBILE: 320,
9-
* MOBILE_LANDSCAPE_HEIGHT: 415,
10-
* MEDIUM_HEIGHT: 720
11-
* }}
12-
*/
13-
const BREAKPOINTS = {
1+
export const BREAKPOINTS = {
142
DESKTOP: 1280,
153
TABLET: 1024,
164
SMALL_TABLET: 768,
175
MOBILE: 320,
186
MOBILE_LANDSCAPE_HEIGHT: 415,
197
MEDIUM_HEIGHT: 720,
20-
};
8+
} as const;
219

2210
/**
2311
* Луч [a;+∞)
24-
*
25-
* @param {number} a
26-
* @returns {string}
2712
*/
28-
function widthPlus(a) {
13+
export function widthPlus(a: number): string {
2914
return `(min-width: ${a}px)`;
3015
}
3116

3217
/**
3318
* Открытый луч (-∞;b)
34-
*
35-
* @param {number} b
36-
* @returns {string}
3719
*/
38-
function widthMinus(b) {
20+
export function widthMinus(b: number): string {
3921
// NOTE: `not` плохо поддерживается, поэтому используем max-width и вычитаем
4022
// от числа 0.1
4123
return `(max-width: ${b - 0.1}px)`;
4224
}
4325

4426
/**
4527
* Полуинтервал [a;b)
46-
*
47-
* @param {number} a
48-
* @param {number} b
49-
* @returns {string}
5028
*/
51-
function widthHalfInterval(a, b) {
29+
export function widthHalfInterval(a: number, b: number): string {
5230
return `${widthPlus(a)} and ${widthMinus(b)}`;
5331
}
5432

5533
/**
5634
* Луч [a;+∞)
57-
*
58-
* @param {number} a
59-
* @returns {string}
6035
*/
61-
function heightPlus(a) {
36+
export function heightPlus(a: number): string {
6237
return `(min-height: ${a}px)`;
6338
}
6439

6540
/**
6641
* Открытый луч (-∞;b)
67-
*
68-
* @param {number} b
69-
* @returns {string}
7042
*/
71-
function heightMinus(b) {
43+
export function heightMinus(b: number): string {
7244
// NOTE: `not` плохо поддерживается, поэтому используем max-width и вычитаем
7345
// от числа 0.1
7446
return `(max-height: ${b - 0.1}px)`;
7547
}
7648

7749
/**
7850
* Полуинтервал [a;b)
79-
*
80-
* @param {number} a
81-
* @param {number} b
82-
* @returns {string}
8351
*/
84-
function heightHalfInterval(a, b) {
52+
export function heightHalfInterval(a: number, b: number): string {
8553
return `${heightPlus(a)} and ${heightMinus(b)}`;
8654
}
8755

88-
const MEDIA_QUERIES = {
56+
export const MEDIA_QUERIES = {
8957
DESKTOP_PLUS: widthPlus(BREAKPOINTS.DESKTOP),
9058

9159
TABLET: widthHalfInterval(BREAKPOINTS.TABLET, BREAKPOINTS.DESKTOP),
@@ -98,15 +66,4 @@ const MEDIA_QUERIES = {
9866
MEDIUM_HEIGHT: heightPlus(BREAKPOINTS.MEDIUM_HEIGHT),
9967

10068
MOBILE_LANDSCAPE_HEIGHT: heightPlus(BREAKPOINTS.MOBILE_LANDSCAPE_HEIGHT),
101-
};
102-
103-
module.exports = {
104-
BREAKPOINTS,
105-
MEDIA_QUERIES,
106-
widthHalfInterval,
107-
widthPlus,
108-
widthMinus,
109-
heightHalfInterval,
110-
heightPlus,
111-
heightMinus,
112-
};
69+
} as const;

packages/vkui/src/lib/adaptivity/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { ValuesOfObject } from '../../types';
22

3-
export { BREAKPOINTS, MEDIA_QUERIES } from '../../shared/breakpoints';
4-
53
/**
64
* Public API.
75
* Брейкпоинты на ширину.

packages/vkui/src/lib/adaptivity/functions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Exact } from '../../types';
22
import { type PlatformType } from '../platform';
3+
import { BREAKPOINTS } from './breakpoints';
34
import {
4-
BREAKPOINTS,
55
SizeTypeValues,
66
VIEW_WIDTH_TO_CSS_BREAKPOINT_MAP,
77
ViewHeight,

0 commit comments

Comments
 (0)