diff --git a/.eslintignore b/.eslintignore index b5a60872..2ff523db 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,6 +4,7 @@ node_modules dist # don't lint build folder output build +react # don't lint coverage output coverage # don't lint storybook files diff --git a/.gitignore b/.gitignore index 19f22a4a..08a09ef3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ node_modules/ # Production dist/ +react/ storybook-static/ # Tests diff --git a/.npmignore b/.npmignore index dd3174e3..25d68505 100644 --- a/.npmignore +++ b/.npmignore @@ -28,6 +28,7 @@ storybook-static/ babel.config.js tsconfig.json tsconfig.build.json +tsconfig.eslint.json webpack.config.js rollup.config.js policheck diff --git a/.prettierignore b/.prettierignore index 595ac050..bfa85ccc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,7 @@ node_modules/ # Production build/ dist/ +react/ storybook-static/ # Tests diff --git a/.prettierrc b/.prettierrc index a3852765..cf13ef07 100644 --- a/.prettierrc +++ b/.prettierrc @@ -33,7 +33,7 @@ } }, { - "files": "scripts/setup-webview-test-env.js", + "files": "scripts/*.js", "options": { "printWidth": 200 } diff --git a/api-extractor.json b/api-extractor.json index 0451e991..ff0453eb 100644 --- a/api-extractor.json +++ b/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "dist/dts/index.d.ts", + "mainEntryPointFilePath": "dist/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "docs", diff --git a/package-lock.json b/package-lock.json index a51f82e5..6e0cca1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,9 @@ "version": "0.8.5", "license": "MIT", "dependencies": { - "@microsoft/fast-element": "^1.6.0", - "@microsoft/fast-foundation": "^2.30.0" + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.30.0", + "@microsoft/fast-react-wrapper": "^0.1.18" }, "devDependencies": { "@babel/core": "^7.14.3", @@ -48,6 +49,9 @@ "tslib": "^2.1.0", "typescript": "4.3.5", "webpack": "^4.46.0" + }, + "peerDependencies": { + "react": ">=16.9.0" } }, "node_modules/@babel/code-frame": { @@ -2950,16 +2954,16 @@ } }, "node_modules/@microsoft/fast-element": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.6.2.tgz", - "integrity": "sha512-TrFOpe9k9xIK2iLfIG5T2+bavUAWBvAC/KQ/3ecFsK65l9PAZ/j3zlkyLxNrpIksFtUBkfVdV03kwFurZjqzKQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.7.0.tgz", + "integrity": "sha512-2qpAWuiOSdQfH/XdO8ZtVhlvQVCjHlojWUPoGbvHJDizBccZib+4uGReG87RIBp2Fi0s7ngYPRUioS1Lr+Xe0A==" }, "node_modules/@microsoft/fast-foundation": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.30.0.tgz", - "integrity": "sha512-9rJo8bLMke8pPWkdQBvJPxfqIiqqBkuEUtx65szbkU7HvKyHFX5+C1u+vLOahk7jkehFm4oTB6lp6DfsE878uQ==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.32.0.tgz", + "integrity": "sha512-0RK5c/xNACIXtb05vejIxUQKV1odhNfHykjd+rXeR3EaXIi0gMpzAPnFfEOLLFsjYoi5K4hzAsCAwT6NvCFkZQ==", "dependencies": { - "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-element": "^1.7.0", "@microsoft/fast-web-utilities": "^5.0.2", "tabbable": "^5.2.0", "tslib": "^1.13.0" @@ -2970,6 +2974,18 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/@microsoft/fast-react-wrapper": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.18.tgz", + "integrity": "sha512-xKLNWW+dvd+GAzEmq4DKTikKvOgKVHdLdRoWgmMpKXGD+d4eYf39O5yI3wZoSxKFz7tWv51dYXHnHVMIkzAGgw==", + "dependencies": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.27.2" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, "node_modules/@microsoft/fast-web-utilities": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.0.2.tgz", @@ -17014,8 +17030,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -17378,7 +17393,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -18648,7 +18662,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19983,7 +19996,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -20247,7 +20259,6 @@ "version": "16.14.0", "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -20586,8 +20597,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", @@ -27824,16 +27834,16 @@ } }, "@microsoft/fast-element": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.6.2.tgz", - "integrity": "sha512-TrFOpe9k9xIK2iLfIG5T2+bavUAWBvAC/KQ/3ecFsK65l9PAZ/j3zlkyLxNrpIksFtUBkfVdV03kwFurZjqzKQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.7.0.tgz", + "integrity": "sha512-2qpAWuiOSdQfH/XdO8ZtVhlvQVCjHlojWUPoGbvHJDizBccZib+4uGReG87RIBp2Fi0s7ngYPRUioS1Lr+Xe0A==" }, "@microsoft/fast-foundation": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.30.0.tgz", - "integrity": "sha512-9rJo8bLMke8pPWkdQBvJPxfqIiqqBkuEUtx65szbkU7HvKyHFX5+C1u+vLOahk7jkehFm4oTB6lp6DfsE878uQ==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.32.0.tgz", + "integrity": "sha512-0RK5c/xNACIXtb05vejIxUQKV1odhNfHykjd+rXeR3EaXIi0gMpzAPnFfEOLLFsjYoi5K4hzAsCAwT6NvCFkZQ==", "requires": { - "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-element": "^1.7.0", "@microsoft/fast-web-utilities": "^5.0.2", "tabbable": "^5.2.0", "tslib": "^1.13.0" @@ -27846,6 +27856,15 @@ } } }, + "@microsoft/fast-react-wrapper": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.18.tgz", + "integrity": "sha512-xKLNWW+dvd+GAzEmq4DKTikKvOgKVHdLdRoWgmMpKXGD+d4eYf39O5yI3wZoSxKFz7tWv51dYXHnHVMIkzAGgw==", + "requires": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.27.2" + } + }, "@microsoft/fast-web-utilities": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.0.2.tgz", @@ -38739,8 +38758,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -39028,7 +39046,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -40087,8 +40104,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -41108,7 +41124,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -41315,7 +41330,6 @@ "version": "16.14.0", "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -41579,8 +41593,7 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-lifecycles-compat": { "version": "3.0.4", diff --git a/package.json b/package.json index 11bfbd3d..4e4df5da 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,12 @@ "type": "git", "url": "git+https://github.com/microsoft/vscode-webview-ui-toolkit.git" }, - "main": "dist/esm/index.js", - "types": "dist/dts/index.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "sideEffects": false, "scripts": { "start": "start-storybook -p 6006", - "build": "rollup -c && tsc -p ./tsconfig.json && npm run doc", + "build": "rollup -c && tsc -p ./tsconfig.json && npm run doc && node ./scripts/move-react-build-dir.js", "build:docs": "build-storybook", "deploy:docs": "npm run build:docs && gh-pages -d storybook-static", "doc": "api-extractor run --local", @@ -30,8 +30,12 @@ "test:webview": "npm run build && node ./scripts/setup-webview-test-env.js" }, "dependencies": { - "@microsoft/fast-element": "^1.6.0", - "@microsoft/fast-foundation": "^2.30.0" + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.30.0", + "@microsoft/fast-react-wrapper": "^0.1.18" + }, + "peerDependencies": { + "react": ">=16.9.0" }, "devDependencies": { "@babel/core": "^7.14.3", diff --git a/scripts/helpers.js b/scripts/helpers.js new file mode 100644 index 00000000..0c3185b2 --- /dev/null +++ b/scripts/helpers.js @@ -0,0 +1,76 @@ +const fs = require('fs'); +const path = require('path'); + +function createDir(dir) { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } +} + +function copyDir(source, target) { + let files = []; + const targetFolder = path.join(target, path.basename(source)); + if (!fs.existsSync(targetFolder)) { + fs.mkdirSync(targetFolder); + } + if (fs.lstatSync(source).isDirectory()) { + files = fs.readdirSync(source); + files.forEach(function (file) { + const curSource = path.join(source, file); + if (fs.lstatSync(curSource).isDirectory()) { + copyDir(curSource, targetFolder); + } else { + copyFile(curSource, targetFolder); + } + }); + } +} + +function copyFile(source, target) { + let targetFile = target; + if (fs.existsSync(target)) { + if (fs.lstatSync(target).isDirectory()) { + targetFile = path.join(target, path.basename(source)); + } + } + fs.writeFileSync(targetFile, fs.readFileSync(source)); +} + +const colors = { + reset: '\x1b[0m', + bold: '\x1b[1m', + dim: '\x1b[2m', + red: '\x1b[31m', + green: '\x1b[32m', + cyan: '\x1b[36m', +}; + +function color(opts, text) { + let colorString = ''; + for (const opt of opts) { + colorString += colors[opt]; + } + return `${colorString}${text}${colors.reset}`; +} + +function delDir(path) { + if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { + fs.readdirSync(path).forEach(function (file, index) { + const currPath = path + '/' + file; + if (fs.lstatSync(currPath).isDirectory()) { + delDir(currPath); + } else { + fs.unlinkSync(currPath); + } + }); + fs.rmdirSync(path); + } +} + +module.exports = { + createDir, + copyDir, + copyFile, + color, + delDir, +}; diff --git a/scripts/move-react-build-dir.js b/scripts/move-react-build-dir.js new file mode 100755 index 00000000..7dfb047c --- /dev/null +++ b/scripts/move-react-build-dir.js @@ -0,0 +1,87 @@ +const {copyDir, color, delDir} = require('./helpers'); +const fsPromises = require('fs').promises; +const process = require('process'); + +/** + * Developer note: + * + * The ultimate goal of this script is to enable the ability to import the React components + * with the following syntax: + * + * import { ComponentName } from "@vscode/webview-ui-toolkit/react"; + * + * Without this script, the import statement would instead look like so (note the `dist`): + * + * import { ComponentName } from "@vscode/webview-ui-toolkit/dist/react"; + * + * This import syntax is accomplished by simply moving the already built react directory + * out of the dist directory into the project root and then updating some of the import + * paths in the React build files to reflect this new location. This react folder is + * intentionally not included in .npmignore so it will be published in the root directory + * of the toolkit package. + * + * It's important to note that this script is somewhat brittle because it relies on some + * assumptions about what the import paths in the React build files look like to begin + * with (reference the regex strings in the updateReactBuildImportPaths function). If + * anything about the starting import paths change it will likely break this script. + * + * This is an intentional trade off for implementation simplicity, a light sense of confidence + * that these import paths probably won't change soon, and the fact that this script is supposed + * to be temporary. + * + * Eventually this script should be replaced with TypeScript support for package exports + * (https://github.com/microsoft/TypeScript/issues/33079). It was supposed to arrive in TS v4.5, + * but was pushed back due to stability concerns. When those changes land, the toolkit should be + * updated to the appropriate version of TS and start using the `exports` field in package.json. + * + * Until that time, this script will achieve the same results in import syntax. + */ +async function main() { + // Move the react build directory out of dist and into the project root + try { + console.log(color(['dim'], '\nMoving react build into root...')); + // Delete the root react directory if it already exists + delDir('./react'); + // Copy react build directory into root + copyDir('./dist/react', './'); + // Delete react build directory in dist + delDir('./dist/react'); + } catch (err) { + console.log(`${color(['red'], 'Error: Moving the React build directory into the project root failed.')}\n ${err}`); + process.exit(); + } + + // Update import paths in the React build files to reflect new location + console.log(color(['dim'], 'Updating React build import paths...')); + await updateReactBuildImportPaths('./react/index.js'); + await updateReactBuildImportPaths('./react/index.d.ts'); + + console.log(color(['bold', 'green'], '\nBuild complete!')); +} + +async function updateReactBuildImportPaths(path) { + let result = ''; + + // Read React build file and update import paths if appropriate + try { + const fileContents = await fsPromises.readFile(path, {encoding: 'utf8'}); + // These regex strings rely on an assumption that they will not change + // If importing React components from the toolkit starts to break check here first + result = fileContents.replace(/\.\.\/index/g, '../dist/index'); + result = result.replace(/\.\.\/vscode-design-system/g, '../dist/vscode-design-system'); + result = result.replace(/Pick