From dab68e52aff3438ef2bbd3375a50e909b5e09053 Mon Sep 17 00:00:00 2001 From: Alexander Marks Date: Wed, 9 Jun 2021 12:55:53 -0700 Subject: [PATCH] Replace mwc-tab-bar with custom tab bar (#159) * Run latest prettier format * Remove unused imports * Rename lib/ to internal/ * Add playground-internal-tab and bar * Remove mwc-tab dependency --- .gitignore | 2 +- package-lock.json | 459 ++++-------------- package.json | 4 +- src/configurator/playground-configurator.ts | 4 +- src/configurator/playground-theme-detector.ts | 6 +- src/{lib => internal}/codemirror.ts | 8 +- src/internal/tab-bar.ts | 223 +++++++++ src/internal/tab.ts | 115 +++++ src/{lib => internal}/version.ts | 0 src/playground-code-editor.ts | 2 +- src/playground-file-editor.ts | 2 - src/playground-ide.ts | 2 +- src/playground-project.ts | 2 +- src/playground-tab-bar.ts | 270 ++++------- src/test/playground-code-editor_test.ts | 2 +- src/test/playground-ide_test.ts | 12 +- .../playground-typescript-worker.ts | 21 +- tsconfig.json | 2 +- 18 files changed, 563 insertions(+), 573 deletions(-) rename src/{lib => internal}/codemirror.ts (81%) create mode 100644 src/internal/tab-bar.ts create mode 100644 src/internal/tab.ts rename src/{lib => internal}/version.ts (100%) diff --git a/.gitignore b/.gitignore index 03494c77..6f1319d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /packages/*/node_modules /node_modules -/lib/ +/internal/ /service-worker/ /shared/ /configurator/*.js diff --git a/package-lock.json b/package-lock.json index 9edcaa57..eb83d89e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,6 @@ "@material/mwc-linear-progress": "^0.21.0", "@material/mwc-list": "^0.21.0", "@material/mwc-menu": "^0.21.0", - "@material/mwc-tab": "^0.21.0", - "@material/mwc-tab-bar": "^0.21.0", "@material/mwc-textfield": "^0.21.0", "@types/codemirror": "^5.60.0", "comlink": "=4.3.1", @@ -516,6 +514,7 @@ "version": "0.21.0", "resolved": "https://registry.npmjs.org/@material/mwc-linear-progress/-/mwc-linear-progress-0.21.0.tgz", "integrity": "sha512-BLE2AtOgkvsBQ6oCsXmcWh5TlQUIaDgKWYiYZKGMxGcQckEFx7NulZNk8bC1XwAOX0b0WcscspSwE0ue5FT66A==", + "license": "Apache-2.0", "dependencies": { "@material/linear-progress": "=12.0.0-canary.197f64fa2.0", "@material/theme": "=12.0.0-canary.197f64fa2.0", @@ -642,90 +641,6 @@ "lit-html": "^1.1.1" } }, - "node_modules/@material/mwc-tab": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab/-/mwc-tab-0.21.0.tgz", - "integrity": "sha512-eE89BxK9gRpRuJbWU8W7mto8K2NMlCwl5oER3Y0Vdy/9ptj9sc/05UWpuiP+x2Gq7v3j7kIzXWhP5Gk3ld7LxQ==", - "dependencies": { - "@material/mwc-base": "^0.21.0", - "@material/mwc-ripple": "^0.21.0", - "@material/mwc-tab-indicator": "^0.21.0", - "@material/tab": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "lit-html": "^1.1.2", - "tslib": "^2.0.1" - } - }, - "node_modules/@material/mwc-tab-bar": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-bar/-/mwc-tab-bar-0.21.0.tgz", - "integrity": "sha512-0V7vIsmbVJ8jg5LN3GxD/Q82U8UOZOMxPwzQLWbr4LDVEauNpN5a9JBq8LvcA8ge6xsSyAtfGfFk2OWIYbVypw==", - "dependencies": { - "@material/mwc-base": "^0.21.0", - "@material/mwc-tab": "^0.21.0", - "@material/mwc-tab-scroller": "^0.21.0", - "@material/tab": "=12.0.0-canary.197f64fa2.0", - "@material/tab-bar": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "tslib": "^2.0.1" - } - }, - "node_modules/@material/mwc-tab-bar/node_modules/lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "dependencies": { - "lit-html": "^1.1.1" - } - }, - "node_modules/@material/mwc-tab-indicator": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-indicator/-/mwc-tab-indicator-0.21.0.tgz", - "integrity": "sha512-/4vQoyv+LLctyG4/KZxcjdlWsGd3oevpTaIUz/QALjE+8zooETOpbt2V64Zd2NCn4PPNtKLrTnAGxVhF1eU93w==", - "dependencies": { - "@material/mwc-base": "^0.21.0", - "@material/tab-indicator": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "lit-html": "^1.1.2", - "tslib": "^2.0.1" - } - }, - "node_modules/@material/mwc-tab-indicator/node_modules/lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "dependencies": { - "lit-html": "^1.1.1" - } - }, - "node_modules/@material/mwc-tab-scroller": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-scroller/-/mwc-tab-scroller-0.21.0.tgz", - "integrity": "sha512-Is/bUtmjAveQy8XM6gAtgMyRolyp9qwR9HprCTssreE/bNQYrn0/ME4i/bq8woS+JQ4pFgL6C8Wgtt/0V9H38w==", - "dependencies": { - "@material/dom": "=12.0.0-canary.197f64fa2.0", - "@material/mwc-base": "^0.21.0", - "@material/tab-scroller": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "tslib": "^2.0.1" - } - }, - "node_modules/@material/mwc-tab-scroller/node_modules/lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "dependencies": { - "lit-html": "^1.1.1" - } - }, - "node_modules/@material/mwc-tab/node_modules/lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "dependencies": { - "lit-html": "^1.1.1" - } - }, "node_modules/@material/mwc-textfield": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/@material/mwc-textfield/-/mwc-textfield-0.21.0.tgz", @@ -822,60 +737,6 @@ "tslib": "^2.1.0" } }, - "node_modules/@material/tab": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-MFv9eDgj/BpHiMubE7P+lb44EtwB5HRxZVk4ZuxODrv1Tq/L0/0yBj8aencg0A/NVwKrBt+NJncwsbnnG+IEhg==", - "dependencies": { - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/ripple": "12.0.0-canary.197f64fa2.0", - "@material/rtl": "12.0.0-canary.197f64fa2.0", - "@material/tab-indicator": "12.0.0-canary.197f64fa2.0", - "@material/theme": "12.0.0-canary.197f64fa2.0", - "@material/typography": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-bar": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-5qqMQMLaphtwPmep2nBXp8rBTGIOjFZvxMuYrWwbcBryxmflggxBs2FKy3O01p4RIfw+hvNYKjcKxcexzBRyBw==", - "dependencies": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/density": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/tab": "12.0.0-canary.197f64fa2.0", - "@material/tab-scroller": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-indicator": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-iCH/TQIR6zyQo21BgGSh4CnW+5SNh++mLy3c6UbpRk77KAcGlEn419JwIEWbXSxNs7YTtSqg5AFDgI3JH9bvog==", - "dependencies": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/theme": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-scroller": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-g93N2XOpxhCHCgkceVRsl2g/Mh0/qilxpG/dxZNzTDHvlVc2G/uJN1rrctXsUJGGKAhbsjhZYMsR0+3r7pUlkQ==", - "dependencies": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/dom": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/tab": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, "node_modules/@material/textfield": { "version": "12.0.0-canary.197f64fa2.0", "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-12.0.0-canary.197f64fa2.0.tgz", @@ -1341,9 +1202,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz", + "integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==", "dev": true }, "node_modules/@types/parse5": { @@ -1549,16 +1410,16 @@ } }, "node_modules/@web/test-runner": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.13.4.tgz", - "integrity": "sha512-TuS8UnW+bdY0K2RoqldyORJime4R1cnARvUtxsXJDbHq78Dcfud2xCgrOepQbbxbniF77OShuEEwCXNULftobw==", + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.13.5.tgz", + "integrity": "sha512-S1/fAE1aIJEbKSptinP/m8jvl4PA+RCF2tt7EAyvvucpSzeKo05prht2NLgoJhZJGhSvgdw1BCayOVNXMFfB9A==", "dev": true, "dependencies": { "@web/browser-logs": "^0.2.2", "@web/config-loader": "^0.1.3", "@web/dev-server": "^0.1.17", "@web/test-runner-chrome": "^0.10.0", - "@web/test-runner-commands": "^0.4.5", + "@web/test-runner-commands": "^0.5.0", "@web/test-runner-core": "^0.10.17", "@web/test-runner-mocha": "^0.7.2", "camelcase": "^6.2.0", @@ -1595,9 +1456,9 @@ } }, "node_modules/@web/test-runner-commands": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.4.5.tgz", - "integrity": "sha512-jbhsS+nZmnbZPj/XL/g4se1c9TRtIgwrlYpaIIcWkHhCu5mKbdipgZ/nlFIhFS9UaVY52NiulmVj6dhAx7w4SA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.5.0.tgz", + "integrity": "sha512-yVYJ869/csbDgCNrN2cEwFoX8ZfdAeCXC72CgddKO3jBut2OsFaEy4RWe1uP9Pz9vffiAlV3st3IsnWwTHMLYQ==", "dev": true, "dependencies": { "@web/test-runner-core": "^0.10.14", @@ -1673,9 +1534,9 @@ } }, "node_modules/@web/test-runner-playwright": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@web/test-runner-playwright/-/test-runner-playwright-0.8.5.tgz", - "integrity": "sha512-4UvWKBT/1QogQ1LxFTOB4hrIwEOu6xmYxgRSbaNlQ98ouPApTawXkgKwRcAwJrlAYazzAo98WCQ6w7v+YGxChw==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/@web/test-runner-playwright/-/test-runner-playwright-0.8.6.tgz", + "integrity": "sha512-GjjCd5MtCxmCsNlfe4HmmRyTg1S1SMAn0+i+2yhG9pvYwSJWLmLqN4AE39ZhlhuPh79spSVU889F6CGEXZGXPg==", "dev": true, "dependencies": { "@web/test-runner-core": "^0.10.8", @@ -2294,9 +2155,9 @@ } }, "node_modules/cacache": { - "version": "15.0.6", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz", - "integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.2.0.tgz", + "integrity": "sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw==", "dev": true, "dependencies": { "@npmcli/move-file": "^1.0.1", @@ -2971,9 +2832,9 @@ } }, "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "optional": true, "dependencies": { @@ -4805,9 +4666,9 @@ } }, "node_modules/npm-registry-fetch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.1.1.tgz", - "integrity": "sha512-F6a3l+ffCQ7hvvN16YG5bpm1rPZntCg66PLHDQ1apWJPOCUVHoKnL2w5fqEaTVhp42dmossTyXeR7hTGirfXrg==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.1.2.tgz", + "integrity": "sha512-KsM/TdPmntqgBFlfsbkOLkkE9ovZo7VpVcd+/eTdYszCrgy5zFl5JzWm+OxavFaEWlbkirpkou+ZYI00RmOBFA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0", @@ -4913,9 +4774,9 @@ "dev": true }, "node_modules/open": { - "version": "8.0.9", - "resolved": "https://registry.npmjs.org/open/-/open-8.0.9.tgz", - "integrity": "sha512-vbCrqMav3K8mCCy8NdK4teUky0tpDrBbuiDLduCdVhc5oA9toJMip9rBkuwdwSI9E7NOkz4VkLWPi8DD2MP1gQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.2.0.tgz", + "integrity": "sha512-O8uInONB4asyY3qUcEytpgwxQG3O0fJ/hlssoUHsBboOIRVZzT6Wq+Rwj5nffbeUhOdMjpXeISpDDzHCMRDuOQ==", "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", @@ -5056,9 +4917,9 @@ } }, "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "node_modules/path-type": { @@ -5092,9 +4953,9 @@ "dev": true }, "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true, "engines": { "node": ">=8.6" @@ -5116,9 +4977,9 @@ } }, "node_modules/playwright": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.11.0.tgz", - "integrity": "sha512-s3FQBRpu/pW/vZ/lFYhG/Q3WBUbT2rvMgrgy1PHDA7QtPN910C2rj9Ovd6A/m8yxuLnltd/OKqvlAGevWISHKw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.11.1.tgz", + "integrity": "sha512-UuMrYuvzttbJXUD7sTVcQBsGRojelGepvuQPD+QtVm/n5zyKvkiUErU/DGRXfX8VDZRdQ5D6qVqZndrydC2b4w==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5724,9 +5585,9 @@ } }, "node_modules/rollup": { - "version": "2.48.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz", - "integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==", + "version": "2.50.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.50.0.tgz", + "integrity": "sha512-wO+F2MqWPGUCZx0549oqY8dsQqHVjuSxoyBWWnxKoQE+1UGcDKjtL7wHq/8jnnLJEeoGDQLf3ztrpgRwlbGJ0A==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -6449,9 +6310,9 @@ } }, "node_modules/tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "dependencies": { "punycode": "^2.1.1" @@ -6915,9 +6776,9 @@ "dev": true }, "node_modules/ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true, "engines": { "node": ">=8.3.0" @@ -7582,98 +7443,6 @@ } } }, - "@material/mwc-tab": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab/-/mwc-tab-0.21.0.tgz", - "integrity": "sha512-eE89BxK9gRpRuJbWU8W7mto8K2NMlCwl5oER3Y0Vdy/9ptj9sc/05UWpuiP+x2Gq7v3j7kIzXWhP5Gk3ld7LxQ==", - "requires": { - "@material/mwc-base": "^0.21.0", - "@material/mwc-ripple": "^0.21.0", - "@material/mwc-tab-indicator": "^0.21.0", - "@material/tab": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "lit-html": "^1.1.2", - "tslib": "^2.0.1" - }, - "dependencies": { - "lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "requires": { - "lit-html": "^1.1.1" - } - } - } - }, - "@material/mwc-tab-bar": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-bar/-/mwc-tab-bar-0.21.0.tgz", - "integrity": "sha512-0V7vIsmbVJ8jg5LN3GxD/Q82U8UOZOMxPwzQLWbr4LDVEauNpN5a9JBq8LvcA8ge6xsSyAtfGfFk2OWIYbVypw==", - "requires": { - "@material/mwc-base": "^0.21.0", - "@material/mwc-tab": "^0.21.0", - "@material/mwc-tab-scroller": "^0.21.0", - "@material/tab": "=12.0.0-canary.197f64fa2.0", - "@material/tab-bar": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "tslib": "^2.0.1" - }, - "dependencies": { - "lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "requires": { - "lit-html": "^1.1.1" - } - } - } - }, - "@material/mwc-tab-indicator": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-indicator/-/mwc-tab-indicator-0.21.0.tgz", - "integrity": "sha512-/4vQoyv+LLctyG4/KZxcjdlWsGd3oevpTaIUz/QALjE+8zooETOpbt2V64Zd2NCn4PPNtKLrTnAGxVhF1eU93w==", - "requires": { - "@material/mwc-base": "^0.21.0", - "@material/tab-indicator": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "lit-html": "^1.1.2", - "tslib": "^2.0.1" - }, - "dependencies": { - "lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "requires": { - "lit-html": "^1.1.1" - } - } - } - }, - "@material/mwc-tab-scroller": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@material/mwc-tab-scroller/-/mwc-tab-scroller-0.21.0.tgz", - "integrity": "sha512-Is/bUtmjAveQy8XM6gAtgMyRolyp9qwR9HprCTssreE/bNQYrn0/ME4i/bq8woS+JQ4pFgL6C8Wgtt/0V9H38w==", - "requires": { - "@material/dom": "=12.0.0-canary.197f64fa2.0", - "@material/mwc-base": "^0.21.0", - "@material/tab-scroller": "=12.0.0-canary.197f64fa2.0", - "lit-element": "~2.4.0", - "tslib": "^2.0.1" - }, - "dependencies": { - "lit-element": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.4.0.tgz", - "integrity": "sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==", - "requires": { - "lit-html": "^1.1.1" - } - } - } - }, "@material/mwc-textfield": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/@material/mwc-textfield/-/mwc-textfield-0.21.0.tgz", @@ -7772,60 +7541,6 @@ "tslib": "^2.1.0" } }, - "@material/tab": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-MFv9eDgj/BpHiMubE7P+lb44EtwB5HRxZVk4ZuxODrv1Tq/L0/0yBj8aencg0A/NVwKrBt+NJncwsbnnG+IEhg==", - "requires": { - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/ripple": "12.0.0-canary.197f64fa2.0", - "@material/rtl": "12.0.0-canary.197f64fa2.0", - "@material/tab-indicator": "12.0.0-canary.197f64fa2.0", - "@material/theme": "12.0.0-canary.197f64fa2.0", - "@material/typography": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "@material/tab-bar": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-5qqMQMLaphtwPmep2nBXp8rBTGIOjFZvxMuYrWwbcBryxmflggxBs2FKy3O01p4RIfw+hvNYKjcKxcexzBRyBw==", - "requires": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/density": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/tab": "12.0.0-canary.197f64fa2.0", - "@material/tab-scroller": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "@material/tab-indicator": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-iCH/TQIR6zyQo21BgGSh4CnW+5SNh++mLy3c6UbpRk77KAcGlEn419JwIEWbXSxNs7YTtSqg5AFDgI3JH9bvog==", - "requires": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/theme": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, - "@material/tab-scroller": { - "version": "12.0.0-canary.197f64fa2.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-12.0.0-canary.197f64fa2.0.tgz", - "integrity": "sha512-g93N2XOpxhCHCgkceVRsl2g/Mh0/qilxpG/dxZNzTDHvlVc2G/uJN1rrctXsUJGGKAhbsjhZYMsR0+3r7pUlkQ==", - "requires": { - "@material/animation": "12.0.0-canary.197f64fa2.0", - "@material/base": "12.0.0-canary.197f64fa2.0", - "@material/dom": "12.0.0-canary.197f64fa2.0", - "@material/feature-targeting": "12.0.0-canary.197f64fa2.0", - "@material/tab": "12.0.0-canary.197f64fa2.0", - "tslib": "^2.1.0" - } - }, "@material/textfield": { "version": "12.0.0-canary.197f64fa2.0", "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-12.0.0-canary.197f64fa2.0.tgz", @@ -8251,9 +7966,9 @@ "dev": true }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz", + "integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==", "dev": true }, "@types/parse5": { @@ -8433,16 +8148,16 @@ } }, "@web/test-runner": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.13.4.tgz", - "integrity": "sha512-TuS8UnW+bdY0K2RoqldyORJime4R1cnARvUtxsXJDbHq78Dcfud2xCgrOepQbbxbniF77OShuEEwCXNULftobw==", + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.13.5.tgz", + "integrity": "sha512-S1/fAE1aIJEbKSptinP/m8jvl4PA+RCF2tt7EAyvvucpSzeKo05prht2NLgoJhZJGhSvgdw1BCayOVNXMFfB9A==", "dev": true, "requires": { "@web/browser-logs": "^0.2.2", "@web/config-loader": "^0.1.3", "@web/dev-server": "^0.1.17", "@web/test-runner-chrome": "^0.10.0", - "@web/test-runner-commands": "^0.4.5", + "@web/test-runner-commands": "^0.5.0", "@web/test-runner-core": "^0.10.17", "@web/test-runner-mocha": "^0.7.2", "camelcase": "^6.2.0", @@ -8469,9 +8184,9 @@ } }, "@web/test-runner-commands": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.4.5.tgz", - "integrity": "sha512-jbhsS+nZmnbZPj/XL/g4se1c9TRtIgwrlYpaIIcWkHhCu5mKbdipgZ/nlFIhFS9UaVY52NiulmVj6dhAx7w4SA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.5.0.tgz", + "integrity": "sha512-yVYJ869/csbDgCNrN2cEwFoX8ZfdAeCXC72CgddKO3jBut2OsFaEy4RWe1uP9Pz9vffiAlV3st3IsnWwTHMLYQ==", "dev": true, "requires": { "@web/test-runner-core": "^0.10.14", @@ -8535,9 +8250,9 @@ } }, "@web/test-runner-playwright": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@web/test-runner-playwright/-/test-runner-playwright-0.8.5.tgz", - "integrity": "sha512-4UvWKBT/1QogQ1LxFTOB4hrIwEOu6xmYxgRSbaNlQ98ouPApTawXkgKwRcAwJrlAYazzAo98WCQ6w7v+YGxChw==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/@web/test-runner-playwright/-/test-runner-playwright-0.8.6.tgz", + "integrity": "sha512-GjjCd5MtCxmCsNlfe4HmmRyTg1S1SMAn0+i+2yhG9pvYwSJWLmLqN4AE39ZhlhuPh79spSVU889F6CGEXZGXPg==", "dev": true, "requires": { "@web/test-runner-core": "^0.10.8", @@ -9004,9 +8719,9 @@ "dev": true }, "cacache": { - "version": "15.0.6", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz", - "integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.2.0.tgz", + "integrity": "sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw==", "dev": true, "requires": { "@npmcli/move-file": "^1.0.1", @@ -9545,9 +9260,9 @@ }, "dependencies": { "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "optional": true, "requires": { @@ -10999,9 +10714,9 @@ } }, "npm-registry-fetch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.1.1.tgz", - "integrity": "sha512-F6a3l+ffCQ7hvvN16YG5bpm1rPZntCg66PLHDQ1apWJPOCUVHoKnL2w5fqEaTVhp42dmossTyXeR7hTGirfXrg==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.1.2.tgz", + "integrity": "sha512-KsM/TdPmntqgBFlfsbkOLkkE9ovZo7VpVcd+/eTdYszCrgy5zFl5JzWm+OxavFaEWlbkirpkou+ZYI00RmOBFA==", "dev": true, "requires": { "lru-cache": "^6.0.0", @@ -11083,9 +10798,9 @@ "dev": true }, "open": { - "version": "8.0.9", - "resolved": "https://registry.npmjs.org/open/-/open-8.0.9.tgz", - "integrity": "sha512-vbCrqMav3K8mCCy8NdK4teUky0tpDrBbuiDLduCdVhc5oA9toJMip9rBkuwdwSI9E7NOkz4VkLWPi8DD2MP1gQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.2.0.tgz", + "integrity": "sha512-O8uInONB4asyY3qUcEytpgwxQG3O0fJ/hlssoUHsBboOIRVZzT6Wq+Rwj5nffbeUhOdMjpXeISpDDzHCMRDuOQ==", "dev": true, "requires": { "define-lazy-prop": "^2.0.0", @@ -11184,9 +10899,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { @@ -11217,9 +10932,9 @@ "dev": true }, "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pkg-dir": { @@ -11232,9 +10947,9 @@ } }, "playwright": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.11.0.tgz", - "integrity": "sha512-s3FQBRpu/pW/vZ/lFYhG/Q3WBUbT2rvMgrgy1PHDA7QtPN910C2rj9Ovd6A/m8yxuLnltd/OKqvlAGevWISHKw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.11.1.tgz", + "integrity": "sha512-UuMrYuvzttbJXUD7sTVcQBsGRojelGepvuQPD+QtVm/n5zyKvkiUErU/DGRXfX8VDZRdQ5D6qVqZndrydC2b4w==", "dev": true, "requires": { "commander": "^6.1.0", @@ -11710,9 +11425,9 @@ } }, "rollup": { - "version": "2.48.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz", - "integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==", + "version": "2.50.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.50.0.tgz", + "integrity": "sha512-wO+F2MqWPGUCZx0549oqY8dsQqHVjuSxoyBWWnxKoQE+1UGcDKjtL7wHq/8jnnLJEeoGDQLf3ztrpgRwlbGJ0A==", "dev": true, "requires": { "fsevents": "~2.3.1" @@ -12289,9 +12004,9 @@ } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" @@ -12648,9 +12363,9 @@ "dev": true }, "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 050f9915..2ca20e12 100755 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "playground-service-worker.js", "playground-typescript-worker.js", "playground-styles.{css,js,d.ts,d.ts.map}", - "lib/**/*.{js,d.ts,d.ts.map}", + "internal/**/*.{js,d.ts,d.ts.map}", "shared/**/*.{js,d.ts,d.ts.map}", "src/**/*.{ts,js}", "!src/test/**", @@ -79,8 +79,6 @@ "@material/mwc-linear-progress": "^0.21.0", "@material/mwc-list": "^0.21.0", "@material/mwc-menu": "^0.21.0", - "@material/mwc-tab": "^0.21.0", - "@material/mwc-tab-bar": "^0.21.0", "@material/mwc-textfield": "^0.21.0", "@types/codemirror": "^5.60.0", "comlink": "=4.3.1", diff --git a/src/configurator/playground-configurator.ts b/src/configurator/playground-configurator.ts index c7dcad41..23bb4db4 100644 --- a/src/configurator/playground-configurator.ts +++ b/src/configurator/playground-configurator.ts @@ -184,9 +184,7 @@ export class PlaygroundConfigurator extends LitElement { } private async setValue(id: T, value: KnobValueType) { - await this.setValues( - new Map([[id, value]]) - ); + await this.setValues(new Map([[id, value]])); } private async setValues(values: Map) { diff --git a/src/configurator/playground-theme-detector.ts b/src/configurator/playground-theme-detector.ts index e436f371..227de46f 100644 --- a/src/configurator/playground-theme-detector.ts +++ b/src/configurator/playground-theme-detector.ts @@ -22,7 +22,6 @@ import { } from 'lit-element'; import '../playground-code-editor.js'; import {PlaygroundCodeEditor} from '../playground-code-editor.js'; -import '@material/mwc-tab-bar'; import {tokens} from './highlight-tokens.js'; @customElement('playground-theme-detector') @@ -309,8 +308,9 @@ export class PlaygroundThemeDetector extends LitElement { } } else if (!foundBackground && node.nodeType === Node.ELEMENT_NODE) { // Use the first non-transparent background (depth first). - const background = window.getComputedStyle(node as Element) - .backgroundColor; + const background = window.getComputedStyle( + node as Element + ).backgroundColor; if (background !== 'rgba(0, 0, 0, 0)') { foundBackground = true; this._propertyValues.set('--playground-code-background', background); diff --git a/src/lib/codemirror.ts b/src/internal/codemirror.ts similarity index 81% rename from src/lib/codemirror.ts rename to src/internal/codemirror.ts index 82bfea6d..3acdd82b 100644 --- a/src/lib/codemirror.ts +++ b/src/internal/codemirror.ts @@ -18,6 +18,8 @@ import type CoreMirrorFolding from 'codemirror/addon/fold/foldcode.js'; * This function is defined as window.CodeMirror, but @types/codemirror doesn't * declare that. */ -export const CodeMirror = (window as { - CodeMirror: typeof CodeMirrorCore & typeof CoreMirrorFolding; -}).CodeMirror; +export const CodeMirror = ( + window as { + CodeMirror: typeof CodeMirrorCore & typeof CoreMirrorFolding; + } +).CodeMirror; diff --git a/src/internal/tab-bar.ts b/src/internal/tab-bar.ts new file mode 100644 index 00000000..40d4b568 --- /dev/null +++ b/src/internal/tab-bar.ts @@ -0,0 +1,223 @@ +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +import {html, css, LitElement, customElement, property} from 'lit-element'; +import {ifDefined} from 'lit-html/directives/if-defined.js'; + +import type {PlaygroundInternalTab} from './tab.js'; + +/** + * A horizontal bar of tabs. + * + * Slots: + * - default: The tabs. + */ +@customElement('playground-internal-tab-bar') +export class PlaygroundInternalTabBar extends LitElement { + static styles = css` + :host { + display: flex; + overflow-x: auto; + } + + :host::-webkit-scrollbar { + display: none; + } + + div { + display: flex; + } + `; + + /** + * Aria label of the tab list. + */ + @property() + label?: string; + + /** + * Get or set the active tab. + */ + get active(): PlaygroundInternalTab | undefined { + return this._active; + } + + set active(tab: PlaygroundInternalTab | undefined) { + /** + * Note the active tab can be set either by setting the bar's `active` + * property to the tab, or by setting the tab's `active` property to + * true. The two become synchronized according to the following flow: + * + * bar click/keydown + * | + * v + * bar.active = tab ---> changed? ---> tab.active = true + * ^ | + * | v + * bar tabchange listener changed from false to true? + * ^ | + * | | + * +--- tab dispatches tabchange <---+ + */ + const oldActive = this._active; + if (tab === oldActive) { + return; + } + this._active = tab; + if (oldActive !== undefined) { + oldActive.active = false; + } + if (tab !== undefined) { + tab.active = true; + } else { + // Usually the tab itself emits the tabchange event, but we need to handle + // the "no active tab" case here. + this.dispatchEvent( + new CustomEvent<{tab?: PlaygroundInternalTab}>('tabchange', { + detail: {tab: undefined}, + bubbles: true, + }) + ); + } + } + + private _tabs: PlaygroundInternalTab[] = []; + private _active: PlaygroundInternalTab | undefined = undefined; + + render() { + return html` +
+ +
+ `; + } + + private _onSlotchange(event: Event) { + this._tabs = ( + event.target as HTMLSlotElement + ).assignedElements() as PlaygroundInternalTab[]; + let newActive; + // Manage the idx and active properties on all tabs. The first tab that + // asserts it is active wins. + for (let i = 0; i < this._tabs.length; i++) { + const tab = this._tabs[i]; + tab.index = i; + if (newActive !== undefined) { + tab.active = false; + } else if (tab.active || tab.hasAttribute('active')) { + // Check both the active property and the active attribute, because the + // user could have set the initial active state either way, and it might + // not have reflected to the other yet. + newActive = tab; + } + } + this.active = newActive; + } + + private _activateTab(event: Event) { + const tab = this._findEventTab(event); + if (tab === undefined) { + return; + } + this.active = tab; + this._scrollTabIntoViewIfNeeded(tab); + } + + /** + * If the given tab is not visible, or if not enough of its adjacent tabs are + * visible, scroll so that the tab is centered. + */ + private _scrollTabIntoViewIfNeeded(tab: PlaygroundInternalTab) { + // Note we don't want to use tab.scrollIntoView() because that would also + // scroll the viewport to show the tab bar. + const barRect = this.getBoundingClientRect(); + const tabRect = tab.getBoundingClientRect(); + // Add a margin so that we'll also scroll if not enough of an adjacent tab + // is visible, so that it's clickable. 48px is the recommended minimum touch + // target size from the Material Accessibility guidelines + // (https://material.io/design/usability/accessibility.html#layout-and-typography) + const margin = 48; + if ( + tabRect.left - margin < barRect.left || + tabRect.right + margin > barRect.right + ) { + const centered = + tabRect.left - + barRect.left + + this.scrollLeft - + barRect.width / 2 + + tabRect.width / 2; + this.scroll({left: centered, behavior: 'smooth'}); + } + } + + private async _onKeydown(event: KeyboardEvent) { + const oldIdx = this.active?.index ?? 0; + const endIdx = this._tabs.length - 1; + let newIdx = oldIdx; + switch (event.key) { + case 'ArrowLeft': { + if (oldIdx === 0) { + newIdx = endIdx; // Wrap around. + } else { + newIdx--; + } + break; + } + case 'ArrowRight': { + if (oldIdx === endIdx) { + newIdx = 0; // Wrap around. + } else { + newIdx++; + } + break; + } + case 'Home': { + newIdx = 0; + break; + } + case 'End': { + newIdx = endIdx; + break; + } + } + if (newIdx !== oldIdx) { + // Prevent default scrolling behavior. + event.preventDefault(); + const tab = this._tabs[newIdx]; + this.active = tab; + // Wait for tabindex to update so we can call focus. + await tab.updateComplete; + tab.focus(); + } + } + + private _findEventTab(event: Event): PlaygroundInternalTab | undefined { + const target = event.target as HTMLElement | undefined; + if (target?.localName === 'playground-internal-tab') { + return event.target as PlaygroundInternalTab; + } + for (const el of event.composedPath()) { + if ( + (el as HTMLElement | undefined)?.localName === 'playground-internal-tab' + ) { + return el as PlaygroundInternalTab; + } + } + return undefined; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'playground-internal-tab-bar': PlaygroundInternalTabBar; + } +} diff --git a/src/internal/tab.ts b/src/internal/tab.ts new file mode 100644 index 00000000..64b9b42d --- /dev/null +++ b/src/internal/tab.ts @@ -0,0 +1,115 @@ +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +import { + html, + css, + LitElement, + customElement, + property, + PropertyValues, + query, +} from 'lit-element'; + +/** + * A tab in a . + * + * Slots: + * - default: Label or other contents of the tab. + * + * Parts: + * - button: Button with tab role. + */ +@customElement('playground-internal-tab') +export class PlaygroundInternalTab extends LitElement { + static styles = css` + :host { + display: flex; + } + + button { + flex: 1; + border: none; + color: inherit; + background: transparent; + display: flex; + align-items: center; + cursor: pointer; + position: relative; + outline: none; + } + + button::before { + content: ''; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background: currentcolor; + opacity: 0; + transition: opacity 150ms; + } + + button:focus::before, + button:hover::before { + opacity: 10%; + } + + button:active::before { + opacity: 20%; + } + `; + + /** + * Whether this tab is currently active. + */ + @property({type: Boolean, reflect: true}) + active = false; + + @query('button') + private _button!: HTMLButtonElement; + + /** + * The 0-indexed position of this tab within its . + * + * Note this property is managed by the containing and + * should not be set directly. + */ + index = 0; + + render() { + return html``; + } + + updated(changes: PropertyValues) { + if (changes.has('active') && this.active) { + this.dispatchEvent( + new CustomEvent<{tab?: PlaygroundInternalTab}>('tabchange', { + detail: {tab: this}, + bubbles: true, + }) + ); + } + } + + focus() { + this._button.focus(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'playground-internal-tab': PlaygroundInternalTab; + } +} diff --git a/src/lib/version.ts b/src/internal/version.ts similarity index 100% rename from src/lib/version.ts rename to src/internal/version.ts diff --git a/src/playground-code-editor.ts b/src/playground-code-editor.ts index 2f34d740..dbb86211 100644 --- a/src/playground-code-editor.ts +++ b/src/playground-code-editor.ts @@ -16,7 +16,7 @@ import { } from 'lit-element'; import {nothing} from 'lit-html'; import {ifDefined} from 'lit-html/directives/if-defined.js'; -import {CodeMirror} from './lib/codemirror.js'; +import {CodeMirror} from './internal/codemirror.js'; import playgroundStyles from './playground-styles.js'; import type {Diagnostic} from 'vscode-languageserver'; diff --git a/src/playground-file-editor.ts b/src/playground-file-editor.ts index 8bbd5f67..03ca0753 100644 --- a/src/playground-file-editor.ts +++ b/src/playground-file-editor.ts @@ -14,8 +14,6 @@ import { } from 'lit-element'; import {live} from 'lit-html/directives/live.js'; -import '@material/mwc-icon-button'; - import './playground-code-editor.js'; import {PlaygroundProject} from './playground-project.js'; import {PlaygroundCodeEditor} from './playground-code-editor.js'; diff --git a/src/playground-ide.ts b/src/playground-ide.ts index d381d6f2..de28b6e1 100644 --- a/src/playground-ide.ts +++ b/src/playground-ide.ts @@ -21,7 +21,7 @@ import './playground-file-editor.js'; import './playground-preview.js'; import {PlaygroundProject} from './playground-project.js'; import {ProjectManifest} from './shared/worker-api.js'; -import {version} from './lib/version.js'; +import {version} from './internal/version.js'; /** * A multi-file code editor component with live preview that works without a diff --git a/src/playground-project.ts b/src/playground-project.ts index 280178b9..7db395a4 100644 --- a/src/playground-project.ts +++ b/src/playground-project.ts @@ -33,7 +33,7 @@ import { endWithSlash, forceSkypackRawMode, } from './shared/util.js'; -import {version} from './lib/version.js'; +import {version} from './internal/version.js'; import {Deferred} from './shared/deferred.js'; import type {Diagnostic} from 'vscode-languageserver'; diff --git a/src/playground-tab-bar.ts b/src/playground-tab-bar.ts index 44beb70a..b82692ea 100644 --- a/src/playground-tab-bar.ts +++ b/src/playground-tab-bar.ts @@ -12,23 +12,22 @@ import { internalProperty, query, PropertyValues, - CSSResult, } from 'lit-element'; import {nothing} from 'lit-html'; -import '@material/mwc-tab-bar'; import '@material/mwc-icon-button'; -import {TabBar} from '@material/mwc-tab-bar'; -import {Tab} from '@material/mwc-tab'; -import {style as mwcTabStyle} from '@material/mwc-tab/mwc-tab-css.js'; -import './playground-code-editor.js'; +import './internal/tab-bar.js'; +import './internal/tab.js'; import './playground-file-system-controls.js'; -import {PlaygroundFileEditor} from './playground-file-editor.js'; -import {PlaygroundFileSystemControls} from './playground-file-system-controls.js'; -import {PlaygroundProject} from './playground-project.js'; + import {PlaygroundConnectedElement} from './playground-connected-element.js'; +import type {PlaygroundFileEditor} from './playground-file-editor.js'; +import type {PlaygroundFileSystemControls} from './playground-file-system-controls.js'; +import type {PlaygroundProject} from './playground-project.js'; +import type {PlaygroundInternalTab} from './internal/tab'; + /** * A horizontal bar of tabs for switching between playground files, with * optional controls for create/delete/rename. @@ -40,26 +39,51 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { display: flex; height: var(--playground-bar-height, 40px); background: var(--playground-tab-bar-background, #eaeaea); - flex-direction: row; align-items: center; - --mdc-theme-primary: var(--playground-highlight-color, #6200ee); } - mwc-tab-bar { - overflow: hidden; - height: 100%; - --mdc-tab-height: var(--playground-bar-height, 40px); - --mdc-tab-text-label-color-default: var( - --playground-tab-bar-foreground-color, - #000 + playground-internal-tab-bar { + height: var(--playground-bar-height, 40px); + } + + playground-internal-tab::part(button) { + box-sizing: border-box; + padding: 2px 24px 0 24px; + } + + playground-internal-tab { + color: var(--playground-tab-bar-foreground-color, #000); + font-size: var(--playground-tab-bar-font-size, 0.85em); + border-bottom: 2px solid transparent; + transition: border 150ms; + } + + playground-internal-tab[active] { + color: var( + --playground-tab-bar-active-color, + var(--playground-highlight-color, #6200ee) ); - --mdc-typography-button-text-transform: none; - --mdc-typography-button-font-weight: normal; - --mdc-typography-button-font-size: var( - --playground-tab-bar-font-size, - 0.85em + background: var(--playground-tab-bar-active-background, transparent); + border-color: var( + --playground-tab-bar-indicator-color, + var(--playground-highlight-color, #6200ee) ); - --mdc-typography-button-letter-spacing: normal; + } + + :host([editable-file-system]) playground-internal-tab::part(button) { + /* The 24px menu button with opacity 0 now serves as padding-right. */ + padding-right: 0; + } + + .menu-button { + visibility: hidden; + --mdc-icon-button-size: 24px; + --mdc-icon-size: 16px; + } + + playground-internal-tab:hover > .menu-button, + playground-internal-tab:focus-within > .menu-button { + visibility: visible; } mwc-icon-button { @@ -74,7 +98,7 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { } .add-file-button:hover { - opacity: 100%; + opacity: 1; } `; @@ -82,7 +106,7 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { * Allow the user to add, remove, and rename files in the project's virtual * filesystem. Disabled by default. */ - @property({type: Boolean, attribute: 'editable-file-system'}) + @property({type: Boolean, attribute: 'editable-file-system', reflect: true}) editableFileSystem = false; @internalProperty() @@ -91,9 +115,6 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { @internalProperty() private _activeFileIndex = 0; - @query('mwc-tab-bar') - private _tabBar?: TabBar; - @query('playground-file-system-controls') private _fileSystemControls?: PlaygroundFileSystemControls; @@ -155,18 +176,39 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { render() { return html` - + ${this._visibleFiles.map( - ({name, label}, index) => - html`` + ({name, label}) => + html` + ${label || name} + ${this.editableFileSystem + ? html` + + + + + ` + : nothing} + ` )} - + ${this.editableFileSystem ? html` @@ -176,7 +218,13 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { @click=${this._onClickAddFile} > - + @@ -191,26 +239,23 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { `; } - async updated() { - // TODO(aomarks) There still seems to be a timing bug where the mwc-tab-bar - // activeIndex property doesn't initially take. This hack pokes the bar - // after render to make sure the active tab is really selected. - if (!this._tabBar) { - return; - } - await this._tabBar.updateComplete; - this._tabBar.activeIndex = -1; - this._tabBar.activeIndex = this._activeFileIndex; - } - private _onProjectFilesChanged = () => { this._setNewActiveFile(); this.requestUpdate(); }; - private _onTabActivated(event: CustomEvent<{index: number}>) { - const index = event.detail.index; - const name = this._visibleFiles[index].name; + private _onTabchange( + event: CustomEvent<{ + tab?: PlaygroundInternalTab; + previous?: PlaygroundInternalTab; + }> + ) { + const tab = event.detail.tab; + if (!tab) { + return; + } + const name = tab.dataset.filename!; + const index = tab.index!; if (name !== this._activeFileName) { this._activeFileName = name; this._activeFileIndex = index; @@ -225,8 +270,11 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { return; } controls.state = 'menu'; - controls.filename = this._visibleFiles[event.detail.index].name; - controls.anchorElement = event.detail.anchor; + controls.filename = ( + event.target as HTMLElement + ).parentElement!.dataset.filename; + controls.anchorElement = event.target as HTMLElement; + event.stopPropagation(); } private _onClickAddFile(event: Event) { @@ -277,116 +325,8 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement { } } -/** - * Internal element for tabs within . - * - * This is a subclass of . We subclass because only supports - * text labels, and has no way to slot in our menu button. - * - * Note we can't subclass TabBase, because relies on an instanceof - * check for Tab. - */ -@customElement('playground-tab') -class PlaygroundTab extends Tab { - /** - * Whether to show the 3-dots menu button. - */ - @property({type: Boolean, reflect: true}) - showMenuButton = false; - - /** - * 0-indexed position of this tab in the tab list. - * - * Note this could be parsed from the 1-indexed `id` that sets - * on each instance after slotting, but taking a property here is simpler. - */ - index = 0; - - static styles = ([ - mwcTabStyle, - css` - :host { - /* Vertically center the menu button. */ - display: flex; - align-items: center; - } - - .menu-button { - /* Shift the menu button to be inside the tab itself. */ - margin-left: -24px; - z-index: 1; - opacity: 0; - --mdc-icon-button-size: 24px; - --mdc-icon-size: 16px; - } - - :host(:hover) .menu-button, - :host(:focus) .menu-button { - /* Note we use opacity instead of visibility so that keyboard focus - works. */ - opacity: 100%; - } - - mwc-icon-button { - color: var(--playground-tab-bar-foreground-color); - } - - .mdc-tab--active .mdc-tab__text-label { - color: var( - --playground-tab-bar-active-color, - var(--playground-highlight-color, #6200ee) - ) !important; - } - - .mdc-tab--active { - background: var(--playground-tab-bar-active-background, transparent); - } - - mwc-tab-indicator { - --mdc-theme-primary: var( - --playground-tab-bar-indicator-color, - var(--playground-highlight-color, #6200ee) - ); - } - `, - ] as unknown) as CSSResult; - - render() { - return html`${super.render()} - ${this.showMenuButton ? this._menuButton : nothing} `; - } - - private get _menuButton() { - return html` - - - - - `; - } - - private _onClickMenuButton(event: Event) { - this.dispatchEvent( - new CustomEvent<{index: number; anchor: HTMLElement}>('openMenu', { - composed: true, - detail: { - index: this.index, - anchor: event.target as HTMLElement, - }, - }) - ); - } -} - declare global { interface HTMLElementTagNameMap { 'playground-tab-bar': PlaygroundTabBar; - 'playground-tab': PlaygroundTab; } } diff --git a/src/test/playground-code-editor_test.ts b/src/test/playground-code-editor_test.ts index 2005d9c6..6aa386a9 100644 --- a/src/test/playground-code-editor_test.ts +++ b/src/test/playground-code-editor_test.ts @@ -52,7 +52,7 @@ suite('playground-code-editor', () => { await editor.updateComplete; await new Promise((resolve) => { editor.addEventListener('change', () => resolve()); - const editorInternals = (editor as unknown) as { + const editorInternals = editor as unknown as { _codemirror: PlaygroundCodeEditor['_codemirror']; }; editorInternals._codemirror!.setValue('bar'); diff --git a/src/test/playground-ide_test.ts b/src/test/playground-ide_test.ts index b2676155..fc23da3a 100644 --- a/src/test/playground-ide_test.ts +++ b/src/test/playground-ide_test.ts @@ -148,7 +148,7 @@ suite('playground-ide', () => { 'playground-file-editor', 'playground-code-editor' )) as PlaygroundCodeEditor; - const codemirrorInternals = (codemirror as unknown) as { + const codemirrorInternals = codemirror as unknown as { _codemirror: PlaygroundCodeEditor['_codemirror']; }; codemirrorInternals._codemirror!.setValue('Hello HTML 2'); @@ -178,7 +178,7 @@ suite('playground-ide', () => { ); await assertPreviewContains('Hello JS'); const tabBar = await pierce('playground-ide', 'playground-tab-bar'); - const tabs = tabBar.shadowRoot?.querySelectorAll('playground-tab'); + const tabs = tabBar.shadowRoot?.querySelectorAll('playground-internal-tab'); assert.equal(tabs?.length, 1); }); @@ -200,10 +200,8 @@ suite('playground-ide', () => { ); await assertPreviewContains('Hello JS'); const tabBar = await pierce('playground-ide', 'playground-tab-bar'); - const tabs = tabBar.shadowRoot?.querySelectorAll('playground-tab'); - const texts = Array.from(tabs ?? []).map((tab) => - tab.shadowRoot?.querySelector('button')?.textContent?.trim() - ); + const tabs = tabBar.shadowRoot?.querySelectorAll('playground-internal-tab'); + const texts = Array.from(tabs ?? []).map((tab) => tab.textContent?.trim()); assert.deepEqual(texts, ['HTML', 'JS']); }); @@ -283,7 +281,7 @@ suite('playground-ide', () => { assert.equal(queryHiddenLineNumbers().length, 2); // Add a line. - const editorInternals = (editor as unknown) as { + const editorInternals = editor as unknown as { _codemirror: PlaygroundCodeEditor['_codemirror']; }; editorInternals._codemirror!.setValue(editor.value + '\nBaz'); diff --git a/src/typescript-worker/playground-typescript-worker.ts b/src/typescript-worker/playground-typescript-worker.ts index a6042d06..caf15643 100755 --- a/src/typescript-worker/playground-typescript-worker.ts +++ b/src/typescript-worker/playground-typescript-worker.ts @@ -44,9 +44,11 @@ const makeBareSpecifierTransformVisitor = ( const {type, url} = moduleResolver.resolve(specifier, self.origin); if (type === 'bare') { const newNode = ts.getMutableClone(node); - (newNode as { - moduleSpecifier: ts.ImportDeclaration['moduleSpecifier']; - }).moduleSpecifier = ts.createStringLiteral(url); + ( + newNode as { + moduleSpecifier: ts.ImportDeclaration['moduleSpecifier']; + } + ).moduleSpecifier = ts.createStringLiteral(url); return newNode; } } @@ -112,12 +114,13 @@ const workerAPI: TypeScriptWorkerAPI = { } const transformers: ts.CustomTransformers = { after: [ - (context: ts.TransformationContext) => (node: T) => { - return ts.visitNode( - node, - makeBareSpecifierTransformVisitor(context, moduleResolver) - ); - }, + (context: ts.TransformationContext) => + (node: T) => { + return ts.visitNode( + node, + makeBareSpecifierTransformVisitor(context, moduleResolver) + ); + }, ], }; diff --git a/tsconfig.json b/tsconfig.json index f1b38d08..e83b6e58 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,7 +24,7 @@ "allowSyntheticDefaultImports": true, "importHelpers": true }, - "include": ["src/**/*.ts", "src/lib/worker-api.ts", "src/shared/util.ts"], + "include": ["src/**/*.ts", "src/internal/worker-api.ts", "src/shared/util.ts"], "exclude": ["src/service-worker", "src/shared", "src/typescript-worker"], "references": [ {