From e5b8898293d7eefa13e7f5f0a8659337f86ab91e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Jun 2021 05:50:09 +0000 Subject: [PATCH 01/48] chore(release): 17.4.2 [skip ci] ## [17.4.2](https://github.com/alfa-laboratory/core-components/compare/v17.4.1...v17.4.2) (2021-06-09) ### Bug Fixes * **skeleton:** remove vars that purge kills ([886d1b2](https://github.com/alfa-laboratory/core-components/commit/886d1b24b144d9d277821d3264f71a93c7a1b146)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 735924f888..8b67516162 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [17.4.2](https://github.com/alfa-laboratory/core-components/compare/v17.4.1...v17.4.2) (2021-06-09) + + +### Bug Fixes + +* **skeleton:** remove vars that purge kills ([886d1b2](https://github.com/alfa-laboratory/core-components/commit/886d1b24b144d9d277821d3264f71a93c7a1b146)) + ## [17.4.1](https://github.com/alfa-laboratory/core-components/compare/v17.4.0...v17.4.1) (2021-06-08) diff --git a/package.json b/package.json index bb6843f0f0..c5e0ad07db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@alfalab/core-components", - "version": "17.4.1", + "version": "17.4.2", "private": true, "workspaces": [ "packages/*" From a72d447b4e9f1b2ac340909562108099b47f11ec Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Jun 2021 05:50:36 +0000 Subject: [PATCH 02/48] chore: publish - @alfalab/core-components-calendar-with-skeleton@2.0.3 - @alfalab/core-components-skeleton@1.4.1 --- packages/calendar-with-skeleton/CHANGELOG.md | 8 ++++++++ packages/calendar-with-skeleton/package.json | 4 ++-- packages/skeleton/CHANGELOG.md | 11 +++++++++++ packages/skeleton/package.json | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/calendar-with-skeleton/CHANGELOG.md b/packages/calendar-with-skeleton/CHANGELOG.md index 5266b5a637..6628caf9e5 100644 --- a/packages/calendar-with-skeleton/CHANGELOG.md +++ b/packages/calendar-with-skeleton/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.3](https://github.com/alfa-laboratory/core-components/compare/@alfalab/core-components-calendar-with-skeleton@2.0.2...@alfalab/core-components-calendar-with-skeleton@2.0.3) (2021-06-09) + +**Note:** Version bump only for package @alfalab/core-components-calendar-with-skeleton + + + + + ## [2.0.2](https://github.com/alfa-laboratory/core-components/compare/@alfalab/core-components-calendar-with-skeleton@2.0.1...@alfalab/core-components-calendar-with-skeleton@2.0.2) (2021-06-08) **Note:** Version bump only for package @alfalab/core-components-calendar-with-skeleton diff --git a/packages/calendar-with-skeleton/package.json b/packages/calendar-with-skeleton/package.json index dd0d9baf1a..bf6a3a085f 100644 --- a/packages/calendar-with-skeleton/package.json +++ b/packages/calendar-with-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alfalab/core-components-calendar-with-skeleton", - "version": "2.0.2", + "version": "2.0.3", "description": "CalendarWithSkeleton component", "keywords": [], "license": "MIT", @@ -21,7 +21,7 @@ }, "dependencies": { "@alfalab/core-components-calendar": "^2.0.1", - "@alfalab/core-components-skeleton": "^1.4.0", + "@alfalab/core-components-skeleton": "^1.4.1", "classnames": "^2.2.6", "react-transition-group": "^4.3.0" } diff --git a/packages/skeleton/CHANGELOG.md b/packages/skeleton/CHANGELOG.md index 58b9f5bd2e..07a21e2384 100644 --- a/packages/skeleton/CHANGELOG.md +++ b/packages/skeleton/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.1](https://github.com/alfa-laboratory/core-components/compare/@alfalab/core-components-skeleton@1.4.0...@alfalab/core-components-skeleton@1.4.1) (2021-06-09) + + +### Bug Fixes + +* **skeleton:** remove vars that purge kills ([886d1b2](https://github.com/alfa-laboratory/core-components/commit/886d1b24b144d9d277821d3264f71a93c7a1b146)) + + + + + # [1.4.0](https://github.com/alfa-laboratory/core-components/compare/@alfalab/core-components-skeleton@1.3.6...@alfalab/core-components-skeleton@1.4.0) (2021-06-08) diff --git a/packages/skeleton/package.json b/packages/skeleton/package.json index c23aacbf07..55876613c7 100644 --- a/packages/skeleton/package.json +++ b/packages/skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alfalab/core-components-skeleton", - "version": "1.4.0", + "version": "1.4.1", "description": "Skeleton component", "keywords": [], "license": "MIT", From f12e198a31935bd127d88c3caac957cde72fcd4c Mon Sep 17 00:00:00 2001 From: Dmitry Savkin Date: Thu, 10 Jun 2021 14:34:09 +0300 Subject: [PATCH 03/48] chore: add codemod for heading, label, paragraph (#690) * chore: add heading, label and paragraph codemode --- .prettierignore | 1 + bin/build.sh | 1 + docs/12.migrations.stories.mdx | 6 + jest.codemod.config.js | 1 + jest.config.js | 1 + lerna.json | 3 +- package.json | 1 + packages/codemod/.npmignore | 1 + packages/codemod/README.md | 35 +++ packages/codemod/bin/index.js | 67 ++++++ packages/codemod/package.json | 20 ++ .../__testfixtures__/transform.input.tsx | 16 ++ .../__testfixtures__/transform.output.tsx | 16 ++ .../src/heading/__tests__/transform.test.ts | 6 + packages/codemod/src/heading/transform.ts | 201 ++++++++++++++++++ .../__testfixtures__/transform.input.tsx | 21 ++ .../__testfixtures__/transform.output.tsx | 20 ++ .../src/label/__tests__/transform.test.ts | 6 + packages/codemod/src/label/transform.ts | 133 ++++++++++++ .../__testfixtures__/transform.input.tsx | 14 ++ .../__testfixtures__/transform.output.tsx | 14 ++ .../src/paragraph/__tests__/transform.test.ts | 6 + packages/codemod/src/paragraph/transform.ts | 128 +++++++++++ packages/codemod/src/utils/index.ts | 1 + packages/codemod/src/utils/utils.ts | 116 ++++++++++ yarn.lock | 23 +- 26 files changed, 856 insertions(+), 2 deletions(-) create mode 100644 .prettierignore create mode 100644 docs/12.migrations.stories.mdx create mode 100644 jest.codemod.config.js create mode 100644 packages/codemod/.npmignore create mode 100644 packages/codemod/README.md create mode 100755 packages/codemod/bin/index.js create mode 100644 packages/codemod/package.json create mode 100644 packages/codemod/src/heading/__testfixtures__/transform.input.tsx create mode 100644 packages/codemod/src/heading/__testfixtures__/transform.output.tsx create mode 100644 packages/codemod/src/heading/__tests__/transform.test.ts create mode 100644 packages/codemod/src/heading/transform.ts create mode 100644 packages/codemod/src/label/__testfixtures__/transform.input.tsx create mode 100644 packages/codemod/src/label/__testfixtures__/transform.output.tsx create mode 100644 packages/codemod/src/label/__tests__/transform.test.ts create mode 100644 packages/codemod/src/label/transform.ts create mode 100644 packages/codemod/src/paragraph/__testfixtures__/transform.input.tsx create mode 100644 packages/codemod/src/paragraph/__testfixtures__/transform.output.tsx create mode 100644 packages/codemod/src/paragraph/__tests__/transform.test.ts create mode 100644 packages/codemod/src/paragraph/transform.ts create mode 100644 packages/codemod/src/utils/index.ts create mode 100644 packages/codemod/src/utils/utils.ts diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..f48045523d --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +__testfixtures__ diff --git a/bin/build.sh b/bin/build.sh index cb0386b471..d2501f6d35 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -14,6 +14,7 @@ echo "start build on $CONCURRENCY parallel process" lerna exec --concurrency $CONCURRENCY \ --ignore @alfalab/core-components-vars \ --ignore @alfalab/core-components-themes \ + --ignore @alfalab/core-components-codemod \ -- $(pwd)/bin/rollup.sh # собираю css пакеты diff --git a/docs/12.migrations.stories.mdx b/docs/12.migrations.stories.mdx new file mode 100644 index 0000000000..43951430b2 --- /dev/null +++ b/docs/12.migrations.stories.mdx @@ -0,0 +1,6 @@ +import { Description } from '@storybook/addon-docs/blocks'; +import migrationsReadme from '../packages/codemod/README.md'; + + + +{migrationsReadme} diff --git a/jest.codemod.config.js b/jest.codemod.config.js new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/jest.codemod.config.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/jest.config.js b/jest.config.js index 79e5620fa1..171940c869 100644 --- a/jest.config.js +++ b/jest.config.js @@ -19,6 +19,7 @@ module.exports = { '\\.css$': 'identity-obj-proxy', }, testMatch: ['**/*.test.ts?(x)', '!**/*.screenshots.test.ts?(x)'], + testPathIgnorePatterns: ['codemod'], coverageReporters: ['lcov', 'text', 'text-summary', 'clover'], coveragePathIgnorePatterns: ['index.ts'], }; diff --git a/lerna.json b/lerna.json index 053b4864d2..a7963b6c68 100644 --- a/lerna.json +++ b/lerna.json @@ -9,7 +9,8 @@ "ignoreChanges": [ "*.stories.*", "**/__snapshots__/**", - "*.test.*" + "*.test.*", + "**/codemod/**" ] } diff --git a/package.json b/package.json index c5e0ad07db..b06e9dfee3 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lint:js": "eslint ./packages --ext .ts,.tsx,.js,.jsx", "test": "jest --watchAll=false --env=jsdom-sixteen", "test:screenshots": "jest --config=jest.screenshots.config.js", + "test:codemod": "jest --config=jest.codemod.config.js packages/codemod/", "format": "prettier --write \"./{packages,bin}/**/*.{ts,tsx,js,jsx,css,json}\"", "clean": "rimraf packages/*/{tsconfig.tsbuildinfo,dist} && rimraf {dist,build}", "cm": "git-cz", diff --git a/packages/codemod/.npmignore b/packages/codemod/.npmignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/packages/codemod/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/codemod/README.md b/packages/codemod/README.md new file mode 100644 index 0000000000..44590e226f --- /dev/null +++ b/packages/codemod/README.md @@ -0,0 +1,35 @@ +## Тулзы для миграции с arui-feather на core-components. + +С помощью данного cli-инструмента можно быстро заменить компоненты из arui-feather на компоненты из core-components. + +На данный момент, для замены доступны следуюшие компоненты из arui-feather: + +- Heading +- Paragraph +- Label + +### Использование + +1. Установить к себе на проект: + +```bash +$ yarn add --dev @alfalab/core-components-codemod +``` + +2. Заменить компоненты: + +Можно заменить сразу все доступные компоненты: + +```bash +$ ./node_modules/.bin/core-components-codemod src/**/*.tsx +``` + +Можно заменять компоненты частично. Например только Label и Paragraph: + +```bash +$ ./node_modules/.bin/core-components-codemod --components=Label,Paragraph src/**/*.tsx +``` + +В большинстве случаев можно заменить один компонент на другой и однозначно поменять ему пропсы. Но это не всегда возможно. В таких случаях вы увидите предупреждение, и должны будете руками поменять пропсы у компонента. + +Сейчас замена компонентов доступна только для кода, написанного на `typescript`. Если кому-то нужно мигрировать с `js` - дайте знать, докрутим. diff --git a/packages/codemod/bin/index.js b/packages/codemod/bin/index.js new file mode 100755 index 0000000000..24bbc24338 --- /dev/null +++ b/packages/codemod/bin/index.js @@ -0,0 +1,67 @@ +#! /usr/bin/env node +/* eslint-disable @typescript-eslint/no-var-requires, no-console */ + +const yargs = require('yargs/yargs'); +const shell = require('shelljs'); +const chalk = require('chalk'); +const path = require('path'); +const kebab = require('lodash.kebabcase'); +const { hideBin } = require('yargs/helpers'); + +const getTransformerPath = componentName => + path.resolve(__dirname, `../src/${kebab(componentName)}/transform.ts`); + +const availableComponentsTransformers = ['Label', 'Heading', 'Paragraph']; + +function main() { + const { argv } = yargs(hideBin(process.argv)); + + if (argv.help) { + // TODO: show help + return; + } + + if (!argv._ || argv._.length === 0) { + console.log( + chalk.red( + 'Укажите glob для файлов, которые нужно трансформировать, например src/**/*.tsx', + ), + ); + + return; + } + + if (argv.components && typeof argv.components !== 'string') { + console.log( + chalk.red( + 'Укажите компоненты, которые хотите заменить, например --components="Label,Heading,Paragraph"', + ), + ); + + return; + } + + let components = availableComponentsTransformers; + + if (argv.components) { + components = argv.components.split(','); + } + + components.forEach(componentName => { + if (!availableComponentsTransformers.includes(componentName)) { + console.log(chalk.yellow(`Для компонента ${componentName} еще нет трансформера`)); + return; + } + + const transformer = getTransformerPath(componentName); + + try { + console.log(chalk.green(`Трансформируем ${componentName}:`)); + shell.exec(`jscodeshift --parser=tsx --transform=${transformer} ${argv._.join(' ')}`); + } catch (error) { + console.log(chalk.red(error)); + } + }); +} + +main(); diff --git a/packages/codemod/package.json b/packages/codemod/package.json new file mode 100644 index 0000000000..20c68c7a20 --- /dev/null +++ b/packages/codemod/package.json @@ -0,0 +1,20 @@ +{ + "name": "@alfalab/core-components-codemod", + "version": "1.0.0", + "description": "Codemod tools for migrating from feather to core-components", + "keywords": [], + "license": "MIT", + "scripts": { + "postinstall": "npm i -g jscodeshift @types/jscodeshift lodash > /dev/null 2>&1 || exit 0" + }, + "publishConfig": { + "access": "public" + }, + "bin": "./bin/index.js", + "dependencies": { + "chalk": "^4.1.1", + "lodash.kebabcase": "^4.1.1", + "shelljs": "^0.8.4", + "yargs": "^17.0.1" + } +} diff --git a/packages/codemod/src/heading/__testfixtures__/transform.input.tsx b/packages/codemod/src/heading/__testfixtures__/transform.input.tsx new file mode 100644 index 0000000000..5d2aca3d6d --- /dev/null +++ b/packages/codemod/src/heading/__testfixtures__/transform.input.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import Heading from 'arui-feather/heading'; + +const someVar = false; + +export const Component = () => ( + + Heading xs + Heading s + Heading m + Heading l + Heading xl + Heading + Heading + +); diff --git a/packages/codemod/src/heading/__testfixtures__/transform.output.tsx b/packages/codemod/src/heading/__testfixtures__/transform.output.tsx new file mode 100644 index 0000000000..e3d2e195fe --- /dev/null +++ b/packages/codemod/src/heading/__testfixtures__/transform.output.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Typography } from '@alfalab/core-components/typography'; + +const someVar = false; + +export const Component = () => ( + + Heading xs + Heading s + Heading m + Heading l + Heading xl + Heading + Heading + +); diff --git a/packages/codemod/src/heading/__tests__/transform.test.ts b/packages/codemod/src/heading/__tests__/transform.test.ts new file mode 100644 index 0000000000..68504ef34d --- /dev/null +++ b/packages/codemod/src/heading/__tests__/transform.test.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line prefer-destructuring +const defineTest = require('jscodeshift/dist/testUtils').defineTest; + +jest.autoMockOff(); + +defineTest(__dirname, 'transform', null, 'transform', { parser: 'tsx' }); diff --git a/packages/codemod/src/heading/transform.ts b/packages/codemod/src/heading/transform.ts new file mode 100644 index 0000000000..9bf6635e22 --- /dev/null +++ b/packages/codemod/src/heading/transform.ts @@ -0,0 +1,201 @@ +/* eslint-disable no-param-reassign, no-shadow */ +import { + Transform, + JSXIdentifier, + StringLiteral, + ASTPath, + JSXElement, + JSCodeshift, + JSXOpeningElement, + FileInfo, +} from 'jscodeshift'; + +import { transformTypographyImports, renameAttribute, addStringAttribute, log } from '../utils'; + +const sizes = { + xs: 'xsmall', + s: 'small', + m: 'medium', + l: 'large', + xl: 'xlarge', +}; + +const tag = { + xs: 'h5', + s: 'h4', + m: 'h3', + l: 'h2', + xl: 'h1', +}; + +const transformSize = (j: JSCodeshift, openingElement: JSXOpeningElement, fileInfo: FileInfo) => { + const hasSizeProp = + j(openingElement).find(j.JSXAttribute, { name: { name: 'size' } }).length !== 0; + + /** + * Если указан size, то + */ + if (hasSizeProp) { + /** + * Выставляем соответствующий тэг + */ + j(openingElement) + .find(j.JSXAttribute, { name: { name: 'size' } }) + .forEach(({ node }) => { + /** + * Если размер указан явно, то выставляем соответствующий тэг + */ + if (node.value.type === 'StringLiteral') { + const nodeValue = node.value as StringLiteral; + + openingElement.attributes.push( + j.jsxAttribute( + j.jsxIdentifier('tag'), + j.stringLiteral(tag[nodeValue.value]), + ), + ); + } + }); + + /** + * Меняем size на view + */ + j(openingElement) + .find(j.JSXAttribute, { name: { name: 'size' } }) + .replaceWith(({ node }) => { + /** + * Если размер указан явно, то меняем значение + */ + if (node.value.type === 'StringLiteral') { + const nodeValue = node.value as StringLiteral; + + return j.jsxAttribute( + j.jsxIdentifier('view'), + j.stringLiteral(sizes[nodeValue.value]), + ); + } + + /** + * Если размер указан неявно (например, записан в переменную, или использовано выражение), + * то меняем название атрибута, значение оставляем как есть и выводим предупреждение + */ + node.name.name = 'view'; + + log( + `Не удалось определить значение 'view' у компонента Heading:\n${fileInfo.path}:${node.loc.start.line}\n`, + 'warning', + ); + + return node; + }); + } else { + /** + * Если size не указан, то выставляем view='xlarge', + * так как в фижере дефолтный size='xl' + */ + addStringAttribute(j, openingElement, { name: 'view', value: 'xlarge' }); + + /** + * Выставляем тэг h1 + */ + addStringAttribute(j, openingElement, { name: 'tag', value: 'h1' }); + } +}; + +const transformMargins = (j: JSCodeshift, openingElement: JSXOpeningElement) => { + const hasHasDefaultMarginsProp = + j(openingElement).find(j.JSXAttribute, { name: { name: 'hasDefaultMargins' } }).length !== + 0; + + /** + * Если указана пропса hasDefaultMargins, то + */ + if (hasHasDefaultMarginsProp) { + /** + * Удаляем ее, если она false + */ + j(openingElement) + .find(j.JSXAttribute, { + name: { name: 'hasDefaultMargins' }, + value: { expression: { value: false } }, + }) + .remove(); + + /** + * Меняем имя на defaultMargins, если он true + */ + j(openingElement) + .find(j.JSXAttribute, { + name: { name: 'hasDefaultMargins' }, + value: { expression: { value: true } }, + }) + .replaceWith(() => + j.jsxAttribute( + j.jsxIdentifier('defaultMargins'), + j.jsxExpressionContainer(j.booleanLiteral(true)), + ), + ); + } else { + /** + * Если hasDefaultMargins не указан, то выставляем defaultMargins='true', + * так как в фижере дефолтный hasDefaultMargins='true' + */ + openingElement.attributes.push( + j.jsxAttribute( + j.jsxIdentifier('defaultMargins'), + j.jsxExpressionContainer(j.booleanLiteral(true)), + ), + ); + } +}; + +const headingTransform: Transform = (fileInfo, api) => { + const j = api.jscodeshift; + const source = j(fileInfo.source); + + transformTypographyImports(j, source, { + from: 'arui-feather/heading', + }); + + /** + * Находим использование компонента Heading и меняем ему пропсы + */ + source.findJSXElements('Heading').forEach(path => { + j(path).replaceWith((path: ASTPath) => { + const { node } = path; + + const { openingElement, closingElement } = node; + + const openingElementName = openingElement.name as JSXIdentifier; + + openingElementName.name = 'Typography.TitleResponsive'; + + if (closingElement) { + const closingElementName = closingElement.name as JSXIdentifier; + closingElementName.name = 'Typography.TitleResponsive'; + } + + transformSize(j, openingElement, fileInfo); + + transformMargins(j, openingElement); + + renameAttribute(j, openingElement, { from: 'data-test-id', to: 'dataTestId' }); + + addStringAttribute(j, openingElement, { name: 'font', value: 'system' }); + + addStringAttribute(j, openingElement, { name: 'color', value: 'primary' }); + + return node; + }); + }); + + return source.toSource({ + quote: 'single', + // Не переносим строки, чтобы было удобнее писать тесты + wrapColumn: 1000, + }); +}; + +headingTransform.componentName = 'Heading'; + +export default headingTransform; diff --git a/packages/codemod/src/label/__testfixtures__/transform.input.tsx b/packages/codemod/src/label/__testfixtures__/transform.input.tsx new file mode 100644 index 0000000000..d8fc19cb8f --- /dev/null +++ b/packages/codemod/src/label/__testfixtures__/transform.input.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import Label from 'arui-feather/label'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Typography } from '@alfalab/core-components/typography'; + +const someVar = true; + +export const Component = () => ( + + + + + + + + + + + + +); diff --git a/packages/codemod/src/label/__testfixtures__/transform.output.tsx b/packages/codemod/src/label/__testfixtures__/transform.output.tsx new file mode 100644 index 0000000000..9d425fbc50 --- /dev/null +++ b/packages/codemod/src/label/__testfixtures__/transform.output.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Typography } from '@alfalab/core-components/typography'; + +const someVar = true; + +export const Component = () => ( + + Label s + Label m + Label l + Label xl + Label 2xl + Label 3xl + Label 4xl + Label without props + Label + Label + +); diff --git a/packages/codemod/src/label/__tests__/transform.test.ts b/packages/codemod/src/label/__tests__/transform.test.ts new file mode 100644 index 0000000000..68504ef34d --- /dev/null +++ b/packages/codemod/src/label/__tests__/transform.test.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line prefer-destructuring +const defineTest = require('jscodeshift/dist/testUtils').defineTest; + +jest.autoMockOff(); + +defineTest(__dirname, 'transform', null, 'transform', { parser: 'tsx' }); diff --git a/packages/codemod/src/label/transform.ts b/packages/codemod/src/label/transform.ts new file mode 100644 index 0000000000..3580b2ef43 --- /dev/null +++ b/packages/codemod/src/label/transform.ts @@ -0,0 +1,133 @@ +/* eslint-disable no-param-reassign, no-shadow */ +import { + Transform, + JSXIdentifier, + StringLiteral, + ASTPath, + JSXElement, + JSCodeshift, + JSXOpeningElement, + FileInfo, +} from 'jscodeshift'; + +import { transformTypographyImports, renameAttribute, addStringAttribute, log } from '../utils'; + +const componentSizeMap = { + s: 'Typography.Text', + m: 'Typography.Text', + l: 'Typography.Text', + xl: 'Typography.Title', + '2xl': 'Typography.Title', + '3xl': 'Typography.Title', + '4xl': 'Typography.Title', +}; + +const sizes = { + s: 'primary-small', + m: 'primary-medium', + l: 'primary-large', + xl: 'xsmall', + '2xl': 'medium', + '3xl': 'large', + '4xl': 'xlarge', +}; + +const transformSize = ( + j: JSCodeshift, + openingElement: JSXOpeningElement, + fileInfo: FileInfo, +): string => { + let size = 'm'; + let componentName = componentSizeMap[size]; + + j(openingElement) + .find(j.JSXAttribute, { name: { name: 'size' } }) + .replaceWith(({ node }) => { + /** + * Если размер указан явно, то меняем значение + */ + if (node.value.type === 'StringLiteral') { + const nodeValue = node.value as StringLiteral; + size = nodeValue.value; + componentName = componentSizeMap[size]; + + return j.jsxAttribute(j.jsxIdentifier('view'), j.stringLiteral(sizes[size])); + } + + /** + * Если размер указан неявно (например, записан в переменную, или использовано выражение), + * то меняем название атрибута, значение оставляем как есть и выводим предупреждение + */ + node.name.name = 'view'; + + log( + `Не удалось определить значение 'view' у компонента Label:\n${fileInfo.path}:${node.loc.start.line}\n`, + 'warning', + ); + + return node; + }); + + return componentName; +}; + +const labelTransform: Transform = (fileInfo, api) => { + const j = api.jscodeshift; + const source = j(fileInfo.source); + + transformTypographyImports(j, source, { + from: 'arui-feather/label', + }); + + /** + * Находим использование компонента Label и меняем ему пропсы + */ + source.findJSXElements('Label').forEach(path => { + j(path).replaceWith((path: ASTPath) => { + const { node } = path; + + const { openingElement, closingElement } = node; + + const openingElementName = openingElement.name as JSXIdentifier; + + const componentName = transformSize(j, openingElement, fileInfo); + + openingElementName.name = componentName; + + if (closingElement) { + const closingElementName = closingElement.name as JSXIdentifier; + closingElementName.name = componentName; + } + + renameAttribute(j, openingElement, { from: 'data-test-id', to: 'dataTestId' }); + + if (componentName === 'Typography.Title') { + addStringAttribute(j, openingElement, { name: 'font', value: 'system' }); + } + + addStringAttribute(j, openingElement, { name: 'color', value: 'primary' }); + + const hasIsNoWrapProp = + j(openingElement).find(j.JSXAttribute, { name: { name: 'isNoWrap' } }).length > 0; + + if (hasIsNoWrapProp) { + log( + `Свойство 'isNoWrap' не существует у компонента '${componentName}':\n${fileInfo.path}:${node.loc.start.line}\n`, + 'warning', + ); + } + + return node; + }); + }); + + return source.toSource({ + quote: 'single', + // Не переносим строки, чтобы было удобнее писать тесты + wrapColumn: 1000, + }); +}; + +labelTransform.componentName = 'Label'; + +export default labelTransform; diff --git a/packages/codemod/src/paragraph/__testfixtures__/transform.input.tsx b/packages/codemod/src/paragraph/__testfixtures__/transform.input.tsx new file mode 100644 index 0000000000..06f67c6ccc --- /dev/null +++ b/packages/codemod/src/paragraph/__testfixtures__/transform.input.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import Paragraph from 'arui-feather/paragraph'; + +const someVar = true; + +export const Component = () => ( + + Paragraph small + Paragraph normal + Paragraph lead + Paragraph + Paragraph + +); diff --git a/packages/codemod/src/paragraph/__testfixtures__/transform.output.tsx b/packages/codemod/src/paragraph/__testfixtures__/transform.output.tsx new file mode 100644 index 0000000000..06481c0a68 --- /dev/null +++ b/packages/codemod/src/paragraph/__testfixtures__/transform.output.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Typography } from '@alfalab/core-components/typography'; + +const someVar = true; + +export const Component = () => ( + + Paragraph small + Paragraph normal + Paragraph lead + Paragraph + Paragraph + +); diff --git a/packages/codemod/src/paragraph/__tests__/transform.test.ts b/packages/codemod/src/paragraph/__tests__/transform.test.ts new file mode 100644 index 0000000000..68504ef34d --- /dev/null +++ b/packages/codemod/src/paragraph/__tests__/transform.test.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line prefer-destructuring +const defineTest = require('jscodeshift/dist/testUtils').defineTest; + +jest.autoMockOff(); + +defineTest(__dirname, 'transform', null, 'transform', { parser: 'tsx' }); diff --git a/packages/codemod/src/paragraph/transform.ts b/packages/codemod/src/paragraph/transform.ts new file mode 100644 index 0000000000..3979e31ad0 --- /dev/null +++ b/packages/codemod/src/paragraph/transform.ts @@ -0,0 +1,128 @@ +/* eslint-disable no-param-reassign, no-shadow */ +import { + Transform, + JSXIdentifier, + StringLiteral, + ASTPath, + JSXElement, + JSCodeshift, + JSXOpeningElement, + FileInfo, +} from 'jscodeshift'; + +import { transformTypographyImports, renameAttribute, addStringAttribute, log } from '../utils'; + +const componentViewMap = { + small: 'primary-small', + normal: 'primary-medium', + lead: 'small', +}; + +const componentSizeMap = { + small: 'Typography.Text', + normal: 'Typography.Text', + lead: 'Typography.Title', +}; + +const transformSize = ( + j: JSCodeshift, + openingElement: JSXOpeningElement, + fileInfo: FileInfo, +): string => { + let size = 'normal'; + let componentName = componentSizeMap[size]; + + j(openingElement) + .find(j.JSXAttribute, { name: { name: 'view' } }) + .replaceWith(({ node }) => { + /** + * Если размер указан явно, то меняем значение + */ + if (node.value.type === 'StringLiteral') { + const nodeValue = node.value as StringLiteral; + size = nodeValue.value; + componentName = componentSizeMap[size]; + + return j.jsxAttribute( + j.jsxIdentifier('view'), + j.stringLiteral(componentViewMap[size]), + ); + } + + /** + * Если размер указан неявно (например, записан в переменную, или использовано выражение), + * то меняем название атрибута, значение оставляем как есть и выводим предупреждение + */ + node.name.name = 'view'; + + log( + `Не удалось определить значение 'view' у компонента Paragraph:\n${fileInfo.path}:${node.loc.start.line}\n`, + 'warning', + ); + + return node; + }); + + return componentName; +}; + +const paragraphTransform: Transform = (fileInfo, api) => { + const j = api.jscodeshift; + const source = j(fileInfo.source); + + transformTypographyImports(j, source, { + from: 'arui-feather/paragraph', + }); + + /** + * Находим использование компонента Heading и меняем ему пропсы + */ + source.findJSXElements('Paragraph').forEach(path => { + j(path).replaceWith((path: ASTPath) => { + const { node } = path; + + const { openingElement, closingElement } = node; + + const openingElementName = openingElement.name as JSXIdentifier; + + const componentName = transformSize(j, openingElement, fileInfo); + + openingElementName.name = componentName; + + if (closingElement) { + const closingElementName = closingElement.name as JSXIdentifier; + closingElementName.name = componentName; + } + + if (componentName === 'Typography.Title') { + addStringAttribute(j, openingElement, { name: 'weight', value: 'regular' }); + addStringAttribute(j, openingElement, { name: 'tag', value: 'h4' }); + addStringAttribute(j, openingElement, { name: 'font', value: 'system' }); + } + + renameAttribute(j, openingElement, { from: 'data-test-id', to: 'dataTestId' }); + addStringAttribute(j, openingElement, { name: 'color', value: 'primary' }); + + const hasMarkProp = + j(openingElement).find(j.JSXAttribute, { name: { name: 'mark' } }).length > 0; + + if (hasMarkProp) { + log( + `Свойство 'mark' не существует у компонента 'Typography.Text':\n${fileInfo.path}:${node.loc.start.line}\n`, + 'warning', + ); + } + + return node; + }); + }); + + return source.toSource({ + quote: 'single', + wrapColumn: 1000, + }); +}; + +paragraphTransform.componentName = 'Paragraph'; + +export default paragraphTransform; diff --git a/packages/codemod/src/utils/index.ts b/packages/codemod/src/utils/index.ts new file mode 100644 index 0000000000..04bca77e0d --- /dev/null +++ b/packages/codemod/src/utils/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/packages/codemod/src/utils/utils.ts b/packages/codemod/src/utils/utils.ts new file mode 100644 index 0000000000..f0f88dbbca --- /dev/null +++ b/packages/codemod/src/utils/utils.ts @@ -0,0 +1,116 @@ +import { JSCodeshift, Collection, JSXOpeningElement } from 'jscodeshift'; + +type TransformTypographyImportOpts = { + from: string; +}; + +type RenameAttributeOpts = { + from: string; + to: string; +}; + +type AddStringAttributeOpts = { + name: string; + value: string; +}; + +export const transformTypographyImports = ( + j: JSCodeshift, + source: Collection, + opts: TransformTypographyImportOpts, +) => { + const { from } = opts; + + const to = '@alfalab/core-components/typography'; + const componentName = 'Typography'; + + /** + * Импорты типографики + */ + const existedTypographyImports = source + .find(j.ImportSpecifier) + .filter(path => path.parent.value.source.value === to) + .map(path => path.parent); + + /** + * Импорты компонента, который надо заменить + */ + const imports = source + .find(j.ImportSpecifier) + .filter(path => path.parent.value.source.value === from) + .map(path => path.parent); + + /** + * Импорты компонента, который надо заменить (import default) + */ + const defaultImports = source + .find(j.ImportDefaultSpecifier) + .filter(path => path.parent.value.source.value === from) + .map(path => path.parent); + + if (existedTypographyImports.length > 0) { + /** + * Если типографика уже заимпортирована, то просто удаляем импорт компонента + */ + imports.remove(); + defaultImports.remove(); + } else { + /** + * Если типографика не заимпортирована, то заменяем импорт компонента на импорт типографики + */ + imports.replaceWith(() => + j.importDeclaration( + [j.importSpecifier(j.identifier(componentName))], + j.stringLiteral(to), + ), + ); + defaultImports.replaceWith(() => + j.importDeclaration( + [j.importSpecifier(j.identifier(componentName))], + j.stringLiteral(to), + ), + ); + } +}; + +export const renameAttribute = ( + j: JSCodeshift, + openingElement: JSXOpeningElement, + opts: RenameAttributeOpts, +) => { + const { from, to } = opts; + + j(openingElement) + .find(j.JSXAttribute, { name: { name: from } }) + .replaceWith(path => { + const { node } = path; + + node.name.name = to; + + return node; + }); +}; + +export const addStringAttribute = ( + j: JSCodeshift, + openingElement: JSXOpeningElement, + opts: AddStringAttributeOpts, +) => { + const { name, value } = opts; + + openingElement.attributes.push(j.jsxAttribute(j.jsxIdentifier(name), j.stringLiteral(value))); +}; + +type LogLevel = 'error' | 'warning' | 'info' | 'success'; + +const messageColor = { + error: '\x1b[31m', + warning: '\x1b[33m', + success: '\x1b[32m', + info: '\x1b[37m', +}; + +export const log = (message: string, level: LogLevel = 'error') => { + // eslint-disable-next-line no-console + console.log(`${messageColor[level]}%s\x1b[0m`, message); +}; diff --git a/yarn.lock b/yarn.lock index 5cb714ba54..c3cde9fd1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6587,6 +6587,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -19873,7 +19881,7 @@ shell-quote@1.7.2: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== -shelljs@^0.8.3: +shelljs@^0.8.3, shelljs@^0.8.4: version "0.8.4" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== @@ -22996,6 +23004,19 @@ yargs@^16.1.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" + integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" From 7ac698d119ac98a1b447f734ebfb44e19d0da519 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Thu, 17 Jun 2021 11:25:44 +0300 Subject: [PATCH 04/48] style(select): change optgroup label color (#701) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Михаил Корецкий --- ...actions-tests-click-open-select-select-one-item-4-snap.png | 4 ++-- .../src/__image_snapshots__/select-optgroup-click-snap.png | 4 ++-- .../src/__image_snapshots__/select-optgroup-default-snap.png | 4 ++-- packages/select/src/vars.css | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png b/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png index 3ba997b8d7..d9a722c928 100644 --- a/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png +++ b/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f4ccf170a9b7d4e883ea116c79725162d6f2f874103ebaffc82258f6bedc8f9 -size 12859 +oid sha256:51795776d3ac13b5516045fa82e37263ed95f8a27dde6595034c4f68f941eb8b +size 12873 diff --git a/packages/select/src/__image_snapshots__/select-optgroup-click-snap.png b/packages/select/src/__image_snapshots__/select-optgroup-click-snap.png index d47d81c7dc..b853304e05 100644 --- a/packages/select/src/__image_snapshots__/select-optgroup-click-snap.png +++ b/packages/select/src/__image_snapshots__/select-optgroup-click-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eaa80a30d311f21c0aaacff1271826f3d5c46abf7425883b065fbd9ea78ae252 -size 16083 +oid sha256:aea41caa31adcd9ef17e7504bbce055b2eecde2e09294ee45abcd73d7e9d4f16 +size 16149 diff --git a/packages/select/src/__image_snapshots__/select-optgroup-default-snap.png b/packages/select/src/__image_snapshots__/select-optgroup-default-snap.png index 04ba093be8..bd205b7841 100644 --- a/packages/select/src/__image_snapshots__/select-optgroup-default-snap.png +++ b/packages/select/src/__image_snapshots__/select-optgroup-default-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1cc51e0037728b40398ca48b2d34f568fda129f6f6c75075bb0c251b8262dd7 -size 15369 +oid sha256:b8f214b6baab732cb09b8bbafb076a27d3c6b268cf7f6af6ebb6c1f822683980 +size 15431 diff --git a/packages/select/src/vars.css b/packages/select/src/vars.css index ce8e67bb7e..631c039afb 100644 --- a/packages/select/src/vars.css +++ b/packages/select/src/vars.css @@ -42,7 +42,7 @@ /* optgroup */ - --select-optgroup-color: var(--color-light-text-tertiary); + --select-optgroup-color: var(--color-light-text-secondary); --select-optgroup-background: var(--color-light-bg-primary); --select-optgroup-left-padding: var(--gap-s); --select-optgroup-right-padding: var(--gap-s); From 0a3bab52278b4db8f327a8bf5da97cfb5acecc6a Mon Sep 17 00:00:00 2001 From: Alexander Yatsenko Date: Thu, 17 Jun 2021 11:26:20 +0300 Subject: [PATCH 05/48] fix(select): fix checkmark position on click theme (#699) --- packages/select/src/Component.stories.mdx | 1 - ...actions-tests-click-open-select-select-one-item-4-snap.png | 4 ++-- packages/select/src/components/option/index.module.css | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/select/src/Component.stories.mdx b/packages/select/src/Component.stories.mdx index 5ffd71b7cb..6af7fe089a 100644 --- a/packages/select/src/Component.stories.mdx +++ b/packages/select/src/Component.stories.mdx @@ -33,7 +33,6 @@ export const options = [ { key: '13', content: 'Dubnium' }, { key: '14', content: 'Seaborgium' }, { key: '15', content: 'Bohrium' }, - { key: '16', content: 'Очень длинный текст Очень длинный текст Очень длинный текст' }, ]; export const groups = [ diff --git a/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png b/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png index d9a722c928..33a8652937 100644 --- a/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png +++ b/packages/select/src/__image_snapshots__/select-interactions-tests-click-open-select-select-one-item-4-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51795776d3ac13b5516045fa82e37263ed95f8a27dde6595034c4f68f941eb8b -size 12873 +oid sha256:49d83ff7c45c7dec65b85dcf5e34244f6d7d1df72e42ce74d4ae7035054a790a +size 12867 \ No newline at end of file diff --git a/packages/select/src/components/option/index.module.css b/packages/select/src/components/option/index.module.css index bb7ed12c0f..12d1102d65 100644 --- a/packages/select/src/components/option/index.module.css +++ b/packages/select/src/components/option/index.module.css @@ -89,6 +89,7 @@ .content { overflow: hidden; text-overflow: ellipsis; + flex: 1; } .textContent { From 6c2f0e083ec94797e8193b19d8bbafd042a5c2a5 Mon Sep 17 00:00:00 2001 From: Artem Kononenko Date: Thu, 17 Jun 2021 11:26:30 +0300 Subject: [PATCH 06/48] feat(notification): add null autoCloseDelay (#698) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Кононенко Артем Игоревич --- packages/notification/src/Component.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/notification/src/Component.tsx b/packages/notification/src/Component.tsx index 6a102c6670..cd37e1fc85 100644 --- a/packages/notification/src/Component.tsx +++ b/packages/notification/src/Component.tsx @@ -34,7 +34,7 @@ export type NotificationProps = ToastPlateProps & { /** * Время до закрытия компонента */ - autoCloseDelay?: number; + autoCloseDelay?: number | null; /** * Использовать портал @@ -98,11 +98,13 @@ export const Notification = forwardRef( const [isClosing, setIsClosing] = useState(false); const startAutoCloseTimer = useCallback(() => { - autoCloseTimeoutRef.current = window.setTimeout(() => { - if (onCloseTimeout) { - onCloseTimeout(); - } - }, autoCloseDelay); + if (autoCloseDelay !== null) { + autoCloseTimeoutRef.current = window.setTimeout(() => { + if (onCloseTimeout) { + onCloseTimeout(); + } + }, autoCloseDelay); + } }, [autoCloseDelay, onCloseTimeout]); const stopAutoCloseTimer = useCallback(() => { From 12d542f11dddcd022c1ba895e4105115be0b98b2 Mon Sep 17 00:00:00 2001 From: Alexander Yatsenko Date: Thu, 17 Jun 2021 11:26:43 +0300 Subject: [PATCH 07/48] feat(select): add useSelectWithLoading preset (#693) --- packages/select/package.json | 1 + packages/select/src/Component.stories.mdx | 46 +++++++++++++++++++ packages/select/src/index.ts | 1 + packages/select/src/presets/index.ts | 1 + .../src/presets/useSelectWithLoading/hook.tsx | 38 +++++++++++++++ .../useSelectWithLoading/index.module.css | 7 +++ packages/select/tsconfig.json | 9 +++- 7 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 packages/select/src/presets/index.ts create mode 100644 packages/select/src/presets/useSelectWithLoading/hook.tsx create mode 100644 packages/select/src/presets/useSelectWithLoading/index.module.css diff --git a/packages/select/package.json b/packages/select/package.json index c7ea044c00..b65bd76b9d 100644 --- a/packages/select/package.json +++ b/packages/select/package.json @@ -23,6 +23,7 @@ "@alfalab/core-components-form-control": "^6.1.1", "@alfalab/core-components-input": "^6.1.3", "@alfalab/core-components-popover": "^4.0.0", + "@alfalab/core-components-skeleton": "^1.3.6", "@alfalab/hooks": "^1.0.0", "classnames": "^2.2.6", "downshift": "5.4.7", diff --git a/packages/select/src/Component.stories.mdx b/packages/select/src/Component.stories.mdx index 6af7fe089a..00da52c17f 100644 --- a/packages/select/src/Component.stories.mdx +++ b/packages/select/src/Component.stories.mdx @@ -540,3 +540,49 @@ const groups = [{ label='preventFlip' /> + + +## Пресеты + +### Селект со скелетной загрузкой + +```tsx live +const options = [ + { key: '1', content: 'Neptunium' }, + { key: '2', content: 'Plutonium' }, + { key: '3', content: 'Americium' }, + { key: '4', content: 'Curium' }, + { key: '5', content: 'Berkelium' }, + { key: '6', content: 'Californium' }, + { key: '7', content: 'Einsteinium' }, +]; + +function Example() { + const [loading, setLoading] = React.useState(true); + + const loadingProps = useSelectWithLoading({ + visibleOptions: 6, + loading, + }); + + const handleOpen = () => { + setLoading(true); + setTimeout(() => setLoading(false), 2000); + }; + + return ( + + + + + + + Custom counter + + + +`; + +exports[`Textarea Snapshots tests should match snapshot with default counter 1`] = ` +
+
+
+
+
+ +
+
+
+ + + 5/500 символов + +
+
+`; diff --git a/packages/textarea/src/component.screenshots.test.tsx b/packages/textarea/src/component.screenshots.test.tsx index 41a2077ad3..966a09e985 100644 --- a/packages/textarea/src/component.screenshots.test.tsx +++ b/packages/textarea/src/component.screenshots.test.tsx @@ -37,6 +37,19 @@ describe('Textarea | sprite', () => { size: { width: 240, height: 100 }, }), ], + [ + `${theme} - counter`, + createSpriteStorybookUrl({ + componentName: 'Textarea', + knobs: { + value: 'Компонент текстового поля ввода.', + block: true, + showCounter: true, + maxLength: 500, + }, + size: { width: 240, height: 100 }, + }), + ], ], screenshotOpts: { fullPage: true, diff --git a/packages/textarea/src/docs/component.stories.mdx b/packages/textarea/src/docs/component.stories.mdx new file mode 100644 index 0000000000..e64e46e32f --- /dev/null +++ b/packages/textarea/src/docs/component.stories.mdx @@ -0,0 +1,66 @@ +import { Meta, Story, Props, Preview } from '@storybook/addon-docs/blocks'; +import { text, select, boolean, number } from '@storybook/addon-knobs'; +import { CssVars, ComponentHeader, Tabs } from 'storybook/blocks'; +import Icon from '@alfalab/icons-glyph/StarMIcon'; + +import { Textarea } from '..'; +import { name, version } from '../../package.json'; + +import styles from '!!raw-loader!../index.module.css'; +import Description from './description.mdx'; + + + + + + + {React.createElement(() => { + const showCounter = boolean('showCounter', false); + return ( +