From 52d612fa06af8a5f7849d4c7e90798c013ab8d04 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 21 Mar 2022 17:38:44 +0900 Subject: [PATCH 1/4] build: ready for migrating TypeScript (#808) * build: setup typescript * refactor: change some file's extensions from .js to .ts * refactor: remove an unused file --- .babelrc.js | 10 +- .size-snapshot.json | 16 +- package.json | 13 +- rollup.config.js | 3 +- ...upContext.js => TransitionGroupContext.ts} | 0 src/{config.js => config.ts} | 0 src/{index.js => index.ts} | 0 src/utils/{PropTypes.js => PropTypes.ts} | 0 src/utils/SimpleSet.js | 21 -- tsconfig.json | 104 +++++++++ yarn.lock | 219 +++++++++++++++++- 11 files changed, 345 insertions(+), 41 deletions(-) rename src/{TransitionGroupContext.js => TransitionGroupContext.ts} (100%) rename src/{config.js => config.ts} (100%) rename src/{index.js => index.ts} (100%) rename src/utils/{PropTypes.js => PropTypes.ts} (100%) delete mode 100644 src/utils/SimpleSet.js create mode 100644 tsconfig.json diff --git a/.babelrc.js b/.babelrc.js index a12cc6d4..6a3e2887 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,11 +1,17 @@ module.exports = { - presets: [['babel-preset-jason', { runtime: false }]], + presets: [ + ['babel-preset-jason', { runtime: false }], + '@babel/preset-typescript', + ], plugins: [ ['babel-plugin-transform-react-remove-prop-types', { mode: 'wrap' }], ], env: { esm: { - presets: [['babel-preset-jason', { modules: false }]], + presets: [ + ['babel-preset-jason', { modules: false }], + '@babel/preset-typescript', + ], }, }, }; diff --git a/.size-snapshot.json b/.size-snapshot.json index 28cd868b..7825d6c3 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,12 +1,12 @@ { - "./lib/dist/react-transition-group.js": { - "bundled": 82684, - "minified": 22426, - "gzipped": 6876 + "lib/dist/react-transition-group.js": { + "bundled": 98066, + "minified": 26272, + "gzipped": 8027 }, - "./lib/dist/react-transition-group.min.js": { - "bundled": 47269, - "minified": 14623, - "gzipped": 4616 + "lib/dist/react-transition-group.min.js": { + "bundled": 55134, + "minified": 17999, + "gzipped": 5654 } } diff --git a/package.json b/package.json index 8a7b252e..6ab48cee 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "tdd": "jest --watch", "build": "rimraf lib && yarn build:cjs && yarn build:esm && yarn build:pick && yarn build:dist && cp README.md LICENSE ./lib", "build:docs": "yarn --cwd www run build", - "build:cjs": "babel src --out-dir lib/cjs", - "build:esm": "cross-env BABEL_ENV=esm babel src --out-dir lib/esm", + "build:cjs": "babel src --out-dir lib/cjs --extensions '.js,.ts,.tsx'", + "build:esm": "cross-env BABEL_ENV=esm babel src --out-dir lib/esm --extensions '.js,.ts,.tsx'", "build:pick": "cherry-pick --cwd=lib --input-dir=../src --cjs-dir=cjs --esm-dir=esm", "build:dist": "cross-env BABEL_ENV=esm rollup -c", "bootstrap": "yarn && yarn --cwd www", @@ -19,8 +19,9 @@ "fix:eslint": "yarn lint:eslint --fix", "fix:prettier": "yarn lint:prettier --write", "lint": "run-p lint:*", - "lint:eslint": "eslint .", + "lint:eslint": "eslint . --ext '.js,.ts,.tsx'", "lint:prettier": "prettier . --check", + "lint:tsc": "tsc", "release": "release", "release:next": "release --preid beta --tag next", "deploy-docs": "yarn --cwd www run deploy", @@ -73,6 +74,7 @@ "devDependencies": { "@babel/cli": "^7.8.4", "@babel/core": "^7.9.0", + "@babel/preset-typescript": "^7.16.7", "@restart/hooks": "^0.3.22", "@semantic-release/changelog": "^5.0.1", "@semantic-release/git": "^9.0.0", @@ -81,6 +83,9 @@ "@storybook/addon-actions": "^6.3.4", "@storybook/react": "^6.3.4", "@testing-library/react": "alpha", + "@types/prop-types": "^15.7.4", + "@types/react": "^17.0.41", + "@types/react-dom": "^17.0.14", "@typescript-eslint/eslint-plugin": "^4.26.1", "astroturf": "^0.10.4", "babel-eslint": "^10.1.0", @@ -112,7 +117,7 @@ "rollup-plugin-terser": "^5.3.0", "semantic-release": "^17.0.6", "semantic-release-alt-publish-dir": "^3.0.0", - "typescript": "^4.3.2", + "typescript": "^4.6.2", "webpack-atoms": "14.0.0" }, "release": { diff --git a/rollup.config.js b/rollup.config.js index 5000c878..6d1d2afc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -5,7 +5,7 @@ import replace from 'rollup-plugin-replace'; import { sizeSnapshot } from 'rollup-plugin-size-snapshot'; import { terser } from 'rollup-plugin-terser'; -const input = './src/index.js'; +const input = './src/index.ts'; const name = 'ReactTransitionGroup'; const globals = { react: 'React', @@ -19,6 +19,7 @@ const babelOptions = { const commonjsOptions = { include: /node_modules/, + extensions: ['.js', '.ts', '.tsx'], namedExports: { 'prop-types': ['object', 'oneOfType', 'element', 'bool', 'func'], }, diff --git a/src/TransitionGroupContext.js b/src/TransitionGroupContext.ts similarity index 100% rename from src/TransitionGroupContext.js rename to src/TransitionGroupContext.ts diff --git a/src/config.js b/src/config.ts similarity index 100% rename from src/config.js rename to src/config.ts diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/utils/PropTypes.js b/src/utils/PropTypes.ts similarity index 100% rename from src/utils/PropTypes.js rename to src/utils/PropTypes.ts diff --git a/src/utils/SimpleSet.js b/src/utils/SimpleSet.js deleted file mode 100644 index 1617ecba..00000000 --- a/src/utils/SimpleSet.js +++ /dev/null @@ -1,21 +0,0 @@ -export default class SimpleSet { - constructor() { - this.v = []; - } - clear() { - this.v.length = 0; - } - has(k) { - return this.v.indexOf(k) !== -1; - } - add(k) { - if (this.has(k)) return; - this.v.push(k); - } - delete(k) { - const idx = this.v.indexOf(k); - if (idx === -1) return false; - this.v.splice(idx, 1); - return true; - } -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..20c79ba7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,104 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": [ + "es2015", + "DOM" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "jsx": "react" /* Specify what JSX code is generated. */, + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + "noEmit": true /* Disable emitting files from a compilation. */, + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock index 062bb735..bf51b493 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,6 +72,13 @@ dependencies: "@babel/highlight" "^7.14.5" +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.5.tgz#8ef4c18e58e801c5c95d3c1c0f2874a2680fadea" @@ -160,6 +167,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.17.3": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/generator@^7.3.4", "@babel/generator@^7.9.0", "@babel/generator@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" @@ -177,6 +193,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-annotate-as-pure@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" @@ -250,6 +273,19 @@ "@babel/helper-replace-supers" "^7.14.5" "@babel/helper-split-export-declaration" "^7.14.5" +"@babel/helper-create-class-features-plugin@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-create-class-features-plugin@^7.8.3": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.9.5.tgz#79753d44017806b481017f24b02fd4113c7106ea" @@ -316,6 +352,13 @@ resolve "^1.14.2" semver "^6.1.2" +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-explode-assignable-expression@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645" @@ -340,6 +383,15 @@ "@babel/template" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" @@ -356,6 +408,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-get-function-arity@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" @@ -370,6 +429,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-hoist-variables@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" @@ -384,6 +450,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== + dependencies: + "@babel/types" "^7.17.0" + "@babel/helper-member-expression-to-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" @@ -439,6 +512,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-optimise-call-expression@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" @@ -461,6 +541,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== +"@babel/helper-plugin-utils@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + "@babel/helper-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" @@ -498,6 +583,17 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" @@ -537,6 +633,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-split-export-declaration@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" @@ -549,6 +652,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" @@ -559,6 +667,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + "@babel/helper-wrap-function@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff" @@ -606,6 +719,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/highlight@^7.8.3": version "7.9.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" @@ -630,6 +752,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2" integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== +"@babel/parser@^7.16.7", "@babel/parser@^7.17.3": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e" @@ -1080,6 +1207,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-transform-arrow-functions@^7.12.1", "@babel/plugin-transform-arrow-functions@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" @@ -1658,6 +1792,15 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript" "^7.14.5" +"@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + "@babel/plugin-transform-unicode-escapes@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" @@ -1890,6 +2033,15 @@ "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-transform-typescript" "^7.14.5" +"@babel/preset-typescript@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + "@babel/register@^7.12.1": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.14.5.tgz#d0eac615065d9c2f1995842f85d6e56c345f3233" @@ -1939,6 +2091,15 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/template@^7.2.2", "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" @@ -1993,6 +2154,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.3.4", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" @@ -2010,6 +2187,14 @@ "@babel/helper-validator-identifier" "^7.14.5" to-fast-properties "^2.0.0" +"@babel/types@^7.16.7", "@babel/types@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -3750,6 +3935,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== +"@types/prop-types@^15.7.4": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" @@ -3767,7 +3957,7 @@ dependencies: "@types/react" "*" -"@types/react-dom@*": +"@types/react-dom@*", "@types/react-dom@^17.0.14": version "17.0.14" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.14.tgz#c8f917156b652ddf807711f5becbd2ab018dea9f" integrity sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ== @@ -3789,6 +3979,15 @@ "@types/prop-types" "*" csstype "^2.2.0" +"@types/react@^17.0.41": + version "17.0.41" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.41.tgz#6e179590d276394de1e357b3f89d05d7d3da8b85" + integrity sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -3801,6 +4000,11 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" @@ -6771,6 +6975,11 @@ csstype@^2.2.0, csstype@^2.5.7, csstype@^2.6.7: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== +csstype@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -16896,10 +17105,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" - integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== +typescript@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" + integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== uglify-js@^3.1.4: version "3.13.5" From 8a36e765961aeaad99729e46d7c8cf13a67a07fb Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 6 Apr 2022 01:12:03 +0900 Subject: [PATCH 2/4] refactor: migrate `src/` to TypeScript (#809) * build: add tsx files as targets of Babel * refactor: migrate ChildMapping to TypeScript * refactor: add types for TransitionGroupContext * refactor: migrate SwitchTransition to TypeScript * refactor: migrate Transition to TypeScript * refactor: migrate CSSTransition to TypeScript * refactor: migrate TransitionGroup to TypeScript * refactor: migrate ReplaceTransition to TypeScript * chore: update size-snapshot --- .size-snapshot.json | 12 +- .storybook/main.js | 13 +- package.json | 2 +- rollup.config.js | 1 + src/{CSSTransition.js => CSSTransition.tsx} | 65 ++- ...aceTransition.js => ReplaceTransition.tsx} | 36 +- ...itchTransition.js => SwitchTransition.tsx} | 86 +-- src/{Transition.js => Transition.tsx} | 516 ++++++++++-------- ...TransitionGroup.js => TransitionGroup.tsx} | 67 ++- src/TransitionGroupContext.ts | 2 +- .../{ChildMapping.js => ChildMapping.ts} | 44 +- yarn.lock | 10 + 12 files changed, 523 insertions(+), 331 deletions(-) rename src/{CSSTransition.js => CSSTransition.tsx} (78%) rename src/{ReplaceTransition.js => ReplaceTransition.tsx} (50%) rename src/{SwitchTransition.js => SwitchTransition.tsx} (66%) rename src/{Transition.js => Transition.tsx} (50%) rename src/{TransitionGroup.js => TransitionGroup.tsx} (71%) rename src/utils/{ChildMapping.js => ChildMapping.ts} (77%) diff --git a/.size-snapshot.json b/.size-snapshot.json index 7825d6c3..c90cbc0d 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,12 +1,12 @@ { "lib/dist/react-transition-group.js": { - "bundled": 98066, - "minified": 26272, - "gzipped": 8027 + "bundled": 101943, + "minified": 26331, + "gzipped": 8046 }, "lib/dist/react-transition-group.min.js": { - "bundled": 55134, - "minified": 17999, - "gzipped": 5654 + "bundled": 58919, + "minified": 18068, + "gzipped": 5664 } } diff --git a/.storybook/main.js b/.storybook/main.js index 6d952e40..03c63cc6 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -4,9 +4,18 @@ module.exports = { stories: ['../stories/index.js'], webpackFinal: (config) => { config.module = { - rules: [rules.js(), rules.astroturf(), rules.css({ extract: false })], + rules: [ + { + test: /\.[t|j]sx?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + }, + }, + rules.astroturf(), + rules.css({ extract: false }), + ], }; - config.plugins.push(plugins.extractCss({ disable: true })); return config; diff --git a/package.json b/package.json index 6ab48cee..50518b7c 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "@typescript-eslint/eslint-plugin": "^4.26.1", "astroturf": "^0.10.4", "babel-eslint": "^10.1.0", - "babel-loader": "^8.1.0", + "babel-loader": "^8.2.3", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "babel-preset-jason": "^6.2.0", "cherry-pick": "^0.5.0", diff --git a/rollup.config.js b/rollup.config.js index 6d1d2afc..bbabeb46 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -14,6 +14,7 @@ const globals = { const babelOptions = { exclude: /node_modules/, + extensions: ['.js', '.ts', '.tsx'], runtimeHelpers: true, }; diff --git a/src/CSSTransition.js b/src/CSSTransition.tsx similarity index 78% rename from src/CSSTransition.js rename to src/CSSTransition.tsx index ef97b825..4ca8d4b8 100644 --- a/src/CSSTransition.js +++ b/src/CSSTransition.tsx @@ -4,14 +4,32 @@ import addOneClass from 'dom-helpers/addClass'; import removeOneClass from 'dom-helpers/removeClass'; import React from 'react'; -import Transition from './Transition'; +import Transition, { Props as TransitionProps } from './Transition'; import { classNamesShape } from './utils/PropTypes'; -const addClass = (node, classes) => +const addClass = (node: HTMLElement, classes: string) => node && classes && classes.split(' ').forEach((c) => addOneClass(node, c)); -const removeClass = (node, classes) => +const removeClass = (node: HTMLElement, classes: string) => node && classes && classes.split(' ').forEach((c) => removeOneClass(node, c)); +type TransitionClassNames = { + appear: string; + appearActive: string; + appearDone: string; + enter: string; + enterActive: string; + enterDone: string; + exit: string; + exitActive: string; + exitDone: string; +}; + +type Props = TransitionProps & { + classNames: string | Partial; +}; + +type TransitionClassNameKeys = 'appear' | 'enter' | 'exit'; + /** * A transition component inspired by the excellent * [ng-animate](https://docs.angularjs.org/api/ngAnimate) library, you should @@ -81,7 +99,7 @@ const removeClass = (node, classes) => * [`appear`](http://reactcommunity.org/react-transition-group/transition#Transition-prop-appear) * prop, make sure to define styles for `.appear-*` classes as well. */ -class CSSTransition extends React.Component { +class CSSTransition extends React.Component { static defaultProps = { classNames: '', }; @@ -92,7 +110,7 @@ class CSSTransition extends React.Component { exit: {}, }; - onEnter = (maybeNode, maybeAppearing) => { + onEnter = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => { const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing); this.removeClasses(node, 'exit'); this.addClass(node, appearing ? 'appear' : 'enter', 'base'); @@ -102,7 +120,7 @@ class CSSTransition extends React.Component { } }; - onEntering = (maybeNode, maybeAppearing) => { + onEntering = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => { const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing); const type = appearing ? 'appear' : 'enter'; this.addClass(node, type, 'active'); @@ -112,7 +130,7 @@ class CSSTransition extends React.Component { } }; - onEntered = (maybeNode, maybeAppearing) => { + onEntered = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => { const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing); const type = appearing ? 'appear' : 'enter'; this.removeClasses(node, type); @@ -123,7 +141,7 @@ class CSSTransition extends React.Component { } }; - onExit = (maybeNode) => { + onExit = (maybeNode?: HTMLElement) => { const [node] = this.resolveArguments(maybeNode); this.removeClasses(node, 'appear'); this.removeClasses(node, 'enter'); @@ -134,7 +152,7 @@ class CSSTransition extends React.Component { } }; - onExiting = (maybeNode) => { + onExiting = (maybeNode?: HTMLElement) => { const [node] = this.resolveArguments(maybeNode); this.addClass(node, 'exit', 'active'); @@ -143,7 +161,7 @@ class CSSTransition extends React.Component { } }; - onExited = (maybeNode) => { + onExited = (maybeNode?: HTMLElement) => { const [node] = this.resolveArguments(maybeNode); this.removeClasses(node, 'exit'); this.addClass(node, 'exit', 'done'); @@ -154,12 +172,16 @@ class CSSTransition extends React.Component { }; // when prop `nodeRef` is provided `node` is excluded - resolveArguments = (maybeNode, maybeAppearing) => + resolveArguments = ( + maybeNode: HTMLElement | boolean | undefined, + maybeAppearing?: boolean + ): [HTMLElement, boolean] => + // @ts-expect-error FIXME: Type at position 1 in source is not compatible with type at position 1 in target. Type 'boolean | HTMLElement' is not assignable to type 'boolean'. Type 'HTMLElement' is not assignable to type 'boolean'.ts(2322) this.props.nodeRef ? [this.props.nodeRef.current, maybeNode] // here `maybeNode` is actually `appearing` : [maybeNode, maybeAppearing]; // `findDOMNode` was used - getClassNames = (type) => { + getClassNames = (type: TransitionClassNameKeys) => { const { classNames } = this.props; const isStringClassNames = typeof classNames === 'string'; const prefix = isStringClassNames && classNames ? `${classNames}-` : ''; @@ -183,7 +205,11 @@ class CSSTransition extends React.Component { }; }; - addClass(node, type, phase) { + addClass( + node: HTMLElement | null, + type: TransitionClassNameKeys, + phase: 'base' | 'active' | 'done' + ) { let className = this.getClassNames(type)[`${phase}ClassName`]; const { doneClassName } = this.getClassNames('enter'); @@ -194,32 +220,40 @@ class CSSTransition extends React.Component { // This is to force a repaint, // which is necessary in order to transition styles when adding a class name. if (phase === 'active') { - /* eslint-disable no-unused-expressions */ + /* eslint-disable no-unused-expressions, @typescript-eslint/no-unused-expressions */ node && node.scrollTop; } if (className) { + // @ts-expect-error FIXME: Property 'active' does not exist on type '{} | {} | {}'.ts(7053) this.appliedClasses[type][phase] = className; + // @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345) addClass(node, className); } } - removeClasses(node, type) { + removeClasses(node: HTMLElement | null, type: TransitionClassNameKeys) { const { + // @ts-expect-error FIXME: Property 'base' does not exist on type '{} | {} | {}'.ts(2339) base: baseClassName, + // @ts-expect-error FIXME: Property 'active' does not exist on type '{} | {} | {}'.ts(2339) active: activeClassName, + // @ts-expect-error FIMXE: Property 'done' does not exist on type '{} | {} | {}'.ts(2339) done: doneClassName, } = this.appliedClasses[type]; this.appliedClasses[type] = {}; if (baseClassName) { + // @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345) removeClass(node, baseClassName); } if (activeClassName) { + // @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345) removeClass(node, activeClassName); } if (doneClassName) { + // @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345) removeClass(node, doneClassName); } } @@ -241,6 +275,7 @@ class CSSTransition extends React.Component { } } +// @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property CSSTransition.propTypes = { ...Transition.propTypes, diff --git a/src/ReplaceTransition.js b/src/ReplaceTransition.tsx similarity index 50% rename from src/ReplaceTransition.js rename to src/ReplaceTransition.tsx index 7c0b9092..5e7144bb 100644 --- a/src/ReplaceTransition.js +++ b/src/ReplaceTransition.tsx @@ -1,7 +1,13 @@ import PropTypes from 'prop-types'; import React from 'react'; +import type { ReactElement } from 'react'; import ReactDOM from 'react-dom'; import TransitionGroup from './TransitionGroup'; +import type { Props as TransitionProps } from './Transition'; + +type Props = Omit & { + children: [ReactElement, ReactElement]; +}; /** * The `` component is a specialized `Transition` component @@ -14,32 +20,35 @@ import TransitionGroup from './TransitionGroup'; * * ``` */ -class ReplaceTransition extends React.Component { - handleEnter = (...args) => this.handleLifecycle('onEnter', 0, args); - handleEntering = (...args) => this.handleLifecycle('onEntering', 0, args); - handleEntered = (...args) => this.handleLifecycle('onEntered', 0, args); +class ReplaceTransition extends React.Component { + handleEnter = (...args: any) => this.handleLifecycle('onEnter', 0, args); + handleEntering = (...args: any) => + this.handleLifecycle('onEntering', 0, args); + handleEntered = (...args: any) => this.handleLifecycle('onEntered', 0, args); - handleExit = (...args) => this.handleLifecycle('onExit', 1, args); - handleExiting = (...args) => this.handleLifecycle('onExiting', 1, args); - handleExited = (...args) => this.handleLifecycle('onExited', 1, args); + handleExit = (...args: any) => this.handleLifecycle('onExit', 1, args); + handleExiting = (...args: any) => this.handleLifecycle('onExiting', 1, args); + handleExited = (...args: any) => this.handleLifecycle('onExited', 1, args); - handleLifecycle(handler, idx, originalArgs) { + handleLifecycle(handler: any, idx: number, originalArgs: any) { const { children } = this.props; - const child = React.Children.toArray(children)[idx]; + // @ts-expect-error FIXME: Type 'string' is not assignable to type 'ReactElement>'.ts(2322) + const child: ChildElement = React.Children.toArray(children)[idx]; if (child.props[handler]) child.props[handler](...originalArgs); + // @ts-expect-error Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Readonly & Readonly<{ children?: ReactNode; }>'.ts(7053) if (this.props[handler]) { const maybeNode = child.props.nodeRef ? undefined : ReactDOM.findDOMNode(this); - + // @ts-expect-error FIXME: Argument of type 'Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement'.ts(2769) this.props[handler](maybeNode); } } render() { - const { children, in: inProp, ...props } = this.props; - const [first, second] = React.Children.toArray(children); + const { children, in: inProp, ...props }: any = this.props; + const [first, second]: any = React.Children.toArray(children); delete props.onEnter; delete props.onEntering; @@ -68,9 +77,10 @@ class ReplaceTransition extends React.Component { } } +// @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property ReplaceTransition.propTypes = { in: PropTypes.bool.isRequired, - children(props, propName) { + children(props: any, propName: any) { if (React.Children.count(props[propName]) !== 2) return new Error( `"${propName}" must be exactly two transition components.` diff --git a/src/SwitchTransition.js b/src/SwitchTransition.tsx similarity index 66% rename from src/SwitchTransition.js rename to src/SwitchTransition.tsx index cb3a45b3..ee74f773 100644 --- a/src/SwitchTransition.js +++ b/src/SwitchTransition.tsx @@ -1,9 +1,13 @@ import React from 'react'; +import { ReactElement } from 'react'; import PropTypes from 'prop-types'; -import { ENTERED, ENTERING, EXITING } from './Transition'; +import { ENTERED, ENTERING, EXITING, TransitionState } from './Transition'; import TransitionGroupContext from './TransitionGroupContext'; -function areChildrenDifferent(oldChildren, newChildren) { +function areChildrenDifferent( + oldChildren: ReactElement, + newChildren: ReactElement +) { if (oldChildren === newChildren) return false; if ( React.isValidElement(oldChildren) && @@ -26,21 +30,29 @@ export const modes = { }; const callHook = - (element, name, cb) => - (...args) => { + (element: ReactElement, name: string, cb: () => void) => + (...args: unknown[]) => { element.props[name] && element.props[name](...args); cb(); }; +type RenderCallbackParameter = { + current: ReactElement | null; + changeState: (status: TransitionState, current?: ReactElement | null) => void; + children: ReactElement; +}; + const leaveRenders = { - [modes.out]: ({ current, changeState }) => + [modes.out]: ({ current, changeState }: RenderCallbackParameter) => + // @ts-expect-error FIXME: Type 'null' is not assignable to type 'ReactElement>'.ts(2769) React.cloneElement(current, { in: false, + // @ts-expect-error FIXME: Type 'null' is not assignable to type 'ReactElement>'.ts(2345) onExited: callHook(current, 'onExited', () => { changeState(ENTERING, null); }), }), - [modes.in]: ({ current, changeState, children }) => [ + [modes.in]: ({ current, changeState, children }: RenderCallbackParameter) => [ current, React.cloneElement(children, { in: true, @@ -52,16 +64,18 @@ const leaveRenders = { }; const enterRenders = { - [modes.out]: ({ children, changeState }) => + [modes.out]: ({ children, changeState }: RenderCallbackParameter) => React.cloneElement(children, { in: true, onEntered: callHook(children, 'onEntered', () => { changeState(ENTERED, React.cloneElement(children, { in: true })); }), }), - [modes.in]: ({ current, children, changeState }) => [ + [modes.in]: ({ current, children, changeState }: RenderCallbackParameter) => [ + // @ts-expect-error FIXME: Type 'null' is not assignable to type 'ReactElement>'.ts(2769) React.cloneElement(current, { in: false, + // @ts-expect-error FIXME: Type 'null' is not assignable to type 'ReactElement>'.ts(2345) onExited: callHook(current, 'onExited', () => { changeState(ENTERED, React.cloneElement(children, { in: true })); }), @@ -72,6 +86,16 @@ const enterRenders = { ], }; +type Props = { + mode: 'in-out' | 'out-in'; + children: ReactElement; +}; + +type State = { + status: TransitionState; + current: ReactElement | null; +}; + /** * A transition component inspired by the [vue transition modes](https://vuejs.org/v2/guide/transitions.html#Transition-Modes). * You can use it when you want to control the render between state transitions. @@ -124,19 +148,38 @@ const enterRenders = { * } * ``` */ -class SwitchTransition extends React.Component { - state = { +class SwitchTransition extends React.Component { + state: State = { status: ENTERED, current: null, }; + static propTypes = { + /** + * Transition modes. + * `out-in`: Current element transitions out first, then when complete, the new element transitions in. + * `in-out`: New element transitions in first, then when complete, the current element transitions out. + * + * @type {'out-in'|'in-out'} + */ + mode: PropTypes.oneOf([modes.in, modes.out]), + /** + * Any `Transition` or `CSSTransition` component. + */ + children: PropTypes.oneOfType([PropTypes.element.isRequired]), + }; + + static defaultProps = { + mode: modes.out, + }; + appeared = false; componentDidMount() { this.appeared = true; } - static getDerivedStateFromProps(props, state) { + static getDerivedStateFromProps(props: Props, state: State) { if (props.children == null) { return { current: null, @@ -162,7 +205,7 @@ class SwitchTransition extends React.Component { }; } - changeState = (status, current = this.state.current) => { + changeState = (status: TransitionState, current = this.state.current) => { this.setState({ status, current, @@ -196,23 +239,4 @@ class SwitchTransition extends React.Component { } } -SwitchTransition.propTypes = { - /** - * Transition modes. - * `out-in`: Current element transitions out first, then when complete, the new element transitions in. - * `in-out`: New element transitions in first, then when complete, the current element transitions out. - * - * @type {'out-in'|'in-out'} - */ - mode: PropTypes.oneOf([modes.in, modes.out]), - /** - * Any `Transition` or `CSSTransition` component. - */ - children: PropTypes.oneOfType([PropTypes.element.isRequired]), -}; - -SwitchTransition.defaultProps = { - mode: modes.out, -}; - export default SwitchTransition; diff --git a/src/Transition.js b/src/Transition.tsx similarity index 50% rename from src/Transition.js rename to src/Transition.tsx index 04e845db..47698e66 100644 --- a/src/Transition.js +++ b/src/Transition.tsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import type { RefObject, ReactNode } from 'react'; import ReactDOM from 'react-dom'; import config from './config'; @@ -12,6 +13,37 @@ export const ENTERING = 'entering'; export const ENTERED = 'entered'; export const EXITING = 'exiting'; +export type TransitionState = + | 'unmounted' + | 'exited' + | 'entering' + | 'entered' + | 'exiting'; + +export type Props = { + nodeRef?: RefObject; + // The childProps argument is not documented + children: (state: TransitionState, childProps: any) => ReactNode; + in: boolean; + mountOnEnter: boolean; + unmountOnExit: boolean; + appear: boolean; + enter: boolean; + exit: boolean; + timeout: number | { appear?: number; enter?: number; exit?: number }; + addEndListener: (node: HTMLElement | undefined, done: boolean) => void; + onEnter: (maybeNode: HTMLElement | boolean, isAppearing?: boolean) => void; + onEntering: (maybeNode: HTMLElement | boolean, isAppearing?: boolean) => void; + onEntered: (maybeNode: HTMLElement | boolean, isAppearing?: boolean) => void; + onExit: (node?: HTMLElement) => void; + onExiting: (node?: HTMLElement) => void; + onExited: (node?: HTMLElement) => void; +}; + +type State = { + status: TransitionState; +}; + /** * The Transition component lets you describe a transition from one component * state to another _over time_ with a simple declarative API. Most commonly @@ -103,10 +135,234 @@ export const EXITING = 'exiting'; * When `in` is `false` the same thing happens except the state moves from * `'exiting'` to `'exited'`. */ -class Transition extends React.Component { +class Transition extends React.Component { + appearStatus: TransitionState | null; + nextCallback: any; + + static defaultProps = { + in: false, + mountOnEnter: false, + unmountOnExit: false, + appear: false, + enter: true, + exit: true, + + onEnter: noop, + onEntering: noop, + onEntered: noop, + + onExit: noop, + onExiting: noop, + onExited: noop, + }; + static UNMOUNTED = UNMOUNTED; + static EXITED = EXITED; + static ENTERING = ENTERING; + static ENTERED = ENTERED; + static EXITING = EXITING; + + static propTypes = { + /** + * A React reference to DOM element that need to transition: + * https://stackoverflow.com/a/51127130/4671932 + * + * - When `nodeRef` prop is used, `node` is not passed to callback functions + * (e.g. `onEnter`) because user already has direct access to the node. + * - When changing `key` prop of `Transition` in a `TransitionGroup` a new + * `nodeRef` need to be provided to `Transition` with changed `key` prop + * (see + * [test/CSSTransition-test.js](https://github.com/reactjs/react-transition-group/blob/13435f897b3ab71f6e19d724f145596f5910581c/test/CSSTransition-test.js#L362-L437)). + */ + nodeRef: PropTypes.shape({ + // @ts-expect-error We'll remove the PropTypes definition + current: + typeof Element === 'undefined' + ? PropTypes.any + : // @ts-expect-error We'll remove the PropTypes definition + (propValue, key, componentName, location, propFullName, secret) => { + const value = propValue[key]; + + return PropTypes.instanceOf( + value && 'ownerDocument' in value + ? value.ownerDocument.defaultView.Element + : Element + // @ts-expect-error We'll remove the PropTypes definition + )(propValue, key, componentName, location, propFullName, secret); + }, + }), + + /** + * A `function` child can be used instead of a React element. This function is + * called with the current transition status (`'entering'`, `'entered'`, + * `'exiting'`, `'exited'`), which can be used to apply context + * specific props to a component. + * + * ```jsx + * + * {state => ( + * + * )} + * + * ``` + */ + children: PropTypes.oneOfType([ + PropTypes.func.isRequired, + PropTypes.element.isRequired, + ]).isRequired, + + /** + * Show the component; triggers the enter or exit states + */ + in: PropTypes.bool, + + /** + * By default the child component is mounted immediately along with + * the parent `Transition` component. If you want to "lazy mount" the component on the + * first `in={true}` you can set `mountOnEnter`. After the first enter transition the component will stay + * mounted, even on "exited", unless you also specify `unmountOnExit`. + */ + mountOnEnter: PropTypes.bool, + + /** + * By default the child component stays mounted after it reaches the `'exited'` state. + * Set `unmountOnExit` if you'd prefer to unmount the component after it finishes exiting. + */ + unmountOnExit: PropTypes.bool, + + /** + * By default the child component does not perform the enter transition when + * it first mounts, regardless of the value of `in`. If you want this + * behavior, set both `appear` and `in` to `true`. + * + * > **Note**: there are no special appear states like `appearing`/`appeared`, this prop + * > only adds an additional enter transition. However, in the + * > `` component that first enter transition does result in + * > additional `.appear-*` classes, that way you can choose to style it + * > differently. + */ + appear: PropTypes.bool, + + /** + * Enable or disable enter transitions. + */ + enter: PropTypes.bool, + + /** + * Enable or disable exit transitions. + */ + exit: PropTypes.bool, + + /** + * The duration of the transition, in milliseconds. + * Required unless `addEndListener` is provided. + * + * You may specify a single timeout for all transitions: + * + * ```jsx + * timeout={500} + * ``` + * + * or individually: + * + * ```jsx + * timeout={{ + * appear: 500, + * enter: 300, + * exit: 500, + * }} + * ``` + * + * - `appear` defaults to the value of `enter` + * - `enter` defaults to `0` + * - `exit` defaults to `0` + * + * @type {number | { enter?: number, exit?: number, appear?: number }} + */ + timeout: (props: any, ...args: any[]) => { + let pt = timeoutsShape; + // @ts-expect-error We'll remove the PropTypes definition + if (!props.addEndListener) pt = pt.isRequired; + // @ts-expect-error We'll remove the PropTypes definition + return pt(props, ...args); + }, + + /** + * Add a custom transition end trigger. Called with the transitioning + * DOM node and a `done` callback. Allows for more fine grained transition end + * logic. Timeouts are still used as a fallback if provided. + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * ```jsx + * addEndListener={(node, done) => { + * // use the css transitionend event to mark the finish of a transition + * node.addEventListener('transitionend', done, false); + * }} + * ``` + */ + addEndListener: PropTypes.func, + + /** + * Callback fired before the "entering" status is applied. An extra parameter + * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * @type Function(node: HtmlElement, isAppearing: bool) -> void + */ + onEnter: PropTypes.func, + + /** + * Callback fired after the "entering" status is applied. An extra parameter + * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * @type Function(node: HtmlElement, isAppearing: bool) + */ + onEntering: PropTypes.func, + + /** + * Callback fired after the "entered" status is applied. An extra parameter + * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * @type Function(node: HtmlElement, isAppearing: bool) -> void + */ + onEntered: PropTypes.func, + + /** + * Callback fired before the "exiting" status is applied. + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * @type Function(node: HtmlElement) -> void + */ + onExit: PropTypes.func, + + /** + * Callback fired after the "exiting" status is applied. + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed. + * + * @type Function(node: HtmlElement) -> void + */ + onExiting: PropTypes.func, + + /** + * Callback fired after the "exited" status is applied. + * + * **Note**: when `nodeRef` prop is passed, `node` is not passed + * + * @type Function(node: HtmlElement) -> void + */ + onExited: PropTypes.func, + }; + static contextType = TransitionGroupContext; - constructor(props, context) { + constructor(props: Props, context: any) { super(props, context); let parentGroup = context; @@ -114,7 +370,7 @@ class Transition extends React.Component { let appear = parentGroup && !parentGroup.isMounting ? props.enter : props.appear; - let initialStatus; + let initialStatus: TransitionState; this.appearStatus = null; @@ -138,7 +394,10 @@ class Transition extends React.Component { this.nextCallback = null; } - static getDerivedStateFromProps({ in: nextIn }, prevState) { + static getDerivedStateFromProps( + { in: nextIn }: { in: boolean }, + prevState: State + ) { if (nextIn && prevState.status === UNMOUNTED) { return { status: EXITED }; } @@ -169,8 +428,8 @@ class Transition extends React.Component { this.updateStatus(true, this.appearStatus); } - componentDidUpdate(prevProps) { - let nextStatus = null; + componentDidUpdate(prevProps: Props) { + let nextStatus: TransitionState | null = null; if (prevProps !== this.props) { const { status } = this.state; @@ -195,18 +454,18 @@ class Transition extends React.Component { const { timeout } = this.props; let exit, enter, appear; - exit = enter = appear = timeout; - if (timeout != null && typeof timeout !== 'number') { exit = timeout.exit; enter = timeout.enter; // TODO: remove fallback for next major appear = timeout.appear !== undefined ? timeout.appear : enter; + } else { + exit = enter = appear = timeout; } return { exit, enter, appear }; } - updateStatus(mounting = false, nextStatus) { + updateStatus(mounting = false, nextStatus: TransitionState | null) { if (nextStatus !== null) { // nextStatus will always be ENTERING or EXITING. this.cancelNextCallback(); @@ -221,7 +480,7 @@ class Transition extends React.Component { } } - performEnter(mounting) { + performEnter(mounting: boolean) { const { enter } = this.props; const appearing = this.context ? this.context.isMounting : mounting; const [maybeNode, maybeAppearing] = this.props.nodeRef @@ -255,7 +514,8 @@ class Transition extends React.Component { performExit() { const { exit } = this.props; const timeouts = this.getTimeouts(); - const maybeNode = this.props.nodeRef + // @ts-expect-error FIXME: Type 'Element | Text | null | undefined' is not assignable to type 'HTMLElement | undefined' Type 'null' is not assignable to type 'HTMLElement | undefined'.ts(2322) + const maybeNode: HTMLElement | undefined = this.props.nodeRef ? undefined : ReactDOM.findDOMNode(this); @@ -287,7 +547,7 @@ class Transition extends React.Component { } } - safeSetState(nextState, callback) { + safeSetState(nextState: State, callback: () => void) { // This shouldn't be necessary, but there are weird race conditions with // setState callbacks and unmounting in testing, so always make sure that // we can cancel any pending setState callbacks after we unmount. @@ -295,15 +555,15 @@ class Transition extends React.Component { this.setState(nextState, callback); } - setNextCallback(callback) { + setNextCallback(callback: () => void) { let active = true; - this.nextCallback = (event) => { + this.nextCallback = () => { if (active) { active = false; this.nextCallback = null; - callback(event); + callback(); } }; @@ -314,7 +574,7 @@ class Transition extends React.Component { return this.nextCallback; } - onTransitionEnd(timeout, handler) { + onTransitionEnd(timeout: number | undefined, handler: () => void) { this.setNextCallback(handler); const node = this.props.nodeRef ? this.props.nodeRef.current @@ -372,230 +632,16 @@ class Transition extends React.Component { {typeof children === 'function' ? children(status, childProps) - : React.cloneElement(React.Children.only(children), childProps)} + : // @ts-expect-error FIXME: Type 'ReactChildren' is missing the following properties from type 'ReactElement>': type, props, keyts(2769) + React.cloneElement(React.Children.only(children), childProps)} ); } } -Transition.propTypes = { - /** - * A React reference to DOM element that need to transition: - * https://stackoverflow.com/a/51127130/4671932 - * - * - When `nodeRef` prop is used, `node` is not passed to callback functions - * (e.g. `onEnter`) because user already has direct access to the node. - * - When changing `key` prop of `Transition` in a `TransitionGroup` a new - * `nodeRef` need to be provided to `Transition` with changed `key` prop - * (see - * [test/CSSTransition-test.js](https://github.com/reactjs/react-transition-group/blob/13435f897b3ab71f6e19d724f145596f5910581c/test/CSSTransition-test.js#L362-L437)). - */ - nodeRef: PropTypes.shape({ - current: - typeof Element === 'undefined' - ? PropTypes.any - : (propValue, key, componentName, location, propFullName, secret) => { - const value = propValue[key]; - - return PropTypes.instanceOf( - value && 'ownerDocument' in value - ? value.ownerDocument.defaultView.Element - : Element - )(propValue, key, componentName, location, propFullName, secret); - }, - }), - - /** - * A `function` child can be used instead of a React element. This function is - * called with the current transition status (`'entering'`, `'entered'`, - * `'exiting'`, `'exited'`), which can be used to apply context - * specific props to a component. - * - * ```jsx - * - * {state => ( - * - * )} - * - * ``` - */ - children: PropTypes.oneOfType([ - PropTypes.func.isRequired, - PropTypes.element.isRequired, - ]).isRequired, - - /** - * Show the component; triggers the enter or exit states - */ - in: PropTypes.bool, - - /** - * By default the child component is mounted immediately along with - * the parent `Transition` component. If you want to "lazy mount" the component on the - * first `in={true}` you can set `mountOnEnter`. After the first enter transition the component will stay - * mounted, even on "exited", unless you also specify `unmountOnExit`. - */ - mountOnEnter: PropTypes.bool, - - /** - * By default the child component stays mounted after it reaches the `'exited'` state. - * Set `unmountOnExit` if you'd prefer to unmount the component after it finishes exiting. - */ - unmountOnExit: PropTypes.bool, - - /** - * By default the child component does not perform the enter transition when - * it first mounts, regardless of the value of `in`. If you want this - * behavior, set both `appear` and `in` to `true`. - * - * > **Note**: there are no special appear states like `appearing`/`appeared`, this prop - * > only adds an additional enter transition. However, in the - * > `` component that first enter transition does result in - * > additional `.appear-*` classes, that way you can choose to style it - * > differently. - */ - appear: PropTypes.bool, - - /** - * Enable or disable enter transitions. - */ - enter: PropTypes.bool, - - /** - * Enable or disable exit transitions. - */ - exit: PropTypes.bool, - - /** - * The duration of the transition, in milliseconds. - * Required unless `addEndListener` is provided. - * - * You may specify a single timeout for all transitions: - * - * ```jsx - * timeout={500} - * ``` - * - * or individually: - * - * ```jsx - * timeout={{ - * appear: 500, - * enter: 300, - * exit: 500, - * }} - * ``` - * - * - `appear` defaults to the value of `enter` - * - `enter` defaults to `0` - * - `exit` defaults to `0` - * - * @type {number | { enter?: number, exit?: number, appear?: number }} - */ - timeout: (props, ...args) => { - let pt = timeoutsShape; - if (!props.addEndListener) pt = pt.isRequired; - return pt(props, ...args); - }, - - /** - * Add a custom transition end trigger. Called with the transitioning - * DOM node and a `done` callback. Allows for more fine grained transition end - * logic. Timeouts are still used as a fallback if provided. - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * ```jsx - * addEndListener={(node, done) => { - * // use the css transitionend event to mark the finish of a transition - * node.addEventListener('transitionend', done, false); - * }} - * ``` - */ - addEndListener: PropTypes.func, - - /** - * Callback fired before the "entering" status is applied. An extra parameter - * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * @type Function(node: HtmlElement, isAppearing: bool) -> void - */ - onEnter: PropTypes.func, - - /** - * Callback fired after the "entering" status is applied. An extra parameter - * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * @type Function(node: HtmlElement, isAppearing: bool) - */ - onEntering: PropTypes.func, - - /** - * Callback fired after the "entered" status is applied. An extra parameter - * `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * @type Function(node: HtmlElement, isAppearing: bool) -> void - */ - onEntered: PropTypes.func, - - /** - * Callback fired before the "exiting" status is applied. - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * @type Function(node: HtmlElement) -> void - */ - onExit: PropTypes.func, - - /** - * Callback fired after the "exiting" status is applied. - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed. - * - * @type Function(node: HtmlElement) -> void - */ - onExiting: PropTypes.func, - - /** - * Callback fired after the "exited" status is applied. - * - * **Note**: when `nodeRef` prop is passed, `node` is not passed - * - * @type Function(node: HtmlElement) -> void - */ - onExited: PropTypes.func, -}; - // Name the function so it is clearer in the documentation -function noop() {} - -Transition.defaultProps = { - in: false, - mountOnEnter: false, - unmountOnExit: false, - appear: false, - enter: true, - exit: true, - - onEnter: noop, - onEntering: noop, - onEntered: noop, - - onExit: noop, - onExiting: noop, - onExited: noop, -}; - -Transition.UNMOUNTED = UNMOUNTED; -Transition.EXITED = EXITED; -Transition.ENTERING = ENTERING; -Transition.ENTERED = ENTERED; -Transition.EXITING = EXITING; +function noop() { + /* noop */ +} export default Transition; diff --git a/src/TransitionGroup.js b/src/TransitionGroup.tsx similarity index 71% rename from src/TransitionGroup.js rename to src/TransitionGroup.tsx index 14783c0f..e6f64164 100644 --- a/src/TransitionGroup.js +++ b/src/TransitionGroup.tsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import type { ReactElement, ReactChild } from 'react'; import TransitionGroupContext from './TransitionGroupContext'; import { @@ -8,11 +9,32 @@ import { getNextChildMapping, } from './utils/ChildMapping'; -const values = Object.values || ((obj) => Object.keys(obj).map((k) => obj[k])); +const values = + Object.values || + ((obj: Record) => Object.keys(obj).map((k) => obj[k])); const defaultProps = { component: 'div', - childFactory: (child) => child, + childFactory: (child: ReactElement) => child, +}; + +type Props = { + component: any; + children: any; + appear: boolean; + enter: boolean; + exit: boolean; + childFactory: (child: ReactElement) => ReactElement; +}; + +type State = { + children: Record; + contextValue: { isMounting: boolean }; + handleExited: ( + child: ReactElement<{ onExited: (node: HTMLElement) => void }>, + node: HTMLElement + ) => void; + firstRender: boolean; }; /** @@ -29,13 +51,17 @@ const defaultProps = { * component. This means you can mix and match animations across different list * items. */ -class TransitionGroup extends React.Component { - constructor(props, context) { +class TransitionGroup extends React.Component { + static defaultProps = defaultProps; + + mounted = false; + constructor(props: Props, context: any) { super(props, context); const handleExited = this.handleExited.bind(this); // Initial children should all be entering, dependent on appear + // @ts-expect-error FIXME: Property 'children' is missing in type '{ contextValue: { isMounting: true; }; handleExited: (child: React.ReactElement<{ onExited: (node: HTMLElement) => void; }, string | React.JSXElementConstructor>, node: HTMLElement) => void; firstRender: true; }' but required in type 'Readonly'.ts(2741) this.state = { contextValue: { isMounting: true }, handleExited, @@ -55,8 +81,8 @@ class TransitionGroup extends React.Component { } static getDerivedStateFromProps( - nextProps, - { children: prevChildMapping, handleExited, firstRender } + nextProps: Props, + { children: prevChildMapping, handleExited, firstRender }: State ) { return { children: firstRender @@ -67,10 +93,12 @@ class TransitionGroup extends React.Component { } // node is `undefined` when user provided `nodeRef` prop - handleExited(child, node) { + handleExited( + child: ReactElement<{ onExited: (node: HTMLElement) => void }>, + node: HTMLElement + ) { let currentChildMapping = getChildMapping(this.props.children); - - if (child.key in currentChildMapping) return; + if (child.key && child.key in currentChildMapping) return; if (child.props.onExited) { child.props.onExited(node); @@ -79,8 +107,9 @@ class TransitionGroup extends React.Component { if (this.mounted) { this.setState((state) => { let children = { ...state.children }; - - delete children[child.key]; + if (child.key) { + delete children[child.key]; + } return { children }; }); } @@ -89,11 +118,14 @@ class TransitionGroup extends React.Component { render() { const { component: Component, childFactory, ...props } = this.props; const { contextValue } = this.state; + // @ts-expect-error FIXME: Type 'undefined' is not assignable to type 'ReactElement>'.ts(2345) const children = values(this.state.children).map(childFactory); - - delete props.appear; - delete props.enter; - delete props.exit; + const { + appear: _appear, + enter: _enter, + exit: _exit, + ...delegatingProps + } = props; if (Component === null) { return ( @@ -104,12 +136,13 @@ class TransitionGroup extends React.Component { } return ( - {children} + {children} ); } } +// @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property TransitionGroup.propTypes = { /** * `` renders a `
` by default. You can change this @@ -166,6 +199,4 @@ TransitionGroup.propTypes = { childFactory: PropTypes.func, }; -TransitionGroup.defaultProps = defaultProps; - export default TransitionGroup; diff --git a/src/TransitionGroupContext.ts b/src/TransitionGroupContext.ts index 51b82c7d..afe8ddbb 100644 --- a/src/TransitionGroupContext.ts +++ b/src/TransitionGroupContext.ts @@ -1,3 +1,3 @@ import React from 'react'; -export default React.createContext(null); +export default React.createContext<{ isMounting: boolean } | null>(null); diff --git a/src/utils/ChildMapping.js b/src/utils/ChildMapping.ts similarity index 77% rename from src/utils/ChildMapping.js rename to src/utils/ChildMapping.ts index cdd33a3e..98740760 100644 --- a/src/utils/ChildMapping.js +++ b/src/utils/ChildMapping.ts @@ -1,4 +1,5 @@ import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactChild, ReactElement, ReactNode } from 'react'; /** * Given `this.props.children`, return an object mapping key to child. @@ -6,14 +7,19 @@ import { Children, cloneElement, isValidElement } from 'react'; * @param {*} children `this.props.children` * @return {object} Mapping of key to child */ -export function getChildMapping(children, mapFn) { - let mapper = (child) => +export function getChildMapping( + children: ReactNode[] | ReactNode, + mapFn?: (child: ReactElement) => ReactElement +) { + let mapper = (child: ReactNode) => mapFn && isValidElement(child) ? mapFn(child) : child; let result = Object.create(null); if (children) + // @ts-expect-error FIXME: Object is possibly 'null' or 'undefined'.ts(2533) Children.map(children, (c) => c).forEach((child) => { // run the map function here instead so that the key is the computed one + // @ts-expect-error FIXME: Property 'key' does not exist on type 'string'.ts(2339) result[child.key] = mapper(child); }); return result; @@ -36,11 +42,14 @@ export function getChildMapping(children, mapFn) { * @return {object} a key set that contains all keys in `prev` and all keys * in `next` in a reasonable order. */ -export function mergeChildMappings(prev, next) { +export function mergeChildMappings( + prev: Record, + next: Record +) { prev = prev || {}; next = next || {}; - function getValueForKey(key) { + function getValueForKey(key: string) { return key in next ? next[key] : prev[key]; } @@ -61,7 +70,7 @@ export function mergeChildMappings(prev, next) { } let i; - let childMapping = {}; + let childMapping: Record = {}; for (let nextKey in next) { if (nextKeysPending[nextKey]) { for (i = 0; i < nextKeysPending[nextKey].length; i++) { @@ -81,12 +90,22 @@ export function mergeChildMappings(prev, next) { return childMapping; } -function getProp(child, prop, props) { +function getProp( + child: ReactElement, + prop: string, + props: Record +) { return props[prop] != null ? props[prop] : child.props[prop]; } -export function getInitialChildMapping(props, onExited) { - return getChildMapping(props.children, (child) => { +export function getInitialChildMapping( + props: { children: ReactNode[] }, + onExited: ( + child: ReactElement<{ onExited: (node: HTMLElement) => void }>, + node: HTMLElement + ) => void +) { + return getChildMapping(props.children, (child: ReactElement) => { return cloneElement(child, { onExited: onExited.bind(null, child), in: true, @@ -97,7 +116,14 @@ export function getInitialChildMapping(props, onExited) { }); } -export function getNextChildMapping(nextProps, prevChildMapping, onExited) { +export function getNextChildMapping( + nextProps: { children: ReactNode[] }, + prevChildMapping: Record, + onExited: ( + child: ReactElement<{ onExited: (node: HTMLElement) => void }>, + node: HTMLElement + ) => void +) { let nextChildMapping = getChildMapping(nextProps.children); let children = mergeChildMappings(prevChildMapping, nextChildMapping); diff --git a/yarn.lock b/yarn.lock index bf51b493..f95a0760 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5005,6 +5005,16 @@ babel-loader@^8.2.2: make-dir "^3.1.0" schema-utils "^2.6.5" +babel-loader@^8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" + integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^1.4.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + babel-plugin-add-module-exports@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.2.tgz#96cd610d089af664f016467fc4567c099cce2d9c" From 597f983b64d93be3ca5e3eec91473be1d64a4b71 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 3 May 2022 23:10:23 +0900 Subject: [PATCH 3/4] refactor: apply more strict types to ReplaceTransition (#812) * refactor: apply more strict types to ReplaceTransition * lint: enable the ignoreRestSiblings option of no-unused-vars --- .eslintrc.yml | 4 +++ src/ReplaceTransition.tsx | 61 +++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 0428d894..1deacabc 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -11,6 +11,10 @@ env: browser: true plugins: - jsx-a11y +rules: + "@typescript-eslint/no-unused-vars": + - error + - ignoreRestSiblings: true overrides: - files: www/**/* diff --git a/src/ReplaceTransition.tsx b/src/ReplaceTransition.tsx index 5e7144bb..29859780 100644 --- a/src/ReplaceTransition.tsx +++ b/src/ReplaceTransition.tsx @@ -9,6 +9,18 @@ type Props = Omit & { children: [ReactElement, ReactElement]; }; +type LifecycleMethodNames = + | 'onEnter' + | 'onEntering' + | 'onEntered' + | 'onExit' + | 'onExiting' + | 'onExited'; + +type HandlerArgs = [HTMLElement | boolean, boolean | undefined]; +type ChildElement = ReactElement; +type ReplaceElements = [ChildElement, ChildElement]; + /** * The `` component is a specialized `Transition` component * that animates between two children. @@ -21,22 +33,31 @@ type Props = Omit & { * ``` */ class ReplaceTransition extends React.Component { - handleEnter = (...args: any) => this.handleLifecycle('onEnter', 0, args); - handleEntering = (...args: any) => + handleEnter = (...args: HandlerArgs) => + this.handleLifecycle('onEnter', 0, args); + handleEntering = (...args: HandlerArgs) => this.handleLifecycle('onEntering', 0, args); - handleEntered = (...args: any) => this.handleLifecycle('onEntered', 0, args); + handleEntered = (...args: HandlerArgs) => + this.handleLifecycle('onEntered', 0, args); - handleExit = (...args: any) => this.handleLifecycle('onExit', 1, args); - handleExiting = (...args: any) => this.handleLifecycle('onExiting', 1, args); - handleExited = (...args: any) => this.handleLifecycle('onExited', 1, args); + handleExit = (...args: HandlerArgs) => + this.handleLifecycle('onExit', 1, args); + handleExiting = (...args: HandlerArgs) => + this.handleLifecycle('onExiting', 1, args); + handleExited = (...args: HandlerArgs) => + this.handleLifecycle('onExited', 1, args); - handleLifecycle(handler: any, idx: number, originalArgs: any) { + handleLifecycle( + handler: LifecycleMethodNames, + idx: number, + originalArgs: HandlerArgs + ) { const { children } = this.props; // @ts-expect-error FIXME: Type 'string' is not assignable to type 'ReactElement>'.ts(2322) const child: ChildElement = React.Children.toArray(children)[idx]; + // @ts-expect-error FIXME: Type 'false' is not assignable to type '(((boolean | HTMLElement) & (HTMLElement | undefined)) & (HTMLElement | undefined)) & (HTMLElement | undefined)'.ts(2345) if (child.props[handler]) child.props[handler](...originalArgs); - // @ts-expect-error Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Readonly & Readonly<{ children?: ReactNode; }>'.ts(7053) if (this.props[handler]) { const maybeNode = child.props.nodeRef ? undefined @@ -47,15 +68,19 @@ class ReplaceTransition extends React.Component { } render() { - const { children, in: inProp, ...props }: any = this.props; - const [first, second]: any = React.Children.toArray(children); - - delete props.onEnter; - delete props.onEntering; - delete props.onEntered; - delete props.onExit; - delete props.onExiting; - delete props.onExited; + const { + children, + in: inProp, + onEnter, + onEntering, + onEntered, + onExit, + onExiting, + onExited, + ...props + } = this.props; + // @ts-expect-error FIXME: Target requires 2 element(s) but source may have fewer.ts(2322) + const [first, second]: ReplaceElements = React.Children.toArray(children); return ( @@ -80,7 +105,7 @@ class ReplaceTransition extends React.Component { // @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property ReplaceTransition.propTypes = { in: PropTypes.bool.isRequired, - children(props: any, propName: any) { + children(props: any, propName: LifecycleMethodNames) { if (React.Children.count(props[propName]) !== 2) return new Error( `"${propName}" must be exactly two transition components.` From 5be0c7fc4f20d5df4cfc82a007761ea1bdd496bc Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 4 May 2022 13:52:40 +0900 Subject: [PATCH 4/4] refactor: fix lint errors (#823) --- .eslintrc.yml | 5 +++-- .size-snapshot.json | 12 +++++------ package.json | 2 +- src/CSSTransition.tsx | 2 +- src/Transition.tsx | 28 ++++++++++++------------- src/TransitionGroup.tsx | 7 +------ test/SSR-test.js | 1 + yarn.lock | 46 ++++++++++++++++++++++++++++++++++++++++- 8 files changed, 72 insertions(+), 31 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 1deacabc..8dda0cb9 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,4 +1,4 @@ -parser: babel-eslint +parser: '@typescript-eslint/parser' extends: - jason/react - plugin:jsx-a11y/recommended @@ -11,8 +11,9 @@ env: browser: true plugins: - jsx-a11y + - '@typescript-eslint' rules: - "@typescript-eslint/no-unused-vars": + '@typescript-eslint/no-unused-vars': - error - ignoreRestSiblings: true diff --git a/.size-snapshot.json b/.size-snapshot.json index c90cbc0d..7825d6c3 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,12 +1,12 @@ { "lib/dist/react-transition-group.js": { - "bundled": 101943, - "minified": 26331, - "gzipped": 8046 + "bundled": 98066, + "minified": 26272, + "gzipped": 8027 }, "lib/dist/react-transition-group.min.js": { - "bundled": 58919, - "minified": 18068, - "gzipped": 5664 + "bundled": 55134, + "minified": 17999, + "gzipped": 5654 } } diff --git a/package.json b/package.json index 50518b7c..7c92c13b 100644 --- a/package.json +++ b/package.json @@ -87,8 +87,8 @@ "@types/react": "^17.0.41", "@types/react-dom": "^17.0.14", "@typescript-eslint/eslint-plugin": "^4.26.1", + "@typescript-eslint/parser": "4", "astroturf": "^0.10.4", - "babel-eslint": "^10.1.0", "babel-loader": "^8.2.3", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "babel-preset-jason": "^6.2.0", diff --git a/src/CSSTransition.tsx b/src/CSSTransition.tsx index 4ca8d4b8..7abfa62e 100644 --- a/src/CSSTransition.tsx +++ b/src/CSSTransition.tsx @@ -259,7 +259,7 @@ class CSSTransition extends React.Component { } render() { - const { classNames: _, ...props } = this.props; + const { classNames, ...props } = this.props; return ( { children, // filter props for `Transition` in: _in, - mountOnEnter: _mountOnEnter, - unmountOnExit: _unmountOnExit, - appear: _appear, - enter: _enter, - exit: _exit, - timeout: _timeout, - addEndListener: _addEndListener, - onEnter: _onEnter, - onEntering: _onEntering, - onEntered: _onEntered, - onExit: _onExit, - onExiting: _onExiting, - onExited: _onExited, - nodeRef: _nodeRef, + mountOnEnter, + unmountOnExit, + appear, + enter, + exit, + timeout, + addEndListener, + onEnter, + onEntering, + onEntered, + onExit, + onExiting, + onExited, + nodeRef, ...childProps } = this.props; diff --git a/src/TransitionGroup.tsx b/src/TransitionGroup.tsx index e6f64164..f39013f7 100644 --- a/src/TransitionGroup.tsx +++ b/src/TransitionGroup.tsx @@ -120,12 +120,7 @@ class TransitionGroup extends React.Component { const { contextValue } = this.state; // @ts-expect-error FIXME: Type 'undefined' is not assignable to type 'ReactElement>'.ts(2345) const children = values(this.state.children).map(childFactory); - const { - appear: _appear, - enter: _enter, - exit: _exit, - ...delegatingProps - } = props; + const { appear, enter, exit, ...delegatingProps } = props; if (Component === null) { return ( diff --git a/test/SSR-test.js b/test/SSR-test.js index 629acacd..20c282de 100644 --- a/test/SSR-test.js +++ b/test/SSR-test.js @@ -3,6 +3,7 @@ */ // test that import does not crash +// eslint-disable-next-line @typescript-eslint/no-unused-vars import * as ReactTransitionGroup from '../src'; // eslint-disable-line no-unused-vars describe('SSR', () => { diff --git a/yarn.lock b/yarn.lock index f95a0760..e9105f1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4118,6 +4118,16 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" +"@typescript-eslint/parser@4": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + "@typescript-eslint/parser@^4.9.1": version "4.26.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.26.1.tgz#cecfdd5eb7a5c13aabce1c1cfd7fbafb5a0f1e8e" @@ -4136,11 +4146,24 @@ "@typescript-eslint/types" "4.26.1" "@typescript-eslint/visitor-keys" "4.26.1" +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + "@typescript-eslint/types@4.26.1": version "4.26.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.26.1.tgz#9e7c523f73c34b04a765e4167ca5650436ef1d38" integrity sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg== +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + "@typescript-eslint/typescript-estree@4.26.1": version "4.26.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz#b2ce2e789233d62283fae2c16baabd4f1dbc9633" @@ -4154,6 +4177,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@4.26.1": version "4.26.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz#0d55ea735cb0d8903b198017d6d4f518fdaac546" @@ -4162,6 +4198,14 @@ "@typescript-eslint/types" "4.26.1" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -4959,7 +5003,7 @@ axobject-query@^2.2.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== -babel-eslint@^10.0.3, babel-eslint@^10.1.0: +babel-eslint@^10.0.3: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==