diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index ed61fed7..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index eaeeec8a..00000000 --- a/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -/_codemirror/ -/.wireit -/*.d.ts -/*.js -/configurator/ -/demo/ -/examples/ -/internal/ -/service-worker/ -/shared/ -/test/ -/themes/ -/typescript-worker/ diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index a6b95799..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module", - "project": "./tsconfig.json" - }, - "plugins": ["@typescript-eslint", "no-only-tests", "import"], - "rules": { - "no-only-tests/no-only-tests": "error", - "import/extensions": ["error", "always"], - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-floating-promises": "error" - }, - "overrides": [ - { - "files": ["src/playground-styles.ts"], - "rules": { - "no-var": "off" - } - }, - { - "files": [ - "src/typescript-worker/**", - "src/playground-typescript-worker-entrypoint.ts" - ], - "parserOptions": { - "project": "./tsconfig-typescript-worker.json" - } - }, - { - "files": ["src/service-worker/**"], - "parserOptions": { - "project": "./src/service-worker/tsconfig.json" - } - }, - { - "files": ["src/shared/**"], - "parserOptions": { - "project": "./src/shared/tsconfig.json" - } - }, - { - // These files aren't imported into Google so we don't care about floating - // promises. - "files": [ - "scripts/**", - "playwright.config.ts", - "src/configurator/**", - "src/test/**" - ], - "parserOptions": { - "project": null - }, - "rules": { - "@typescript-eslint/no-floating-promises": "off" - } - } - ] -} diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml deleted file mode 100644 index 140b0676..00000000 --- a/.github/workflows/deploy-demo.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: deploy-demo - -on: - push: - branches: - - main - -jobs: - deploy-demo: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - uses: google/wireit@setup-github-actions-caching/v2 - - - run: npm ci - - run: npx playwright install-deps - - run: npx playwright install - - run: npm run build - - - name: Deploy to gh-pages - run: | - cp -r configurator/deploy .. - git fetch origin gh-pages --depth=1 - git checkout --track origin/gh-pages - ls -A1 | grep -vx .git | xargs rm -rf - mv ../deploy/* . - if [[ -n $(git status -s) ]] - then - git config user.name "$GITHUB_ACTOR (bot)" - git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - git add -A - git commit -am "Deploy $GITHUB_SHA" - git push - fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index b25b42d8..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: lint - -on: [push, pull_request] - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - uses: google/wireit@setup-github-actions-caching/v2 - - - run: npm ci - - run: npm run lint diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 3253c822..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: test - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - uses: google/wireit@setup-github-actions-caching/v2 - - - run: npm ci - - run: npx playwright install-deps - - run: npx playwright install - - run: npm test - env: - WIREIT_FAILURES: continue diff --git a/.github/workflows/version-module.yml b/.github/workflows/version-module.yml deleted file mode 100644 index b7abf4e7..00000000 --- a/.github/workflows/version-module.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: version-module - -on: [push, pull_request] - -jobs: - version-module: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - uses: google/wireit@setup-github-actions-caching/v2 - - - run: npm ci - - run: npx playwright install-deps - - run: npx playwright install - # This script automatically fails if the version module is not up-to-date. - - run: npm run update-version-module diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ef10a3cf..00000000 --- a/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -/packages/*/node_modules -/node_modules -/internal/ -/service-worker/ -/shared/ -/configurator/*.js -!/configurator/playground-service-worker.js -/configurator/*.d.ts -/configurator/*.d.ts.map -/configurator/deploy/ -/typescript-worker/ -/playground-typescript-worker.js -/index.js -/index.d.ts -/index.d.ts.map -/playground-*.js -/playground-*.d.ts -/playground-*.d.ts.map -/codemirror-extension*.js -/codemirror-extension*.d.ts -/codemirror-extension*.d.ts.map -/cm-lang-lit.js -/cm-lang-lit.d.ts -/cm-lang-lit.d.ts.map -/test/ -/_codemirror/ -/themes/ -/src/themes/ -/src/_codemirror/codemirror-styles.ts -/src/configurator/themes.ts -.tsbuildinfo -/playground-service-worker.* -/playground-service-worker-proxy.* -/*.tgz -/.wireit -/.eslintcache diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 4479c6fa..00000000 --- a/.prettierignore +++ /dev/null @@ -1,15 +0,0 @@ -*.html -/_codemirror/ -/.wireit -/*.d.ts -/*.js -/configurator/ -/demo/ -/examples/ -/internal/ -/service-worker/ -/shared/ -/src/playground-styles.ts -/test/ -/themes/ -/typescript-worker/ diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index a0f24c99..00000000 --- a/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "singleQuote": true, - "bracketSpacing": false -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0b27791c..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files.exclude": { - "**/bundle": true - }, - "editor.formatOnSave": true, - "files.insertFinalNewline": true, - "typescript.tsdk": "node_modules/typescript/lib" -} diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 8aca78a5..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,1289 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) -and this project adheres to [Semantic Versioning](http://semver.org/). - - - - - - - -## [0.21.2] - 2025-10-02 - -### Fixed - -- Only fire change event on non-programmatic changes - -### Changed - -- Make `tabchange` event bubble. - -## [0.21.1] - 2025-09-26 - -### Fixed - -- Fixed missing `codemirror-extension-mixin.js` file. - -## [0.21.0] - 2025-09-23 - -### Changed - -- **POTENTIALLY BREAKING** Upgraded CodeMirror to v6 - -### Added - -- Added `extensions` property to ``, - ``, and `` for applying - programmatic CodeMirror extensions. -- Added an `extensions` slot to ``, - ``, and `` for applying - declarative CodeMirror extensions. -- Exported `codemirrorExtensionMixin` for creating declarative CodeMirror - extensions. - -### Fixed - -- Safari cursor issues - - Cursor selection and visiblity was broken in Safari - - Fixed by updating to Codemirror 6 - - - -## [0.20.0] - 2025-03-31 - -### Added - -- Implement `cdnBaseUrl` property to allow changing the underlying npm CDN base url. See [README](README.md) for more information. - -### Fixed - -- Make playground-elements more resilient to 404's from the CDN by not throwing errors when they occur. Instead, log a warning and continue to load the rest of the project. - -## [0.19.1] - 2024-08-19 - -### Fixed - -- Fix broken import of typescript.js module - -## [0.19.0] - 2024-08-19 - -### Changed - -- Upgraded to TypeScript 5.2 and Lit 3.0 -- **BREAKING** Use modules in workers. See [caniuse.com's support table](https://caniuse.com/mdn-api_worker_worker_ecmascript_modules) for browser support information. -- Updated `comlink`, `fuse.js`, and `tslib` dependencies. - -## [0.18.1] - 2023-08-10 - -### Fixed - -- Fix tab-to-spaces conversion in the code editor which was resulting in one less space being produced on tab than desired. - -## [0.18.0] - 2023-05-25 - -### Changed - -- **BREAKING** Update bundled version of TypeScript from `4.8.4` to `5.0.4`. See [TypeScript 5 breaking changes](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#breaking-changes-and-deprecations). - -## [0.17.1] - 2023-04-25 - -### Added - -- Fetch all `@types` packages listed in the project's `package.json` file and - include them for TypeScript compilation. This allows type-checking packages - that do not ship their own types but do have a DefinitelyTyped package - available. Note: This does not automatically download the `@types` package for - a package. It must be manually listed in `package.json`. - -## [0.17.0] - 2022-11-11 - -### Changed - -- Replaced `vscode-languageserver` dependency with smaller - `vscode-languageserver-protocol`. -- TypeScript version upgraded from `4.4.4` to `4.8.4`. -- `PlaygroundConnectedElement` `project` is now permitted to be `undefined` according to TypeScript. -- Upgrade `codemirror` from `5.63.0` to `5.65.9`. -- **BREAKING** Switched TypeScript `moduleResolution` from `esnext` to `nodenext`. -- **BREAKING** Bumped TypeScript `target` from `es2017` to `es2021`. -- **BREAKING** The local `package.json` is now passed to TypeScript for - compilation, and the default value of the `type` field is modified to - `module`. - -## [0.16.3] - 2022-08-02 - -### Added - -- Added styntax highlighting for `jsx` and `tsx` modules. - -## [0.16.2] - 2022-06-16 - -### Added - -- Added support for compiling `jsx` and `tsx` modules. - -## [0.16.1] - 2022-05-17 - -### Changed - -- Upgraded MWC dependencies. - -## [0.16.0] - 2022-05-11 - -### Changed - -- **BREAKING** Added `browser` to the set of export conditions used during - module resolution. - -## [0.15.5] - 2022-05-06 - -### Added - -- Added `lineWrapping` property (`line-wrapping` attribute) to - ``, `` and `` - which when enabled wraps long lines, otherwise the editor will scroll. Off by - default. - -### Fixed - -- Fix typo in README. Add missing forward slash in escaped script tag. - -## [0.15.4] - 2022-04-05 - -### Added - -- Add the ability to select a file by setting `selected: true` in a project - config, or by setting the `selected` attribute on slotted children. - -## [0.15.3] - 2022-03-29 - -### Fixed - -- Fixed the hiding of comments that surround a fold/hide code block from - creating invisible readonly regions. - -- Refactored fold/hide marker logic so it doesn't add document history when - clearing the prior fold/hide markers. - -- Fix typo and incorrectly documented event name in README. `changed` event - should instead be `change`. - -## [0.15.2] - 2022-03-24 - -### Added - -- Make hidden code blocks readonly to prevent accidental erasure. - -- Added `Ctrl+/` or `Cmd+/` hotkey for toggling line comments. - -- Added keyboard shortcut documentation to the playground-code-editor README. - -## [0.15.1] - 2022-03-16 - -### Changed - -- playground-preview now exposes the internal iframe via the `iframe` property. - -## [0.15.0] - 2022-03-07 - -### Added - -- Added `noCompletions` property documentation to README. - -### Fixed - -- Normalize content-type response header to lowercase when matching filetypes. - -## [0.15.0-pre.5] - 2022-02-23 - -### Added - -- More mobile friendly completion items via media query - -### Fixed - -- Pressing ESC to close completions menu doesn't de-focus the code-editor - -- Word wrapping on long completion item details doesn't extend to multiple lines - -- Elevation on completion items list matches other elevations on project - -## [0.15.0-pre.4] - 2022-02-17 - -### Added - -- Added `Ctrl-Space` hotkey for triggering interactive code completions. - -## [0.15.0-pre.3] - 2022-02-16 - -### Fixed - -- Fixed syntax highlighting and code folding regressions introduced when using - `documentKey`. - -## [0.15.0-pre.2] - 2022-02-15 - -### Added - -- Added `documentKey` property to `` which is - used to keep track of individual CodeMirror document instances internally. - Default behavior without setting a `documentKey` is unchanged. - - Use `documentKey` for fine control over the CodeMirror document instance. For - example, to model changing a file. - -### Fixed - -- Fixed undo history applying across files - ([#154](https://github.com/google/playground-elements/issues/154)). - - Previously all files shared the same document instance resulting in files - sharing undo/redo history. Now each file has its own isolated internal - document instance. - -- Fixed only a single closing script tag unescaping in html files using - playground-ide - ([#251](https://github.com/google/playground-elements/issues/251)). - -## [0.15.0-pre.1] - 2022-02-04 - -### Added - -- Added interactive code completions for TypeScript files - ([#243](https://github.com/google/playground-elements/pull/243)). - - Completions can be disabled by setting the `no-completions` attribute on - ``, ``, or ` - components. - -## [0.14.8] - 2022-01-25 - -### Added - -- Added `html-file` attribute (`htmlFile` property) to `playground-preview` and - `playground-ide` which allows configuring the project HTML file which should - be displayed in the preview. Defaults to `index.html` (which was previously - the only possible value) - -### Fixed - -- Remove nbsp characters from README. - -## [0.14.7] - 2021-12-07 - -### Fixed - -- Fixed missing `aria-label` attributes on the reload button, file context menu - button, and new file button - -## [0.14.6] - 2021-10-18 - -### Fixed - -- Fixed bug where files could not be deleted or renamed using MWC v0.25.2 or - above. - -## [0.14.5] - 2021-10-07 - -### Fixed - -- Upgraded `es-module-lexer` dependency to bring in fix for - https://github.com/guybedford/es-module-lexer/issues/92. - -## [0.14.4] - 2021-10-06 - -### Fixed - -- Fixed positioning of overlay that displays over previews when service workers - are not available so that it is constrained to the preview, rather than the - nearest containing positioned ancestor. - -## [0.14.3] - 2021-10-06 - -### Added - -- Added an overlay that will display over the preview when we detect that - service workers are not available. One reason this can happen is using - Playground in Firefox private browsing mode, which does not support service - workers (https://bugzilla.mozilla.org/show_bug.cgi?id=1320796). - -- Added `cursorPosition`, `cursorIndex`, and `tokenUnderCursor` getters to - ``. - -### Changed - -- Upgraded dependencies, including CodeMirror. - -### Fixed - -- Fixed a bottleneck that prevented previews from loading until semantic - TypeScript errors were computed. This should significantly improve the latency - between updating a file and the new preview loading. - -- Fixed bug where parent window history entries were added every time the - preview reloaded. - -- Improvements to service worker version updates: - - - The service worker will require less frequent updates going forward. - Previously it needed updating for every playground-elements release. Now it - only needs updating if the bytes of the service worker have changed between - releases. - - - The default service worker scope has changed from - `/playground-project` to - `/__playground_swfs_`. This should make service - worker updates more reliable because old and new versions of service workers - will no longer be in contention to control the same URLs. - - - Misc other small service worker robustness improvements, and additional - logging to help debug future issues. - -## [0.14.2] - 2021-09-30 - -### Changed - -- Updated bundled version of TypeScript to 4.4.3. -- Internal refactoring of language service. - -## [0.14.1] - 2021-09-21 - -### Changed - -- GitHub org changed from PolymerLabs to google. - -## [0.14.0] - 2021-09-20 - -### Changed - -- Upgrade to Lit 2.0. -- TypeScript files are now compiled incrementally for improved performance - -### Fixed - -- Fixed bug where the `value` property of a `` did not take effect if set before element upgrade. - -### Added - -- It is now possible to set the `value` of a `` using the `value` HTML attribute. - -## [0.13.0] - 2021-09-14 - -### Changed - -- Node [package exports](https://nodejs.org/api/packages.html#packages_exports) - are now supported when resolving dependency modules. - - The `module`, `import`, and `development` - [conditions](https://nodejs.org/api/packages.html#packages_conditional_exports) - are enabled. - - Note this change should not theoretically be **BREAKING**, but this release is - versioned with a major increment because there a risk of breakage in practice - due to misconfigured `package.json` files, differences between `prod` and - `dev` modes, etc. - -### Added - -- Added `modified` property to `` and `` - which indicates whether the user has modified, added, or removed any project - files. Resets whenever a new project is loaded. - -## [0.12.1] - 2021-08-26 - -### Changed - -- If a file is marked `hidden`, and the user creates a new file by that name, - the file will become visible and editable. - -## [0.12.0] - 2021-08-17 - -### Fixed - -- Fixes duplicate module errors by canonicalizing all import specifiers. Import - specifiers are now canonicalized by version number and default module. This - applies both to local project files, and throughout the entire external - dependency tree. - -- Import maps now apply to modules in external dependencies, not just to local - project files. - -- The TypeScript compiler can now deal with multiple versions of the same - dependency. Previously, if the import graph included two versions of the same - package, only one arbitrary version of the types would be compiled. This - caused various errors and missing type issues. - -### Changed - -- If the project contains a `package.json` file, then its - [`dependencies`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#dependencies) - field will be used to determine the version of dependencies (just like how NPM - works locally). - -- Dependencies are now served from the special - "/node_modules/..." path, instead of directly from - `https://unpkg.com/...?module` URLs. Behind-the-scenes, dependencies are still - fetched from unpkg, but they are now themselves transformed to ensure correct - specifier canonicalization. - -- **BREAKING** Due to large changes to the way dependencies are handled, there - is some risk of breakage due to subtle behavior changes that existing - configurations may be relying on. Therefore, this release is versioned with a - major increment. - -## [0.11.1] - 2021-08-09 - -### Added - -- Added MIME-type detection for the following project file extensions: `gif`, - `ico`, `jpeg`, `jpg`, `mid`, `midi`, `mp3`, `png`, `svg`, `weba`, `webm`, - `webp`. - -## [0.11.0] - 2021-07-28 - -### Fixed - -- Playgrounds now ensure that the service worker they are connected to have a - matching version. Fixes issues relating to playgrounds being broken for some - time after an upgrade. - -- The `--playground-tab-bar-font-size` CSS custom property now behaves as - documented, and defaults to `14px`. - -- The `--playground-floating-controls-color` CSS custom property now behaves as - documented. - -- Fix missing `.js` extension from import in `build.js` that may have broken - Webpack and other builds. - -- The hover effect and touch area for tabs in the tab bar are no longer offset - by the height of the active tab indicator. - -- Fix bug that caused failures to load `d.ts` files and "Could not resolve - module specifier" console errors when using import maps. - -### Changed - -- **BREAKING** `playground-base-url` is now resolved relative to the - `import.meta.url` of the module containing the definition of - ``, instead of relative to `document.location.href` as - before. This means that `.` can now be used to refer to the local playground - installation directory. - -- The service worker now sets the `Origin-Agent-Cluster: ?1` heading on all - responses, to encourage browsers to allocate a separate process or thread for - Playground preview iframe under certain conditions. See the [Process - isolation](https://github.com/google/playground-elements#process-isolation) - section of the README for more details. - -- It is now possible to change the `font-family` of the tab-bar using a - `::part(tab-bar)` selector. - -## [0.10.1] - 2021-07-14 - -### Changed - -- Bumped MWC dependency versions. - -## [0.10.0] - 2021-07-01 - -### Added - -- Adds `--playground-code-padding` and `--playground-code-line-padding` for - configuring code editor padding. - -- Bare module specifiers are now transformed in dynamic `import()` statements. - -### Changed - -- **BREAKING** The `src/` directory is no longer published to NPM. - -- **BREAKING** `.js` files are no longer compiled by TypeScript, so they cannot - contain types, decorators, or other TypeScript-specific syntax. - -- Previews will now begin loading immediately, instead of waiting for - compilation to completely finish, and each `.js` file is served as it - compiles. - -### Fixed - -- Query parameters are now ignored when serving files from the virtual file - system. - -## [0.9.4] - 2021-05-18 - -### Fixed - -- Fixed timeouts when using the default `unpkg.com` service worker origin, - caused by `comlink` versions being out-of-sync between local components and - remote service worker. - -### Added - -- Added `readonly` property to ``. - -## [0.9.3] - 2021-05-05 - -### Changed - -- Error tooltips now follow `--playground-code-font-family`. -- Optimized the UX for fast compile and display by switching to a leading edge - debouncer and eliminating the minimum display time for the loading bar. - -## [0.9.2] - 2021-04-26 - -### Changed - -- Playground now executes code on the unpkg.com origin by default, meaning user - code execution is now sandboxed by default. The sandbox URL can still be - changed with the `sandboxBaseUrl` property or `sandbox-base-url` attribute, - though it is highly advisable to always use a separate and unprivileged - origin. - -## [0.9.1] - 2021-04-19 - -### Changed - -- Tab key now inserts 2 spaces instead of a tab character. - -### Fixed - -- Fixed missing vertical scrollbars. -- Fixed transparent region between horizontal and vertical scrollbars. - -## [0.9.0] - 2021-04-13 - -### Changed - -- Focusing the editor using the Tab key no longer activates edit mode - immediately. This prevents the Tab key from being trapped, which was an - accessibility problem for keyboard users. - - Instead, when the editor is focused, users can now press Enter to begin - editing, and Escape to stop editing. A prompt is displayed with these - instructions when focused. Focusing the editor with a mouse click continues to - activate edit mode immediately, as before. - -- The editor now uses the CodeMirror `contenteditable` input style, which has - much better screen reader support. - -- Line numbers are now annotated with `aria-hidden` so that they are not voiced - by screen readers. - -- Increased default `line-height` from `normal` to `1.4em`. - -- Added a default `padding-left` of `1em`. - -- Increased width of cursor from `1px` to `2px`. - -- Increased default tab `font-size` from `0.75rem` to `0.8em`; - -- Increased default `--playground-bar-height` from `35px` to `40px. - -- `--playground-cursor-color` now defaults to the value of - `--playground-code-default-color`. - -- `--playground-code-gutter-background` now defaults to the value of - `--playground-code-background`. - -- `--playground-code-gutter-margin-right` default changed from `1px solid #ddd` to `none`. - -- `--playground-code-linenumber-color` default changed from `#999` to `#767676`. - -### Added - -- Added `playground-styles.css` and `playground-styles.js` which can be imported - to apply Playground styles to server-side rendered code. - -- Added `dialog` CSS shadow part to `code-editor`, `file-editor`, and `ide` for - styling modal dialogs that appear over the editor (currently just used for the - keyboard help that shows when the editor is focused using the keyboard). - -- Added CSS custom properties: - - - `--playground-code-line-height`: `line-height` of code in the editor. - - `--playground-tab-bar-font-size`: `font-size` of tabs in the file picker tab - bar. - - `--playground-tab-bar-active-color`: Text `color` of active file-picker tab. - - `--playground-tab-bar-indicator-color`: `color` of the active tab indicator - line (use `transparent` to hide). - - `--playground-tab-bar-active-background`: `background` of the active file-picker tab. - -- Added `aria-label` attribute to reload, new file, and file context menu - buttons. - -- Added `title` attribute to preview ` + `}_slotChange(){var e;const{type:t}=this._source;if("none"!==t&&"slot"!==t)return;const r=[];let o;for(const t of this._slot.assignedElements({flatten:!0})){const i=t.getAttribute("type");if(!(null==i?void 0:i.startsWith("sample/")))continue;const n=i.substring(7);let a=null!==(e=t.textContent)&&void 0!==e?e:"";if("html"===n&&(a=a.replace(/<\//g,"0||void 0!==o)&&(this._source={type:"slot",files:r,importMap:null!=o?o:{}})}async firstUpdated(){const e=("cdn.skypack.dev"===(t=new URL("./playground-typescript-worker.js",import.meta.url)).hostname&&(t.pathname=t.pathname.replace(/mode=imports\/(un)?optimized/,"mode=raw")),t);var t;let r;if(e.origin===window.location.origin)r=new Worker(e,{type:"module"});else{const t=await fetch(e.href),o=await t.text(),i=URL.createObjectURL(new Blob([o],{type:"application/javascript"}));r=new Worker(i),URL.revokeObjectURL(i)}this._deferredTypeScriptWorkerApi.resolve(Ie(r))}_onServiceWorkerProxyIframeLoad(){const{port1:e,port2:t}=new MessageChannel;e.addEventListener("message",(e=>{3===e.data.type&&this._onNewServiceWorkerPort(e.data.port)})),e.start(),this._postMessageToServiceWorkerProxyIframe({type:1,scope:this.sandboxScope,port:t},[t])}_onNewServiceWorkerPort(e){const t=r=>{4===r.data.type&&(e.removeEventListener("message",t),r.data.version===Rt?(this._serviceWorkerAPI=Ie(e),this._serviceWorkerAPI.setFileAPI(Ue({getFile:e=>this._getFile(e)}),this._sessionId)):(console.info(`Playground service worker is outdated. Want ${Rt} but got ${r.data.version}. Waiting for update.`),this._postMessageToServiceWorkerProxyIframe({type:6})))};e.addEventListener("message",t),e.start()}_postMessageToServiceWorkerProxyIframe(e,t){const r=this._serviceWorkerProxyIframe.contentWindow;if(!r)throw Error("Unexpected internal error: service worker proxy iframe had no contentWindow");r.postMessage(e,"*",t)}async _getFile(e){return void 0===this._build?{status:503,body:"Playground build not started"}:this._build.getFile(e)}async save(){var e,t;null===(e=this._build)||void 0===e||e.cancel();const r=new Dt((()=>{this.dispatchEvent(new CustomEvent("diagnosticsChanged"))}));this._build=r,this.dispatchEvent(new CustomEvent("compileStart"));const o=await this._deferredTypeScriptWorkerApi.promise;"active"===r.state()&&(o.compileProject(null!==(t=this._files)&&void 0!==t?t:[],{importMap:this._importMap},Ue((e=>r.onOutput(e)))),await r.stateChange,"done"===r.state()&&this.dispatchEvent(new CustomEvent("compileDone")))}async getCompletions(e){var t,r,o;const i=e.tokenUnderCursor.trim();if(!e.isRefinement){const t=await this._deferredTypeScriptWorkerApi.promise,r=await t.getCompletions(e.fileName,e.fileContent,i,e.cursorIndex,{importMap:this._importMap});if(r){const t=this._getCompletionDetails.bind(this);this._completionInfo=function(e,t,r,o){const i=e;return i.entries=null==e?void 0:e.entries.map((e=>({...e,_details:void 0,get details(){return this._details||(this._details=o(t,r,e.name)),this._details}}))),i}(r,e.fileName,e.cursorIndex,t)}}let n=[];return n="."===e.tokenUnderCursor||""===e.tokenUnderCursor?function(e,t=""){var r;return null!==(r=null==e?void 0:e.map((e=>({text:t+e.name,displayText:e.name,score:Number.parseInt(e.sortText),get details(){return e.details}}))))&&void 0!==r?r:[]}(null===(t=this._completionInfo)||void 0===t?void 0:t.entries,e.tokenUnderCursor): +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +function(e,t){if(!e)return[];const r=new Mt(null!=e?e:[],{threshold:.3,shouldSort:!0,isCaseSensitive:!0,includeScore:!0,includeMatches:!0,keys:["name"],minMatchCharLength:Math.max(t.length/1.2,1)}).search(t).map((e=>{var t;return{text:e.item.name,displayText:e.item.name,score:null!==(t=e.score)&&void 0!==t?t:0,matches:e.matches,get details(){return e.item.details}}})).sort(((e,t)=>e.score===t.score?e.text.localeCompare(t.text):e.score-t.score));return r}(null===(r=this._completionInfo)||void 0===r?void 0:r.entries,i),null===(o=n[0])||void 0===o||o.details,n}async _getCompletionDetails(e,t,r){const o=await this._deferredTypeScriptWorkerApi.promise;return await o.getCompletionItemDetails(e,t,{importMap:this._importMap},r)}async saveDebounced(){this.savePending||(this.savePending=!0,await this.lastSave,this.savePending=!1,this.lastSave=this.save())}isValidNewFilename(e){var t;if(!e)return!1;const r=null===(t=this._files)||void 0===t?void 0:t.find((t=>t.name===e));return void 0===r||!0===r.hidden}editFile(e,t){e.content=t,this._modified=void 0,this.saveDebounced()}addFile(e){var t;if(!this._files||!this.isValidNewFilename(e))return;const r=null===(t=this._files)||void 0===t?void 0:t.find((t=>t.name===e));!0===(null==r?void 0:r.hidden)?r.hidden=!1:this._files.push({name:e,content:"",contentType:Kt(e)}),this._modified=void 0,this.requestUpdate(),this.dispatchEvent(new Ht),this.save()}deleteFile(e){if(!this._files)return;const t=this._files.findIndex((t=>t.name===e));t<0||(this._files=[...this._files.slice(0,t),...this._files.slice(t+1)],this._modified=void 0,this.dispatchEvent(new Ht),this.save())}renameFile(e,t){if(!e||!this._files)return;if(!this.isValidNewFilename(t))return;const r=this._files.find((t=>t.name===e));r&&(r.name=t,r.contentType=Kt(t),this._files=[...this._files],this._modified=void 0,this.dispatchEvent(new Ht),this.save())}};Ut.styles=c` + iframe { + display: none; + } + `,o([ge({attribute:"project-src",hasChanged:()=>!1})],Ut.prototype,"projectSrc",null),o([ge({attribute:!1,hasChanged:()=>!1})],Ut.prototype,"config",null),o([me()],Ut.prototype,"_source",void 0),o([ge({attribute:"sandbox-base-url"})],Ut.prototype,"sandboxBaseUrl",void 0),o([ge({attribute:"sandbox-scope"})],Ut.prototype,"sandboxScope",void 0),o([me()],Ut.prototype,"_serviceWorkerAPI",void 0),o([ye("slot")],Ut.prototype,"_slot",void 0),o([ye("iframe")],Ut.prototype,"_serviceWorkerProxyIframe",void 0),Ut=o([ue("playground-project")],Ut);const Bt=async(e,t=new Set,r=new Set)=>{if(r.has(e))throw Error("Circular project config extends: "+[...r.values(),e].join(" extends "));r.add(e);const o=await fetch(e);if(200!==o.status)throw Error(`Error ${o.status} fetching project config from ${e}: ${await o.text()}`);let i;try{i=await o.json()}catch(t){throw Error(`Error parsing project config JSON from ${e}: ${t.message}`)}return await Wt(i,e,t,r)},Wt=async(e,t,r=new Set,o=new Set)=>{var i,n,a,l,s;const d=[];for(const[o,l]of Object.entries(null!==(i=e.files)&&void 0!==i?i:{}))r.has(o)||(r.add(o),void 0===l.content?d.push((async()=>{var e,r;const i=await fetch(new URL(o,t).href);return{...l,name:o,content:await i.text(),contentType:null!==(r=null===(e=i.headers.get("Content-Type"))||void 0===e?void 0:e.toLowerCase())&&void 0!==r?r:"text/plain"}})()):d.push(Promise.resolve({...l,name:o,content:null!==(n=l.content)&&void 0!==n?n:"",contentType:null!==(a=Kt(o))&&void 0!==a?a:"text/plain"})));const c=e.extends?Bt(new URL(e.extends,t).href,r,o):void 0,u=await Promise.all(d),p=null!==(l=e.importMap)&&void 0!==l?l:{};if(c){const e=await c;u.push(...e.files),p.imports={...null===(s=e.importMap)||void 0===s?void 0:s.imports,...p.imports}}return{files:u,importMap:p}},Kt=e=>{const t=e.lastIndexOf(".");if(-1===t||t===e.length-1)return;const r=e.slice(t+1);return jt(r)},jt=e=>{if(void 0!==e)switch(e){case"ts":return"video/mp2t";case"js":return"application/javascript; charset=utf-8";case"json":return"application/json; charset=utf-8";case"jsx":return"text/jsx; charset=utf-8";case"tsx":return"text/typescript-jsx; charset=utf-8";case"html":return"text/html; charset=utf-8";case"css":return"text/css; charset=utf-8";case"svg":return"image/svg+xml";case"png":return"image/png";case"gif":return"image/gif";case"jpeg":case"jpg":return"image/jpeg";case"ico":return"image/vnd.microsoft.icon";case"webp":return"image/webp";case"webm":return"video/webm";case"mid":case"midi":return"audio/midi";case"mp3":return"audio/mpeg";case"weba":return"audio/webm"}},Vt=e=>{const t=[];if("object"!=typeof e||null===e)return t.push(`Import map is invalid because it must be an object, but it was ${null===e?"null":typeof e}.`),t;const r=Object.keys(e).filter((e=>"imports"!==e));r.length>0&&t.push(`Invalid import map properties: ${[...r].join(", ")}. Only "imports" are currently supported.`);const o=e.imports;if(void 0===o)return t;if("object"!=typeof o||null===o)return t.push(`Import map "imports" property is invalid because it must be an object, but it was ${null===o?"null":typeof o}.`),t;for(const[e,r]of Object.entries(o))if("string"==typeof r){e.endsWith("/")&&!r.endsWith("/")&&t.push(`Import map key "${e}" is invalid because address "${r}" must end in a forward-slash.`);try{new URL(r)}catch{t.push(`Import map key "${e}" is invalid because address "${r}" is not a valid URL.`)}}else t.push(`Import map key "${e}" is invalid because address must be a string, but was `+(null===r?"null":typeof r));return t},qt=e=>{let t;e=e.replace(/(^[\n\s]*\n)|(\n[\n\s]*$)/g,"");for(const r of e.split(/\n/g)){const e=r.match(/^\s*/)[0].length;(void 0===t||e{if(e.length!==t.length)return!1;for(let r=0;r{e.classList.add(t)},removeClass:t=>{e.classList.remove(t)},hasClass:t=>e.classList.contains(t)}}const Qt=()=>{},Yt={get passive(){return!1}};document.addEventListener("x",Qt,Yt),document.removeEventListener("x",Qt);const Xt=(e=window.document)=>{let t=e.activeElement;const r=[];if(!t)return r;for(;t&&(r.push(t),t.shadowRoot);)t=t.shadowRoot.activeElement;return r},$t=e=>{const t=Xt();if(!t.length)return!1;const r=t[t.length-1],o=new Event("check-if-focused",{bubbles:!0,composed:!0});let i=[];const n=e=>{i=e.composedPath()};return document.body.addEventListener("check-if-focused",n),r.dispatchEvent(o),document.body.removeEventListener("check-if-focused",n),-1!==i.indexOf(e)}; +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +class er extends de{click(){if(this.mdcRoot)return this.mdcRoot.focus(),void this.mdcRoot.click();super.click()}createFoundation(){void 0!==this.mdcFoundation&&this.mdcFoundation.destroy(),this.mdcFoundationClass&&(this.mdcFoundation=new this.mdcFoundationClass(this.createAdapter()),this.mdcFoundation.init())}firstUpdated(){this.createFoundation()}} +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */var tr=function(){function e(e){void 0===e&&(e={}),this.adapter=e}return Object.defineProperty(e,"cssClasses",{get:function(){return{}},enumerable:!1,configurable:!0}),Object.defineProperty(e,"strings",{get:function(){return{}},enumerable:!1,configurable:!0}),Object.defineProperty(e,"numbers",{get:function(){return{}},enumerable:!1,configurable:!0}),Object.defineProperty(e,"defaultAdapter",{get:function(){return{}},enumerable:!1,configurable:!0}),e.prototype.init=function(){},e.prototype.destroy=function(){},e}(),rr={BG_FOCUSED:"mdc-ripple-upgraded--background-focused",FG_ACTIVATION:"mdc-ripple-upgraded--foreground-activation",FG_DEACTIVATION:"mdc-ripple-upgraded--foreground-deactivation",ROOT:"mdc-ripple-upgraded",UNBOUNDED:"mdc-ripple-upgraded--unbounded"},or={VAR_FG_SCALE:"--mdc-ripple-fg-scale",VAR_FG_SIZE:"--mdc-ripple-fg-size",VAR_FG_TRANSLATE_END:"--mdc-ripple-fg-translate-end",VAR_FG_TRANSLATE_START:"--mdc-ripple-fg-translate-start",VAR_LEFT:"--mdc-ripple-left",VAR_TOP:"--mdc-ripple-top"},ir={DEACTIVATION_TIMEOUT_MS:225,FG_DEACTIVATION_MS:150,INITIAL_ORIGIN_SCALE:.6,PADDING:10,TAP_DELAY_MS:300},nr=["touchstart","pointerdown","mousedown","keydown"],ar=["touchend","pointerup","mouseup","contextmenu"],lr=[],sr=function(e){function o(t){var i=e.call(this,r(r({},o.defaultAdapter),t))||this;return i.activationAnimationHasEnded=!1,i.activationTimer=0,i.fgDeactivationRemovalTimer=0,i.fgScale="0",i.frame={width:0,height:0},i.initialSize=0,i.layoutFrame=0,i.maxRadius=0,i.unboundedCoords={left:0,top:0},i.activationState=i.defaultActivationState(),i.activationTimerCallback=function(){i.activationAnimationHasEnded=!0,i.runDeactivationUXLogicIfReady()},i.activateHandler=function(e){i.activateImpl(e)},i.deactivateHandler=function(){i.deactivateImpl()},i.focusHandler=function(){i.handleFocus()},i.blurHandler=function(){i.handleBlur()},i.resizeHandler=function(){i.layout()},i}return t(o,e),Object.defineProperty(o,"cssClasses",{get:function(){return rr},enumerable:!1,configurable:!0}),Object.defineProperty(o,"strings",{get:function(){return or},enumerable:!1,configurable:!0}),Object.defineProperty(o,"numbers",{get:function(){return ir},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},browserSupportsCssVars:function(){return!0},computeBoundingRect:function(){return{top:0,right:0,bottom:0,left:0,width:0,height:0}},containsEventTarget:function(){return!0},deregisterDocumentInteractionHandler:function(){},deregisterInteractionHandler:function(){},deregisterResizeHandler:function(){},getWindowPageOffset:function(){return{x:0,y:0}},isSurfaceActive:function(){return!0},isSurfaceDisabled:function(){return!0},isUnbounded:function(){return!0},registerDocumentInteractionHandler:function(){},registerInteractionHandler:function(){},registerResizeHandler:function(){},removeClass:function(){},updateCssVariable:function(){}}},enumerable:!1,configurable:!0}),o.prototype.init=function(){var e=this,t=this.supportsPressRipple();if(this.registerRootHandlers(t),t){var r=o.cssClasses,i=r.ROOT,n=r.UNBOUNDED;requestAnimationFrame((function(){e.adapter.addClass(i),e.adapter.isUnbounded()&&(e.adapter.addClass(n),e.layoutInternal())}))}},o.prototype.destroy=function(){var e=this;if(this.supportsPressRipple()){this.activationTimer&&(clearTimeout(this.activationTimer),this.activationTimer=0,this.adapter.removeClass(o.cssClasses.FG_ACTIVATION)),this.fgDeactivationRemovalTimer&&(clearTimeout(this.fgDeactivationRemovalTimer),this.fgDeactivationRemovalTimer=0,this.adapter.removeClass(o.cssClasses.FG_DEACTIVATION));var t=o.cssClasses,r=t.ROOT,i=t.UNBOUNDED;requestAnimationFrame((function(){e.adapter.removeClass(r),e.adapter.removeClass(i),e.removeCssVars()}))}this.deregisterRootHandlers(),this.deregisterDeactivationHandlers()},o.prototype.activate=function(e){this.activateImpl(e)},o.prototype.deactivate=function(){this.deactivateImpl()},o.prototype.layout=function(){var e=this;this.layoutFrame&&cancelAnimationFrame(this.layoutFrame),this.layoutFrame=requestAnimationFrame((function(){e.layoutInternal(),e.layoutFrame=0}))},o.prototype.setUnbounded=function(e){var t=o.cssClasses.UNBOUNDED;e?this.adapter.addClass(t):this.adapter.removeClass(t)},o.prototype.handleFocus=function(){var e=this;requestAnimationFrame((function(){return e.adapter.addClass(o.cssClasses.BG_FOCUSED)}))},o.prototype.handleBlur=function(){var e=this;requestAnimationFrame((function(){return e.adapter.removeClass(o.cssClasses.BG_FOCUSED)}))},o.prototype.supportsPressRipple=function(){return this.adapter.browserSupportsCssVars()},o.prototype.defaultActivationState=function(){return{activationEvent:void 0,hasDeactivationUXRun:!1,isActivated:!1,isProgrammatic:!1,wasActivatedByPointer:!1,wasElementMadeActive:!1}},o.prototype.registerRootHandlers=function(e){var t,r;if(e){try{for(var o=i(nr),n=o.next();!n.done;n=o.next()){var a=n.value;this.adapter.registerInteractionHandler(a,this.activateHandler)}}catch(e){t={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.adapter.isUnbounded()&&this.adapter.registerResizeHandler(this.resizeHandler)}this.adapter.registerInteractionHandler("focus",this.focusHandler),this.adapter.registerInteractionHandler("blur",this.blurHandler)},o.prototype.registerDeactivationHandlers=function(e){var t,r;if("keydown"===e.type)this.adapter.registerInteractionHandler("keyup",this.deactivateHandler);else try{for(var o=i(ar),n=o.next();!n.done;n=o.next()){var a=n.value;this.adapter.registerDocumentInteractionHandler(a,this.deactivateHandler)}}catch(e){t={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}},o.prototype.deregisterRootHandlers=function(){var e,t;try{for(var r=i(nr),o=r.next();!o.done;o=r.next()){var n=o.value;this.adapter.deregisterInteractionHandler(n,this.activateHandler)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(t=r.return)&&t.call(r)}finally{if(e)throw e.error}}this.adapter.deregisterInteractionHandler("focus",this.focusHandler),this.adapter.deregisterInteractionHandler("blur",this.blurHandler),this.adapter.isUnbounded()&&this.adapter.deregisterResizeHandler(this.resizeHandler)},o.prototype.deregisterDeactivationHandlers=function(){var e,t;this.adapter.deregisterInteractionHandler("keyup",this.deactivateHandler);try{for(var r=i(ar),o=r.next();!o.done;o=r.next()){var n=o.value;this.adapter.deregisterDocumentInteractionHandler(n,this.deactivateHandler)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(t=r.return)&&t.call(r)}finally{if(e)throw e.error}}},o.prototype.removeCssVars=function(){var e=this,t=o.strings;Object.keys(t).forEach((function(r){0===r.indexOf("VAR_")&&e.adapter.updateCssVariable(t[r],null)}))},o.prototype.activateImpl=function(e){var t=this;if(!this.adapter.isSurfaceDisabled()){var r=this.activationState;if(!r.isActivated){var o=this.previousActivationEvent;o&&void 0!==e&&o.type!==e.type||(r.isActivated=!0,r.isProgrammatic=void 0===e,r.activationEvent=e,r.wasActivatedByPointer=!r.isProgrammatic&&void 0!==e&&("mousedown"===e.type||"touchstart"===e.type||"pointerdown"===e.type),void 0!==e&&lr.length>0&&lr.some((function(e){return t.adapter.containsEventTarget(e)}))?this.resetActivationState():(void 0!==e&&(lr.push(e.target),this.registerDeactivationHandlers(e)),r.wasElementMadeActive=this.checkElementMadeActive(e),r.wasElementMadeActive&&this.animateActivation(),requestAnimationFrame((function(){lr=[],r.wasElementMadeActive||void 0===e||" "!==e.key&&32!==e.keyCode||(r.wasElementMadeActive=t.checkElementMadeActive(e),r.wasElementMadeActive&&t.animateActivation()),r.wasElementMadeActive||(t.activationState=t.defaultActivationState())}))))}}},o.prototype.checkElementMadeActive=function(e){return void 0===e||"keydown"!==e.type||this.adapter.isSurfaceActive()},o.prototype.animateActivation=function(){var e=this,t=o.strings,r=t.VAR_FG_TRANSLATE_START,i=t.VAR_FG_TRANSLATE_END,n=o.cssClasses,a=n.FG_DEACTIVATION,l=n.FG_ACTIVATION,s=o.numbers.DEACTIVATION_TIMEOUT_MS;this.layoutInternal();var d="",c="";if(!this.adapter.isUnbounded()){var u=this.getFgTranslationCoordinates(),p=u.startPoint,h=u.endPoint;d=p.x+"px, "+p.y+"px",c=h.x+"px, "+h.y+"px"}this.adapter.updateCssVariable(r,d),this.adapter.updateCssVariable(i,c),clearTimeout(this.activationTimer),clearTimeout(this.fgDeactivationRemovalTimer),this.rmBoundedActivationClasses(),this.adapter.removeClass(a),this.adapter.computeBoundingRect(),this.adapter.addClass(l),this.activationTimer=setTimeout((function(){e.activationTimerCallback()}),s)},o.prototype.getFgTranslationCoordinates=function(){var e,t=this.activationState,r=t.activationEvent;return e=t.wasActivatedByPointer?function(e,t,r){if(!e)return{x:0,y:0};var o,i,n=t.x,a=t.y,l=n+r.left,s=a+r.top;if("touchstart"===e.type){var d=e;o=d.changedTouches[0].pageX-l,i=d.changedTouches[0].pageY-s}else{var c=e;o=c.pageX-l,i=c.pageY-s}return{x:o,y:i}} +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */(r,this.adapter.getWindowPageOffset(),this.adapter.computeBoundingRect()):{x:this.frame.width/2,y:this.frame.height/2},{startPoint:e={x:e.x-this.initialSize/2,y:e.y-this.initialSize/2},endPoint:{x:this.frame.width/2-this.initialSize/2,y:this.frame.height/2-this.initialSize/2}}},o.prototype.runDeactivationUXLogicIfReady=function(){var e=this,t=o.cssClasses.FG_DEACTIVATION,r=this.activationState,i=r.hasDeactivationUXRun,n=r.isActivated;(i||!n)&&this.activationAnimationHasEnded&&(this.rmBoundedActivationClasses(),this.adapter.addClass(t),this.fgDeactivationRemovalTimer=setTimeout((function(){e.adapter.removeClass(t)}),ir.FG_DEACTIVATION_MS))},o.prototype.rmBoundedActivationClasses=function(){var e=o.cssClasses.FG_ACTIVATION;this.adapter.removeClass(e),this.activationAnimationHasEnded=!1,this.adapter.computeBoundingRect()},o.prototype.resetActivationState=function(){var e=this;this.previousActivationEvent=this.activationState.activationEvent,this.activationState=this.defaultActivationState(),setTimeout((function(){return e.previousActivationEvent=void 0}),o.numbers.TAP_DELAY_MS)},o.prototype.deactivateImpl=function(){var e=this,t=this.activationState;if(t.isActivated){var o=r({},t);t.isProgrammatic?(requestAnimationFrame((function(){e.animateDeactivation(o)})),this.resetActivationState()):(this.deregisterDeactivationHandlers(),requestAnimationFrame((function(){e.activationState.hasDeactivationUXRun=!0,e.animateDeactivation(o),e.resetActivationState()})))}},o.prototype.animateDeactivation=function(e){var t=e.wasActivatedByPointer,r=e.wasElementMadeActive;(t||r)&&this.runDeactivationUXLogicIfReady()},o.prototype.layoutInternal=function(){this.frame=this.adapter.computeBoundingRect();var e=Math.max(this.frame.height,this.frame.width);this.maxRadius=this.adapter.isUnbounded()?e:Math.sqrt(Math.pow(this.frame.width,2)+Math.pow(this.frame.height,2))+o.numbers.PADDING;var t=Math.floor(e*o.numbers.INITIAL_ORIGIN_SCALE);this.adapter.isUnbounded()&&t%2!=0?this.initialSize=t-1:this.initialSize=t,this.fgScale=""+this.maxRadius/this.initialSize,this.updateLayoutCssVars()},o.prototype.updateLayoutCssVars=function(){var e=o.strings,t=e.VAR_FG_SIZE,r=e.VAR_LEFT,i=e.VAR_TOP,n=e.VAR_FG_SCALE;this.adapter.updateCssVariable(t,this.initialSize+"px"),this.adapter.updateCssVariable(n,this.fgScale),this.adapter.isUnbounded()&&(this.unboundedCoords={left:Math.round(this.frame.width/2-this.initialSize/2),top:Math.round(this.frame.height/2-this.initialSize/2)},this.adapter.updateCssVariable(r,this.unboundedCoords.left+"px"),this.adapter.updateCssVariable(i,this.unboundedCoords.top+"px"))},o}(tr),dr=sr; +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +const cr=e=>(...t)=>({_$litDirective$:e,values:t});let ur=class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,r){this._$Ct=e,this._$AM=t,this._$Ci=r}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}; +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const pr=cr(class extends ur{constructor(e){var t;if(super(e),1!==e.type||"class"!==e.name||(null===(t=e.strings)||void 0===t?void 0:t.length)>2)throw Error("`classMap()` can only be used in the `class` attribute and must be the only part in the attribute.")}render(e){return" "+Object.keys(e).filter((t=>e[t])).join(" ")+" "}update(e,[t]){var r,o;if(void 0===this.it){this.it=new Set,void 0!==e.strings&&(this.nt=new Set(e.strings.join(" ").split(/\s/).filter((e=>""!==e))));for(const e in t)t[e]&&!(null===(r=this.nt)||void 0===r?void 0:r.has(e))&&this.it.add(e);return this.render(t)}const i=e.element.classList;this.it.forEach((e=>{e in t||(i.remove(e),this.it.delete(e))}));for(const e in t){const r=!!t[e];r===this.it.has(e)||(null===(o=this.nt)||void 0===o?void 0:o.has(e))||(r?(i.add(e),this.it.add(e)):(i.remove(e),this.it.delete(e)))}return K}}),hr="important",gr=" !"+hr,mr=cr(class extends ur{constructor(e){var t;if(super(e),1!==e.type||"style"!==e.name||(null===(t=e.strings)||void 0===t?void 0:t.length)>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.")}render(e){return Object.keys(e).reduce(((t,r)=>{const o=e[r];return null==o?t:t+`${r=r.includes("-")?r:r.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-$&").toLowerCase()}:${o};`}),"")}update(e,[t]){const{style:r}=e.element;if(void 0===this.ht){this.ht=new Set;for(const e in t)this.ht.add(e);return this.render(t)}this.ht.forEach((e=>{null==t[e]&&(this.ht.delete(e),e.includes("-")?r.removeProperty(e):r[e]="")}));for(const e in t){const o=t[e];if(null!=o){this.ht.add(e);const t="string"==typeof o&&o.endsWith(gr);e.includes("-")||t?r.setProperty(e,t?o.slice(0,-11):o,t?hr:""):r[e]=o}}return K}}); +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +class fr extends er{constructor(){super(...arguments),this.primary=!1,this.accent=!1,this.unbounded=!1,this.disabled=!1,this.activated=!1,this.selected=!1,this.internalUseStateLayerCustomProperties=!1,this.hovering=!1,this.bgFocused=!1,this.fgActivation=!1,this.fgDeactivation=!1,this.fgScale="",this.fgSize="",this.translateStart="",this.translateEnd="",this.leftPos="",this.topPos="",this.mdcFoundationClass=dr}get isActive(){return Gt(this.parentElement||this,":active")}createAdapter(){return{browserSupportsCssVars:()=>!0,isUnbounded:()=>this.unbounded,isSurfaceActive:()=>this.isActive,isSurfaceDisabled:()=>this.disabled,addClass:e=>{switch(e){case"mdc-ripple-upgraded--background-focused":this.bgFocused=!0;break;case"mdc-ripple-upgraded--foreground-activation":this.fgActivation=!0;break;case"mdc-ripple-upgraded--foreground-deactivation":this.fgDeactivation=!0}},removeClass:e=>{switch(e){case"mdc-ripple-upgraded--background-focused":this.bgFocused=!1;break;case"mdc-ripple-upgraded--foreground-activation":this.fgActivation=!1;break;case"mdc-ripple-upgraded--foreground-deactivation":this.fgDeactivation=!1}},containsEventTarget:()=>!0,registerInteractionHandler:()=>{},deregisterInteractionHandler:()=>{},registerDocumentInteractionHandler:()=>{},deregisterDocumentInteractionHandler:()=>{},registerResizeHandler:()=>{},deregisterResizeHandler:()=>{},updateCssVariable:(e,t)=>{switch(e){case"--mdc-ripple-fg-scale":this.fgScale=t;break;case"--mdc-ripple-fg-size":this.fgSize=t;break;case"--mdc-ripple-fg-translate-end":this.translateEnd=t;break;case"--mdc-ripple-fg-translate-start":this.translateStart=t;break;case"--mdc-ripple-left":this.leftPos=t;break;case"--mdc-ripple-top":this.topPos=t}},computeBoundingRect:()=>(this.parentElement||this).getBoundingClientRect(),getWindowPageOffset:()=>({x:window.pageXOffset,y:window.pageYOffset})}}startPress(e){this.waitForFoundation((()=>{this.mdcFoundation.activate(e)}))}endPress(){this.waitForFoundation((()=>{this.mdcFoundation.deactivate()}))}startFocus(){this.waitForFoundation((()=>{this.mdcFoundation.handleFocus()}))}endFocus(){this.waitForFoundation((()=>{this.mdcFoundation.handleBlur()}))}startHover(){this.hovering=!0}endHover(){this.hovering=!1}waitForFoundation(e){this.mdcFoundation?e():this.updateComplete.then(e)}update(e){e.has("disabled")&&this.disabled&&this.endHover(),super.update(e)}render(){const e=this.activated&&(this.primary||!this.accent),t=this.selected&&(this.primary||!this.accent),r={"mdc-ripple-surface--accent":this.accent,"mdc-ripple-surface--primary--activated":e,"mdc-ripple-surface--accent--activated":this.accent&&this.activated,"mdc-ripple-surface--primary--selected":t,"mdc-ripple-surface--accent--selected":this.accent&&this.selected,"mdc-ripple-surface--disabled":this.disabled,"mdc-ripple-surface--hover":this.hovering,"mdc-ripple-surface--primary":this.primary,"mdc-ripple-surface--selected":this.selected,"mdc-ripple-upgraded--background-focused":this.bgFocused,"mdc-ripple-upgraded--foreground-activation":this.fgActivation,"mdc-ripple-upgraded--foreground-deactivation":this.fgDeactivation,"mdc-ripple-upgraded--unbounded":this.unbounded,"mdc-ripple-surface--internal-use-state-layer-custom-properties":this.internalUseStateLayerCustomProperties};return W` +
`}}o([ye(".mdc-ripple-surface")],fr.prototype,"mdcRoot",void 0),o([ge({type:Boolean})],fr.prototype,"primary",void 0),o([ge({type:Boolean})],fr.prototype,"accent",void 0),o([ge({type:Boolean})],fr.prototype,"unbounded",void 0),o([ge({type:Boolean})],fr.prototype,"disabled",void 0),o([ge({type:Boolean})],fr.prototype,"activated",void 0),o([ge({type:Boolean})],fr.prototype,"selected",void 0),o([ge({type:Boolean})],fr.prototype,"internalUseStateLayerCustomProperties",void 0),o([me()],fr.prototype,"hovering",void 0),o([me()],fr.prototype,"bgFocused",void 0),o([me()],fr.prototype,"fgActivation",void 0),o([me()],fr.prototype,"fgDeactivation",void 0),o([me()],fr.prototype,"fgScale",void 0),o([me()],fr.prototype,"fgSize",void 0),o([me()],fr.prototype,"translateStart",void 0),o([me()],fr.prototype,"translateEnd",void 0),o([me()],fr.prototype,"leftPos",void 0),o([me()],fr.prototype,"topPos",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const br=c`.mdc-ripple-surface{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;position:relative;outline:none;overflow:hidden}.mdc-ripple-surface::before,.mdc-ripple-surface::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-ripple-surface::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-ripple-surface::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-ripple-surface.mdc-ripple-upgraded::before{transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface.mdc-ripple-upgraded::after{top:0;left:0;transform:scale(0);transform-origin:center center}.mdc-ripple-surface.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-activation::after{animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-deactivation::after{animation:mdc-ripple-fg-opacity-out 150ms;transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface::before,.mdc-ripple-surface::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-ripple-surface.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded],.mdc-ripple-upgraded--unbounded{overflow:visible}.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::after,.mdc-ripple-upgraded--unbounded::before,.mdc-ripple-upgraded--unbounded::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::before,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface::before,.mdc-ripple-surface::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-ripple-surface:hover::before,.mdc-ripple-surface.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-ripple-surface.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-ripple-surface:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}@keyframes mdc-ripple-fg-radius-in{from{animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-opacity-in{from{animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-out{from{animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}:host{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;display:block}:host .mdc-ripple-surface{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;will-change:unset}.mdc-ripple-surface--primary::before,.mdc-ripple-surface--primary::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-ripple-surface--primary:hover::before,.mdc-ripple-surface--primary.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-ripple-surface--primary.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface--primary.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface--primary--activated::before{opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12)}.mdc-ripple-surface--primary--activated::before,.mdc-ripple-surface--primary--activated::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-ripple-surface--primary--activated:hover::before,.mdc-ripple-surface--primary--activated.mdc-ripple-surface--hover::before{opacity:0.16;opacity:var(--mdc-ripple-hover-opacity, 0.16)}.mdc-ripple-surface--primary--activated.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--primary--activated:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-ripple-surface--primary--activated:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--primary--activated:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-ripple-surface--primary--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-ripple-surface--primary--selected::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}.mdc-ripple-surface--primary--selected::before,.mdc-ripple-surface--primary--selected::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-ripple-surface--primary--selected:hover::before,.mdc-ripple-surface--primary--selected.mdc-ripple-surface--hover::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}.mdc-ripple-surface--primary--selected.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--primary--selected:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}.mdc-ripple-surface--primary--selected:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--primary--selected:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}.mdc-ripple-surface--primary--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}.mdc-ripple-surface--accent::before,.mdc-ripple-surface--accent::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-ripple-surface--accent:hover::before,.mdc-ripple-surface--accent.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-ripple-surface--accent.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface--accent.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface--accent--activated::before{opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12)}.mdc-ripple-surface--accent--activated::before,.mdc-ripple-surface--accent--activated::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-ripple-surface--accent--activated:hover::before,.mdc-ripple-surface--accent--activated.mdc-ripple-surface--hover::before{opacity:0.16;opacity:var(--mdc-ripple-hover-opacity, 0.16)}.mdc-ripple-surface--accent--activated.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--accent--activated:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-ripple-surface--accent--activated:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--accent--activated:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-ripple-surface--accent--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-ripple-surface--accent--selected::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}.mdc-ripple-surface--accent--selected::before,.mdc-ripple-surface--accent--selected::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-ripple-surface--accent--selected:hover::before,.mdc-ripple-surface--accent--selected.mdc-ripple-surface--hover::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}.mdc-ripple-surface--accent--selected.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--accent--selected:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}.mdc-ripple-surface--accent--selected:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--accent--selected:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}.mdc-ripple-surface--accent--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}.mdc-ripple-surface--disabled{opacity:0}.mdc-ripple-surface--internal-use-state-layer-custom-properties::before,.mdc-ripple-surface--internal-use-state-layer-custom-properties::after{background-color:#000;background-color:var(--mdc-ripple-hover-state-layer-color, #000)}.mdc-ripple-surface--internal-use-state-layer-custom-properties:hover::before,.mdc-ripple-surface--internal-use-state-layer-custom-properties.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-state-layer-opacity, 0.04)}.mdc-ripple-surface--internal-use-state-layer-custom-properties.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--internal-use-state-layer-custom-properties:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-state-layer-opacity, 0.12)}.mdc-ripple-surface--internal-use-state-layer-custom-properties:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--internal-use-state-layer-custom-properties:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-pressed-state-layer-opacity, 0.12)}.mdc-ripple-surface--internal-use-state-layer-custom-properties.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-pressed-state-layer-opacity, 0.12)}` +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let yr=class extends fr{};function vr(e,t,r){if(void 0!==t) +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +return function(e,t,r){const o=e.constructor;if(!r){const e="__"+t;if(!(r=o.getPropertyDescriptor(t,e)))throw Error("@ariaProperty must be used after a @property decorator")}const i=r;let n="";if(!i.set)throw Error("@ariaProperty requires a setter for "+t);if(e.dispatchWizEvent)return r;const a={configurable:!0,enumerable:!0,set(e){if(""===n){const e=o.getPropertyOptions(t);n="string"==typeof e.attribute?e.attribute:t}this.hasAttribute(n)&&this.removeAttribute(n),i.set.call(this,e)}};return i.get&&(a.get=function(){return i.get.call(this)}),a}(e,t,r);throw Error("@ariaProperty only supports TypeScript Decorators")} +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */yr.styles=[br],yr=o([ue("mwc-ripple")],yr);class xr{constructor(e){this.startPress=t=>{e().then((e=>{e&&e.startPress(t)}))},this.endPress=()=>{e().then((e=>{e&&e.endPress()}))},this.startFocus=()=>{e().then((e=>{e&&e.startFocus()}))},this.endFocus=()=>{e().then((e=>{e&&e.endFocus()}))},this.startHover=()=>{e().then((e=>{e&&e.startHover()}))},this.endHover=()=>{e().then((e=>{e&&e.endHover()}))}}} +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const wr=e=>null!=e?e:j +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;class kr extends de{constructor(){super(...arguments),this.disabled=!1,this.icon="",this.shouldRenderRipple=!1,this.rippleHandlers=new xr((()=>(this.shouldRenderRipple=!0,this.ripple)))}renderRipple(){return this.shouldRenderRipple?W` + + `:""}focus(){const e=this.buttonElement;e&&(this.rippleHandlers.startFocus(),e.focus())}blur(){const e=this.buttonElement;e&&(this.rippleHandlers.endFocus(),e.blur())}render(){return W``}handleRippleMouseDown(e){const t=()=>{window.removeEventListener("mouseup",t),this.handleRippleDeactivate()};window.addEventListener("mouseup",t),this.rippleHandlers.startPress(e)}handleRippleTouchStart(e){this.rippleHandlers.startPress(e)}handleRippleDeactivate(){this.rippleHandlers.endPress()}handleRippleMouseEnter(){this.rippleHandlers.startHover()}handleRippleMouseLeave(){this.rippleHandlers.endHover()}handleRippleFocus(){this.rippleHandlers.startFocus()}handleRippleBlur(){this.rippleHandlers.endFocus()}}o([ge({type:Boolean,reflect:!0})],kr.prototype,"disabled",void 0),o([ge({type:String})],kr.prototype,"icon",void 0),o([vr,ge({type:String,attribute:"aria-label"})],kr.prototype,"ariaLabel",void 0),o([vr,ge({type:String,attribute:"aria-haspopup"})],kr.prototype,"ariaHasPopup",void 0),o([ye("button")],kr.prototype,"buttonElement",void 0),o([ve("mwc-ripple")],kr.prototype,"ripple",void 0),o([me()],kr.prototype,"shouldRenderRipple",void 0),o([be({passive:!0})],kr.prototype,"handleRippleMouseDown",null),o([be({passive:!0})],kr.prototype,"handleRippleTouchStart",null); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const _r=c`.material-icons{font-family:var(--mdc-icon-font, "Material Icons");font-weight:normal;font-style:normal;font-size:var(--mdc-icon-size, 24px);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:"liga"}.mdc-icon-button{font-size:24px;width:48px;height:48px;padding:12px}.mdc-icon-button .mdc-icon-button__focus-ring{display:none}.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring{display:block;max-height:48px;max-width:48px}@media screen and (forced-colors: active){.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring{pointer-events:none;border:2px solid transparent;border-radius:6px;box-sizing:content-box;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);height:100%;width:100%}}@media screen and (forced-colors: active)and (forced-colors: active){.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring{border-color:CanvasText}}@media screen and (forced-colors: active){.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring::after,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring::after{content:"";border:2px solid transparent;border-radius:8px;display:block;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);height:calc(100% + 4px);width:calc(100% + 4px)}}@media screen and (forced-colors: active)and (forced-colors: active){.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring::after,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring::after{border-color:CanvasText}}.mdc-icon-button.mdc-icon-button--reduced-size .mdc-icon-button__ripple{width:40px;height:40px;margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-icon-button.mdc-icon-button--reduced-size.mdc-ripple-upgraded--background-focused .mdc-icon-button__focus-ring,.mdc-icon-button.mdc-icon-button--reduced-size:not(.mdc-ripple-upgraded):focus .mdc-icon-button__focus-ring{max-height:40px;max-width:40px}.mdc-icon-button .mdc-icon-button__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;transform:translate(-50%, -50%)}.mdc-icon-button:disabled{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38))}.mdc-icon-button svg,.mdc-icon-button img{width:24px;height:24px}.mdc-icon-button{display:inline-block;position:relative;box-sizing:border-box;border:none;outline:none;background-color:transparent;fill:currentColor;color:inherit;text-decoration:none;cursor:pointer;user-select:none;z-index:0;overflow:visible}.mdc-icon-button .mdc-icon-button__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;transform:translate(-50%, -50%)}.mdc-icon-button:disabled{cursor:default;pointer-events:none}.mdc-icon-button--display-flex{align-items:center;display:inline-flex;justify-content:center}.mdc-icon-button__icon{display:inline-block}.mdc-icon-button__icon.mdc-icon-button__icon--on{display:none}.mdc-icon-button--on .mdc-icon-button__icon{display:none}.mdc-icon-button--on .mdc-icon-button__icon.mdc-icon-button__icon--on{display:inline-block}.mdc-icon-button__link{height:100%;left:0;outline:none;position:absolute;top:0;width:100%}.mdc-icon-button{display:inline-block;position:relative;box-sizing:border-box;border:none;outline:none;background-color:transparent;fill:currentColor;color:inherit;text-decoration:none;cursor:pointer;user-select:none;z-index:0;overflow:visible}.mdc-icon-button .mdc-icon-button__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;transform:translate(-50%, -50%)}.mdc-icon-button:disabled{cursor:default;pointer-events:none}.mdc-icon-button--display-flex{align-items:center;display:inline-flex;justify-content:center}.mdc-icon-button__icon{display:inline-block}.mdc-icon-button__icon.mdc-icon-button__icon--on{display:none}.mdc-icon-button--on .mdc-icon-button__icon{display:none}.mdc-icon-button--on .mdc-icon-button__icon.mdc-icon-button__icon--on{display:inline-block}.mdc-icon-button__link{height:100%;left:0;outline:none;position:absolute;top:0;width:100%}:host{display:inline-block;outline:none}:host([disabled]){pointer-events:none}.mdc-icon-button i,.mdc-icon-button svg,.mdc-icon-button img,.mdc-icon-button ::slotted(*){display:block}:host{--mdc-ripple-color: currentcolor;-webkit-tap-highlight-color:transparent}:host,.mdc-icon-button{vertical-align:top}.mdc-icon-button{width:var(--mdc-icon-button-size, 48px);height:var(--mdc-icon-button-size, 48px);padding:calc( (var(--mdc-icon-button-size, 48px) - var(--mdc-icon-size, 24px)) / 2 )}.mdc-icon-button i,.mdc-icon-button svg,.mdc-icon-button img,.mdc-icon-button ::slotted(*){display:block;width:var(--mdc-icon-size, 24px);height:var(--mdc-icon-size, 24px)}` +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let Cr=class extends kr{};Cr.styles=[_r],Cr=o([ue("mwc-icon-button")],Cr); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let Sr=class extends de{constructor(){super(...arguments),this._tabs=[],this._active=void 0}get active(){return this._active}set active(e){const t=this._active;e!==t&&(this._active=e,void 0!==t&&(t.active=!1),void 0!==e?e.active=!0:this.dispatchEvent(new CustomEvent("tabchange",{detail:{tab:void 0},bubbles:!0})))}render(){return W` +
+ +
+ `}_onSlotchange(e){let t;this._tabs=e.target.assignedElements();for(let e=0;et.right){const e=r.left-t.left+this.scrollLeft-t.width/2+r.width/2;this.scroll({left:e,behavior:"smooth"})}}async _onKeydown(e){var t,r;const o=null!==(r=null===(t=this.active)||void 0===t?void 0:t.index)&&void 0!==r?r:0,i=this._tabs.length-1;let n=o;switch(e.key){case"ArrowLeft":0===o?n=i:n--;break;case"ArrowRight":o===i?n=0:n++;break;case"Home":n=0;break;case"End":n=i}if(n!==o){e.preventDefault();const t=this._tabs[n];this.active=t,await t.updateComplete,t.focus()}}_findEventTab(e){const t=e.target;if("playground-internal-tab"===(null==t?void 0:t.localName))return e.target;for(const t of e.composedPath())if("playground-internal-tab"===(null==t?void 0:t.localName))return t}};Sr.styles=c` + :host { + display: flex; + overflow-x: auto; + } + + :host::-webkit-scrollbar { + display: none; + } + + div { + display: flex; + } + `,o([ge()],Sr.prototype,"label",void 0),Sr=o([ue("playground-internal-tab-bar")],Sr); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let Er=class extends de{constructor(){super(...arguments),this.active=!1,this.index=0}render(){return W``}updated(e){e.has("active")&&this.active&&this.dispatchEvent(new CustomEvent("tabchange",{detail:{tab:this},bubbles:!0}))}focus(){this._button.focus()}};Er.styles=c` + :host { + display: flex; + } + + button { + flex: 1; + border: none; + font-size: inherit; + font-family: inherit; + 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%; + } + + :host([active]) > button::after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 2px; + background: var( + --playground-tab-bar-indicator-color, + var(--playground-highlight-color, #6200ee) + ); + } + `,o([ge({type:Boolean,reflect:!0})],Er.prototype,"active",void 0),o([ye("button")],Er.prototype,"_button",void 0),Er=o([ue("playground-internal-tab")],Er); +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +const Tr=e=>(t,r)=>{if(t.constructor._observers){if(!t.constructor.hasOwnProperty("_observers")){const e=t.constructor._observers;t.constructor._observers=new Map,e.forEach(((e,r)=>t.constructor._observers.set(r,e)))}}else{t.constructor._observers=new Map;const e=t.updated;t.updated=function(t){e.call(this,t),t.forEach(((e,t)=>{const r=this.constructor._observers.get(t);void 0!==r&&r.call(this,this[t],e)}))}}t.constructor._observers.set(r,e)} +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;class Ar extends de{constructor(){super(...arguments),this.value="",this.group=null,this.tabindex=-1,this.disabled=!1,this.twoline=!1,this.activated=!1,this.graphic=null,this.multipleGraphics=!1,this.hasMeta=!1,this.noninteractive=!1,this.selected=!1,this.shouldRenderRipple=!1,this._managingList=null,this.boundOnClick=this.onClick.bind(this),this._firstChanged=!0,this._skipPropRequest=!1,this.rippleHandlers=new xr((()=>(this.shouldRenderRipple=!0,this.ripple))),this.listeners=[{target:this,eventNames:["click"],cb:()=>{this.onClick()}},{target:this,eventNames:["mouseenter"],cb:this.rippleHandlers.startHover},{target:this,eventNames:["mouseleave"],cb:this.rippleHandlers.endHover},{target:this,eventNames:["focus"],cb:this.rippleHandlers.startFocus},{target:this,eventNames:["blur"],cb:this.rippleHandlers.endFocus},{target:this,eventNames:["mousedown","touchstart"],cb:e=>{const t=e.type;this.onDown("mousedown"===t?"mouseup":"touchend",e)}}]}get text(){const e=this.textContent;return e?e.trim():""}render(){const e=this.renderText(),t=this.graphic?this.renderGraphic():W``,r=this.hasMeta?this.renderMeta():W``;return W` + ${this.renderRipple()} + ${t} + ${e} + ${r}`}renderRipple(){return this.shouldRenderRipple?W` + + `:this.activated?W`
`:""}renderGraphic(){const e={multi:this.multipleGraphics};return W` + + + `}renderMeta(){return W` + + + `}renderText(){const e=this.twoline?this.renderTwoline():this.renderSingleLine();return W` + + ${e} + `}renderSingleLine(){return W``}renderTwoline(){return W` + + + + + + + `}onClick(){this.fireRequestSelected(!this.selected,"interaction")}onDown(e,t){const r=()=>{window.removeEventListener(e,r),this.rippleHandlers.endPress()};window.addEventListener(e,r),this.rippleHandlers.startPress(t)}fireRequestSelected(e,t){if(this.noninteractive)return;const r=new CustomEvent("request-selected",{bubbles:!0,composed:!0,detail:{source:t,selected:e}});this.dispatchEvent(r)}connectedCallback(){super.connectedCallback(),this.noninteractive||this.setAttribute("mwc-list-item","");for(const e of this.listeners)for(const t of e.eventNames)e.target.addEventListener(t,e.cb,{passive:!0})}disconnectedCallback(){super.disconnectedCallback();for(const e of this.listeners)for(const t of e.eventNames)e.target.removeEventListener(t,e.cb);this._managingList&&(this._managingList.debouncedLayout?this._managingList.debouncedLayout(!0):this._managingList.layout(!0))}firstUpdated(){const e=new Event("list-item-rendered",{bubbles:!0,composed:!0});this.dispatchEvent(e)}}o([ye("slot")],Ar.prototype,"slotElement",void 0),o([ve("mwc-ripple")],Ar.prototype,"ripple",void 0),o([ge({type:String})],Ar.prototype,"value",void 0),o([ge({type:String,reflect:!0})],Ar.prototype,"group",void 0),o([ge({type:Number,reflect:!0})],Ar.prototype,"tabindex",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e){e?this.setAttribute("aria-disabled","true"):this.setAttribute("aria-disabled","false")}))],Ar.prototype,"disabled",void 0),o([ge({type:Boolean,reflect:!0})],Ar.prototype,"twoline",void 0),o([ge({type:Boolean,reflect:!0})],Ar.prototype,"activated",void 0),o([ge({type:String,reflect:!0})],Ar.prototype,"graphic",void 0),o([ge({type:Boolean})],Ar.prototype,"multipleGraphics",void 0),o([ge({type:Boolean})],Ar.prototype,"hasMeta",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e){e?(this.removeAttribute("aria-checked"),this.removeAttribute("mwc-list-item"),this.selected=!1,this.activated=!1,this.tabIndex=-1):this.setAttribute("mwc-list-item","")}))],Ar.prototype,"noninteractive",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e){const t=this.getAttribute("role"),r="gridcell"===t||"option"===t||"row"===t||"tab"===t;r&&e?this.setAttribute("aria-selected","true"):r&&this.setAttribute("aria-selected","false"),this._firstChanged?this._firstChanged=!1:this._skipPropRequest||this.fireRequestSelected(e,"property")}))],Ar.prototype,"selected",void 0),o([me()],Ar.prototype,"shouldRenderRipple",void 0),o([me()],Ar.prototype,"_managingList",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const Or=c`:host{cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;height:48px;display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;padding-left:var(--mdc-list-side-padding, 16px);padding-right:var(--mdc-list-side-padding, 16px);outline:none;height:48px;color:rgba(0,0,0,.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}:host:focus{outline:none}:host([activated]){color:#6200ee;color:var(--mdc-theme-primary, #6200ee);--mdc-ripple-color: var( --mdc-theme-primary, #6200ee )}:host([activated]) .mdc-deprecated-list-item__graphic{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}:host([activated]) .fake-activated-ripple::before{position:absolute;display:block;top:0;bottom:0;left:0;right:0;width:100%;height:100%;pointer-events:none;z-index:1;content:"";opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12);background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-deprecated-list-item__graphic{flex-shrink:0;align-items:center;justify-content:center;fill:currentColor;display:inline-flex}.mdc-deprecated-list-item__graphic ::slotted(*){flex-shrink:0;align-items:center;justify-content:center;fill:currentColor;width:100%;height:100%;text-align:center}.mdc-deprecated-list-item__meta{width:var(--mdc-list-item-meta-size, 24px);height:var(--mdc-list-item-meta-size, 24px);margin-left:auto;margin-right:0;color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38))}.mdc-deprecated-list-item__meta.multi{width:auto}.mdc-deprecated-list-item__meta ::slotted(*){width:var(--mdc-list-item-meta-size, 24px);line-height:var(--mdc-list-item-meta-size, 24px)}.mdc-deprecated-list-item__meta ::slotted(.material-icons),.mdc-deprecated-list-item__meta ::slotted(mwc-icon){line-height:var(--mdc-list-item-meta-size, 24px) !important}.mdc-deprecated-list-item__meta ::slotted(:not(.material-icons):not(mwc-icon)){-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}[dir=rtl] .mdc-deprecated-list-item__meta,.mdc-deprecated-list-item__meta[dir=rtl]{margin-left:0;margin-right:auto}.mdc-deprecated-list-item__meta ::slotted(*){width:100%;height:100%}.mdc-deprecated-list-item__text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-deprecated-list-item__text ::slotted([for]),.mdc-deprecated-list-item__text[for]{pointer-events:none}.mdc-deprecated-list-item__primary-text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal;margin-bottom:-20px;display:block}.mdc-deprecated-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-deprecated-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-deprecated-list-item__secondary-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal;display:block}.mdc-deprecated-list-item__secondary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-deprecated-list--dense .mdc-deprecated-list-item__secondary-text{font-size:inherit}* ::slotted(a),a{color:inherit;text-decoration:none}:host([twoline]){height:72px}:host([twoline]) .mdc-deprecated-list-item__text{align-self:flex-start}:host([disabled]),:host([noninteractive]){cursor:default;pointer-events:none}:host([disabled]) .mdc-deprecated-list-item__text ::slotted(*){opacity:.38}:host([disabled]) .mdc-deprecated-list-item__text ::slotted(*),:host([disabled]) .mdc-deprecated-list-item__primary-text ::slotted(*),:host([disabled]) .mdc-deprecated-list-item__secondary-text ::slotted(*){color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-deprecated-list-item__secondary-text ::slotted(*){color:rgba(0, 0, 0, 0.54);color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54))}.mdc-deprecated-list-item__graphic ::slotted(*){background-color:transparent;color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38))}.mdc-deprecated-list-group__subheader ::slotted(*){color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic{width:var(--mdc-list-item-graphic-size, 40px);height:var(--mdc-list-item-graphic-size, 40px)}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic.multi{width:auto}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic ::slotted(*){width:var(--mdc-list-item-graphic-size, 40px);line-height:var(--mdc-list-item-graphic-size, 40px)}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic ::slotted(.material-icons),:host([graphic=avatar]) .mdc-deprecated-list-item__graphic ::slotted(mwc-icon){line-height:var(--mdc-list-item-graphic-size, 40px) !important}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic ::slotted(*){border-radius:50%}:host([graphic=avatar]) .mdc-deprecated-list-item__graphic,:host([graphic=medium]) .mdc-deprecated-list-item__graphic,:host([graphic=large]) .mdc-deprecated-list-item__graphic,:host([graphic=control]) .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:var(--mdc-list-item-graphic-margin, 16px)}[dir=rtl] :host([graphic=avatar]) .mdc-deprecated-list-item__graphic,[dir=rtl] :host([graphic=medium]) .mdc-deprecated-list-item__graphic,[dir=rtl] :host([graphic=large]) .mdc-deprecated-list-item__graphic,[dir=rtl] :host([graphic=control]) .mdc-deprecated-list-item__graphic,:host([graphic=avatar]) .mdc-deprecated-list-item__graphic[dir=rtl],:host([graphic=medium]) .mdc-deprecated-list-item__graphic[dir=rtl],:host([graphic=large]) .mdc-deprecated-list-item__graphic[dir=rtl],:host([graphic=control]) .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:var(--mdc-list-item-graphic-margin, 16px);margin-right:0}:host([graphic=icon]) .mdc-deprecated-list-item__graphic{width:var(--mdc-list-item-graphic-size, 24px);height:var(--mdc-list-item-graphic-size, 24px);margin-left:0;margin-right:var(--mdc-list-item-graphic-margin, 32px)}:host([graphic=icon]) .mdc-deprecated-list-item__graphic.multi{width:auto}:host([graphic=icon]) .mdc-deprecated-list-item__graphic ::slotted(*){width:var(--mdc-list-item-graphic-size, 24px);line-height:var(--mdc-list-item-graphic-size, 24px)}:host([graphic=icon]) .mdc-deprecated-list-item__graphic ::slotted(.material-icons),:host([graphic=icon]) .mdc-deprecated-list-item__graphic ::slotted(mwc-icon){line-height:var(--mdc-list-item-graphic-size, 24px) !important}[dir=rtl] :host([graphic=icon]) .mdc-deprecated-list-item__graphic,:host([graphic=icon]) .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:var(--mdc-list-item-graphic-margin, 32px);margin-right:0}:host([graphic=avatar]:not([twoLine])),:host([graphic=icon]:not([twoLine])){height:56px}:host([graphic=medium]:not([twoLine])),:host([graphic=large]:not([twoLine])){height:72px}:host([graphic=medium]) .mdc-deprecated-list-item__graphic,:host([graphic=large]) .mdc-deprecated-list-item__graphic{width:var(--mdc-list-item-graphic-size, 56px);height:var(--mdc-list-item-graphic-size, 56px)}:host([graphic=medium]) .mdc-deprecated-list-item__graphic.multi,:host([graphic=large]) .mdc-deprecated-list-item__graphic.multi{width:auto}:host([graphic=medium]) .mdc-deprecated-list-item__graphic ::slotted(*),:host([graphic=large]) .mdc-deprecated-list-item__graphic ::slotted(*){width:var(--mdc-list-item-graphic-size, 56px);line-height:var(--mdc-list-item-graphic-size, 56px)}:host([graphic=medium]) .mdc-deprecated-list-item__graphic ::slotted(.material-icons),:host([graphic=medium]) .mdc-deprecated-list-item__graphic ::slotted(mwc-icon),:host([graphic=large]) .mdc-deprecated-list-item__graphic ::slotted(.material-icons),:host([graphic=large]) .mdc-deprecated-list-item__graphic ::slotted(mwc-icon){line-height:var(--mdc-list-item-graphic-size, 56px) !important}:host([graphic=large]){padding-left:0px}` +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let Lr=class extends Ar{};Lr.styles=[Or],Lr=o([ue("mwc-list-item")],Lr); +/** + * @license + * Copyright 2020 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +var Mr="Backspace",Ir="Enter",Rr="Spacebar",Fr="PageUp",Nr="PageDown",zr="End",Dr="Home",Pr="ArrowLeft",Hr="ArrowUp",Ur="ArrowRight",Br="ArrowDown",Wr="Delete",Kr="Escape",jr=new Set;jr.add(Mr),jr.add(Ir),jr.add(Rr),jr.add(Fr),jr.add(Nr),jr.add(zr),jr.add(Dr),jr.add(Pr),jr.add(Hr),jr.add(Ur),jr.add(Br),jr.add(Wr),jr.add(Kr),jr.add("Tab");var Vr=new Map;Vr.set(8,Mr),Vr.set(13,Ir),Vr.set(32,Rr),Vr.set(33,Fr),Vr.set(34,Nr),Vr.set(35,zr),Vr.set(36,Dr),Vr.set(37,Pr),Vr.set(38,Hr),Vr.set(39,Ur),Vr.set(40,Br),Vr.set(46,Wr),Vr.set(27,Kr),Vr.set(9,"Tab");var qr,Zr,Gr=new Set;function Jr(e){var t=e.key;return jr.has(t)?t:Vr.get(e.keyCode)||"Unknown"} +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */Gr.add(Fr),Gr.add(Nr),Gr.add(zr),Gr.add(Dr),Gr.add(Pr),Gr.add(Hr),Gr.add(Ur),Gr.add(Br);var Qr="mdc-list-item--activated",Yr="mdc-list-item",Xr="mdc-list-item--disabled",$r="mdc-list-item--selected",eo="mdc-list-item__primary-text",to="mdc-list";(qr={})[""+Qr]="mdc-list-item--activated",qr[""+Yr]="mdc-list-item",qr[""+Xr]="mdc-list-item--disabled",qr[""+$r]="mdc-list-item--selected",qr[""+eo]="mdc-list-item__primary-text",qr[""+to]="mdc-list";var ro=((Zr={})[""+Qr]="mdc-deprecated-list-item--activated",Zr[""+Yr]="mdc-deprecated-list-item",Zr[""+Xr]="mdc-deprecated-list-item--disabled",Zr[""+$r]="mdc-deprecated-list-item--selected",Zr["mdc-list-item__text"]="mdc-deprecated-list-item__text",Zr[""+eo]="mdc-deprecated-list-item__primary-text",Zr[""+to]="mdc-deprecated-list",Zr),oo={ACTION_EVENT:"MDCList:action",SELECTION_CHANGE_EVENT:"MDCList:selectionChange",ARIA_CHECKED:"aria-checked",ARIA_CHECKED_CHECKBOX_SELECTOR:'[role="checkbox"][aria-checked="true"]',ARIA_CHECKED_RADIO_SELECTOR:'[role="radio"][aria-checked="true"]',ARIA_CURRENT:"aria-current",ARIA_DISABLED:"aria-disabled",ARIA_ORIENTATION:"aria-orientation",ARIA_ORIENTATION_HORIZONTAL:"horizontal",ARIA_ROLE_CHECKBOX_SELECTOR:'[role="checkbox"]',ARIA_SELECTED:"aria-selected",ARIA_INTERACTIVE_ROLES_SELECTOR:'[role="listbox"], [role="menu"]',ARIA_MULTI_SELECTABLE_SELECTOR:'[aria-multiselectable="true"]',CHECKBOX_RADIO_SELECTOR:'input[type="checkbox"], input[type="radio"]',CHECKBOX_SELECTOR:'input[type="checkbox"]',CHILD_ELEMENTS_TO_TOGGLE_TABINDEX:"\n ."+Yr+" button:not(:disabled),\n ."+Yr+" a,\n ."+ro[Yr]+" button:not(:disabled),\n ."+ro[Yr]+" a\n ",DEPRECATED_SELECTOR:".mdc-deprecated-list",FOCUSABLE_CHILD_ELEMENTS:"\n ."+Yr+" button:not(:disabled),\n ."+Yr+" a,\n ."+Yr+' input[type="radio"]:not(:disabled),\n .'+Yr+' input[type="checkbox"]:not(:disabled),\n .'+ro[Yr]+" button:not(:disabled),\n ."+ro[Yr]+" a,\n ."+ro[Yr]+' input[type="radio"]:not(:disabled),\n .'+ro[Yr]+' input[type="checkbox"]:not(:disabled)\n ',RADIO_SELECTOR:'input[type="radio"]',SELECTED_ITEM_SELECTOR:'[aria-selected="true"], [aria-current="true"]'},io={UNSET_INDEX:-1,TYPEAHEAD_BUFFER_CLEAR_TIMEOUT_MS:300}; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +const no=(e,t)=>e-t,ao=["input","button","textarea","select"];function lo(e){return e instanceof Set}const so=e=>{const t=e===io.UNSET_INDEX?new Set:e;return lo(t)?new Set(t):new Set([t])};class co extends tr{constructor(e){super(Object.assign(Object.assign({},co.defaultAdapter),e)),this.isMulti_=!1,this.wrapFocus_=!1,this.isVertical_=!0,this.selectedIndex_=io.UNSET_INDEX,this.focusedItemIndex_=io.UNSET_INDEX,this.useActivatedClass_=!1,this.ariaCurrentAttrValue_=null}static get strings(){return oo}static get numbers(){return io}static get defaultAdapter(){return{focusItemAtIndex:()=>{},getFocusedElementIndex:()=>0,getListItemCount:()=>0,isFocusInsideList:()=>!1,isRootFocused:()=>!1,notifyAction:()=>{},notifySelected:()=>{},getSelectedStateForElementIndex:()=>!1,setDisabledStateForElementIndex:()=>{},getDisabledStateForElementIndex:()=>!1,setSelectedStateForElementIndex:()=>{},setActivatedStateForElementIndex:()=>{},setTabIndexForElementIndex:()=>{},setAttributeForElementIndex:()=>{},getAttributeForElementIndex:()=>null}}setWrapFocus(e){this.wrapFocus_=e}setMulti(e){this.isMulti_=e;const t=this.selectedIndex_;if(e){if(!lo(t)){const e=t===io.UNSET_INDEX;this.selectedIndex_=e?new Set:new Set([t])}}else if(lo(t))if(t.size){const e=Array.from(t).sort(no);this.selectedIndex_=e[0]}else this.selectedIndex_=io.UNSET_INDEX}setVerticalOrientation(e){this.isVertical_=e}setUseActivatedClass(e){this.useActivatedClass_=e}getSelectedIndex(){return this.selectedIndex_}setSelectedIndex(e){this.isIndexValid_(e)&&(this.isMulti_?this.setMultiSelectionAtIndex_(so(e)):this.setSingleSelectionAtIndex_(e))}handleFocusIn(e,t){t>=0&&this.adapter.setTabIndexForElementIndex(t,0)}handleFocusOut(e,t){t>=0&&this.adapter.setTabIndexForElementIndex(t,-1),setTimeout((()=>{this.adapter.isFocusInsideList()||this.setTabindexToFirstSelectedItem_()}),0)}handleKeydown(e,t,r){const o="ArrowLeft"===Jr(e),i="ArrowUp"===Jr(e),n="ArrowRight"===Jr(e),a="ArrowDown"===Jr(e),l="Home"===Jr(e),s="End"===Jr(e),d="Enter"===Jr(e),c="Spacebar"===Jr(e);if(this.adapter.isRootFocused())return void(i||s?(e.preventDefault(),this.focusLastElement()):(a||l)&&(e.preventDefault(),this.focusFirstElement()));let u,p=this.adapter.getFocusedElementIndex();if(!(-1===p&&(p=r,p<0))){if(this.isVertical_&&a||!this.isVertical_&&n)this.preventDefaultEvent(e),u=this.focusNextElement(p);else if(this.isVertical_&&i||!this.isVertical_&&o)this.preventDefaultEvent(e),u=this.focusPrevElement(p);else if(l)this.preventDefaultEvent(e),u=this.focusFirstElement();else if(s)this.preventDefaultEvent(e),u=this.focusLastElement();else if((d||c)&&t){const t=e.target;if(t&&"A"===t.tagName&&d)return;this.preventDefaultEvent(e),this.setSelectedIndexOnAction_(p,!0)}this.focusedItemIndex_=p,void 0!==u&&(this.setTabindexAtIndex_(u),this.focusedItemIndex_=u)}}handleSingleSelection(e,t,r){e!==io.UNSET_INDEX&&(this.setSelectedIndexOnAction_(e,t,r),this.setTabindexAtIndex_(e),this.focusedItemIndex_=e)}focusNextElement(e){let t=e+1;if(t>=this.adapter.getListItemCount()){if(!this.wrapFocus_)return e;t=0}return this.adapter.focusItemAtIndex(t),t}focusPrevElement(e){let t=e-1;if(t<0){if(!this.wrapFocus_)return e;t=this.adapter.getListItemCount()-1}return this.adapter.focusItemAtIndex(t),t}focusFirstElement(){return this.adapter.focusItemAtIndex(0),0}focusLastElement(){const e=this.adapter.getListItemCount()-1;return this.adapter.focusItemAtIndex(e),e}setEnabled(e,t){this.isIndexValid_(e)&&this.adapter.setDisabledStateForElementIndex(e,!t)}preventDefaultEvent(e){const t=(""+e.target.tagName).toLowerCase();-1===ao.indexOf(t)&&e.preventDefault()}setSingleSelectionAtIndex_(e,t=!0){this.selectedIndex_!==e&&(this.selectedIndex_!==io.UNSET_INDEX&&(this.adapter.setSelectedStateForElementIndex(this.selectedIndex_,!1),this.useActivatedClass_&&this.adapter.setActivatedStateForElementIndex(this.selectedIndex_,!1)),t&&this.adapter.setSelectedStateForElementIndex(e,!0),this.useActivatedClass_&&this.adapter.setActivatedStateForElementIndex(e,!0),this.setAriaForSingleSelectionAtIndex_(e),this.selectedIndex_=e,this.adapter.notifySelected(e))}setMultiSelectionAtIndex_(e,t=!0){const r=((e,t)=>{const r=Array.from(e),o=Array.from(t),i={added:[],removed:[]},n=r.sort(no),a=o.sort(no);let l=0,s=0;for(;l=0&&this.focusedItemIndex_!==e&&this.adapter.setTabIndexForElementIndex(this.focusedItemIndex_,-1),this.adapter.setTabIndexForElementIndex(e,0)}setTabindexToFirstSelectedItem_(){let e=0;"number"==typeof this.selectedIndex_&&this.selectedIndex_!==io.UNSET_INDEX?e=this.selectedIndex_:lo(this.selectedIndex_)&&this.selectedIndex_.size>0&&(e=Math.min(...this.selectedIndex_)),this.setTabindexAtIndex_(e)}isIndexValid_(e){if(e instanceof Set){if(!this.isMulti_)throw Error("MDCListFoundation: Array of index is only supported for checkbox based list");if(0===e.size)return!0;{let t=!1;for(const r of e)if(t=this.isIndexInRange_(r),t)break;return t}}if("number"==typeof e){if(this.isMulti_)throw Error("MDCListFoundation: Expected array of index for checkbox based list but got number: "+e);return e===io.UNSET_INDEX||this.isIndexInRange_(e)}return!1}isIndexInRange_(e){const t=this.adapter.getListItemCount();return e>=0&&ee.hasAttribute("mwc-list-item");function po(){const e=this.itemsReadyResolver;this.itemsReady=new Promise((e=>this.itemsReadyResolver=e)),e()}class ho extends er{constructor(){super(),this.mdcAdapter=null,this.mdcFoundationClass=co,this.activatable=!1,this.multi=!1,this.wrapFocus=!1,this.itemRoles=null,this.innerRole=null,this.innerAriaLabel=null,this.rootTabbable=!1,this.previousTabindex=null,this.noninteractive=!1,this.itemsReadyResolver=()=>{},this.itemsReady=Promise.resolve([]),this.items_=[];const e=function(e,t=50){let r;return function(o=!0){clearTimeout(r),r=setTimeout((()=>{e(o)}),t)}}(this.layout.bind(this));this.debouncedLayout=(t=!0)=>{po.call(this),e(t)}}async getUpdateComplete(){const e=await super.getUpdateComplete();return await this.itemsReady,e}get items(){return this.items_}updateItems(){var e;const t=null!==(e=this.assignedElements)&&void 0!==e?e:[],r=[];for(const e of t)uo(e)&&(r.push(e),e._managingList=this),e.hasAttribute("divider")&&!e.hasAttribute("role")&&e.setAttribute("role","separator");this.items_=r;const o=new Set;if(this.items_.forEach(((e,t)=>{this.itemRoles?e.setAttribute("role",this.itemRoles):e.removeAttribute("role"),e.selected&&o.add(t)})),this.multi)this.select(o);else{const e=o.size?o.entries().next().value[1]:-1;this.select(e)}const i=new Event("items-updated",{bubbles:!0,composed:!0});this.dispatchEvent(i)}get selected(){const e=this.index;if(!lo(e))return-1===e?null:this.items[e];const t=[];for(const r of e)t.push(this.items[r]);return t}get index(){return this.mdcFoundation?this.mdcFoundation.getSelectedIndex():-1}render(){const e=null===this.innerRole?void 0:this.innerRole,t=null===this.innerAriaLabel?void 0:this.innerAriaLabel,r=this.rootTabbable?"0":"-1";return W` + +
    + + ${this.renderPlaceholder()} +
+ `}renderPlaceholder(){var e;const t=null!==(e=this.assignedElements)&&void 0!==e?e:[];return void 0!==this.emptyMessage&&0===t.length?W` + ${this.emptyMessage} + `:null}firstUpdated(){super.firstUpdated(),this.items.length||(this.mdcFoundation.setMulti(this.multi),this.layout())}onFocusIn(e){if(this.mdcFoundation&&this.mdcRoot){const t=this.getIndexOfTarget(e);this.mdcFoundation.handleFocusIn(e,t)}}onFocusOut(e){if(this.mdcFoundation&&this.mdcRoot){const t=this.getIndexOfTarget(e);this.mdcFoundation.handleFocusOut(e,t)}}onKeydown(e){if(this.mdcFoundation&&this.mdcRoot){const t=this.getIndexOfTarget(e),r=e.target,o=uo(r);this.mdcFoundation.handleKeydown(e,o,t)}}onRequestSelected(e){if(this.mdcFoundation){let t=this.getIndexOfTarget(e);if(-1===t&&(this.layout(),t=this.getIndexOfTarget(e),-1===t))return;if(this.items[t].disabled)return;const r=e.detail.selected,o=e.detail.source;this.mdcFoundation.handleSingleSelection(t,"interaction"===o,r),e.stopPropagation()}}getIndexOfTarget(e){const t=this.items,r=e.composedPath();for(const e of r){let r=-1;if(e.nodeType===Node.ELEMENT_NODE&&uo(e)&&(r=t.indexOf(e)),-1!==r)return r}return-1}createAdapter(){return this.mdcAdapter={getListItemCount:()=>this.mdcRoot?this.items.length:0,getFocusedElementIndex:this.getFocusedItemIndex,getAttributeForElementIndex:(e,t)=>{if(!this.mdcRoot)return"";const r=this.items[e];return r?r.getAttribute(t):""},setAttributeForElementIndex:(e,t,r)=>{if(!this.mdcRoot)return;const o=this.items[e];o&&o.setAttribute(t,r)},focusItemAtIndex:e=>{const t=this.items[e];t&&t.focus()},setTabIndexForElementIndex:(e,t)=>{const r=this.items[e];r&&(r.tabindex=t)},notifyAction:e=>{const t={bubbles:!0,composed:!0};t.detail={index:e};const r=new CustomEvent("action",t);this.dispatchEvent(r)},notifySelected:(e,t)=>{const r={bubbles:!0,composed:!0};r.detail={index:e,diff:t};const o=new CustomEvent("selected",r);this.dispatchEvent(o)},isFocusInsideList:()=>$t(this),isRootFocused:()=>{const e=this.mdcRoot;return e.getRootNode().activeElement===e},setDisabledStateForElementIndex:(e,t)=>{const r=this.items[e];r&&(r.disabled=t)},getDisabledStateForElementIndex:e=>{const t=this.items[e];return!!t&&t.disabled},setSelectedStateForElementIndex:(e,t)=>{const r=this.items[e];r&&(r.selected=t)},getSelectedStateForElementIndex:e=>{const t=this.items[e];return!!t&&t.selected},setActivatedStateForElementIndex:(e,t)=>{const r=this.items[e];r&&(r.activated=t)}},this.mdcAdapter}selectUi(e,t=!1){const r=this.items[e];r&&(r.selected=!0,r.activated=t)}deselectUi(e){const t=this.items[e];t&&(t.selected=!1,t.activated=!1)}select(e){this.mdcFoundation&&this.mdcFoundation.setSelectedIndex(e)}toggle(e,t){this.multi&&this.mdcFoundation.toggleMultiAtIndex(e,t)}onListItemConnected(e){const t=e.target;this.layout(-1===this.items.indexOf(t))}layout(e=!0){e&&this.updateItems();const t=this.items[0];for(const e of this.items)e.tabindex=-1;t&&(this.noninteractive?this.previousTabindex||(this.previousTabindex=t):t.tabindex=0),this.itemsReadyResolver()}getFocusedItemIndex(){if(!this.mdcRoot)return-1;if(!this.items.length)return-1;const e=Xt();if(!e.length)return-1;for(let t=e.length-1;t>=0;t--){const r=e[t];if(uo(r))return this.items.indexOf(r)}return-1}focusItemAtIndex(e){for(const e of this.items)if(0===e.tabindex){e.tabindex=-1;break}this.items[e].tabindex=0,this.items[e].focus()}focus(){const e=this.mdcRoot;e&&e.focus()}blur(){const e=this.mdcRoot;e&&e.blur()}}o([ge({type:String})],ho.prototype,"emptyMessage",void 0),o([ye(".mdc-deprecated-list")],ho.prototype,"mdcRoot",void 0),o([ke("",!0,"*")],ho.prototype,"assignedElements",void 0),o([ke("",!0,'[tabindex="0"]')],ho.prototype,"tabbableElements",void 0),o([ge({type:Boolean}),Tr((function(e){this.mdcFoundation&&this.mdcFoundation.setUseActivatedClass(e)}))],ho.prototype,"activatable",void 0),o([ge({type:Boolean}),Tr((function(e,t){this.mdcFoundation&&this.mdcFoundation.setMulti(e),void 0!==t&&this.layout()}))],ho.prototype,"multi",void 0),o([ge({type:Boolean}),Tr((function(e){this.mdcFoundation&&this.mdcFoundation.setWrapFocus(e)}))],ho.prototype,"wrapFocus",void 0),o([ge({type:String}),Tr((function(e,t){void 0!==t&&this.updateItems()}))],ho.prototype,"itemRoles",void 0),o([ge({type:String})],ho.prototype,"innerRole",void 0),o([ge({type:String})],ho.prototype,"innerAriaLabel",void 0),o([ge({type:Boolean})],ho.prototype,"rootTabbable",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e){var t,r;if(e){const e=null!==(r=null===(t=this.tabbableElements)||void 0===t?void 0:t[0])&&void 0!==r?r:null;this.previousTabindex=e,e&&e.setAttribute("tabindex","-1")}else!e&&this.previousTabindex&&(this.previousTabindex.setAttribute("tabindex","0"),this.previousTabindex=null)}))],ho.prototype,"noninteractive",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const go=c`@keyframes mdc-ripple-fg-radius-in{from{animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-opacity-in{from{animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-out{from{animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}:host{display:block}.mdc-deprecated-list{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);line-height:1.5rem;margin:0;padding:8px 0;list-style-type:none;color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));padding:var(--mdc-list-vertical-padding, 8px) 0}.mdc-deprecated-list:focus{outline:none}.mdc-deprecated-list-item{height:48px}.mdc-deprecated-list--dense{padding-top:4px;padding-bottom:4px;font-size:.812rem}.mdc-deprecated-list ::slotted([divider]){height:0;margin:0;border:none;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgba(0, 0, 0, 0.12)}.mdc-deprecated-list ::slotted([divider][padded]){margin:0 var(--mdc-list-side-padding, 16px)}.mdc-deprecated-list ::slotted([divider][inset]){margin-left:var(--mdc-list-inset-margin, 72px);margin-right:0;width:calc( 100% - var(--mdc-list-inset-margin, 72px) )}[dir=rtl] .mdc-deprecated-list ::slotted([divider][inset]),.mdc-deprecated-list ::slotted([divider][inset][dir=rtl]){margin-left:0;margin-right:var(--mdc-list-inset-margin, 72px)}.mdc-deprecated-list ::slotted([divider][inset][padded]){width:calc( 100% - var(--mdc-list-inset-margin, 72px) - var(--mdc-list-side-padding, 16px) )}.mdc-deprecated-list--dense ::slotted([mwc-list-item]){height:40px}.mdc-deprecated-list--dense ::slotted([mwc-list]){--mdc-list-item-graphic-size: 20px}.mdc-deprecated-list--two-line.mdc-deprecated-list--dense ::slotted([mwc-list-item]),.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense ::slotted([mwc-list-item]){height:60px}.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense ::slotted([mwc-list]){--mdc-list-item-graphic-size: 36px}:host([noninteractive]){pointer-events:none;cursor:default}.mdc-deprecated-list--dense ::slotted(.mdc-deprecated-list-item__primary-text){display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-deprecated-list--dense ::slotted(.mdc-deprecated-list-item__primary-text)::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-deprecated-list--dense ::slotted(.mdc-deprecated-list-item__primary-text)::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}` +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let mo=class extends ho{};mo.styles=[go],mo=o([ue("mwc-list")],mo); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const fo=c`:host{font-family:var(--mdc-icon-font, "Material Icons");font-weight:normal;font-style:normal;font-size:var(--mdc-icon-size, 24px);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:"liga"}` +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let bo=class extends de{render(){return W``}};bo.styles=[fo],bo=o([ue("mwc-icon")],bo); +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +class yo extends de{constructor(){super(...arguments),this.raised=!1,this.unelevated=!1,this.outlined=!1,this.dense=!1,this.disabled=!1,this.trailingIcon=!1,this.fullwidth=!1,this.icon="",this.label="",this.expandContent=!1,this.shouldRenderRipple=!1,this.rippleHandlers=new xr((()=>(this.shouldRenderRipple=!0,this.ripple)))}renderOverlay(){return W``}renderRipple(){const e=this.raised||this.unelevated;return this.shouldRenderRipple?W``:""}focus(){const e=this.buttonElement;e&&(this.rippleHandlers.startFocus(),e.focus())}blur(){const e=this.buttonElement;e&&(this.rippleHandlers.endFocus(),e.blur())}getRenderClasses(){return{"mdc-button--raised":this.raised,"mdc-button--unelevated":this.unelevated,"mdc-button--outlined":this.outlined,"mdc-button--dense":this.dense}}render(){return W` + `}renderIcon(){return W` + + ${this.icon} + `}handleRippleActivate(e){const t=()=>{window.removeEventListener("mouseup",t),this.handleRippleDeactivate()};window.addEventListener("mouseup",t),this.rippleHandlers.startPress(e)}handleRippleDeactivate(){this.rippleHandlers.endPress()}handleRippleMouseEnter(){this.rippleHandlers.startHover()}handleRippleMouseLeave(){this.rippleHandlers.endHover()}handleRippleFocus(){this.rippleHandlers.startFocus()}handleRippleBlur(){this.rippleHandlers.endFocus()}}yo.shadowRootOptions={mode:"open",delegatesFocus:!0},o([vr,ge({type:String,attribute:"aria-haspopup"})],yo.prototype,"ariaHasPopup",void 0),o([ge({type:Boolean,reflect:!0})],yo.prototype,"raised",void 0),o([ge({type:Boolean,reflect:!0})],yo.prototype,"unelevated",void 0),o([ge({type:Boolean,reflect:!0})],yo.prototype,"outlined",void 0),o([ge({type:Boolean})],yo.prototype,"dense",void 0),o([ge({type:Boolean,reflect:!0})],yo.prototype,"disabled",void 0),o([ge({type:Boolean,attribute:"trailingicon"})],yo.prototype,"trailingIcon",void 0),o([ge({type:Boolean,reflect:!0})],yo.prototype,"fullwidth",void 0),o([ge({type:String})],yo.prototype,"icon",void 0),o([ge({type:String})],yo.prototype,"label",void 0),o([ge({type:Boolean})],yo.prototype,"expandContent",void 0),o([ye("#button")],yo.prototype,"buttonElement",void 0),o([ve("mwc-ripple")],yo.prototype,"ripple",void 0),o([me()],yo.prototype,"shouldRenderRipple",void 0),o([be({passive:!0})],yo.prototype,"handleRippleActivate",null); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const vo=c`.mdc-button{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase)}.mdc-touch-target-wrapper{display:inline}.mdc-elevation-overlay{position:absolute;border-radius:inherit;pointer-events:none;opacity:0;opacity:var(--mdc-elevation-overlay-opacity, 0);transition:opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);background-color:#fff;background-color:var(--mdc-elevation-overlay-color, #fff)}.mdc-button{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:64px;border:none;outline:none;line-height:inherit;user-select:none;-webkit-appearance:none;overflow:visible;vertical-align:middle;background:transparent}.mdc-button .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-button::-moz-focus-inner{padding:0;border:0}.mdc-button:active{outline:none}.mdc-button:hover{cursor:pointer}.mdc-button:disabled{cursor:default;pointer-events:none}.mdc-button .mdc-button__icon{margin-left:0;margin-right:8px;display:inline-block;position:relative;vertical-align:top}[dir=rtl] .mdc-button .mdc-button__icon,.mdc-button .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:0}.mdc-button .mdc-button__label{position:relative}.mdc-button .mdc-button__focus-ring{display:none}@media screen and (forced-colors: active){.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__focus-ring,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__focus-ring{pointer-events:none;border:2px solid transparent;border-radius:6px;box-sizing:content-box;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);height:calc( 100% + 4px );width:calc( 100% + 4px );display:block}}@media screen and (forced-colors: active)and (forced-colors: active){.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__focus-ring,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__focus-ring{border-color:CanvasText}}@media screen and (forced-colors: active){.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__focus-ring::after,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__focus-ring::after{content:"";border:2px solid transparent;border-radius:8px;display:block;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);height:calc(100% + 4px);width:calc(100% + 4px)}}@media screen and (forced-colors: active)and (forced-colors: active){.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__focus-ring::after,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__focus-ring::after{border-color:CanvasText}}.mdc-button .mdc-button__touch{position:absolute;top:50%;height:48px;left:0;right:0;transform:translateY(-50%)}.mdc-button__label+.mdc-button__icon{margin-left:8px;margin-right:0}[dir=rtl] .mdc-button__label+.mdc-button__icon,.mdc-button__label+.mdc-button__icon[dir=rtl]{margin-left:0;margin-right:8px}svg.mdc-button__icon{fill:currentColor}.mdc-button--touch{margin-top:6px;margin-bottom:6px}.mdc-button{padding:0 8px 0 8px}.mdc-button--unelevated{transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);padding:0 16px 0 16px}.mdc-button--unelevated.mdc-button--icon-trailing{padding:0 12px 0 16px}.mdc-button--unelevated.mdc-button--icon-leading{padding:0 16px 0 12px}.mdc-button--raised{transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);padding:0 16px 0 16px}.mdc-button--raised.mdc-button--icon-trailing{padding:0 12px 0 16px}.mdc-button--raised.mdc-button--icon-leading{padding:0 16px 0 12px}.mdc-button--outlined{border-style:solid;transition:border 280ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-button--outlined .mdc-button__ripple{border-style:solid;border-color:transparent}.mdc-button{height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button .mdc-button__icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mdc-button .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--raised,.mdc-button--unelevated{height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-button--raised:disabled,.mdc-button--unelevated:disabled{background-color:rgba(0, 0, 0, 0.12)}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-button--raised:disabled,.mdc-button--unelevated:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button--raised .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mdc-button--raised .mdc-button__ripple,.mdc-button--unelevated .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--outlined{height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px);padding:0 15px 0 15px;border-width:1px}.mdc-button--outlined:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button--outlined:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button--outlined .mdc-button__icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mdc-button--outlined .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--outlined:not(:disabled){border-color:rgba(0, 0, 0, 0.12)}.mdc-button--outlined:disabled{border-color:rgba(0, 0, 0, 0.12)}.mdc-button--outlined.mdc-button--icon-trailing{padding:0 11px 0 15px}.mdc-button--outlined.mdc-button--icon-leading{padding:0 15px 0 11px}.mdc-button--outlined .mdc-button__ripple{top:-1px;left:-1px;bottom:-1px;right:-1px;border-width:1px}.mdc-button--outlined .mdc-button__touch{left:calc(-1 * 1px);width:calc(100% + 2 * 1px)}.mdc-button--raised{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-button--raised:hover,.mdc-button--raised:focus{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-button--raised:active{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-button--raised:disabled{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}:host{display:inline-flex;outline:none;-webkit-tap-highlight-color:transparent;vertical-align:top}:host([fullwidth]){width:100%}:host([raised]),:host([unelevated]){--mdc-ripple-color:#fff;--mdc-ripple-focus-opacity:0.24;--mdc-ripple-hover-opacity:0.08;--mdc-ripple-press-opacity:0.24}.trailing-icon ::slotted(*),.trailing-icon .mdc-button__icon,.leading-icon ::slotted(*),.leading-icon .mdc-button__icon{margin-left:0;margin-right:8px;display:inline-block;position:relative;vertical-align:top;font-size:1.125rem;height:1.125rem;width:1.125rem}[dir=rtl] .trailing-icon ::slotted(*),[dir=rtl] .trailing-icon .mdc-button__icon,[dir=rtl] .leading-icon ::slotted(*),[dir=rtl] .leading-icon .mdc-button__icon,.trailing-icon ::slotted(*[dir=rtl]),.trailing-icon .mdc-button__icon[dir=rtl],.leading-icon ::slotted(*[dir=rtl]),.leading-icon .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:0}.trailing-icon ::slotted(*),.trailing-icon .mdc-button__icon{margin-left:8px;margin-right:0}[dir=rtl] .trailing-icon ::slotted(*),[dir=rtl] .trailing-icon .mdc-button__icon,.trailing-icon ::slotted(*[dir=rtl]),.trailing-icon .mdc-button__icon[dir=rtl]{margin-left:0;margin-right:8px}.slot-container{display:inline-flex;align-items:center;justify-content:center}.slot-container.flex{flex:auto}.mdc-button{flex:auto;overflow:hidden;padding-left:8px;padding-left:var(--mdc-button-horizontal-padding, 8px);padding-right:8px;padding-right:var(--mdc-button-horizontal-padding, 8px)}.mdc-button--raised{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);box-shadow:var(--mdc-button-raised-box-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12))}.mdc-button--raised:focus{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);box-shadow:var(--mdc-button-raised-box-shadow-focus, var(--mdc-button-raised-box-shadow-hover, 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12)))}.mdc-button--raised:hover{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);box-shadow:var(--mdc-button-raised-box-shadow-hover, 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12))}.mdc-button--raised:active{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);box-shadow:var(--mdc-button-raised-box-shadow-active, 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12))}.mdc-button--raised:disabled{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12);box-shadow:var(--mdc-button-raised-box-shadow-disabled, 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12))}.mdc-button--raised,.mdc-button--unelevated{padding-left:16px;padding-left:var(--mdc-button-horizontal-padding, 16px);padding-right:16px;padding-right:var(--mdc-button-horizontal-padding, 16px)}.mdc-button--outlined{border-width:1px;border-width:var(--mdc-button-outline-width, 1px);padding-left:calc(16px - 1px);padding-left:calc(var(--mdc-button-horizontal-padding, 16px) - var(--mdc-button-outline-width, 1px));padding-right:calc(16px - 1px);padding-right:calc(var(--mdc-button-horizontal-padding, 16px) - var(--mdc-button-outline-width, 1px))}.mdc-button--outlined:not(:disabled){border-color:rgba(0, 0, 0, 0.12);border-color:var(--mdc-button-outline-color, rgba(0, 0, 0, 0.12))}.mdc-button--outlined .ripple{top:calc(-1 * 1px);top:calc(-1 * var(--mdc-button-outline-width, 1px));left:calc(-1 * 1px);left:calc(-1 * var(--mdc-button-outline-width, 1px));right:initial;right:initial;border-width:1px;border-width:var(--mdc-button-outline-width, 1px);border-style:solid;border-color:transparent}[dir=rtl] .mdc-button--outlined .ripple,.mdc-button--outlined .ripple[dir=rtl]{left:initial;left:initial;right:calc(-1 * 1px);right:calc(-1 * var(--mdc-button-outline-width, 1px))}.mdc-button--dense{height:28px;margin-top:0;margin-bottom:0}.mdc-button--dense .mdc-button__touch{height:100%}:host([disabled]){pointer-events:none}:host([disabled]) .mdc-button{color:rgba(0, 0, 0, 0.38);color:var(--mdc-button-disabled-ink-color, rgba(0, 0, 0, 0.38))}:host([disabled]) .mdc-button--raised,:host([disabled]) .mdc-button--unelevated{background-color:rgba(0, 0, 0, 0.12);background-color:var(--mdc-button-disabled-fill-color, rgba(0, 0, 0, 0.12))}:host([disabled]) .mdc-button--outlined{border-color:rgba(0, 0, 0, 0.12);border-color:var(--mdc-button-disabled-outline-color, rgba(0, 0, 0, 0.12))}` +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let xo=class extends yo{};xo.styles=[vo],xo=o([ue("mwc-button")],xo); +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +var wo={NOTCH_ELEMENT_SELECTOR:".mdc-notched-outline__notch"},ko={NOTCH_ELEMENT_PADDING:8},_o={NO_LABEL:"mdc-notched-outline--no-label",OUTLINE_NOTCHED:"mdc-notched-outline--notched",OUTLINE_UPGRADED:"mdc-notched-outline--upgraded"},Co=function(e){function o(t){return e.call(this,r(r({},o.defaultAdapter),t))||this}return t(o,e),Object.defineProperty(o,"strings",{get:function(){return wo},enumerable:!1,configurable:!0}),Object.defineProperty(o,"cssClasses",{get:function(){return _o},enumerable:!1,configurable:!0}),Object.defineProperty(o,"numbers",{get:function(){return ko},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},setNotchWidthProperty:function(){},removeNotchWidthProperty:function(){}}},enumerable:!1,configurable:!0}),o.prototype.notch=function(e){var t=o.cssClasses.OUTLINE_NOTCHED;e>0&&(e+=ko.NOTCH_ELEMENT_PADDING),this.adapter.setNotchWidthProperty(e),this.adapter.addClass(t)},o.prototype.closeNotch=function(){var e=o.cssClasses.OUTLINE_NOTCHED;this.adapter.removeClass(e),this.adapter.removeNotchWidthProperty()},o}(tr); +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +class So extends er{constructor(){super(...arguments),this.mdcFoundationClass=Co,this.width=0,this.open=!1,this.lastOpen=this.open}createAdapter(){return{addClass:e=>this.mdcRoot.classList.add(e),removeClass:e=>this.mdcRoot.classList.remove(e),setNotchWidthProperty:e=>this.notchElement.style.setProperty("width",e+"px"),removeNotchWidthProperty:()=>this.notchElement.style.removeProperty("width")}}openOrClose(e,t){this.mdcFoundation&&(e&&void 0!==t?this.mdcFoundation.notch(t):this.mdcFoundation.closeNotch())}render(){this.openOrClose(this.open,this.width);const e=pr({"mdc-notched-outline--notched":this.open});return W` + + + + + + + `}}o([ye(".mdc-notched-outline")],So.prototype,"mdcRoot",void 0),o([ge({type:Number})],So.prototype,"width",void 0),o([ge({type:Boolean,reflect:!0})],So.prototype,"open",void 0),o([ye(".mdc-notched-outline__notch")],So.prototype,"notchElement",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const Eo=c`.mdc-notched-outline{display:flex;position:absolute;top:0;right:0;left:0;box-sizing:border-box;width:100%;max-width:100%;height:100%;text-align:left;pointer-events:none}[dir=rtl] .mdc-notched-outline,.mdc-notched-outline[dir=rtl]{text-align:right}.mdc-notched-outline__leading,.mdc-notched-outline__notch,.mdc-notched-outline__trailing{box-sizing:border-box;height:100%;border-top:1px solid;border-bottom:1px solid;pointer-events:none}.mdc-notched-outline__leading{border-left:1px solid;border-right:none;width:12px}[dir=rtl] .mdc-notched-outline__leading,.mdc-notched-outline__leading[dir=rtl]{border-left:none;border-right:1px solid}.mdc-notched-outline__trailing{border-left:none;border-right:1px solid;flex-grow:1}[dir=rtl] .mdc-notched-outline__trailing,.mdc-notched-outline__trailing[dir=rtl]{border-left:1px solid;border-right:none}.mdc-notched-outline__notch{flex:0 0 auto;width:auto;max-width:calc(100% - 12px * 2)}.mdc-notched-outline .mdc-floating-label{display:inline-block;position:relative;max-width:100%}.mdc-notched-outline .mdc-floating-label--float-above{text-overflow:clip}.mdc-notched-outline--upgraded .mdc-floating-label--float-above{max-width:calc(100% / 0.75)}.mdc-notched-outline--notched .mdc-notched-outline__notch{padding-left:0;padding-right:8px;border-top:none}[dir=rtl] .mdc-notched-outline--notched .mdc-notched-outline__notch,.mdc-notched-outline--notched .mdc-notched-outline__notch[dir=rtl]{padding-left:8px;padding-right:0}.mdc-notched-outline--no-label .mdc-notched-outline__notch{display:none}:host{display:block;position:absolute;right:0;left:0;box-sizing:border-box;width:100%;max-width:100%;height:100%;text-align:left;pointer-events:none}[dir=rtl] :host,:host([dir=rtl]){text-align:right}::slotted(.mdc-floating-label){display:inline-block;position:relative;top:17px;bottom:auto;max-width:100%}::slotted(.mdc-floating-label--float-above){text-overflow:clip}.mdc-notched-outline--upgraded ::slotted(.mdc-floating-label--float-above){max-width:calc(100% / 0.75)}.mdc-notched-outline .mdc-notched-outline__leading{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}[dir=rtl] .mdc-notched-outline .mdc-notched-outline__leading,.mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}@supports(top: max(0%)){.mdc-notched-outline .mdc-notched-outline__leading{width:max(12px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-notched-outline .mdc-notched-outline__notch{max-width:calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2)}}.mdc-notched-outline .mdc-notched-outline__trailing{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}[dir=rtl] .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}.mdc-notched-outline__leading,.mdc-notched-outline__notch,.mdc-notched-outline__trailing{border-color:var(--mdc-notched-outline-border-color, var(--mdc-theme-primary, #6200ee));border-width:1px;border-width:var(--mdc-notched-outline-stroke-width, 1px)}.mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:0;padding-top:var(--mdc-notched-outline-notch-offset, 0)}` +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let To=class extends So{}; +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +var Ao,Oo;To.styles=[Eo],To=o([ue("mwc-notched-outline")],To);const Lo=null!==(Oo=null===(Ao=window.ShadyDOM)||void 0===Ao?void 0:Ao.inUse)&&void 0!==Oo&&Oo;class Mo extends er{constructor(){super(...arguments),this.disabled=!1,this.containingForm=null,this.formDataListener=e=>{this.disabled||this.setFormData(e.formData)}}findFormElement(){if(!this.shadowRoot||Lo)return null;const e=this.getRootNode().querySelectorAll("form");for(const t of Array.from(e))if(t.contains(this))return t;return null}connectedCallback(){var e;super.connectedCallback(),this.containingForm=this.findFormElement(),null===(e=this.containingForm)||void 0===e||e.addEventListener("formdata",this.formDataListener)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this.containingForm)||void 0===e||e.removeEventListener("formdata",this.formDataListener),this.containingForm=null}click(){this.formElement&&!this.disabled&&(this.formElement.focus(),this.formElement.click())}firstUpdated(){super.firstUpdated(),this.shadowRoot&&this.mdcRoot.addEventListener("change",(e=>{this.dispatchEvent(new Event("change",e))}))}}Mo.shadowRootOptions={mode:"open",delegatesFocus:!0},o([ge({type:Boolean})],Mo.prototype,"disabled",void 0); +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +var Io={LABEL_FLOAT_ABOVE:"mdc-floating-label--float-above",LABEL_REQUIRED:"mdc-floating-label--required",LABEL_SHAKE:"mdc-floating-label--shake",ROOT:"mdc-floating-label"},Ro=function(e){function o(t){var i=e.call(this,r(r({},o.defaultAdapter),t))||this;return i.shakeAnimationEndHandler=function(){i.handleShakeAnimationEnd()},i}return t(o,e),Object.defineProperty(o,"cssClasses",{get:function(){return Io},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},getWidth:function(){return 0},registerInteractionHandler:function(){},deregisterInteractionHandler:function(){}}},enumerable:!1,configurable:!0}),o.prototype.init=function(){this.adapter.registerInteractionHandler("animationend",this.shakeAnimationEndHandler)},o.prototype.destroy=function(){this.adapter.deregisterInteractionHandler("animationend",this.shakeAnimationEndHandler)},o.prototype.getWidth=function(){return this.adapter.getWidth()},o.prototype.shake=function(e){var t=o.cssClasses.LABEL_SHAKE;e?this.adapter.addClass(t):this.adapter.removeClass(t)},o.prototype.float=function(e){var t=o.cssClasses,r=t.LABEL_FLOAT_ABOVE,i=t.LABEL_SHAKE;e?this.adapter.addClass(r):(this.adapter.removeClass(r),this.adapter.removeClass(i))},o.prototype.setRequired=function(e){var t=o.cssClasses.LABEL_REQUIRED;e?this.adapter.addClass(t):this.adapter.removeClass(t)},o.prototype.handleShakeAnimationEnd=function(){var e=o.cssClasses.LABEL_SHAKE;this.adapter.removeClass(e)},o}(tr); +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */const Fo=cr(class extends ur{constructor(e){switch(super(e),this.foundation=null,this.previousPart=null,e.type){case 1:case 3:break;default:throw Error("FloatingLabel directive only support attribute and property parts")}}update(e,[t]){if(e!==this.previousPart){this.foundation&&this.foundation.destroy(),this.previousPart=e;const t=e.element;t.classList.add("mdc-floating-label");const r=(e=>({addClass:t=>e.classList.add(t),removeClass:t=>e.classList.remove(t),getWidth:()=>e.scrollWidth,registerInteractionHandler:(t,r)=>{e.addEventListener(t,r)},deregisterInteractionHandler:(t,r)=>{e.removeEventListener(t,r)}}))(t);this.foundation=new Ro(r),this.foundation.init()}return this.render(t)}render(e){return this.foundation}}); +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */var No={LINE_RIPPLE_ACTIVE:"mdc-line-ripple--active",LINE_RIPPLE_DEACTIVATING:"mdc-line-ripple--deactivating"},zo=function(e){function o(t){var i=e.call(this,r(r({},o.defaultAdapter),t))||this;return i.transitionEndHandler=function(e){i.handleTransitionEnd(e)},i}return t(o,e),Object.defineProperty(o,"cssClasses",{get:function(){return No},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},hasClass:function(){return!1},setStyle:function(){},registerEventHandler:function(){},deregisterEventHandler:function(){}}},enumerable:!1,configurable:!0}),o.prototype.init=function(){this.adapter.registerEventHandler("transitionend",this.transitionEndHandler)},o.prototype.destroy=function(){this.adapter.deregisterEventHandler("transitionend",this.transitionEndHandler)},o.prototype.activate=function(){this.adapter.removeClass(No.LINE_RIPPLE_DEACTIVATING),this.adapter.addClass(No.LINE_RIPPLE_ACTIVE)},o.prototype.setRippleCenter=function(e){this.adapter.setStyle("transform-origin",e+"px center")},o.prototype.deactivate=function(){this.adapter.addClass(No.LINE_RIPPLE_DEACTIVATING)},o.prototype.handleTransitionEnd=function(e){var t=this.adapter.hasClass(No.LINE_RIPPLE_DEACTIVATING);"opacity"===e.propertyName&&t&&(this.adapter.removeClass(No.LINE_RIPPLE_ACTIVE),this.adapter.removeClass(No.LINE_RIPPLE_DEACTIVATING))},o}(tr); +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */const Do=cr(class extends ur{constructor(e){switch(super(e),this.previousPart=null,this.foundation=null,e.type){case 1:case 3:return;default:throw Error("LineRipple only support attribute and property parts.")}}update(e,t){if(this.previousPart!==e){this.foundation&&this.foundation.destroy(),this.previousPart=e;const t=e.element;t.classList.add("mdc-line-ripple");const r=(e=>({addClass:t=>e.classList.add(t),removeClass:t=>e.classList.remove(t),hasClass:t=>e.classList.contains(t),setStyle:(t,r)=>e.style.setProperty(t,r),registerEventHandler:(t,r)=>{e.addEventListener(t,r)},deregisterEventHandler:(t,r)=>{e.removeEventListener(t,r)}}))(t);this.foundation=new zo(r),this.foundation.init()}return this.render()}render(){return this.foundation}}); +/** + * @license + * Copyright 2016 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */var Po={ARIA_CONTROLS:"aria-controls",ARIA_DESCRIBEDBY:"aria-describedby",INPUT_SELECTOR:".mdc-text-field__input",LABEL_SELECTOR:".mdc-floating-label",LEADING_ICON_SELECTOR:".mdc-text-field__icon--leading",LINE_RIPPLE_SELECTOR:".mdc-line-ripple",OUTLINE_SELECTOR:".mdc-notched-outline",PREFIX_SELECTOR:".mdc-text-field__affix--prefix",SUFFIX_SELECTOR:".mdc-text-field__affix--suffix",TRAILING_ICON_SELECTOR:".mdc-text-field__icon--trailing"},Ho={DISABLED:"mdc-text-field--disabled",FOCUSED:"mdc-text-field--focused",HELPER_LINE:"mdc-text-field-helper-line",INVALID:"mdc-text-field--invalid",LABEL_FLOATING:"mdc-text-field--label-floating",NO_LABEL:"mdc-text-field--no-label",OUTLINED:"mdc-text-field--outlined",ROOT:"mdc-text-field",TEXTAREA:"mdc-text-field--textarea",WITH_LEADING_ICON:"mdc-text-field--with-leading-icon",WITH_TRAILING_ICON:"mdc-text-field--with-trailing-icon",WITH_INTERNAL_COUNTER:"mdc-text-field--with-internal-counter"},Uo={LABEL_SCALE:.75},Bo=["pattern","min","max","required","step","minlength","maxlength"],Wo=["color","date","datetime-local","month","range","time","week"],Ko=["mousedown","touchstart"],jo=["click","keydown"],Vo=function(e){function o(t,i){void 0===i&&(i={});var n=e.call(this,r(r({},o.defaultAdapter),t))||this;return n.isFocused=!1,n.receivedUserInput=!1,n.valid=!0,n.useNativeValidation=!0,n.validateOnValueChange=!0,n.helperText=i.helperText,n.characterCounter=i.characterCounter,n.leadingIcon=i.leadingIcon,n.trailingIcon=i.trailingIcon,n.inputFocusHandler=function(){n.activateFocus()},n.inputBlurHandler=function(){n.deactivateFocus()},n.inputInputHandler=function(){n.handleInput()},n.setPointerXOffset=function(e){n.setTransformOrigin(e)},n.textFieldInteractionHandler=function(){n.handleTextFieldInteraction()},n.validationAttributeChangeHandler=function(e){n.handleValidationAttributeChange(e)},n}return t(o,e),Object.defineProperty(o,"cssClasses",{get:function(){return Ho},enumerable:!1,configurable:!0}),Object.defineProperty(o,"strings",{get:function(){return Po},enumerable:!1,configurable:!0}),Object.defineProperty(o,"numbers",{get:function(){return Uo},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"shouldAlwaysFloat",{get:function(){var e=this.getNativeInput().type;return Wo.indexOf(e)>=0},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"shouldFloat",{get:function(){return this.shouldAlwaysFloat||this.isFocused||!!this.getValue()||this.isBadInput()},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"shouldShake",{get:function(){return!this.isFocused&&!this.isValid()&&!!this.getValue()},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},hasClass:function(){return!0},setInputAttr:function(){},removeInputAttr:function(){},registerTextFieldInteractionHandler:function(){},deregisterTextFieldInteractionHandler:function(){},registerInputInteractionHandler:function(){},deregisterInputInteractionHandler:function(){},registerValidationAttributeChangeHandler:function(){return new MutationObserver((function(){}))},deregisterValidationAttributeChangeHandler:function(){},getNativeInput:function(){return null},isFocused:function(){return!1},activateLineRipple:function(){},deactivateLineRipple:function(){},setLineRippleTransformOrigin:function(){},shakeLabel:function(){},floatLabel:function(){},setLabelRequired:function(){},hasLabel:function(){return!1},getLabelWidth:function(){return 0},hasOutline:function(){return!1},notchOutline:function(){},closeOutline:function(){}}},enumerable:!1,configurable:!0}),o.prototype.init=function(){var e,t,r,o;this.adapter.hasLabel()&&this.getNativeInput().required&&this.adapter.setLabelRequired(!0),this.adapter.isFocused()?this.inputFocusHandler():this.adapter.hasLabel()&&this.shouldFloat&&(this.notchOutline(!0),this.adapter.floatLabel(!0),this.styleFloating(!0)),this.adapter.registerInputInteractionHandler("focus",this.inputFocusHandler),this.adapter.registerInputInteractionHandler("blur",this.inputBlurHandler),this.adapter.registerInputInteractionHandler("input",this.inputInputHandler);try{for(var n=i(Ko),a=n.next();!a.done;a=n.next()){var l=a.value;this.adapter.registerInputInteractionHandler(l,this.setPointerXOffset)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}try{for(var s=i(jo),d=s.next();!d.done;d=s.next())l=d.value,this.adapter.registerTextFieldInteractionHandler(l,this.textFieldInteractionHandler)}catch(e){r={error:e}}finally{try{d&&!d.done&&(o=s.return)&&o.call(s)}finally{if(r)throw r.error}}this.validationObserver=this.adapter.registerValidationAttributeChangeHandler(this.validationAttributeChangeHandler),this.setcharacterCounter(this.getValue().length)},o.prototype.destroy=function(){var e,t,r,o;this.adapter.deregisterInputInteractionHandler("focus",this.inputFocusHandler),this.adapter.deregisterInputInteractionHandler("blur",this.inputBlurHandler),this.adapter.deregisterInputInteractionHandler("input",this.inputInputHandler);try{for(var n=i(Ko),a=n.next();!a.done;a=n.next()){var l=a.value;this.adapter.deregisterInputInteractionHandler(l,this.setPointerXOffset)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}try{for(var s=i(jo),d=s.next();!d.done;d=s.next())l=d.value,this.adapter.deregisterTextFieldInteractionHandler(l,this.textFieldInteractionHandler)}catch(e){r={error:e}}finally{try{d&&!d.done&&(o=s.return)&&o.call(s)}finally{if(r)throw r.error}}this.adapter.deregisterValidationAttributeChangeHandler(this.validationObserver)},o.prototype.handleTextFieldInteraction=function(){var e=this.adapter.getNativeInput();e&&e.disabled||(this.receivedUserInput=!0)},o.prototype.handleValidationAttributeChange=function(e){var t=this;e.some((function(e){return Bo.indexOf(e)>-1&&(t.styleValidity(!0),t.adapter.setLabelRequired(t.getNativeInput().required),!0)})),e.indexOf("maxlength")>-1&&this.setcharacterCounter(this.getValue().length)},o.prototype.notchOutline=function(e){if(this.adapter.hasOutline()&&this.adapter.hasLabel())if(e){var t=this.adapter.getLabelWidth()*Uo.LABEL_SCALE;this.adapter.notchOutline(t)}else this.adapter.closeOutline()},o.prototype.activateFocus=function(){this.isFocused=!0,this.styleFocused(this.isFocused),this.adapter.activateLineRipple(),this.adapter.hasLabel()&&(this.notchOutline(this.shouldFloat),this.adapter.floatLabel(this.shouldFloat),this.styleFloating(this.shouldFloat),this.adapter.shakeLabel(this.shouldShake)),!this.helperText||!this.helperText.isPersistent()&&this.helperText.isValidation()&&this.valid||this.helperText.showToScreenReader()},o.prototype.setTransformOrigin=function(e){if(!this.isDisabled()&&!this.adapter.hasOutline()){var t=e.touches,r=t?t[0]:e,o=r.target.getBoundingClientRect(),i=r.clientX-o.left;this.adapter.setLineRippleTransformOrigin(i)}},o.prototype.handleInput=function(){this.autoCompleteFocus(),this.setcharacterCounter(this.getValue().length)},o.prototype.autoCompleteFocus=function(){this.receivedUserInput||this.activateFocus()},o.prototype.deactivateFocus=function(){this.isFocused=!1,this.adapter.deactivateLineRipple();var e=this.isValid();this.styleValidity(e),this.styleFocused(this.isFocused),this.adapter.hasLabel()&&(this.notchOutline(this.shouldFloat),this.adapter.floatLabel(this.shouldFloat),this.styleFloating(this.shouldFloat),this.adapter.shakeLabel(this.shouldShake)),this.shouldFloat||(this.receivedUserInput=!1)},o.prototype.getValue=function(){return this.getNativeInput().value},o.prototype.setValue=function(e){if(this.getValue()!==e&&(this.getNativeInput().value=e),this.setcharacterCounter(e.length),this.validateOnValueChange){var t=this.isValid();this.styleValidity(t)}this.adapter.hasLabel()&&(this.notchOutline(this.shouldFloat),this.adapter.floatLabel(this.shouldFloat),this.styleFloating(this.shouldFloat),this.validateOnValueChange&&this.adapter.shakeLabel(this.shouldShake))},o.prototype.isValid=function(){return this.useNativeValidation?this.isNativeInputValid():this.valid},o.prototype.setValid=function(e){this.valid=e,this.styleValidity(e);var t=!e&&!this.isFocused&&!!this.getValue();this.adapter.hasLabel()&&this.adapter.shakeLabel(t)},o.prototype.setValidateOnValueChange=function(e){this.validateOnValueChange=e},o.prototype.getValidateOnValueChange=function(){return this.validateOnValueChange},o.prototype.setUseNativeValidation=function(e){this.useNativeValidation=e},o.prototype.isDisabled=function(){return this.getNativeInput().disabled},o.prototype.setDisabled=function(e){this.getNativeInput().disabled=e,this.styleDisabled(e)},o.prototype.setHelperTextContent=function(e){this.helperText&&this.helperText.setContent(e)},o.prototype.setLeadingIconAriaLabel=function(e){this.leadingIcon&&this.leadingIcon.setAriaLabel(e)},o.prototype.setLeadingIconContent=function(e){this.leadingIcon&&this.leadingIcon.setContent(e)},o.prototype.setTrailingIconAriaLabel=function(e){this.trailingIcon&&this.trailingIcon.setAriaLabel(e)},o.prototype.setTrailingIconContent=function(e){this.trailingIcon&&this.trailingIcon.setContent(e)},o.prototype.setcharacterCounter=function(e){if(this.characterCounter){var t=this.getNativeInput().maxLength;if(-1===t)throw Error("MDCTextFieldFoundation: Expected maxlength html property on text input or textarea.");this.characterCounter.setCounterValue(e,t)}},o.prototype.isBadInput=function(){return this.getNativeInput().validity.badInput||!1},o.prototype.isNativeInputValid=function(){return this.getNativeInput().validity.valid},o.prototype.styleValidity=function(e){var t=o.cssClasses.INVALID;if(e?this.adapter.removeClass(t):this.adapter.addClass(t),this.helperText){if(this.helperText.setValidity(e),!this.helperText.isValidation())return;var r=this.helperText.isVisible(),i=this.helperText.getId();r&&i?this.adapter.setInputAttr(Po.ARIA_DESCRIBEDBY,i):this.adapter.removeInputAttr(Po.ARIA_DESCRIBEDBY)}},o.prototype.styleFocused=function(e){var t=o.cssClasses.FOCUSED;e?this.adapter.addClass(t):this.adapter.removeClass(t)},o.prototype.styleDisabled=function(e){var t=o.cssClasses,r=t.DISABLED,i=t.INVALID;e?(this.adapter.addClass(r),this.adapter.removeClass(i)):this.adapter.removeClass(r),this.leadingIcon&&this.leadingIcon.setDisabled(e),this.trailingIcon&&this.trailingIcon.setDisabled(e)},o.prototype.styleFloating=function(e){var t=o.cssClasses.LABEL_FLOATING;e?this.adapter.addClass(t):this.adapter.removeClass(t)},o.prototype.getNativeInput=function(){return(this.adapter?this.adapter.getNativeInput():null)||{disabled:!1,maxLength:-1,required:!1,type:"input",validity:{badInput:!1,valid:!0},value:""}},o}(tr),qo=Vo; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +const Zo={},Go=cr(class extends ur{constructor(e){if(super(e),3!==e.type&&1!==e.type&&4!==e.type)throw Error("The `live` directive is not allowed on child or event bindings");if(!(e=>void 0===e.strings)(e))throw Error("`live` bindings can only contain a single expression")}render(e){return e}update(e,[t]){if(t===K||t===j)return t;const r=e.element,o=e.name;if(3===e.type){if(t===r[o])return K}else if(4===e.type){if(!!t===r.hasAttribute(o))return K}else if(1===e.type&&r.getAttribute(o)===t+"")return K;return((e,t=Zo)=>{e._$AH=t; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */})(e),t}}),Jo=["touchstart","touchmove","scroll","mousewheel"],Qo=(e={})=>{const t={};for(const r in e)t[r]=e[r];return Object.assign({badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:!0,valueMissing:!1},t)};class Yo extends Mo{constructor(){super(...arguments),this.mdcFoundationClass=qo,this.value="",this.type="text",this.placeholder="",this.label="",this.icon="",this.iconTrailing="",this.disabled=!1,this.required=!1,this.minLength=-1,this.maxLength=-1,this.outlined=!1,this.helper="",this.validateOnInitialRender=!1,this.validationMessage="",this.autoValidate=!1,this.pattern="",this.min="",this.max="",this.step=null,this.size=null,this.helperPersistent=!1,this.charCounter=!1,this.endAligned=!1,this.prefix="",this.suffix="",this.name="",this.readOnly=!1,this.autocapitalize="",this.outlineOpen=!1,this.outlineWidth=0,this.isUiValid=!0,this.focused=!1,this._validity=Qo(),this.validityTransform=null}get validity(){return this._checkValidity(this.value),this._validity}get willValidate(){return this.formElement.willValidate}get selectionStart(){return this.formElement.selectionStart}get selectionEnd(){return this.formElement.selectionEnd}focus(){const e=new CustomEvent("focus");this.formElement.dispatchEvent(e),this.formElement.focus()}blur(){const e=new CustomEvent("blur");this.formElement.dispatchEvent(e),this.formElement.blur()}select(){this.formElement.select()}setSelectionRange(e,t,r){this.formElement.setSelectionRange(e,t,r)}update(e){e.has("autoValidate")&&this.mdcFoundation&&this.mdcFoundation.setValidateOnValueChange(this.autoValidate),e.has("value")&&"string"!=typeof this.value&&(this.value=""+this.value),super.update(e)}setFormData(e){this.name&&e.append(this.name,this.value)}render(){const e=this.charCounter&&-1!==this.maxLength,t=!!this.helper||!!this.validationMessage||e,r={"mdc-text-field--disabled":this.disabled,"mdc-text-field--no-label":!this.label,"mdc-text-field--filled":!this.outlined,"mdc-text-field--outlined":this.outlined,"mdc-text-field--with-leading-icon":this.icon,"mdc-text-field--with-trailing-icon":this.iconTrailing,"mdc-text-field--end-aligned":this.endAligned};return W` + + ${this.renderHelperText(t,e)} + `}updated(e){e.has("value")&&void 0!==e.get("value")&&(this.mdcFoundation.setValue(this.value),this.autoValidate&&this.reportValidity())}renderRipple(){return this.outlined?"":W` + + `}renderOutline(){return this.outlined?W` + + ${this.renderLabel()} + `:""}renderLabel(){return this.label?W` + ${this.label} + `:""}renderLeadingIcon(){return this.icon?this.renderIcon(this.icon):""}renderTrailingIcon(){return this.iconTrailing?this.renderIcon(this.iconTrailing,!0):""}renderIcon(e,t=!1){return W`${e}`}renderPrefix(){return this.prefix?this.renderAffix(this.prefix):""}renderSuffix(){return this.suffix?this.renderAffix(this.suffix,!0):""}renderAffix(e,t=!1){return W` + ${e}`}renderInput(e){const t=-1===this.minLength?void 0:this.minLength,r=-1===this.maxLength?void 0:this.maxLength,o=this.autocapitalize?this.autocapitalize:void 0,i=this.validationMessage&&!this.isUiValid,n=this.label?"label":void 0,a=e?"helper-text":void 0,l=this.focused||this.helperPersistent||i?"helper-text":void 0;return W` + `}renderLineRipple(){return this.outlined?"":W` + + `}renderHelperText(e,t){const r=this.validationMessage&&!this.isUiValid,o={"mdc-text-field-helper-text--persistent":this.helperPersistent,"mdc-text-field-helper-text--validation-msg":r},i=this.focused||this.helperPersistent||r?void 0:"true",n=r?this.validationMessage:this.helper;return e?W` +
+
${n}
+ ${this.renderCharCounter(t)} +
`:""}renderCharCounter(e){const t=Math.min(this.value.length,this.maxLength);return e?W` + ${t} / ${this.maxLength}`:""}onInputFocus(){this.focused=!0}onInputBlur(){this.focused=!1,this.reportValidity()}checkValidity(){const e=this._checkValidity(this.value);if(!e){const e=new Event("invalid",{bubbles:!1,cancelable:!0});this.dispatchEvent(e)}return e}reportValidity(){const e=this.checkValidity();return this.mdcFoundation.setValid(e),this.isUiValid=e,e}_checkValidity(e){const t=this.formElement.validity;let r=Qo(t);if(this.validityTransform){const t=this.validityTransform(e,r);r=Object.assign(Object.assign({},r),t),this.mdcFoundation.setUseNativeValidation(!1)}else this.mdcFoundation.setUseNativeValidation(!0);return this._validity=r,this._validity.valid}setCustomValidity(e){this.validationMessage=e,this.formElement.setCustomValidity(e)}handleInputChange(){this.value=this.formElement.value}createAdapter(){return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},this.getRootAdapterMethods()),this.getInputAdapterMethods()),this.getLabelAdapterMethods()),this.getLineRippleAdapterMethods()),this.getOutlineAdapterMethods())}getRootAdapterMethods(){return Object.assign({registerTextFieldInteractionHandler:(e,t)=>this.addEventListener(e,t),deregisterTextFieldInteractionHandler:(e,t)=>this.removeEventListener(e,t),registerValidationAttributeChangeHandler:e=>{const t=new MutationObserver((t=>{e((e=>e.map((e=>e.attributeName)).filter((e=>e)))(t))}));return t.observe(this.formElement,{attributes:!0}),t},deregisterValidationAttributeChangeHandler:e=>e.disconnect()},Jt(this.mdcRoot))}getInputAdapterMethods(){return{getNativeInput:()=>this.formElement,setInputAttr:()=>{},removeInputAttr:()=>{},isFocused:()=>!!this.shadowRoot&&this.shadowRoot.activeElement===this.formElement,registerInputInteractionHandler:(e,t)=>this.formElement.addEventListener(e,t,{passive:e in Jo}),deregisterInputInteractionHandler:(e,t)=>this.formElement.removeEventListener(e,t)}}getLabelAdapterMethods(){return{floatLabel:e=>this.labelElement&&this.labelElement.floatingLabelFoundation.float(e),getLabelWidth:()=>this.labelElement?this.labelElement.floatingLabelFoundation.getWidth():0,hasLabel:()=>!!this.labelElement,shakeLabel:e=>this.labelElement&&this.labelElement.floatingLabelFoundation.shake(e),setLabelRequired:e=>{this.labelElement&&this.labelElement.floatingLabelFoundation.setRequired(e)}}}getLineRippleAdapterMethods(){return{activateLineRipple:()=>{this.lineRippleElement&&this.lineRippleElement.lineRippleFoundation.activate()},deactivateLineRipple:()=>{this.lineRippleElement&&this.lineRippleElement.lineRippleFoundation.deactivate()},setLineRippleTransformOrigin:e=>{this.lineRippleElement&&this.lineRippleElement.lineRippleFoundation.setRippleCenter(e)}}}async getUpdateComplete(){var e;const t=await super.getUpdateComplete();return await(null===(e=this.outlineElement)||void 0===e?void 0:e.updateComplete),t}firstUpdated(){var e;super.firstUpdated(),this.mdcFoundation.setValidateOnValueChange(this.autoValidate),this.validateOnInitialRender&&this.reportValidity(),null===(e=this.outlineElement)||void 0===e||e.updateComplete.then((()=>{var e;this.outlineWidth=(null===(e=this.labelElement)||void 0===e?void 0:e.floatingLabelFoundation.getWidth())||0}))}getOutlineAdapterMethods(){return{closeOutline:()=>this.outlineElement&&(this.outlineOpen=!1),hasOutline:()=>!!this.outlineElement,notchOutline:e=>{this.outlineElement&&!this.outlineOpen&&(this.outlineWidth=e,this.outlineOpen=!0)}}}async layout(){await this.updateComplete;const e=this.labelElement;if(!e)return void(this.outlineOpen=!1);const t=!!this.label&&!!this.value;if(e.floatingLabelFoundation.float(t),!this.outlined)return;this.outlineOpen=t,await this.updateComplete;const r=e.floatingLabelFoundation.getWidth();this.outlineOpen&&(this.outlineWidth=r,await this.updateComplete)}}o([ye(".mdc-text-field")],Yo.prototype,"mdcRoot",void 0),o([ye("input")],Yo.prototype,"formElement",void 0),o([ye(".mdc-floating-label")],Yo.prototype,"labelElement",void 0),o([ye(".mdc-line-ripple")],Yo.prototype,"lineRippleElement",void 0),o([ye("mwc-notched-outline")],Yo.prototype,"outlineElement",void 0),o([ye(".mdc-notched-outline__notch")],Yo.prototype,"notchElement",void 0),o([ge({type:String})],Yo.prototype,"value",void 0),o([ge({type:String})],Yo.prototype,"type",void 0),o([ge({type:String})],Yo.prototype,"placeholder",void 0),o([ge({type:String}),Tr((function(e,t){void 0!==t&&this.label!==t&&this.layout()}))],Yo.prototype,"label",void 0),o([ge({type:String})],Yo.prototype,"icon",void 0),o([ge({type:String})],Yo.prototype,"iconTrailing",void 0),o([ge({type:Boolean,reflect:!0})],Yo.prototype,"disabled",void 0),o([ge({type:Boolean})],Yo.prototype,"required",void 0),o([ge({type:Number})],Yo.prototype,"minLength",void 0),o([ge({type:Number})],Yo.prototype,"maxLength",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e,t){void 0!==t&&this.outlined!==t&&this.layout()}))],Yo.prototype,"outlined",void 0),o([ge({type:String})],Yo.prototype,"helper",void 0),o([ge({type:Boolean})],Yo.prototype,"validateOnInitialRender",void 0),o([ge({type:String})],Yo.prototype,"validationMessage",void 0),o([ge({type:Boolean})],Yo.prototype,"autoValidate",void 0),o([ge({type:String})],Yo.prototype,"pattern",void 0),o([ge({type:String})],Yo.prototype,"min",void 0),o([ge({type:String})],Yo.prototype,"max",void 0),o([ge({type:String})],Yo.prototype,"step",void 0),o([ge({type:Number})],Yo.prototype,"size",void 0),o([ge({type:Boolean})],Yo.prototype,"helperPersistent",void 0),o([ge({type:Boolean})],Yo.prototype,"charCounter",void 0),o([ge({type:Boolean})],Yo.prototype,"endAligned",void 0),o([ge({type:String})],Yo.prototype,"prefix",void 0),o([ge({type:String})],Yo.prototype,"suffix",void 0),o([ge({type:String})],Yo.prototype,"name",void 0),o([ge({type:String})],Yo.prototype,"inputMode",void 0),o([ge({type:Boolean})],Yo.prototype,"readOnly",void 0),o([ge({type:String})],Yo.prototype,"autocapitalize",void 0),o([me()],Yo.prototype,"outlineOpen",void 0),o([me()],Yo.prototype,"outlineWidth",void 0),o([me()],Yo.prototype,"isUiValid",void 0),o([me()],Yo.prototype,"focused",void 0),o([be({passive:!0})],Yo.prototype,"handleInputChange",null); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const Xo=c`.mdc-floating-label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);position:absolute;left:0;-webkit-transform-origin:left top;transform-origin:left top;line-height:1.15rem;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:text;overflow:hidden;will-change:transform;transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-floating-label,.mdc-floating-label[dir=rtl]{right:0;left:auto;-webkit-transform-origin:right top;transform-origin:right top;text-align:right}.mdc-floating-label--float-above{cursor:auto}.mdc-floating-label--required::after{margin-left:1px;margin-right:0px;content:"*"}[dir=rtl] .mdc-floating-label--required::after,.mdc-floating-label--required[dir=rtl]::after{margin-left:0;margin-right:1px}.mdc-floating-label--float-above{transform:translateY(-106%) scale(0.75)}.mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-standard 250ms 1}@keyframes mdc-floating-label-shake-float-above-standard{0%{transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75)}100%{transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}}.mdc-line-ripple::before,.mdc-line-ripple::after{position:absolute;bottom:0;left:0;width:100%;border-bottom-style:solid;content:""}.mdc-line-ripple::before{border-bottom-width:1px}.mdc-line-ripple::before{z-index:1}.mdc-line-ripple::after{transform:scaleX(0);border-bottom-width:2px;opacity:0;z-index:2}.mdc-line-ripple::after{transition:transform 180ms cubic-bezier(0.4, 0, 0.2, 1),opacity 180ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-line-ripple--active::after{transform:scaleX(1);opacity:1}.mdc-line-ripple--deactivating::after{opacity:0}.mdc-notched-outline{display:flex;position:absolute;top:0;right:0;left:0;box-sizing:border-box;width:100%;max-width:100%;height:100%;text-align:left;pointer-events:none}[dir=rtl] .mdc-notched-outline,.mdc-notched-outline[dir=rtl]{text-align:right}.mdc-notched-outline__leading,.mdc-notched-outline__notch,.mdc-notched-outline__trailing{box-sizing:border-box;height:100%;border-top:1px solid;border-bottom:1px solid;pointer-events:none}.mdc-notched-outline__leading{border-left:1px solid;border-right:none;width:12px}[dir=rtl] .mdc-notched-outline__leading,.mdc-notched-outline__leading[dir=rtl]{border-left:none;border-right:1px solid}.mdc-notched-outline__trailing{border-left:none;border-right:1px solid;flex-grow:1}[dir=rtl] .mdc-notched-outline__trailing,.mdc-notched-outline__trailing[dir=rtl]{border-left:1px solid;border-right:none}.mdc-notched-outline__notch{flex:0 0 auto;width:auto;max-width:calc(100% - 12px * 2)}.mdc-notched-outline .mdc-floating-label{display:inline-block;position:relative;max-width:100%}.mdc-notched-outline .mdc-floating-label--float-above{text-overflow:clip}.mdc-notched-outline--upgraded .mdc-floating-label--float-above{max-width:calc(100% / 0.75)}.mdc-notched-outline--notched .mdc-notched-outline__notch{padding-left:0;padding-right:8px;border-top:none}[dir=rtl] .mdc-notched-outline--notched .mdc-notched-outline__notch,.mdc-notched-outline--notched .mdc-notched-outline__notch[dir=rtl]{padding-left:8px;padding-right:0}.mdc-notched-outline--no-label .mdc-notched-outline__notch{display:none}@keyframes mdc-ripple-fg-radius-in{from{animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-opacity-in{from{animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-out{from{animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}.mdc-text-field--filled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-text-field--filled .mdc-text-field__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-text-field--filled .mdc-text-field__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::before{transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{top:0;left:0;transform:scale(0);transform-origin:center center}.mdc-text-field--filled.mdc-ripple-upgraded--unbounded .mdc-text-field__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-activation .mdc-text-field__ripple::after{animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-deactivation .mdc-text-field__ripple::after{animation:mdc-ripple-fg-opacity-out 150ms;transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-text-field__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-text-field{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:0;border-bottom-left-radius:0;display:inline-flex;align-items:baseline;padding:0 16px;position:relative;box-sizing:border-box;overflow:hidden;will-change:opacity,transform,color}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input{color:rgba(0, 0, 0, 0.87)}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::placeholder{color:rgba(0, 0, 0, 0.54)}}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.54)}}.mdc-text-field .mdc-text-field__input{caret-color:#6200ee;caret-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field-character-counter,.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--leading{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--prefix{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix{color:rgba(0, 0, 0, 0.6)}.mdc-text-field .mdc-floating-label{top:50%;transform:translateY(-50%);pointer-events:none}.mdc-text-field__input{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);width:100%;min-width:0;border:none;border-radius:0;background:none;appearance:none;padding:0}.mdc-text-field__input::-ms-clear{display:none}.mdc-text-field__input::-webkit-calendar-picker-indicator{display:none}.mdc-text-field__input:focus{outline:none}.mdc-text-field__input:invalid{box-shadow:none}@media all{.mdc-text-field__input::placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field__input:-ms-input-placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field--no-label .mdc-text-field__input::placeholder,.mdc-text-field--focused .mdc-text-field__input::placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}@media all{.mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}.mdc-text-field__affix{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0;white-space:nowrap}.mdc-text-field--label-floating .mdc-text-field__affix,.mdc-text-field--no-label .mdc-text-field__affix{opacity:1}@supports(-webkit-hyphens: none){.mdc-text-field--outlined .mdc-text-field__affix{align-items:center;align-self:center;display:inline-flex;height:100%}}.mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field__affix--prefix,.mdc-text-field__affix--prefix[dir=rtl]{padding-left:2px;padding-right:0}.mdc-text-field--end-aligned .mdc-text-field__affix--prefix{padding-left:0;padding-right:12px}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--end-aligned .mdc-text-field__affix--prefix[dir=rtl]{padding-left:12px;padding-right:0}.mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field__affix--suffix,.mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:12px}.mdc-text-field--end-aligned .mdc-text-field__affix--suffix{padding-left:2px;padding-right:0}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--end-aligned .mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:2px}.mdc-text-field--filled{height:56px}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{background-color:rgba(0, 0, 0, 0.87);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.87))}.mdc-text-field--filled:hover .mdc-text-field__ripple::before,.mdc-text-field--filled.mdc-ripple-surface--hover .mdc-text-field__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-text-field--filled.mdc-ripple-upgraded--background-focused .mdc-text-field__ripple::before,.mdc-text-field--filled:not(.mdc-ripple-upgraded):focus .mdc-text-field__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-text-field--filled::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-text-field--filled:not(.mdc-text-field--disabled){background-color:whitesmoke}.mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.42)}.mdc-text-field--filled:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.87)}.mdc-text-field--filled .mdc-line-ripple::after{border-bottom-color:#6200ee;border-bottom-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--filled .mdc-floating-label{left:16px;right:initial}[dir=rtl] .mdc-text-field--filled .mdc-floating-label,.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:16px}.mdc-text-field--filled .mdc-floating-label--float-above{transform:translateY(-106%) scale(0.75)}.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input{height:100%}.mdc-text-field--filled.mdc-text-field--no-label .mdc-floating-label{display:none}.mdc-text-field--filled.mdc-text-field--no-label::before{display:none}@supports(-webkit-hyphens: none){.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__affix{align-items:center;align-self:center;display:inline-flex;height:100%}}.mdc-text-field--outlined{height:56px;overflow:visible}.mdc-text-field--outlined .mdc-floating-label--float-above{transform:translateY(-37.25px) scale(1)}.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{transform:translateY(-34.75px) scale(0.75)}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--outlined .mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-text-field-outlined 250ms 1}@keyframes mdc-floating-label-shake-float-above-text-field-outlined{0%{transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--outlined .mdc-text-field__input{height:100%}.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.38)}.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.87)}.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}@supports(top: max(0%)){.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading{width:max(12px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch{max-width:calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2)}}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}@supports(top: max(0%)){.mdc-text-field--outlined{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined{padding-right:max(16px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined+.mdc-text-field-helper-line{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined+.mdc-text-field-helper-line{padding-right:max(16px, var(--mdc-shape-small, 4px))}}.mdc-text-field--outlined.mdc-text-field--with-leading-icon{padding-left:0}@supports(top: max(0%)){.mdc-text-field--outlined.mdc-text-field--with-leading-icon{padding-right:max(16px, var(--mdc-shape-small, 4px))}}[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon,.mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl]{padding-right:0}@supports(top: max(0%)){[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon,.mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl]{padding-left:max(16px, var(--mdc-shape-small, 4px))}}.mdc-text-field--outlined.mdc-text-field--with-trailing-icon{padding-right:0}@supports(top: max(0%)){.mdc-text-field--outlined.mdc-text-field--with-trailing-icon{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon,.mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0}@supports(top: max(0%)){[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon,.mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl]{padding-right:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}.mdc-text-field--outlined.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon{padding-left:0;padding-right:0}.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:1px}.mdc-text-field--outlined .mdc-text-field__ripple::before,.mdc-text-field--outlined .mdc-text-field__ripple::after{background-color:transparent;background-color:var(--mdc-ripple-color, transparent)}.mdc-text-field--outlined .mdc-floating-label{left:4px;right:initial}[dir=rtl] .mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-text-field--outlined .mdc-text-field__input{display:flex;border:none !important;background-color:transparent}.mdc-text-field--outlined .mdc-notched-outline{z-index:1}.mdc-text-field--textarea{flex-direction:column;align-items:center;width:auto;height:auto;padding:0;transition:none}.mdc-text-field--textarea .mdc-floating-label{top:19px}.mdc-text-field--textarea .mdc-floating-label:not(.mdc-floating-label--float-above){transform:none}.mdc-text-field--textarea .mdc-text-field__input{flex-grow:1;height:auto;min-height:1.5rem;overflow-x:hidden;overflow-y:auto;box-sizing:border-box;resize:none;padding:0 16px;line-height:1.5rem}.mdc-text-field--textarea.mdc-text-field--filled::before{display:none}.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--float-above{transform:translateY(-10.25px) scale(0.75)}.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-textarea-filled 250ms 1}@keyframes mdc-floating-label-shake-float-above-textarea-filled{0%{transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75)}100%{transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}}.mdc-text-field--textarea.mdc-text-field--filled .mdc-text-field__input{margin-top:23px;margin-bottom:9px}.mdc-text-field--textarea.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input{margin-top:16px;margin-bottom:16px}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:0}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above{transform:translateY(-27.25px) scale(1)}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{transform:translateY(-24.75px) scale(0.75)}.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-textarea-outlined 250ms 1}@keyframes mdc-floating-label-shake-float-above-textarea-outlined{0%{transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75)}100%{transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-text-field__input{margin-top:16px;margin-bottom:16px}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label{top:18px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field__input{margin-bottom:2px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter{align-self:flex-end;padding:0 16px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::after{display:inline-block;width:0;height:16px;content:"";vertical-align:-16px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::before{display:none}.mdc-text-field__resizer{align-self:stretch;display:inline-flex;flex-direction:column;flex-grow:1;max-height:100%;max-width:100%;min-height:56px;min-width:fit-content;min-width:-moz-available;min-width:-webkit-fill-available;overflow:hidden;resize:both}.mdc-text-field--filled .mdc-text-field__resizer{transform:translateY(-1px)}.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field__input,.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field-character-counter{transform:translateY(1px)}.mdc-text-field--outlined .mdc-text-field__resizer{transform:translateX(-1px) translateY(-1px)}[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer,.mdc-text-field--outlined .mdc-text-field__resizer[dir=rtl]{transform:translateX(1px) translateY(-1px)}.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input,.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter{transform:translateX(1px) translateY(1px)}[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input,[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter,.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input[dir=rtl],.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter[dir=rtl]{transform:translateX(-1px) translateY(1px)}.mdc-text-field--with-leading-icon{padding-left:0;padding-right:16px}[dir=rtl] .mdc-text-field--with-leading-icon,.mdc-text-field--with-leading-icon[dir=rtl]{padding-left:16px;padding-right:0}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 48px);left:48px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:48px}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label{left:36px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:36px}.mdc-text-field--with-leading-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{transform:translateY(-37.25px) translateX(-32px) scale(1)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above[dir=rtl]{transform:translateY(-37.25px) translateX(32px) scale(1)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{transform:translateY(-34.75px) translateX(-32px) scale(0.75)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl],.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl]{transform:translateY(-34.75px) translateX(32px) scale(0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon{0%{transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake,.mdc-text-field--with-leading-icon.mdc-text-field--outlined[dir=rtl] .mdc-floating-label--shake{animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl{0%{transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--with-trailing-icon{padding-left:16px;padding-right:0}[dir=rtl] .mdc-text-field--with-trailing-icon,.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 64px)}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-trailing-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon{padding-left:0;padding-right:0}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 96px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 96px / 0.75)}.mdc-text-field-helper-line{display:flex;justify-content:space-between;box-sizing:border-box}.mdc-text-field+.mdc-text-field-helper-line{padding-right:16px;padding-left:16px}.mdc-form-field>.mdc-text-field+label{align-self:flex-start}.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(98, 0, 238, 0.87)}.mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--focused .mdc-notched-outline__trailing{border-width:2px}.mdc-text-field--focused+.mdc-text-field-helper-line .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg){opacity:1}.mdc-text-field--focused.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:2px}.mdc-text-field--focused.mdc-text-field--outlined.mdc-text-field--textarea .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:0}.mdc-text-field--invalid:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::after{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid .mdc-text-field__input{caret-color:#b00020;caret-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{opacity:1}.mdc-text-field--disabled{pointer-events:none}.mdc-text-field--disabled .mdc-text-field__input{color:rgba(0, 0, 0, 0.38)}@media all{.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:rgba(0, 0, 0, 0.38)}}@media all{.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.38)}}.mdc-text-field--disabled .mdc-floating-label{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__icon--leading{color:rgba(0, 0, 0, 0.3)}.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:rgba(0, 0, 0, 0.3)}.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.06)}.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.06)}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-floating-label{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--leading{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:GrayText}}@media screen and (forced-colors: active){.mdc-text-field--disabled .mdc-text-field__input{background-color:Window}.mdc-text-field--disabled .mdc-floating-label{z-index:1}}.mdc-text-field--disabled .mdc-floating-label{cursor:default}.mdc-text-field--disabled.mdc-text-field--filled{background-color:#fafafa}.mdc-text-field--disabled.mdc-text-field--filled .mdc-text-field__ripple{display:none}.mdc-text-field--disabled .mdc-text-field__input{pointer-events:auto}.mdc-text-field--end-aligned .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--end-aligned .mdc-text-field__input[dir=rtl]{text-align:left}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix{direction:ltr}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--leading,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--leading{order:1}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{order:2}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input{order:3}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{order:4}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--trailing,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--trailing{order:5}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--prefix{padding-right:12px}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--suffix{padding-left:2px}.mdc-text-field-helper-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;opacity:0;will-change:opacity;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-text-field-helper-text::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}.mdc-text-field-helper-text--persistent{transition:none;opacity:1;will-change:initial}.mdc-text-field-character-counter{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-left:auto;margin-right:0;padding-left:16px;padding-right:0;white-space:nowrap}.mdc-text-field-character-counter::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{margin-left:0;margin-right:auto}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field__icon{align-self:center;cursor:pointer}.mdc-text-field__icon:not([tabindex]),.mdc-text-field__icon[tabindex="-1"]{cursor:default;pointer-events:none}.mdc-text-field__icon svg{display:block}.mdc-text-field__icon--leading{margin-left:16px;margin-right:8px}[dir=rtl] .mdc-text-field__icon--leading,.mdc-text-field__icon--leading[dir=rtl]{margin-left:8px;margin-right:16px}.mdc-text-field__icon--trailing{padding:12px;margin-left:0px;margin-right:0px}[dir=rtl] .mdc-text-field__icon--trailing,.mdc-text-field__icon--trailing[dir=rtl]{margin-left:0px;margin-right:0px}.material-icons{font-family:var(--mdc-icon-font, "Material Icons");font-weight:normal;font-style:normal;font-size:var(--mdc-icon-size, 24px);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:"liga"}:host{display:inline-flex;flex-direction:column;outline:none}.mdc-text-field{width:100%}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.42);border-bottom-color:var(--mdc-text-field-idle-line-color, rgba(0, 0, 0, 0.42))}.mdc-text-field:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.87);border-bottom-color:var(--mdc-text-field-hover-line-color, rgba(0, 0, 0, 0.87))}.mdc-text-field.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.06);border-bottom-color:var(--mdc-text-field-disabled-line-color, rgba(0, 0, 0, 0.06))}.mdc-text-field.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field__input{direction:inherit}mwc-notched-outline{--mdc-notched-outline-border-color: var( --mdc-text-field-outlined-idle-border-color, rgba(0, 0, 0, 0.38) )}:host(:not([disabled]):hover) :not(.mdc-text-field--invalid):not(.mdc-text-field--focused) mwc-notched-outline{--mdc-notched-outline-border-color: var( --mdc-text-field-outlined-hover-border-color, rgba(0, 0, 0, 0.87) )}:host(:not([disabled])) .mdc-text-field:not(.mdc-text-field--outlined){background-color:var(--mdc-text-field-fill-color, whitesmoke)}:host(:not([disabled])) .mdc-text-field.mdc-text-field--invalid mwc-notched-outline{--mdc-notched-outline-border-color: var( --mdc-text-field-error-color, var(--mdc-theme-error, #b00020) )}:host(:not([disabled])) .mdc-text-field.mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-character-counter,:host(:not([disabled])) .mdc-text-field.mdc-text-field--invalid .mdc-text-field__icon{color:var(--mdc-text-field-error-color, var(--mdc-theme-error, #b00020))}:host(:not([disabled])) .mdc-text-field:not(.mdc-text-field--invalid):not(.mdc-text-field--focused) .mdc-floating-label,:host(:not([disabled])) .mdc-text-field:not(.mdc-text-field--invalid):not(.mdc-text-field--focused) .mdc-floating-label::after{color:var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6))}:host(:not([disabled])) .mdc-text-field.mdc-text-field--focused mwc-notched-outline{--mdc-notched-outline-stroke-width: 2px}:host(:not([disabled])) .mdc-text-field.mdc-text-field--focused:not(.mdc-text-field--invalid) mwc-notched-outline{--mdc-notched-outline-border-color: var( --mdc-text-field-focused-label-color, var(--mdc-theme-primary, rgba(98, 0, 238, 0.87)) )}:host(:not([disabled])) .mdc-text-field.mdc-text-field--focused:not(.mdc-text-field--invalid) .mdc-floating-label{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}:host(:not([disabled])) .mdc-text-field .mdc-text-field__input{color:var(--mdc-text-field-ink-color, rgba(0, 0, 0, 0.87))}:host(:not([disabled])) .mdc-text-field .mdc-text-field__input::placeholder{color:var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6))}:host(:not([disabled])) .mdc-text-field-helper-line .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg),:host(:not([disabled])) .mdc-text-field-helper-line:not(.mdc-text-field--invalid) .mdc-text-field-character-counter{color:var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6))}:host([disabled]) .mdc-text-field:not(.mdc-text-field--outlined){background-color:var(--mdc-text-field-disabled-fill-color, #fafafa)}:host([disabled]) .mdc-text-field.mdc-text-field--outlined mwc-notched-outline{--mdc-notched-outline-border-color: var( --mdc-text-field-outlined-disabled-border-color, rgba(0, 0, 0, 0.06) )}:host([disabled]) .mdc-text-field:not(.mdc-text-field--invalid):not(.mdc-text-field--focused) .mdc-floating-label,:host([disabled]) .mdc-text-field:not(.mdc-text-field--invalid):not(.mdc-text-field--focused) .mdc-floating-label::after{color:var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38))}:host([disabled]) .mdc-text-field .mdc-text-field__input,:host([disabled]) .mdc-text-field .mdc-text-field__input::placeholder{color:var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38))}:host([disabled]) .mdc-text-field-helper-line .mdc-text-field-helper-text,:host([disabled]) .mdc-text-field-helper-line .mdc-text-field-character-counter{color:var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.38))}` +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let $o=class extends Yo{};$o.styles=[Xo],$o=o([ue("mwc-textfield")],$o); +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +var ei,ti,ri={ANCHOR:"mdc-menu-surface--anchor",ANIMATING_CLOSED:"mdc-menu-surface--animating-closed",ANIMATING_OPEN:"mdc-menu-surface--animating-open",FIXED:"mdc-menu-surface--fixed",IS_OPEN_BELOW:"mdc-menu-surface--is-open-below",OPEN:"mdc-menu-surface--open",ROOT:"mdc-menu-surface"},oi={CLOSED_EVENT:"MDCMenuSurface:closed",CLOSING_EVENT:"MDCMenuSurface:closing",OPENED_EVENT:"MDCMenuSurface:opened",OPENING_EVENT:"MDCMenuSurface:opening",FOCUSABLE_ELEMENTS:'button:not(:disabled), [href]:not([aria-disabled="true"]), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"]):not([aria-disabled="true"])'},ii={TRANSITION_OPEN_DURATION:120,TRANSITION_CLOSE_DURATION:75,MARGIN_TO_EDGE:32,ANCHOR_TO_MENU_SURFACE_WIDTH_RATIO:.67,TOUCH_EVENT_WAIT_MS:30};!function(e){e[e.BOTTOM=1]="BOTTOM",e[e.CENTER=2]="CENTER",e[e.RIGHT=4]="RIGHT",e[e.FLIP_RTL=8]="FLIP_RTL"}(ei||(ei={})),function(e){e[e.TOP_LEFT=0]="TOP_LEFT",e[e.TOP_RIGHT=4]="TOP_RIGHT",e[e.BOTTOM_LEFT=1]="BOTTOM_LEFT",e[e.BOTTOM_RIGHT=5]="BOTTOM_RIGHT",e[e.TOP_START=8]="TOP_START",e[e.TOP_END=12]="TOP_END",e[e.BOTTOM_START=9]="BOTTOM_START",e[e.BOTTOM_END=13]="BOTTOM_END"}(ti||(ti={})); +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +var ni=function(e){function o(t){var i=e.call(this,r(r({},o.defaultAdapter),t))||this;return i.isSurfaceOpen=!1,i.isQuickOpen=!1,i.isHoistedElement=!1,i.isFixedPosition=!1,i.isHorizontallyCenteredOnViewport=!1,i.maxHeight=0,i.openBottomBias=0,i.openAnimationEndTimerId=0,i.closeAnimationEndTimerId=0,i.animationRequestId=0,i.anchorCorner=ti.TOP_START,i.originCorner=ti.TOP_START,i.anchorMargin={top:0,right:0,bottom:0,left:0},i.position={x:0,y:0},i}return t(o,e),Object.defineProperty(o,"cssClasses",{get:function(){return ri},enumerable:!1,configurable:!0}),Object.defineProperty(o,"strings",{get:function(){return oi},enumerable:!1,configurable:!0}),Object.defineProperty(o,"numbers",{get:function(){return ii},enumerable:!1,configurable:!0}),Object.defineProperty(o,"Corner",{get:function(){return ti},enumerable:!1,configurable:!0}),Object.defineProperty(o,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},hasClass:function(){return!1},hasAnchor:function(){return!1},isElementInContainer:function(){return!1},isFocused:function(){return!1},isRtl:function(){return!1},getInnerDimensions:function(){return{height:0,width:0}},getAnchorDimensions:function(){return null},getWindowDimensions:function(){return{height:0,width:0}},getBodyDimensions:function(){return{height:0,width:0}},getWindowScroll:function(){return{x:0,y:0}},setPosition:function(){},setMaxHeight:function(){},setTransformOrigin:function(){},saveFocus:function(){},restoreFocus:function(){},notifyClose:function(){},notifyClosing:function(){},notifyOpen:function(){},notifyOpening:function(){}}},enumerable:!1,configurable:!0}),o.prototype.init=function(){var e=o.cssClasses,t=e.ROOT,r=e.OPEN;if(!this.adapter.hasClass(t))throw Error(t+" class required in root element.");this.adapter.hasClass(r)&&(this.isSurfaceOpen=!0)},o.prototype.destroy=function(){clearTimeout(this.openAnimationEndTimerId),clearTimeout(this.closeAnimationEndTimerId),cancelAnimationFrame(this.animationRequestId)},o.prototype.setAnchorCorner=function(e){this.anchorCorner=e},o.prototype.flipCornerHorizontally=function(){this.originCorner=this.originCorner^ei.RIGHT},o.prototype.setAnchorMargin=function(e){this.anchorMargin.top=e.top||0,this.anchorMargin.right=e.right||0,this.anchorMargin.bottom=e.bottom||0,this.anchorMargin.left=e.left||0},o.prototype.setIsHoisted=function(e){this.isHoistedElement=e},o.prototype.setFixedPosition=function(e){this.isFixedPosition=e},o.prototype.isFixed=function(){return this.isFixedPosition},o.prototype.setAbsolutePosition=function(e,t){this.position.x=this.isFinite(e)?e:0,this.position.y=this.isFinite(t)?t:0},o.prototype.setIsHorizontallyCenteredOnViewport=function(e){this.isHorizontallyCenteredOnViewport=e},o.prototype.setQuickOpen=function(e){this.isQuickOpen=e},o.prototype.setMaxHeight=function(e){this.maxHeight=e},o.prototype.setOpenBottomBias=function(e){this.openBottomBias=e},o.prototype.isOpen=function(){return this.isSurfaceOpen},o.prototype.open=function(){var e=this;this.isSurfaceOpen||(this.adapter.notifyOpening(),this.adapter.saveFocus(),this.isQuickOpen?(this.isSurfaceOpen=!0,this.adapter.addClass(o.cssClasses.OPEN),this.dimensions=this.adapter.getInnerDimensions(),this.autoposition(),this.adapter.notifyOpen()):(this.adapter.addClass(o.cssClasses.ANIMATING_OPEN),this.animationRequestId=requestAnimationFrame((function(){e.dimensions=e.adapter.getInnerDimensions(),e.autoposition(),e.adapter.addClass(o.cssClasses.OPEN),e.openAnimationEndTimerId=setTimeout((function(){e.openAnimationEndTimerId=0,e.adapter.removeClass(o.cssClasses.ANIMATING_OPEN),e.adapter.notifyOpen()}),ii.TRANSITION_OPEN_DURATION)})),this.isSurfaceOpen=!0))},o.prototype.close=function(e){var t=this;if(void 0===e&&(e=!1),this.isSurfaceOpen){if(this.adapter.notifyClosing(),this.isQuickOpen)return this.isSurfaceOpen=!1,e||this.maybeRestoreFocus(),this.adapter.removeClass(o.cssClasses.OPEN),this.adapter.removeClass(o.cssClasses.IS_OPEN_BELOW),void this.adapter.notifyClose();this.adapter.addClass(o.cssClasses.ANIMATING_CLOSED),requestAnimationFrame((function(){t.adapter.removeClass(o.cssClasses.OPEN),t.adapter.removeClass(o.cssClasses.IS_OPEN_BELOW),t.closeAnimationEndTimerId=setTimeout((function(){t.closeAnimationEndTimerId=0,t.adapter.removeClass(o.cssClasses.ANIMATING_CLOSED),t.adapter.notifyClose()}),ii.TRANSITION_CLOSE_DURATION)})),this.isSurfaceOpen=!1,e||this.maybeRestoreFocus()}},o.prototype.handleBodyClick=function(e){var t=e.target;this.adapter.isElementInContainer(t)||this.close()},o.prototype.handleKeydown=function(e){var t=e.keyCode;("Escape"===e.key||27===t)&&this.close()},o.prototype.autoposition=function(){var e;this.measurements=this.getAutoLayoutmeasurements();var t=this.getoriginCorner(),r=this.getMenuSurfaceMaxHeight(t),i=this.hasBit(t,ei.BOTTOM)?"bottom":"top",n=this.hasBit(t,ei.RIGHT)?"right":"left",a=this.getHorizontalOriginOffset(t),l=this.getVerticalOriginOffset(t),s=this.measurements,d=s.anchorSize,c=s.surfaceSize,u=((e={})[n]=a,e[i]=l,e);d.width/c.width>ii.ANCHOR_TO_MENU_SURFACE_WIDTH_RATIO&&(n="center"),(this.isHoistedElement||this.isFixedPosition)&&this.adjustPositionForHoistedElement(u),this.adapter.setTransformOrigin(n+" "+i),this.adapter.setPosition(u),this.adapter.setMaxHeight(r?r+"px":""),this.hasBit(t,ei.BOTTOM)||this.adapter.addClass(o.cssClasses.IS_OPEN_BELOW)},o.prototype.getAutoLayoutmeasurements=function(){var e=this.adapter.getAnchorDimensions(),t=this.adapter.getBodyDimensions(),r=this.adapter.getWindowDimensions(),o=this.adapter.getWindowScroll();return e||(e={top:this.position.y,right:this.position.x,bottom:this.position.y,left:this.position.x,width:0,height:0}),{anchorSize:e,bodySize:t,surfaceSize:this.dimensions,viewportDistance:{top:e.top,right:r.width-e.right,bottom:r.height-e.bottom,left:e.left},viewportSize:r,windowScroll:o}},o.prototype.getoriginCorner=function(){var e,t,r=this.originCorner,i=this.measurements,n=i.viewportDistance,a=i.anchorSize,l=i.surfaceSize,s=o.numbers.MARGIN_TO_EDGE;this.hasBit(this.anchorCorner,ei.BOTTOM)?(e=n.top-s+this.anchorMargin.bottom,t=n.bottom-s-this.anchorMargin.bottom):(e=n.top-s+this.anchorMargin.top,t=n.bottom-s+a.height-this.anchorMargin.top),!(t-l.height>0)&&e>t+this.openBottomBias&&(r=this.setBit(r,ei.BOTTOM));var d,c,u,p=this.adapter.isRtl(),h=this.hasBit(this.anchorCorner,ei.FLIP_RTL),g=this.hasBit(this.anchorCorner,ei.RIGHT)||this.hasBit(r,ei.RIGHT);(u=p&&h?!g:g)?(d=n.left+a.width+this.anchorMargin.right,c=n.right-this.anchorMargin.right):(d=n.left+this.anchorMargin.left,c=n.right+a.width-this.anchorMargin.left);var m=d-l.width>0,f=c-l.width>0,b=this.hasBit(r,ei.FLIP_RTL)&&this.hasBit(r,ei.RIGHT);return f&&b&&p||!m&&b?r=this.unsetBit(r,ei.RIGHT):(m&&u&&p||m&&!u&&g||!f&&d>=c)&&(r=this.setBit(r,ei.RIGHT)),r},o.prototype.getMenuSurfaceMaxHeight=function(e){if(this.maxHeight>0)return this.maxHeight;var t=this.measurements.viewportDistance,r=0,i=this.hasBit(e,ei.BOTTOM),n=this.hasBit(this.anchorCorner,ei.BOTTOM),a=o.numbers.MARGIN_TO_EDGE;return i?(r=t.top+this.anchorMargin.top-a,n||(r+=this.measurements.anchorSize.height)):(r=t.bottom-this.anchorMargin.bottom+this.measurements.anchorSize.height-a,n&&(r-=this.measurements.anchorSize.height)),r},o.prototype.getHorizontalOriginOffset=function(e){var t=this.measurements.anchorSize,r=this.hasBit(e,ei.RIGHT),o=this.hasBit(this.anchorCorner,ei.RIGHT);if(r){var i=o?t.width-this.anchorMargin.left:this.anchorMargin.right;return this.isHoistedElement||this.isFixedPosition?i-(this.measurements.viewportSize.width-this.measurements.bodySize.width):i}return o?t.width-this.anchorMargin.right:this.anchorMargin.left},o.prototype.getVerticalOriginOffset=function(e){var t=this.measurements.anchorSize,r=this.hasBit(e,ei.BOTTOM),o=this.hasBit(this.anchorCorner,ei.BOTTOM);return r?o?t.height-this.anchorMargin.top:-this.anchorMargin.bottom:o?t.height+this.anchorMargin.bottom:this.anchorMargin.top},o.prototype.adjustPositionForHoistedElement=function(e){var t,r,o=this.measurements,n=o.windowScroll,a=o.viewportDistance,l=o.surfaceSize,s=o.viewportSize,d=Object.keys(e);try{for(var c=i(d),u=c.next();!u.done;u=c.next()){var p=u.value,h=e[p]||0;!this.isHorizontallyCenteredOnViewport||"left"!==p&&"right"!==p?(h+=a[p],this.isFixedPosition||("top"===p?h+=n.y:"bottom"===p?h-=n.y:"left"===p?h+=n.x:h-=n.x),e[p]=h):e[p]=(s.width-l.width)/2}}catch(e){t={error:e}}finally{try{u&&!u.done&&(r=c.return)&&r.call(c)}finally{if(t)throw t.error}}},o.prototype.maybeRestoreFocus=function(){var e=this,t=this.adapter.isFocused(),r=this.adapter.getOwnerDocument?this.adapter.getOwnerDocument():document,o=r.activeElement&&this.adapter.isElementInContainer(r.activeElement);(t||o)&&setTimeout((function(){e.adapter.restoreFocus()}),ii.TOUCH_EVENT_WAIT_MS)},o.prototype.hasBit=function(e,t){return!!(e&t)},o.prototype.setBit=function(e,t){return e|t},o.prototype.unsetBit=function(e,t){return e^t},o.prototype.isFinite=function(e){return"number"==typeof e&&isFinite(e)},o}(tr),ai=ni; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +const li={TOP_LEFT:ti.TOP_LEFT,TOP_RIGHT:ti.TOP_RIGHT,BOTTOM_LEFT:ti.BOTTOM_LEFT,BOTTOM_RIGHT:ti.BOTTOM_RIGHT,TOP_START:ti.TOP_START,TOP_END:ti.TOP_END,BOTTOM_START:ti.BOTTOM_START,BOTTOM_END:ti.BOTTOM_END};class si extends er{constructor(){super(...arguments),this.mdcFoundationClass=ai,this.absolute=!1,this.fullwidth=!1,this.fixed=!1,this.x=null,this.y=null,this.quick=!1,this.open=!1,this.stayOpenOnBodyClick=!1,this.bitwiseCorner=ti.TOP_START,this.previousMenuCorner=null,this.menuCorner="START",this.corner="TOP_START",this.styleTop="",this.styleLeft="",this.styleRight="",this.styleBottom="",this.styleMaxHeight="",this.styleTransformOrigin="",this.anchor=null,this.previouslyFocused=null,this.previousAnchor=null,this.onBodyClickBound=()=>{}}render(){return this.renderSurface()}renderSurface(){const e=this.getRootClasses(),t=this.getRootStyles();return W` +
+ ${this.renderContent()} +
`}getRootClasses(){return{"mdc-menu-surface":!0,"mdc-menu-surface--fixed":this.fixed,"mdc-menu-surface--fullwidth":this.fullwidth}}getRootStyles(){return{top:this.styleTop,left:this.styleLeft,right:this.styleRight,bottom:this.styleBottom,"max-height":this.styleMaxHeight,"transform-origin":this.styleTransformOrigin}}renderContent(){return W``}createAdapter(){return Object.assign(Object.assign({},Jt(this.mdcRoot)),{hasAnchor:()=>!!this.anchor,notifyClose:()=>{const e=new CustomEvent("closed",{bubbles:!0,composed:!0});this.open=!1,this.mdcRoot.dispatchEvent(e)},notifyClosing:()=>{const e=new CustomEvent("closing",{bubbles:!0,composed:!0});this.mdcRoot.dispatchEvent(e)},notifyOpen:()=>{const e=new CustomEvent("opened",{bubbles:!0,composed:!0});this.open=!0,this.mdcRoot.dispatchEvent(e)},notifyOpening:()=>{const e=new CustomEvent("opening",{bubbles:!0,composed:!0});this.mdcRoot.dispatchEvent(e)},isElementInContainer:()=>!1,isRtl:()=>!!this.mdcRoot&&"rtl"===getComputedStyle(this.mdcRoot).direction,setTransformOrigin:e=>{this.mdcRoot&&(this.styleTransformOrigin=e)},isFocused:()=>$t(this),saveFocus:()=>{const e=Xt(),t=e.length;t||(this.previouslyFocused=null),this.previouslyFocused=e[t-1]},restoreFocus:()=>{this.previouslyFocused&&"focus"in this.previouslyFocused&&this.previouslyFocused.focus()},getInnerDimensions:()=>{const e=this.mdcRoot;return e?{width:e.offsetWidth,height:e.offsetHeight}:{width:0,height:0}},getAnchorDimensions:()=>{const e=this.anchor;return e?e.getBoundingClientRect():null},getBodyDimensions:()=>({width:document.body.clientWidth,height:document.body.clientHeight}),getWindowDimensions:()=>({width:window.innerWidth,height:window.innerHeight}),getWindowScroll:()=>({x:window.pageXOffset,y:window.pageYOffset}),setPosition:e=>{this.mdcRoot&&(this.styleLeft="left"in e?e.left+"px":"",this.styleRight="right"in e?e.right+"px":"",this.styleTop="top"in e?e.top+"px":"",this.styleBottom="bottom"in e?e.bottom+"px":"")},setMaxHeight:async e=>{this.mdcRoot&&(this.styleMaxHeight=e,await this.updateComplete,this.styleMaxHeight=`var(--mdc-menu-max-height, ${e})`)}})}onKeydown(e){this.mdcFoundation&&this.mdcFoundation.handleKeydown(e)}onBodyClick(e){this.stayOpenOnBodyClick||-1===e.composedPath().indexOf(this)&&this.close()}registerBodyClick(){this.onBodyClickBound=this.onBodyClick.bind(this),document.body.addEventListener("click",this.onBodyClickBound,{passive:!0,capture:!0})}deregisterBodyClick(){document.body.removeEventListener("click",this.onBodyClickBound,{capture:!0})}onOpenChanged(e,t){this.mdcFoundation&&(e?this.mdcFoundation.open():void 0!==t&&this.mdcFoundation.close())}close(){this.open=!1}show(){this.open=!0}}o([ye(".mdc-menu-surface")],si.prototype,"mdcRoot",void 0),o([ye("slot")],si.prototype,"slotElement",void 0),o([ge({type:Boolean}),Tr((function(e){this.mdcFoundation&&!this.fixed&&this.mdcFoundation.setIsHoisted(e)}))],si.prototype,"absolute",void 0),o([ge({type:Boolean})],si.prototype,"fullwidth",void 0),o([ge({type:Boolean}),Tr((function(e){this.mdcFoundation&&!this.absolute&&this.mdcFoundation.setFixedPosition(e)}))],si.prototype,"fixed",void 0),o([ge({type:Number}),Tr((function(e){this.mdcFoundation&&null!==this.y&&null!==e&&(this.mdcFoundation.setAbsolutePosition(e,this.y),this.mdcFoundation.setAnchorMargin({left:e,top:this.y,right:-e,bottom:this.y}))}))],si.prototype,"x",void 0),o([ge({type:Number}),Tr((function(e){this.mdcFoundation&&null!==this.x&&null!==e&&(this.mdcFoundation.setAbsolutePosition(this.x,e),this.mdcFoundation.setAnchorMargin({left:this.x,top:e,right:-this.x,bottom:e}))}))],si.prototype,"y",void 0),o([ge({type:Boolean}),Tr((function(e){this.mdcFoundation&&this.mdcFoundation.setQuickOpen(e)}))],si.prototype,"quick",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e,t){this.onOpenChanged(e,t)}))],si.prototype,"open",void 0),o([ge({type:Boolean})],si.prototype,"stayOpenOnBodyClick",void 0),o([me(),Tr((function(e){this.mdcFoundation&&this.mdcFoundation.setAnchorCorner(e)}))],si.prototype,"bitwiseCorner",void 0),o([ge({type:String}),Tr((function(e){if(this.mdcFoundation){const t="START"===e||"END"===e,r=null===this.previousMenuCorner,o=!r&&e!==this.previousMenuCorner;t&&(o||r&&"END"===e)&&(this.bitwiseCorner=this.bitwiseCorner^ei.RIGHT,this.mdcFoundation.flipCornerHorizontally(),this.previousMenuCorner=e)}}))],si.prototype,"menuCorner",void 0),o([ge({type:String}),Tr((function(e){if(this.mdcFoundation&&e){let t=li[e];"END"===this.menuCorner&&(t^=ei.RIGHT),this.bitwiseCorner=t}}))],si.prototype,"corner",void 0),o([me()],si.prototype,"styleTop",void 0),o([me()],si.prototype,"styleLeft",void 0),o([me()],si.prototype,"styleRight",void 0),o([me()],si.prototype,"styleBottom",void 0),o([me()],si.prototype,"styleMaxHeight",void 0),o([me()],si.prototype,"styleTransformOrigin",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const di=c`.mdc-menu-surface{display:none;position:absolute;box-sizing:border-box;max-width:calc(100vw - 32px);max-width:var(--mdc-menu-max-width, calc(100vw - 32px));max-height:calc(100vh - 32px);max-height:var(--mdc-menu-max-height, calc(100vh - 32px));margin:0;padding:0;transform:scale(1);transform-origin:top left;opacity:0;overflow:auto;will-change:transform,opacity;z-index:8;transition:opacity .03s linear,transform .12s cubic-bezier(0, 0, 0.2, 1),height 250ms cubic-bezier(0, 0, 0.2, 1);box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12);background-color:#fff;background-color:var(--mdc-theme-surface, #fff);color:#000;color:var(--mdc-theme-on-surface, #000);border-radius:4px;border-radius:var(--mdc-shape-medium, 4px);transform-origin-left:top left;transform-origin-right:top right}.mdc-menu-surface:focus{outline:none}.mdc-menu-surface--animating-open{display:inline-block;transform:scale(0.8);opacity:0}.mdc-menu-surface--open{display:inline-block;transform:scale(1);opacity:1}.mdc-menu-surface--animating-closed{display:inline-block;opacity:0;transition:opacity .075s linear}[dir=rtl] .mdc-menu-surface,.mdc-menu-surface[dir=rtl]{transform-origin-left:top right;transform-origin-right:top left}.mdc-menu-surface--anchor{position:relative;overflow:visible}.mdc-menu-surface--fixed{position:fixed}.mdc-menu-surface--fullwidth{width:100%}:host(:not([open])){display:none}.mdc-menu-surface{z-index:8;z-index:var(--mdc-menu-z-index, 8);min-width:112px;min-width:var(--mdc-menu-min-width, 112px)}` +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let ci=class extends si{};ci.styles=[di],ci=o([ue("mwc-menu-surface")],ci); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +class ui extends de{set project(e){"string"==typeof e?requestAnimationFrame((()=>{var t;const r=this.getRootNode();this._project=null!==(t=r.getElementById(e))&&void 0!==t?t:void 0})):this._project=e}}o([ge()],ui.prototype,"project",null),o([me()],ui.prototype,"_project",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let pi=class extends ui{constructor(){super(...arguments),this.state="closed",this._postStateChangeRenderDone=!1}update(e){e.has("state")&&(this._postStateChangeRenderDone=!1),super.update(e)}render(){var e;return W`
${this._surfaceContents}
`}async updated(){if(!this._postStateChangeRenderDone){if("menu"===this.state){const e=this._menuList;e&&(await e.updateComplete,e.focusItemAtIndex(0))}else if("rename"===this.state||"newfile"===this.state){const e=this._filenameInput;e&&(await e.updateComplete,e.focus(),"rename"===this.state&&e.setSelectionRange(0,e.value.lastIndexOf(".")))}this._postStateChangeRenderDone=!0}}get _surfaceContents(){switch(this.state){case"closed":return j;case"menu":return this._menu;case"rename":return this._rename;case"newfile":return this._newFile}}get _menu(){return W` + + + Rename + + + + + + Delete + + + + + + `}get _rename(){return W` + +
+ Cancel + Rename +
+ `}get _newFile(){return W` + +
+ Cancel + Create +
+ `}_onSurfaceClosed(){this.state="closed"}_onClickCancel(){this._surface.close()}_onMenuAction(e){switch(e.detail.index){case 0:return this._onMenuSelectRename();case 1:return this._onMenuSelectDelete()}}_onMenuSelectRename(){this.state="rename"}_onMenuSelectDelete(){this._surface.close(),this._project&&this.filename&&this._project.deleteFile(this.filename)}_onFilenameInputChange(){this.requestUpdate()}get _filenameInputValid(){return!!(this._project&&this._filenameInput&&this._project.isValidNewFilename(this._filenameInput.value))}_onFilenameInputKeydown(e){var t;"Enter"===e.key&&!1===(null===(t=this._submitButton)||void 0===t?void 0:t.disabled)&&(e.preventDefault(),this._submitButton.click())}_onSubmitRename(){var e;this._surface.close();const t=this.filename,r=null===(e=this._filenameInput)||void 0===e?void 0:e.value;this._project&&t&&r&&this._project.renameFile(t,r)}_onSubmitNewFile(){var e;this._surface.close();const t=null===(e=this._filenameInput)||void 0===e?void 0:e.value;this._project&&t&&(this._project.addFile(t),this.dispatchEvent(new CustomEvent("newFile",{detail:{filename:t}})))}};pi.styles=c` + mwc-menu-surface { + --mdc-theme-primary: var( + --playground-floating-controls-color, + var(--playground-highlight-color, #6200ee) + ); + } + + mwc-menu-surface.menu { + --mdc-typography-subtitle1-font-size: 13px; + --mdc-list-item-graphic-margin: 14px; + } + + mwc-list-item { + min-width: 100px; + height: 40px; + } + + mwc-menu-surface.rename > .wrapper, + mwc-menu-surface.newfile > .wrapper { + padding: 18px; + } + + .actions { + margin-top: 18px; + display: flex; + justify-content: flex-end; + } + + .actions > * { + margin-left: 12px; + } + `,o([ge({attribute:!1})],pi.prototype,"anchorElement",void 0),o([ge()],pi.prototype,"state",void 0),o([ge()],pi.prototype,"filename",void 0),o([ye("mwc-menu-surface")],pi.prototype,"_surface",void 0),o([ye(".menu-list")],pi.prototype,"_menuList",void 0),o([ye(".filename-input")],pi.prototype,"_filenameInput",void 0),o([ye(".submit-button")],pi.prototype,"_submitButton",void 0),pi=o([ue("playground-file-system-controls")],pi); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let hi=class extends ui{constructor(){super(...arguments),this.editableFileSystem=!1,this._activeFileName="",this._activeFileIndex=0,this._onProjectFilesChanged=e=>{this._handleFilesChanged(e.projectLoaded)}}set editor(e){"string"==typeof e?requestAnimationFrame((()=>{var t;const r=this.getRootNode();this._editor=null!==(t=r.getElementById(e))&&void 0!==t?t:void 0})):this._editor=e}get _visibleFiles(){var e,t;return(null!==(t=null===(e=this._project)||void 0===e?void 0:e.files)&&void 0!==t?t:[]).filter((({hidden:e})=>!e))}update(e){if(e.has("_project")){const t=e.get("_project");t&&t.removeEventListener("filesChanged",this._onProjectFilesChanged),this._project&&(this._handleFilesChanged(!0),this._project.addEventListener("filesChanged",this._onProjectFilesChanged))}e.has("_activeFileName")&&this._editor&&(this._editor.filename=this._activeFileName,this._setNewActiveFile()),super.update(e)}render(){return W` + + ${this._visibleFiles.map((({name:e,label:t})=>W` + ${t||e} + ${this.editableFileSystem?W` + + + + + `:j} + `))} + + + ${this.editableFileSystem?W` + + + + + + + + + + `:j} + `}_handleFilesChanged(e=!1){var t;if(e){const e=null===(t=this._visibleFiles.find((e=>e.selected)))||void 0===t?void 0:t.name;void 0!==e&&(this._activeFileName=e)}this._setNewActiveFile(),this.requestUpdate()}_onTabchange(e){const t=e.detail.tab;if(!t)return;const r=t.dataset.filename,o=t.index;r!==this._activeFileName&&(this._activeFileName=r,this._activeFileIndex=o)}_onOpenMenu(e){const t=this._fileSystemControls;if(t){t.state="menu";for(const r of e.composedPath())if(r instanceof HTMLElement&&r.dataset.filename){t.filename=r.dataset.filename;break}t.anchorElement=e.target,e.stopPropagation()}}_onClickAddFile(e){const t=this._fileSystemControls;t&&(t.state="newfile",t.anchorElement=e.target)}_onNewFile(e){this._activeFileName=e.detail.filename}_setNewActiveFile(){if(this._activeFileName){const e=this._visibleFiles.findIndex((e=>e.name===this._activeFileName));if(e>=0)return void(this._activeFileIndex=e)}for(let e=this._activeFileIndex;e>=0;e--){const t=this._visibleFiles[e];if(t&&!t.hidden)return void(this._activeFileName=t.name)}this._activeFileIndex=0,this._activeFileName=""}}; +/* @license CodeMirror, copyright (c) by Marijn Haverbeke and others +Distributed under an MIT license: https://codemirror.net/LICENSE */ +var gi;function mi(e,t,r,o,i,n){this.name=e,this.tokenType=t,this.depth=r,this.parent=o,this.startLine=i,this.startPos=n}function fi(){this.stream=null,this.line=this.startPos=0,this.string=this.startLine="",this.copyInstance=null}hi.styles=c` + :host { + display: flex; + font-size: var(--playground-tab-bar-font-size, 14px); + height: var(--playground-bar-height, 40px); + background: var(--playground-tab-bar-background, #eaeaea); + align-items: center; + } + + 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); + } + + playground-internal-tab[active] { + color: var( + --playground-tab-bar-active-color, + var(--playground-highlight-color, #6200ee) + ); + background: var(--playground-tab-bar-active-background, transparent); + } + + :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 { + color: var(--playground-tab-bar-foreground-color); + } + + .add-file-button { + margin: 0 4px; + opacity: 70%; + --mdc-icon-button-size: 24px; + --mdc-icon-size: 24px; + } + + .add-file-button:hover { + opacity: 1; + } + `,o([ge({type:Boolean,attribute:"editable-file-system",reflect:!0})],hi.prototype,"editableFileSystem",void 0),o([me()],hi.prototype,"_activeFileName",void 0),o([me()],hi.prototype,"_activeFileIndex",void 0),o([ye("playground-file-system-controls")],hi.prototype,"_fileSystemControls",void 0),o([me()],hi.prototype,"_editor",void 0),o([ge()],hi.prototype,"editor",null),hi=o([ue("playground-tab-bar")],hi),gi=function(){var e=navigator.userAgent,t=navigator.platform,r=/gecko\/\d/i.test(e),o=/MSIE \d/.test(e),i=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),n=/Edge\/(\d+)/.exec(e),a=o||i||n,l=a&&(o?document.documentMode||6:+(n||i)[1]),s=!n&&/WebKit\//.test(e),d=s&&/Qt\/\d+\.\d+/.test(e),c=!n&&/Chrome\/(\d+)/.exec(e),u=c&&+c[1],p=/Opera\//.test(e),h=/Apple Computer/.test(navigator.vendor),g=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),m=/PhantomJS/.test(e),f=h&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),b=/Android/.test(e),y=f||b||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),v=f||/Mac/.test(t),x=/\bCrOS\b/.test(e),w=/win/i.test(t),k=p&&e.match(/Version\/(\d*\.\d*)/);k&&(k=Number(k[1])),k&&k>=15&&(p=!1,s=!0);var _=v&&(d||p&&(null==k||k<12.11)),C=r||a&&l>=9;function S(e){return RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var E,T=function(e,t){var r=e.className,o=S(t).exec(r);if(o){var i=r.slice(o.index+o[0].length);e.className=r.slice(0,o.index)+(i?o[1]+i:"")}};function A(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function O(e,t){return A(e).appendChild(t)}function L(e,t,r,o){var i=document.createElement(e);if(r&&(i.className=r),o&&(i.style.cssText=o),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var n=0;n=t)return a+(t-n);a+=l-n,a+=r-a%r,n=l+1}}f?z=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:a&&(z=function(e){try{e.select()}catch(e){}});var j=function(){this.id=null,this.f=null,this.time=0,this.handler=B(this.onTimeout,this)};function V(e,t){for(var r=0;r=t)return o+Math.min(a,t-i);if(i+=n-o,o=n+1,(i+=r-i%r)>=t)return o}}var X=[""];function $(e){for(;X.length<=e;)X.push(ee(X)+" ");return X[e]}function ee(e){return e[e.length-1]}function te(e,t){for(var r=[],o=0;o"€"&&(e.toUpperCase()!=e.toLowerCase()||ie.test(e))}function ae(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ne(e))||t.test(e):ne(e)}function le(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var se=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function de(e){return e.charCodeAt(0)>=768&&se.test(e)}function ce(e,t,r){for(;(r<0?t>0:tr?-1:1;;){if(t==r)return t;var i=(t+r)/2,n=o<0?Math.ceil(i):Math.floor(i);if(n==t)return e(n)?t:r;e(n)?r=n:t=n+o}}var pe=null;function he(e,t,r){var o;pe=null;for(var i=0;it)return i;n.to==t&&(n.from!=n.to&&"before"==r?o=i:pe=i),n.from==t&&(n.from!=n.to&&"before"!=r?o=i:pe=i)}return null!=o?o:pe}var ge=function(){var e=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,t=/[stwN]/,r=/[LRr]/,o=/[Lb1n]/,i=/[1n]/;function n(e,t,r){this.level=e,this.from=t,this.to=r}return function(a,l){var s="ltr"==l?"L":"R";if(0==a.length||"ltr"==l&&!e.test(a))return!1;for(var d,c=a.length,u=[],p=0;p-1&&(o[t]=i.slice(0,n).concat(i.slice(n+1)))}}}function xe(e,t){var r=ye(e,t);if(r.length)for(var o=Array.prototype.slice.call(arguments,2),i=0;i0}function Ce(e){e.prototype.on=function(e,t){be(this,e,t)},e.prototype.off=function(e,t){ve(this,e,t)}}function Se(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Ee(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function Te(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function Ae(e){Se(e),Ee(e)}function Oe(e){return e.target||e.srcElement}function Le(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),v&&e.ctrlKey&&1==t&&(t=3),t}var Me,Ie,Re=function(){if(a&&l<9)return!1;var e=L("div");return"draggable"in e||"dragDrop"in e}();function Fe(e){if(null==Me){var t=L("span","​");O(e,L("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Me=t.offsetWidth<=1&&t.offsetHeight>2&&!(a&&l<8))}var r=Me?L("span","​"):L("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return r.setAttribute("cm-text",""),r}function Ne(e){if(null!=Ie)return Ie;var t=O(e,document.createTextNode("AخA")),r=E(t,0,1).getBoundingClientRect(),o=E(t,1,2).getBoundingClientRect();return A(e),!(!r||r.left==r.right)&&(Ie=o.right-r.right<3)}var ze,De=function(e){return e.split(/\r\n?|\n/)},Pe=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},He="oncopy"in(ze=L("div"))||(ze.setAttribute("oncopy","return;"),"function"==typeof ze.oncopy),Ue=null,Be={},We={};function Ke(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Be[e]=t}function je(e){if("string"==typeof e&&We.hasOwnProperty(e))e=We[e];else if(e&&"string"==typeof e.name&&We.hasOwnProperty(e.name)){var t=We[e.name];"string"==typeof t&&(t={name:t}),(e=oe(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return je("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return je("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ve(e,t){t=je(t);var r=Be[t.name];if(!r)return Ve(e,"text/plain");var o=r(e,t);if(qe.hasOwnProperty(t.name)){var i=qe[t.name];for(var n in i)i.hasOwnProperty(n)&&(o.hasOwnProperty(n)&&(o["_"+n]=o[n]),o[n]=i[n])}if(o.name=t.name,t.helperType&&(o.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)o[a]=t.modeProps[a];return o}var qe={};function Ze(e,t){W(t,qe.hasOwnProperty(e)?qe[e]:qe[e]={})}function Ge(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var r={};for(var o in t){var i=t[o];i instanceof Array&&(i=i.concat([])),r[o]=i}return r}function Je(e,t){for(var r;e.innerMode&&(r=e.innerMode(t))&&r.mode!=e;)t=r.state,e=r.mode;return r||{mode:e,state:t}}function Qe(e,t,r){return!e.startState||e.startState(t,r)}var Ye=function(e,t,r){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=r};function Xe(e,t){if((t-=e.first)<0||t>=e.size)throw Error("There is no line "+(t+e.first)+" in the document.");for(var r=e;!r.lines;)for(var o=0;;++o){var i=r.children[o],n=i.chunkSize();if(t=e.first&&tr?at(r,Xe(e,r).text.length):function(e,t){var r=e.ch;return null==r||r>t?at(e.line,t):r<0?at(e.line,0):e}(t,Xe(e,t.line).text.length)}function gt(e,t){for(var r=[],o=0;o=this.string.length},Ye.prototype.sol=function(){return this.pos==this.lineStart},Ye.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Ye.prototype.next=function(){if(this.post},Ye.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Ye.prototype.skipToEnd=function(){this.pos=this.string.length},Ye.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Ye.prototype.backUp=function(e){this.pos-=e},Ye.prototype.column=function(){return this.lastColumnPos0?null:(o&&!1!==t&&(this.pos+=o[0].length),o)}var i=function(e){return r?e.toLowerCase():e};if(i(this.string.substr(this.pos,e.length))==i(e))return!1!==t&&(this.pos+=e.length),!0},Ye.prototype.current=function(){return this.string.slice(this.start,this.pos)},Ye.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Ye.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Ye.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var mt=function(e,t){this.state=e,this.lookAhead=t},ft=function(e,t,r,o){this.state=t,this.doc=e,this.line=r,this.maxLookAhead=o||0,this.baseTokens=null,this.baseTokenPos=1};function bt(e,t,r,o){var i=[e.state.modeGen],n={};Et(e,t.text,e.doc.mode,r,(function(e,t){return i.push(e,t)}),n,o);for(var a=r.state,l=function(o){r.baseTokens=i;var l=e.state.overlays[o],s=1,d=0;r.state=!0,Et(e,t.text,l.mode,r,(function(e,t){for(var r=s;de&&i.splice(s,1,e,i[s+1],o),s+=2,d=Math.min(e,o)}if(t)if(l.opaque)i.splice(r,s-r,e,"overlay "+t),s=r+2;else for(;re.options.maxHighlightLength&&Ge(e.doc.mode,o.state),n=bt(e,t,o);i&&(o.state=i),t.stateAfter=o.save(!i),t.styles=n.styles,n.classes?t.styleClasses=n.classes:t.styleClasses&&(t.styleClasses=null),r===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function vt(e,t,r){var o=e.doc,i=e.display;if(!o.mode.startState)return new ft(o,!0,t);var n=function(e,t,r){for(var o,i,n=e.doc,a=r?-1:t-(e.doc.mode.innerMode?1e3:100),l=t;l>a;--l){if(l<=n.first)return n.first;var s=Xe(n,l-1),d=s.stateAfter;if(d&&(!r||l+(d instanceof mt?d.lookAhead:0)<=n.modeFrontier))return l;var c=K(s.text,null,e.options.tabSize);(null==i||o>c)&&(i=l-1,o=c)}return i}(e,t,r),a=n>o.first&&Xe(o,n-1).stateAfter,l=a?ft.fromSaved(o,a,n):new ft(o,Qe(o.mode),n);return o.iter(n,t,(function(r){xt(e,r.text,l);var o=l.line;r.stateAfter=o==t-1||o%5==0||o>=i.viewFrom&&ot.start)return n}throw Error("Mode "+e.name+" failed to advance stream.")}ft.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},ft.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},ft.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},ft.fromSaved=function(e,t,r){return t instanceof mt?new ft(e,Ge(e.mode,t.state),r,t.lookAhead):new ft(e,Ge(e.mode,t),r)},ft.prototype.save=function(e){var t=!1!==e?Ge(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new mt(t,this.maxLookAhead):t};var _t=function(e,t,r){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=r};function Ct(e,t,r,o){var i,n,a=e.doc,l=a.mode,s=Xe(a,(t=ht(a,t)).line),d=vt(e,t.line,r),c=new Ye(s.text,e.options.tabSize,d);for(o&&(n=[]);(o||c.pose.options.maxHighlightLength?(l=!1,a&&xt(e,t,o,u.pos),u.pos=t.length,s=null):s=St(kt(r,u,o.state,p),n),p){var h=p[0].name;h&&(s="m-"+(s?h+" "+s:h))}if(!l||c!=s){for(;d=t:n.to>t);(o||(o=[])).push(new Ot(a,n.from,l?null:n.to))}}return o}(r,i,a),s=function(e,t,r){var o;if(e)for(var i=0;i=t:n.to>t)||n.from==t&&"bookmark"==a.type&&(!r||n.marker.insertLeft)){var l=null==n.from||(a.inclusiveLeft?n.from<=t:n.from0&&l)for(var v=0;vt)&&(!r||Pt(r,n.marker)<0)&&(r=n.marker)}return r}function Kt(e,t,r,o,i){var n=Xe(e,t),a=At&&n.markedSpans;if(a)for(var l=0;l=0&&u<=0||c<=0&&u>=0)&&(c<=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?lt(d.to,r)>=0:lt(d.to,r)>0)||c>=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?lt(d.from,o)<=0:lt(d.from,o)<0)))return!0}}}function jt(e){for(var t;t=Ut(e);)e=t.find(-1,!0).line;return e}function Vt(e,t){var r=Xe(e,t),o=jt(r);return r==o?t:rt(o)}function qt(e,t){if(t>e.lastLine())return t;var r,o=Xe(e,t);if(!Zt(e,o))return t;for(;r=Bt(o);)o=r.find(1,!0).line;return rt(o)+1}function Zt(e,t){var r=At&&t.markedSpans;if(r)for(var o=void 0,i=0;it.maxLineLength&&(t.maxLineLength=r,t.maxLine=e)}))}var Xt=function(e,t,r){this.text=e,Nt(this,t),this.height=r?r(this):1};function $t(e){e.parent=null,Ft(e)}Xt.prototype.lineNo=function(){return rt(this)},Ce(Xt);var er={},tr={};function rr(e,t){if(!e||/^\s*$/.test(e))return null;var r=t.addModeClass?tr:er;return r[e]||(r[e]=e.replace(/\S+/g,"cm-$&"))}function or(e,t){var r=M("span",null,null,s?"padding-right: .1px":null),o={pre:M("pre",[r],"CodeMirror-line"),content:r,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var n=i?t.rest[i-1]:t.line,a=void 0;o.pos=0,o.addToken=nr,Ne(e.display.measure)&&(a=me(n,e.doc.direction))&&(o.addToken=ar(o.addToken,a)),o.map=[],sr(n,o,yt(e,n,t!=e.display.externalMeasured&&rt(n))),n.styleClasses&&(n.styleClasses.bgClass&&(o.bgClass=N(n.styleClasses.bgClass,o.bgClass||"")),n.styleClasses.textClass&&(o.textClass=N(n.styleClasses.textClass,o.textClass||""))),0==o.map.length&&o.map.push(0,0,o.content.appendChild(Fe(e.display.measure))),0==i?(t.measure.map=o.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(o.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(s){var l=o.content.lastChild;(/\bcm-tab\b/.test(l.className)||l.querySelector&&l.querySelector(".cm-tab"))&&(o.content.className="cm-tab-wrap-hack")}return xe(e,"renderLine",e,t.line,o.pre),o.pre.className&&(o.textClass=N(o.pre.className,o.textClass||"")),o}function ir(e){var t=L("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function nr(e,t,r,o,i,n,s){if(t){var d,c=e.splitSpaces?function(e,t){if(e.length>1&&!/ /.test(e))return e;for(var r=t,o="",i=0;id&&u.from<=d);p++);if(u.to>=c)return e(r,o,i,n,a,l,s);e(r,o.slice(0,u.to-d),i,n,null,l,s),n=null,o=o.slice(u.to-d),d=u.to}}}function lr(e,t,r,o){var i=!o&&r.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!o&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",r.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function sr(e,t,r){var o=e.markedSpans,i=e.text,n=0;if(o)for(var a,l,s,d,c,u,p,h=i.length,g=0,m=1,f="",b=0;;){if(b==g){s=d=c=l="",p=null,u=null,b=1/0;for(var y=[],v=void 0,x=0;xg||k.collapsed&&w.to==g&&w.from==g)){if(null!=w.to&&w.to!=g&&b>w.to&&(b=w.to,d=""),k.className&&(s+=" "+k.className),k.css&&(l=(l?l+";":"")+k.css),k.startStyle&&w.from==g&&(c+=" "+k.startStyle),k.endStyle&&w.to==b&&(v||(v=[])).push(k.endStyle,w.to),k.title&&((p||(p={})).title=k.title),k.attributes)for(var _ in k.attributes)(p||(p={}))[_]=k.attributes[_];k.collapsed&&(!u||Pt(u.marker,k)<0)&&(u=w)}else w.from>g&&b>w.from&&(b=w.from)}if(v)for(var C=0;C=h)break;for(var E=Math.min(h,b);;){if(f){var T=g+f.length;if(!u){var A=T>E?f.slice(0,E-g):f;t.addToken(t,A,a?a+s:s,c,g+A.length==b?d:"",l,p)}if(T>=E){f=f.slice(E-g),g=E;break}g=T,c=""}f=i.slice(n,n=r[m++]),a=rr(r[m++],t.cm.options)}}else for(var O=1;Or)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function Nr(e,t,r,o){return Pr(e,Dr(e,t),r,o)}function zr(e,t){if(t>=e.display.viewFrom&&t=r.lineN&&t2&&n.push((s.bottom+d.top)/2-r.top)}}n.push(r.bottom-r.top)}}(e,t.view,t.rect),t.hasHeights=!0),n=function(e,t,r,o){var i,n=Br(t.map,r,o),s=n.node,d=n.start,c=n.end,u=n.collapse;if(3==s.nodeType){for(var p=0;p<4;p++){for(;d&&de(t.line.text.charAt(n.coverStart+d));)--d;for(;n.coverStart+c1}(e))return t;var r=screen.logicalXDPI/screen.deviceXDPI,o=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*r,right:t.right*r,top:t.top*o,bottom:t.bottom*o}}(e.display.measure,i))}else{var h;d>0&&(u=o="right"),i=e.options.lineWrapping&&(h=s.getClientRects()).length>1?h["right"==o?h.length-1:0]:s.getBoundingClientRect()}if(a&&l<9&&!d&&(!i||!i.left&&!i.right)){var g=s.parentNode.getClientRects()[0];i=g?{left:g.left,right:g.left+co(e.display),top:g.top,bottom:g.bottom}:Ur}for(var m=i.top-t.rect.top,f=i.bottom-t.rect.top,b=(m+f)/2,y=t.view.measure.heights,v=0;vt)&&(i=(n=s-l)-1,t>=s&&(a="right")),null!=i){if(o=e[d+2],l==s&&r==(o.insertLeft?"left":"right")&&(a=r),"left"==r&&0==i)for(;d&&e[d-2]==e[d-3]&&e[d-1].insertLeft;)o=e[2+(d-=3)],a="left";if("right"==r&&i==s-l)for(;d=0&&(r=e[i]).left==r.right;i--);return r}function Kr(e){if(e.measure&&(e.measure.cache={},e.measure.heights=null,e.rest))for(var t=0;t=o.text.length?(s=o.text.length,d="before"):s<=0&&(s=0,d="after"),!l)return a("before"==d?s-1:s,"before"==d);function c(e,t,r){return a(r?e-1:e,1==l[t].level!=r)}var u=he(l,s,d),p=pe,h=c(s,u,"before"==d);return null!=p&&(h.other=c(s,p,"before"!=d)),h}function $r(e,t){var r=0;t=ht(e.doc,t),e.options.lineWrapping||(r=co(e.display)*t.ch);var o=Xe(e.doc,t.line),i=Jt(o)+Ar(e.display);return{left:r,right:r,top:i,bottom:i+o.height}}function eo(e,t,r,o,i){var n=at(e,t,r);return n.xRel=i,o&&(n.outside=o),n}function to(e,t,r){var o=e.doc;if((r+=e.display.viewOffset)<0)return eo(o.first,0,null,-1,-1);var i=ot(o,r),n=o.first+o.size-1;if(i>n)return eo(o.first+o.size-1,Xe(o,n).text.length,null,1,1);t<0&&(t=0);for(var a=Xe(o,i);;){var l=no(e,a,i,t,r),s=Wt(a,l.ch+(l.xRel>0||l.outside>0?1:0));if(!s)return l;var d=s.find(1);if(d.line==i)return d;a=Xe(o,i=d.line)}}function ro(e,t,r,o){o-=Gr(t);var i=t.text.length,n=ue((function(t){return Pr(e,r,t-1).bottom<=o}),i,0);return{begin:n,end:i=ue((function(t){return Pr(e,r,t).top>o}),n,i)}}function oo(e,t,r,o){return r||(r=Dr(e,t)),ro(e,t,r,Jr(e,t,Pr(e,r,o),"line").top)}function io(e,t,r,o){return!(e.bottom<=r)&&(e.top>r||(o?e.left:e.right)>t)}function no(e,t,r,o,i){i-=Jt(t);var n=Dr(e,t),a=Gr(t),l=0,s=t.text.length,d=!0,c=me(t,e.doc.direction);if(c){var u=(e.options.lineWrapping?lo:ao)(e,t,r,n,c,o,i);l=(d=1!=u.level)?u.from:u.to-1,s=d?u.to:u.from-1}var p,h,g=null,m=null,f=ue((function(t){var r=Pr(e,n,t);return r.top+=a,r.bottom+=a,!!io(r,o,i,!1)&&(r.top<=i&&r.left<=o&&(g=t,m=r),!0)}),l,s),b=!1;if(m){var y=o-m.left=x.bottom?1:0}return eo(r,f=ce(t.text,f,1),h,b,o-p)}function ao(e,t,r,o,i,n,a){var l=ue((function(l){var s=i[l],d=1!=s.level;return io(Xr(e,at(r,d?s.to:s.from,d?"before":"after"),"line",t,o),n,a,!0)}),0,i.length-1),s=i[l];if(l>0){var d=1!=s.level,c=Xr(e,at(r,d?s.from:s.to,d?"after":"before"),"line",t,o);io(c,n,a,!0)&&c.top>a&&(s=i[l-1])}return s}function lo(e,t,r,o,i,n,a){var l=ro(e,t,o,a),s=l.begin,d=l.end;/\s/.test(t.text.charAt(d-1))&&d--;for(var c=null,u=null,p=0;p=d||h.to<=s)){var g=Pr(e,o,1!=h.level?Math.min(d,h.to)-1:Math.max(s,h.from)).right,m=gm)&&(c=h,u=m)}}return c||(c=i[i.length-1]),c.fromd&&(c={from:c.from,to:d,level:c.level}),c}function so(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Hr){Hr=L("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Hr.appendChild(document.createTextNode("x")),Hr.appendChild(L("br"));Hr.appendChild(document.createTextNode("x"))}O(e.measure,Hr);var r=Hr.offsetHeight/50;return r>3&&(e.cachedTextHeight=r),A(e.measure),r||1}function co(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=L("span","xxxxxxxxxx"),r=L("pre",[t],"CodeMirror-line-like");O(e.measure,r);var o=t.getBoundingClientRect(),i=(o.right-o.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function uo(e){for(var t=e.display,r={},o={},i=t.gutters.clientLeft,n=t.gutters.firstChild,a=0;n;n=n.nextSibling,++a){var l=e.display.gutterSpecs[a].className;r[l]=n.offsetLeft+n.clientLeft+i,o[l]=n.clientWidth}return{fixedPos:po(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:r,gutterWidth:o,wrapperWidth:t.wrapper.clientWidth}}function po(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function ho(e){var t=so(e.display),r=e.options.lineWrapping,o=r&&Math.max(5,e.display.scroller.clientWidth/co(e.display)-3);return function(i){if(Zt(e.doc,i))return 0;var n=0;if(i.widgets)for(var a=0;a0&&(s=Xe(e.doc,d.line).text).length==d.ch){var c=K(s,s.length,e.options.tabSize)-s.length;d=at(d.line,Math.max(0,Math.round((n-Lr(e.display).left)/co(e.display))-c))}return d}function fo(e,t){if(t>=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var r=e.display.view,o=0;ot)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)At&&Vt(e.doc,t)i.viewFrom?vo(e):(i.viewFrom+=o,i.viewTo+=o);else if(t<=i.viewFrom&&r>=i.viewTo)vo(e);else if(t<=i.viewFrom){var n=xo(e,r,r+o,1);n?(i.view=i.view.slice(n.index),i.viewFrom=n.lineN,i.viewTo+=o):vo(e)}else if(r>=i.viewTo){var a=xo(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):vo(e)}else{var l=xo(e,t,t,-1),s=xo(e,r,r+o,1);l&&s?(i.view=i.view.slice(0,l.index).concat(cr(e,l.lineN,s.lineN)).concat(i.view.slice(s.index)),i.viewTo+=o):vo(e)}var d=i.externalMeasured;d&&(r=i.lineN&&t=o.viewTo)){var n=o.view[fo(e,t)];if(null!=n.node){var a=n.changes||(n.changes=[]);-1==V(a,r)&&a.push(r)}}}function vo(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function xo(e,t,r,o){var i,n=fo(e,t),a=e.display.view;if(!At||r==e.doc.first+e.doc.size)return{index:n,lineN:r};for(var l=e.display.viewFrom,s=0;s0){if(n==a.length-1)return null;i=l+a[n].size-t,n++}else i=l-t;t+=i,r+=i}for(;Vt(e.doc,r)!=r;){if(n==(o<0?0:a.length-1))return null;r+=o*a[n-(o<0?1:0)].size,n+=o}return{index:n,lineN:r}}function wo(e){for(var t=e.display.view,r=0,o=0;o=e.display.viewTo||s.to().line0?a:e.defaultCharWidth())+"px"}if(o.other){var l=r.appendChild(L("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));l.style.display="",l.style.left=o.other.left+"px",l.style.top=o.other.top+"px",l.style.height=.85*(o.other.bottom-o.other.top)+"px"}}function So(e,t){return e.top-t.top||e.left-t.left}function Eo(e,t,r){var o=e.display,i=e.doc,n=document.createDocumentFragment(),a=Lr(e.display),l=a.left,s=Math.max(o.sizerWidth,Ir(e)-o.sizer.offsetLeft)-a.right,d="ltr"==i.direction;function c(e,t,r,o){t<0&&(t=0),t=Math.round(t),o=Math.round(o),n.appendChild(L("div",null,"CodeMirror-selected","position: absolute; left: "+e+"px;\n top: "+t+"px; width: "+(null==r?s-e:r)+"px;\n height: "+(o-t)+"px"))}function u(t,r,o){var n,a,u=Xe(i,t),p=u.text.length;function h(r,o){return Yr(e,at(t,r),"div",u,o)}function g(t,r,o){var i=oo(e,u,null,t),n="ltr"==r==("after"==o)?"left":"right";return h("after"==o?i.begin:i.end-(/\s/.test(u.text.charAt(i.end-1))?2:1),n)[n]}var m=me(u,i.direction);return function(e,t,r,o){if(!e)return o(t,r,"ltr",0);for(var i=!1,n=0;nt||t==r&&a.to==t)&&(o(Math.max(a.from,t),Math.min(a.to,r),1==a.level?"rtl":"ltr",n),i=!0)}i||o(t,r,"ltr")}(m,r||0,null==o?p:o,(function(e,t,i,u){var f="ltr"==i,b=h(e,f?"left":"right"),y=h(t-1,f?"right":"left"),v=null==r&&0==e,x=null==o&&t==p,w=0==u,k=!m||u==m.length-1;if(y.top-b.top<=3){var _=(d?x:v)&&k,C=(d?v:x)&&w?l:(f?b:y).left,S=_?s:(f?y:b).right;c(C,b.top,S-C,b.bottom)}else{var E,T,A,O;f?(E=d&&v&&w?l:b.left,T=d?s:g(e,i,"before"),A=d?l:g(t,i,"after"),O=d&&x&&k?s:y.right):(E=d?g(e,i,"before"):l,T=!d&&v&&w?s:b.right,A=!d&&x&&k?l:y.left,O=d?g(t,i,"after"):s),c(E,b.top,T-E,b.bottom),b.bottom0?t.blinker=setInterval((function(){e.hasFocus()||Mo(e),t.cursorDiv.style.visibility=(r=!r)?"":"hidden"}),e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Ao(e){e.hasFocus()||(e.display.input.focus(),e.state.focused||Lo(e))}function Oo(e){e.state.delayingBlurEvent=!0,setTimeout((function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,e.state.focused&&Mo(e))}),100)}function Lo(e,t){e.state.delayingBlurEvent&&!e.state.draggingText&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(xe(e,"focus",e,t),e.state.focused=!0,F(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),s&&setTimeout((function(){return e.display.input.reset(!0)}),20)),e.display.input.receivedFocus()),To(e))}function Mo(e,t){e.state.delayingBlurEvent||(e.state.focused&&(xe(e,"blur",e,t),e.state.focused=!1,T(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout((function(){e.state.focused||(e.display.shift=!1)}),150))}function Io(e){for(var t=e.display,r=t.lineDiv.offsetTop,o=Math.max(0,t.scroller.getBoundingClientRect().top),i=t.lineDiv.getBoundingClientRect().top,n=0,s=0;s.005||m<-.005)&&(ie.display.sizerWidth){var b=Math.ceil(p/co(e.display));b>e.display.maxLineLength&&(e.display.maxLineLength=b,e.display.maxLine=d.line,e.display.maxLineChanged=!0)}}}Math.abs(n)>2&&(t.scroller.scrollTop+=n)}function Ro(e){if(e.widgets)for(var t=0;t=a&&(n=ot(t,Jt(Xe(t,s))-e.wrapper.clientHeight),a=s)}return{from:n,to:Math.max(a,n+1)}}function No(e,t){var r=e.display,o=so(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:r.scroller.scrollTop,n=Rr(e),a={};t.bottom-t.top>n&&(t.bottom=t.top+n);var l=e.doc.height+Or(r),s=t.topl-o;if(t.topi+n){var c=Math.min(t.top,(d?l:t.bottom)-n);c!=i&&(a.scrollTop=c)}var u=e.options.fixedGutter?0:r.gutters.offsetWidth,p=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:r.scroller.scrollLeft-u,h=Ir(e)-r.gutters.offsetWidth,g=t.right-t.left>h;return g&&(t.right=t.left+h),t.left<10?a.scrollLeft=0:t.lefth+p-3&&(a.scrollLeft=t.right+(g?0:10)-h),a}function zo(e,t){null!=t&&(Ho(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Do(e){Ho(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Po(e,t,r){null==t&&null==r||Ho(e),null!=t&&(e.curOp.scrollLeft=t),null!=r&&(e.curOp.scrollTop=r)}function Ho(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,Uo(e,$r(e,t.from),$r(e,t.to),t.margin))}function Uo(e,t,r,o){var i=No(e,{left:Math.min(t.left,r.left),top:Math.min(t.top,r.top)-o,right:Math.max(t.right,r.right),bottom:Math.max(t.bottom,r.bottom)+o});Po(e,i.scrollLeft,i.scrollTop)}function Bo(e,t){Math.abs(e.doc.scrollTop-t)<2||(r||gi(e,{top:t}),Wo(e,t,!0),r&&gi(e),di(e,100))}function Wo(e,t,r){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),(e.display.scroller.scrollTop!=t||r)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Ko(e,t,r,o){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(r?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!o||(e.doc.scrollLeft=t,bi(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function jo(e){var t=e.display,r=t.gutters.offsetWidth,o=Math.round(e.doc.height+Or(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?r:0,docHeight:o,scrollHeight:o+Mr(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:r}}var Vo=function(e,t,r){this.cm=r;var o=this.vert=L("div",[L("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=L("div",[L("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");o.tabIndex=i.tabIndex=-1,e(o),e(i),be(o,"scroll",(function(){o.clientHeight&&t(o.scrollTop,"vertical")})),be(i,"scroll",(function(){i.clientWidth&&t(i.scrollLeft,"horizontal")})),this.checkedZeroWidth=!1,a&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Vo.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,r=e.scrollHeight>e.clientHeight+1,o=e.nativeBarWidth;if(r){this.vert.style.display="block",this.vert.style.bottom=t?o+"px":"0";var i=e.viewHeight-(t?o:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=r?o+"px":"0",this.horiz.style.left=e.barLeft+"px";var n=e.viewWidth-e.barLeft-(r?o:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+n)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==o&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:r?o:0,bottom:t?o:0}},Vo.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Vo.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Vo.prototype.zeroWidthHack=function(){var e=v&&!g?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.visibility=this.vert.style.visibility="hidden",this.disableHoriz=new j,this.disableVert=new j},Vo.prototype.enableZeroWidthBar=function(e,t,r){e.style.visibility="",t.set(1e3,(function o(){var i=e.getBoundingClientRect();("vert"==r?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.visibility="hidden":t.set(1e3,o)}))},Vo.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var qo=function(){};function Zo(e,t){t||(t=jo(e));var r=e.display.barWidth,o=e.display.barHeight;Go(e,t);for(var i=0;i<4&&r!=e.display.barWidth||o!=e.display.barHeight;i++)r!=e.display.barWidth&&e.options.lineWrapping&&Io(e),Go(e,jo(e)),r=e.display.barWidth,o=e.display.barHeight}function Go(e,t){var r=e.display,o=r.scrollbars.update(t);r.sizer.style.paddingRight=(r.barWidth=o.right)+"px",r.sizer.style.paddingBottom=(r.barHeight=o.bottom)+"px",r.heightForcer.style.borderBottom=o.bottom+"px solid transparent",o.right&&o.bottom?(r.scrollbarFiller.style.display="block",r.scrollbarFiller.style.height=o.bottom+"px",r.scrollbarFiller.style.width=o.right+"px"):r.scrollbarFiller.style.display="",o.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(r.gutterFiller.style.display="block",r.gutterFiller.style.height=o.bottom+"px",r.gutterFiller.style.width=t.gutterWidth+"px"):r.gutterFiller.style.display=""}qo.prototype.update=function(){return{bottom:0,right:0}},qo.prototype.setScrollLeft=function(){},qo.prototype.setScrollTop=function(){},qo.prototype.clear=function(){};var Jo={native:Vo,null:qo};function Qo(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&T(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new Jo[e.options.scrollbarStyle]((function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),be(t,"mousedown",(function(){e.state.focused&&setTimeout((function(){return e.display.input.focus()}),0)})),t.setAttribute("cm-not-content","true")}),(function(t,r){"horizontal"==r?Ko(e,t):Bo(e,t)}),e),e.display.scrollbars.addClass&&F(e.display.wrapper,e.display.scrollbars.addClass)}var Yo=0;function Xo(e){var t;e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Yo,markArrays:null},t=e.curOp,ur?ur.ops.push(t):t.ownsGroup=ur={ops:[t],delayedCallbacks:[]}}function $o(e){var t=e.curOp;t&&function(e,t){var r=e.ownsGroup;if(r)try{!function(e){var t=e.delayedCallbacks,r=0;do{for(;r=r.viewTo)||r.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ui(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function ti(e){e.updatedDisplay=e.mustUpdate&&pi(e.cm,e.update)}function ri(e){var t=e.cm,r=t.display;e.updatedDisplay&&Io(t),e.barMeasure=jo(t),r.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=Nr(t,r.maxLine,r.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(r.scroller.clientWidth,r.sizer.offsetLeft+e.adjustWidthTo+Mr(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,r.sizer.offsetLeft+e.adjustWidthTo-Ir(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=r.input.prepareSelection())}function oi(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft1&&(a=!0)),null!=d.scrollLeft&&(Ko(e,d.scrollLeft),Math.abs(e.doc.scrollLeft-u)>1&&(a=!0)),!a)break}return i}(t,ht(o,e.scrollToPos.from),ht(o,e.scrollToPos.to),e.scrollToPos.margin);!function(e,t){if(!we(e,"scrollCursorIntoView")){var r=e.display,o=r.sizer.getBoundingClientRect(),i=null,n=r.wrapper.ownerDocument;if(t.top+o.top<0?i=!0:t.bottom+o.top>(n.defaultView.innerHeight||n.documentElement.clientHeight)&&(i=!1),null!=i&&!m){var a=L("div","​",null,"position: absolute;\n top: "+(t.top-r.viewOffset-Ar(e.display))+"px;\n height: "+(t.bottom-t.top+Mr(e)+r.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(a),a.scrollIntoView(i),e.display.lineSpace.removeChild(a)}}}(t,i)}var n=e.maybeHiddenMarkers,a=e.maybeUnhiddenMarkers;if(n)for(var l=0;l=e.display.viewTo)){var r=+new Date+e.options.workTime,o=vt(e,t.highlightFrontier),i=[];t.iter(o.line,Math.min(t.first+t.size,e.display.viewTo+500),(function(n){if(o.line>=e.display.viewFrom){var a=n.styles,l=n.text.length>e.options.maxHighlightLength?Ge(t.mode,o.state):null,s=bt(e,n,o,!0);l&&(o.state=l),n.styles=s.styles;var d=n.styleClasses,c=s.classes;c?n.styleClasses=c:d&&(n.styleClasses=null);for(var u=!a||a.length!=n.styles.length||d!=c&&(!d||!c||d.bgClass!=c.bgClass||d.textClass!=c.textClass),p=0;!u&&pr)return di(e,e.options.workDelay),!0})),t.highlightFrontier=o.line,t.modeFrontier=Math.max(t.modeFrontier,o.line),i.length&&ni(e,(function(){for(var t=0;t=r.viewFrom&&t.visible.to<=r.viewTo&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo)&&r.renderedView==r.view&&0==wo(e))return!1;yi(e)&&(vo(e),t.dims=uo(e));var i=o.first+o.size,n=Math.max(t.visible.from-e.options.viewportMargin,o.first),a=Math.min(i,t.visible.to+e.options.viewportMargin);r.viewFroma&&r.viewTo-a<20&&(a=Math.min(i,r.viewTo)),At&&(n=Vt(e.doc,n),a=qt(e.doc,a));var l=n!=r.viewFrom||a!=r.viewTo||r.lastWrapHeight!=t.wrapperHeight||r.lastWrapWidth!=t.wrapperWidth;!function(e,t,r){var o=e.display;0==o.view.length||t>=o.viewTo||r<=o.viewFrom?(o.view=cr(e,t,r),o.viewFrom=t):(o.viewFrom>t?o.view=cr(e,t,o.viewFrom).concat(o.view):o.viewFromr&&(o.view=o.view.slice(0,fo(e,r)))),o.viewTo=r}(e,n,a),r.viewOffset=Jt(Xe(e.doc,r.viewFrom)),e.display.mover.style.top=r.viewOffset+"px";var d=wo(e);if(!l&&0==d&&!t.force&&r.renderedView==r.view&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo))return!1;var c=function(e){if(e.hasFocus())return null;var t=R(P(e));if(!t||!I(e.display.lineDiv,t))return null;var r={activeElt:t};if(window.getSelection){var o=U(e).getSelection();o.anchorNode&&o.extend&&I(e.display.lineDiv,o.anchorNode)&&(r.anchorNode=o.anchorNode,r.anchorOffset=o.anchorOffset,r.focusNode=o.focusNode,r.focusOffset=o.focusOffset)}return r}(e);return d>4&&(r.lineDiv.style.display="none"),function(e,t,r){var o=e.display,i=e.options.lineNumbers,n=o.lineDiv,a=n.firstChild;function l(t){var r=t.nextSibling;return s&&v&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),r}for(var d=o.view,c=o.viewFrom,u=0;u-1&&(h=!1),mr(e,p,c,r)),h&&(A(p.lineNumber),p.lineNumber.appendChild(document.createTextNode(nt(e.options,c)))),a=p.node.nextSibling}else{var g=kr(e,p,c,r);n.insertBefore(g,a)}c+=p.size}for(;a;)a=l(a)}(e,r.updateLineNumbers,t.dims),d>4&&(r.lineDiv.style.display=""),r.renderedView=r.view,function(e){if(e&&e.activeElt&&e.activeElt!=R(H(e.activeElt))&&(e.activeElt.focus(),!/^(INPUT|TEXTAREA)$/.test(e.activeElt.nodeName)&&e.anchorNode&&I(document.body,e.anchorNode)&&I(document.body,e.focusNode))){var t=e.activeElt.ownerDocument,r=t.defaultView.getSelection(),o=t.createRange();o.setEnd(e.anchorNode,e.anchorOffset),o.collapse(!1),r.removeAllRanges(),r.addRange(o),r.extend(e.focusNode,e.focusOffset)}}(c),A(r.cursorDiv),A(r.selectionDiv),r.gutters.style.height=r.sizer.style.minHeight=0,l&&(r.lastWrapHeight=t.wrapperHeight,r.lastWrapWidth=t.wrapperWidth,di(e,400)),r.updateLineNumbers=null,!0}function hi(e,t){for(var r=t.viewport,o=!0;;o=!1){if(o&&e.options.lineWrapping&&t.oldDisplayWidth!=Ir(e))o&&(t.visible=Fo(e.display,e.doc,r));else if(r&&null!=r.top&&(r={top:Math.min(e.doc.height+Or(e.display)-Rr(e),r.top)}),t.visible=Fo(e.display,e.doc,r),t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!pi(e,t))break;Io(e);var i=jo(e);ko(e),Zo(e,i),fi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function gi(e,t){var r=new ui(e,t);if(pi(e,r)){Io(e),hi(e,r);var o=jo(e);ko(e),Zo(e,o),fi(e,o),r.finish()}}function mi(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",hr(e,"gutterChanged",e)}function fi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Mr(e)+"px"}function bi(e){var t=e.display,r=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var o=po(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,n=o+"px",a=0;a=105&&(n.wrapper.style.clipPath="inset(0px)"),n.wrapper.setAttribute("translate","no"),a&&l<8&&(n.gutters.style.zIndex=-1,n.scroller.style.paddingRight=0),s||r&&y||(n.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(n.wrapper):e(n.wrapper)),n.viewFrom=n.viewTo=t.first,n.reportedViewFrom=n.reportedViewTo=t.first,n.view=[],n.renderedView=null,n.externalMeasured=null,n.viewOffset=0,n.lastWrapHeight=n.lastWrapWidth=0,n.updateLineNumbers=null,n.nativeBarWidth=n.barHeight=n.barWidth=0,n.scrollbarsClipped=!1,n.lineNumWidth=n.lineNumInnerWidth=n.lineNumChars=null,n.alignWidgets=!1,n.cachedCharWidth=n.cachedTextHeight=n.cachedPaddingH=null,n.maxLine=null,n.maxLineLength=0,n.maxLineChanged=!1,n.wheelDX=n.wheelDY=n.wheelStartX=n.wheelStartY=null,n.shift=!1,n.selForContextMenu=null,n.activeTouch=null,n.gutterSpecs=vi(i.gutters,i.lineNumbers),xi(n),o.init(n)}ui.prototype.signal=function(e,t){_e(e,t)&&this.events.push(arguments)},ui.prototype.finish=function(){for(var e=0;ed.clientWidth,g=d.scrollHeight>d.clientHeight;if(i&&h||n&&g){if(n&&v&&s)e:for(var m=t.target,f=l.view;m!=d;m=m.parentNode)for(var b=0;b=0&<(e,o.to())<=0)return r}return-1};var Oi=function(e,t){this.anchor=e,this.head=t};function Li(e,t,r){var o=e&&e.options.selectionsMayTouch,i=t[r];t.sort((function(e,t){return lt(e.from(),t.from())})),r=V(t,i);for(var n=1;n0:s>=0){var d=ut(l.from(),a.from()),c=ct(l.to(),a.to()),u=l.empty()?a.from()==a.head:l.from()==l.head;n<=r&&--r,t.splice(--n,2,new Oi(u?c:d,u?d:c))}}return new Ai(t,r)}function Mi(e,t){return new Ai([new Oi(e,t||e)],0)}function Ii(e){return e.text?at(e.from.line+e.text.length-1,ee(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function Ri(e,t){if(lt(e,t.from)<0)return e;if(lt(e,t.to)<=0)return Ii(t);var r=e.line+t.text.length-(t.to.line-t.from.line)-1,o=e.ch;return e.line==t.to.line&&(o+=Ii(t).ch-t.to.ch),at(r,o)}function Fi(e,t){for(var r=[],o=0;o1&&e.remove(l.line+1,g-1),e.insert(l.line+1,b)}hr(e,"change",e,t)}function Ui(e,t,r){!function e(o,i,n){if(o.linked)for(var a=0;al-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(n=function(e,t){return t?(Vi(e.done),ee(e.done)):e.done.length&&!ee(e.done).ranges?ee(e.done):e.done.length>1&&!e.done[e.done.length-2].ranges?(e.done.pop(),ee(e.done)):void 0}(i,i.lastOp==o)))a=ee(n.changes),0==lt(t.from,t.to)&&0==lt(t.from,a.to)?a.to=Ii(t):n.changes.push(ji(e,t));else{var s=ee(i.done);for(s&&s.ranges||Zi(e.sel,i.done),n={changes:[ji(e,t)],generation:i.generation},i.done.push(n);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(r),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=l,i.lastOp=i.lastSelOp=o,i.lastOrigin=i.lastSelOrigin=t.origin,a||xe(e,"historyAdded")}function Zi(e,t){var r=ee(t);r&&r.ranges&&r.equals(e)||t.push(e)}function Gi(e,t,r,o){var i=t["spans_"+e.id],n=0;e.iter(Math.max(e.first,r),Math.min(e.first+e.size,o),(function(r){r.markedSpans&&((i||(i=t["spans_"+e.id]={}))[n]=r.markedSpans),++n}))}function Ji(e){if(!e)return null;for(var t,r=0;r-1&&(ee(l)[u]=d[u],delete d[u])}}}return o}function Xi(e,t,r,o){if(o){var i=e.anchor;if(r){var n=lt(t,i)<0;n!=lt(r,i)<0?(i=t,t=r):n!=lt(t,r)<0&&(t=r)}return new Oi(i,t)}return new Oi(r||t,t)}function $i(e,t,r,o,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),nn(e,new Ai([Xi(e.sel.primary(),t,r,i)],0),o)}function en(e,t,r){for(var o=[],i=e.cm&&(e.cm.display.shift||e.extend),n=0;n=t.ch:l.to>t.ch))){if(i&&(xe(s,"beforeCursorEnter"),s.explicitlyCleared)){if(n.markedSpans){--a;continue}break}if(!s.atomic)continue;if(r){var u=s.find(o<0?1:-1),p=void 0;if((o<0?c:d)&&(u=pn(e,u,-o,u&&u.line==t.line?n:null)),u&&u.line==t.line&&(p=lt(u,r))&&(o<0?p<0:p>0))return cn(e,u,t,o,i)}var h=s.find(o<0?-1:1);return(o<0?d:c)&&(h=pn(e,h,o,h.line==t.line?n:null)),h?cn(e,h,t,o,i):null}}return t}function un(e,t,r,o,i){var n=o||1;return cn(e,t,r,n,i)||!i&&cn(e,t,r,n,!0)||cn(e,t,r,-n,i)||!i&&cn(e,t,r,-n,!0)||(e.cantEdit=!0,at(e.first,0))}function pn(e,t,r,o){return r<0&&0==t.ch?t.line>e.first?ht(e,at(t.line-1)):null:r>0&&t.ch==(o||Xe(e,t.line)).text.length?t.line0)){var c=[s,1],u=lt(d.from,l.from),p=lt(d.to,l.to);(u<0||!a.inclusiveLeft&&!u)&&c.push({from:d.from,to:l.from}),(p>0||!a.inclusiveRight&&!p)&&c.push({from:l.to,to:d.to}),i.splice.apply(i,c),s+=c.length-3}}return i}(e,t.from,t.to);if(o)for(var i=o.length-1;i>=0;--i)fn(e,{from:o[i].from,to:o[i].to,text:i?[""]:t.text,origin:t.origin});else fn(e,t)}}function fn(e,t){if(1!=t.text.length||""!=t.text[0]||0!=lt(t.from,t.to)){var r=Fi(e,t);qi(e,t,r,e.cm?e.cm.curOp.id:NaN),vn(e,t,r,It(e,t));var o=[];Ui(e,(function(e,r){r||-1!=V(o,e.history)||(_n(e.history,t),o.push(e.history)),vn(e,t,null,It(e,t))}))}}function bn(e,t,r){var o=e.cm&&e.cm.state.suppressEdits;if(!o||r){for(var i,n=e.history,a=e.sel,l="undo"==t?n.done:n.undone,s="undo"==t?n.undone:n.done,d=0;d=0;--h){var g=p(h);if(g)return g.v}}}}function yn(e,t){if(0!=t&&(e.first+=t,e.sel=new Ai(te(e.sel.ranges,(function(e){return new Oi(at(e.anchor.line+t,e.anchor.ch),at(e.head.line+t,e.head.ch))})),e.sel.primIndex),e.cm)){bo(e.cm,e.first,e.first-t,t);for(var r=e.cm.display,o=r.viewFrom;oe.lastLine())){if(t.from.linen&&(t={from:t.from,to:at(n,Xe(e,n).text.length),text:[t.text[0]],origin:t.origin}),t.removed=$e(e,t.from,t.to),r||(r=Fi(e,t)),e.cm?function(e,t,r){var o=e.doc,i=e.display,n=t.from,a=t.to,l=!1,s=n.line;e.options.lineWrapping||(s=rt(jt(Xe(o,n.line))),o.iter(s,a.line+1,(function(e){if(e==i.maxLine)return l=!0,!0}))),o.sel.contains(t.from,t.to)>-1&&ke(e),Hi(o,t,r,ho(e)),e.options.lineWrapping||(o.iter(s,n.line+t.text.length,(function(e){var t=Qt(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,l=!1)})),l&&(e.curOp.updateMaxLine=!0)),function(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontierr;o--){var i=Xe(e,o).stateAfter;if(i&&(!(i instanceof mt)||o+i.lookAhead1||!(this.children[0]instanceof Sn))){var l=[];this.collapse(l),this.children=[new Sn(l)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var a=i.lines.length%25+25,l=a;l10);e.parent.maybeSpill()}},iterN:function(e,t,r){for(var o=0;o0||0==a&&!1!==n.clearWhenEmpty)return n;if(n.replacedWith&&(n.collapsed=!0,n.widgetNode=M("span",[n.replacedWith],"CodeMirror-widget"),o.handleMouseEvents||n.widgetNode.setAttribute("cm-ignore-events","true"),o.insertLeft&&(n.widgetNode.insertLeft=!0)),n.collapsed){if(Kt(e,t.line,t,r,n)||t.line!=r.line&&Kt(e,r.line,t,r,n))throw Error("Inserting collapsed marker partially overlapping an existing one");At=!0}n.addToHistory&&qi(e,{from:t,to:r,origin:"markText"},e.sel,NaN);var l,s=t.line,d=e.cm;if(e.iter(s,r.line+1,(function(o){d&&n.collapsed&&!d.options.lineWrapping&&jt(o)==d.display.maxLine&&(l=!0),n.collapsed&&s!=t.line&&tt(o,0),function(e,t,r){var o=r&&window.WeakSet&&(r.markedSpans||(r.markedSpans=new WeakSet));o&&e.markedSpans&&o.has(e.markedSpans)?e.markedSpans.push(t):(e.markedSpans=e.markedSpans?e.markedSpans.concat([t]):[t],o&&o.add(e.markedSpans)),t.marker.attachLine(e)}(o,new Ot(n,s==t.line?t.ch:null,s==r.line?r.ch:null),e.cm&&e.cm.curOp),++s})),n.collapsed&&e.iter(t.line,r.line+1,(function(t){Zt(e,t)&&tt(t,0)})),n.clearOnEnter&&be(n,"beforeCursorEnter",(function(){return n.clear()})),n.readOnly&&(Tt=!0,(e.history.done.length||e.history.undone.length)&&e.clearHistory()),n.collapsed&&(n.id=++On,n.atomic=!0),d){if(l&&(d.curOp.updateMaxLine=!0),n.collapsed)bo(d,t.line,r.line+1);else if(n.className||n.startStyle||n.endStyle||n.css||n.attributes||n.title)for(var c=t.line;c<=r.line;c++)yo(d,c,"text");n.atomic&&sn(d.doc),hr(d,"markerAdded",d,n)}return n}Ln.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Xo(e),_e(this,"clear")){var r=this.find();r&&hr(this,"clear",r.from,r.to)}for(var o=null,i=null,n=0;ne.display.maxLineLength&&(e.display.maxLine=d,e.display.maxLineLength=c,e.display.maxLineChanged=!0)}null!=o&&e&&this.collapsed&&bo(e,o,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&sn(e.doc)),e&&hr(e,"markerCleared",e,this,o,i),t&&$o(e),this.parent&&this.parent.clear()}},Ln.prototype.find=function(e,t){var r,o;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=0;s--)mn(this,o[s]);l?on(this,l):this.cm&&Do(this.cm)})),undo:si((function(){bn(this,"undo")})),redo:si((function(){bn(this,"redo")})),undoSelection:si((function(){bn(this,"undo",!0)})),redoSelection:si((function(){bn(this,"redo",!0)})),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,r=0,o=0;o=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,r){e=ht(this,e),t=ht(this,t);var o=[],i=e.line;return this.iter(e.line,t.line+1,(function(n){var a=n.markedSpans;if(a)for(var l=0;l=s.to||null==s.from&&i!=e.line||null!=s.from&&i==t.line&&s.from>=t.ch||r&&!r(s.marker)||o.push(s.marker.parent||s.marker)}++i})),o},getAllMarks:function(){var e=[];return this.iter((function(t){var r=t.markedSpans;if(r)for(var o=0;oe)return t=e,!0;e-=n,++r})),ht(this,at(r,t))},indexFromPos:function(e){var t=(e=ht(this,e)).ch;if(e.linet&&(t=e.from),null!=e.to&&e.to-1)return t.state.draggingText(e),void setTimeout((function(){return t.display.input.focus()}),20);try{var u=e.dataTransfer.getData("Text");if(u){var p;if(t.state.draggingText&&!t.state.draggingText.copy&&(p=t.listSelections()),an(t.doc,Mi(r,r)),p)for(var h=0;h=0;t--)xn(e.doc,"",o[t].from,o[t].to,"+delete");Do(e)}))}function ra(e,t,r){var o=ce(e.text,t+r,r);return o<0||o>e.text.length?null:o}function oa(e,t,r){var o=ra(e,t.ch,r);return null==o?null:new at(t.line,o,r<0?"after":"before")}function ia(e,t,r,o,i){if(e){"rtl"==t.doc.direction&&(i=-i);var n=me(r,t.doc.direction);if(n){var a,l=i<0?ee(n):n[0],s=i<0==(1==l.level)?"after":"before";if(l.level>0||"rtl"==t.doc.direction){var d=Dr(t,r);a=i<0?r.text.length-1:0;var c=Pr(t,d,a).top;a=ue((function(e){return Pr(t,d,e).top==c}),i<0==(1==l.level)?l.from:l.to-1,a),"before"==s&&(a=ra(r,a,1))}else a=i<0?l.to:l.from;return new at(o,a,s)}}return new at(o,i<0?r.text.length:0,i<0?"before":"after")}Zn.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Zn.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Zn.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Zn.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Zn.default=v?Zn.macDefault:Zn.pcDefault;var na={selectAll:hn,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),G)},killLine:function(e){return ta(e,(function(t){if(t.empty()){var r=Xe(e.doc,t.head.line).text.length;return t.head.ch==r&&t.head.line0)i=new at(i.line,i.ch+1),e.replaceRange(n.charAt(i.ch-1)+n.charAt(i.ch-2),at(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=Xe(e.doc,i.line-1).text;a&&(i=new at(i.line,1),e.replaceRange(n.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),at(i.line-1,a.length-1),i,"+transpose"))}r.push(new Oi(i,i))}e.setSelections(r)}))},newlineAndIndent:function(e){return ni(e,(function(){for(var t=e.listSelections(),r=t.length-1;r>=0;r--)e.replaceRange(e.doc.lineSeparator(),t[r].anchor,t[r].head,"+input");t=e.listSelections();for(var o=0;o-1&&(lt((i=d.ranges[i]).from(),t)<0||t.xRel>0)&&(lt(i.to(),t)>0||t.xRel<0)?function(e,t,r,o){var i=e.display,n=!1,d=ai(e,(function(t){s&&(i.scroller.draggable=!1),e.state.draggingText=!1,e.state.delayingBlurEvent&&(e.hasFocus()?e.state.delayingBlurEvent=!1:Oo(e)),ve(i.wrapper.ownerDocument,"mouseup",d),ve(i.wrapper.ownerDocument,"mousemove",c),ve(i.scroller,"dragstart",u),ve(i.scroller,"drop",d),n||(Se(t),o.addNew||$i(e.doc,r,null,null,o.extend),s&&!h||a&&9==l?setTimeout((function(){i.wrapper.ownerDocument.body.focus({preventScroll:!0}),i.input.focus()}),20):i.input.focus())})),c=function(e){n=n||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},u=function(){return n=!0};s&&(i.scroller.draggable=!0),e.state.draggingText=d,d.copy=!o.moveOnDrag,be(i.wrapper.ownerDocument,"mouseup",d),be(i.wrapper.ownerDocument,"mousemove",c),be(i.scroller,"dragstart",u),be(i.scroller,"drop",d),e.state.delayingBlurEvent=!0,setTimeout((function(){return i.input.focus()}),20),i.scroller.dragDrop&&i.scroller.dragDrop()}(e,o,t,n):function(e,t,r,o){a&&Oo(e);var i=e.display,n=e.doc;Se(t);var l,s,d=n.sel,c=d.ranges;if(o.addNew&&!o.extend?(s=n.sel.contains(r),l=s>-1?c[s]:new Oi(r,r)):(l=n.sel.primary(),s=n.sel.primIndex),"rectangle"==o.unit)o.addNew||(l=new Oi(r,r)),r=mo(e,t,!0,!0),s=-1;else{var u=wa(e,r,o.unit);l=o.extend?Xi(l,u.anchor,u.head,o.extend):u}o.addNew?-1==s?(s=c.length,nn(n,Li(e,c.concat([l]),s),{scroll:!1,origin:"*mouse"})):c.length>1&&c[s].empty()&&"char"==o.unit&&!o.extend?(nn(n,Li(e,c.slice(0,s).concat(c.slice(s+1)),0),{scroll:!1,origin:"*mouse"}),d=n.sel):tn(n,s,l,J):(s=0,nn(n,new Ai([l],0),J),d=n.sel);var p=r,h=i.wrapper.getBoundingClientRect(),g=0;function m(t){var a=++g,c=mo(e,t,!0,"rectangle"==o.unit);if(c)if(0!=lt(c,p)){e.curOp.focus=R(P(e)),function(t){if(0!=lt(p,t))if(p=t,"rectangle"==o.unit){for(var i=[],a=e.options.tabSize,c=K(Xe(n,r.line).text,r.ch,a),u=K(Xe(n,t.line).text,t.ch,a),h=Math.min(c,u),g=Math.max(c,u),m=Math.min(r.line,t.line),f=Math.min(e.lastLine(),Math.max(r.line,t.line));m<=f;m++){var b=Xe(n,m).text,y=Y(b,h,a);h==g?i.push(new Oi(at(m,y),at(m,y))):b.length>y&&i.push(new Oi(at(m,y),at(m,Y(b,g,a))))}i.length||i.push(new Oi(r,r)),nn(n,Li(e,d.ranges.slice(0,s).concat(i),s),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var v,x=l,w=wa(e,t,o.unit),k=x.anchor;lt(w.anchor,k)>0?(v=w.head,k=ut(x.from(),w.anchor)):(v=w.anchor,k=ct(x.to(),w.head));var _=d.ranges.slice(0);_[s]=function(e,t){var r=t.anchor,o=t.head,i=Xe(e.doc,r.line);if(0==lt(r,o)&&r.sticky==o.sticky)return t;var n=me(i);if(!n)return t;var a=he(n,r.ch,r.sticky),l=n[a];if(l.from!=r.ch&&l.to!=r.ch)return t;var s,d=a+(l.from==r.ch==(1!=l.level)?0:1);if(0==d||d==n.length)return t;if(o.line!=r.line)s=(o.line-r.line)*("ltr"==e.doc.direction?1:-1)>0;else{var c=he(n,o.ch,o.sticky),u=c-a||(o.ch-r.ch)*(1==l.level?-1:1);s=c==d-1||c==d?u<0:u>0}var p=n[d+(s?-1:0)],h=s==(1==p.level),g=h?p.from:p.to,m=h?"after":"before";return r.ch==g&&r.sticky==m?t:new Oi(new at(r.line,g,m),o)}(e,new Oi(ht(n,k),v)),nn(n,Li(e,_,s),J)}}(c);var u=Fo(i,n);(c.line>=u.to||c.lineh.bottom?20:0;f&&setTimeout(ai(e,(function(){g==a&&(i.scroller.scrollTop+=f,m(t))})),50)}}function f(t){e.state.selectingText=!1,g=1/0,t&&(Se(t),i.input.focus()),ve(i.wrapper.ownerDocument,"mousemove",b),ve(i.wrapper.ownerDocument,"mouseup",y),n.history.lastSelOrigin=null}var b=ai(e,(function(e){0!==e.buttons&&Le(e)?m(e):f(e)})),y=ai(e,f);e.state.selectingText=y,be(i.wrapper.ownerDocument,"mousemove",b),be(i.wrapper.ownerDocument,"mouseup",y)}(e,o,t,n)}(t,o,n,e):Oe(e)==r.scroller&&Se(e):2==i?(o&&$i(t.doc,o),setTimeout((function(){return r.input.focus()}),20)):3==i&&(C?t.display.input.onContextMenu(e):Oo(t)))}}function wa(e,t,r){if("char"==r)return new Oi(t,t);if("word"==r)return e.findWordAt(t);if("line"==r)return new Oi(at(t.line,0),ht(e.doc,at(t.line+1,0)));var o=r(e,t);return new Oi(o.from,o.to)}function ka(e,t,r,o){var i,n;if(t.touches)i=t.touches[0].clientX,n=t.touches[0].clientY;else try{i=t.clientX,n=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;o&&Se(t);var a=e.display,l=a.lineDiv.getBoundingClientRect();if(n>l.bottom||!_e(e,r))return Te(t);n-=l.top-a.viewOffset;for(var s=0;s=i)return xe(e,r,e,ot(e.doc,n),e.display.gutterSpecs[s].className,t),Te(t)}}function _a(e,t){return ka(e,t,"gutterClick",!0)}function Ca(e,t){Tr(e.display,t)||function(e,t){return!!_e(e,"gutterContextMenu")&&ka(e,t,"gutterContextMenu",!1)}(e,t)||we(e,t,"contextmenu")||C||e.display.input.onContextMenu(t)}function Sa(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Vr(e)}va.prototype.compare=function(e,t,r){return this.time+400>e&&0==lt(t,this.pos)&&r==this.button};var Ea={toString:function(){return"CodeMirror.Init"}},Ta={},Aa={};function Oa(e,t,r){if(!t!=!(r&&r!=Ea)){var o=e.display.dragFunctions,i=t?be:ve;i(e.display.scroller,"dragstart",o.start),i(e.display.scroller,"dragenter",o.enter),i(e.display.scroller,"dragover",o.over),i(e.display.scroller,"dragleave",o.leave),i(e.display.scroller,"drop",o.drop)}}function La(e){e.options.lineWrapping?(F(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(T(e.display.wrapper,"CodeMirror-wrap"),Yt(e)),go(e),bo(e),Vr(e),setTimeout((function(){return Zo(e)}),100)}function Ma(e,t){var r=this;if(!(this instanceof Ma))return new Ma(e,t);this.options=t=t?W(t):{},W(Ta,t,!1);var o=t.value;"string"==typeof o?o=new zn(o,t.mode,null,t.lineSeparator,t.direction):t.mode&&(o.modeOption=t.mode),this.doc=o;var i=new Ma.inputStyles[t.inputStyle](this),n=this.display=new ki(e,o,i,t);for(var d in n.wrapper.CodeMirror=this,Sa(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),Qo(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new j,keySeq:null,specialChars:null},t.autofocus&&!y&&n.input.focus(),a&&l<11&&setTimeout((function(){return r.display.input.reset(!0)}),20),function(e){var t=e.display;be(t.scroller,"mousedown",ai(e,xa)),be(t.scroller,"dblclick",a&&l<11?ai(e,(function(t){if(!we(e,t)){var r=mo(e,t);if(r&&!_a(e,t)&&!Tr(e.display,t)){Se(t);var o=e.findWordAt(r);$i(e.doc,o.anchor,o.head)}}})):function(t){return we(e,t)||Se(t)}),be(t.scroller,"contextmenu",(function(t){return Ca(e,t)})),be(t.input.getField(),"contextmenu",(function(r){t.scroller.contains(r.target)||Ca(e,r)}));var r,o={end:0};function i(){t.activeTouch&&(r=setTimeout((function(){return t.activeTouch=null}),1e3),(o=t.activeTouch).end=+new Date)}function n(e,t){if(null==t.left)return!0;var r=t.left-e.left,o=t.top-e.top;return r*r+o*o>400}be(t.scroller,"touchstart",(function(i){if(!we(e,i)&&!function(e){if(1!=e.touches.length)return!1;var t=e.touches[0];return t.radiusX<=1&&t.radiusY<=1}(i)&&!_a(e,i)){t.input.ensurePolled(),clearTimeout(r);var n=+new Date;t.activeTouch={start:n,moved:!1,prev:n-o.end<=300?o:null},1==i.touches.length&&(t.activeTouch.left=i.touches[0].pageX,t.activeTouch.top=i.touches[0].pageY)}})),be(t.scroller,"touchmove",(function(){t.activeTouch&&(t.activeTouch.moved=!0)})),be(t.scroller,"touchend",(function(r){var o=t.activeTouch;if(o&&!Tr(t,r)&&null!=o.left&&!o.moved&&new Date-o.start<300){var a,l=e.coordsChar(t.activeTouch,"page");a=!o.prev||n(o,o.prev)?new Oi(l,l):!o.prev.prev||n(o,o.prev.prev)?e.findWordAt(l):new Oi(at(l.line,0),ht(e.doc,at(l.line+1,0))),e.setSelection(a.anchor,a.head),e.focus(),Se(r)}i()})),be(t.scroller,"touchcancel",i),be(t.scroller,"scroll",(function(){t.scroller.clientHeight&&(Bo(e,t.scroller.scrollTop),Ko(e,t.scroller.scrollLeft,!0),xe(e,"scroll",e))})),be(t.scroller,"mousewheel",(function(t){return Ti(e,t)})),be(t.scroller,"DOMMouseScroll",(function(t){return Ti(e,t)})),be(t.wrapper,"scroll",(function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0})),t.dragFunctions={enter:function(t){we(e,t)||Ae(t)},over:function(t){we(e,t)||(function(e,t){var r=mo(e,t);if(r){var o=document.createDocumentFragment();Co(e,r,o),e.display.dragCursor||(e.display.dragCursor=L("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),e.display.lineSpace.insertBefore(e.display.dragCursor,e.display.cursorDiv)),O(e.display.dragCursor,o)}}(e,t),Ae(t))},start:function(t){return function(e,t){if(a&&(!e.state.draggingText||+new Date-Dn<100))Ae(t);else if(!we(e,t)&&!Tr(e.display,t)&&(t.dataTransfer.setData("Text",e.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!h)){var r=L("img",null,null,"position: fixed; left: 0; top: 0;");r.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",p&&(r.width=r.height=1,e.display.wrapper.appendChild(r),r._top=r.offsetTop),t.dataTransfer.setDragImage(r,0,0),p&&r.parentNode.removeChild(r)}}(e,t)},drop:ai(e,Pn),leave:function(t){we(e,t)||Hn(e)}};var s=t.input.getField();be(s,"keyup",(function(t){return ma.call(e,t)})),be(s,"keydown",ai(e,ga)),be(s,"keypress",ai(e,fa)),be(s,"focus",(function(t){return Lo(e,t)})),be(s,"blur",(function(t){return Mo(e,t)}))}(this),function(){var e;Bn||(be(window,"resize",(function(){null==e&&(e=setTimeout((function(){e=null,Un(Wn)}),100))})),be(window,"blur",(function(){return Un(Mo)})),Bn=!0)}(),Xo(this),this.curOp.forceUpdate=!0,Bi(this,o),t.autofocus&&!y||this.hasFocus()?setTimeout((function(){r.hasFocus()&&!r.state.focused&&Lo(r)}),20):Mo(this),Aa)Aa.hasOwnProperty(d)&&Aa[d](this,t[d],Ea);yi(this),t.finishInit&&t.finishInit(this);for(var c=0;c150)){if(!o)return;r="prev"}}else d=0,r="not";"prev"==r?d=t>n.first?K(Xe(n,t-1).text,null,a):0:"add"==r?d=s+e.options.indentUnit:"subtract"==r?d=s-e.options.indentUnit:"number"==typeof r&&(d=s+r),d=Math.max(0,d);var u="",p=0;if(e.options.indentWithTabs)for(var h=Math.floor(d/a);h;--h)p+=a,u+="\t";if(pa,s=De(t),d=null;if(l&&o.ranges.length>1)if(Fa&&Fa.text.join("\n")==t){if(o.ranges.length%Fa.text.length==0){d=[];for(var c=0;c=0;p--){var h=o.ranges[p],g=h.from(),m=h.to();h.empty()&&(r&&r>0?g=at(g.line,g.ch-r):e.state.overwrite&&!l?m=at(m.line,Math.min(Xe(n,m.line).text.length,m.ch+ee(s).length)):l&&Fa&&Fa.lineWise&&Fa.text.join("\n")==s.join("\n")&&(g=m=at(g.line,0)));var f={from:g,to:m,text:d?d[p%d.length]:s,origin:i||(l?"paste":e.state.cutIncoming>a?"cut":"+input")};mn(e.doc,f),hr(e,"inputRead",e,f)}t&&!l&&Pa(e,t),Do(e),e.curOp.updateInput<2&&(e.curOp.updateInput=u),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Da(e,t){var r=e.clipboardData&&e.clipboardData.getData("Text");if(r)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||!t.hasFocus()||ni(t,(function(){return za(t,r,0,null,"paste")})),!0}function Pa(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var r=e.doc.sel,o=r.ranges.length-1;o>=0;o--){var i=r.ranges[o];if(!(i.head.ch>100||o&&r.ranges[o-1].head.line==i.head.line)){var n=e.getModeAt(i.head),a=!1;if(n.electricChars){for(var l=0;l-1){a=Ra(e,i.head.line,"smart");break}}else n.electricInput&&n.electricInput.test(Xe(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Ra(e,i.head.line,"smart"));a&&hr(e,"electricInput",e,i.head.line)}}}function Ha(e){for(var t=[],r=[],o=0;o0?0:-1));if(isNaN(c))a=null;else{var u=r>0?c>=55296&&c<56320:c>=56320&&c<57343;a=new at(t.line,Math.max(0,Math.min(l.text.length,t.ch+r*(u?2:1))),-r)}}else a=i?function(e,t,r,o){var i=me(t,e.doc.direction);if(!i)return oa(t,r,o);r.ch>=t.text.length?(r.ch=t.text.length,r.sticky="before"):r.ch<=0&&(r.ch=0,r.sticky="after");var n=he(i,r.ch,r.sticky),a=i[n];if("ltr"==e.doc.direction&&a.level%2==0&&(o>0?a.to>r.ch:a.from=a.from&&p>=c.begin)){var h=u?"before":"after";return new at(r.line,p,h)}}var g=function(e,t,o){for(var n=function(e,t){return t?new at(r.line,s(e,1),"before"):new at(r.line,e,"after")};e>=0&&e0==(1!=a.level),d=l?o.begin:s(o.end,-1);if(a.from<=d&&d0?c.end:s(c.begin,-1);return null==f||o>0&&f==t.text.length||!(m=g(o>0?0:i.length-1,o,d(f)))?null:m}(e.cm,l,t,r):oa(l,t,r);if(null==a){if(n||(d=t.line+s)=e.first+e.size||(t=new at(d,t.ch,t.sticky),!(l=Xe(e,d))))return!1;t=ia(i,e.cm,l,t.line,s)}else t=a;return!0}if("char"==o||"codepoint"==o)d();else if("column"==o)d(!0);else if("word"==o||"group"==o)for(var c=null,u="group"==o,p=e.cm&&e.cm.getHelper(t,"wordChars"),h=!0;!(r<0)||d(!h);h=!1){var g=l.text.charAt(t.ch)||"\n",m=ae(g,p)?"w":u&&"\n"==g?"n":!u||/\s/.test(g)?null:"p";if(!u||h||m||(m="s"),c&&c!=m){r<0&&(r=1,d(),t.sticky="after");break}if(m&&(c=m),r>0&&!d(!h))break}var f=un(e,t,n,a,!0);return st(n,f)&&(f.hitSide=!0),f}function Ka(e,t,r,o){var i,n,a=e.doc,l=t.left;if("page"==o){var s=Math.min(e.display.wrapper.clientHeight,U(e).innerHeight||a(e).documentElement.clientHeight),d=Math.max(s-.5*so(e.display),3);i=(r>0?t.bottom:t.top)+r*d}else"line"==o&&(i=r>0?t.bottom+3:t.top-3);for(;(n=to(e,l,i)).outside;){if(r<0?i<=0:i>=a.height){n.hitSide=!0;break}i+=5*r}return n}var ja=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new j,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Va(e,t){var r=zr(e,t.line);if(!r||r.hidden)return null;var o=Xe(e.doc,t.line),i=Fr(r,o,t.line),n=me(o,e.doc.direction),a="left";n&&(a=he(n,t.ch)%2?"right":"left");var l=Br(i.map,t.ch,a);return l.offset="right"==l.collapse?l.end:l.start,l}function qa(e,t){return t&&(e.bad=!0),e}function Za(e,t,r){var o;if(t==e.display.lineDiv){if(!(o=e.display.lineDiv.childNodes[r]))return qa(e.clipPos(at(e.display.viewTo-1)),!0);t=null,r=0}else for(o=t;;o=o.parentNode){if(!o||o==e.display.lineDiv)return null;if(o.parentNode&&o.parentNode==e.display.lineDiv)break}for(var i=0;i=t.display.viewTo||n.line=t.display.viewFrom&&Va(t,i)||{node:s[0].measure.map[2],offset:0},c=n.lineo.firstLine()&&(a=at(a.line-1,Xe(o.doc,a.line-1).length)),l.ch==Xe(o.doc,l.line).text.length&&l.linei.viewTo-1)return!1;a.line==i.viewFrom||0==(e=fo(o,a.line))?(t=rt(i.view[0].line),r=i.view[0].node):(t=rt(i.view[e].line),r=i.view[e-1].node.nextSibling);var s,d,c=fo(o,l.line);if(c==i.view.length-1?(s=i.viewTo-1,d=i.lineDiv.lastChild):(s=rt(i.view[c+1].line)-1,d=i.view[c+1].node.previousSibling),!r)return!1;for(var u=o.doc.splitLines(function(e,t,r,o,i){var n="",a=!1,l=e.doc.lineSeparator(),s=!1;function d(){a&&(n+=l,s&&(n+=l),a=s=!1)}function c(e){e&&(d(),n+=e)}function u(t){if(1==t.nodeType){var r=t.getAttribute("cm-text");if(r)return void c(r);var n,p=t.getAttribute("cm-marker");if(p){var h=e.findMarks(at(o,0),at(i+1,0),(f=+p,function(e){return e.id==f}));return void(h.length&&(n=h[0].find(0))&&c($e(e.doc,n.from,n.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var g=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;g&&d();for(var m=0;m1&&p.length>1;)if(ee(u)==ee(p))u.pop(),p.pop(),s--;else{if(u[0]!=p[0])break;u.shift(),p.shift(),t++}for(var h=0,g=0,m=u[0],f=p[0],b=Math.min(m.length,f.length);ha.ch&&y.charCodeAt(y.length-g-1)==v.charCodeAt(v.length-g-1);)h--,g++;u[u.length-1]=y.slice(0,y.length-g).replace(/^\u200b+/,""),u[0]=u[0].slice(h).replace(/\u200b+$/,"");var w=at(t,h),k=at(s,p.length?ee(p).length-g:0);return u.length>1||u[0]||lt(w,k)?(xn(o.doc,u,w,k,"+input"),!0):void 0},ja.prototype.ensurePolled=function(){this.forceCompositionEnd()},ja.prototype.reset=function(){this.forceCompositionEnd()},ja.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},ja.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout((function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()}),80))},ja.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||ni(this.cm,(function(){return bo(e.cm)}))},ja.prototype.setUneditable=function(e){e.contentEditable="false"},ja.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||ai(this.cm,za)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},ja.prototype.readOnlyChanged=function(e){this.div.contentEditable=("nocursor"!=e)+""},ja.prototype.onContextMenu=function(){},ja.prototype.resetPosition=function(){},ja.prototype.needsContentAttribute=!0;var Ja=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new j,this.hasSelection=!1,this.composing=null,this.resetting=!1};Ja.prototype.init=function(e){var t=this,r=this,o=this.cm;this.createField(e);var i=this.textarea;function n(e){if(!we(o,e)){if(o.somethingSelected())Na({lineWise:!1,text:o.getSelections()});else{if(!o.options.lineWiseCopyCut)return;var t=Ha(o);Na({lineWise:!0,text:t.text}),"cut"==e.type?o.setSelections(t.ranges,null,G):(r.prevInput="",i.value=t.text.join("\n"),z(i))}"cut"==e.type&&(o.state.cutIncoming=+new Date)}}e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),f&&(i.style.width="0px"),be(i,"input",(function(){a&&l>=9&&t.hasSelection&&(t.hasSelection=null),r.poll()})),be(i,"paste",(function(e){we(o,e)||Da(e,o)||(o.state.pasteIncoming=+new Date,r.fastPoll())})),be(i,"cut",n),be(i,"copy",n),be(e.scroller,"paste",(function(t){if(!Tr(e,t)&&!we(o,t)){if(!i.dispatchEvent)return o.state.pasteIncoming=+new Date,void r.focus();var n=new Event("paste");n.clipboardData=t.clipboardData,i.dispatchEvent(n)}})),be(e.lineSpace,"selectstart",(function(t){Tr(e,t)||Se(t)})),be(i,"compositionstart",(function(){var e=o.getCursor("from");r.composing&&r.composing.range.clear(),r.composing={start:e,range:o.markText(e,o.getCursor("to"),{className:"CodeMirror-composing"})}})),be(i,"compositionend",(function(){r.composing&&(r.poll(),r.composing.range.clear(),r.composing=null)}))},Ja.prototype.createField=function(e){this.wrapper=Ba(),this.textarea=this.wrapper.firstChild;var t=this.cm.options;Ua(this.textarea,t.spellcheck,t.autocorrect,t.autocapitalize)},Ja.prototype.screenReaderLabelChanged=function(e){e?this.textarea.setAttribute("aria-label",e):this.textarea.removeAttribute("aria-label")},Ja.prototype.prepareSelection=function(){var e=this.cm,t=e.display,r=e.doc,o=_o(e);if(e.options.moveInputWithCursor){var i=Xr(e,r.sel.primary().head,"div"),n=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();o.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-n.top)),o.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-n.left))}return o},Ja.prototype.showSelection=function(e){var t=this.cm.display;O(t.cursorDiv,e.cursors),O(t.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Ja.prototype.reset=function(e){if(!(this.contextMenuPending||this.composing&&e)){var t=this.cm;if(this.resetting=!0,t.somethingSelected()){this.prevInput="";var r=t.getSelection();this.textarea.value=r,t.state.focused&&z(this.textarea),a&&l>=9&&(this.hasSelection=r)}else e||(this.prevInput=this.textarea.value="",a&&l>=9&&(this.hasSelection=null));this.resetting=!1}},Ja.prototype.getField=function(){return this.textarea},Ja.prototype.supportsTouch=function(){return!1},Ja.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!y||R(H(this.textarea))!=this.textarea))try{this.textarea.focus()}catch(e){}},Ja.prototype.blur=function(){this.textarea.blur()},Ja.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Ja.prototype.receivedFocus=function(){this.slowPoll()},Ja.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,(function(){e.poll(),e.cm.state.focused&&e.slowPoll()}))},Ja.prototype.fastPoll=function(){var e=!1,t=this;t.pollingFast=!0,t.polling.set(20,(function r(){t.poll()||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,r))}))},Ja.prototype.poll=function(){var e=this,t=this.cm,r=this.textarea,o=this.prevInput;if(this.contextMenuPending||this.resetting||!t.state.focused||Pe(r)&&!o&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=r.value;if(i==o&&!t.somethingSelected())return!1;if(a&&l>=9&&this.hasSelection===i||v&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var n=i.charCodeAt(0);if(8203!=n||o||(o="​"),8666==n)return this.reset(),this.cm.execCommand("undo")}for(var s=0,d=Math.min(o.length,i.length);s1e3||i.indexOf("\n")>-1?r.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))})),!0},Ja.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Ja.prototype.onKeyPress=function(){a&&l>=9&&(this.hasSelection=null),this.fastPoll()},Ja.prototype.onContextMenu=function(e){var t=this,r=t.cm,o=r.display,i=t.textarea;t.contextMenuPending&&t.contextMenuPending();var n=mo(r,e),d=o.scroller.scrollTop;if(n&&!p){r.options.resetSelectionOnContextMenu&&-1==r.doc.sel.contains(n)&&ai(r,nn)(r.doc,Mi(n),G);var c,u=i.style.cssText,h=t.wrapper.style.cssText,g=t.wrapper.offsetParent.getBoundingClientRect();if(t.wrapper.style.cssText="position: static",i.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-g.top-5)+"px; left: "+(e.clientX-g.left-5)+"px;\n z-index: 1000; background: "+(a?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",s&&(c=i.ownerDocument.defaultView.scrollY),o.input.focus(),s&&i.ownerDocument.defaultView.scrollTo(null,c),o.input.reset(),r.somethingSelected()||(i.value=t.prevInput=" "),t.contextMenuPending=b,o.selForContextMenu=r.doc.sel,clearTimeout(o.detectingSelectAll),a&&l>=9&&f(),C){Ae(e);var m=function(){ve(window,"mouseup",m),setTimeout(b,20)};be(window,"mouseup",m)}else setTimeout(b,50)}function f(){if(null!=i.selectionStart){var e=r.somethingSelected(),n="​"+(e?i.value:"");i.value="⇚",i.value=n,t.prevInput=e?"":"​",i.selectionStart=1,i.selectionEnd=n.length,o.selForContextMenu=r.doc.sel}}function b(){if(t.contextMenuPending==b&&(t.contextMenuPending=!1,t.wrapper.style.cssText=h,i.style.cssText=u,a&&l<9&&o.scrollbars.setScrollTop(o.scroller.scrollTop=d),null!=i.selectionStart)){(!a||a&&l<9)&&f();var e=0,n=function(){o.selForContextMenu==r.doc.sel&&0==i.selectionStart&&i.selectionEnd>0&&"​"==t.prevInput?ai(r,hn)(r):e++<10?o.detectingSelectAll=setTimeout(n,500):(o.selForContextMenu=null,o.input.reset())};o.detectingSelectAll=setTimeout(n,200)}}},Ja.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e,this.textarea.readOnly=!!e},Ja.prototype.setUneditable=function(){},Ja.prototype.needsContentAttribute=!1,function(e){var t=e.optionHandlers;function r(r,o,i,n){e.defaults[r]=o,i&&(t[r]=n?function(e,t,r){r!=Ea&&i(e,t,r)}:i)}e.defineOption=r,e.Init=Ea,r("value","",(function(e,t){return e.setValue(t)}),!0),r("mode",null,(function(e,t){e.doc.modeOption=t,zi(e)}),!0),r("indentUnit",2,zi,!0),r("indentWithTabs",!1),r("smartIndent",!0),r("tabSize",4,(function(e){Di(e),Vr(e),bo(e)}),!0),r("lineSeparator",null,(function(e,t){if(e.doc.lineSep=t,t){var r=[],o=e.doc.first;e.doc.iter((function(e){for(var i=0;;){var n=e.text.indexOf(t,i);if(-1==n)break;i=n+t.length,r.push(at(o,n))}o++}));for(var i=r.length-1;i>=0;i--)xn(e.doc,t,r[i],at(r[i].line,r[i].ch+t.length))}})),r("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g,(function(e,t,r){e.state.specialChars=RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),r!=Ea&&e.refresh()})),r("specialCharPlaceholder",ir,(function(e){return e.refresh()}),!0),r("electricChars",!0),r("inputStyle",y?"contenteditable":"textarea",(function(){throw Error("inputStyle can not (yet) be changed in a running editor")}),!0),r("spellcheck",!1,(function(e,t){return e.getInputField().spellcheck=t}),!0),r("autocorrect",!1,(function(e,t){return e.getInputField().autocorrect=t}),!0),r("autocapitalize",!1,(function(e,t){return e.getInputField().autocapitalize=t}),!0),r("rtlMoveVisually",!w),r("wholeLineUpdateBefore",!0),r("theme","default",(function(e){Sa(e),wi(e)}),!0),r("keyMap","default",(function(e,t,r){var o=ea(t),i=r!=Ea&&ea(r);i&&i.detach&&i.detach(e,o),o.attach&&o.attach(e,i||null)})),r("extraKeys",null),r("configureMouse",null),r("lineWrapping",!1,La,!0),r("gutters",[],(function(e,t){e.display.gutterSpecs=vi(t,e.options.lineNumbers),wi(e)}),!0),r("fixedGutter",!0,(function(e,t){e.display.gutters.style.left=t?po(e.display)+"px":"0",e.refresh()}),!0),r("coverGutterNextToScrollbar",!1,(function(e){return Zo(e)}),!0),r("scrollbarStyle","native",(function(e){Qo(e),Zo(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)}),!0),r("lineNumbers",!1,(function(e,t){e.display.gutterSpecs=vi(e.options.gutters,t),wi(e)}),!0),r("firstLineNumber",1,wi,!0),r("lineNumberFormatter",(function(e){return e}),wi,!0),r("showCursorWhenSelecting",!1,ko,!0),r("resetSelectionOnContextMenu",!0),r("lineWiseCopyCut",!0),r("pasteLinesPerSelection",!0),r("selectionsMayTouch",!1),r("readOnly",!1,(function(e,t){"nocursor"==t&&(Mo(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)})),r("screenReaderLabel",null,(function(e,t){t=""===t?null:t,e.display.input.screenReaderLabelChanged(t)})),r("disableInput",!1,(function(e,t){t||e.display.input.reset()}),!0),r("dragDrop",!0,Oa),r("allowDropFileTypes",null),r("cursorBlinkRate",530),r("cursorScrollMargin",0),r("cursorHeight",1,ko,!0),r("singleCursorHeightPerLine",!0,ko,!0),r("workTime",100),r("workDelay",100),r("flattenSpans",!0,Di,!0),r("addModeClass",!1,Di,!0),r("pollInterval",100),r("undoDepth",200,(function(e,t){return e.doc.history.undoDepth=t})),r("historyEventDelay",1250),r("viewportMargin",10,(function(e){return e.refresh()}),!0),r("maxHighlightLength",1e4,Di,!0),r("moveInputWithCursor",!0,(function(e,t){t||e.display.input.resetPosition()})),r("tabindex",null,(function(e,t){return e.display.input.getField().tabIndex=t||""})),r("autofocus",null),r("direction","ltr",(function(e,t){return e.doc.setDirection(t)}),!0),r("phrases",null)}(Ma),function(e){var t=e.optionHandlers,r=e.helpers={};e.prototype={constructor:e,focus:function(){U(this).focus(),this.display.input.focus()},setOption:function(e,r){var o=this.options,i=o[e];o[e]==r&&"mode"!=e||(o[e]=r,t.hasOwnProperty(e)&&ai(this,t[e])(this,r,i),xe(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](ea(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,r=0;rr&&(Ra(this,i.head.line,e,!0),r=i.head.line,o==this.doc.sel.primIndex&&Do(this));else{var n=i.from(),a=i.to(),l=Math.max(r,n.line);r=Math.min(this.lastLine(),a.line-(a.ch?0:1))+1;for(var s=l;s0&&tn(this.doc,o,new Oi(n,d[o].to()),G)}}})),getTokenAt:function(e,t){return Ct(this,e,t)},getLineTokens:function(e,t){return Ct(this,at(e),t,!0)},getTokenTypeAt:function(e){e=ht(this.doc,e);var t,r=yt(this,Xe(this.doc,e.line)),o=0,i=(r.length-1)/2,n=e.ch;if(0==n)t=r[2];else for(;;){var a=o+i>>1;if((a?r[2*a-1]:0)>=n)i=a;else{if(!(r[2*a+1]n&&(e=n,i=!0),o=Xe(this.doc,e)}else o=e;return Jr(this,o,{top:0,left:0},t||"page",r||i).top+(i?this.doc.height-Jt(o):0)},defaultTextHeight:function(){return so(this.display)},defaultCharWidth:function(){return co(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,r,o,i){var n,a=this.display,l=(e=Xr(this,ht(this.doc,e))).bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),a.sizer.appendChild(t),"over"==o)l=e.top;else if("above"==o||"near"==o){var d=Math.max(a.wrapper.clientHeight,this.doc.height),c=Math.max(a.sizer.clientWidth,a.lineSpace.clientWidth);("above"==o||e.bottom+t.offsetHeight>d)&&e.top>t.offsetHeight?l=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=d&&(l=e.bottom),s+t.offsetWidth>c&&(s=c-t.offsetWidth)}t.style.top=l+"px",t.style.left=t.style.right="","right"==i?(s=a.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(a.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),r&&(null!=(n=No(this,{left:s,top:l,right:s+t.offsetWidth,bottom:l+t.offsetHeight})).scrollTop&&Bo(this,n.scrollTop),null!=n.scrollLeft&&Ko(this,n.scrollLeft))},triggerOnKeyDown:li(ga),triggerOnKeyPress:li(fa),triggerOnKeyUp:ma,triggerOnMouseDown:li(xa),execCommand:function(e){if(na.hasOwnProperty(e))return na[e].call(null,this)},triggerElectric:li((function(e){Pa(this,e)})),findPosH:function(e,t,r,o){var i=1;t<0&&(i=-1,t=-t);for(var n=ht(this.doc,e),a=0;a0&&a(t.charAt(r-1));)--r;for(;o.5||this.options.lineWrapping)&&go(this),xe(this,"refresh",this)})),swapDoc:li((function(e){var t=this.doc;return t.cm=null,this.state.selectingText&&this.state.selectingText(),Bi(this,e),Vr(this),this.display.input.reset(),Po(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,hr(this,"swapDoc",this,t),t})),phrase:function(e){var t=this.options.phrases;return t&&Object.prototype.hasOwnProperty.call(t,e)?t[e]:e},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Ce(e),e.registerHelper=function(t,o,i){r.hasOwnProperty(t)||(r[t]=e[t]={_global:[]}),r[t][o]=i},e.registerGlobalHelper=function(t,o,i,n){e.registerHelper(t,o,n),r[t]._global.push({pred:i,val:n})}}(Ma);var Qa="iter insert remove copy getEditor constructor".split(" ");for(var Ya in zn.prototype)zn.prototype.hasOwnProperty(Ya)&&V(Qa,Ya)<0&&(Ma.prototype[Ya]=function(e){return function(){return e.apply(this.doc,arguments)}}(zn.prototype[Ya]));return Ce(zn),Ma.inputStyles={textarea:Ja,contenteditable:ja},Ma.defineMode=function(e){Ma.defaults.mode||"null"==e||(Ma.defaults.mode=e),Ke.apply(this,arguments)},Ma.defineMIME=function(e,t){We[e]=t},Ma.defineMode("null",(function(){return{token:function(e){return e.skipToEnd()}}})),Ma.defineMIME("text/plain","null"),Ma.defineExtension=function(e,t){Ma.prototype[e]=t},Ma.defineDocExtension=function(e,t){zn.prototype[e]=t},Ma.fromTextArea=function(e,t){if((t=t?W(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var r=R(H(e));t.autofocus=r==e||null!=e.getAttribute("autofocus")&&r==document.body}function o(){e.value=l.getValue()}var i;if(e.form&&(be(e.form,"submit",o),!t.leaveSubmitMethodAlone)){var n=e.form;i=n.submit;try{var a=n.submit=function(){o(),n.submit=i,n.submit(),n.submit=a}}catch(e){}}t.finishInit=function(r){r.save=o,r.getTextArea=function(){return e},r.toTextArea=function(){r.toTextArea=isNaN,o(),e.parentNode.removeChild(r.getWrapperElement()),e.style.display="",e.form&&(ve(e.form,"submit",o),t.leaveSubmitMethodAlone||"function"!=typeof e.form.submit||(e.form.submit=i))}},e.style.display="none";var l=Ma((function(t){return e.parentNode.insertBefore(t,e.nextSibling)}),t);return l},function(e){e.off=ve,e.on=be,e.wheelEventPixels=Ei,e.Doc=zn,e.splitLines=De,e.countColumn=K,e.findColumn=Y,e.isWordChar=ne,e.Pass=Z,e.signal=xe,e.Line=Xt,e.changeEnd=Ii,e.scrollbarModel=Jo,e.Pos=at,e.cmpPos=lt,e.modes=Be,e.mimeModes=We,e.resolveMode=je,e.getMode=Ve,e.modeExtensions=qe,e.extendMode=Ze,e.copyState=Ge,e.startState=Qe,e.innerMode=Je,e.commands=na,e.keyMap=Zn,e.keyName=$n,e.isModifierKey=Yn,e.lookupKey=Qn,e.normalizeKeyMap=Jn,e.StringStream=Ye,e.SharedTextMarker=In,e.TextMarker=Ln,e.LineWidget=Tn,e.e_preventDefault=Se,e.e_stopPropagation=Ee,e.e_stop=Ae,e.addClass=F,e.contains=I,e.rmClass=T,e.keyNames=Kn}(Ma),Ma.version="5.65.16",Ma},(window||self).CodeMirror=gi(),function(e){var t="CodeMirror-hint-active";function r(e,t){if(this.cm=e,this.options=t,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length,this.options.updateOnCursorActivity){var r=this;e.on("cursorActivity",this.activityFunc=function(){r.cursorActivity()})}}e.showHint=function(e,t,r){if(!t)return e.showHint(r);r&&r.async&&(t.async=!0);var o={hint:t};if(r)for(var i in r)o[i]=r[i];return e.showHint(o)},e.defineExtension("showHint",(function(t){t=function(e,t,r){var o=e.options.hintOptions,i={};for(var n in d)i[n]=d[n];if(o)for(var n in o)void 0!==o[n]&&(i[n]=o[n]);if(r)for(var n in r)void 0!==r[n]&&(i[n]=r[n]);return i.hint.resolve&&(i.hint=i.hint.resolve(e,t)),i}(this,this.getCursor("start"),t);var o=this.listSelections();if(!(o.length>1)){if(this.somethingSelected()){if(!t.hint.supportsSelection)return;for(var i=0;ic.clientHeight+1;if(setTimeout((function(){O=l.getScrollInfo()})),L.bottom-A>0){var I=L.bottom-L.top,R=L.top-(y.bottom-y.top)-2;A-L.topR&&(c.style.height=(I=R)+"px"),c.style.top=(x=y.top-I)+_+"px",w=!1):c.style.height=A-L.top-2+"px"}var F,N=L.right-T;if(M&&(N+=l.display.nativeBarWidth),N>0&&(L.right-L.left>T&&(c.style.width=T-5+"px",N-=L.right-L.left-T),c.style.left=(v=Math.max(y.left-N-k,0))+"px"),M)for(var z=c.firstChild;z;z=z.nextSibling)z.style.paddingRight=l.display.nativeBarWidth+"px";l.addKeyMap(this.keyMap=function(e,t){var r={Up:function(){t.moveFocus(-1)},Down:function(){t.moveFocus(1)},PageUp:function(){t.moveFocus(1-t.menuSize(),!0)},PageDown:function(){t.moveFocus(t.menuSize()-1,!0)},Home:function(){t.setFocus(0)},End:function(){t.setFocus(t.length-1)},Enter:t.pick,Tab:t.pick,Esc:t.close};/Mac/.test(navigator.platform)&&(r["Ctrl-P"]=function(){t.moveFocus(-1)},r["Ctrl-N"]=function(){t.moveFocus(1)});var o=e.options.customKeys,i=o?{}:r;function n(e,o){var n;n="string"!=typeof o?function(e){return o(e,t)}:r.hasOwnProperty(o)?r[o]:o,i[e]=n}if(o)for(var a in o)o.hasOwnProperty(a)&&n(a,o[a]);var l=e.options.extraKeys;if(l)for(var a in l)l.hasOwnProperty(a)&&n(a,l[a]);return i}(r,{moveFocus:function(e,t){i.changeActive(i.selectedHint+e,t)},setFocus:function(e){i.changeActive(e)},menuSize:function(){return i.screenAmount()},length:p.length,close:function(){r.close()},pick:function(){i.pick()},data:o})),r.options.closeOnUnfocus&&(l.on("blur",this.onBlur=function(){F=setTimeout((function(){r.close()}),100)}),l.on("focus",this.onFocus=function(){clearTimeout(F)})),l.on("scroll",this.onScroll=function(){var e=l.getScrollInfo(),t=l.getWrapperElement().getBoundingClientRect();O||(O=l.getScrollInfo());var o=x+O.top-e.top,i=o-(d.pageYOffset||(s.documentElement||s.body).scrollTop);if(w||(i+=c.offsetHeight),i<=t.top||i>=t.bottom)return r.close();c.style.top=o+"px",c.style.left=v+O.left-e.left+"px"}),e.on(c,"dblclick",(function(e){var t=a(c,e.target||e.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),i.pick())})),e.on(c,"click",(function(e){var t=a(c,e.target||e.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),r.options.completeOnSingleClick&&i.pick())})),e.on(c,"mousedown",(function(){setTimeout((function(){l.focus()}),20)}));var D=this.getSelectedHintRange();return 0===D.from&&0===D.to||this.scrollToActive(),e.signal(o,"select",p[this.selectedHint],c.childNodes[this.selectedHint]),!0}function s(e,t,r,o){if(e.async)e(t,o,r);else{var i=e(t,r);i&&i.then?i.then(o):o(i)}}r.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.options.updateOnCursorActivity&&this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&e.signal(this.data,"close"),this.widget&&this.widget.close(),e.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(t,r){var o=t.list[r],i=this;this.cm.operation((function(){o.hint?o.hint(i.cm,t,o):i.cm.replaceRange(n(o),o.from||t.from,o.to||t.to,"complete"),e.signal(t,"pick",o),i.cm.scrollIntoView()})),this.options.closeOnPick&&this.close()},cursorActivity:function(){this.debounce&&(i(this.debounce),this.debounce=0);var e=this.startPos;this.data&&(e=this.data.from);var t=this.cm.getCursor(),r=this.cm.getLine(t.line);if(t.line!=this.startPos.line||r.length-t.ch!=this.startLen-this.startPos.ch||t.ch=this.data.list.length?r=o?this.data.list.length-1:0:r<0&&(r=o?0:this.data.list.length-1),this.selectedHint!=r){var i=this.hints.childNodes[this.selectedHint];i&&(i.className=i.className.replace(" "+t,""),i.removeAttribute("aria-selected")),(i=this.hints.childNodes[this.selectedHint=r]).className+=" "+t,i.setAttribute("aria-selected","true"),this.completion.cm.getInputField().setAttribute("aria-activedescendant",i.id),this.scrollToActive(),e.signal(this.data,"select",this.data.list[this.selectedHint],i)}},scrollToActive:function(){var e=this.getSelectedHintRange(),t=this.hints.childNodes[e.from],r=this.hints.childNodes[e.to],o=this.hints.firstChild;t.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=r.offsetTop+r.offsetHeight-this.hints.clientHeight+o.offsetTop)},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1},getSelectedHintRange:function(){var e=this.completion.options.scrollMargin||0;return{from:Math.max(0,this.selectedHint-e),to:Math.min(this.data.list.length-1,this.selectedHint+e)}}},e.registerHelper("hint","auto",{resolve:function(t,r){var o,i=t.getHelpers(r,"hint");if(i.length){var n=function(e,t,r){var o=function(e,t){if(!e.somethingSelected())return t;for(var r=[],o=0;o0?t(e):i(n+1)}))}(0)};return n.async=!0,n.supportsSelection=!0,n}return(o=t.getHelper(t.getCursor(),"hintWords"))?function(t){return e.hint.fromList(t,{words:o})}:e.hint.anyword?function(t,r){return e.hint.anyword(t,r)}:function(){}}}),e.registerHelper("hint","fromList",(function(t,r){var o,i=t.getCursor(),n=t.getTokenAt(i),a=e.Pos(i.line,n.start),l=i;n.start,]/,closeOnPick:!0,closeOnUnfocus:!0,updateOnCursorActivity:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null,paddingForScrollbar:!0,moveOnOverlap:!0};e.defineOption("hintOptions",null)}(CodeMirror),function(e){function t(t,r,i,n){if(i&&i.call){var a=i;i=null}else a=o(t,i,"rangeFinder");"number"==typeof r&&(r=e.Pos(r,0));var l=o(t,i,"minFoldSize");function s(e){var o=a(t,r);if(!o||o.to.line-o.from.linet.firstLine();)r=e.Pos(r.line-1,0),d=s(!1);if(d&&!d.cleared&&"unfold"!==n){var c=function(e,t,r){var i=o(e,t,"widget");if("function"==typeof i&&(i=i(r.from,r.to)),"string"==typeof i){var n=document.createTextNode(i);(i=document.createElement("span")).appendChild(n),i.className="CodeMirror-foldmarker"}else i&&(i=i.cloneNode(!0));return i}(t,i,d);e.on(c,"mousedown",(function(t){u.clear(),e.e_preventDefault(t)}));var u=t.markText(d.from,d.to,{replacedWith:c,clearOnEnter:o(t,i,"clearOnEnter"),__isFold:!0});u.on("clear",(function(r,o){e.signal(t,"unfold",t,r,o)})),e.signal(t,"fold",t,d.from,d.to)}}e.newFoldFunction=function(e,r){return function(o,i){t(o,i,{rangeFinder:e,widget:r})}},e.defineExtension("foldCode",(function(e,r,o){t(this,e,r,o)})),e.defineExtension("isFolded",(function(e){for(var t=this.findMarksAt(e),r=0;r=0;l--){var s=n[l].from(),d=n[l].to();s.line>=i||(d.line>=i&&(d=o(i,0)),i=s.line,null==a?r.uncomment(s,d,e)?a="un":(r.lineComment(s,d,e),a="line"):"un"==a?r.uncomment(s,d,e):r.lineComment(s,d,e))}})),e.defineExtension("lineComment",(function(e,i,l){l||(l=t);var s=this,d=a(s,e),c=s.getLine(e.line);if(null!=c&&(u=e,p=c,!/\bstring\b/.test(s.getTokenTypeAt(o(u.line,0)))||/^[\'\"\`]/.test(p))){var u,p,h=l.lineComment||d.lineComment;if(h){var g=Math.min(0!=i.ch||i.line==e.line?i.line+1:i.line,s.lastLine()+1),m=null==l.padding?" ":l.padding,f=l.commentBlankLines||e.line==i.line;s.operation((function(){if(l.indent){for(var t=null,i=e.line;ia.length)&&(t=a)}for(i=e.line;ip||s.operation((function(){if(0!=l.fullLines){var t=r.test(s.getLine(p));s.replaceRange(h+u,o(p)),s.replaceRange(c+h,o(e.line,0));var a=l.blockCommentLead||d.blockCommentLead;if(null!=a)for(var g=e.line+1;g<=p;++g)(g!=p||t)&&s.replaceRange(a+h,o(g,0))}else{var m=0==i(s.getCursor("to"),n),f=!s.somethingSelected();s.replaceRange(u,n),m&&s.setSelection(f?n:s.getCursor("from"),n),s.replaceRange(c,e)}}))}}else(l.lineComment||d.lineComment)&&0!=l.fullLines&&s.lineComment(e,n,l)})),e.defineExtension("uncomment",(function(e,i,n){n||(n=t);var l,s=this,d=a(s,e),c=Math.min(0!=i.ch||i.line==e.line?i.line:i.line-1,s.lastLine()),u=Math.min(e.line,c),p=n.lineComment||d.lineComment,h=[],g=null==n.padding?" ":n.padding;e:if(p){for(var m=u;m<=c;++m){var f=s.getLine(m),b=f.indexOf(p);if(b>-1&&!/comment/.test(s.getTokenTypeAt(o(m,b+1)))&&(b=-1),-1==b&&r.test(f))break e;if(b>-1&&r.test(f.slice(0,b)))break e;h.push(f)}if(s.operation((function(){for(var e=u;e<=c;++e){var t=h[e-u],r=t.indexOf(p),i=r+p.length;r<0||(t.slice(i,i+g.length)==g&&(i+=g.length),l=!0,s.replaceRange("",o(e,r),o(e,i)))}})),l)return!0}var y=n.blockCommentStart||d.blockCommentStart,v=n.blockCommentEnd||d.blockCommentEnd;if(!y||!v)return!1;var x=n.blockCommentLead||d.blockCommentLead,w=s.getLine(u),k=w.indexOf(y);if(-1==k)return!1;var _=c==u?w:s.getLine(c),C=_.indexOf(v,c==u?k+y.length:0),S=o(u,k+1),E=o(c,C+1);if(-1==C||!/comment/.test(s.getTokenTypeAt(S))||!/comment/.test(s.getTokenTypeAt(E))||s.getRange(S,E,"\n").indexOf(v)>-1)return!1;var T=w.lastIndexOf(y,e.ch),A=-1==T?-1:w.slice(0,e.ch).indexOf(v,T+y.length);if(-1!=T&&-1!=A&&A+v.length!=e.ch)return!1;A=_.indexOf(v,i.ch);var O=_.slice(i.ch).lastIndexOf(y,A-i.ch);return T=-1==A||-1==O?-1:i.ch+O,(-1==A||-1==T||T==i.ch)&&(s.operation((function(){s.replaceRange("",o(c,C-(g&&_.slice(C-g.length,C)==g?g.length:0)),o(c,C+v.length));var e=k+y.length;if(g&&w.slice(e,e+g.length)==g&&(e+=g.length),s.replaceRange("",o(u,k),o(u,e)),x)for(var t=u+1;t<=c;++t){var i=s.getLine(t),n=i.indexOf(x);if(-1!=n&&!r.test(i.slice(0,n))){var a=n+x.length;g&&i.slice(a,a+g.length)==g&&(a+=g.length),s.replaceRange("",o(t,n),o(t,a))}}})),!0)}))}(CodeMirror),fi.prototype.start=function(e){return this.stream=e,this.line=0,this.string=e.string.slice(e.start),this.startLine=e.string,this.startPos=e.start,this},fi.prototype.startLinebreak=function(){return this.stream=null,this.line=this.startPos=0,this.string="\n",this.startLine="",this},fi.prototype.copy=function(){var e=this.copyInstance||(this.copyInstance=new fi);return e.stream=this.stream,e.startPos=this.startPos,e.line=this.line,e.startLine=this.startLine,e.string=this.string,e},fi.prototype.updateStart=function(){this.startLine=this.stream?0==this.line?this.stream.string:this.stream.lookAhead(this.line):"",this.startPos=this.startLine.length-(this.string.length-1)},fi.prototype.ahead=function(e){for(;;){if(e<=this.string.length)return!0;if(10!==this.string.charCodeAt(this.string.length-1))this.string+="\n";else{if(3===this.line||!this.stream||!this.stream.lookAhead)return!1;var t=this.stream.lookAhead(this.line+1);if(null==t)return!1;this.string+=t+"\n",this.line++}}};var bi=null;function yi(e,t){this.State=function(e,t){function r(e,t){this.stack=e,this.context=t}function o(){return null}return r.prototype.matchNext=function(t,r,o,i){for(var n=this.stack.length-1,a=this.stack[n],l=e.nodes[a],s=0;sr&&(bi=b)}else d=this.matchExpr(u,t,r),c=l[++s]}if(d<0){if(!(o>0&&s==l.length-1))continue;o--,d=r}if(this.go(c),!i&&-1===c||0===this.stack.length)return d;if(d>r)return d;if((d=this.matchNext(t,r,s==l.length-1?o:0,i))>=0)return d;this.stack.length=n+1,this.stack[n]=a}return-1},r.prototype.go=function(e){for(this.stack.pop();this.context&&this.context.depth>this.stack.length;)this.context=this.context.parent;-1!==e&&this.stack.push(e)},r.prototype.runMaybe=function(e,t,r){return bi=null,this.matchNext(e,t,r,!0)},r.prototype.forward=function(t,r){var o=this.runMaybe(t,r,2);return o<0&&(this.stack.push(e.token),o=this.runMaybe(t,r,0)),o},r.prototype.lookahead=function(e,t,r){var o=bi,i=new this.constructor([r],null);for(e=e.copy();;){e.updateStart();var n=i.runMaybe(e,t,0);if(n<0)return bi=o,!1;if(0===i.stack.length)return bi=o,!0;t=n}},r.prototype.matchExpr=function(e,r,i){if("string"==typeof e){var n=i+e.length;return r.ahead(n)&&r.string.slice(i,n)===e?n:-1}if(e.exec){var a=r.ahead(i+1)&&e.exec(i>0?r.string.slice(i):r.string);return a?i+a[0].length:-1}var l,s=e[0];if(0===s){for(var d=1;d-1)return u}return-1}if(2!==s&&3!==s){if(4===s)return Math.max(this.matchExpr(e[1],r,i),i);if(5===s)return this.lookahead(r,i,e[1])?i:-1;if(6===s)return this.lookahead(r,i,e[1])?-1:i;if(7===s){var p,h,g=i?r.string.lastIndexOf("\n",i-1):-1;if(r.stream&&g<0)p=r.stream.string,h=i+r.stream.start;else{var m=r.string.indexOf("\n",i);p=r.string.slice(g+1,m<0?r.string.length:m),h=i-(g+1)}return t.predicates[e[1]](p,h,this.context,r.stream?(l=r.stream,function(e){return l.lookAhead(e)}):o)?i:-1}throw Error("Unknown match type "+e)}if(3===s&&(i=this.matchExpr(e[1],r,i))<0)return-1;for(;;){var f=this.matchExpr(e[1],r,i);if(-1==f)return i;i=f}},r.prototype.contextAt=function(e,t){var r=this.copy(),o=new fi,i=0,n=this.context;for(o.string=e+"\n",o.startLine=e;;){var a=r.runMaybe(o,i,0);if(-1==a)return r.context;if(a>t){var l=r.context;if(i==t)e:for(;l;){for(var s=n;s;s=s.parent)if(s===l)break e;l=l.parent}return l}i=a,n=r.context}},r.prototype.copy=function(){return new this.constructor(this.stack.slice(),this.context)},r.start=function(){return new this([e.start],null)},r}(e,t||{}),this.mcx=new fi}CodeMirror.GrammarMode=yi,yi.prototype.startState=function(){return this.State.start()},yi.prototype.copyState=function(e){return e.copy()},yi.prototype.token=function(e,t){e.pos+=t.forward(this.mcx.start(e),0);for(var r=bi,o=t.context;o;o=o.parent)o.tokenType&&(r=o.tokenType+(r?" "+r:""));return e.eol()&&t.forward(this.mcx,e.pos-e.start),r},yi.prototype.blankLine=function(e){e.forward(this.mcx.startLinebreak(),0)},function(e,t){!function(e){var t=function(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}(e),r=[/^(?:var|let|const)(?![a-zA-Z¡-￿_0-9_\$])/,/^while(?![a-zA-Z¡-￿_0-9_\$])/,/^with(?![a-zA-Z¡-￿_0-9_\$])/,/^do(?![a-zA-Z¡-￿_0-9_\$])/,/^debugger(?![a-zA-Z¡-￿_0-9_\$])/,/^if(?![a-zA-Z¡-￿_0-9_\$])/,/^function(?![a-zA-Z¡-￿_0-9_\$])/,/^for(?![a-zA-Z¡-￿_0-9_\$])/,/^default(?![a-zA-Z¡-￿_0-9_\$])/,/^case(?![a-zA-Z¡-￿_0-9_\$])/,/^return(?![a-zA-Z¡-￿_0-9_\$])/,/^throw(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:break|continue)(?![a-zA-Z¡-￿_0-9_\$])/,/^switch(?![a-zA-Z¡-￿_0-9_\$])/,/^try(?![a-zA-Z¡-￿_0-9_\$])/,/^class(?![a-zA-Z¡-￿_0-9_\$])/,/^export(?![a-zA-Z¡-￿_0-9_\$])/,/^import(?![a-zA-Z¡-￿_0-9_\$])/,[0,"async",/^(?![a-zA-Z¡-￿_0-9_\$])/,[5,114]],[1,";",/^(?=\})/,[7,"canInsertSemi"]],/^[a-zA-Z¡-￿__\$][a-zA-Z¡-￿_0-9_\$]*/,/^extends(?![a-zA-Z¡-￿_0-9_\$])/,/^from(?![a-zA-Z¡-￿_0-9_\$])/,/^else(?![a-zA-Z¡-￿_0-9_\$])/,/^catch(?![a-zA-Z¡-￿_0-9_\$])/,/^finally(?![a-zA-Z¡-￿_0-9_\$])/,/^as(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:true|false|null|undefined|NaN|Infinity)(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:super|this)(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:delete|typeof|yield|await|void)(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:\.\.\.|\!|\+\+?|\-\-?)/,/^(?:0x[0-9a-fA-F_]+|0o[0-7_]+|0b[01_]+|(?:[0-9][0-9_]*(?:\.[0-9_]*)?|\.[0-9_]+)(?:[eE][\+\-]?[0-9_]+)?)/,/^\/(?![\/\*])(?:\\.|\[(?:(?!\]).)*\]|(?!\/).)+\/[gimyus]*/,/^(?:\+\+|\-\-)/,/^(?:(?:\+|\-|\%|\*|\/(?![\/\*])|\>\>?\>?|\<\",-1],[2,258,364,{name:"ParamList"}],[1,6,365],["=>",-1],[3,"operator","=>",367],[1,6,368],[2,129,-1,{name:"Block"},1,142,-1],[1,142,370,0,-1],[1,6,371],[",",372,0,-1],[1,6,373],[1,142,374,0,374],[1,6,371],[2,274,376,{name:"ObjectMember"},0,-1],[1,6,377],[",",378,0,-1],[1,6,379],[2,274,380,{name:"ObjectMember"},0,380],[1,6,377],[1,139,382],[1,6,383],[3,"operator","=",384,0,-1],[1,6,385],[1,142,-1],[3,"def",/^[a-zA-Z¡-￿__\$][a-zA-Z¡-￿_0-9_\$]*(?![a-z]|[A-Z]|[¡-￿]|_|[0-9]|_|\$| *\:)/,387,3,"property",r[20],391,3,"number",r[31],391,2,116,391,{name:"string",token:"string"},3,"operator","...",395],[1,6,388],[3,"operator","=",389,0,-1],[1,6,390],[1,142,-1],[1,6,392],[":",393],[1,6,394],[1,381,-1],[1,6,396],[1,381,-1]],start:0,token:5}),i=/(^|\s)variable($|\s)/;function n(e){var t=/^(if|for|do|while|try)\b/.exec(e.startLine.slice(e.startPos));return t&&t[1]}var a={Block:"}",BlockOf:"}",ClassBody:"}",AnnotationTypeBody:"}",ObjectLiteral:"}",ObjectPattern:"}",EnumBody:"}",LambdaBlock:"}",WhenBody:"}",ObjType:"}",ArrayInitializer:"}",NamespaceBlock:"}",BraceTokens:"}",ArrayLiteral:"]",BracketTokens:"]",TupleType:"]",ParamList:")",SimpleParamList:")",ArgList:")",ParenExpr:")",CondExpr:")",ForSpec:")",ParenTokens:")",ParenthesizedExpression:")",ConstructorParamList:")",TypeParams:">",TypeArgs:">",TemplateArgs:">",TemplateParams:">"},l=["Block","NamespaceBlock","ClassBody","AnnotationTypeBody","BlockOf","EnumBody"],s=["Statement","ObjectMember","ClassItem","EnumConstant","AnnotationTypeItem","ArgExpr","StatementMaybeOf","NewExpr"];function d(e,r){for(var o=e.startLine;;e=e.parent){if("CondExpr"==e.name)return t.countColumn(e.startLine,e.startPos+1,r.tabSize);if(s.indexOf(e.name)>-1&&/(^\s*|[\(\{\[])$/.test(e.startLine.slice(0,e.startPos)))return t.countColumn(e.startLine,e.startPos,r.tabSize);if(!e.parent||e.parent.startLine!=o)return t.countColumn(e.startLine,null,r.tabSize)}}function c(e,r,o){if(!e)return 0;if("string"==e.name||"comment"==e.name)return t.Pass;var i,p,h=a[e.name],g=r&&r.charAt(0)==h;if(h&&!1!==o.align&&(!o.dontAlign||o.dontAlign.indexOf(e.name)<0)&&function(e){return!/^\s*((\/\/.*)?$|.*=>)/.test(e.startLine.slice(e.startPos+1))}(e))return t.countColumn(e.startLine,e.startPos,o.tabSize)+(g?0:1);if(h&&l.indexOf(e.name)>-1){var m=e.parent;m&&"Statement"==m.name&&m.parent&&"Statement"==m.parent.name&&n(m.parent)&&!n(m)&&(m=m.parent);var f=u(m,o);return g||"NamespaceBlock"==e.name?f:/^(public|private|protected)\s*:/.test(r)?f+1:!(p=e.parent)||"Statement"!=p.name||!/^switch\b/.test(p.startLine.slice(p.startPos))||(i=r)&&/^\s*(case|default)\b/.test(i)?f+o.indentUnit:f+2*o.indentUnit}var b=d(e,o);return h?g&&(o.dontCloseBrackets||"").indexOf(h)<0?b:b+o.indentUnit*((o.doubleIndentBrackets||"").indexOf(h)<0?1:2):s.indexOf(e.name)>-1?n(e)?b+o.indentUnit:b+2*o.indentUnit:"Alternative"==e.name||"CatchFinally"==e.name?(b=d(e.parent,o),!r||/^((else|catch|finally)\b|\/[\/\*])/.test(r)?b:b+o.indentUnit):"ArrowRest"==e.name?b+o.indentUnit:"NewExpression"==e.name&&e.startLine.length>e.startPos+5?t.countColumn(e.startLine,e.startPos,o.tabSize)+2*o.indentUnit:"InitializerList"==e.name?b+2:"ThrowsClause"!=e.name||/throws\s*$/.test(e.startLine.slice(e.startPos))?c(e.parent,r,o):b+2*o.indentUnit}function u(e,r){for(;;e=e.parent){if(!e)return 0;if(s.indexOf(e.name)>-1||e.parent&&a[e.parent.name])return t.countColumn(e.startLine,null,r.tabSize)}}function p(e,r,o,i){var n=e.context&&e.context.name;if("DeclType"==n||"BeforeStatement"==n||"AnnotationHead"==n||"Template"==n||"str"==n)return u(e.context,i);if(("doccomment.braced"==n||"doccomment.tagGroup"==n)&&!/^[@*]/.test(r))return t.countColumn(e.context.startLine,null,i.tabSize)+2*i.indentUnit;var a=i.forceContent&&/^\s*(\/\/.*)?$/.test(o)?"x":o;return c(e.contextAt(a,o.length-r.length),r,i)}function h(e,t){for(var r=t-1;r>=0;r--){var o=e.charCodeAt(r);if(10===o)break;if(32!==o&&9!==o)return!1}return!0}var g=function(e){this.config=e};g.prototype.startState=function(){return new m},g.prototype.copyState=function(e){return e.copy()},g.prototype.shouldInterceptTokenizing=function(e){var t=e.currentTemplateState;return void 0!==t&&null!==t.mode},g.prototype.interceptTokenizing=function(e,t){if(e.match("${")&&(e.backUp(2),!this.isEscaped(e,e.pos-2)))return{handled:!1};if("`"===e.peek()&&!this.isEscaped(e,e.pos))return{handled:!1};var r=t.currentTemplateState,o=r.mode,i=r.state,n=o.token(e,i);return this.backupIfEmbeddedTokenizerOvershot(e),{handled:!0,style:n}},g.prototype.trackState=function(e,t,r){if(e){var o=r.currentTemplateState;o&&"inline-expression"!==o.kind?this.trackStateInTemplate(e,t,r,o):this.trackStateNotInTemplate(e,t,r,o),r.previousVariable="variable"===e?t.current():null}},g.prototype.trackStateNotInTemplate=function(e,t,r,o){if(o&&"string-2"===e&&t.current().startsWith("}"))return r.templateStack.pop(),void t.backUp(t.current().length-1);if("string-2"===e&&t.current().startsWith("`")){var i=this.getModeForTemplateTag(r.previousVariable),n="template";i?(t.backUp(t.current().length-1),r.templateStack.push(new b(n,i,CodeMirror.startState(i)))):r.templateStack.push(new b(n,null,null))}},g.prototype.trackStateInTemplate=function(e,t,r,o){"string-2"!==e||!t.current().endsWith("`")||this.isEscaped(t.pos-1)?"string-2"!==e||!t.current().endsWith("${")||this.isEscaped(t.pos-2)||r.templateStack.push(new b("inline-expression",null,null)):r.templateStack.pop()},g.prototype.backupIfEmbeddedTokenizerOvershot=function(e){for(var t=e.current(),r=0;;){var o=t.slice(r).search(/`|\$\{/);if(-1===o)return;o+=r;var i=t.length-o,n=e.pos-i;if(!this.isEscaped(e,n))return void e.backUp(t.length-o);r=o+1}},g.prototype.isEscaped=function(e,t){for(var r=!1,o=t;o>0&&"\\"===e.string[o-1];)r=!r,o--;return r},g.prototype.getModeForTemplateTag=function(e){if(!e)return null;"htm"===e&&(e="html");for(var t=["google-"+e,""+e],r=0;r)",dontCloseBrackets:")",tabSize:t.tabSize,indentUnit:t.indentUnit,forceContent:!0}}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.startState=function(){var t=e.prototype.startState.call(this);return t.embeddedParserState=this.embeddedParser.startState(),t},t.prototype.copyState=function(t){var r=e.prototype.copyState.call(this,t);return r.embeddedParserState=this.embeddedParser.copyState(t.embeddedParserState),r},t.prototype.token=function(t,r){var o=r.embeddedParserState;if(this.embeddedParser.shouldInterceptTokenizing(o)){var n=this.embeddedParser.interceptTokenizing(t,o),a=n.handled,l=n.style;if(a)return l}var s=e.prototype.token.call(this,t,r);return this.embeddedParser.trackState(s,t,o),function(e,t,r,o){if("def"==e){var n=function(e,t){for(var r=e;r;r=r.parent)if(t.indexOf(r.name)>-1)return r}(o.context,t),a=r.current();if(n&&(n.locals||(n.locals=[]),-1==n.locals.indexOf(a)&&n.locals.push(a),"funcName"!=o.context.name))return"def local"}else i.test(e)&&!/qualified/.test(e)&&function(e,t){for(var r=e;r;r=r.parent)if(r.locals&&r.locals.indexOf(t)>-1)return!0;return!1}(o.context,r.current())&&(e=e.replace(i,"$1variable-2$2"));return e}(s,y,t,r)},t.prototype.indent=function(e,t,r){return t||(t=r="x"),p(e,t,r,this.indentConf)},t}(t.GrammarMode),x={electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``"};for(var w in x)v.prototype[w]=x[w];t.registerHelper("wordChars","google-javascript",/[\w$]/),t.defineMode("google-javascript",(function(e,t){return new v(e,t)}))}((e="undefined"!=typeof globalThis?globalThis:e||self).CodeMirror)}(window),function(e,t){!function(e){var t=function(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}(e),r=[/^(?:var|let|const)(?![a-zA-Z¡-￿_0-9_\$])/,/^while(?![a-zA-Z¡-￿_0-9_\$])/,/^with(?![a-zA-Z¡-￿_0-9_\$])/,/^do(?![a-zA-Z¡-￿_0-9_\$])/,/^debugger(?![a-zA-Z¡-￿_0-9_\$])/,/^if(?![a-zA-Z¡-￿_0-9_\$])/,/^function(?![a-zA-Z¡-￿_0-9_\$])/,/^for(?![a-zA-Z¡-￿_0-9_\$])/,/^default(?![a-zA-Z¡-￿_0-9_\$])/,/^case(?![a-zA-Z¡-￿_0-9_\$])/,/^return(?![a-zA-Z¡-￿_0-9_\$])/,/^throw(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:break|continue)(?![a-zA-Z¡-￿_0-9_\$])/,/^switch(?![a-zA-Z¡-￿_0-9_\$])/,/^try(?![a-zA-Z¡-￿_0-9_\$])/,/^class(?![a-zA-Z¡-￿_0-9_\$])/,/^export(?![a-zA-Z¡-￿_0-9_\$])/,/^import(?![a-zA-Z¡-￿_0-9_\$])/,[0,"async",/^(?![a-zA-Z¡-￿_0-9_\$])/,[5,139]],/^[a-zA-Z¡-￿__\$][a-zA-Z¡-￿_0-9_\$]*/,/^extends(?![a-zA-Z¡-￿_0-9_\$])/,/^enum(?![a-zA-Z¡-￿_0-9_\$])/,[1,";",/^(?=\})/,[7,"canInsertSemi"]],/^from(?![a-zA-Z¡-￿_0-9_\$])/,[1,"\n","\t"," "],/^[a-zA-Z¡-￿__\$]/,/^const(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:true|false|null|undefined|NaN|Infinity)(?![a-zA-Z¡-￿_0-9_\$])/,/^new(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:0x[0-9a-fA-F_]+|0o[0-7_]+|0b[01_]+|(?:[0-9][0-9_]*(?:\.[0-9_]*)?|\.[0-9_]+)(?:[eE][\+\-]?[0-9_]+)?)/,/^else(?![a-zA-Z¡-￿_0-9_\$])/,/^catch(?![a-zA-Z¡-￿_0-9_\$])/,/^finally(?![a-zA-Z¡-￿_0-9_\$])/,/^as(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:super|this)(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:delete|typeof|yield|await|void)(?![a-zA-Z¡-￿_0-9_\$])/,/^(?:\.\.\.|\!|\+\+?|\-\-?)/,/^\/(?![\/\*])(?:\\.|\[(?:(?!\]).)*\]|(?!\/).)+\/[gimyus]*/,[0,/^[a-zA-Z¡-￿__\$]/,/^[a-zA-Z¡-￿_0-9_\$]*/,[5,508]],/^(?:\+\+|\-\-)/,/^(?:(?:\+|\-|\%|\*|\/(?![\/\*])|\>\>?\>?|\<\",-1],[3,"keyword",/^this(?![a-zA-Z¡-￿_0-9_\$])/,209,3,"atom",r[27],209,3,"keyword",/^typeof(?![a-zA-Z¡-￿_0-9_\$])/,177,3,"keyword",/^(?:keyof|readonly|unique)(?![a-zA-Z¡-￿_0-9_\$])/,178,[0,[5,393],"("],179,3,"keyword",r[28],180,0,180,0,181,2,396,209,{name:"TupleType"},2,233,209,{name:"ObjType"},2,141,209,{name:"string",token:"string"},3,"number",r[29],209],[1,6,182],[1,6,183],[1,6,184],[1,6,185],[[5,401],186,3,"type",r[19],187],[3,"variable",r[19],188],[1,176,209],[1,176,189],[2,171,190,{name:"TypeParams"},0,190],[3,"variable",r[19],191],[1,6,192],[1,6,193],[1,6,194],[1,6,195],[1,6,196],[2,404,209,{name:"TypeArgs"},0,209],[".",197,"[",198,0,209],[")",209],[2,409,199,{name:"ParamListSpec"}],[".",200],[1,6,201],[1,6,202],[1,6,203],[1,6,181],[3,"property",r[19],204],[1,165,205],[3,"operator","=>",206],[1,6,193],[1,6,207],[1,6,208],["]",204],[1,410,209],[1,6,210],[3,"operator",/^[\&\|]/,211,3,"keyword",r[20],211,"[",212,3,"operator","?",213,0,-1],[1,6,214],[1,6,215],[1,6,216],[1,176,217],[1,176,218,0,218],[1,176,219],[1,6,210],[1,6,220],[1,6,221],["]",217],[3,"operator",":",222],[1,6,223],[1,176,217],[r[19],225],[1,6,226],[".",-1],[1,176,228,0,-1],[1,6,229],[",",230,0,-1],[1,6,231],[1,176,232,0,232],[1,6,229],["{",234],[1,6,235],[1,416,236,0,236],[1,6,237],[/^[\,\;]/,238,"}",-1],[1,6,239],[1,416,240,0,240],[1,6,237],["{",242],[1,6,243],[1,449,244],[1,6,245],["}",-1],[1,463,247],[1,6,248],[3,"operator","!",249,0,249],[1,6,250],[":",251,0,253],[1,6,252],[1,176,253],[1,6,254],[3,"operator","=",255,0,-1],[1,6,256],[1,367,-1],["(",258],[1,6,259],[1,165,260],[1,6,261],[")",-1],[1,6,263],[3,"keyword",r[30],264,0,-1],[1,6,265],[2,7,-1,{name:"Statement"}],[2,171,267,{name:"TypeParams"},0,267],[1,6,268],[2,466,269,{name:"ParamList"}],[1,6,270],[":",271,0,273],[1,6,272],[1,410,273],[1,6,274],[2,161,-1,{name:"Block"},r[22],-1],[2,471,276,{name:"ForSpec"}],[1,6,277],[2,7,-1,{name:"Statement"}],[3,"keyword",r[31],279,0,287],[1,6,280],["(",281,0,282],[1,6,283],[1,6,284],[1,463,285],[2,161,287,{name:"Block"}],[1,6,286],[")",282],[1,6,288],[3,"keyword",r[32],289,0,-1],[1,6,290],[2,161,-1,{name:"Block"}],[2,171,292,{name:"TypeParams"},0,292],[1,6,293],[3,"keyword",r[20],294,0,296],[1,6,295],[1,176,296],[1,6,297],[3,"keyword",/^implements(?![a-zA-Z¡-￿_0-9_\$])/,298,0,300],[1,6,299],[1,227,300],[1,6,301],[2,482,-1,{name:"ClassBody"}],[1,308,303,0,-1],[1,6,304],[",",305,0,-1],[1,6,306],[1,308,307,0,307],[1,6,304],[3,"variable",/^[a-zA-Z¡-￿__\$][a-zA-Z¡-￿_0-9_\$]*(?= +as)/,309,3,"def",r[19],-1],[1,6,310],[3,"keyword",r[33],311],[1,6,312],[3,"def",r[19],-1],[0,314,2,490,-1,{name:"doccomment.braced"}],[[0,/^(?!\*\/|\@[a-zA-Z¡-￿_0-9]|\{)/,/^[^]/],315],[0,314,0,-1],[1,494,317],[1,313,317,0,-1],["\\",319,"\n",-1],[/^[^]/,-1],["<",321,3,"atom",r[27],-1,3,"keyword",r[34],-1,3,"keyword",r[35],327,3,"operator",r[36],327,3,"keyword",r[18],327,3,"keyword",r[28],329,3,"keyword",r[6],335,3,"keyword",r[15],341,2,500,-1,{name:"ArrowFunc"},3,"variable callee",r[38],346,3,"variable",r[19],-1,3,"number",r[29],-1,2,141,-1,{name:"string",token:"string"},3,"string-2",r[37],-1,1,150,-1,2,512,-1,{name:"ArrayLiteral"},2,517,-1,{name:"ObjectLiteral"},2,522,-1,{name:"ParenExpr"}],[1,6,322],[1,176,323],[1,6,324],[">",325],[1,6,326],[1,320,-1],[1,6,328],[1,320,-1],[1,6,330],[".",331,3,"variable callee",r[38],332,1,320,-1],[1,6,333],[1,6,334],[3,"keyword",/^target(?![a-zA-Z¡-￿_0-9_\$])/,-1],[2,404,-1,{name:"TypeArgs"},0,-1],[1,6,336],[3,"keyword","*",337,0,337],[1,6,338],[3,"def",r[19],339,0,339],[1,6,340],[2,266,-1,{name:"FunctionDef"}],[1,6,342],[[6,527],343,0,344],[3,"def type",r[19],344],[1,6,345],[1,291,-1],[1,6,347],[2,404,-1,{name:"TypeArgs"},0,-1],[3,"keyword",r[33],349,3,"operator","!",-1,3,"operator",r[39],-1,3,"operator",r[40],351,3,"keyword",r[41],351,2,528,-1,{name:"ArgList"},1,150,-1,r[43],353,"[",357,3,"operator","?",361],[1,6,350],[1,176,-1],[1,6,352],[1,165,-1],[1,6,354],[3,"property callee",r[44],355,3,"property",r[19],-1],[1,6,356],[2,404,-1,{name:"TypeArgs"},0,-1],[1,6,358],[1,165,359],[1,6,360],["]",-1],[1,6,362],[1,165,363],[1,6,364],[3,"operator",":",365],[1,6,366],[1,165,-1],[1,320,368],[1,6,369],[1,537,370,0,-1],[1,6,369],[3,"def type",r[19],372,0,-1],[1,6,373],[3,"keyword",r[20],374,0,375],[1,6,376],[1,6,377],[1,176,375],[3,"operator","=",378,0,379],[1,6,380],[1,6,381],[1,176,379],[",",382,0,-1],[1,6,383],[3,"def type",r[19],384,0,385],[1,6,386],[1,6,381],[3,"keyword",r[20],387,0,388],[1,6,389],[1,6,390],[1,176,388],[3,"operator","=",391,0,385],[1,6,392],[1,176,385],["(",394],[1,6,395],[[6,556],-1],["[",397],[1,6,398],[1,559,399],[1,6,400],["]",-1],[r[19],402],[1,6,403],[".",-1],["<",405],[1,6,406],[1,227,407],[1,6,408],[">",-1],[2,466,-1,{name:"ParamList"}],[[5,573],411,0,414],[3,"variable",r[19],412],[1,6,413],[3,"keyword",r[46],414],[1,6,415],[1,176,-1],[3,"keyword",r[28],417,0,417,0,425],[1,6,418],[2,171,419,{name:"TypeParams"},0,419],[1,6,420],[2,466,421,{name:"ParamList"}],[1,6,422],[":",423,0,-1],[1,6,424],[1,410,-1],[3,"keyword",r[42],426,"[",427,3,"def property",r[19],428,2,141,428,{name:"string",token:"string"},3,"number",r[29],428],[1,6,425],[1,6,429],[1,6,430],[[0,[5,576],/^[a-zA-Z¡-￿__\$]/,/^[a-zA-Z¡-￿_0-9_\$]*/],431,1,165,432],[/^\??/,433],[1,6,434],[1,6,435],[1,6,436],[":",437,3,"keyword",/^in(?![a-zA-Z¡-￿_0-9_\$])/,437],["]",438],[2,171,439,{name:"TypeParams"},0,439,0,440],[1,6,441],[1,6,442],[1,6,443],[1,6,444],[1,176,432],[":",445],[2,466,440,{name:"ParamList"}],[":",446,0,-1],[1,6,447],[1,6,448],[1,176,-1],[1,410,-1],[3,"def property",r[19],450,0,-1],[1,6,451],[3,"operator","=",452,0,453],[1,6,454],[1,6,455],[1,367,453],[",",456,0,-1],[1,6,457],[3,"def property",r[19],458,0,459],[1,6,460],[1,6,455],[3,"operator","=",461,0,459],[1,6,462],[1,367,459],[3,"operator","...",464,0,464],[1,6,465],[3,"def",r[19],-1,2,579,-1,{name:"ArrayPattern"},2,584,-1,{name:"ObjectPattern"}],["(",467],[1,6,468],[1,589,469],[1,6,470],[")",-1],["(",472],[1,6,473],[2,629,474,{name:"StatementMaybeOf"}],[1,6,475],[1,165,476,0,476,0,480],[1,6,477],[";",478],[1,6,479],[1,165,480,0,480],[1,6,481],[")",-1],["{",483],[1,6,484],[0,485,"@",486,"}",-1],[3,"keyword",r[42],487,3,"keyword",[0,"override",/^(?![a-zA-Z¡-￿_0-9_\$])/,[5,634]],487,2,635,488,{name:"ClassItem"}],[1,6,489],[1,6,485],[1,6,484],[1,165,488],["{",491],[1,494,492,1,313,493],[[0,/^(?!\}|\*\/)/,/^[^]/],492,0,493],[/^(?:\}|(?=\*\/))/,-1],[3,"tag",/^\@(?:member|param|arg(?:ument)?|module|namespace|typedef)(?![a-zA-Z¡-￿_0-9])/,495,3,"tag",/^\@[a-zA-Z¡-￿_0-9]+/,-1],[r[24],495,"{",496,0,497,0,-1],[2,656,498,{name:"doccomment.type"}],[3,"def",/^[a-zA-Z¡-￿_0-9]+/,-1,0,-1],["}",499],[[1,"\n","\t"," ",/^\*(?!\/)/],499,0,497],[3,"def",[0,/^[a-zA-Z¡-￿__\$]/,/^[a-zA-Z¡-￿_0-9_\$]*/,[5,660]],506,[5,666],501],[2,466,502,{name:"ParamList"}],[1,6,503],[":",504,0,506],[1,6,505],[1,410,506],[1,6,507],[2,673,-1,{name:"ArrowRest"}],[/^\<(?! )/,-1,/^ */,509],[1,678,510,0,511],[/^ */,511],["(",-1],["[",513],[1,6,514],[1,680,515],[1,6,516],["]",-1],["{",518],[1,6,519],[1,686,520],[1,6,521],["}",-1],["(",523],[1,6,524],[1,165,525],[1,6,526],[")",-1],[3,"keyword",r[20],-1],["(",529],[1,6,530],[1,680,531],[1,6,532],[")",-1],[/^ */,534],[1,678,535,0,536],[/^ */,536],["(",-1],[3,"keyword",r[33],538,3,"operator","!",-1,3,"operator",r[39],-1,3,"operator",r[40],540,3,"keyword",r[41],540,2,528,-1,{name:"ArgList"},1,150,-1,r[43],542,"[",546,3,"operator","?",550],[1,6,539],[1,176,-1],[1,6,541],[1,367,-1],[1,6,543],[3,"property callee",r[44],544,3,"property",r[19],-1],[1,6,545],[2,404,-1,{name:"TypeArgs"},0,-1],[1,6,547],[1,165,548],[1,6,549],["]",-1],[1,6,551],[1,165,552],[1,6,553],[3,"operator",":",554],[1,6,555],[1,367,-1],[/^(?:\)|\.\.\.)/,-1,r[19],557],[1,6,558],[/^[\?\:]/,-1],[r[45],560,0,561,0,-1],[1,6,562],[1,6,563],[":",561],[1,176,564],[1,6,565],[",",566,0,-1],[1,6,567],[r[45],568,0,569,0,570],[1,6,571],[1,6,572],[1,6,565],[":",569],[1,176,570],[r[19],574],[1,6,575],[3,"keyword",r[46],-1],[r[19],577],[1,6,578],[/^(?:\:|in)/,-1],["[",580],[1,6,581],[1,692,582],[1,6,583],["]",-1],["{",585],[1,6,586],[1,698,587],[1,6,588],["}",-1],["@",590,0,591,0,-1],[1,6,592],[3,"keyword",r[42],593,r[47],594],[1,165,595],[1,6,591],[1,6,596],[1,6,589],[1,463,597],[1,6,598],[/^\??/,599],[1,6,600],[":",601,0,602],[1,6,603],[1,6,604],[1,176,602],[3,"operator","=",605,0,606],[1,6,607],[1,6,608],[1,367,606],[",",609,0,-1],[1,6,610],["@",611,0,612,0,613],[1,6,614],[3,"keyword",r[42],615,r[47],616],[1,6,608],[1,165,617],[1,6,612],[1,6,618],[1,6,610],[1,463,619],[1,6,620],[/^\??/,621],[1,6,622],[":",623,0,624],[1,6,625],[1,6,626],[1,176,624],[3,"operator","=",627,0,613],[1,6,628],[1,367,613],[2,7,630,{name:"Statement"}],[1,6,631],[3,"keyword",/^of(?![a-zA-Z¡-￿_0-9_\$])/,632,0,-1],[1,6,633],[1,165,-1],[r[24],634,r[25],-1],[3,"keyword",r[48],636,0,636],[1,6,637],[3,"def property",r[19],642,"[",638,3,"number",r[29],642,2,141,642,{name:"string",token:"string"}],[1,6,639],[1,165,640],[1,6,641],["]",642],[1,6,643],[3,"keyword","*",644,0,644,/^[\!\?]?/,645],[1,6,646],[1,6,647],[2,266,-1,{name:"FunctionDef"}],[":",648,0,649],[1,6,650],[1,6,651],[1,176,649],[3,"operator","=",652,0,653],[1,6,654],[1,6,655],[1,165,653],[r[22],-1],[3,"type","{",657,3,"type",/^(?:(?!\{|\}|\*\/).)+/,656,"\n",658,0,-1],[2,656,659,{name:"doccomment.type"}],[/^[\t ]*(?:\*(?!\/)[\t ]*)?/,656],[/^(?=\*\/)/,656,3,"type","}",656],[1,6,661],[":",662,0,665],[1,6,663],[1,176,664],[1,6,665],["=>",-1],[2,466,667,{name:"ParamList"}],[1,6,668],[":",669,0,671],[1,6,670],[1,410,671],[1,6,672],["=>",-1],[3,"operator","=>",674],[1,6,675],[2,171,676,{name:"TypeParams"},0,676],[1,6,677],[2,161,-1,{name:"Block"},1,367,-1],["<",679],[1,678,679,[1,"=>",[0,/^(?!\>)/,/^[^]/]],679,">",-1],[1,367,681,0,-1],[1,6,682],[",",683,0,-1],[1,6,684],[1,367,685,0,685],[1,6,682],[2,704,687,{name:"ObjectMember"},0,-1],[1,6,688],[",",689,0,-1],[1,6,690],[2,704,691,{name:"ObjectMember"},0,691],[1,6,688],[1,719,693,0,693,0,-1],[1,6,694],[",",695,0,-1],[1,6,696],[1,719,697,0,697,0,697],[1,6,694],[1,724,699,0,-1],[1,6,700],[",",701,0,-1],[1,6,702],[1,724,703,0,703],[1,6,700],[3,"keyword",r[48],705,0,705],[1,6,706],[3,"keyword","*",707,0,707],[1,6,708],[3,"def property",r[19],709,"[",710,3,"number",r[29],709,2,141,709,{name:"string",token:"string"},3,"operator","...",711],[1,6,712],[1,6,713],[1,6,714],[2,266,-1,{name:"FunctionDef"},":",715,0,-1],[1,165,716],[1,367,-1],[1,6,717],[1,6,718],[1,367,-1],["]",709],[1,463,720],[1,6,721],[3,"operator","=",722,0,-1],[1,6,723],[1,367,-1],[3,"def",/^[a-zA-Z¡-￿__\$][a-zA-Z¡-￿_0-9_\$]*(?![a-z]|[A-Z]|[¡-￿]|_|[0-9]|_|\$| *\:)/,725,3,"property",r[19],729,3,"number",r[29],729,2,141,729,{name:"string",token:"string"},3,"operator","...",733],[1,6,726],[3,"operator","=",727,0,-1],[1,6,728],[1,367,-1],[1,6,730],[":",731],[1,6,732],[1,719,-1],[1,6,734],[1,719,-1]],start:0,token:5}),i=/(^|\s)variable($|\s)/;function n(e){var t=/^(if|for|do|while|try)\b/.exec(e.startLine.slice(e.startPos));return t&&t[1]}var a={Block:"}",BlockOf:"}",ClassBody:"}",AnnotationTypeBody:"}",ObjectLiteral:"}",ObjectPattern:"}",EnumBody:"}",LambdaBlock:"}",WhenBody:"}",ObjType:"}",ArrayInitializer:"}",NamespaceBlock:"}",BraceTokens:"}",ArrayLiteral:"]",BracketTokens:"]",TupleType:"]",ParamList:")",SimpleParamList:")",ArgList:")",ParenExpr:")",CondExpr:")",ForSpec:")",ParenTokens:")",ParenthesizedExpression:")",ConstructorParamList:")",TypeParams:">",TypeArgs:">",TemplateArgs:">",TemplateParams:">"},l=["Block","NamespaceBlock","ClassBody","AnnotationTypeBody","BlockOf","EnumBody"],s=["Statement","ObjectMember","ClassItem","EnumConstant","AnnotationTypeItem","ArgExpr","StatementMaybeOf","NewExpr"];function d(e,r){for(var o=e.startLine;;e=e.parent){if("CondExpr"==e.name)return t.countColumn(e.startLine,e.startPos+1,r.tabSize);if(s.indexOf(e.name)>-1&&/(^\s*|[\(\{\[])$/.test(e.startLine.slice(0,e.startPos)))return t.countColumn(e.startLine,e.startPos,r.tabSize);if(!e.parent||e.parent.startLine!=o)return t.countColumn(e.startLine,null,r.tabSize)}}function c(e,r,o){if(!e)return 0;if("string"==e.name||"comment"==e.name)return t.Pass;var i,p,h=a[e.name],g=r&&r.charAt(0)==h;if(h&&!1!==o.align&&(!o.dontAlign||o.dontAlign.indexOf(e.name)<0)&&function(e){return!/^\s*((\/\/.*)?$|.*=>)/.test(e.startLine.slice(e.startPos+1))}(e))return t.countColumn(e.startLine,e.startPos,o.tabSize)+(g?0:1);if(h&&l.indexOf(e.name)>-1){var m=e.parent;m&&"Statement"==m.name&&m.parent&&"Statement"==m.parent.name&&n(m.parent)&&!n(m)&&(m=m.parent);var f=u(m,o);return g||"NamespaceBlock"==e.name?f:/^(public|private|protected)\s*:/.test(r)?f+1:!(p=e.parent)||"Statement"!=p.name||!/^switch\b/.test(p.startLine.slice(p.startPos))||(i=r)&&/^\s*(case|default)\b/.test(i)?f+o.indentUnit:f+2*o.indentUnit}var b=d(e,o);return h?g&&(o.dontCloseBrackets||"").indexOf(h)<0?b:b+o.indentUnit*((o.doubleIndentBrackets||"").indexOf(h)<0?1:2):s.indexOf(e.name)>-1?n(e)?b+o.indentUnit:b+2*o.indentUnit:"Alternative"==e.name||"CatchFinally"==e.name?(b=d(e.parent,o),!r||/^((else|catch|finally)\b|\/[\/\*])/.test(r)?b:b+o.indentUnit):"ArrowRest"==e.name?b+o.indentUnit:"NewExpression"==e.name&&e.startLine.length>e.startPos+5?t.countColumn(e.startLine,e.startPos,o.tabSize)+2*o.indentUnit:"InitializerList"==e.name?b+2:"ThrowsClause"!=e.name||/throws\s*$/.test(e.startLine.slice(e.startPos))?c(e.parent,r,o):b+2*o.indentUnit}function u(e,r){for(;;e=e.parent){if(!e)return 0;if(s.indexOf(e.name)>-1||e.parent&&a[e.parent.name])return t.countColumn(e.startLine,null,r.tabSize)}}function p(e,r,o,i){var n=e.context&&e.context.name;if("DeclType"==n||"BeforeStatement"==n||"AnnotationHead"==n||"Template"==n||"str"==n)return u(e.context,i);if(("doccomment.braced"==n||"doccomment.tagGroup"==n)&&!/^[@*]/.test(r))return t.countColumn(e.context.startLine,null,i.tabSize)+2*i.indentUnit;var a=i.forceContent&&/^\s*(\/\/.*)?$/.test(o)?"x":o;return c(e.contextAt(a,o.length-r.length),r,i)}function h(e,t){for(var r=t-1;r>=0;r--){var o=e.charCodeAt(r);if(10===o)break;if(32!==o&&9!==o)return!1}return!0}var g=function(e){this.config=e};g.prototype.startState=function(){return new m},g.prototype.copyState=function(e){return e.copy()},g.prototype.shouldInterceptTokenizing=function(e){var t=e.currentTemplateState;return void 0!==t&&null!==t.mode},g.prototype.interceptTokenizing=function(e,t){if(e.match("${")&&(e.backUp(2),!this.isEscaped(e,e.pos-2)))return{handled:!1};if("`"===e.peek()&&!this.isEscaped(e,e.pos))return{handled:!1};var r=t.currentTemplateState,o=r.mode,i=r.state,n=o.token(e,i);return this.backupIfEmbeddedTokenizerOvershot(e),{handled:!0,style:n}},g.prototype.trackState=function(e,t,r){if(e){var o=r.currentTemplateState;o&&"inline-expression"!==o.kind?this.trackStateInTemplate(e,t,r,o):this.trackStateNotInTemplate(e,t,r,o),r.previousVariable="variable"===e?t.current():null}},g.prototype.trackStateNotInTemplate=function(e,t,r,o){if(o&&"string-2"===e&&t.current().startsWith("}"))return r.templateStack.pop(),void t.backUp(t.current().length-1);if("string-2"===e&&t.current().startsWith("`")){var i=this.getModeForTemplateTag(r.previousVariable),n="template";i?(t.backUp(t.current().length-1),r.templateStack.push(new b(n,i,CodeMirror.startState(i)))):r.templateStack.push(new b(n,null,null))}},g.prototype.trackStateInTemplate=function(e,t,r,o){"string-2"!==e||!t.current().endsWith("`")||this.isEscaped(t.pos-1)?"string-2"!==e||!t.current().endsWith("${")||this.isEscaped(t.pos-2)||r.templateStack.push(new b("inline-expression",null,null)):r.templateStack.pop()},g.prototype.backupIfEmbeddedTokenizerOvershot=function(e){for(var t=e.current(),r=0;;){var o=t.slice(r).search(/`|\$\{/);if(-1===o)return;o+=r;var i=t.length-o,n=e.pos-i;if(!this.isEscaped(e,n))return void e.backUp(t.length-o);r=o+1}},g.prototype.isEscaped=function(e,t){for(var r=!1,o=t;o>0&&"\\"===e.string[o-1];)r=!r,o--;return r},g.prototype.getModeForTemplateTag=function(e){if(!e)return null;"htm"===e&&(e="html");for(var t=["google-"+e,""+e],r=0;r)",dontCloseBrackets:")",tabSize:t.tabSize,indentUnit:t.indentUnit,forceContent:!0}}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.startState=function(){var t=e.prototype.startState.call(this);return t.embeddedParserState=this.templateTokenizer.startState(),t},t.prototype.copyState=function(t){var r=e.prototype.copyState.call(this,t);return r.embeddedParserState=this.templateTokenizer.copyState(t.embeddedParserState),r},t.prototype.token=function(t,r){var o=r.embeddedParserState;if(this.templateTokenizer.shouldInterceptTokenizing(o)){var n=this.templateTokenizer.interceptTokenizing(t,o),a=n.handled,l=n.style;if(a)return l}var s=e.prototype.token.call(this,t,r);return this.templateTokenizer.trackState(s,t,o),function(e,t,r,o){if("def"==e){var n=function(e,t){for(var r=e;r;r=r.parent)if(t.indexOf(r.name)>-1)return r}(o.context,t),a=r.current();if(n&&(n.locals||(n.locals=[]),-1==n.locals.indexOf(a)&&n.locals.push(a),"funcName"!=o.context.name))return"def local"}else i.test(e)&&!/qualified/.test(e)&&function(e,t){for(var r=e;r;r=r.parent)if(r.locals&&r.locals.indexOf(t)>-1)return!0;return!1}(o.context,r.current())&&(e=e.replace(i,"$1variable-2$2"));return e}(s,y,t,r)},t.prototype.indent=function(e,t,r){return t||(t=r="x"),p(e,t,r,this.indentConf)},t}(t.GrammarMode),x={electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``"};for(var w in x)v.prototype[w]=x[w];t.registerHelper("wordChars","google-typescript",/[\w$]/),t.defineMode("google-typescript",(function(e,t){return new v(e,t)}))}((e="undefined"!=typeof globalThis?globalThis:e||self).CodeMirror)}(window),function(e,t){!function(e){var t=function(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}(e),r=[[1,"\n","\t"," "],/^[a-zA-Z\-\.0-9_]+/],o=Object.freeze({__proto__:null,nodes:[[1,3,0,0,1],[/^[^]/,0],[/^[^]/,-1],[2,4,-1,{name:"comment",token:"comment"},2,6,-1,{name:"doctype",token:"meta"},2,8,-1,{name:"tag"},3,"atom",/^\&(?:(?![\;\n\t ]).)*\;/,-1,[1,"\n",/^(?:(?![\&\<]).)+/],-1],["\x3c!--",5],[[0,/^(?!\-\-\>)/,/^[^]/],5,"--\x3e",-1],[/^(?:\<\!doctype|\<\!DOCTYPE)(?![a-zA-Z\-\.0-9_])/,7],[[0,/^(?!\>)/,/^[^]/],7,">",-1],[2,14,9,{name:"openTag"}],[3,"tag","/>",-1,[7,"selfClosing"],10,3,"tag",">",11],[3,"tag",">",-1],[1,3,11,/^(?=\<\/)/,12],[[7,"matchingTag"],13,0,-1],[2,21,-1,{name:"closeTag"}],[3,"tag",[0,"<",[6,24]],15],[r[0],15,3,"tag",r[1],16],[r[0],16,0,17],[3,"attribute",r[1],18,0,-1],[r[0],18,"=",19,0,20],[r[0],19,2,25,20,{name:"attributeValue",token:"string"}],[r[0],20,0,17],[3,"tag","",-1],[r[0],24,"/",-1],['"',26,"'",27,/^(?:(?![\n\t \>]).)*/,-1],[[0,/^(?!\")/,/^[^]/],26,'"',-1],[[0,/^(?!\')/,/^[^]/],27,"'",-1]],start:0,token:2});function i(e){var t=/^\s*([\w_\.-]+)/.exec(e);return t?t[1].toLowerCase():"x"}function n(e){return i(e.startLine.slice(e.startPos+1))}var a="area base br col command embed frame hr img input keygen link meta param source track wbr menuitem".split(" "),l={selfClosing:function(e,t,r){return a.indexOf(n(r))>-1},matchingTag:function(e,t,r){return i(e.slice(t+2))==n(r)}},s=function(e){function t(t,r){e.call(this,o,{predicates:l}),this.conf=t}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.indent=function(e,t,r){return function(e,t,r,o){for(var i=e.contextAt(r,r.length-t.length),a=/^\s*<\/\s*([\w_\.-]+)/.exec(t);i;){if("tag"==i.name){var l=CodeMirror.countColumn(i.startLine,null,o.tabSize);return a&&a[1].toLowerCase()==n(i)?l:l+o.indentUnit}if("openTag"==i.name)return CodeMirror.countColumn(i.startLine,null,o.tabSize)+2*o.indentUnit;i=i.parent}return 0}(e,t,r,this.conf)},t}(t.GrammarMode),d=s.prototype;d.electricInput=/^\s*<\/.*?>/,d.blockCommentStart="\x3c!--",d.blockCommentEnd="--\x3e",d.fold="xml",function(e){e.xmlCurrentTag=function(e){var t=e.context;if(!t||"openTag"!=t.name&&"closeTag"!=t.name)return null;var r=/^<\/?\s*([\w\-\.]+)/.exec(t.startLine.slice(t.startPos));return r?{name:r[1],close:"closeTag"==t.name}:null},e.xmlCurrentContext=function(e){for(var t=[],r=e.context;r;r=r.parent)if("tag"==r.name){var o=/^<\s*([\w\-\.]+)/.exec(r.startLine.slice(r.startPos));o&&t.push(o[1])}return t.reverse()}}(d),t.defineMode("google-html",(function(e,t){return new s(e,t)}))}((e="undefined"!=typeof globalThis?globalThis:e||self).CodeMirror)}(window),function(e){function t(e){for(var t={},r=0;r*\/]/.test(r)?k(null,"select-op"):"."==r&&e.match(/^-?[_a-z][_a-z0-9-]*/i)?k("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(r)?k(null,r):e.match(/^[\w-.]+(?=\()/)?(/^(url(-prefix)?|domain|regexp)$/i.test(e.current())&&(t.tokenize=S),k("variable callee","variable")):/[\w\\\-]/.test(r)?(e.eatWhile(/[\w\\\-]/),k("property","word")):k(null,null):/[\d.]/.test(e.peek())?(e.eatWhile(/[\w.%]/),k("number","unit")):e.match(/^-[\w\\\-]*/)?(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?k("variable-2","variable-definition"):k("variable-2","variable")):e.match(/^\w+-/)?k("meta","meta"):void 0}function C(e){return function(t,r){for(var o,i=!1;null!=(o=t.next());){if(o==e&&!i){")"==e&&t.backUp(1);break}i=!i&&"\\"==o}return(o==e||!i&&")"!=e)&&(r.tokenize=null),k("string","string")}}function S(e,t){return e.next(),e.match(/^\s*[\"\')]/,!1)?t.tokenize=null:t.tokenize=C(")"),k(null,"(")}function E(e,t,r){this.type=e,this.indent=t,this.prev=r}function T(e,t,r,o){return e.context=new E(r,t.indentation()+(!1===o?0:a),e.context),r}function A(e){return e.context.prev&&(e.context=e.context.prev),e.context.type}function O(e,t,r){return I[r.context.type](e,t,r)}function L(e,t,r,o){for(var i=o||1;i>0;i--)r.context=r.context.prev;return O(e,t,r)}function M(e){var t=e.current().toLowerCase();n=b.hasOwnProperty(t)?"atom":f.hasOwnProperty(t)?"keyword":"variable"}var I={top:function(e,t,r){if("{"==e)return T(r,t,"block");if("}"==e&&r.context.prev)return A(r);if(x&&/@component/i.test(e))return T(r,t,"atComponentBlock");if(/^@(-moz-)?document$/i.test(e))return T(r,t,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/i.test(e))return T(r,t,"atBlock");if(/^@(font-face|counter-style)/i.test(e))return r.stateArg=e,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(e))return"keyframes";if(e&&"@"==e.charAt(0))return T(r,t,"at");if("hash"==e)n="builtin";else if("word"==e)n="tag";else{if("variable-definition"==e)return"maybeprop";if("interpolation"==e)return T(r,t,"interpolation");if(":"==e)return"pseudo";if(y&&"("==e)return T(r,t,"parens")}return r.context.type},block:function(e,t,r){if("word"==e){var o=t.current().toLowerCase();return p.hasOwnProperty(o)?(n="property","maybeprop"):h.hasOwnProperty(o)?(n=w?"string-2":"property","maybeprop"):y?(n=t.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(n+=" error","maybeprop")}return"meta"==e?"block":y||"hash"!=e&&"qualifier"!=e?I.top(e,t,r):(n="error","block")},maybeprop:function(e,t,r){return":"==e?T(r,t,"prop"):O(e,t,r)},prop:function(e,t,r){if(";"==e)return A(r);if("{"==e&&y)return T(r,t,"propBlock");if("}"==e||"{"==e)return L(e,t,r);if("("==e)return T(r,t,"parens");if("hash"!=e||/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(t.current())){if("word"==e)M(t);else if("interpolation"==e)return T(r,t,"interpolation")}else n+=" error";return"prop"},propBlock:function(e,t,r){return"}"==e?A(r):"word"==e?(n="property","maybeprop"):r.context.type},parens:function(e,t,r){return"{"==e||"}"==e?L(e,t,r):")"==e?A(r):"("==e?T(r,t,"parens"):"interpolation"==e?T(r,t,"interpolation"):("word"==e&&M(t),"parens")},pseudo:function(e,t,r){return"meta"==e?"pseudo":"word"==e?(n="variable-3",r.context.type):O(e,t,r)},documentTypes:function(e,t,r){return"word"==e&&s.hasOwnProperty(t.current())?(n="tag",r.context.type):I.atBlock(e,t,r)},atBlock:function(e,t,r){if("("==e)return T(r,t,"atBlock_parens");if("}"==e||";"==e)return L(e,t,r);if("{"==e)return A(r)&&T(r,t,y?"block":"top");if("interpolation"==e)return T(r,t,"interpolation");if("word"==e){var o=t.current().toLowerCase();n="only"==o||"not"==o||"and"==o||"or"==o?"keyword":d.hasOwnProperty(o)?"attribute":c.hasOwnProperty(o)?"property":u.hasOwnProperty(o)?"keyword":p.hasOwnProperty(o)?"property":h.hasOwnProperty(o)?w?"string-2":"property":b.hasOwnProperty(o)?"atom":f.hasOwnProperty(o)?"keyword":"error"}return r.context.type},atComponentBlock:function(e,t,r){return"}"==e?L(e,t,r):"{"==e?A(r)&&T(r,t,y?"block":"top",!1):("word"==e&&(n="error"),r.context.type)},atBlock_parens:function(e,t,r){return")"==e?A(r):"{"==e||"}"==e?L(e,t,r,2):I.atBlock(e,t,r)},restricted_atBlock_before:function(e,t,r){return"{"==e?T(r,t,"restricted_atBlock"):"word"==e&&"@counter-style"==r.stateArg?(n="variable","restricted_atBlock_before"):O(e,t,r)},restricted_atBlock:function(e,t,r){return"}"==e?(r.stateArg=null,A(r)):"word"==e?(n="@font-face"==r.stateArg&&!g.hasOwnProperty(t.current().toLowerCase())||"@counter-style"==r.stateArg&&!m.hasOwnProperty(t.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},keyframes:function(e,t,r){return"word"==e?(n="variable","keyframes"):"{"==e?T(r,t,"top"):O(e,t,r)},at:function(e,t,r){return";"==e?A(r):"{"==e||"}"==e?L(e,t,r):("word"==e?n="tag":"hash"==e&&(n="builtin"),"at")},interpolation:function(e,t,r){return"}"==e?A(r):"{"==e||";"==e?L(e,t,r):("word"==e?n="variable":"variable"!=e&&"("!=e&&")"!=e&&(n="error"),"interpolation")}};return{startState:function(e){return{tokenize:null,state:o?"block":"top",stateArg:null,context:new E(o?"block":"top",e||0,null)}},token:function(e,t){if(!t.tokenize&&e.eatSpace())return null;var r=(t.tokenize||_)(e,t);return r&&"object"==typeof r&&(i=r[1],r=r[0]),n=r,"comment"!=i&&(t.state=I[t.state](i,e,t)),n},indent:function(e,t){var r=e.context,o=t&&t.charAt(0),i=r.indent;return"prop"!=r.type||"}"!=o&&")"!=o||(r=r.prev),r.prev&&("}"!=o||"block"!=r.type&&"top"!=r.type&&"interpolation"!=r.type&&"restricted_atBlock"!=r.type?(")"!=o||"parens"!=r.type&&"atBlock_parens"!=r.type)&&("{"!=o||"at"!=r.type&&"atBlock"!=r.type)||(i=Math.max(0,r.indent-a)):i=(r=r.prev).indent),i},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:v,fold:"brace"}}));var r=["domain","regexp","url","url-prefix"],o=t(r),i=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],n=t(i),a=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover","prefers-color-scheme","dynamic-range","video-dynamic-range"],l=t(a),s=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive","dark","light","standard","high"],d=t(s),c=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","all","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","binding","bleed","block-size","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-content","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-gap","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-gap","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","inset","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","left","letter-spacing","line-break","line-height","line-height-step","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","place-content","place-items","place-self","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotate","rotation","rotation-point","row-gap","ruby-align","ruby-overhang","ruby-position","ruby-span","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-type","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-orientation","text-outline","text-overflow","text-rendering","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","touch-action","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-select","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","paint-order","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],u=t(c),p=["accent-color","aspect-ratio","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","content-visibility","margin-block","margin-block-end","margin-block-start","margin-inline","margin-inline-end","margin-inline-start","overflow-anchor","overscroll-behavior","padding-block","padding-block-end","padding-block-start","padding-inline","padding-inline-end","padding-inline-start","scroll-snap-stop","scrollbar-3d-light-color","scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-track-color","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","shape-inside","zoom"],h=t(p),g=t(["font-display","font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]),m=t(["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"]),f=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],b=t(f),y=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","auto-flow","avoid","avoid-column","avoid-page","avoid-region","axis-pan","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","blur","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","brightness","bullets","button","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","color","color-burn","color-dodge","column","column-reverse","compact","condensed","conic-gradient","contain","content","contents","content-box","context-menu","continuous","contrast","copy","counter","counters","cover","crop","cross","crosshair","cubic-bezier","currentcolor","cursive","cyclic","darken","dashed","decimal","decimal-leading-zero","default","default-button","dense","destination-atop","destination-in","destination-out","destination-over","devanagari","difference","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","drop-shadow","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","exclusion","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fill-box","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","grayscale","graytext","grid","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hard-light","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","hue","hue-rotate","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-grid","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","lighten","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","luminosity","malayalam","manipulation","match","matrix","matrix3d","media-play-button","media-slider","media-sliderthumb","media-volume-slider","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","multiple_mask_images","multiply","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","opacity","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","pinch-zoom","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeating-conic-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","saturate","saturation","scale","scale3d","scaleX","scaleY","scaleZ","screen","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","self-start","self-end","semi-condensed","semi-expanded","separate","sepia","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","soft-light","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","space-evenly","spell-out","square","square-button","start","static","status-bar","stretch","stroke","stroke-box","sub","subpixel-antialiased","svg_masks","super","sw-resize","symbolic","symbols","system-ui","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","transform","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","unidirectional-pan","unset","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","view-box","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],v=t(y),x=r.concat(i).concat(a).concat(s).concat(c).concat(p).concat(f).concat(y);function w(e,t){for(var r,o=!1;null!=(r=e.next());){if(o&&"/"==r){t.tokenize=null;break}o="*"==r}return["comment","comment"]}e.registerHelper("hintWords","css",x),e.defineMIME("text/css",{documentTypes:o,mediaTypes:n,mediaFeatures:l,mediaValueKeywords:d,propertyKeywords:u,nonStandardPropertyKeywords:h,fontProperties:g,counterDescriptors:m,colorKeywords:b,valueKeywords:v,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=w,w(e,t))}},name:"css"}),e.defineMIME("text/x-scss",{mediaTypes:n,mediaFeatures:l,mediaValueKeywords:d,propertyKeywords:u,nonStandardPropertyKeywords:h,colorKeywords:b,valueKeywords:v,fontProperties:g,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=w,w(e,t)):["operator","operator"]},":":function(e){return!!e.match(/^\s*\{/,!1)&&[null,null]},$:function(e){return e.match(/^[\w-]+/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(e){return!!e.eat("{")&&[null,"interpolation"]}},name:"css",helperType:"scss"}),e.defineMIME("text/x-less",{mediaTypes:n,mediaFeatures:l,mediaValueKeywords:d,propertyKeywords:u,nonStandardPropertyKeywords:h,colorKeywords:b,valueKeywords:v,fontProperties:g,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=w,w(e,t)):["operator","operator"]},"@":function(e){return e.eat("{")?[null,"interpolation"]:!e.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i,!1)&&(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"}),e.defineMIME("text/x-gss",{documentTypes:o,mediaTypes:n,mediaFeatures:l,propertyKeywords:u,nonStandardPropertyKeywords:h,fontProperties:g,counterDescriptors:m,colorKeywords:b,valueKeywords:v,supportsAtComponent:!0,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=w,w(e,t))}},name:"css",helperType:"gss"})}(CodeMirror),function(e){e.defineMode("javascript",(function(t,r){var o,i,n=t.indentUnit,a=r.statementIndent,l=r.jsonld,s=r.json||l,d=!1!==r.trackScope,c=r.typescript,u=r.wordCharacters||/[\w$\xa1-\uffff]/,p=function(){function e(e){return{type:e,style:"keyword"}}var t=e("keyword a"),r=e("keyword b"),o=e("keyword c"),i=e("keyword d"),n=e("operator"),a={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:r,do:r,try:r,finally:r,return:i,break:i,continue:i,new:e("new"),delete:o,void:o,throw:o,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:n,typeof:n,instanceof:n,true:a,false:a,null:a,undefined:a,NaN:a,Infinity:a,this:e("this"),class:e("class"),super:e("atom"),yield:o,export:e("export"),import:e("import"),extends:o,await:o}}(),h=/[+\-*&%=<>!?|~^@]/,g=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function m(e,t,r){return o=e,i=r,t}function f(e,t){var r,o=e.next();if('"'==o||"'"==o)return t.tokenize=(r=o,function(e,t){var o,i=!1;if(l&&"@"==e.peek()&&e.match(g))return t.tokenize=f,m("jsonld-keyword","meta");for(;null!=(o=e.next())&&(o!=r||i);)i=!i&&"\\"==o;return i||(t.tokenize=f),m("string","string")}),t.tokenize(e,t);if("."==o&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return m("number","number");if("."==o&&e.match(".."))return m("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(o))return m(o);if("="==o&&e.eat(">"))return m("=>","operator");if("0"==o&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return m("number","number");if(/\d/.test(o))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),m("number","number");if("/"==o)return e.eat("*")?(t.tokenize=b,b(e,t)):e.eat("/")?(e.skipToEnd(),m("comment","comment")):et(e,t,1)?(function(e){for(var t,r=!1,o=!1;null!=(t=e.next());){if(!r){if("/"==t&&!o)return;"["==t?o=!0:o&&"]"==t&&(o=!1)}r=!r&&"\\"==t}}(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),m("regexp","string-2")):(e.eat("="),m("operator","operator",e.current()));if("`"==o)return t.tokenize=y,y(e,t);if("#"==o&&"!"==e.peek())return e.skipToEnd(),m("meta","meta");if("#"==o&&e.eatWhile(u))return m("variable","property");if("<"==o&&e.match("!--")||"-"==o&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),m("comment","comment");if(h.test(o))return">"==o&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=o&&"="!=o||e.eat("="):/[<>*+\-|&?]/.test(o)&&(e.eat(o),">"==o&&e.eat(o))),"?"==o&&e.eat(".")?m("."):m("operator","operator",e.current());if(u.test(o)){e.eatWhile(u);var i=e.current();if("."!=t.lastType){if(p.propertyIsEnumerable(i)){var n=p[i];return m(n.type,n.style,i)}if("async"==i&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return m("async","keyword",i)}return m("variable","variable",i)}}function b(e,t){for(var r,o=!1;r=e.next();){if("/"==r&&o){t.tokenize=f;break}o="*"==r}return m("comment","comment")}function y(e,t){for(var r,o=!1;null!=(r=e.next());){if(!o&&("`"==r||"$"==r&&e.eat("{"))){t.tokenize=f;break}o=!o&&"\\"==r}return m("quasi","string-2",e.current())}var v="([{}])";function x(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var r=e.string.indexOf("=>",e.start);if(!(r<0)){if(c){var o=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,r));o&&(r=o.index)}for(var i=0,n=!1,a=r-1;a>=0;--a){var l=e.string.charAt(a),s=v.indexOf(l);if(s>=0&&s<3){if(!i){++a;break}if(0==--i){"("==l&&(n=!0);break}}else if(s>=3&&s<6)++i;else if(u.test(l))n=!0;else if(/["'\/`]/.test(l))for(;;--a){if(0==a)return;if(e.string.charAt(a-1)==l&&"\\"!=e.string.charAt(a-2)){a--;break}}else if(n&&!i){++a;break}}n&&!i&&(t.fatArrowAt=a)}}var w={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function k(e,t,r,o,i,n){this.indented=e,this.column=t,this.type=r,this.prev=i,this.info=n,null!=o&&(this.align=o)}function _(e,t){if(!d)return!1;for(var r=e.localVars;r;r=r.next)if(r.name==t)return!0;for(var o=e.context;o;o=o.prev)for(r=o.vars;r;r=r.next)if(r.name==t)return!0}function C(e,t,r,o,i){var n=e.cc;for(S.state=e,S.stream=i,S.marked=null,S.cc=n,S.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((n.length?n.pop():s?K:B)(r,o)){for(;n.length&&n[n.length-1].lex;)n.pop()();return S.marked?S.marked:"variable"==r&&_(e,o)?"variable-2":t}}var S={state:null,column:null,marked:null,cc:null};function E(){for(var e=arguments.length-1;e>=0;e--)S.cc.push(arguments[e])}function T(){return E.apply(null,arguments),!0}function A(e,t){for(var r=t;r;r=r.next)if(r.name==e)return!0;return!1}function O(e){var t=S.state;if(S.marked="def",d){if(t.context)if("var"==t.lexical.info&&t.context&&t.context.block){var o=L(e,t.context);if(null!=o)return void(t.context=o)}else if(!A(e,t.localVars))return void(t.localVars=new R(e,t.localVars));r.globalVars&&!A(e,t.globalVars)&&(t.globalVars=new R(e,t.globalVars))}}function L(e,t){if(t){if(t.block){var r=L(e,t.prev);return r?r==t.prev?t:new I(r,t.vars,!0):null}return A(e,t.vars)?t:new I(t.prev,new R(e,t.vars),!1)}return null}function M(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function I(e,t,r){this.prev=e,this.vars=t,this.block=r}function R(e,t){this.name=e,this.next=t}var F=new R("this",new R("arguments",null));function N(){S.state.context=new I(S.state.context,S.state.localVars,!1),S.state.localVars=F}function z(){S.state.context=new I(S.state.context,S.state.localVars,!0),S.state.localVars=null}function D(){S.state.localVars=S.state.context.vars,S.state.context=S.state.context.prev}function P(e,t){var r=function(){var r=S.state,o=r.indented;if("stat"==r.lexical.type)o=r.lexical.indented;else for(var i=r.lexical;i&&")"==i.type&&i.align;i=i.prev)o=i.indented;r.lexical=new k(o,S.stream.column(),e,null,r.lexical,t)};return r.lex=!0,r}function H(){var e=S.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function U(e){return function t(r){return r==e?T():";"==e||"}"==r||")"==r||"]"==r?E():T(t)}}function B(e,t){return"var"==e?T(P("vardef",t),Se,U(";"),H):"keyword a"==e?T(P("form"),V,B,H):"keyword b"==e?T(P("form"),B,H):"keyword d"==e?S.stream.match(/^\s*$/,!1)?T():T(P("stat"),Z,U(";"),H):"debugger"==e?T(U(";")):"{"==e?T(P("}"),z,de,H,D):";"==e?T():"if"==e?("else"==S.state.lexical.info&&S.state.cc[S.state.cc.length-1]==H&&S.state.cc.pop()(),T(P("form"),V,B,H,Me)):"function"==e?T(Ne):"for"==e?T(P("form"),z,Ie,B,D,H):"class"==e||c&&"interface"==t?(S.marked="keyword",T(P("form","class"==e?e:t),Ue,H)):"variable"==e?c&&"declare"==t?(S.marked="keyword",T(B)):c&&("module"==t||"enum"==t||"type"==t)&&S.stream.match(/^\s*\w/,!1)?(S.marked="keyword","enum"==t?T(Xe):"type"==t?T(De,U("operator"),ge,U(";")):T(P("form"),Ee,U("{"),P("}"),de,H,H)):c&&"namespace"==t?(S.marked="keyword",T(P("form"),K,B,H)):c&&"abstract"==t?(S.marked="keyword",T(B)):T(P("stat"),re):"switch"==e?T(P("form"),V,U("{"),P("}","switch"),z,de,H,H,D):"case"==e?T(K,U(":")):"default"==e?T(U(":")):"catch"==e?T(P("form"),N,W,B,H,D):"export"==e?T(P("stat"),je,H):"import"==e?T(P("stat"),qe,H):"async"==e?T(B):"@"==t?T(K,B):E(P("stat"),K,U(";"),H)}function W(e){if("("==e)return T(Pe,U(")"))}function K(e,t){return q(e,t,!1)}function j(e,t){return q(e,t,!0)}function V(e){return"("!=e?E():T(P(")"),Z,U(")"),H)}function q(e,t,r){if(S.state.fatArrowAt==S.stream.start){var o=r?$:X;if("("==e)return T(N,P(")"),le(Pe,")"),H,U("=>"),o,D);if("variable"==e)return E(N,Ee,U("=>"),o,D)}var i=r?J:G;return w.hasOwnProperty(e)?T(i):"function"==e?T(Ne,i):"class"==e||c&&"interface"==t?(S.marked="keyword",T(P("form"),He,H)):"keyword c"==e||"async"==e?T(r?j:K):"("==e?T(P(")"),Z,U(")"),H,i):"operator"==e||"spread"==e?T(r?j:K):"["==e?T(P("]"),Ye,H,i):"{"==e?se(ie,"}",null,i):"quasi"==e?E(Q,i):"new"==e?T(function(e){return function(t){return"."==t?T(e?te:ee):"variable"==t&&c?T(ke,e?J:G):E(e?j:K)}}(r)):T()}function Z(e){return e.match(/[;\}\)\],]/)?E():E(K)}function G(e,t){return","==e?T(Z):J(e,t,!1)}function J(e,t,r){var o=0==r?G:J,i=0==r?K:j;return"=>"==e?T(N,r?$:X,D):"operator"==e?/\+\+|--/.test(t)||c&&"!"==t?T(o):c&&"<"==t&&S.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?T(P(">"),le(ge,">"),H,o):"?"==t?T(K,U(":"),i):T(i):"quasi"==e?E(Q,o):";"!=e?"("==e?se(j,")","call",o):"."==e?T(oe,o):"["==e?T(P("]"),Z,U("]"),H,o):c&&"as"==t?(S.marked="keyword",T(ge,o)):"regexp"==e?(S.state.lastType=S.marked="operator",S.stream.backUp(S.stream.pos-S.stream.start-1),T(i)):void 0:void 0}function Q(e,t){return"quasi"!=e?E():"${"!=t.slice(t.length-2)?T(Q):T(Z,Y)}function Y(e){if("}"==e)return S.marked="string-2",S.state.tokenize=y,T(Q)}function X(e){return x(S.stream,S.state),E("{"==e?B:K)}function $(e){return x(S.stream,S.state),E("{"==e?B:j)}function ee(e,t){if("target"==t)return S.marked="keyword",T(G)}function te(e,t){if("target"==t)return S.marked="keyword",T(J)}function re(e){return":"==e?T(H,B):E(G,U(";"),H)}function oe(e){if("variable"==e)return S.marked="property",T()}function ie(e,t){return"async"==e?(S.marked="property",T(ie)):"variable"==e||"keyword"==S.style?(S.marked="property","get"==t||"set"==t?T(ne):(c&&S.state.fatArrowAt==S.stream.start&&(r=S.stream.match(/^\s*:\s*/,!1))&&(S.state.fatArrowAt=S.stream.pos+r[0].length),T(ae))):"number"==e||"string"==e?(S.marked=l?"property":S.style+" property",T(ae)):"jsonld-keyword"==e?T(ae):c&&M(t)?(S.marked="keyword",T(ie)):"["==e?T(K,ce,U("]"),ae):"spread"==e?T(j,ae):"*"==t?(S.marked="keyword",T(ie)):":"==e?E(ae):void 0;var r}function ne(e){return"variable"!=e?E(ae):(S.marked="property",T(Ne))}function ae(e){return":"==e?T(j):"("==e?E(Ne):void 0}function le(e,t,r){function o(i,n){if(r?r.indexOf(i)>-1:","==i){var a=S.state.lexical;return"call"==a.info&&(a.pos=(a.pos||0)+1),T((function(r,o){return r==t||o==t?E():E(e)}),o)}return i==t||n==t?T():r&&r.indexOf(";")>-1?E(e):T(U(t))}return function(r,i){return r==t||i==t?T():E(e,o)}}function se(e,t,r){for(var o=3;o"),ge):"quasi"==e?E(ye,we):void 0}function me(e){if("=>"==e)return T(ge)}function fe(e){return e.match(/[\}\)\]]/)?T():","==e||";"==e?T(fe):E(be,fe)}function be(e,t){return"variable"==e||"keyword"==S.style?(S.marked="property",T(be)):"?"==t||"number"==e||"string"==e?T(be):":"==e?T(ge):"["==e?T(U("variable"),ue,U("]"),be):"("==e?E(ze,be):e.match(/[;\}\)\],]/)?void 0:T()}function ye(e,t){return"quasi"!=e?E():"${"!=t.slice(t.length-2)?T(ye):T(ge,ve)}function ve(e){if("}"==e)return S.marked="string-2",S.state.tokenize=y,T(ye)}function xe(e,t){return"variable"==e&&S.stream.match(/^\s*[?:]/,!1)||"?"==t?T(xe):":"==e?T(ge):"spread"==e?T(xe):E(ge)}function we(e,t){return"<"==t?T(P(">"),le(ge,">"),H,we):"|"==t||"."==e||"&"==t?T(ge):"["==e?T(ge,U("]"),we):"extends"==t||"implements"==t?(S.marked="keyword",T(ge)):"?"==t?T(ge,U(":"),ge):void 0}function ke(e,t){if("<"==t)return T(P(">"),le(ge,">"),H,we)}function _e(){return E(ge,Ce)}function Ce(e,t){if("="==t)return T(ge)}function Se(e,t){return"enum"==t?(S.marked="keyword",T(Xe)):E(Ee,ce,Oe,Le)}function Ee(e,t){return c&&M(t)?(S.marked="keyword",T(Ee)):"variable"==e?(O(t),T()):"spread"==e?T(Ee):"["==e?se(Ae,"]"):"{"==e?se(Te,"}"):void 0}function Te(e,t){return"variable"!=e||S.stream.match(/^\s*:/,!1)?("variable"==e&&(S.marked="property"),"spread"==e?T(Ee):"}"==e?E():"["==e?T(K,U("]"),U(":"),Te):T(U(":"),Ee,Oe)):(O(t),T(Oe))}function Ae(){return E(Ee,Oe)}function Oe(e,t){if("="==t)return T(j)}function Le(e){if(","==e)return T(Se)}function Me(e,t){if("keyword b"==e&&"else"==t)return T(P("form","else"),B,H)}function Ie(e,t){return"await"==t?T(Ie):"("==e?T(P(")"),Re,H):void 0}function Re(e){return"var"==e?T(Se,Fe):"variable"==e?T(Fe):E(Fe)}function Fe(e,t){return")"==e?T():";"==e?T(Fe):"in"==t||"of"==t?(S.marked="keyword",T(K,Fe)):E(K,Fe)}function Ne(e,t){return"*"==t?(S.marked="keyword",T(Ne)):"variable"==e?(O(t),T(Ne)):"("==e?T(N,P(")"),le(Pe,")"),H,pe,B,D):c&&"<"==t?T(P(">"),le(_e,">"),H,Ne):void 0}function ze(e,t){return"*"==t?(S.marked="keyword",T(ze)):"variable"==e?(O(t),T(ze)):"("==e?T(N,P(")"),le(Pe,")"),H,pe,D):c&&"<"==t?T(P(">"),le(_e,">"),H,ze):void 0}function De(e,t){return"keyword"==e||"variable"==e?(S.marked="type",T(De)):"<"==t?T(P(">"),le(_e,">"),H):void 0}function Pe(e,t){return"@"==t&&T(K,Pe),"spread"==e?T(Pe):c&&M(t)?(S.marked="keyword",T(Pe)):c&&"this"==e?T(ce,Oe):E(Ee,ce,Oe)}function He(e,t){return"variable"==e?Ue(e,t):Be(e,t)}function Ue(e,t){if("variable"==e)return O(t),T(Be)}function Be(e,t){return"<"==t?T(P(">"),le(_e,">"),H,Be):"extends"==t||"implements"==t||c&&","==e?("implements"==t&&(S.marked="keyword"),T(c?ge:K,Be)):"{"==e?T(P("}"),We,H):void 0}function We(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||c&&M(t))&&S.stream.match(/^\s+#?[\w$\xa1-\uffff]/,!1)?(S.marked="keyword",T(We)):"variable"==e||"keyword"==S.style?(S.marked="property",T(Ke,We)):"number"==e||"string"==e?T(Ke,We):"["==e?T(K,ce,U("]"),Ke,We):"*"==t?(S.marked="keyword",T(We)):c&&"("==e?E(ze,We):";"==e||","==e?T(We):"}"==e?T():"@"==t?T(K,We):void 0}function Ke(e,t){if("!"==t)return T(Ke);if("?"==t)return T(Ke);if(":"==e)return T(ge,Oe);if("="==t)return T(j);var r=S.state.lexical.prev;return E(r&&"interface"==r.info?ze:Ne)}function je(e,t){return"*"==t?(S.marked="keyword",T(Qe,U(";"))):"default"==t?(S.marked="keyword",T(K,U(";"))):"{"==e?T(le(Ve,"}"),Qe,U(";")):E(B)}function Ve(e,t){return"as"==t?(S.marked="keyword",T(U("variable"))):"variable"==e?E(j,Ve):void 0}function qe(e){return"string"==e?T():"("==e?E(K):"."==e?E(G):E(Ze,Ge,Qe)}function Ze(e,t){return"{"==e?se(Ze,"}"):("variable"==e&&O(t),"*"==t&&(S.marked="keyword"),T(Je))}function Ge(e){if(","==e)return T(Ze,Ge)}function Je(e,t){if("as"==t)return S.marked="keyword",T(Ze)}function Qe(e,t){if("from"==t)return S.marked="keyword",T(K)}function Ye(e){return"]"==e?T():E(le(j,"]"))}function Xe(){return E(P("form"),Ee,U("{"),P("}"),le($e,"}"),H,H)}function $e(){return E(Ee,Oe)}function et(e,t,r){return t.tokenize==f&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(r||0)))}return N.lex=z.lex=!0,D.lex=!0,H.lex=!0,{startState:function(e){var t={tokenize:f,lastType:"sof",cc:[],lexical:new k((e||0)-n,0,"block",!1),localVars:r.localVars,context:r.localVars&&new I(null,null,!1),indented:e||0};return r.globalVars&&"object"==typeof r.globalVars&&(t.globalVars=r.globalVars),t},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),x(e,t)),t.tokenize!=b&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==o?r:(t.lastType="operator"!=o||"++"!=i&&"--"!=i?o:"incdec",C(t,r,o,i,e))},indent:function(t,o){if(t.tokenize==b||t.tokenize==y)return e.Pass;if(t.tokenize!=f)return 0;var i,l=o&&o.charAt(0),s=t.lexical;if(!/^\s*else\b/.test(o))for(var d=t.cc.length-1;d>=0;--d){var c=t.cc[d];if(c==H)s=s.prev;else if(c!=Me&&c!=D)break}for(;("stat"==s.type||"form"==s.type)&&("}"==l||(i=t.cc[t.cc.length-1])&&(i==G||i==J)&&!/^[,\.=+\-*:?[\(]/.test(o));)s=s.prev;a&&")"==s.type&&"stat"==s.prev.type&&(s=s.prev);var u=s.type,p=l==u;return"vardef"==u?s.indented+("operator"==t.lastType||","==t.lastType?s.info.length+1:0):"form"==u&&"{"==l?s.indented:"form"==u?s.indented+n:"stat"==u?s.indented+(function(e,t){return"operator"==e.lastType||","==e.lastType||h.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}(t,o)?a||n:0):"switch"!=s.info||p||0==r.doubleIndentSwitch?s.align?s.column+(p?0:1):s.indented+(p?0:n):s.indented+(/^(?:case|default)\b/.test(o)?n:2*n)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:s?null:"/*",blockCommentEnd:s?null:"*/",blockCommentContinue:s?null:" * ",lineComment:s?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:s?"json":"javascript",jsonldMode:l,jsonMode:s,expressionAllowed:et,skipExpression:function(t){C(t,"atom","atom","true",new e.StringStream("",2,null))}}})),e.registerHelper("wordChars","javascript",/[\w$]/),e.defineMIME("text/javascript","javascript"),e.defineMIME("text/ecmascript","javascript"),e.defineMIME("application/javascript","javascript"),e.defineMIME("application/x-javascript","javascript"),e.defineMIME("application/ecmascript","javascript"),e.defineMIME("application/json",{name:"javascript",json:!0}),e.defineMIME("application/x-json",{name:"javascript",json:!0}),e.defineMIME("application/manifest+json",{name:"javascript",json:!0}),e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),e.defineMIME("text/typescript",{name:"javascript",typescript:!0}),e.defineMIME("application/typescript",{name:"javascript",typescript:!0})}(CodeMirror),function(e){var t={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0},r={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,allowMissingTagName:!1,caseFold:!1};e.defineMode("xml",(function(o,i){var n,a,l=o.indentUnit,s={},d=i.htmlMode?t:r;for(var c in d)s[c]=d[c];for(var c in i)s[c]=i[c];function u(e,t){function r(r){return t.tokenize=r,r(e,t)}var o=e.next();return"<"==o?e.eat("!")?e.eat("[")?e.match("CDATA[")?r(h("atom","]]>")):null:e.match("--")?r(h("comment","--\x3e")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),r(g(1))):null:e.eat("?")?(e.eatWhile(/[\w\._\-]/),t.tokenize=h("meta","?>"),"meta"):(n=e.eat("/")?"closeTag":"openTag",t.tokenize=p,"tag bracket"):"&"==o?(e.eat("#")?e.eat("x")?e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):e.eatWhile(/[\d]/)&&e.eat(";"):e.eatWhile(/[\w\.\-:]/)&&e.eat(";"))?"atom":"error":(e.eatWhile(/[^&<]/),null)}function p(e,t){var r,o,i=e.next();if(">"==i||"/"==i&&e.eat(">"))return t.tokenize=u,n=">"==i?"endTag":"selfcloseTag","tag bracket";if("="==i)return n="equals",null;if("<"==i){t.tokenize=u,t.state=v,t.tagName=t.tagStart=null;var a=t.tokenize(e,t);return a?a+" tag error":"tag error"}return/[\'\"]/.test(i)?(t.tokenize=(r=i,o=function(e,t){for(;!e.eol();)if(e.next()==r){t.tokenize=p;break}return"string"},o.isInAttribute=!0,o),t.stringStartCol=e.column(),t.tokenize(e,t)):(e.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function h(e,t){return function(r,o){for(;!r.eol();){if(r.match(t)){o.tokenize=u;break}r.next()}return e}}function g(e){return function(t,r){for(var o;null!=(o=t.next());){if("<"==o)return r.tokenize=g(e+1),r.tokenize(t,r);if(">"==o){if(1==e){r.tokenize=u;break}return r.tokenize=g(e-1),r.tokenize(t,r)}}return"meta"}}function m(e){return e&&e.toLowerCase()}function f(e,t,r){this.prev=e.context,this.tagName=t||"",this.indent=e.indented,this.startOfLine=r,(s.doNotIndent.hasOwnProperty(t)||e.context&&e.context.noIndent)&&(this.noIndent=!0)}function b(e){e.context&&(e.context=e.context.prev)}function y(e,t){for(var r;;){if(!e.context)return;if(r=e.context.tagName,!s.contextGrabbers.hasOwnProperty(m(r))||!s.contextGrabbers[m(r)].hasOwnProperty(m(t)))return;b(e)}}function v(e,t,r){return"openTag"==e?(r.tagStart=t.column(),x):"closeTag"==e?w:v}function x(e,t,r){return"word"==e?(r.tagName=t.current(),a="tag",C):s.allowMissingTagName&&"endTag"==e?(a="tag bracket",C(e,0,r)):(a="error",x)}function w(e,t,r){if("word"==e){var o=t.current();return r.context&&r.context.tagName!=o&&s.implicitlyClosed.hasOwnProperty(m(r.context.tagName))&&b(r),r.context&&r.context.tagName==o||!1===s.matchClosing?(a="tag",k):(a="tag error",_)}return s.allowMissingTagName&&"endTag"==e?(a="tag bracket",k(e,0,r)):(a="error",_)}function k(e,t,r){return"endTag"!=e?(a="error",k):(b(r),v)}function _(e,t,r){return a="error",k(e,0,r)}function C(e,t,r){if("word"==e)return a="attribute",S;if("endTag"==e||"selfcloseTag"==e){var o=r.tagName,i=r.tagStart;return r.tagName=r.tagStart=null,"selfcloseTag"==e||s.autoSelfClosers.hasOwnProperty(m(o))?y(r,o):(y(r,o),r.context=new f(r,o,i==r.indented)),v}return a="error",C}function S(e,t,r){return"equals"==e?E:(s.allowMissing||(a="error"),C(e,0,r))}function E(e,t,r){return"string"==e?T:"word"==e&&s.allowUnquoted?(a="string",C):(a="error",C(e,0,r))}function T(e,t,r){return"string"==e?T:C(e,0,r)}return u.isInText=!0,{startState:function(e){var t={tokenize:u,state:v,indented:e||0,tagName:null,tagStart:null,context:null};return null!=e&&(t.baseIndent=e),t},token:function(e,t){if(!t.tagName&&e.sol()&&(t.indented=e.indentation()),e.eatSpace())return null;n=null;var r=t.tokenize(e,t);return(r||n)&&"comment"!=r&&(a=null,t.state=t.state(n||r,e,t),a&&(r="error"==a?r+" error":a)),r},indent:function(t,r,o){var i=t.context;if(t.tokenize.isInAttribute)return t.tagStart==t.indented?t.stringStartCol+1:t.indented+l;if(i&&i.noIndent)return e.Pass;if(t.tokenize!=p&&t.tokenize!=u)return o?o.match(/^(\s*)/)[0].length:0;if(t.tagName)return!1!==s.multilineTagIndentPastTag?t.tagStart+t.tagName.length+2:t.tagStart+l*(s.multilineTagIndentFactor||1);if(s.alignCDATA&&/$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:s.htmlMode?"html":"xml",helperType:s.htmlMode?"html":"xml",skipAttribute:function(e){e.state==E&&(e.state=C)},xmlCurrentTag:function(e){return e.tagName?{name:e.tagName,close:"closeTag"==e.type}:null},xmlCurrentContext:function(e){for(var t=[],r=e.context;r;r=r.prev)t.push(r.tagName);return t.reverse()}}})),e.defineMIME("text/xml","xml"),e.defineMIME("application/xml","xml"),e.mimeModes.hasOwnProperty("text/html")||e.defineMIME("text/html",{name:"xml",htmlMode:!0})}(CodeMirror),function(e){function t(e,t,r,o){this.state=e,this.mode=t,this.depth=r,this.prev=o}function r(o){return new t(e.copyState(o.mode,o.state),o.mode,o.depth,o.prev&&r(o.prev))}e.defineMode("jsx",(function(o,i){var n=e.getMode(o,{name:"xml",allowMissing:!0,multilineTagIndentPastTag:!1,allowMissingTagName:!0}),a=e.getMode(o,i&&i.base||"javascript");function l(e){var t=e.tagName;e.tagName=null;var r=n.indent(e,"","");return e.tagName=t,r}return{startState:function(){return{context:new t(e.startState(a),a)}},copyState:function(e){return{context:r(e.context)}},token:function r(i,s){return s.context.mode==n?function(i,s,d){if(2==d.depth)return i.match(/^.*?\*\//)?d.depth=1:i.skipToEnd(),"comment";if("{"==i.peek()){n.skipAttribute(d.state);var c=l(d.state),u=d.state.context;if(u&&i.match(/^[^>]*>\s*$/,!1)){for(;u.prev&&!u.startOfLine;)u=u.prev;u.startOfLine?c-=o.indentUnit:d.prev.state.lexical&&(c=d.prev.state.lexical.indented)}else 1==d.depth&&(c+=o.indentUnit);return s.context=new t(e.startState(a,c),a,0,s.context),null}if(1==d.depth){if("<"==i.peek())return n.skipAttribute(d.state),s.context=new t(e.startState(n,l(d.state)),n,0,s.context),null;if(i.match("//"))return i.skipToEnd(),"comment";if(i.match("/*"))return d.depth=2,r(i,s)}var p,h=n.token(i,d.state),g=i.current();return/\btag\b/.test(h)?/>$/.test(g)?d.state.context?d.depth=0:s.context=s.context.prev:/^-1&&i.backUp(g.length-p),h}(i,s,s.context):function(r,o,i){if("<"==r.peek()&&!r.match(/^<([^<>]|<[^>]*>)+,\s*>/,!1)&&a.expressionAllowed(r,i.state))return o.context=new t(e.startState(n,a.indent(i.state,"","")),n,0,o.context),a.skipExpression(i.state),null;var l=a.token(r,i.state);if(!l&&null!=i.depth){var s=r.current();"{"==s?i.depth++:"}"==s&&0==--i.depth&&(o.context=o.context.prev)}return l}(i,s,s.context)},indent:function(e,t,r){return e.context.mode.indent(e.context.state,t,r)},innerMode:function(e){return e.context}}}),"xml","javascript"),e.defineMIME("text/jsx","jsx"),e.defineMIME("text/typescript-jsx",{name:"jsx",base:{name:"javascript",typescript:!0}})}(CodeMirror); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +const vi=window.CodeMirror,xi=c`/** + * This file is derived from \`code-mirror/lib/codemirror.css\`, modified in the + * following ways: + * + * - CSS custom properties added. + * - Rules for unused features and addons removed. + * - Unnecessary vendor prefixes removed. + * - \`.cm-s-default\` class selectors removed. + * - Empty rules removed. + */ + +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: var(--playground-code-font-family, monospace); + font-size: var(--playground-code-font-size, 14px); + padding: var(--playground-code-padding, 0); + height: 350px; + color: var(--playground-code-default-color, #000); + background: var(--playground-code-background, #fff); + direction: ltr; + /* CodeMirror uses z-indexes up to 6 to e.g. place scrollbars above the code + area. However, this can create undesirable stacking effects with the rest + of the page. Force a new stacking context. */ + isolation: isolate; + line-height: var(--playground-code-line-height, 1.4em); +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + padding: var( + --playground-code-line-padding, + 0 4px + ); /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, +.CodeMirror-gutter-filler { + background: var( + --playground-code-background, + #fff + ); /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: var(--playground-code-gutter-border-right, none); + background: var( + --playground-code-gutter-background, + var(--playground-code-background, #fff) + ); + box-shadow: var(--playground-code-gutter-box-shadow, none); + white-space: nowrap; +} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: var(--playground-code-linenumber-color, #767676); + white-space: nowrap; + margin-right: 1em; +} +.CodeMirror-code > div > .CodeMirror-line { + /* Some extra room between the line number gutter and the line */ + padding-left: 0.7em; +} + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 2px solid + var( + --playground-code-cursor-color, + var(--playground-code-default-color, #000) + ); + border-right: none; + width: 0; +} + +@keyframes blink { + 0% { + } + 50% { + background: transparent; + } + 100% { + } +} + +/* DEFAULT THEME */ + +.cm-header, +.cm-strong { + font-weight: bold; +} +.cm-em { + font-style: italic; +} +.cm-link { + text-decoration: underline; +} +.cm-strikethrough { + text-decoration: line-through; +} + +.cm-keyword { + color: var(--playground-code-keyword-color, #708); +} +.cm-atom { + color: var(--playground-code-atom-color, #219); +} +.cm-number { + color: var(--playground-code-number-color, #164); +} +.cm-def { + color: var(--playground-code-def-color, #00f); +} +.cm-variable { + color: var(--playground-code-variable-color, #000); +} +.cm-property { + color: var(--playground-code-property-color, #000); +} +.cm-operator { + color: var(--playground-code-operator-color, #000); +} +.cm-variable-2 { + color: var(--playground-code-variable-2-color, #05a); +} +.cm-variable-3 { + color: var(--playground-code-variable-3-color, #085); +} +.cm-type { + color: var(--playground-code-type-color, #085); +} +.cm-comment { + color: var(--playground-code-comment-color, #a50); +} +.cm-string { + color: var(--playground-code-string-color, #a11); +} +.cm-string-2 { + color: var(--playground-code-string-2-color, #f50); +} +.cm-meta { + color: var(--playground-code-meta-color, #555); +} +.cm-qualifier { + color: var(--playground-code-qualifier-color, #555); +} +.cm-builtin { + color: var(--playground-code-builtin-color, #30a); +} +.cm-tag { + color: var(--playground-code-tag-color, #170); +} +.cm-attribute { + color: var(--playground-code-attribute-color, #00c); +} +.cm-callee { + color: var(--playground-code-callee-color, #000); +} + +.CodeMirror-composing { + border-bottom: 2px solid; +} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 50px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -50px; + margin-right: -50px; + padding-bottom: 50px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 50px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, +.CodeMirror-hscrollbar, +.CodeMirror-scrollbar-filler, +.CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; + outline: none; +} +.CodeMirror-vscrollbar { + right: 0; + top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; + left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; + bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; + bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; + left: 0; + top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -50px; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; + bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper ::selection { + background: transparent; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + /* Reset some styles that the rest of the page might have set */ + border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + font-variant-ligatures: contextual; +} +.CodeMirror-wrap pre.CodeMirror-line, +.CodeMirror-wrap pre.CodeMirror-line-like { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ +} + +.CodeMirror-rtl pre { + direction: rtl; +} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} +.CodeMirror-measure pre { + position: static; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { + background: var(--playground-code-selection-background, #d7d4f0); +} +.CodeMirror-focused .CodeMirror-selected { + background: var(--playground-code-selection-background, #d7d4f0); +} +.CodeMirror-crosshair { + cursor: crosshair; +} +.CodeMirror-line::selection, +.CodeMirror-line > span::selection, +.CodeMirror-line > span > span::selection { + background: var(--playground-code-selection-background, #d7d4f0); +} + +/* Completions */ + +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 0; + + box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 5px -3px, + rgba(0, 0, 0, 0.14) 0px 8px 10px 1px, rgba(0, 0, 0, 0.12) 0px 3px 14px 2px; + border: 1px solid var(--playground-code-selection-background, silver); + + background: var(--playground-code-background, white); + font-size: var(--playground-code-font-size, 14px); + font-family: var(--playground-code-font-family, monospace); + + max-height: 20em; + width: 600px; + max-width: min(600px, 80vw); + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 6px; + white-space: pre; + color: var(--playground-code-cursor-color, black); + cursor: pointer; + display: flex; + justify-content: space-between; +} + +@media (pointer: coarse) { + .CodeMirror-hint { + padding: 1em 6px; + } +} + +.CodeMirror-hint-active { + background: var(--playground-code-background, rgba(0, 0, 0, 0.2)); + filter: brightness(1.2); +} + +.CodeMirror-hint mark { + background: inherit; + color: var(--playground-code-qualifier-color, #555); +} + +.CodeMirror-hint .hint-object-name { + padding-right: 2em; + white-space: nowrap; +} + +.CodeMirror-hint .hint-object-details { + flex-basis: 80%; + font-size: calc(var(--playground-code-font-size, 14px) * 0.9); + color: var(--playground-code-string-2-color, white); + opacity: 0.8; + text-align: right; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Used to force a border model for a node */ +.cm-force-border { + padding-right: 0.1px; +} + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { + content: ''; +} + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { + background: none; +} +` +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */;let wi=class extends de{render(){return W`
`}};wi.styles=c` + :host { + position: absolute; + width: 100%; + height: 100%; + box-sizing: border-box; + left: 0; + top: 0; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + z-index: 9; + background: rgba(0, 0, 0, 0.32); + overflow-y: auto; + } + + #message { + background: #fff; + color: #000; + padding: 10px 20px; + border-radius: 5px; + box-shadow: rgba(0, 0, 0, 0.3) 0 2px 10px; + } + `,wi=o([ue("playground-internal-overlay")],wi); +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let ki=class extends de{constructor(){super(...arguments),this._docCache=new WeakMap,this.lineNumbers=!1,this.lineWrapping=!1,this.readonly=!1,this.noCompletions=!1,this._completionsOpen=!1,this._currentCompletionSelectionLabel="",this._currentCompletionRequestId=0,this.pragmas="on",this._showKeyboardHelp=!1,this._resizing=!1,this._valueChangingFromOutside=!1,this._diagnosticMarkers=[],this._diagnosticsMouseoverListenerActive=!1,this._onMouseOverWithDiagnostics=e=>{var t,r,o;if(!(null===(t=this.diagnostics)||void 0===t?void 0:t.length))return;const i=null===(r=e.target.className)||void 0===r?void 0:r.match(/diagnostic-(\d+)/);if(null===i)return void(this._tooltipDiagnostic=void 0);const n=Number(i[1]),a=this.diagnostics[n];if(a===(null===(o=this._tooltipDiagnostic)||void 0===o?void 0:o.diagnostic))return;let l="";const s=this.getBoundingClientRect(),d=e.target.getBoundingClientRect(),c=s.y+s.height/2;d.y + ${this._showKeyboardHelp?W` +

+ Press Enter to start editing
+ Press Escape to exit editor +

+
`:j} + ${this._cmDom} +
+
+ ${null===(t=this._tooltipDiagnostic)||void 0===t?void 0:t.diagnostic.message} +
+
+ + `}connectedCallback(){"function"==typeof ResizeObserver&&(this._resizeObserver=new ResizeObserver((()=>{var e;this._resizing||(this._resizing=!0,null===(e=this._codemirror)||void 0===e||e.refresh(),this._resizing=!1)})),this._resizeObserver.observe(this)),super.connectedCallback()}disconnectedCallback(){var e;null===(e=this._resizeObserver)||void 0===e||e.disconnect(),this._resizeObserver=void 0,super.disconnectedCallback()}_createView(){var e;const t=vi((e=>{this._cmDom=e,this._resizing=!0,requestAnimationFrame((()=>{requestAnimationFrame((()=>{var e;null===(e=this._codemirror)||void 0===e||e.refresh(),this._resizing=!1}))}))}),{value:null!==(e=this.value)&&void 0!==e?e:"",lineNumbers:this.lineNumbers,lineWrapping:this.lineWrapping,mode:this._getLanguageMode(),readOnly:this.readonly,inputStyle:"contenteditable",tabindex:-1,extraKeys:{Tab:()=>{var e;t.replaceSelection(Array((null!==(e=t.getOption("indentUnit"))&&void 0!==e?e:2)+1).join(" "))},"Ctrl-Space":()=>{const e=this.tokenUnderCursor.string.trim();this._requestCompletions({isRefinement:!1,tokenUnderCursor:e})},"Ctrl-/":()=>t.toggleComment(),"Cmd-/":()=>t.toggleComment()}});t.on("change",((e,r)=>{this._value=t.getValue(),this._valueChangingFromOutside?(this._applyHideAndFoldRegions(),this._showDiagnostics()):(this.dispatchEvent(new Event("change")),this._requestCompletionsIfNeeded(r))})),this.lineWrapping&&t.on("renderLine",this._onRenderLine),this._codemirror=t}_onRenderLine(e,t,r){const o=e.getOption("lineNumbers")?"0.7em":"4px",i=e.getOption("tabSize")||4,n=vi.countColumn(t.text,null,i);n>0&&(r.style.textIndent=`-${n}ch`,r.style.paddingLeft=`calc(${o} + ${n}ch)`)}_requestCompletionsIfNeeded(e){if(this.noCompletions||!this._currentFiletypeSupportsCompletion()||!this._codemirror)return;const t=this._codemirror.getTokenAt(e.from),r=this.tokenUnderCursor.string.trim(),o=r.trim(),i="+input"===e.origin,n=(r.length>1||"."===t.string)&&i,a="complete"===e.origin;o.length<=0||(a?this._completions=[]:this._requestCompletions({isRefinement:n,tokenUnderCursor:r}))}_requestCompletions({isRefinement:e,tokenUnderCursor:t}){if(this.noCompletions||!this._currentFiletypeSupportsCompletion()||!this._codemirror)return;const r=++this._currentCompletionRequestId,o=this.cursorIndex;this.dispatchEvent(new CustomEvent("request-completions",{detail:{isRefinement:e,fileContent:this.value,tokenUnderCursor:t,cursorIndex:this.cursorIndex,provideCompletions:e=>this._onCompletionsProvided(r,e,o)}}))}_onCompletionsProvided(e,t,r){e===this._currentCompletionRequestId&&r===this.cursorIndex&&(this._completions=t)}_currentFiletypeSupportsCompletion(){return"ts"===this.type}focus(){var e;null===(e=this._codemirrorEditable)||void 0===e||e.focus()}_completionsAsHints(){var e,t;const r=this._codemirror,o=r.getCursor("start"),i=r.getTokenAt(o),n=o.line,a=null!==(t=null===(e=this._completions)||void 0===e?void 0:e.map(((e,t)=>({text:e.text,displayText:e.displayText,render:(r,o,i)=>{const n=i;this._renderHint(r,o,n,0===t?e.details:void 0)},get details(){return e.details}}))))&&void 0!==t?t:[],l={from:{line:n,ch:i.start},to:{line:n,ch:i.end},list:a};return vi.on(l,"select",(async(e,t)=>{var r;this._isCodeEditorHint(e)&&this._currentCompletionSelectionLabel!==e.text&&(null===(r=this._onCompletionSelectedChange)||void 0===r||r.call(this),this._renderHint(t,l,e,e.details))})),vi.on(l,"shown",(()=>{window.requestAnimationFrame((()=>{this._completionsOpen=!0}))})),vi.on(l,"close",(()=>{window.requestAnimationFrame((()=>{this._completionsOpen=!1}))})),l}_isCodeEditorHint(e){return"string"!=typeof e&&Object.prototype.hasOwnProperty.call(e,"details")}_renderHint(e,t,r,o){var i;if(!e)return;const n=t.list.indexOf(r),a=null===(i=this._completions)||void 0===i?void 0:i[n],l=this._buildHintObjectName(r.displayText,a);this._renderCompletionItem(l,e),void 0!==o&&o.then((o=>{this._renderCompletionItemWithDetails(l,o,e),this._onCompletionSelectedChange=()=>this._renderHint(e,t,r),this._currentCompletionSelectionLabel=r.text}))}_renderCompletionItem(e,t){ae(W`${e}`,t)}_renderCompletionItemWithDetails(e,t,r){ae(W`${e} + ${t.text} `,r)}_buildHintObjectName(e,t){var r;const o=null!=e?e:"",i=null!==(r=null==t?void 0:t.matches)&&void 0!==r?r:[];if(i.length<=0)return o;const n=i[0].indices[0],a=n[0],l=n[1],s=null==o?void 0:o.substring(0,a),d=null==o?void 0:o.substring(a,l+1),c=null==o?void 0:o.substring(l+1);return W` + ${s}${d}${c} + `}_showCompletions(){const e=this._codemirror;if(!e||!this._completions||this._completions.length<=0)return;const t={hint:this._completionsAsHints.bind(this),completeSingle:!1,closeOnPick:!0,closeOnUnfocus:!0,container:this._focusContainer,alignWithWord:!0};e.showHint(t)}_onMousedown(){var e;null===(e=this._codemirrorEditable)||void 0===e||e.focus()}_onFocus(){this._showKeyboardHelp=!0}_onBlur(){this._showKeyboardHelp=!1}_onKeyDown(e){var t,r;"Enter"===e.key&&e.target===this._focusContainer?(null===(t=this._codemirrorEditable)||void 0===t||t.focus(),e.preventDefault()):"Escape"===e.key&&(this._completionsOpen||null===(r=this._focusContainer)||void 0===r||r.focus())}async _applyHideAndFoldRegions(){const e=this._codemirror;if(!e)return;for(const t of e.getAllMarks())t.clear();if("off-visible"===this.pragmas)return;const t=this._maskPatternForLang();if(void 0===t)return;const r=e.getDoc(),o=(t,o)=>{e.foldCode(0,{widget:"…",rangeFinder:()=>({from:r.posFromIndex(t),to:r.posFromIndex(o)})})},i=(e,t,o)=>{r.markText(r.posFromIndex(e),r.posFromIndex(t),{collapsed:!0,readOnly:o})},n=e.getValue();for(const e of n.matchAll(t)){const[,t,r,a,l]=e,s=e.index;if(void 0===s)continue;const d=s+t.length;i(s,d,!1);const c=d;let u;a&&l?(u=c+a.length,i(u,u+l.length,!1)):u=n.length,"on"===this.pragmas&&("fold"===r?o(c,u):"hide"===r&&i(c,u,!0))}}_maskPatternForLang(){switch(this.type){case"js":case"ts":case"css":case"jsx":case"tsx":return/( *\/\* *playground-(?hide|fold) *\*\/\n?)(?:(.*?)( *\/\* *playground-\k-end *\*\/\n?))?/gs;case"html":return/( *\n?)(?:(.*?)( *\n?))?/gs;default:return}}_getLanguageMode(){switch(this.type){case"ts":return"google-typescript";case"js":case"json":return"google-javascript";case"html":return"google-html";case"css":return"css";case"jsx":case"tsx":return"jsx"}}_showDiagnostics(){const e=this._codemirror;void 0!==e&&e.operation((()=>{var t,r,o;for(this._tooltipDiagnostic=void 0;this._diagnosticMarkers.length>0;)this._diagnosticMarkers.pop().clear();if(null===(t=this.diagnostics)||void 0===t?void 0:t.length){this._diagnosticsMouseoverListenerActive||(null===(o=this._cmDom)||void 0===o||o.addEventListener("mouseover",this._onMouseOverWithDiagnostics),this._diagnosticsMouseoverListenerActive=!0);for(let t=0;t div { + background: var(--playground-code-background, #fff); + color: var(--playground-code-default-color, #000); + /* Kind of hacky... line number color tends to work out as a good + default border, because it's usually visible on top of the + background, but slightly muted. */ + border: 1px solid var(--playground-code-linenumber-color, #ccc); + padding: 5px; + } + `,xi],o([ge()],ki.prototype,"value",null),o([ge({attribute:!1})],ki.prototype,"documentKey",void 0),o([ge()],ki.prototype,"type",void 0),o([ge({type:Boolean,attribute:"line-numbers",reflect:!0})],ki.prototype,"lineNumbers",void 0),o([ge({type:Boolean,attribute:"line-wrapping",reflect:!0})],ki.prototype,"lineWrapping",void 0),o([ge({type:Boolean,reflect:!0})],ki.prototype,"readonly",void 0),o([ge({type:Boolean,attribute:"no-completions"})],ki.prototype,"noCompletions",void 0),o([ge({attribute:!1})],ki.prototype,"diagnostics",void 0),o([me()],ki.prototype,"_completions",void 0),o([me()],ki.prototype,"_completionsOpen",void 0),o([ge()],ki.prototype,"pragmas",void 0),o([me()],ki.prototype,"_tooltipDiagnostic",void 0),o([me()],ki.prototype,"_showKeyboardHelp",void 0),o([ye("#focusContainer")],ki.prototype,"_focusContainer",void 0),o([ye(".CodeMirror-code")],ki.prototype,"_codemirrorEditable",void 0),ki=o([ue("playground-code-editor")],ki); +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let _i=class extends ui{constructor(){super(...arguments),this.lineNumbers=!1,this.lineWrapping=!1,this.pragmas="on",this.readonly=!1,this.noCompletions=!1,this._onProjectFilesChanged=()=>{var e,t;null!==(e=this.filename)&&void 0!==e||(this.filename=null===(t=this._files[0])||void 0===t?void 0:t.name),this.requestUpdate()},this._onCompileDone=()=>{this.requestUpdate()},this._onDiagnosticsChanged=()=>{this.requestUpdate()}}get _files(){var e,t;return null!==(t=null===(e=this._project)||void 0===e?void 0:e.files)&&void 0!==t?t:[]}get _currentFile(){return this.filename?this._files.find((e=>e.name===this.filename)):void 0}async update(e){if(e.has("_project")){const t=e.get("_project");t&&(t.removeEventListener("filesChanged",this._onProjectFilesChanged),t.removeEventListener("compileDone",this._onCompileDone),t.removeEventListener("diagnosticsChanged",this._onDiagnosticsChanged)),this._project&&(this._project.addEventListener("filesChanged",this._onProjectFilesChanged),this._project.addEventListener("compileDone",this._onCompileDone),this._project.addEventListener("diagnosticsChanged",this._onDiagnosticsChanged)),this._onProjectFilesChanged()}super.update(e)}render(){var e,t,r,o,i,n;return W` + ${this._files?W` + + + `:W``} + `}_onEdit(){void 0!==this._project&&void 0!==this._currentFile&&void 0!==this._editor.value&&this._project.editFile(this._currentFile,this._editor.value)}async _onRequestCompletions(e){var t,r;const o=e.detail;o.fileName=null!==(t=this.filename)&&void 0!==t?t:"";const i=await(null===(r=this._project)||void 0===r?void 0:r.getCompletions(o));i&&o.provideCompletions(i)}};_i.styles=c` + :host { + display: block; + /* Prevents scrollbars from changing container size and shifting layout + slightly. */ + box-sizing: border-box; + height: 350px; + } + + slot { + height: 100%; + display: block; + background: var(--playground-code-background, unset); + } + + playground-code-editor { + height: 100%; + border-radius: inherit; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + `,o([ye("playground-code-editor")],_i.prototype,"_editor",void 0),o([ge()],_i.prototype,"filename",void 0),o([ge({type:Boolean,attribute:"line-numbers"})],_i.prototype,"lineNumbers",void 0),o([ge({type:Boolean,attribute:"line-wrapping"})],_i.prototype,"lineWrapping",void 0),o([ge()],_i.prototype,"pragmas",void 0),o([ge({type:Boolean,reflect:!0})],_i.prototype,"readonly",void 0),o([ge({type:Boolean,attribute:"no-completions"})],_i.prototype,"noCompletions",void 0),_i=o([ue("playground-file-editor")],_i);const Ci=e=>{if(void 0===e)return;const t=e.indexOf(";");switch(-1!==t&&(e=e.substring(0,t)),e){case"video/mp2t":return"ts";case"text/javascript":case"application/javascript":return"js";case"text/jsx":return"jsx";case"text/typescript-jsx":return"tsx";case"application/json":return"json";case"text/html":return"html";case"text/css":return"css"}}; +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */class Si extends de{constructor(){super(...arguments),this.indeterminate=!1,this.progress=0,this.buffer=1,this.reverse=!1,this.closed=!1,this.stylePrimaryHalf="",this.stylePrimaryFull="",this.styleSecondaryQuarter="",this.styleSecondaryHalf="",this.styleSecondaryFull="",this.animationReady=!0,this.closedAnimationOff=!1,this.resizeObserver=null}connectedCallback(){super.connectedCallback(),this.rootEl&&this.attachResizeObserver()}render(){const e={"mdc-linear-progress--closed":this.closed,"mdc-linear-progress--closed-animation-off":this.closedAnimationOff,"mdc-linear-progress--indeterminate":this.indeterminate,"mdc-linear-progress--animation-ready":this.animationReady},t={"--mdc-linear-progress-primary-half":this.stylePrimaryHalf,"--mdc-linear-progress-primary-half-neg":""!==this.stylePrimaryHalf?"-"+this.stylePrimaryHalf:"","--mdc-linear-progress-primary-full":this.stylePrimaryFull,"--mdc-linear-progress-primary-full-neg":""!==this.stylePrimaryFull?"-"+this.stylePrimaryFull:"","--mdc-linear-progress-secondary-quarter":this.styleSecondaryQuarter,"--mdc-linear-progress-secondary-quarter-neg":""!==this.styleSecondaryQuarter?"-"+this.styleSecondaryQuarter:"","--mdc-linear-progress-secondary-half":this.styleSecondaryHalf,"--mdc-linear-progress-secondary-half-neg":""!==this.styleSecondaryHalf?"-"+this.styleSecondaryHalf:"","--mdc-linear-progress-secondary-full":this.styleSecondaryFull,"--mdc-linear-progress-secondary-full-neg":""!==this.styleSecondaryFull?"-"+this.styleSecondaryFull:""},r={"flex-basis":this.indeterminate?"100%":100*this.buffer+"%"},o={transform:this.indeterminate?"scaleX(1)":`scaleX(${this.progress})`};return W` +
+
+
+
+
+
+
+ +
+
+ +
+
`}update(e){!e.has("closed")||this.closed&&void 0!==e.get("closed")||this.syncClosedState(),super.update(e)}async firstUpdated(e){super.firstUpdated(e),this.attachResizeObserver()}syncClosedState(){this.closedAnimationOff=this.closed}updated(e){!e.has("indeterminate")&&e.has("reverse")&&this.indeterminate&&this.restartAnimation(),e.has("indeterminate")&&void 0!==e.get("indeterminate")&&this.indeterminate&&window.ResizeObserver&&this.calculateAndSetAnimationDimensions(this.rootEl.offsetWidth),super.updated(e)}disconnectedCallback(){this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),super.disconnectedCallback()}attachResizeObserver(){if(window.ResizeObserver)return this.resizeObserver=new window.ResizeObserver((e=>{if(this.indeterminate)for(const t of e)if(t.contentRect){const e=t.contentRect.width;this.calculateAndSetAnimationDimensions(e)}})),void this.resizeObserver.observe(this.rootEl);this.resizeObserver=null}calculateAndSetAnimationDimensions(e){const t=.8367142*e,r=2.00611057*e,o=.37651913*e,i=.84386165*e,n=1.60277782*e;this.stylePrimaryHalf=t+"px",this.stylePrimaryFull=r+"px",this.styleSecondaryQuarter=o+"px",this.styleSecondaryHalf=i+"px",this.styleSecondaryFull=n+"px",this.restartAnimation()}async restartAnimation(){this.animationReady=!1,await this.updateComplete,await new Promise(requestAnimationFrame),this.animationReady=!0,await this.updateComplete}open(){this.closed=!1}close(){this.closed=!0}}o([ye(".mdc-linear-progress")],Si.prototype,"rootEl",void 0),o([ge({type:Boolean,reflect:!0})],Si.prototype,"indeterminate",void 0),o([ge({type:Number})],Si.prototype,"progress",void 0),o([ge({type:Number})],Si.prototype,"buffer",void 0),o([ge({type:Boolean,reflect:!0})],Si.prototype,"reverse",void 0),o([ge({type:Boolean,reflect:!0})],Si.prototype,"closed",void 0),o([vr,ge({attribute:"aria-label"})],Si.prototype,"ariaLabel",void 0),o([me()],Si.prototype,"stylePrimaryHalf",void 0),o([me()],Si.prototype,"stylePrimaryFull",void 0),o([me()],Si.prototype,"styleSecondaryQuarter",void 0),o([me()],Si.prototype,"styleSecondaryHalf",void 0),o([me()],Si.prototype,"styleSecondaryFull",void 0),o([me()],Si.prototype,"animationReady",void 0),o([me()],Si.prototype,"closedAnimationOff",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const Ei=c`@keyframes mdc-linear-progress-primary-indeterminate-translate{0%{transform:translateX(0)}20%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(0)}59.15%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(83.67142%);transform:translateX(var(--mdc-linear-progress-primary-half, 83.67142%))}100%{transform:translateX(200.611057%);transform:translateX(var(--mdc-linear-progress-primary-full, 200.611057%))}}@keyframes mdc-linear-progress-primary-indeterminate-scale{0%{transform:scaleX(0.08)}36.65%{animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);transform:scaleX(0.08)}69.15%{animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);transform:scaleX(0.661479)}100%{transform:scaleX(0.08)}}@keyframes mdc-linear-progress-secondary-indeterminate-translate{0%{animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);transform:translateX(0)}25%{animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);transform:translateX(37.651913%);transform:translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%))}48.35%{animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);transform:translateX(84.386165%);transform:translateX(var(--mdc-linear-progress-secondary-half, 84.386165%))}100%{transform:translateX(160.277782%);transform:translateX(var(--mdc-linear-progress-secondary-full, 160.277782%))}}@keyframes mdc-linear-progress-secondary-indeterminate-scale{0%{animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);transform:scaleX(0.08)}19.15%{animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);transform:scaleX(0.457104)}44.15%{animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);transform:scaleX(0.72796)}100%{transform:scaleX(0.08)}}@keyframes mdc-linear-progress-buffering{from{transform:rotate(180deg) translateX(-10px)}}@keyframes mdc-linear-progress-primary-indeterminate-translate-reverse{0%{transform:translateX(0)}20%{animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);transform:translateX(0)}59.15%{animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);transform:translateX(-83.67142%);transform:translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%))}100%{transform:translateX(-200.611057%);transform:translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%))}}@keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse{0%{animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);transform:translateX(0)}25%{animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);transform:translateX(-37.651913%);transform:translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%))}48.35%{animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);transform:translateX(-84.386165%);transform:translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%))}100%{transform:translateX(-160.277782%);transform:translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%))}}@keyframes mdc-linear-progress-buffering-reverse{from{transform:translateX(-10px)}}.mdc-linear-progress{position:relative;width:100%;transform:translateZ(0);outline:1px solid transparent;overflow:hidden;transition:opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}@media screen and (forced-colors: active){.mdc-linear-progress{outline-color:CanvasText}}.mdc-linear-progress__bar{position:absolute;width:100%;height:100%;animation:none;transform-origin:top left;transition:transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__bar-inner{display:inline-block;position:absolute;width:100%;animation:none;border-top-style:solid}.mdc-linear-progress__buffer{display:flex;position:absolute;width:100%;height:100%}.mdc-linear-progress__buffer-dots{background-repeat:repeat-x;flex:auto;transform:rotate(180deg);animation:mdc-linear-progress-buffering 250ms infinite linear}.mdc-linear-progress__buffer-bar{flex:0 1 100%;transition:flex-basis 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__primary-bar{transform:scaleX(0)}.mdc-linear-progress__secondary-bar{display:none}.mdc-linear-progress--indeterminate .mdc-linear-progress__bar{transition:none}.mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar{left:-145.166611%}.mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar{left:-54.888891%;display:block}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar{animation:mdc-linear-progress-primary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar>.mdc-linear-progress__bar-inner{animation:mdc-linear-progress-primary-indeterminate-scale 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar{animation:mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar>.mdc-linear-progress__bar-inner{animation:mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear}[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__bar{right:0;-webkit-transform-origin:center right;transform-origin:center right}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar{animation-name:mdc-linear-progress-primary-indeterminate-translate-reverse}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar{animation-name:mdc-linear-progress-secondary-indeterminate-translate-reverse}[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__buffer-dots,.mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__buffer-dots{animation:mdc-linear-progress-buffering-reverse 250ms infinite linear;transform:rotate(0)}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar{right:-145.166611%;left:auto}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar{right:-54.888891%;left:auto}.mdc-linear-progress--closed{opacity:0}.mdc-linear-progress--closed-animation-off .mdc-linear-progress__buffer-dots{animation:none}.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar,.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar .mdc-linear-progress__bar-inner{animation:none}.mdc-linear-progress__bar-inner{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-linear-progress__buffer-dots{background-image:url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E")}.mdc-linear-progress__buffer-bar{background-color:#e6e6e6}.mdc-linear-progress{height:4px}.mdc-linear-progress__bar-inner{border-top-width:4px}.mdc-linear-progress__buffer-dots{background-size:10px 4px}:host{display:block}.mdc-linear-progress__buffer-bar{background-color:#e6e6e6;background-color:var(--mdc-linear-progress-buffer-color, #e6e6e6)}.mdc-linear-progress__buffer-dots{background-image:url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E");background-image:var(--mdc-linear-progress-buffering-dots-image, url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E"))}` +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let Ti=class extends Si{};Ti.styles=[Ei],Ti=o([ue("mwc-linear-progress")],Ti); +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let Ai=class extends ui{constructor(){super(),this.htmlFile="index.html",this.location="Result",this._loading=!0,this._showLoadingBar=!1,this._loadedAtLeastOnce=!1,this.reload=()=>{const e=this.iframe;if(!e)return;const{parentNode:t,nextSibling:r}=e;t&&e.remove(),e.src="",e.src=this._indexUrl,t&&t.insertBefore(e,r),this._loading=!0,this._showLoadingBar=!0},void 0===navigator.serviceWorker&&(this._error=W`

+ Sorry! Preview unavailable because this browser doesn't + support + service workers. +

+

+ Note: Firefox + doesn't + support service workers in private browsing mode. +

`)}update(e){if(e.has("_project")){const t=e.get("_project");t&&(t.removeEventListener("urlChanged",this.reload),t.removeEventListener("compileStart",this.reload)),this._project&&(this._project.addEventListener("urlChanged",this.reload),this._project.addEventListener("compileStart",this.reload))}super.update(e)}get _indexUrl(){var e;const t=null===(e=this._project)||void 0===e?void 0:e.baseUrl;return t&&this.htmlFile?new URL(this.htmlFile,t).toString():""}render(){return W` +
+ ${this.location} + + + + + + +
+ +
+ + + ${this._loadedAtLeastOnce?j:W``} + + +
+ + ${this._error?W` + + ${this._error} + `:j} + `}updated(){this.iframe&&this.iframe.src!==this._indexUrl&&(this.iframe.src=this._indexUrl)}async firstUpdated(){var e,t;this._loading&&!this._slotHasAnyVisibleChildren()&&(this._showLoadingBar=!0);const r=this.shadowRoot.querySelector("mwc-linear-progress");await r.updateComplete,null===(t=null===(e=r.shadowRoot)||void 0===e?void 0:e.querySelector("[role=progressbar]"))||void 0===t||t.setAttribute("aria-label","Preview is loading")}_slotHasAnyVisibleChildren(){var e;const t=null===(e=this._slot)||void 0===e?void 0:e.assignedNodes({flatten:!0});if(!t)return!1;for(const e of t)if(e.nodeType!==Node.COMMENT_NODE&&(e.nodeType!==Node.TEXT_NODE||""!==(e.textContent||"").trim()))return!0;return!1}_onIframeLoad(){this._indexUrl&&(this._loading=!1,this._loadedAtLeastOnce=!0,this._showLoadingBar=!1)}};Ai.styles=c` + :host { + display: flex; + flex-direction: column; + background: white; + font-family: sans-serif; + height: 350px; + position: relative; /* for the error message overlay */ + } + + #toolbar { + flex: 0 0 var(--playground-bar-height, 40px); + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: var(--playground-border, solid 1px #ddd); + font-size: 15px; + color: var(--playground-preview-toolbar-foreground-color, #444); + border-radius: inherit; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background: var(--playground-preview-toolbar-background, white); + } + + #location { + margin: 0 10px; + } + + #reload-button { + --mdc-icon-button-size: 30px; + --mdc-icon-size: 18px; + } + + #content { + max-height: 100%; + position: relative; + flex: 1; + } + + #content.error { + display: none; + } + + #error { + padding: 0 20px; + } + + mwc-linear-progress { + /* There is no way to directly specify the height of a linear progress + bar, but zooming works well enough. It's 4px by default, and we want it to + be 2px to match the tab bar indicator.*/ + zoom: 0.5; + --mdc-linear-progress-buffer-color: transparent; + position: absolute; + top: -6px; + width: 100%; + --mdc-theme-primary: var(--playground-highlight-color, #6200ee); + } + + iframe, + slot { + width: 100%; + height: 100%; + } + + iframe { + border: none; + } + + [hidden] { + display: none; + } + `,o([ge({attribute:"html-file"})],Ai.prototype,"htmlFile",void 0),o([ge()],Ai.prototype,"location",void 0),o([ye("iframe",!0)],Ai.prototype,"iframe",void 0),o([ye("slot")],Ai.prototype,"_slot",void 0),o([me()],Ai.prototype,"_loading",void 0),o([me()],Ai.prototype,"_showLoadingBar",void 0),o([me()],Ai.prototype,"_loadedAtLeastOnce",void 0),o([me()],Ai.prototype,"_error",void 0),Ai=o([ue("playground-preview")],Ai); +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let Oi=class extends de{constructor(){super(...arguments),this.sandboxBaseUrl=`https://unpkg.com/playground-elements@${It}/`,this.sandboxScope=`__playground_swfs_${Rt}/`,this.editableFileSystem=!1,this.lineNumbers=!1,this.lineWrapping=!1,this.resizable=!1,this.pragmas="on",this.htmlFile="index.html",this.noCompletions=!1}get projectSrc(){var e,t;return null!==(t=null===(e=this._project)||void 0===e?void 0:e.projectSrc)&&void 0!==t?t:this._projectSrcSetBeforeRender}set projectSrc(e){const t=this._project;t?t.projectSrc=e:this._projectSrcSetBeforeRender=e}get config(){var e,t;return null!==(t=null===(e=this._project)||void 0===e?void 0:e.config)&&void 0!==t?t:this._configSetBeforeRender}set config(e){const t=this._project;t?t.config=e:this._configSetBeforeRender=e}get modified(){var e,t;return null!==(t=null===(e=this._project)||void 0===e?void 0:e.modified)&&void 0!==t&&t}render(){const e="project",t="editor";return W` + + + + +
+ + + + + +
+ +
+ ${this.resizable?W`
`:j} + + +
+ `}firstUpdated(){this._configSetBeforeRender&&(this._project.config=this._configSetBeforeRender,this._configSetBeforeRender=void 0),this._projectSrcSetBeforeRender&&(this._project.projectSrc=this._projectSrcSetBeforeRender,this._projectSrcSetBeforeRender=void 0)}async update(e){var t;e.has("resizable")&&!1===this.resizable&&(null===(t=this._rhs)||void 0===t||t.style.removeProperty("--playground-preview-width")),super.update(e)}_onResizeBarPointerdown({pointerId:e}){const t=this._resizeBar;t.setPointerCapture(e);const r=this._rhs.style,{left:o,right:i}=this.getBoundingClientRect(),n=i-o,a=n-100,l=e=>{const t=Math.min(a,Math.max(100,i-e.clientX))/n*100;r.setProperty("--playground-preview-width",t+"%")};t.addEventListener("pointermove",l);const s=()=>{t.releasePointerCapture(e),t.removeEventListener("pointermove",l),t.removeEventListener("pointerup",s)};t.addEventListener("pointerup",s)}};Oi.styles=c` + :host { + display: flex; + height: 350px; + min-width: 200px; + border: var(--playground-border, solid 1px #ddd); + /* The invisible resize bar has a high z-index so that it's above + CodeMirror. But we don't want it also above other elements on the page. + Force a new stacking context. */ + isolation: isolate; + } + + #lhs { + display: flex; + flex-direction: column; + height: 100%; + flex: 1; + min-width: 100px; + border-radius: inherit; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: var(--playground-border, solid 1px #ddd); + } + + playground-tab-bar { + flex-shrink: 0; + } + + playground-file-editor { + flex: 1; + height: calc(100% - var(--playground-bar-height, 40px)); + } + + #rhs { + height: 100%; + width: max(100px, var(--playground-preview-width, 30%)); + position: relative; + border-radius: inherit; + } + + playground-preview { + height: 100%; + width: 100%; + border-radius: inherit; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + slot { + display: none; + } + + #resizeBar { + position: absolute; + top: 0; + left: -5px; + width: 10px; + height: 100%; + z-index: 9; + cursor: col-resize; + } + + #resizeOverlay { + display: none; + } + #resizeOverlay.resizing { + display: block; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 99999; + cursor: col-resize; + } + `,o([ge({attribute:"project-src",hasChanged:()=>!1})],Oi.prototype,"projectSrc",null),o([ge({attribute:!1,hasChanged:()=>!1})],Oi.prototype,"config",null),o([ge({attribute:"sandbox-base-url"})],Oi.prototype,"sandboxBaseUrl",void 0),o([ge({attribute:"sandbox-scope"})],Oi.prototype,"sandboxScope",void 0),o([ge({type:Boolean,attribute:"editable-file-system"})],Oi.prototype,"editableFileSystem",void 0),o([ge({type:Boolean,attribute:"line-numbers"})],Oi.prototype,"lineNumbers",void 0),o([ge({type:Boolean,attribute:"line-wrapping"})],Oi.prototype,"lineWrapping",void 0),o([ge({type:Boolean})],Oi.prototype,"resizable",void 0),o([ge()],Oi.prototype,"pragmas",void 0),o([ge({attribute:"html-file"})],Oi.prototype,"htmlFile",void 0),o([ge({type:Boolean,attribute:"no-completions"})],Oi.prototype,"noCompletions",void 0),o([ye("playground-project")],Oi.prototype,"_project",void 0),o([ye("#resizeBar")],Oi.prototype,"_resizeBar",void 0),o([ye("#rhs")],Oi.prototype,"_rhs",void 0),Oi=o([ue("playground-ide")],Oi);const Li=[c` +.playground-theme-3024-day { + --playground-code-background: rgb(247, 247, 247); + --playground-code-default-color: rgb(58, 52, 50); + --playground-code-cursor-color: rgb(92, 88, 85); + --playground-code-selection-background: rgb(214, 213, 212); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(128, 125, 124); + --playground-code-atom-color: rgb(161, 106, 148); + --playground-code-attribute-color: rgb(1, 162, 82); + --playground-code-builtin-color: rgb(58, 52, 50); + --playground-code-comment-color: rgb(205, 171, 83); + --playground-code-def-color: rgb(232, 187, 208); + --playground-code-keyword-color: rgb(219, 45, 32); + --playground-code-meta-color: rgb(58, 52, 50); + --playground-code-number-color: rgb(161, 106, 148); + --playground-code-operator-color: rgb(58, 52, 50); + --playground-code-qualifier-color: rgb(58, 52, 50); + --playground-code-string-color: rgb(253, 237, 2); + --playground-code-string-2-color: rgb(58, 52, 50); + --playground-code-tag-color: rgb(219, 45, 32); + --playground-code-type-color: rgb(58, 52, 50); + --playground-code-variable-color: rgb(1, 162, 82); + --playground-code-variable-2-color: rgb(1, 160, 228); + --playground-code-variable-3-color: rgb(58, 52, 50); + --playground-code-callee-color: rgb(58, 52, 50); + --playground-code-property-color: rgb(1, 162, 82) +} +`,c` +.playground-theme-3024-night { + --playground-code-background: rgb(9, 3, 0); + --playground-code-default-color: rgb(214, 213, 212); + --playground-code-cursor-color: rgb(128, 125, 124); + --playground-code-selection-background: rgb(58, 52, 50); + --playground-code-gutter-background: rgb(9, 3, 0); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(92, 88, 85); + --playground-code-atom-color: rgb(161, 106, 148); + --playground-code-attribute-color: rgb(1, 162, 82); + --playground-code-builtin-color: rgb(214, 213, 212); + --playground-code-comment-color: rgb(205, 171, 83); + --playground-code-def-color: rgb(232, 187, 208); + --playground-code-keyword-color: rgb(219, 45, 32); + --playground-code-meta-color: rgb(214, 213, 212); + --playground-code-number-color: rgb(161, 106, 148); + --playground-code-operator-color: rgb(214, 213, 212); + --playground-code-qualifier-color: rgb(214, 213, 212); + --playground-code-string-color: rgb(253, 237, 2); + --playground-code-string-2-color: rgb(214, 213, 212); + --playground-code-tag-color: rgb(219, 45, 32); + --playground-code-type-color: rgb(214, 213, 212); + --playground-code-variable-color: rgb(1, 162, 82); + --playground-code-variable-2-color: rgb(1, 160, 228); + --playground-code-variable-3-color: rgb(214, 213, 212); + --playground-code-callee-color: rgb(214, 213, 212); + --playground-code-property-color: rgb(1, 162, 82) +} +`,c` +.playground-theme-abbott { + --playground-code-background: rgb(35, 28, 20); + --playground-code-default-color: rgb(216, 255, 132); + --playground-code-cursor-color: rgb(160, 234, 0); + --playground-code-selection-background: rgb(39, 57, 0); + --playground-code-gutter-background: rgb(35, 28, 20); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(251, 236, 93); + --playground-code-atom-color: rgb(254, 243, 180); + --playground-code-attribute-color: rgb(36, 165, 7); + --playground-code-builtin-color: rgb(63, 145, 241); + --playground-code-comment-color: rgb(251, 179, 47); + --playground-code-def-color: rgb(140, 205, 240); + --playground-code-keyword-color: rgb(216, 4, 80); + --playground-code-meta-color: rgb(236, 108, 153); + --playground-code-number-color: rgb(246, 63, 5); + --playground-code-operator-color: rgb(216, 255, 132); + --playground-code-qualifier-color: rgb(63, 145, 241); + --playground-code-string-color: rgb(230, 162, 243); + --playground-code-string-2-color: rgb(230, 162, 243); + --playground-code-tag-color: rgb(216, 4, 80); + --playground-code-type-color: rgb(36, 165, 7); + --playground-code-variable-color: rgb(140, 205, 240); + --playground-code-variable-2-color: rgb(140, 205, 240); + --playground-code-variable-3-color: rgb(140, 205, 240); + --playground-code-callee-color: rgb(216, 255, 132); + --playground-code-property-color: rgb(63, 145, 241) +} +`,c` +.playground-theme-abcdef { + --playground-code-background: rgb(15, 15, 15); + --playground-code-default-color: rgb(222, 253, 239); + --playground-code-cursor-color: rgb(0, 255, 0); + --playground-code-selection-background: rgb(81, 81, 81); + --playground-code-gutter-background: rgb(85, 85, 85); + --playground-code-gutter-border-right: 2px solid rgb(49, 65, 81); + --playground-code-linenumber-color: rgb(255, 255, 255); + --playground-code-atom-color: rgb(119, 119, 255); + --playground-code-attribute-color: rgb(221, 255, 0); + --playground-code-builtin-color: rgb(48, 170, 188); + --playground-code-comment-color: rgb(122, 123, 124); + --playground-code-def-color: rgb(255, 250, 188); + --playground-code-keyword-color: rgb(184, 134, 11); + --playground-code-meta-color: rgb(204, 153, 255); + --playground-code-number-color: rgb(238, 130, 238); + --playground-code-operator-color: rgb(255, 255, 0); + --playground-code-qualifier-color: rgb(255, 247, 0); + --playground-code-string-color: rgb(34, 187, 68); + --playground-code-string-2-color: rgb(222, 253, 239); + --playground-code-tag-color: rgb(255, 221, 68); + --playground-code-type-color: rgb(221, 238, 255); + --playground-code-variable-color: rgb(171, 205, 239); + --playground-code-variable-2-color: rgb(202, 203, 204); + --playground-code-variable-3-color: rgb(221, 238, 255); + --playground-code-callee-color: rgb(222, 253, 239); + --playground-code-property-color: rgb(254, 220, 186) +} +`,c` +.playground-theme-ambiance { + --playground-code-background: rgb(32, 32, 32) url("data:image/png;base64,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") repeat scroll 0% 0%/auto padding-box border-box; + --playground-code-default-color: rgb(230, 225, 220); + --playground-code-cursor-color: rgb(121, 145, 232); + --playground-code-selection-background: rgba(255, 255, 255, 0.15); + --playground-code-gutter-background: rgb(61, 61, 61) url("data:image/png;base64,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") repeat scroll 0% 0%/auto padding-box border-box; + --playground-code-gutter-border-right: 1px solid rgb(77, 77, 77); + --playground-code-gutter-box-shadow: rgb(0, 0, 0) 0px 10px 20px 0px; + --playground-code-linenumber-color: rgb(17, 17, 17); + --playground-code-atom-color: rgb(207, 126, 169); + --playground-code-attribute-color: rgb(155, 133, 157); + --playground-code-builtin-color: rgb(153, 153, 204); + --playground-code-comment-color: rgb(85, 85, 85); + --playground-code-def-color: rgb(170, 198, 227); + --playground-code-keyword-color: rgb(205, 168, 105); + --playground-code-meta-color: rgb(210, 168, 161); + --playground-code-number-color: rgb(120, 207, 138); + --playground-code-operator-color: rgb(250, 141, 106); + --playground-code-qualifier-color: rgb(255, 255, 0); + --playground-code-string-color: rgb(143, 157, 106); + --playground-code-string-2-color: rgb(157, 147, 124); + --playground-code-tag-color: rgb(254, 228, 255); + --playground-code-type-color: rgb(250, 222, 211); + --playground-code-variable-color: rgb(255, 183, 149); + --playground-code-variable-2-color: rgb(238, 209, 179); + --playground-code-variable-3-color: rgb(250, 222, 211); + --playground-code-callee-color: rgb(230, 225, 220); + --playground-code-property-color: rgb(238, 209, 179) +} +`,c` +.playground-theme-ayu-dark { + --playground-code-background: rgb(10, 14, 20); + --playground-code-default-color: rgb(179, 177, 173); + --playground-code-cursor-color: rgb(230, 180, 80); + --playground-code-selection-background: rgb(39, 55, 71); + --playground-code-gutter-background: rgb(10, 14, 20); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(61, 66, 77); + --playground-code-atom-color: rgb(174, 129, 255); + --playground-code-attribute-color: rgb(255, 180, 84); + --playground-code-builtin-color: rgb(230, 180, 80); + --playground-code-comment-color: rgb(98, 106, 115); + --playground-code-def-color: rgb(255, 238, 153); + --playground-code-keyword-color: rgb(255, 143, 64); + --playground-code-meta-color: rgb(179, 177, 173); + --playground-code-number-color: rgb(230, 180, 80); + --playground-code-operator-color: rgb(179, 177, 173); + --playground-code-qualifier-color: rgb(179, 177, 173); + --playground-code-string-color: rgb(194, 217, 76); + --playground-code-string-2-color: rgb(179, 177, 173); + --playground-code-tag-color: rgb(57, 186, 230); + --playground-code-type-color: rgb(255, 143, 64); + --playground-code-variable-color: rgb(179, 177, 173); + --playground-code-variable-2-color: rgb(240, 113, 120); + --playground-code-variable-3-color: rgb(57, 186, 230); + --playground-code-callee-color: rgb(179, 177, 173); + --playground-code-property-color: rgb(255, 180, 84) +} +`,c` +.playground-theme-ayu-mirage { + --playground-code-background: rgb(31, 36, 48); + --playground-code-default-color: rgb(203, 204, 198); + --playground-code-cursor-color: rgb(255, 204, 102); + --playground-code-selection-background: rgb(52, 69, 90); + --playground-code-gutter-background: rgb(31, 36, 48); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(61, 66, 77); + --playground-code-atom-color: rgb(174, 129, 255); + --playground-code-attribute-color: rgb(255, 213, 128); + --playground-code-builtin-color: rgb(255, 204, 102); + --playground-code-comment-color: rgb(92, 103, 115); + --playground-code-def-color: rgb(255, 213, 128); + --playground-code-keyword-color: rgb(255, 167, 89); + --playground-code-meta-color: rgb(203, 204, 198); + --playground-code-number-color: rgb(255, 204, 102); + --playground-code-operator-color: rgb(203, 204, 198); + --playground-code-qualifier-color: rgb(203, 204, 198); + --playground-code-string-color: rgb(186, 230, 126); + --playground-code-string-2-color: rgb(203, 204, 198); + --playground-code-tag-color: rgb(92, 207, 230); + --playground-code-type-color: rgb(255, 167, 89); + --playground-code-variable-color: rgb(203, 204, 198); + --playground-code-variable-2-color: rgb(242, 135, 121); + --playground-code-variable-3-color: rgb(92, 207, 230); + --playground-code-callee-color: rgb(203, 204, 198); + --playground-code-property-color: rgb(242, 158, 116) +} +`,c` +.playground-theme-base16-dark { + --playground-code-background: rgb(21, 21, 21); + --playground-code-default-color: rgb(224, 224, 224); + --playground-code-cursor-color: rgb(176, 176, 176); + --playground-code-selection-background: rgb(48, 48, 48); + --playground-code-gutter-background: rgb(21, 21, 21); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(80, 80, 80); + --playground-code-atom-color: rgb(170, 117, 159); + --playground-code-attribute-color: rgb(144, 169, 89); + --playground-code-builtin-color: rgb(224, 224, 224); + --playground-code-comment-color: rgb(143, 85, 54); + --playground-code-def-color: rgb(210, 132, 69); + --playground-code-keyword-color: rgb(172, 65, 66); + --playground-code-meta-color: rgb(224, 224, 224); + --playground-code-number-color: rgb(170, 117, 159); + --playground-code-operator-color: rgb(224, 224, 224); + --playground-code-qualifier-color: rgb(224, 224, 224); + --playground-code-string-color: rgb(244, 191, 117); + --playground-code-string-2-color: rgb(224, 224, 224); + --playground-code-tag-color: rgb(172, 65, 66); + --playground-code-type-color: rgb(224, 224, 224); + --playground-code-variable-color: rgb(144, 169, 89); + --playground-code-variable-2-color: rgb(106, 159, 181); + --playground-code-variable-3-color: rgb(224, 224, 224); + --playground-code-callee-color: rgb(224, 224, 224); + --playground-code-property-color: rgb(144, 169, 89) +} +`,c` +.playground-theme-base16-light { + --playground-code-background: rgb(245, 245, 245); + --playground-code-default-color: rgb(32, 32, 32); + --playground-code-cursor-color: rgb(80, 80, 80); + --playground-code-selection-background: rgb(224, 224, 224); + --playground-code-gutter-background: rgb(245, 245, 245); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(176, 176, 176); + --playground-code-atom-color: rgb(170, 117, 159); + --playground-code-attribute-color: rgb(144, 169, 89); + --playground-code-builtin-color: rgb(32, 32, 32); + --playground-code-comment-color: rgb(143, 85, 54); + --playground-code-def-color: rgb(210, 132, 69); + --playground-code-keyword-color: rgb(172, 65, 66); + --playground-code-meta-color: rgb(32, 32, 32); + --playground-code-number-color: rgb(170, 117, 159); + --playground-code-operator-color: rgb(32, 32, 32); + --playground-code-qualifier-color: rgb(32, 32, 32); + --playground-code-string-color: rgb(244, 191, 117); + --playground-code-string-2-color: rgb(32, 32, 32); + --playground-code-tag-color: rgb(172, 65, 66); + --playground-code-type-color: rgb(32, 32, 32); + --playground-code-variable-color: rgb(144, 169, 89); + --playground-code-variable-2-color: rgb(106, 159, 181); + --playground-code-variable-3-color: rgb(32, 32, 32); + --playground-code-callee-color: rgb(32, 32, 32); + --playground-code-property-color: rgb(144, 169, 89) +} +`,c` +.playground-theme-bespin { + --playground-code-background: rgb(40, 33, 28); + --playground-code-default-color: rgb(157, 155, 151); + --playground-code-cursor-color: rgb(121, 121, 119); + --playground-code-selection-background: rgb(89, 85, 79); + --playground-code-gutter-background: rgb(40, 33, 28); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(102, 102, 102); + --playground-code-atom-color: rgb(155, 133, 157); + --playground-code-attribute-color: rgb(84, 190, 13); + --playground-code-builtin-color: rgb(157, 155, 151); + --playground-code-comment-color: rgb(147, 113, 33); + --playground-code-def-color: rgb(207, 125, 52); + --playground-code-keyword-color: rgb(207, 106, 76); + --playground-code-meta-color: rgb(157, 155, 151); + --playground-code-number-color: rgb(155, 133, 157); + --playground-code-operator-color: rgb(157, 155, 151); + --playground-code-qualifier-color: rgb(157, 155, 151); + --playground-code-string-color: rgb(249, 238, 152); + --playground-code-string-2-color: rgb(157, 155, 151); + --playground-code-tag-color: rgb(207, 106, 76); + --playground-code-type-color: rgb(157, 155, 151); + --playground-code-variable-color: rgb(84, 190, 13); + --playground-code-variable-2-color: rgb(94, 166, 234); + --playground-code-variable-3-color: rgb(157, 155, 151); + --playground-code-callee-color: rgb(157, 155, 151); + --playground-code-property-color: rgb(84, 190, 13) +} +`,c` +.playground-theme-blackboard { + --playground-code-background: rgb(12, 16, 33); + --playground-code-default-color: rgb(248, 248, 248); + --playground-code-cursor-color: rgb(167, 167, 167); + --playground-code-selection-background: rgb(37, 59, 118); + --playground-code-gutter-background: rgb(12, 16, 33); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(136, 136, 136); + --playground-code-atom-color: rgb(216, 250, 60); + --playground-code-attribute-color: rgb(141, 166, 206); + --playground-code-builtin-color: rgb(141, 166, 206); + --playground-code-comment-color: rgb(174, 174, 174); + --playground-code-def-color: rgb(141, 166, 206); + --playground-code-keyword-color: rgb(251, 222, 45); + --playground-code-meta-color: rgb(216, 250, 60); + --playground-code-number-color: rgb(216, 250, 60); + --playground-code-operator-color: rgb(251, 222, 45); + --playground-code-qualifier-color: rgb(248, 248, 248); + --playground-code-string-color: rgb(97, 206, 60); + --playground-code-string-2-color: rgb(97, 206, 60); + --playground-code-tag-color: rgb(141, 166, 206); + --playground-code-type-color: rgb(248, 248, 248); + --playground-code-variable-color: rgb(255, 100, 0); + --playground-code-variable-2-color: rgb(248, 248, 248); + --playground-code-variable-3-color: rgb(248, 248, 248); + --playground-code-callee-color: rgb(248, 248, 248); + --playground-code-property-color: rgb(248, 248, 248) +} +`,c` +.playground-theme-cobalt { + --playground-code-background: rgb(0, 34, 64); + --playground-code-default-color: rgb(255, 255, 255); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(179, 101, 57); + --playground-code-gutter-background: rgb(0, 34, 64); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(132, 93, 196); + --playground-code-attribute-color: rgb(255, 128, 225); + --playground-code-builtin-color: rgb(255, 158, 89); + --playground-code-comment-color: rgb(0, 136, 255); + --playground-code-def-color: rgb(255, 255, 255); + --playground-code-keyword-color: rgb(255, 238, 128); + --playground-code-meta-color: rgb(255, 157, 0); + --playground-code-number-color: rgb(255, 128, 225); + --playground-code-operator-color: rgb(255, 255, 255); + --playground-code-qualifier-color: rgb(255, 255, 255); + --playground-code-string-color: rgb(58, 217, 0); + --playground-code-string-2-color: rgb(255, 255, 255); + --playground-code-tag-color: rgb(158, 255, 255); + --playground-code-type-color: rgb(255, 255, 255); + --playground-code-variable-color: rgb(255, 255, 255); + --playground-code-variable-2-color: rgb(158, 255, 255); + --playground-code-variable-3-color: rgb(255, 255, 255); + --playground-code-callee-color: rgb(255, 255, 255); + --playground-code-property-color: rgb(255, 255, 255) +} +`,c` +.playground-theme-colorforth { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(248, 248, 248); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(51, 61, 83); + --playground-code-gutter-background: rgb(10, 0, 31); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(186, 186, 186); + --playground-code-atom-color: rgb(96, 96, 96); + --playground-code-attribute-color: rgb(255, 247, 0); + --playground-code-builtin-color: rgb(0, 217, 90); + --playground-code-comment-color: rgb(237, 237, 237); + --playground-code-def-color: rgb(255, 28, 28); + --playground-code-keyword-color: rgb(255, 217, 0); + --playground-code-meta-color: rgb(255, 255, 0); + --playground-code-number-color: rgb(0, 196, 255); + --playground-code-operator-color: rgb(248, 248, 248); + --playground-code-qualifier-color: rgb(255, 247, 0); + --playground-code-string-color: rgb(0, 123, 255); + --playground-code-string-2-color: rgb(248, 248, 248); + --playground-code-tag-color: rgb(255, 189, 64); + --playground-code-type-color: rgb(221, 221, 221); + --playground-code-variable-color: rgb(115, 255, 0); + --playground-code-variable-2-color: rgb(238, 238, 238); + --playground-code-variable-3-color: rgb(221, 221, 221); + --playground-code-callee-color: rgb(248, 248, 248); + --playground-code-property-color: rgb(248, 248, 248) +} +`,c` +.playground-theme-darcula { + --playground-code-background: rgb(43, 43, 43); + --playground-code-default-color: rgb(169, 183, 198); + --playground-code-cursor-color: rgb(169, 183, 198); + --playground-code-selection-background: rgb(33, 66, 131); + --playground-code-gutter-background: rgb(49, 51, 53); + --playground-code-gutter-border-right: 1px solid rgb(49, 51, 53); + --playground-code-atom-color: rgb(204, 120, 50); + --playground-code-attribute-color: rgb(104, 151, 187); + --playground-code-builtin-color: rgb(255, 158, 89); + --playground-code-comment-color: rgb(97, 161, 81); + --playground-code-def-color: rgb(169, 183, 198); + --playground-code-keyword-color: rgb(204, 120, 50); + --playground-code-meta-color: rgb(187, 181, 41); + --playground-code-number-color: rgb(104, 151, 187); + --playground-code-operator-color: rgb(169, 183, 198); + --playground-code-qualifier-color: rgb(106, 135, 89); + --playground-code-string-color: rgb(106, 135, 89); + --playground-code-string-2-color: rgb(106, 135, 89); + --playground-code-tag-color: rgb(98, 151, 85); + --playground-code-type-color: rgb(170, 187, 204); + --playground-code-variable-color: rgb(169, 183, 198); + --playground-code-variable-2-color: rgb(169, 183, 198); + --playground-code-variable-3-color: rgb(152, 118, 170); + --playground-code-callee-color: rgb(169, 183, 198); + --playground-code-property-color: rgb(255, 198, 109) +} +`,c` +.playground-theme-dracula { + --playground-code-background: rgb(40, 42, 54); + --playground-code-default-color: rgb(248, 248, 242); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-selection-background: rgba(255, 255, 255, 0.1); + --playground-code-gutter-background: rgb(40, 42, 54); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(109, 138, 136); + --playground-code-atom-color: rgb(189, 147, 249); + --playground-code-attribute-color: rgb(80, 250, 123); + --playground-code-builtin-color: rgb(80, 250, 123); + --playground-code-comment-color: rgb(98, 114, 164); + --playground-code-def-color: rgb(80, 250, 123); + --playground-code-keyword-color: rgb(255, 121, 198); + --playground-code-meta-color: rgb(248, 248, 242); + --playground-code-number-color: rgb(189, 147, 249); + --playground-code-operator-color: rgb(255, 121, 198); + --playground-code-qualifier-color: rgb(80, 250, 123); + --playground-code-string-color: rgb(241, 250, 140); + --playground-code-string-2-color: rgb(241, 250, 140); + --playground-code-tag-color: rgb(255, 121, 198); + --playground-code-type-color: rgb(255, 184, 108); + --playground-code-variable-color: rgb(80, 250, 123); + --playground-code-variable-2-color: rgb(255, 255, 255); + --playground-code-variable-3-color: rgb(255, 184, 108); + --playground-code-callee-color: rgb(248, 248, 242); + --playground-code-property-color: rgb(102, 217, 239) +} +`,c` +.playground-theme-duotone-dark { + --playground-code-background: rgb(42, 39, 52); + --playground-code-default-color: rgb(108, 103, 131); + --playground-code-cursor-color: rgb(255, 173, 92); + --playground-code-selection-background: rgb(84, 81, 103); + --playground-code-gutter-background: rgb(42, 39, 52); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(84, 81, 103); + --playground-code-atom-color: rgb(255, 204, 153); + --playground-code-attribute-color: rgb(255, 204, 153); + --playground-code-builtin-color: rgb(238, 235, 255); + --playground-code-comment-color: rgb(108, 103, 131); + --playground-code-def-color: rgb(238, 235, 255); + --playground-code-keyword-color: rgb(255, 204, 153); + --playground-code-meta-color: rgb(108, 103, 131); + --playground-code-number-color: rgb(255, 204, 153); + --playground-code-operator-color: rgb(255, 173, 92); + --playground-code-qualifier-color: rgb(238, 235, 255); + --playground-code-string-color: rgb(255, 184, 112); + --playground-code-string-2-color: rgb(122, 99, 238); + --playground-code-tag-color: rgb(238, 235, 255); + --playground-code-type-color: rgb(122, 99, 238); + --playground-code-variable-color: rgb(255, 204, 153); + --playground-code-variable-2-color: rgb(122, 99, 238); + --playground-code-variable-3-color: rgb(122, 99, 238); + --playground-code-callee-color: rgb(108, 103, 131); + --playground-code-property-color: rgb(154, 134, 253) +} +`,c` +.playground-theme-duotone-light { + --playground-code-background: rgb(250, 248, 245); + --playground-code-default-color: rgb(178, 151, 98); + --playground-code-cursor-color: rgb(147, 171, 220); + --playground-code-selection-background: rgb(227, 220, 206); + --playground-code-gutter-background: rgb(250, 248, 245); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(205, 196, 177); + --playground-code-atom-color: rgb(6, 50, 137); + --playground-code-attribute-color: rgb(6, 50, 137); + --playground-code-builtin-color: rgb(45, 32, 6); + --playground-code-comment-color: rgb(182, 173, 154); + --playground-code-def-color: rgb(45, 32, 6); + --playground-code-keyword-color: rgb(6, 50, 137); + --playground-code-meta-color: rgb(178, 151, 98); + --playground-code-number-color: rgb(6, 50, 137); + --playground-code-operator-color: rgb(22, 89, 223); + --playground-code-qualifier-color: rgb(45, 32, 6); + --playground-code-string-color: rgb(22, 89, 223); + --playground-code-string-2-color: rgb(137, 103, 36); + --playground-code-tag-color: rgb(45, 32, 6); + --playground-code-type-color: rgb(137, 103, 36); + --playground-code-variable-color: rgb(6, 50, 137); + --playground-code-variable-2-color: rgb(137, 103, 36); + --playground-code-variable-3-color: rgb(137, 103, 36); + --playground-code-callee-color: rgb(178, 151, 98); + --playground-code-property-color: rgb(178, 151, 98) +} +`,c` +.playground-theme-eclipse { + --playground-code-comment-color: rgb(63, 127, 95); + --playground-code-keyword-color: rgb(127, 0, 85); + --playground-code-meta-color: rgb(255, 23, 23); + --playground-code-string-color: rgb(42, 0, 255); + --playground-code-type-color: rgb(0, 0, 192); + --playground-code-variable-2-color: rgb(0, 0, 192); + --playground-code-variable-3-color: rgb(0, 0, 192) +} +`,c` +.playground-theme-elegant { + --playground-code-atom-color: rgb(119, 102, 34); + --playground-code-attribute-color: rgb(0, 0, 0); + --playground-code-comment-color: rgb(34, 102, 34); + --playground-code-def-color: rgb(0, 0, 0); + --playground-code-keyword-color: rgb(119, 51, 0); + --playground-code-number-color: rgb(119, 102, 34); + --playground-code-string-color: rgb(119, 102, 34); + --playground-code-string-2-color: rgb(0, 0, 0); + --playground-code-tag-color: rgb(0, 0, 0); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(187, 17, 17); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-erlang-dark { + --playground-code-background: rgb(0, 34, 64); + --playground-code-default-color: rgb(255, 255, 255); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(179, 101, 57); + --playground-code-gutter-background: rgb(0, 34, 64); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(241, 51, 241); + --playground-code-attribute-color: rgb(255, 128, 225); + --playground-code-builtin-color: rgb(238, 170, 170); + --playground-code-comment-color: rgb(119, 119, 255); + --playground-code-def-color: rgb(238, 119, 170); + --playground-code-keyword-color: rgb(255, 238, 128); + --playground-code-meta-color: rgb(80, 254, 254); + --playground-code-number-color: rgb(255, 208, 208); + --playground-code-operator-color: rgb(221, 85, 85); + --playground-code-qualifier-color: rgb(204, 204, 204); + --playground-code-string-color: rgb(58, 217, 0); + --playground-code-string-2-color: rgb(204, 204, 204); + --playground-code-tag-color: rgb(158, 255, 255); + --playground-code-type-color: rgb(204, 204, 204); + --playground-code-variable-color: rgb(80, 254, 80); + --playground-code-variable-2-color: rgb(238, 0, 238); + --playground-code-variable-3-color: rgb(204, 204, 204); + --playground-code-callee-color: rgb(255, 255, 255); + --playground-code-property-color: rgb(204, 204, 204) +} +`,c` +.playground-theme-gruvbox-dark { + --playground-code-background: rgb(40, 40, 40); + --playground-code-default-color: rgb(189, 174, 147); + --playground-code-cursor-color: rgb(235, 219, 178); + --playground-code-selection-background: rgb(146, 131, 116); + --playground-code-gutter-background: rgb(40, 40, 40); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(124, 111, 100); + --playground-code-atom-color: rgb(211, 134, 155); + --playground-code-attribute-color: rgb(142, 192, 124); + --playground-code-builtin-color: rgb(254, 128, 25); + --playground-code-comment-color: rgb(146, 131, 116); + --playground-code-def-color: rgb(235, 219, 178); + --playground-code-keyword-color: rgb(248, 73, 52); + --playground-code-meta-color: rgb(131, 165, 152); + --playground-code-number-color: rgb(211, 134, 155); + --playground-code-operator-color: rgb(235, 219, 178); + --playground-code-qualifier-color: rgb(142, 192, 124); + --playground-code-string-color: rgb(184, 187, 38); + --playground-code-string-2-color: rgb(142, 192, 124); + --playground-code-tag-color: rgb(254, 128, 25); + --playground-code-type-color: rgb(250, 189, 47); + --playground-code-variable-color: rgb(235, 219, 178); + --playground-code-variable-2-color: rgb(235, 219, 178); + --playground-code-variable-3-color: rgb(250, 189, 47); + --playground-code-callee-color: rgb(235, 219, 178); + --playground-code-property-color: rgb(235, 219, 178) +} +`,c` +.playground-theme-hopscotch { + --playground-code-background: rgb(50, 41, 49); + --playground-code-default-color: rgb(213, 211, 213); + --playground-code-cursor-color: rgb(152, 148, 152); + --playground-code-selection-background: rgb(67, 59, 66); + --playground-code-gutter-background: rgb(50, 41, 49); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(121, 115, 121); + --playground-code-atom-color: rgb(200, 94, 124); + --playground-code-attribute-color: rgb(143, 193, 62); + --playground-code-builtin-color: rgb(213, 211, 213); + --playground-code-comment-color: rgb(179, 53, 8); + --playground-code-def-color: rgb(253, 139, 25); + --playground-code-keyword-color: rgb(221, 70, 76); + --playground-code-meta-color: rgb(213, 211, 213); + --playground-code-number-color: rgb(200, 94, 124); + --playground-code-operator-color: rgb(213, 211, 213); + --playground-code-qualifier-color: rgb(213, 211, 213); + --playground-code-string-color: rgb(253, 204, 89); + --playground-code-string-2-color: rgb(213, 211, 213); + --playground-code-tag-color: rgb(221, 70, 76); + --playground-code-type-color: rgb(213, 211, 213); + --playground-code-variable-color: rgb(143, 193, 62); + --playground-code-variable-2-color: rgb(18, 144, 191); + --playground-code-variable-3-color: rgb(213, 211, 213); + --playground-code-callee-color: rgb(213, 211, 213); + --playground-code-property-color: rgb(143, 193, 62) +} +`,c` +.playground-theme-icecoder { + --playground-code-background: rgb(29, 29, 27); + --playground-code-default-color: rgb(102, 102, 102); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(0, 51, 119); + --playground-code-gutter-background: rgb(29, 29, 27); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(85, 85, 85); + --playground-code-atom-color: rgb(225, 199, 110); + --playground-code-attribute-color: rgb(0, 153, 153); + --playground-code-builtin-color: rgb(33, 78, 123); + --playground-code-comment-color: rgb(151, 163, 170); + --playground-code-def-color: rgb(185, 202, 74); + --playground-code-keyword-color: rgb(238, 238, 238); + --playground-code-number-color: rgb(108, 181, 217); + --playground-code-operator-color: rgb(145, 121, 187); + --playground-code-string-color: rgb(185, 202, 74); + --playground-code-string-2-color: rgb(108, 181, 217); + --playground-code-tag-color: rgb(232, 232, 232); + --playground-code-type-color: rgb(249, 96, 44); + --playground-code-variable-color: rgb(108, 181, 217); + --playground-code-variable-2-color: rgb(204, 30, 92); + --playground-code-variable-3-color: rgb(249, 96, 44); + --playground-code-callee-color: rgb(102, 102, 102); + --playground-code-property-color: rgb(238, 238, 238) +} +`,c` +.playground-theme-idea { + --playground-code-atom-color: rgb(0, 0, 128); + --playground-code-attribute-color: rgb(0, 0, 255); + --playground-code-comment-color: rgb(128, 128, 128); + --playground-code-def-color: rgb(0, 0, 0); + --playground-code-keyword-color: rgb(0, 0, 128); + --playground-code-meta-color: rgb(128, 128, 0); + --playground-code-number-color: rgb(0, 0, 255); + --playground-code-string-color: rgb(0, 128, 0); + --playground-code-string-2-color: rgb(0, 128, 0); + --playground-code-tag-color: rgb(0, 0, 128); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(0, 0, 0); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-isotope { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(224, 224, 224); + --playground-code-cursor-color: rgb(192, 192, 192); + --playground-code-selection-background: rgb(64, 64, 64); + --playground-code-gutter-background: rgb(0, 0, 0); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(128, 128, 128); + --playground-code-atom-color: rgb(204, 0, 255); + --playground-code-attribute-color: rgb(51, 255, 0); + --playground-code-builtin-color: rgb(224, 224, 224); + --playground-code-comment-color: rgb(51, 0, 255); + --playground-code-def-color: rgb(255, 153, 0); + --playground-code-keyword-color: rgb(255, 0, 0); + --playground-code-meta-color: rgb(224, 224, 224); + --playground-code-number-color: rgb(204, 0, 255); + --playground-code-operator-color: rgb(224, 224, 224); + --playground-code-qualifier-color: rgb(224, 224, 224); + --playground-code-string-color: rgb(255, 0, 153); + --playground-code-string-2-color: rgb(224, 224, 224); + --playground-code-tag-color: rgb(255, 0, 0); + --playground-code-type-color: rgb(224, 224, 224); + --playground-code-variable-color: rgb(51, 255, 0); + --playground-code-variable-2-color: rgb(0, 102, 255); + --playground-code-variable-3-color: rgb(224, 224, 224); + --playground-code-callee-color: rgb(224, 224, 224); + --playground-code-property-color: rgb(51, 255, 0) +} +`,c` +.playground-theme-juejin { + --playground-code-background: rgb(248, 249, 250); + --playground-code-atom-color: rgb(0, 0, 0); + --playground-code-attribute-color: rgb(253, 119, 65); + --playground-code-builtin-color: rgb(187, 81, 184); + --playground-code-comment-color: rgb(0, 158, 157); + --playground-code-def-color: rgb(27, 162, 240); + --playground-code-keyword-color: rgb(187, 81, 184); + --playground-code-meta-color: rgb(0, 0, 0); + --playground-code-number-color: rgb(0, 0, 0); + --playground-code-qualifier-color: rgb(0, 0, 0); + --playground-code-string-color: rgb(0, 0, 0); + --playground-code-string-2-color: rgb(0, 0, 0); + --playground-code-tag-color: rgb(16, 112, 0); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(0, 80, 160); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-lesser-dark { + --playground-code-background: rgb(38, 38, 38); + --playground-code-default-color: rgb(235, 239, 231); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(69, 68, 59); + --playground-code-gutter-background: rgb(38, 38, 38); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(119, 119, 119); + --playground-code-atom-color: rgb(194, 180, 112); + --playground-code-attribute-color: rgb(129, 164, 213); + --playground-code-builtin-color: rgb(255, 158, 89); + --playground-code-comment-color: rgb(102, 102, 102); + --playground-code-def-color: rgb(255, 255, 255); + --playground-code-keyword-color: rgb(89, 158, 255); + --playground-code-meta-color: rgb(115, 140, 115); + --playground-code-number-color: rgb(179, 94, 77); + --playground-code-operator-color: rgb(146, 167, 92); + --playground-code-string-color: rgb(188, 210, 121); + --playground-code-tag-color: rgb(102, 145, 153); + --playground-code-type-color: rgb(255, 255, 255); + --playground-code-variable-color: rgb(217, 191, 140); + --playground-code-variable-2-color: rgb(102, 145, 153); + --playground-code-variable-3-color: rgb(255, 255, 255); + --playground-code-callee-color: rgb(235, 239, 231); + --playground-code-property-color: rgb(146, 167, 92) +} +`,c` +.playground-theme-liquibyte { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(255, 255, 255); + --playground-code-cursor-color: rgb(238, 238, 238); + --playground-code-selection-background: rgba(255, 0, 0, 0.25); + --playground-code-gutter-background: rgb(38, 38, 38); + --playground-code-gutter-border-right: 1px solid rgb(80, 80, 80); + --playground-code-linenumber-color: rgb(96, 96, 96); + --playground-code-atom-color: rgb(191, 48, 48); + --playground-code-attribute-color: rgb(192, 128, 255); + --playground-code-builtin-color: rgb(255, 175, 64); + --playground-code-comment-color: rgb(0, 128, 0); + --playground-code-def-color: rgb(255, 175, 64); + --playground-code-keyword-color: rgb(192, 128, 255); + --playground-code-meta-color: rgb(0, 255, 0); + --playground-code-number-color: rgb(0, 255, 0); + --playground-code-operator-color: rgb(255, 255, 255); + --playground-code-qualifier-color: rgb(255, 247, 0); + --playground-code-string-color: rgb(255, 128, 0); + --playground-code-string-2-color: rgb(255, 255, 255); + --playground-code-tag-color: rgb(255, 255, 0); + --playground-code-type-color: rgb(192, 128, 255); + --playground-code-variable-color: rgb(89, 103, 255); + --playground-code-variable-2-color: rgb(0, 127, 127); + --playground-code-variable-3-color: rgb(192, 128, 255); + --playground-code-callee-color: rgb(255, 255, 255); + --playground-code-property-color: rgb(153, 153, 153) +} +`,c` +.playground-theme-lucario { + --playground-code-background: rgb(43, 62, 80); + --playground-code-default-color: rgb(248, 248, 242); + --playground-code-cursor-color: rgb(230, 200, 69); + --playground-code-selection-background: rgb(36, 52, 67); + --playground-code-gutter-background: rgb(43, 62, 80); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(248, 248, 242); + --playground-code-atom-color: rgb(189, 147, 249); + --playground-code-attribute-color: rgb(102, 217, 239); + --playground-code-builtin-color: rgb(114, 192, 93); + --playground-code-comment-color: rgb(92, 152, 205); + --playground-code-def-color: rgb(114, 192, 93); + --playground-code-keyword-color: rgb(255, 101, 65); + --playground-code-meta-color: rgb(248, 248, 242); + --playground-code-number-color: rgb(202, 148, 255); + --playground-code-operator-color: rgb(102, 217, 239); + --playground-code-qualifier-color: rgb(114, 192, 93); + --playground-code-string-color: rgb(230, 219, 116); + --playground-code-string-2-color: rgb(230, 219, 116); + --playground-code-tag-color: rgb(255, 101, 65); + --playground-code-type-color: rgb(255, 184, 108); + --playground-code-variable-color: rgb(248, 248, 242); + --playground-code-variable-2-color: rgb(248, 248, 242); + --playground-code-variable-3-color: rgb(255, 184, 108); + --playground-code-callee-color: rgb(248, 248, 242); + --playground-code-property-color: rgb(248, 248, 242) +} +`,c` +.playground-theme-material-darker { + --playground-code-background: rgb(33, 33, 33); + --playground-code-default-color: rgb(238, 255, 255); + --playground-code-cursor-color: rgb(255, 204, 0); + --playground-code-selection-background: rgba(97, 97, 97, 0.2); + --playground-code-gutter-background: rgb(33, 33, 33); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(84, 84, 84); + --playground-code-atom-color: rgb(247, 140, 108); + --playground-code-attribute-color: rgb(199, 146, 234); + --playground-code-builtin-color: rgb(255, 203, 107); + --playground-code-comment-color: rgb(84, 84, 84); + --playground-code-def-color: rgb(130, 170, 255); + --playground-code-keyword-color: rgb(199, 146, 234); + --playground-code-meta-color: rgb(255, 203, 107); + --playground-code-number-color: rgb(255, 83, 112); + --playground-code-operator-color: rgb(137, 221, 255); + --playground-code-qualifier-color: rgb(222, 203, 107); + --playground-code-string-color: rgb(195, 232, 141); + --playground-code-string-2-color: rgb(240, 113, 120); + --playground-code-tag-color: rgb(255, 83, 112); + --playground-code-type-color: rgb(222, 203, 107); + --playground-code-variable-color: rgb(240, 113, 120); + --playground-code-variable-2-color: rgb(238, 255, 255); + --playground-code-variable-3-color: rgb(222, 203, 107); + --playground-code-callee-color: rgb(238, 255, 255); + --playground-code-property-color: rgb(199, 146, 234) +} +`,c` +.playground-theme-material-ocean { + --playground-code-background: rgb(15, 17, 26); + --playground-code-default-color: rgb(143, 147, 162); + --playground-code-cursor-color: rgb(255, 204, 0); + --playground-code-selection-background: rgba(113, 124, 180, 0.2); + --playground-code-gutter-background: rgb(15, 17, 26); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(70, 75, 93); + --playground-code-atom-color: rgb(247, 140, 108); + --playground-code-attribute-color: rgb(199, 146, 234); + --playground-code-builtin-color: rgb(255, 203, 107); + --playground-code-comment-color: rgb(70, 75, 93); + --playground-code-def-color: rgb(130, 170, 255); + --playground-code-keyword-color: rgb(199, 146, 234); + --playground-code-meta-color: rgb(255, 203, 107); + --playground-code-number-color: rgb(255, 83, 112); + --playground-code-operator-color: rgb(137, 221, 255); + --playground-code-qualifier-color: rgb(222, 203, 107); + --playground-code-string-color: rgb(195, 232, 141); + --playground-code-string-2-color: rgb(240, 113, 120); + --playground-code-tag-color: rgb(255, 83, 112); + --playground-code-type-color: rgb(222, 203, 107); + --playground-code-variable-color: rgb(240, 113, 120); + --playground-code-variable-2-color: rgb(238, 255, 255); + --playground-code-variable-3-color: rgb(222, 203, 107); + --playground-code-callee-color: rgb(143, 147, 162); + --playground-code-property-color: rgb(199, 146, 234) +} +`,c` +.playground-theme-material-palenight { + --playground-code-background: rgb(41, 45, 62); + --playground-code-default-color: rgb(166, 172, 205); + --playground-code-cursor-color: rgb(255, 204, 0); + --playground-code-selection-background: rgba(113, 124, 180, 0.2); + --playground-code-gutter-background: rgb(41, 45, 62); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(103, 110, 149); + --playground-code-atom-color: rgb(247, 140, 108); + --playground-code-attribute-color: rgb(199, 146, 234); + --playground-code-builtin-color: rgb(255, 203, 107); + --playground-code-comment-color: rgb(103, 110, 149); + --playground-code-def-color: rgb(130, 170, 255); + --playground-code-keyword-color: rgb(199, 146, 234); + --playground-code-meta-color: rgb(255, 203, 107); + --playground-code-number-color: rgb(255, 83, 112); + --playground-code-operator-color: rgb(137, 221, 255); + --playground-code-qualifier-color: rgb(222, 203, 107); + --playground-code-string-color: rgb(195, 232, 141); + --playground-code-string-2-color: rgb(240, 113, 120); + --playground-code-tag-color: rgb(255, 83, 112); + --playground-code-type-color: rgb(222, 203, 107); + --playground-code-variable-color: rgb(240, 113, 120); + --playground-code-variable-2-color: rgb(238, 255, 255); + --playground-code-variable-3-color: rgb(222, 203, 107); + --playground-code-callee-color: rgb(166, 172, 205); + --playground-code-property-color: rgb(199, 146, 234) +} +`,c` +.playground-theme-material { + --playground-code-background: rgb(38, 50, 56); + --playground-code-default-color: rgb(238, 255, 255); + --playground-code-cursor-color: rgb(255, 204, 0); + --playground-code-selection-background: rgba(128, 203, 196, 0.2); + --playground-code-gutter-background: rgb(38, 50, 56); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(84, 110, 122); + --playground-code-atom-color: rgb(247, 140, 108); + --playground-code-attribute-color: rgb(199, 146, 234); + --playground-code-builtin-color: rgb(255, 203, 107); + --playground-code-comment-color: rgb(84, 110, 122); + --playground-code-def-color: rgb(130, 170, 255); + --playground-code-keyword-color: rgb(199, 146, 234); + --playground-code-meta-color: rgb(255, 203, 107); + --playground-code-number-color: rgb(255, 83, 112); + --playground-code-operator-color: rgb(137, 221, 255); + --playground-code-qualifier-color: rgb(222, 203, 107); + --playground-code-string-color: rgb(195, 232, 141); + --playground-code-string-2-color: rgb(240, 113, 120); + --playground-code-tag-color: rgb(255, 83, 112); + --playground-code-type-color: rgb(222, 203, 107); + --playground-code-variable-color: rgb(240, 113, 120); + --playground-code-variable-2-color: rgb(238, 255, 255); + --playground-code-variable-3-color: rgb(222, 203, 107); + --playground-code-callee-color: rgb(238, 255, 255); + --playground-code-property-color: rgb(199, 146, 234) +} +`,c` +.playground-theme-mbo { + --playground-code-background: rgb(44, 44, 44); + --playground-code-default-color: rgb(255, 255, 236); + --playground-code-cursor-color: rgb(255, 255, 236); + --playground-code-selection-background: rgb(113, 108, 98); + --playground-code-gutter-background: rgb(78, 78, 78); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(218, 218, 218); + --playground-code-atom-color: rgb(0, 168, 198); + --playground-code-attribute-color: rgb(157, 223, 233); + --playground-code-builtin-color: rgb(255, 255, 236); + --playground-code-comment-color: rgb(149, 149, 138); + --playground-code-def-color: rgb(255, 255, 236); + --playground-code-keyword-color: rgb(255, 185, 40); + --playground-code-meta-color: rgb(255, 255, 236); + --playground-code-number-color: rgb(0, 168, 198); + --playground-code-operator-color: rgb(255, 255, 236); + --playground-code-qualifier-color: rgb(255, 255, 236); + --playground-code-string-color: rgb(255, 207, 108); + --playground-code-string-2-color: rgb(255, 255, 236); + --playground-code-tag-color: rgb(157, 223, 233); + --playground-code-type-color: rgb(255, 255, 236); + --playground-code-variable-color: rgb(255, 255, 236); + --playground-code-variable-2-color: rgb(0, 168, 198); + --playground-code-variable-3-color: rgb(255, 255, 236); + --playground-code-callee-color: rgb(255, 255, 236); + --playground-code-property-color: rgb(157, 223, 233) +} +`,c` +.playground-theme-mdn-like { + --playground-code-background: rgb(255, 255, 255) url("data:image/png;base64,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") repeat scroll 0% 0%/auto padding-box border-box; + --playground-code-default-color: rgb(153, 153, 153); + --playground-code-cursor-color: rgb(34, 34, 34); + --playground-code-selection-background: rgb(204, 255, 204); + --playground-code-gutter-background: rgb(248, 248, 248); + --playground-code-linenumber-color: rgb(170, 170, 170); + --playground-code-atom-color: rgb(255, 153, 0); + --playground-code-attribute-color: rgb(214, 187, 109); + --playground-code-builtin-color: rgb(155, 117, 54); + --playground-code-comment-color: rgb(119, 119, 119); + --playground-code-def-color: rgb(0, 119, 170); + --playground-code-keyword-color: rgb(98, 98, 255); + --playground-code-meta-color: rgb(0, 0, 0); + --playground-code-number-color: rgb(202, 120, 65); + --playground-code-operator-color: rgb(205, 168, 105); + --playground-code-qualifier-color: rgb(102, 153, 0); + --playground-code-string-color: rgb(0, 119, 170); + --playground-code-string-2-color: rgb(189, 107, 24); + --playground-code-tag-color: rgb(102, 153, 0); + --playground-code-type-color: rgb(0, 119, 170); + --playground-code-variable-color: rgb(0, 119, 170); + --playground-code-variable-2-color: rgb(102, 153, 0); + --playground-code-variable-3-color: rgb(0, 119, 170); + --playground-code-callee-color: rgb(153, 153, 153); + --playground-code-property-color: rgb(153, 0, 85) +} +`,c` +.playground-theme-midnight { + --playground-code-background: rgb(15, 25, 42); + --playground-code-default-color: rgb(209, 237, 255); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-selection-background: rgb(49, 77, 103); + --playground-code-gutter-background: rgb(15, 25, 42); + --playground-code-gutter-border-right: 1px solid rgb(209, 237, 255); + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(174, 129, 255); + --playground-code-attribute-color: rgb(166, 226, 46); + --playground-code-builtin-color: rgb(209, 237, 255); + --playground-code-comment-color: rgb(66, 139, 221); + --playground-code-def-color: rgb(68, 221, 221); + --playground-code-keyword-color: rgb(232, 55, 55); + --playground-code-meta-color: rgb(209, 237, 255); + --playground-code-number-color: rgb(209, 237, 255); + --playground-code-operator-color: rgb(209, 237, 255); + --playground-code-qualifier-color: rgb(209, 237, 255); + --playground-code-string-color: rgb(29, 193, 22); + --playground-code-string-2-color: rgb(209, 237, 255); + --playground-code-tag-color: rgb(68, 68, 153); + --playground-code-type-color: rgb(209, 237, 255); + --playground-code-variable-color: rgb(255, 170, 62); + --playground-code-variable-2-color: rgb(255, 170, 62); + --playground-code-variable-3-color: rgb(209, 237, 255); + --playground-code-callee-color: rgb(209, 237, 255); + --playground-code-property-color: rgb(166, 226, 46) +} +`,c` +.playground-theme-monokai { + --playground-code-background: rgb(39, 40, 34); + --playground-code-default-color: rgb(248, 248, 242); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-selection-background: rgb(73, 72, 62); + --playground-code-gutter-background: rgb(39, 40, 34); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(174, 129, 255); + --playground-code-attribute-color: rgb(166, 226, 46); + --playground-code-builtin-color: rgb(102, 217, 239); + --playground-code-comment-color: rgb(117, 113, 94); + --playground-code-def-color: rgb(253, 151, 31); + --playground-code-keyword-color: rgb(249, 38, 114); + --playground-code-meta-color: rgb(248, 248, 242); + --playground-code-number-color: rgb(174, 129, 255); + --playground-code-operator-color: rgb(248, 248, 242); + --playground-code-qualifier-color: rgb(248, 248, 242); + --playground-code-string-color: rgb(230, 219, 116); + --playground-code-string-2-color: rgb(248, 248, 242); + --playground-code-tag-color: rgb(249, 38, 114); + --playground-code-type-color: rgb(102, 217, 239); + --playground-code-variable-color: rgb(248, 248, 242); + --playground-code-variable-2-color: rgb(158, 255, 255); + --playground-code-variable-3-color: rgb(102, 217, 239); + --playground-code-callee-color: rgb(248, 248, 242); + --playground-code-property-color: rgb(166, 226, 46) +} +`,c` +.playground-theme-moxer { + --playground-code-background: rgb(9, 10, 15); + --playground-code-default-color: rgb(142, 149, 180); + --playground-code-cursor-color: rgb(255, 204, 0); + --playground-code-selection-background: rgba(128, 203, 196, 0.2); + --playground-code-gutter-background: rgb(9, 10, 15); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(53, 57, 75); + --playground-code-atom-color: rgb(169, 155, 226); + --playground-code-attribute-color: rgb(199, 146, 234); + --playground-code-builtin-color: rgb(255, 203, 107); + --playground-code-comment-color: rgb(63, 68, 90); + --playground-code-def-color: rgb(245, 223, 165); + --playground-code-keyword-color: rgb(212, 108, 108); + --playground-code-meta-color: rgb(255, 203, 107); + --playground-code-number-color: rgb(124, 164, 192); + --playground-code-operator-color: rgb(212, 108, 108); + --playground-code-qualifier-color: rgb(222, 203, 107); + --playground-code-string-color: rgb(178, 228, 174); + --playground-code-string-2-color: rgb(240, 113, 120); + --playground-code-tag-color: rgb(255, 83, 112); + --playground-code-type-color: rgb(222, 203, 107); + --playground-code-variable-color: rgb(142, 149, 180); + --playground-code-variable-2-color: rgb(129, 197, 218); + --playground-code-variable-3-color: rgb(222, 203, 107); + --playground-code-callee-color: rgb(142, 149, 180); + --playground-code-property-color: rgb(129, 197, 218) +} +`,c` +.playground-theme-neat { + --playground-code-atom-color: rgb(51, 170, 51); + --playground-code-attribute-color: rgb(0, 0, 0); + --playground-code-builtin-color: rgb(0, 119, 119); + --playground-code-comment-color: rgb(170, 136, 102); + --playground-code-def-color: rgb(0, 0, 0); + --playground-code-keyword-color: rgb(0, 0, 255); + --playground-code-number-color: rgb(51, 170, 51); + --playground-code-qualifier-color: rgb(0, 0, 0); + --playground-code-string-color: rgb(170, 34, 34); + --playground-code-string-2-color: rgb(0, 0, 0); + --playground-code-tag-color: rgb(0, 0, 0); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(0, 0, 0); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-neo { + --playground-code-default-color: rgb(46, 56, 60); + --playground-code-cursor-color: rgb(46, 56, 60); + --playground-code-gutter-background: rgba(0, 0, 0, 0); + --playground-code-gutter-border-right: 10px solid rgba(0, 0, 0, 0); + --playground-code-linenumber-color: rgb(224, 226, 229); + --playground-code-atom-color: rgb(117, 67, 138); + --playground-code-attribute-color: rgb(46, 56, 60); + --playground-code-builtin-color: rgb(46, 56, 60); + --playground-code-comment-color: rgb(117, 120, 123); + --playground-code-def-color: rgb(46, 56, 60); + --playground-code-keyword-color: rgb(29, 117, 179); + --playground-code-meta-color: rgb(46, 56, 60); + --playground-code-number-color: rgb(117, 67, 138); + --playground-code-operator-color: rgb(46, 56, 60); + --playground-code-qualifier-color: rgb(4, 125, 101); + --playground-code-string-color: rgb(179, 94, 20); + --playground-code-string-2-color: rgb(46, 56, 60); + --playground-code-tag-color: rgb(156, 51, 40); + --playground-code-type-color: rgb(46, 56, 60); + --playground-code-variable-color: rgb(4, 125, 101); + --playground-code-variable-2-color: rgb(46, 56, 60); + --playground-code-variable-3-color: rgb(46, 56, 60); + --playground-code-callee-color: rgb(46, 56, 60); + --playground-code-property-color: rgb(29, 117, 179) +} +`,c` +.playground-theme-night { + --playground-code-background: rgb(10, 0, 31); + --playground-code-default-color: rgb(248, 248, 248); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(68, 68, 119); + --playground-code-gutter-background: rgb(10, 0, 31); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(248, 248, 248); + --playground-code-atom-color: rgb(132, 93, 196); + --playground-code-attribute-color: rgb(255, 213, 0); + --playground-code-builtin-color: rgb(255, 158, 89); + --playground-code-comment-color: rgb(137, 0, 209); + --playground-code-def-color: rgb(255, 255, 255); + --playground-code-keyword-color: rgb(89, 158, 255); + --playground-code-meta-color: rgb(118, 120, 226); + --playground-code-number-color: rgb(255, 213, 0); + --playground-code-operator-color: rgb(248, 248, 248); + --playground-code-qualifier-color: rgb(248, 248, 248); + --playground-code-string-color: rgb(55, 241, 74); + --playground-code-string-2-color: rgb(248, 248, 248); + --playground-code-tag-color: rgb(153, 178, 255); + --playground-code-type-color: rgb(255, 255, 255); + --playground-code-variable-color: rgb(248, 248, 248); + --playground-code-variable-2-color: rgb(153, 178, 255); + --playground-code-variable-3-color: rgb(255, 255, 255); + --playground-code-callee-color: rgb(248, 248, 248); + --playground-code-property-color: rgb(248, 248, 248) +} +`,c` +.playground-theme-nord { + --playground-code-background: rgb(46, 52, 64); + --playground-code-default-color: rgb(216, 222, 233); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-selection-background: rgb(67, 76, 94); + --playground-code-gutter-background: rgb(46, 52, 64); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(76, 86, 106); + --playground-code-atom-color: rgb(180, 142, 173); + --playground-code-attribute-color: rgb(143, 188, 187); + --playground-code-builtin-color: rgb(129, 161, 193); + --playground-code-comment-color: rgb(76, 86, 106); + --playground-code-def-color: rgb(143, 188, 187); + --playground-code-keyword-color: rgb(129, 161, 193); + --playground-code-meta-color: rgb(216, 222, 233); + --playground-code-number-color: rgb(180, 142, 173); + --playground-code-operator-color: rgb(216, 222, 233); + --playground-code-qualifier-color: rgb(216, 222, 233); + --playground-code-string-color: rgb(163, 190, 140); + --playground-code-string-2-color: rgb(216, 222, 233); + --playground-code-tag-color: rgb(191, 97, 106); + --playground-code-type-color: rgb(216, 222, 233); + --playground-code-variable-color: rgb(216, 222, 233); + --playground-code-variable-2-color: rgb(216, 222, 233); + --playground-code-variable-3-color: rgb(216, 222, 233); + --playground-code-callee-color: rgb(216, 222, 233); + --playground-code-property-color: rgb(143, 188, 187) +} +`,c` +.playground-theme-oceanic-next { + --playground-code-background: rgb(48, 65, 72); + --playground-code-default-color: rgb(248, 248, 242); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-selection-background: rgba(101, 115, 126, 0.33); + --playground-code-gutter-background: rgb(48, 65, 72); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(197, 148, 197); + --playground-code-attribute-color: rgb(197, 148, 197); + --playground-code-builtin-color: rgb(102, 217, 239); + --playground-code-comment-color: rgb(101, 115, 126); + --playground-code-def-color: rgb(102, 153, 204); + --playground-code-keyword-color: rgb(197, 148, 197); + --playground-code-meta-color: rgb(248, 248, 242); + --playground-code-number-color: rgb(249, 145, 87); + --playground-code-operator-color: rgb(248, 248, 242); + --playground-code-qualifier-color: rgb(248, 248, 242); + --playground-code-string-color: rgb(153, 199, 148); + --playground-code-string-2-color: rgb(248, 248, 242); + --playground-code-tag-color: rgb(197, 148, 197); + --playground-code-type-color: rgb(248, 248, 242); + --playground-code-variable-color: rgb(248, 248, 242); + --playground-code-variable-2-color: rgb(248, 248, 242); + --playground-code-variable-3-color: rgb(248, 248, 242); + --playground-code-callee-color: rgb(248, 248, 242); + --playground-code-property-color: rgb(153, 199, 148) +} +`,c` +.playground-theme-panda-syntax { + --playground-code-background: rgb(41, 42, 43); + --playground-code-default-color: rgb(230, 230, 230); + --playground-code-cursor-color: rgb(255, 44, 109); + --playground-code-selection-background: rgb(255, 255, 255); + --playground-code-gutter-background: rgb(41, 42, 43); + --playground-code-gutter-border-right: 1px solid rgba(255, 255, 255, 0.1); + --playground-code-linenumber-color: rgb(230, 230, 230); + --playground-code-atom-color: rgb(255, 44, 109); + --playground-code-attribute-color: rgb(255, 184, 108); + --playground-code-builtin-color: rgb(230, 230, 230); + --playground-code-comment-color: rgb(103, 107, 121); + --playground-code-def-color: rgb(230, 230, 230); + --playground-code-keyword-color: rgb(255, 117, 181); + --playground-code-meta-color: rgb(176, 132, 235); + --playground-code-number-color: rgb(255, 184, 108); + --playground-code-operator-color: rgb(243, 243, 243); + --playground-code-qualifier-color: rgb(230, 230, 230); + --playground-code-string-color: rgb(25, 249, 216); + --playground-code-string-2-color: rgb(255, 184, 108); + --playground-code-tag-color: rgb(255, 44, 109); + --playground-code-type-color: rgb(255, 154, 193); + --playground-code-variable-color: rgb(255, 184, 108); + --playground-code-variable-2-color: rgb(255, 154, 193); + --playground-code-variable-3-color: rgb(255, 154, 193); + --playground-code-callee-color: rgb(230, 230, 230); + --playground-code-property-color: rgb(243, 243, 243) +} +`,c` +.playground-theme-paraiso-dark { + --playground-code-background: rgb(47, 30, 46); + --playground-code-default-color: rgb(185, 182, 176); + --playground-code-cursor-color: rgb(141, 134, 135); + --playground-code-selection-background: rgb(65, 50, 63); + --playground-code-gutter-background: rgb(47, 30, 46); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(119, 110, 113); + --playground-code-atom-color: rgb(129, 91, 164); + --playground-code-attribute-color: rgb(72, 182, 133); + --playground-code-builtin-color: rgb(185, 182, 176); + --playground-code-comment-color: rgb(233, 107, 168); + --playground-code-def-color: rgb(249, 155, 21); + --playground-code-keyword-color: rgb(239, 97, 85); + --playground-code-meta-color: rgb(185, 182, 176); + --playground-code-number-color: rgb(129, 91, 164); + --playground-code-operator-color: rgb(185, 182, 176); + --playground-code-qualifier-color: rgb(185, 182, 176); + --playground-code-string-color: rgb(254, 196, 24); + --playground-code-string-2-color: rgb(185, 182, 176); + --playground-code-tag-color: rgb(239, 97, 85); + --playground-code-type-color: rgb(185, 182, 176); + --playground-code-variable-color: rgb(72, 182, 133); + --playground-code-variable-2-color: rgb(6, 182, 239); + --playground-code-variable-3-color: rgb(185, 182, 176); + --playground-code-callee-color: rgb(185, 182, 176); + --playground-code-property-color: rgb(72, 182, 133) +} +`,c` +.playground-theme-paraiso-light { + --playground-code-background: rgb(231, 233, 219); + --playground-code-default-color: rgb(65, 50, 63); + --playground-code-cursor-color: rgb(119, 110, 113); + --playground-code-selection-background: rgb(185, 182, 176); + --playground-code-gutter-background: rgb(231, 233, 219); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(141, 134, 135); + --playground-code-atom-color: rgb(129, 91, 164); + --playground-code-attribute-color: rgb(72, 182, 133); + --playground-code-builtin-color: rgb(65, 50, 63); + --playground-code-comment-color: rgb(233, 107, 168); + --playground-code-def-color: rgb(249, 155, 21); + --playground-code-keyword-color: rgb(239, 97, 85); + --playground-code-meta-color: rgb(65, 50, 63); + --playground-code-number-color: rgb(129, 91, 164); + --playground-code-operator-color: rgb(65, 50, 63); + --playground-code-qualifier-color: rgb(65, 50, 63); + --playground-code-string-color: rgb(254, 196, 24); + --playground-code-string-2-color: rgb(65, 50, 63); + --playground-code-tag-color: rgb(239, 97, 85); + --playground-code-type-color: rgb(65, 50, 63); + --playground-code-variable-color: rgb(72, 182, 133); + --playground-code-variable-2-color: rgb(6, 182, 239); + --playground-code-variable-3-color: rgb(65, 50, 63); + --playground-code-callee-color: rgb(65, 50, 63); + --playground-code-property-color: rgb(72, 182, 133) +} +`,c` +.playground-theme-pastel-on-dark { + --playground-code-background: rgb(44, 40, 39); + --playground-code-default-color: rgb(143, 147, 143); + --playground-code-cursor-color: rgb(167, 167, 167); + --playground-code-selection-background: rgba(221, 240, 255, 0.2); + --playground-code-gutter-background: rgb(52, 48, 47); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(143, 147, 143); + --playground-code-atom-color: rgb(222, 142, 48); + --playground-code-attribute-color: rgb(166, 226, 46); + --playground-code-builtin-color: rgb(193, 193, 68); + --playground-code-comment-color: rgb(166, 198, 255); + --playground-code-def-color: rgb(117, 122, 216); + --playground-code-keyword-color: rgb(174, 178, 248); + --playground-code-meta-color: rgb(143, 147, 143); + --playground-code-number-color: rgb(204, 204, 204); + --playground-code-operator-color: rgb(143, 147, 143); + --playground-code-qualifier-color: rgb(193, 193, 68); + --playground-code-string-color: rgb(102, 169, 104); + --playground-code-string-2-color: rgb(143, 147, 143); + --playground-code-tag-color: rgb(193, 193, 68); + --playground-code-type-color: rgb(222, 142, 48); + --playground-code-variable-color: rgb(174, 178, 248); + --playground-code-variable-2-color: rgb(190, 191, 85); + --playground-code-variable-3-color: rgb(222, 142, 48); + --playground-code-callee-color: rgb(143, 147, 143); + --playground-code-property-color: rgb(143, 147, 143) +} +`,c` +.playground-theme-railscasts { + --playground-code-background: rgb(43, 43, 43); + --playground-code-default-color: rgb(244, 241, 237); + --playground-code-cursor-color: rgb(212, 207, 201); + --playground-code-selection-background: rgb(39, 41, 53); + --playground-code-gutter-background: rgb(43, 43, 43); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(90, 100, 126); + --playground-code-atom-color: rgb(182, 179, 235); + --playground-code-attribute-color: rgb(165, 194, 97); + --playground-code-builtin-color: rgb(244, 241, 237); + --playground-code-comment-color: rgb(188, 148, 88); + --playground-code-def-color: rgb(204, 120, 51); + --playground-code-keyword-color: rgb(218, 73, 57); + --playground-code-meta-color: rgb(244, 241, 237); + --playground-code-number-color: rgb(182, 179, 235); + --playground-code-operator-color: rgb(244, 241, 237); + --playground-code-qualifier-color: rgb(244, 241, 237); + --playground-code-string-color: rgb(255, 198, 109); + --playground-code-string-2-color: rgb(244, 241, 237); + --playground-code-tag-color: rgb(218, 73, 57); + --playground-code-type-color: rgb(244, 241, 237); + --playground-code-variable-color: rgb(165, 194, 97); + --playground-code-variable-2-color: rgb(109, 156, 190); + --playground-code-variable-3-color: rgb(244, 241, 237); + --playground-code-callee-color: rgb(244, 241, 237); + --playground-code-property-color: rgb(165, 194, 97) +} +`,c` +.playground-theme-rubyblue { + --playground-code-background: rgb(17, 36, 53); + --playground-code-default-color: rgb(255, 255, 255); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(56, 86, 111); + --playground-code-gutter-background: rgb(31, 70, 97); + --playground-code-gutter-border-right: 7px solid rgb(62, 112, 135); + --playground-code-linenumber-color: rgb(255, 255, 255); + --playground-code-atom-color: rgb(244, 194, 11); + --playground-code-attribute-color: rgb(130, 198, 224); + --playground-code-builtin-color: rgb(255, 157, 0); + --playground-code-comment-color: rgb(153, 153, 153); + --playground-code-def-color: rgb(255, 255, 255); + --playground-code-keyword-color: rgb(255, 0, 255); + --playground-code-meta-color: rgb(255, 0, 255); + --playground-code-number-color: rgb(130, 198, 224); + --playground-code-operator-color: rgb(255, 255, 255); + --playground-code-qualifier-color: rgb(255, 255, 255); + --playground-code-string-color: rgb(240, 128, 71); + --playground-code-string-2-color: rgb(255, 255, 255); + --playground-code-tag-color: rgb(123, 216, 39); + --playground-code-type-color: rgb(255, 255, 255); + --playground-code-variable-color: rgb(255, 255, 255); + --playground-code-variable-2-color: rgb(123, 216, 39); + --playground-code-variable-3-color: rgb(255, 255, 255); + --playground-code-callee-color: rgb(255, 255, 255); + --playground-code-property-color: rgb(255, 255, 255) +} +`,c` +.playground-theme-seti { + --playground-code-background: rgb(21, 23, 24); + --playground-code-default-color: rgb(207, 210, 209); + --playground-code-cursor-color: rgb(248, 248, 240); + --playground-code-gutter-background: rgb(14, 17, 18); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(109, 138, 136); + --playground-code-atom-color: rgb(205, 63, 69); + --playground-code-attribute-color: rgb(159, 202, 86); + --playground-code-builtin-color: rgb(159, 202, 86); + --playground-code-comment-color: rgb(65, 83, 91); + --playground-code-def-color: rgb(85, 181, 219); + --playground-code-keyword-color: rgb(230, 205, 105); + --playground-code-meta-color: rgb(85, 181, 219); + --playground-code-number-color: rgb(205, 63, 69); + --playground-code-operator-color: rgb(159, 202, 86); + --playground-code-qualifier-color: rgb(159, 202, 86); + --playground-code-string-color: rgb(85, 181, 219); + --playground-code-string-2-color: rgb(85, 181, 219); + --playground-code-tag-color: rgb(85, 181, 219); + --playground-code-type-color: rgb(159, 202, 86); + --playground-code-variable-color: rgb(85, 181, 219); + --playground-code-variable-2-color: rgb(160, 116, 196); + --playground-code-variable-3-color: rgb(159, 202, 86); + --playground-code-callee-color: rgb(207, 210, 209); + --playground-code-property-color: rgb(160, 116, 196) +} +`,c` +.playground-theme-shadowfox { + --playground-code-background: rgb(42, 42, 46); + --playground-code-default-color: rgb(177, 177, 179); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(53, 59, 72); + --playground-code-gutter-background: rgb(12, 12, 13); + --playground-code-gutter-border-right: 1px solid rgb(12, 12, 13); + --playground-code-linenumber-color: rgb(147, 147, 147); + --playground-code-atom-color: rgb(255, 125, 233); + --playground-code-attribute-color: rgb(255, 125, 233); + --playground-code-builtin-color: rgb(255, 125, 233); + --playground-code-comment-color: rgb(147, 147, 147); + --playground-code-def-color: rgb(117, 191, 255); + --playground-code-keyword-color: rgb(255, 125, 233); + --playground-code-meta-color: rgb(147, 147, 147); + --playground-code-number-color: rgb(107, 137, 255); + --playground-code-operator-color: rgb(177, 177, 179); + --playground-code-qualifier-color: rgb(117, 191, 255); + --playground-code-string-color: rgb(107, 137, 255); + --playground-code-string-2-color: rgb(107, 137, 255); + --playground-code-tag-color: rgb(117, 191, 255); + --playground-code-type-color: rgb(177, 177, 179); + --playground-code-variable-color: rgb(185, 142, 255); + --playground-code-variable-2-color: rgb(117, 191, 255); + --playground-code-variable-3-color: rgb(215, 215, 219); + --playground-code-callee-color: rgb(177, 177, 179); + --playground-code-property-color: rgb(134, 222, 116) +} +`,c` +.playground-theme-solarized { + --playground-code-cursor-color: rgb(129, 144, 144); + --playground-code-gutter-border-right: 0px; + --playground-code-atom-color: rgb(211, 54, 130); + --playground-code-attribute-color: rgb(42, 161, 152); + --playground-code-builtin-color: rgb(211, 54, 130); + --playground-code-comment-color: rgb(88, 110, 117); + --playground-code-def-color: rgb(42, 161, 152); + --playground-code-keyword-color: rgb(203, 75, 22); + --playground-code-meta-color: rgb(133, 153, 0); + --playground-code-number-color: rgb(211, 54, 130); + --playground-code-operator-color: rgb(108, 113, 196); + --playground-code-qualifier-color: rgb(181, 137, 0); + --playground-code-string-color: rgb(133, 153, 0); + --playground-code-string-2-color: rgb(181, 137, 0); + --playground-code-tag-color: rgb(147, 161, 161); + --playground-code-type-color: rgb(108, 113, 196); + --playground-code-variable-color: rgb(131, 148, 150); + --playground-code-variable-2-color: rgb(181, 137, 0); + --playground-code-variable-3-color: rgb(108, 113, 196); + --playground-code-property-color: rgb(42, 161, 152) +} +`,c` +.playground-theme-ssms { + --playground-code-selection-background: rgb(173, 214, 255); + --playground-code-gutter-background: rgb(255, 255, 255); + --playground-code-gutter-border-right: 3px solid rgb(255, 238, 98); + --playground-code-linenumber-color: rgb(0, 128, 128); + --playground-code-atom-color: rgb(169, 169, 169); + --playground-code-attribute-color: rgb(0, 0, 0); + --playground-code-builtin-color: rgb(0, 0, 0); + --playground-code-comment-color: rgb(0, 100, 0); + --playground-code-def-color: rgb(0, 0, 0); + --playground-code-keyword-color: rgb(0, 0, 255); + --playground-code-meta-color: rgb(0, 0, 0); + --playground-code-number-color: rgb(0, 0, 0); + --playground-code-operator-color: rgb(169, 169, 169); + --playground-code-qualifier-color: rgb(0, 0, 0); + --playground-code-string-color: rgb(255, 0, 0); + --playground-code-string-2-color: rgb(255, 0, 255); + --playground-code-tag-color: rgb(0, 0, 0); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(0, 0, 0); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-the-matrix { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(0, 255, 0); + --playground-code-cursor-color: rgb(0, 255, 0); + --playground-code-selection-background: rgb(45, 45, 45); + --playground-code-gutter-background: rgb(0, 102, 0); + --playground-code-gutter-border-right: 2px solid rgb(0, 255, 0); + --playground-code-linenumber-color: rgb(255, 255, 255); + --playground-code-atom-color: rgb(51, 255, 255); + --playground-code-attribute-color: rgb(255, 247, 0); + --playground-code-comment-color: rgb(204, 204, 204); + --playground-code-def-color: rgb(153, 153, 204); + --playground-code-keyword-color: rgb(0, 136, 3); + --playground-code-meta-color: rgb(204, 153, 255); + --playground-code-number-color: rgb(255, 185, 79); + --playground-code-operator-color: rgb(153, 153, 153); + --playground-code-qualifier-color: rgb(255, 247, 0); + --playground-code-string-color: rgb(51, 153, 204); + --playground-code-string-2-color: rgb(0, 255, 0); + --playground-code-tag-color: rgb(255, 189, 64); + --playground-code-type-color: rgb(153, 102, 255); + --playground-code-variable-color: rgb(255, 102, 204); + --playground-code-variable-2-color: rgb(204, 102, 255); + --playground-code-variable-3-color: rgb(153, 102, 255); + --playground-code-callee-color: rgb(0, 255, 0); + --playground-code-property-color: rgb(98, 255, 160) +} +`,c` +.playground-theme-tomorrow-night-bright { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(234, 234, 234); + --playground-code-cursor-color: rgb(106, 106, 106); + --playground-code-selection-background: rgb(66, 66, 66); + --playground-code-gutter-background: rgb(0, 0, 0); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(66, 66, 66); + --playground-code-atom-color: rgb(161, 106, 148); + --playground-code-attribute-color: rgb(153, 204, 153); + --playground-code-builtin-color: rgb(234, 234, 234); + --playground-code-comment-color: rgb(210, 123, 83); + --playground-code-def-color: rgb(231, 140, 69); + --playground-code-keyword-color: rgb(213, 78, 83); + --playground-code-meta-color: rgb(234, 234, 234); + --playground-code-number-color: rgb(161, 106, 148); + --playground-code-operator-color: rgb(234, 234, 234); + --playground-code-qualifier-color: rgb(234, 234, 234); + --playground-code-string-color: rgb(231, 197, 71); + --playground-code-string-2-color: rgb(234, 234, 234); + --playground-code-tag-color: rgb(213, 78, 83); + --playground-code-type-color: rgb(234, 234, 234); + --playground-code-variable-color: rgb(185, 202, 74); + --playground-code-variable-2-color: rgb(122, 166, 218); + --playground-code-variable-3-color: rgb(234, 234, 234); + --playground-code-callee-color: rgb(234, 234, 234); + --playground-code-property-color: rgb(153, 204, 153) +} +`,c` +.playground-theme-tomorrow-night-eighties { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(204, 204, 204); + --playground-code-cursor-color: rgb(106, 106, 106); + --playground-code-selection-background: rgb(45, 45, 45); + --playground-code-gutter-background: rgb(0, 0, 0); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(81, 81, 81); + --playground-code-atom-color: rgb(161, 106, 148); + --playground-code-attribute-color: rgb(153, 204, 153); + --playground-code-builtin-color: rgb(204, 204, 204); + --playground-code-comment-color: rgb(210, 123, 83); + --playground-code-def-color: rgb(249, 145, 87); + --playground-code-keyword-color: rgb(242, 119, 122); + --playground-code-meta-color: rgb(204, 204, 204); + --playground-code-number-color: rgb(161, 106, 148); + --playground-code-operator-color: rgb(204, 204, 204); + --playground-code-qualifier-color: rgb(204, 204, 204); + --playground-code-string-color: rgb(255, 204, 102); + --playground-code-string-2-color: rgb(204, 204, 204); + --playground-code-tag-color: rgb(242, 119, 122); + --playground-code-type-color: rgb(204, 204, 204); + --playground-code-variable-color: rgb(153, 204, 153); + --playground-code-variable-2-color: rgb(102, 153, 204); + --playground-code-variable-3-color: rgb(204, 204, 204); + --playground-code-callee-color: rgb(204, 204, 204); + --playground-code-property-color: rgb(153, 204, 153) +} +`,c` +.playground-theme-ttcn { + --playground-code-builtin-color: rgb(0, 0, 0); + --playground-code-comment-color: rgb(51, 51, 51); + --playground-code-keyword-color: rgb(0, 0, 0); + --playground-code-number-color: rgb(0, 0, 0); + --playground-code-string-color: rgb(0, 100, 0); + --playground-code-variable-color: rgb(139, 34, 82) +} +`,c` +.playground-theme-twilight { + --playground-code-background: rgb(20, 20, 20); + --playground-code-default-color: rgb(247, 247, 247); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(50, 50, 50); + --playground-code-gutter-background: rgb(34, 34, 34); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(170, 170, 170); + --playground-code-atom-color: rgb(255, 204, 0); + --playground-code-attribute-color: rgb(214, 187, 109); + --playground-code-builtin-color: rgb(205, 168, 105); + --playground-code-comment-color: rgb(119, 119, 119); + --playground-code-def-color: rgb(96, 115, 146); + --playground-code-keyword-color: rgb(249, 238, 152); + --playground-code-meta-color: rgb(247, 247, 247); + --playground-code-number-color: rgb(202, 120, 65); + --playground-code-operator-color: rgb(205, 168, 105); + --playground-code-qualifier-color: rgb(247, 247, 247); + --playground-code-string-color: rgb(143, 157, 106); + --playground-code-string-2-color: rgb(189, 107, 24); + --playground-code-tag-color: rgb(96, 115, 146); + --playground-code-type-color: rgb(96, 115, 146); + --playground-code-variable-color: rgb(247, 247, 247); + --playground-code-variable-2-color: rgb(96, 115, 146); + --playground-code-variable-3-color: rgb(96, 115, 146); + --playground-code-callee-color: rgb(247, 247, 247); + --playground-code-property-color: rgb(247, 247, 247) +} +`,c` +.playground-theme-vibrant-ink { + --playground-code-background: rgb(0, 0, 0); + --playground-code-default-color: rgb(255, 255, 255); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(53, 73, 60); + --playground-code-gutter-background: rgb(0, 34, 64); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(208, 208, 208); + --playground-code-atom-color: rgb(255, 204, 0); + --playground-code-attribute-color: rgb(141, 166, 206); + --playground-code-builtin-color: rgb(141, 166, 206); + --playground-code-comment-color: rgb(128, 128, 128); + --playground-code-def-color: rgb(141, 166, 206); + --playground-code-keyword-color: rgb(204, 120, 50); + --playground-code-meta-color: rgb(216, 250, 60); + --playground-code-number-color: rgb(255, 238, 152); + --playground-code-operator-color: rgb(136, 136, 136); + --playground-code-qualifier-color: rgb(255, 255, 255); + --playground-code-string-color: rgb(165, 194, 92); + --playground-code-string-2-color: rgb(255, 0, 0); + --playground-code-tag-color: rgb(141, 166, 206); + --playground-code-type-color: rgb(255, 255, 255); + --playground-code-variable-color: rgb(255, 255, 255); + --playground-code-variable-2-color: rgb(255, 198, 109); + --playground-code-variable-3-color: rgb(255, 198, 109); + --playground-code-callee-color: rgb(255, 255, 255); + --playground-code-property-color: rgb(255, 255, 255) +} +`,c` +.playground-theme-xq-dark { + --playground-code-background: rgb(10, 0, 31); + --playground-code-default-color: rgb(248, 248, 248); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(39, 0, 122); + --playground-code-gutter-background: rgb(10, 0, 31); + --playground-code-gutter-border-right: 1px solid rgb(170, 170, 170); + --playground-code-linenumber-color: rgb(248, 248, 248); + --playground-code-atom-color: rgb(108, 140, 213); + --playground-code-attribute-color: rgb(255, 247, 0); + --playground-code-comment-color: rgb(128, 128, 128); + --playground-code-def-color: rgb(255, 255, 255); + --playground-code-keyword-color: rgb(255, 189, 64); + --playground-code-meta-color: rgb(255, 255, 0); + --playground-code-operator-color: rgb(248, 248, 248); + --playground-code-qualifier-color: rgb(255, 247, 0); + --playground-code-string-color: rgb(159, 238, 0); + --playground-code-string-2-color: rgb(248, 248, 248); + --playground-code-tag-color: rgb(255, 189, 64); + --playground-code-type-color: rgb(221, 221, 221); + --playground-code-variable-color: rgb(255, 255, 255); + --playground-code-variable-2-color: rgb(238, 238, 238); + --playground-code-variable-3-color: rgb(221, 221, 221); + --playground-code-callee-color: rgb(248, 248, 248); + --playground-code-property-color: rgb(248, 248, 248) +} +`,c` +.playground-theme-xq-light { + --playground-code-atom-color: rgb(108, 140, 213); + --playground-code-attribute-color: rgb(127, 0, 127); + --playground-code-builtin-color: rgb(126, 166, 86); + --playground-code-comment-color: rgb(0, 128, 255); + --playground-code-def-color: rgb(0, 0, 0); + --playground-code-keyword-color: rgb(90, 92, 173); + --playground-code-meta-color: rgb(255, 255, 0); + --playground-code-qualifier-color: rgb(128, 128, 128); + --playground-code-string-color: rgb(255, 0, 0); + --playground-code-string-2-color: rgb(0, 0, 0); + --playground-code-tag-color: rgb(63, 127, 127); + --playground-code-type-color: rgb(0, 0, 0); + --playground-code-variable-2-color: rgb(0, 0, 0); + --playground-code-variable-3-color: rgb(0, 0, 0) +} +`,c` +.playground-theme-yeti { + --playground-code-background: rgb(236, 234, 232); + --playground-code-default-color: rgb(209, 201, 192); + --playground-code-cursor-color: rgb(209, 201, 192); + --playground-code-gutter-background: rgb(229, 225, 219); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(173, 171, 166); + --playground-code-atom-color: rgb(160, 116, 196); + --playground-code-attribute-color: rgb(159, 185, 110); + --playground-code-builtin-color: rgb(160, 116, 196); + --playground-code-comment-color: rgb(212, 200, 190); + --playground-code-def-color: rgb(85, 181, 219); + --playground-code-keyword-color: rgb(159, 185, 110); + --playground-code-meta-color: rgb(150, 192, 216); + --playground-code-number-color: rgb(160, 116, 196); + --playground-code-operator-color: rgb(159, 185, 110); + --playground-code-qualifier-color: rgb(150, 192, 216); + --playground-code-string-color: rgb(150, 192, 216); + --playground-code-string-2-color: rgb(150, 192, 216); + --playground-code-tag-color: rgb(150, 192, 216); + --playground-code-type-color: rgb(150, 192, 216); + --playground-code-variable-color: rgb(85, 181, 219); + --playground-code-variable-2-color: rgb(160, 116, 196); + --playground-code-variable-3-color: rgb(150, 192, 216); + --playground-code-callee-color: rgb(209, 201, 192); + --playground-code-property-color: rgb(160, 116, 196) +} +`,c` +.playground-theme-yonce { + --playground-code-background: rgb(28, 28, 28); + --playground-code-default-color: rgb(212, 212, 212); + --playground-code-cursor-color: rgb(252, 67, 132); + --playground-code-selection-background: rgba(252, 69, 133, 0.48); + --playground-code-gutter-background: rgb(28, 28, 28); + --playground-code-gutter-border-right: 0px; + --playground-code-linenumber-color: rgb(119, 119, 119); + --playground-code-atom-color: rgb(243, 155, 53); + --playground-code-attribute-color: rgb(160, 111, 202); + --playground-code-builtin-color: rgb(252, 67, 132); + --playground-code-comment-color: rgb(105, 109, 112); + --playground-code-def-color: rgb(152, 227, 66); + --playground-code-keyword-color: rgb(0, 167, 170); + --playground-code-meta-color: rgb(212, 212, 212); + --playground-code-number-color: rgb(160, 111, 202); + --playground-code-operator-color: rgb(252, 67, 132); + --playground-code-qualifier-color: rgb(252, 67, 132); + --playground-code-string-color: rgb(230, 219, 116); + --playground-code-string-2-color: rgb(243, 155, 53); + --playground-code-tag-color: rgb(252, 67, 132); + --playground-code-type-color: rgb(160, 111, 202); + --playground-code-variable-color: rgb(212, 212, 212); + --playground-code-variable-2-color: rgb(218, 125, 174); + --playground-code-variable-3-color: rgb(160, 111, 202); + --playground-code-callee-color: rgb(252, 67, 132); + --playground-code-property-color: rgb(212, 212, 212) +} +`,c` +.playground-theme-zenburn { + --playground-code-background: rgb(63, 63, 63); + --playground-code-default-color: rgb(220, 220, 204); + --playground-code-cursor-color: rgb(255, 255, 255); + --playground-code-selection-background: rgb(84, 84, 84); + --playground-code-gutter-background: rgb(63, 63, 63); + --playground-code-atom-color: rgb(191, 235, 191); + --playground-code-attribute-color: rgb(223, 175, 143); + --playground-code-builtin-color: rgb(220, 220, 204); + --playground-code-comment-color: rgb(127, 159, 127); + --playground-code-def-color: rgb(220, 220, 204); + --playground-code-keyword-color: rgb(240, 223, 175); + --playground-code-meta-color: rgb(240, 223, 175); + --playground-code-number-color: rgb(220, 220, 204); + --playground-code-operator-color: rgb(240, 239, 208); + --playground-code-qualifier-color: rgb(124, 184, 187); + --playground-code-string-color: rgb(204, 147, 147); + --playground-code-string-2-color: rgb(204, 147, 147); + --playground-code-tag-color: rgb(147, 224, 227); + --playground-code-type-color: rgb(220, 220, 204); + --playground-code-variable-color: rgb(223, 175, 143); + --playground-code-variable-2-color: rgb(220, 220, 204); + --playground-code-variable-3-color: rgb(220, 220, 204); + --playground-code-callee-color: rgb(220, 220, 204); + --playground-code-property-color: rgb(223, 175, 143) +} +`],Mi=[{id:"codeBackground",label:"Background",cssProperty:"--playground-code-background",defaultValue:"#ffffff"},{id:"synDefault",label:"Default",cssProperty:"--playground-code-default-color",cmClass:'.CodeMirror-line [role="presentation"]',defaultValue:"#000000"},{id:"synKeyword",label:"Keyword",cssProperty:"--playground-code-keyword-color",cmClass:"cm-keyword",defaultValue:"#770088"},{id:"synAtom",label:"Atom",cssProperty:"--playground-code-atom-color",cmClass:"cm-atom",defaultValue:"#221199"},{id:"synNumber",label:"Number",cssProperty:"--playground-code-number-color",cmClass:"cm-number",defaultValue:"#116644"},{id:"synDef",label:"Def",cssProperty:"--playground-code-def-color",cmClass:"cm-def",defaultValue:"#0000ff"},{id:"synVariable",label:"Variable",cssProperty:"--playground-code-variable-color",cmClass:"cm-variable",defaultValue:"#000000"},{id:"synProperty",label:"Property",cssProperty:"--playground-code-property-color",cmClass:"cm-property",defaultValue:"#000000"},{id:"synOperator",label:"Operator",cssProperty:"--playground-code-operator-color",cmClass:"cm-operator",defaultValue:"#000000"},{id:"synVariable2",label:"Variable 2",cssProperty:"--playground-code-variable-2-color",cmClass:"cm-variable-2",defaultValue:"#0055aa"},{id:"synVariable3",label:"Variable 3",cssProperty:"--playground-code-variable-3-color",cmClass:"cm-variable-3",defaultValue:"#008855"},{id:"synType",label:"Type",cssProperty:"--playground-code-type-color",cmClass:"cm-type",defaultValue:"#008855"},{id:"synComment",label:"Comment",cssProperty:"--playground-code-comment-color",cmClass:"cm-comment",defaultValue:"#aa5500"},{id:"synString",label:"String",cssProperty:"--playground-code-string-color",cmClass:"cm-string",defaultValue:"#aa1111"},{id:"synString2",label:"String 2",cssProperty:"--playground-code-string-2-color",cmClass:"cm-string-2",defaultValue:"#ff5500"},{id:"synMeta",label:"Meta",cssProperty:"--playground-code-meta-color",cmClass:"cm-meta",defaultValue:"#555555"},{id:"synQualifier",label:"Qualifier",cssProperty:"--playground-code-qualifier-color",cmClass:"cm-qualifier",defaultValue:"#555555"},{id:"synBuiltin",label:"Builtin",cssProperty:"--playground-code-builtin-color",cmClass:"cm-builtin",defaultValue:"#3300aa"},{id:"synTag",label:"Tag",cssProperty:"--playground-code-tag-color",cmClass:"cm-tag",defaultValue:"#117700"},{id:"synAttribute",label:"Attribute",cssProperty:"--playground-code-attribute-color",cmClass:"cm-attribute",defaultValue:"#0000cc"},{id:"synCallee",label:"Callee",cssProperty:"--playground-code-callee-color",cmClass:"cm-callee",defaultValue:"#000000"}]; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +function Ii(e){return{type:"checkbox",...e}}function Ri(e){return{type:"slider",...e}}function Fi(e){return{type:"color",...e}}function Ni(e){return{type:"select",...e}}const zi=e=>e+"px",Di=[Ni({id:"theme",label:"Theme",section:"code",options:["default","3024-day","3024-night","abbott","abcdef","ambiance","ayu-dark","ayu-mirage","base16-dark","base16-light","bespin","blackboard","cobalt","colorforth","darcula","dracula","duotone-dark","duotone-light","eclipse","elegant","erlang-dark","gruvbox-dark","hopscotch","icecoder","idea","isotope","juejin","lesser-dark","liquibyte","lucario","material-darker","material-ocean","material-palenight","material","mbo","mdn-like","midnight","monokai","moxer","neat","neo","night","nord","oceanic-next","panda-syntax","paraiso-dark","paraiso-light","pastel-on-dark","railscasts","rubyblue","seti","shadowfox","solarized","ssms","the-matrix","tomorrow-night-bright","tomorrow-night-eighties","ttcn","twilight","vibrant-ink","xq-dark","xq-light","yeti","yonce","zenburn"],default:"default"}),Ri({id:"fontSize",label:"Font size",section:"code",cssProperty:"--playground-code-font-size",formatCss:zi,min:1,max:30,default:14}),Ni({id:"fontFamily",label:"Font",section:"code",cssProperty:"--playground-code-font-family",options:["monospace","Roboto Mono","Source Code Pro","Ubuntu Mono"],formatCss:e=>"monospace"!==e?e+", monospace":e,default:"monospace"}),...Mi.map((e=>{const{id:t,label:r,cssProperty:o,defaultValue:i}=e;return Fi({id:t,label:r,cssProperty:o,default:i,originalDefault:i,section:"code"})})),Ii({id:"resizable",label:"Resizable",section:"features",default:!1,htmlAttribute:"resizable"}),Ii({id:"editableFileSystem",label:"Editable filesystem",section:"features",default:!1,htmlAttribute:"editable-file-system"}),Ii({id:"lineNumbers",label:"Line numbers",section:"features",default:!1,htmlAttribute:"line-numbers"}),Ii({id:"lineWrapping",label:"Line wrapping",section:"features",default:!1,htmlAttribute:"line-wrapping"}),Ii({id:"noCompletions",label:"No completions",section:"features",default:!1,htmlAttribute:"no-completions"}),Fi({id:"highlight",label:"Highlight",cssProperty:"--playground-highlight-color",default:"#6200ee",section:"general appearance"}),Fi({id:"pageBackground",label:"Page background",default:"#cccccc",originalDefault:"#cccccc",section:"general appearance"}),Ri({id:"radius",label:"Radius",cssProperty:"border-radius",formatCss:zi,min:0,max:30,default:0,section:"general appearance"}),Ii({id:"borders",label:"Borders",cssProperty:"--playground-border",formatCss:e=>e?"1px solid #ddd":"none",default:!0,section:"general appearance"}),Fi({id:"tabBarBackground",label:"Background",cssProperty:"--playground-tab-bar-background",default:"#eaeaea",section:"tab bar"}),Fi({id:"tabBarForeground",label:"Foreground",cssProperty:"--playground-tab-bar-foreground-color",default:"#000000",section:"tab bar"}),Ri({id:"barHeight",label:"Bar height",cssProperty:"--playground-bar-height",formatCss:zi,min:10,max:100,default:40,section:"tab bar"}),Fi({id:"previewToolbarBackground",label:"Background",cssProperty:"--playground-preview-toolbar-background",default:"#ffffff",section:"preview"}),Fi({id:"previewToolbarForeground",label:"Foreground",cssProperty:"--playground-preview-toolbar-foreground-color",default:"#444444",section:"preview"}),Ri({id:"previewWidth",label:"Preview width",cssProperty:"--playground-preview-width",formatCss:e=>e+"%",min:0,max:100,default:30,section:"preview"})],Pi={},Hi={};for(const e of Di){Pi[e.id]=e;let t=Hi[e.section];void 0===t&&(t=Hi[e.section]=[]),t.push(e)}const Ui=Object.keys(Pi),Bi=Object.keys(Hi);class Wi{constructor(){this.values=new Map}getValue(e){return this.values.has(e)?this.values.get(e):Pi[e].default}setValue(e,t){this.values.set(e,t)}} +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */(()=>{var e,t,r;const o=Symbol(),i=Symbol(),n=Symbol(),a=Symbol(),l=Symbol(),s=Symbol(),d=Symbol(),c=Symbol(),u=Symbol(),p=Symbol(),h=Symbol(),g=Symbol(),m=Symbol();class f{constructor(){this[e]=[],this[t]=[],this[r]=new Set}destructor(){this[u](this[n]);const e=this;e[o]=null,e[n]=null,e[i]=null}get top(){const e=this[o];return e[e.length-1]||null}push(e){e&&e!==this.top&&(this.remove(e),this[s](e),this[o].push(e))}remove(e){const t=this[o].indexOf(e);return-1!==t&&(this[o].splice(t,1),t===this[o].length&&this[s](this.top),!0)}pop(){const e=this.top;return e&&this.remove(e),e}has(e){return-1!==this[o].indexOf(e)}[(e=o,t=n,r=i,s)](e){const t=this[i],r=this[n];if(!e)return this[u](r),t.clear(),void(this[n]=[]);const o=this[p](e);if(o[o.length-1].parentNode!==document.body)throw Error("Non-connected element cannot be a blocking element");this[n]=o;const a=this[h](e);if(!r.length)return void this[c](o,a,t);let l=r.length-1,s=o.length-1;for(;l>0&&s>0&&r[l]===o[s];)l--,s--;r[l]!==o[s]&&this[d](r[l],o[s]),l>0&&this[u](r.slice(0,l)),s>0&&this[c](o.slice(0,s),a,null)}[d](e,t){const r=e[a];this[g](e)&&!e.inert&&(e.inert=!0,r.add(e)),r.has(t)&&(t.inert=!1,r.delete(t)),t[l]=e[l],t[a]=r,e[l]=void 0,e[a]=void 0}[u](e){for(const t of e){t[l].disconnect(),t[l]=void 0;const e=t[a];for(const t of e)t.inert=!1;t[a]=void 0}}[c](e,t,r){for(const o of e){const e=o.parentNode,i=e.children,n=new Set;for(let e=0;ee instanceof HTMLElement));return e[0]||null}emitNotification(e,t){const r=new CustomEvent(e,{detail:t?{action:t}:{}});this.dispatchEvent(r)}getInitialFocusEl(){const e=`[${this.initialFocusAttribute}]`,t=this.querySelector(e);if(t)return t;const r=this.primarySlot.assignedNodes({flatten:!0}),o=this.searchNodeTreesForAttribute(r,this.initialFocusAttribute);if(o)return o;const i=this.secondarySlot.assignedNodes({flatten:!0}),n=this.searchNodeTreesForAttribute(i,this.initialFocusAttribute);if(n)return n;const a=this.contentSlot.assignedNodes({flatten:!0});return this.searchNodeTreesForAttribute(a,this.initialFocusAttribute)}searchNodeTreesForAttribute(e,t){for(const r of e)if(r instanceof HTMLElement){if(r.hasAttribute(t))return r;{const e=r.querySelector(`[${t}]`);if(e)return e}}return null}createAdapter(){return Object.assign(Object.assign({},Jt(this.mdcRoot)),{addBodyClass:()=>document.body.style.overflow="hidden",removeBodyClass:()=>document.body.style.overflow="",areButtonsStacked:()=>this.stacked,clickDefaultButton:()=>{const e=this.primaryButton;e&&e.click()},eventTargetMatches:(e,t)=>!!e&&Gt(e,t),getActionFromEvent:e=>{if(!e.target)return"";const t= +/** + * @license + * Copyright 2018 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +function(e,t){if(e.closest)return e.closest(t);for(var r=e;r;){if(Gt(r,t))return r;r=r.parentElement}return null}(e.target,`[${this.actionAttribute}]`);return t&&t.getAttribute(this.actionAttribute)},getInitialFocusEl:()=>this.getInitialFocusEl(),isContentScrollable:()=>{const e=this.contentElement;return!!e&&e.scrollHeight>e.offsetHeight},notifyClosed:e=>this.emitNotification("closed",e),notifyClosing:e=>{this.closingDueToDisconnect||(this.open=!1),this.emitNotification("closing",e)},notifyOpened:()=>this.emitNotification("opened"),notifyOpening:()=>{this.open=!0,this.emitNotification("opening")},reverseButtons:()=>{},releaseFocus:()=>{Xi.remove(this)},trapFocus:e=>{this.isConnected&&(Xi.push(this),e&&e.focus())},registerContentEventHandler:(e,t)=>{this.contentElement.addEventListener(e,t)},deregisterContentEventHandler:(e,t)=>{this.contentElement.removeEventListener(e,t)},isScrollableContentAtTop:()=>{const e=this.contentElement;return!!e&&0===e.scrollTop},isScrollableContentAtBottom:()=>{const e=this.contentElement;return!!e&&Math.ceil(e.scrollHeight-e.scrollTop)===e.clientHeight},registerWindowEventHandler:(e,t)=>{window.addEventListener(e,t,Yi())},deregisterWindowEventHandler:(e,t)=>{window.removeEventListener(e,t,Yi())}})}render(){const e={[qi.STACKED]:this.stacked};let t=W``;this.heading&&(t=this.renderHeading());const r={"mdc-dialog__actions":!this.hideActions};return W` +
+
+
+ ${t} +
+ +
+
+ + + + + + +
+
+
+
+
`}renderHeading(){return W` +

${this.heading}

`}firstUpdated(){super.firstUpdated(),this.mdcFoundation.setAutoStackButtons(!0),this.initialSupressDefaultPressSelector?this.suppressDefaultPressSelector=this.initialSupressDefaultPressSelector:this.suppressDefaultPressSelector=[this.suppressDefaultPressSelector,"mwc-textarea, mwc-menu mwc-list-item, mwc-select mwc-list-item"].join(", "),this.boundHandleClick=this.mdcFoundation.handleClick.bind(this.mdcFoundation),this.boundHandleKeydown=this.mdcFoundation.handleKeydown.bind(this.mdcFoundation),this.boundHandleDocumentKeydown=this.mdcFoundation.handleDocumentKeydown.bind(this.mdcFoundation)}connectedCallback(){super.connectedCallback(),this.open&&this.mdcFoundation&&!this.mdcFoundation.isOpen()&&(this.setEventListeners(),this.mdcFoundation.open())}disconnectedCallback(){super.disconnectedCallback(),this.open&&this.mdcFoundation&&(this.removeEventListeners(),this.closingDueToDisconnect=!0,this.mdcFoundation.close(this.currentAction||this.defaultAction),this.closingDueToDisconnect=!1,this.currentAction=void 0,Xi.remove(this))}forceLayout(){this.mdcFoundation.layout()}focus(){const e=this.getInitialFocusEl();e&&e.focus()}blur(){if(!this.shadowRoot)return;const e=this.shadowRoot.activeElement;if(e)e instanceof HTMLElement&&e.blur();else{const e=this.getRootNode(),t=e instanceof Document?e.activeElement:null;t instanceof HTMLElement&&t.blur()}}setEventListeners(){this.boundHandleClick&&this.mdcRoot.addEventListener("click",this.boundHandleClick),this.boundHandleKeydown&&this.mdcRoot.addEventListener("keydown",this.boundHandleKeydown,Yi()),this.boundHandleDocumentKeydown&&document.addEventListener("keydown",this.boundHandleDocumentKeydown,Yi())}removeEventListeners(){this.boundHandleClick&&this.mdcRoot.removeEventListener("click",this.boundHandleClick),this.boundHandleKeydown&&this.mdcRoot.removeEventListener("keydown",this.boundHandleKeydown),this.boundHandleDocumentKeydown&&document.removeEventListener("keydown",this.boundHandleDocumentKeydown)}close(){this.open=!1}show(){this.open=!0}}o([ye(".mdc-dialog")],$i.prototype,"mdcRoot",void 0),o([ye('slot[name="primaryAction"]')],$i.prototype,"primarySlot",void 0),o([ye('slot[name="secondaryAction"]')],$i.prototype,"secondarySlot",void 0),o([ye("#contentSlot")],$i.prototype,"contentSlot",void 0),o([ye(".mdc-dialog__content")],$i.prototype,"contentElement",void 0),o([ye(".mdc-container")],$i.prototype,"conatinerElement",void 0),o([ge({type:Boolean})],$i.prototype,"hideActions",void 0),o([ge({type:Boolean}),Tr((function(){this.forceLayout()}))],$i.prototype,"stacked",void 0),o([ge({type:String})],$i.prototype,"heading",void 0),o([ge({type:String}),Tr((function(e){this.mdcFoundation.setScrimClickAction(e)}))],$i.prototype,"scrimClickAction",void 0),o([ge({type:String}),Tr((function(e){this.mdcFoundation.setEscapeKeyAction(e)}))],$i.prototype,"escapeKeyAction",void 0),o([ge({type:Boolean,reflect:!0}),Tr((function(e){this.mdcFoundation&&this.isConnected&&(e?(this.setEventListeners(),this.mdcFoundation.open()):(this.removeEventListeners(),this.mdcFoundation.close(this.currentAction||this.defaultAction),this.currentAction=void 0))}))],$i.prototype,"open",void 0),o([ge()],$i.prototype,"defaultAction",void 0),o([ge()],$i.prototype,"actionAttribute",void 0),o([ge()],$i.prototype,"initialFocusAttribute",void 0); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-LIcense-Identifier: Apache-2.0 + */ +const en=c`.mdc-dialog .mdc-dialog__surface{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-dialog .mdc-dialog__scrim{background-color:rgba(0,0,0,.32)}.mdc-dialog .mdc-dialog__surface-scrim{background-color:rgba(0,0,0,.32)}.mdc-dialog .mdc-dialog__title{color:rgba(0,0,0,.87)}.mdc-dialog .mdc-dialog__content{color:rgba(0,0,0,.6)}.mdc-dialog .mdc-dialog__close{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000))}.mdc-dialog .mdc-dialog__close:hover .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title,.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__actions,.mdc-dialog.mdc-dialog--scrollable.mdc-dialog-scroll-divider-footer .mdc-dialog__actions{border-color:rgba(0,0,0,.12)}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title{border-bottom:1px solid rgba(0,0,0,.12);margin-bottom:0}.mdc-dialog.mdc-dialog-scroll-divider-header.mdc-dialog--fullscreen .mdc-dialog__header{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12)}.mdc-dialog .mdc-dialog__surface{border-radius:4px;border-radius:var(--mdc-shape-medium, 4px)}.mdc-dialog__surface{box-shadow:0px 11px 15px -7px rgba(0, 0, 0, 0.2),0px 24px 38px 3px rgba(0, 0, 0, 0.14),0px 9px 46px 8px rgba(0,0,0,.12)}.mdc-dialog__title{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:0.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit)}.mdc-dialog__content{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-body1-font-size, 1rem);line-height:1.5rem;line-height:var(--mdc-typography-body1-line-height, 1.5rem);font-weight:400;font-weight:var(--mdc-typography-body1-font-weight, 400);letter-spacing:0.03125em;letter-spacing:var(--mdc-typography-body1-letter-spacing, 0.03125em);text-decoration:inherit;text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body1-text-transform, inherit)}.mdc-elevation-overlay{position:absolute;border-radius:inherit;pointer-events:none;opacity:0;opacity:var(--mdc-elevation-overlay-opacity, 0);transition:opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);background-color:#fff;background-color:var(--mdc-elevation-overlay-color, #fff)}.mdc-dialog,.mdc-dialog__scrim{position:fixed;top:0;left:0;align-items:center;justify-content:center;box-sizing:border-box;width:100%;height:100%}.mdc-dialog{display:none;z-index:7;z-index:var(--mdc-dialog-z-index, 7)}.mdc-dialog .mdc-dialog__content{padding:20px 24px 20px 24px}.mdc-dialog .mdc-dialog__surface{min-width:280px}@media(max-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:calc(100vw - 32px)}}@media(min-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:560px}}.mdc-dialog .mdc-dialog__surface{max-height:calc(100% - 32px)}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-width:none}@media(max-width: 960px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:560px;width:560px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}@media(max-width: 720px)and (max-width: 672px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{width:calc(100vw - 112px)}}@media(max-width: 720px)and (min-width: 672px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{width:560px}}@media(max-width: 720px)and (max-height: 720px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:calc(100vh - 160px)}}@media(max-width: 720px)and (min-height: 720px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:560px}}@media(max-width: 720px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}@media(max-width: 720px)and (max-height: 400px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{height:100%;max-height:100vh;max-width:100vw;width:100vw;border-radius:0}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{order:-1;left:-12px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header{padding:0 16px 9px;justify-content:flex-start}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title{margin-left:calc(16px - 2 * 12px)}}@media(max-width: 600px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{height:100%;max-height:100vh;max-width:100vw;width:100vw;border-radius:0}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{order:-1;left:-12px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header{padding:0 16px 9px;justify-content:flex-start}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title{margin-left:calc(16px - 2 * 12px)}}@media(min-width: 960px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{width:calc(100vw - 400px)}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}.mdc-dialog.mdc-dialog__scrim--hidden .mdc-dialog__scrim{opacity:0}.mdc-dialog__scrim{opacity:0;z-index:-1}.mdc-dialog__container{display:flex;flex-direction:row;align-items:center;justify-content:space-around;box-sizing:border-box;height:100%;transform:scale(0.8);opacity:0;pointer-events:none}.mdc-dialog__surface{position:relative;display:flex;flex-direction:column;flex-grow:0;flex-shrink:0;box-sizing:border-box;max-width:100%;max-height:100%;pointer-events:auto;overflow-y:auto}.mdc-dialog__surface .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}[dir=rtl] .mdc-dialog__surface,.mdc-dialog__surface[dir=rtl]{text-align:right}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-dialog__surface{outline:2px solid windowText}}.mdc-dialog__surface::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:2px solid transparent;border-radius:inherit;content:"";pointer-events:none}@media screen and (forced-colors: active){.mdc-dialog__surface::before{border-color:CanvasText}}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.mdc-dialog__surface::before{content:none}}.mdc-dialog__title{display:block;margin-top:0;position:relative;flex-shrink:0;box-sizing:border-box;margin:0 0 1px;padding:0 24px 9px}.mdc-dialog__title::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}[dir=rtl] .mdc-dialog__title,.mdc-dialog__title[dir=rtl]{text-align:right}.mdc-dialog--scrollable .mdc-dialog__title{margin-bottom:1px;padding-bottom:15px}.mdc-dialog--fullscreen .mdc-dialog__header{align-items:baseline;border-bottom:1px solid transparent;display:inline-flex;justify-content:space-between;padding:0 24px 9px;z-index:1}@media screen and (forced-colors: active){.mdc-dialog--fullscreen .mdc-dialog__header{border-bottom-color:CanvasText}}.mdc-dialog--fullscreen .mdc-dialog__header .mdc-dialog__close{right:-12px}.mdc-dialog--fullscreen .mdc-dialog__title{margin-bottom:0;padding:0;border-bottom:0}.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__title{border-bottom:0;margin-bottom:0}.mdc-dialog--fullscreen .mdc-dialog__close{top:5px}.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__actions{border-top:1px solid transparent}@media screen and (forced-colors: active){.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__actions{border-top-color:CanvasText}}.mdc-dialog__content{flex-grow:1;box-sizing:border-box;margin:0;overflow:auto}.mdc-dialog__content>:first-child{margin-top:0}.mdc-dialog__content>:last-child{margin-bottom:0}.mdc-dialog__title+.mdc-dialog__content,.mdc-dialog__header+.mdc-dialog__content{padding-top:0}.mdc-dialog--scrollable .mdc-dialog__title+.mdc-dialog__content{padding-top:8px;padding-bottom:8px}.mdc-dialog__content .mdc-deprecated-list:first-child:last-child{padding:6px 0 0}.mdc-dialog--scrollable .mdc-dialog__content .mdc-deprecated-list:first-child:last-child{padding:0}.mdc-dialog__actions{display:flex;position:relative;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;box-sizing:border-box;min-height:52px;margin:0;padding:8px;border-top:1px solid transparent}@media screen and (forced-colors: active){.mdc-dialog__actions{border-top-color:CanvasText}}.mdc-dialog--stacked .mdc-dialog__actions{flex-direction:column;align-items:flex-end}.mdc-dialog__button{margin-left:8px;margin-right:0;max-width:100%;text-align:right}[dir=rtl] .mdc-dialog__button,.mdc-dialog__button[dir=rtl]{margin-left:0;margin-right:8px}.mdc-dialog__button:first-child{margin-left:0;margin-right:0}[dir=rtl] .mdc-dialog__button:first-child,.mdc-dialog__button:first-child[dir=rtl]{margin-left:0;margin-right:0}[dir=rtl] .mdc-dialog__button,.mdc-dialog__button[dir=rtl]{text-align:left}.mdc-dialog--stacked .mdc-dialog__button:not(:first-child){margin-top:12px}.mdc-dialog--open,.mdc-dialog--opening,.mdc-dialog--closing{display:flex}.mdc-dialog--opening .mdc-dialog__scrim{transition:opacity 150ms linear}.mdc-dialog--opening .mdc-dialog__container{transition:opacity 75ms linear,transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-dialog--closing .mdc-dialog__scrim,.mdc-dialog--closing .mdc-dialog__container{transition:opacity 75ms linear}.mdc-dialog--closing .mdc-dialog__container{transform:none}.mdc-dialog--open .mdc-dialog__scrim{opacity:1}.mdc-dialog--open .mdc-dialog__container{transform:none;opacity:1}.mdc-dialog--open.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim{opacity:1;z-index:1}.mdc-dialog--open.mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim{transition:opacity 75ms linear}.mdc-dialog--open.mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim{transition:opacity 150ms linear}.mdc-dialog__surface-scrim{display:none;opacity:0;position:absolute;width:100%;height:100%}.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim,.mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim,.mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim{display:block}.mdc-dialog-scroll-lock{overflow:hidden}.mdc-dialog--no-content-padding .mdc-dialog__content{padding:0}.mdc-dialog--sheet .mdc-dialog__close{right:12px;top:9px;position:absolute;z-index:1}#actions:not(.mdc-dialog__actions){display:none}.mdc-dialog__surface{box-shadow:var(--mdc-dialog-box-shadow, 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12))}@media(min-width: 560px){.mdc-dialog .mdc-dialog__surface{max-width:560px;max-width:var(--mdc-dialog-max-width, 560px)}}.mdc-dialog .mdc-dialog__scrim{background-color:rgba(0, 0, 0, 0.32);background-color:var(--mdc-dialog-scrim-color, rgba(0, 0, 0, 0.32))}.mdc-dialog .mdc-dialog__title{color:rgba(0, 0, 0, 0.87);color:var(--mdc-dialog-heading-ink-color, rgba(0, 0, 0, 0.87))}.mdc-dialog .mdc-dialog__content{color:rgba(0, 0, 0, 0.6);color:var(--mdc-dialog-content-ink-color, rgba(0, 0, 0, 0.6))}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title,.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__actions{border-color:rgba(0, 0, 0, 0.12);border-color:var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12))}.mdc-dialog .mdc-dialog__surface{min-width:280px;min-width:var(--mdc-dialog-min-width, 280px)}.mdc-dialog .mdc-dialog__surface{max-height:var(--mdc-dialog-max-height, calc(100% - 32px))}#actions ::slotted(*){margin-left:8px;margin-right:0;max-width:100%;text-align:right}[dir=rtl] #actions ::slotted(*),#actions ::slotted(*[dir=rtl]){margin-left:0;margin-right:8px}[dir=rtl] #actions ::slotted(*),#actions ::slotted(*[dir=rtl]){text-align:left}.mdc-dialog--stacked #actions{flex-direction:column-reverse}.mdc-dialog--stacked #actions *:not(:last-child) ::slotted(*){flex-basis:.000000001px;margin-top:12px}` +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */;let tn=class extends $i{};tn.styles=[en],tn=o([ue("mwc-dialog")],tn); +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +let rn=class extends de{constructor(){super(...arguments),this._filetype="ts",this._iframeSrcdoc="",this._codeText="",this._propertyValues=new Map([["--playground-code-background",null],...Mi.map((({cssProperty:e})=>[e,null]))])}render(){return W` +

Theme detector

+ +
    +
  1. + Pick a theme in VSCode
    + or any editor that copies as styled HTML +
  2. + +
  3. + Open a file with a variety of syntax
    + or click to copy a sample to paste: +
    + + + +
  4. + +
  5. Select All and Copy
  6. + +
  7. + Confirm the filetype: +
    + + + +
  8. +
  9. Click in the box below to paste and extract:
  10. +
+ +
+ +
+ + + +
+ ${[...this._propertyValues].map((([e,t])=>W``))} +
+ +
+ + +
+ `}async firstUpdated(){await this._playgroundWithUserText.updateComplete,this._playgroundWithUserText._codemirror.setOption("viewportMargin",1/0)}async _copySample(e){this._filetype=e,await navigator.clipboard.writeText(on[this._filetype])}async _onClickPasteButton(){const{html:e,text:t}=await this._readClipboard();e&&t&&(this._iframeSrcdoc=""+e,this._codeText=t)}async _readClipboard(){let e="",t="";const r=await navigator.clipboard.read();for(const o of r)for(const r of o.types)if("text/html"===r){const t=await o.getType(r);e=await t.text()}else if("text/plain"===r){const e=await o.getType(r);t=await e.text()}return{html:e,text:t}}_extractStyles(){var e;if(!this._iframeSrcdoc)return;const t=new Map,r=document.createTreeWalker(this._playgroundWithUserText.shadowRoot,NodeFilter.SHOW_TEXT);for(;r.nextNode();){const e=r.currentNode,o=e.parentElement;if(null===o)continue;let i;const n=[...o.classList].filter((e=>e.startsWith("cm-")));if(n.length>0)i=`--playground-code-${n[n.length-1].slice(3)}-color`;else{if("presentation"!==o.getAttribute("role"))continue;i="--playground-code-default-color"}const a=e.textContent.replace(/^<\/?/,"").replace(/>$/,"");let l=t.get(a);l||(l=[],t.set(a,l)),l.push(i)}const o=this._iframeWithUserHtml.contentDocument,i=o.createTreeWalker(o.body,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT);let n=!1;for(;i.nextNode();){const r=i.currentNode;if(r.nodeType===Node.TEXT_NODE){const o=r.textContent.replace(/^<\/?/,"").replace(/>$/,""),i=null===(e=t.get(o))||void 0===e?void 0:e.shift();if(i&&null===this._propertyValues.get(i)){const e=window.getComputedStyle(r.parentElement).color;this._propertyValues.set(i,e)}}else if(!n&&r.nodeType===Node.ELEMENT_NODE){const e=window.getComputedStyle(r).backgroundColor;"rgba(0, 0, 0, 0)"!==e&&(n=!0,this._propertyValues.set("--playground-code-background",e))}}this.requestUpdate()}_onClickApply(){this.dispatchEvent(new CustomEvent("apply",{detail:{properties:this._propertyValues}}))}_onClickCancel(){this.dispatchEvent(new CustomEvent("cancel"))}};rn.styles=c` + ol { + padding-left: 24px; + } + + li { + margin-bottom: 1em; + } + + button, + label { + cursor: pointer; + } + + #pasteArea { + cursor: pointer; + } + + iframe { + width: 100%; + pointer-events: none; + margin-bottom: 1em; + } + + playground-code-editor { + position: absolute; + visibility: hidden; + width: 1px; + height: 1px; + } + + #palette { + display: flex; + margin-bottom: 2em; + } + + .color { + height: 25px; + flex: 1; + } + + #buttons { + display: flex; + justify-content: flex-end; + } + + #buttons > button { + margin-left: 1em; + font-size: 18px; + } + `,o([me()],rn.prototype,"_filetype",void 0),o([me()],rn.prototype,"_iframeSrcdoc",void 0),o([me()],rn.prototype,"_codeText",void 0),o([me()],rn.prototype,"_propertyValues",void 0),o([ye("iframe")],rn.prototype,"_iframeWithUserHtml",void 0),o([ye("playground-code-editor")],rn.prototype,"_playgroundWithUserText",void 0),rn=o([ue("playground-theme-detector")],rn);const on={ts:"// Playground Sample TypeScript file\n/* Another kind of comment */\nlet variable = 1 + 1 === 2 === true;\nconst fn = (param: number) => param;\nfn(3);\n'string1';\n`string2`;\n`string3 ${variable}`\nexport class Class {\n property: string;\n}\nhtml`\n \x3c!-- HTML comment --\x3e\n \n \n`;\ncss`\n /* CSS comment */\n p, #id, .class, a, :hover {\n color: red;\n content: 'c';\n }\n`;",html:'\x3c!-- Playground sample HTML file --\x3e\n\n',css:"/* Playground sample CSS file */\np, #id, .class, a, :hover {\n color: red;\n content: 'c';\n}"}; +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */let nn=class extends de{constructor(){super(...arguments),this.values=new Wi,this._themeDetectorOpen=!1}connectedCallback(){super.connectedCallback(),this.readUrlParams(new URL(document.location.href).searchParams)}async setValue(e,t){await this.setValues(new Map([[e,t]]))}async setValues(e){const t=e.get("theme");t&&await this._applyTheme(t);for(const[t,r]of e)this.values.setValue(t,r);this.setUrlParams(),this.requestUpdate()}async _applyTheme(e){if(this.values.setValue("theme",e),"default"===e){for(const e of Mi){const t=Pi[e.id];t.originalDefault&&(t.default=t.originalDefault),this.values.setValue(t.id,t.default)}return this.setUrlParams(),void this.requestUpdate()}for(const e of Mi){const t=Pi[e.id];this.values.setValue(t.id,t.default)}this.requestUpdate(),await this.updateComplete;const t=window.getComputedStyle(this._ide);for(const e of Mi){const r=Pi[e.id];if(!r.cssProperty)continue;const o=t.getPropertyValue(r.cssProperty),i=sn(o);this.values.setValue(r.id,i),r.default=i}}readUrlParams(e){const t=new Map;for(const r of Ui){const o=e.get(r);if(null===o)continue;const i=Pi[r];switch(i.type){case"checkbox":t.set(i.id,"y"===o);break;case"color":t.set(i.id,"#"+o);break;case"slider":t.set(i.id,Number(o));break;case"select":t.set(i.id,o);break;default:an(0,"Unexpected knob type "+i.type)}}this.setValues(t)}setUrlParams(){const e=new URLSearchParams;for(const t of Di){const r=this.values.getValue(t.id);if(r!==t.default)switch(t.type){case"checkbox":e.set(t.id,r?"y":"n");break;case"color":e.set(t.id,r.substring(1));break;case"slider":e.set(t.id,r+"");break;case"select":e.set(t.id,r);break;default:an(0,"Unexpected knob type "+t.type)}}history.replaceState(null,"","?"+e.toString())}render(){return W` + + + + ${this._themeDetectorOpen?W``:j} + + +
${this.knobs}
+ +
+
+ + + + ${ln} +
+ +
+
+

CSS

+ + +
+ +
+

HTML

+ + +
+
+
+ `}get knobs(){return Bi.map((e=>W`
+ +
+ ${Hi[e].map((e=>this.knob(e)))} +
+
`))}get htmlText(){return`${this.themeImport}\n\n\n`}get themeImport(){const e=this.values.getValue("theme");return"default"===e?"":`\n`}get htmlTextAttributes(){const e=[];for(const t of Ui){const r=Pi[t];if(!r.htmlAttribute)continue;const o=this.values.getValue(t);o!==r.default&&("checkbox"===r.type?o&&e.push("\n "+r.htmlAttribute):e.push(`\n ${r.htmlAttribute}="${o}"`))}const t=this.values.getValue("theme");return"default"!==t&&e.push(`\n class="playground-theme-${t}"`),e.join("")}get cssText(){const e=[];for(const t of Ui){const r=Pi[t];if(!r.cssProperty)continue;const o=this.values.getValue(t);let i=`${r.cssProperty}: ${r.formatCss?r.formatCss(o):o};`;o!==r.default&&(i=" "+i,e.push(i))}return`\n#playground {\n${e.join("\n")}\n}\n `}knob(e){let t;switch(e.type){case"select":t=this.selectKnob(e);break;case"slider":t=this.sliderKnob(e);break;case"color":t=this.colorKnob(e);break;case"checkbox":t=this.checkboxKnob(e)}if(!t)return j;const r=W``;if("theme"===e.id){const e=W``;return[r,t,W``,e]}return[r,t]}selectKnob(e){const t=this.values.getValue(e.id);return W` + + `}sliderKnob(e){const t=this.values.getValue(e.id);return W` + + {this.setValue(e.id,Number(t.target.value))}} + /> + ${e.formatCss?e.formatCss(t):t} + + `}colorKnob(e){let t=this.values.getValue(e.id);return W` + ${"unsetLabel"in e?W` +
+ {t=r.target.checked?"":"#ffffff",this.setValue(e.id,t)}} + /> + +
+ + `:""} + {this.setValue(e.id,t.target.value)}} + /> + `}checkboxKnob(e){const t=this.values.getValue(e.id);return W` + {this.setValue(e.id,t.target.checked)}} + /> + `}_openThemeDetector(){this._themeDetectorOpen=!0}_closeThemeDetector(){this._themeDetectorOpen=!1}async _onThemeDetectorApply(e){const t=new Map;t.set("theme","default");const r=new Map;for(const[t,o]of e.detail.properties)r.set(t,o?sn(o):void 0);const o=Pi.synDefault,i=r.get(o.cssProperty)||o.default;for(const e of Di)if(e.cssProperty&&r.has(e.cssProperty)){const o=r.get(e.cssProperty)||i;t.set(e.id,o)}this.setValues(t),this._closeThemeDetector()}};function an(e,t){throw Error(t)}nn.styles=[...Li,c` + :host { + display: flex; + font-family: Roboto, Arial, Helvetica, sans-serif; + } + + #lhs { + overflow-y: auto; + width: 300px; + border-right: 1px solid #ccc; + box-shadow: -2px 0 6px 0px rgb(0 0 0 / 50%); + z-index: 1; + color: #424242; + font-size: 13px; + } + + #rhs { + display: flex; + flex-direction: column; + flex: 1; + overflow: auto; + } + + #container { + display: flex; + justify-content: center; + align-items: center; + flex: 1; + /* To position the GitHub cat corner. */ + position: relative; + } + + playground-ide { + flex: 1; + margin: 50px; + max-width: 900px; + } + + #code { + display: flex; + flex-wrap: wrap; + border-top: 1px solid #ccc; + height: 30%; + overflow-y: auto; + padding: 10px; + --playground-code-font-family: 'Roboto Mono', monospace; + --playground-code-font-size: 12px; + --playground-code-background: transparent; + background-color: #f7f7f7; + } + + #code > div { + min-width: 50%; + } + + h3 { + color: #949494; + font-weight: 400; + text-transform: uppercase; + } + + #code h3 { + margin: 0; + } + + #lhs section { + padding: 15px; + border-bottom: 1px solid #ccc; + } + + .sectionLabel { + margin-top: 5px; + } + + .knobs { + display: grid; + grid-template-columns: repeat(4, 1fr); + row-gap: 15px; + column-gap: 10px; + align-items: center; + } + + input[type='color'] { + width: 30px; + } + + .knobs label { + text-align: right; + cursor: pointer; + } + + #container { + flex: 1; + } + + .knobs select { + grid-column: 2 / -1; + } + + .sliderAndValue { + display: flex; + align-items: center; + grid-column: 2 / -1; + } + + .sliderValue { + margin-left: 5px; + } + + #openDetectorButton { + background: #0075ff; + opacity: 0.8; + color: white; + padding: 5px; + border: none; + border-radius: 2px; + cursor: pointer; + font-size: 14px; + grid-column-start: 2; + grid-column-end: -1; + } + + #openDetectorButton:hover { + opacity: 1; + } + `],o([me()],nn.prototype,"_themeDetectorOpen",void 0),o([ye("playground-ide")],nn.prototype,"_ide",void 0),nn=o([ue("playground-configurator")],nn);const ln=W``,sn=e=>{const t=e.match(/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/);if(!t)return"";const[,r,o,i]=t,n=e=>Number(e).toString(16).padStart(2,"0");return`#${n(r)}${n(o)}${n(i)}`};export{nn as PlaygroundConfigurator}; diff --git a/playground-service-worker-proxy.html b/playground-service-worker-proxy.html new file mode 100644 index 00000000..91117701 --- /dev/null +++ b/playground-service-worker-proxy.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/playground-service-worker.js b/playground-service-worker.js new file mode 100644 index 00000000..3b45bd00 --- /dev/null +++ b/playground-service-worker.js @@ -0,0 +1,23 @@ +!function(){ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +const e=Symbol("Comlink.proxy"),t=Symbol("Comlink.endpoint"),n=Symbol("Comlink.releaseProxy"),s=Symbol("Comlink.finalizer"),r=Symbol("Comlink.thrown"),a=e=>"object"==typeof e&&null!==e||"function"==typeof e,i=new Map([["proxy",{canHandle:t=>a(t)&&t[e],serialize(e){const{port1:t,port2:n}=new MessageChannel;return o(e,t),[n,[n]]},deserialize:e=>(e.start(),f(e,[],undefined))}],["throw",{canHandle:e=>a(e)&&r in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(Error(e.value.message),e.value);throw e.value}}]]);function o(t,n=globalThis,a=["*"]){n.addEventListener("message",(function i(l){if(!l||!l.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(a,l.origin))return void console.warn(`Invalid origin '${l.origin}' for comlink proxy`);const{id:u,type:p,path:d}=Object.assign({path:[]},l.data),f=(l.data.argumentList||[]).map(v);let g;try{const n=d.slice(0,-1).reduce(((e,t)=>e[t]),t),s=d.reduce(((e,t)=>e[t]),t);switch(p){case"GET":g=s;break;case"SET":n[d.slice(-1)[0]]=v(l.data.value),g=!0;break;case"APPLY":g=s.apply(n,f);break;case"CONSTRUCT":g=function(t){return Object.assign(t,{[e]:!0})}(new s(...f));break;case"ENDPOINT":{const{port1:e,port2:n}=new MessageChannel;o(t,n),g=function(e,t){return h.set(e,t),e}(e,[e])}break;case"RELEASE":g=void 0;break;default:return}}catch(e){g={value:e,[r]:0}}Promise.resolve(g).catch((e=>({value:e,[r]:0}))).then((e=>{const[r,a]=m(e);n.postMessage(Object.assign(Object.assign({},r),{id:u}),a),"RELEASE"===p&&(n.removeEventListener("message",i),c(n),s in t&&"function"==typeof t[s]&&t[s]())})).catch((e=>{const[t,s]=m({value:new TypeError("Unserializable return value"),[r]:0});n.postMessage(Object.assign(Object.assign({},t),{id:u}),s)}))})),n.start&&n.start()}function c(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function l(e){if(e)throw Error("Proxy has been released and is not useable")}function u(e){return y(e,{type:"RELEASE"}).then((()=>{c(e)}))}const p=new WeakMap,d="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(p.get(e)||0)-1;p.set(e,t),0===t&&u(e)}));function f(e,s=[],r=function(){}){let a=!1;const i=new Proxy(r,{get(t,r){if(l(a),r===n)return()=>{!function(e){d&&d.unregister(e)}(i),u(e),a=!0};if("then"===r){if(0===s.length)return{then:()=>i};const t=y(e,{type:"GET",path:s.map((e=>e.toString()))}).then(v);return t.then.bind(t)}return f(e,[...s,r])},set(t,n,r){l(a);const[i,o]=m(r);return y(e,{type:"SET",path:[...s,n].map((e=>e.toString())),value:i},o).then(v)},apply(n,r,i){l(a);const o=s[s.length-1];if(o===t)return y(e,{type:"ENDPOINT"}).then(v);if("bind"===o)return f(e,s.slice(0,-1));const[c,u]=g(i);return y(e,{type:"APPLY",path:s.map((e=>e.toString())),argumentList:c},u).then(v)},construct(t,n){l(a);const[r,i]=g(n);return y(e,{type:"CONSTRUCT",path:s.map((e=>e.toString())),argumentList:r},i).then(v)}});return function(e,t){const n=(p.get(t)||0)+1;p.set(t,n),d&&d.register(e,t,e)}(i,e),i}function g(e){const t=e.map(m);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const h=new WeakMap;function m(e){for(const[t,n]of i)if(n.canHandle(e)){const[s,r]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},r]}return[{type:"RAW",value:e},h.get(e)||[]]}function v(e){switch(e.type){case"HANDLER":return i.get(e.name).deserialize(e.value);case"RAW":return e.value}}function y(e,t,n){return new Promise((s=>{const r=[,,,,].fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");e.addEventListener("message",(function t(n){n.data&&n.data.id&&n.data.id===r&&(e.removeEventListener("message",t),s(n.data))})),e.start&&e.start(),e.postMessage(Object.assign({id:r},t),n)}))} +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +class E{constructor(){this.settled=!1,this.promise=new Promise(((e,t)=>{this._resolve=e,this._reject=t}))}resolve(e){this.settled=!0,this._resolve(e)}reject(e){this.settled=!0,this._reject(e)}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const w=new Map,b={setFileAPI(e,t){let n=w.get(t);(void 0===n||n.settled)&&(n=new E,w.set(t,n)),n.resolve(e)}}; +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */self.addEventListener("fetch",(e=>{const t=e.request.url;if(t.startsWith(self.registration.scope)){const{filePath:n,sessionId:s}=(e=>{const t=self.registration.scope,n=e.substring(t.length).split("?")[0],s=n.indexOf("/");let r,a;return-1===s?console.warn("Invalid sample file URL: "+e):(r=n.slice(0,s),a=n.slice(s+1)),{sessionId:r,filePath:a}})(t);void 0!==s&&e.respondWith((async(e,t,n)=>{const s=await(async e=>{let t=w.get(e);if(void 0!==t)return t.promise;const n=await(async e=>{for(const t of await self.clients.matchAll({includeUncontrolled:!0})){const n=new URL(t.url).hash;if(new URLSearchParams(n.slice(1)).get("playground-session-id")===e)return t}})(e);if(void 0===n)return;return t=new E,w.set(e,t),n.postMessage({type:5}),t.promise})(n);if(void 0===s)return new Response("Playground project not available",{status:503});const r=await s.getFile(t);if("status"in r){const{body:e,status:t}=r;return new Response(e,{status:t})}const{content:a,contentType:i}=r,o=new Headers;return o.set("Origin-Agent-Cluster","?1"),i&&o.set("Content-Type",i),new Response(a,{headers:o})})(0,n,s))}})),self.addEventListener("activate",(e=>{e.waitUntil(self.clients.claim())})),self.addEventListener("install",(()=>{self.skipWaiting()})),self.addEventListener("message",(e=>{if(2===e.data.type){const t={type:4,version:"09cd6a4e"};e.data.port.postMessage(t),o(b,e.data.port)}}))}(); diff --git a/playground-typescript-worker.js b/playground-typescript-worker.js new file mode 100644 index 00000000..b8fb4a38 --- /dev/null +++ b/playground-typescript-worker.js @@ -0,0 +1,87 @@ +import A from"./internal/typescript.js"; +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */const e=Symbol("Comlink.proxy"),t=Symbol("Comlink.endpoint"),n=Symbol("Comlink.releaseProxy"),i=Symbol("Comlink.finalizer"),o=Symbol("Comlink.thrown"),s=A=>"object"==typeof A&&null!==A||"function"==typeof A,r=new Map([["proxy",{canHandle:A=>s(A)&&A[e],serialize(A){const{port1:e,port2:t}=new MessageChannel;return Q(A,e),[t,[t]]},deserialize:A=>(A.start(),c(A,[],undefined))}],["throw",{canHandle:A=>s(A)&&o in A,serialize({value:A}){let e;return e=A instanceof Error?{isError:!0,value:{message:A.message,name:A.name,stack:A.stack}}:{isError:!1,value:A},[e,[]]},deserialize(A){if(A.isError)throw Object.assign(Error(A.value.message),A.value);throw A.value}}]]);function Q(A,t=globalThis,n=["*"]){t.addEventListener("message",(function s(r){if(!r||!r.data)return;if(!function(A,e){for(const t of A){if(e===t||"*"===t)return!0;if(t instanceof RegExp&&t.test(e))return!0}return!1}(n,r.origin))return void console.warn(`Invalid origin '${r.origin}' for comlink proxy`);const{id:g,type:C,path:B}=Object.assign({path:[]},r.data),E=(r.data.argumentList||[]).map(h);let c;try{const t=B.slice(0,-1).reduce(((A,e)=>A[e]),A),n=B.reduce(((A,e)=>A[e]),A);switch(C){case"GET":c=n;break;case"SET":t[B.slice(-1)[0]]=h(r.data.value),c=!0;break;case"APPLY":c=n.apply(t,E);break;case"CONSTRUCT":c=function(A){return Object.assign(A,{[e]:!0})}(new n(...E));break;case"ENDPOINT":{const{port1:e,port2:t}=new MessageChannel;Q(A,t),c=function(A,e){return d.set(A,e),A}(e,[e])}break;case"RELEASE":c=void 0;break;default:return}}catch(A){c={value:A,[o]:0}}Promise.resolve(c).catch((A=>({value:A,[o]:0}))).then((e=>{const[n,o]=p(e);t.postMessage(Object.assign(Object.assign({},n),{id:g}),o),"RELEASE"===C&&(t.removeEventListener("message",s),a(t),i in A&&"function"==typeof A[i]&&A[i]())})).catch((A=>{const[e,n]=p({value:new TypeError("Unserializable return value"),[o]:0});t.postMessage(Object.assign(Object.assign({},e),{id:g}),n)}))})),t.start&&t.start()}function a(A){(function(A){return"MessagePort"===A.constructor.name})(A)&&A.close()}function g(A){if(A)throw Error("Proxy has been released and is not useable")}function C(A){return f(A,{type:"RELEASE"}).then((()=>{a(A)}))}const B=new WeakMap,E="FinalizationRegistry"in globalThis&&new FinalizationRegistry((A=>{const e=(B.get(A)||0)-1;B.set(A,e),0===e&&C(A)}));function c(A,e=[],i=function(){}){let o=!1;const s=new Proxy(i,{get(t,i){if(g(o),i===n)return()=>{!function(A){E&&E.unregister(A)}(s),C(A),o=!0};if("then"===i){if(0===e.length)return{then:()=>s};const t=f(A,{type:"GET",path:e.map((A=>A.toString()))}).then(h);return t.then.bind(t)}return c(A,[...e,i])},set(t,n,i){g(o);const[s,r]=p(i);return f(A,{type:"SET",path:[...e,n].map((A=>A.toString())),value:s},r).then(h)},apply(n,i,s){g(o);const r=e[e.length-1];if(r===t)return f(A,{type:"ENDPOINT"}).then(h);if("bind"===r)return c(A,e.slice(0,-1));const[Q,a]=l(s);return f(A,{type:"APPLY",path:e.map((A=>A.toString())),argumentList:Q},a).then(h)},construct(t,n){g(o);const[i,s]=l(n);return f(A,{type:"CONSTRUCT",path:e.map((A=>A.toString())),argumentList:i},s).then(h)}});return function(A,e){const t=(B.get(e)||0)+1;B.set(e,t),E&&E.register(A,e,A)}(s,A),s}function l(A){const e=A.map(p);return[e.map((A=>A[0])),(t=e.map((A=>A[1])),Array.prototype.concat.apply([],t))];var t}const d=new WeakMap;function p(A){for(const[e,t]of r)if(t.canHandle(A)){const[n,i]=t.serialize(A);return[{type:"HANDLER",name:e,value:n},i]}return[{type:"RAW",value:A},d.get(A)||[]]}function h(A){switch(A.type){case"HANDLER":return r.get(A.name).deserialize(A.value);case"RAW":return A.value}}function f(A,e,t){return new Promise((n=>{const i=[,,,,].fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");A.addEventListener("message",(function e(t){t.data&&t.data.id&&t.data.id===i&&(A.removeEventListener("message",e),n(t.data))})),A.start&&A.start(),A.postMessage(Object.assign({id:i},e),t)}))}const u=1===new Uint8Array(new Uint16Array([1]).buffer)[0];function I(A,e="@"){if(!v)return m.then((()=>I(A)));const t=A.length+1,n=(v.__heap_base.value||v.__heap_base)+4*t-v.memory.buffer.byteLength;n>0&&v.memory.grow(Math.ceil(n/65536));const i=v.sa(t-1);if((u?w:k)(A,new Uint16Array(v.memory.buffer,i,t)),!v.parse())throw Object.assign(Error(`Parse error ${e}:${A.slice(0,v.e()).split("\n").length}:${v.e()-A.lastIndexOf("\n",v.e()-1)}`),{idx:v.e()});const o=[],s=[];for(;v.ri();){const e=v.is(),t=v.ie(),n=v.ai(),i=v.id(),s=v.ss(),Q=v.se();let a;v.ip()&&(a=r(A.slice(-1===i?e-1:e,-1===i?t+1:t))),o.push({n:a,s:e,e:t,ss:s,se:Q,d:i,a:n})}for(;v.re();){const e=v.es(),t=v.ee(),n=v.els(),i=v.ele(),o=A.slice(e,t),Q=o[0],a=n<0?void 0:A.slice(n,i),g=a?a[0]:"";s.push({s:e,e:t,ls:n,le:i,n:'"'===Q||"'"===Q?r(o):o,ln:'"'===g||"'"===g?r(a):a})}function r(A){try{return(0,eval)(A)}catch(A){}}return[o,s,!!v.f(),!!v.ms()]}function k(A,e){const t=A.length;let n=0;for(;n>>8}}function w(A,e){const t=A.length;let n=0;for(;nA.charCodeAt(0))))).then(WebAssembly.instantiate).then((({exports:A})=>{v=A}));var K; +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */class D{constructor(){this._buffer=[],this._numSources=0,this._done=!1}async*[Symbol.asyncIterator](){for(;this._numSources>0;){for(;this._buffer.length>0;){const{value:A,emitted:e}=this._buffer.shift();yield A,e()}await new Promise((A=>this._notify=A)),this._notify=void 0}this._done=!0}add(A){if(this._done)throw Error("Merged iterator is exhausted. Cannot add new source iterators.");this._numSources++,(async()=>{var e;for await(const e of A)await new Promise((A=>{var t;this._buffer.push({value:e,emitted:A}),null===(t=this._notify)||void 0===t||t.call(this)}));this._numSources--,null===(e=this._notify)||void 0===e||e.call(this)})()}}const y=(A,e)=>new URL(e,new URL(A,"ws://_")).pathname,N=A=>{try{return new URL(A).href,"url"}catch{}return null!==A.match(/^(\.){0,2}\//)?"relative":"bare"},J=A=>{const e=A.match(/^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?\/?(.*)$/);if(null===e)return;const[,t,n,i]=e;return{pkg:t,version:null!=n?n:"",path:i}},L=A=>{const e=A.lastIndexOf("/"),t=A.lastIndexOf(".");return-1===t||t{const t=L(A);return""===t?A+"."+e:A.slice(0,-t.length)+e},S=(A,e)=>{let t=0,n=0;for(let i=0;inull!==A.match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/),U=({pkg:A,version:e})=>`${A}@${e||"latest"}`,_=({pkg:A,version:e,path:t})=>q(`${U({pkg:A,version:e})}/${M(t)}`),M=A=>A.startsWith("/")?A.slice(1):A,q=A=>A.endsWith("/")?A.slice(0,-1):A +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */;class Y{constructor(){this.settled=!1,this.promise=new Promise(((A,e)=>{this._resolve=A,this._reject=e}))}resolve(A){this.settled=!0,this._resolve(A)}reject(A){this.settled=!0,this._reject(A)}} +/** + * @license + * Copyright 2016 Node.js contributors. All rights reserved. + * SPDX-License-Identifier: MIT + */function G(A){if("string"==typeof A&&(A=new URL(A)),"file:"!==A.protocol)throw Error("The URL must be of scheme file");return A.pathname} +/** + * @license + * Copyright 2017 Node.js contributors. All rights reserved. + * SPDX-License-Identifier: MIT + */class b extends Error{constructor(A,e,t){super(`Invalid module "${A}" ${e}${t?" imported from "+t:""}`)}}class x extends Error{constructor(A,e,t){super(`Invalid package config ${A}${e?" while importing "+e:""}${t?". "+t:""}`)}}class j extends Error{constructor(A,e,t,n=!1,i){const o="string"==typeof t&&!n&&t.length&&!t.startsWith("./");let s;s="."===e?`Invalid "exports" main target ${JSON.stringify(t)} defined in the package config ${G(A)}package.json${i?" imported from "+i:""}${o?'; targets must start with "./"':""}`:`Invalid "${n?"imports":"exports"}" target ${JSON.stringify(t)} defined for '${e}' in the package config ${G(A)}package.json${i?" imported from "+i:""}${o?'; targets must start with "./"':""}`,super(s)}}class P extends Error{constructor(A,e,t){super("."===e?`No "exports" main defined in ${A}package.json${t?" imported from "+t:""}`:`Package subpath '${e}' is not defined by "exports" in ${A}package.json${t?" imported from "+t:""}`)}} +/** + * @license + * Copyright 2020 Node.js contributors. All rights reserved. + * SPDX-License-Identifier: MIT + */function H(A,e,t){return new P(G(new URL(".",e)),A,t)}function $(A,e,t,n,i){return e="object"==typeof e&&null!==e?JSON.stringify(e,null,""):""+e,new j(t,A,e,n,i)}const O=/(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/,T=/\*/g;function X(A){const e=+A;return""+e===A&&e>=0&&e<4294967295}function W(A,e,t,n,i,o,s,r){if("string"==typeof e)return function(A,e,t,n,i,o,s,r){if(""!==e&&!o&&"/"!==A[A.length-1])throw $(t,A,n,s,i);if(!A.startsWith("./"))throw $(t,A,n,s,i);if(O.test(A.slice(2)))throw $(t,A,n,s,i);const Q=new URL(A,n),a=Q.pathname,g=new URL(".",n).pathname;if(!a.startsWith(g))throw $(t,A,n,s,i);if(""===e)return Q;if(O.test(e))throw function(A,e,t,n){const i=`request is not a valid subpath for the "${t?"imports":"exports"}" resolution of ${G(e)}`;return new b(A,i,n)}(t+e,n,s,i);return o?new URL(Q.href.replace(T,e)):new URL(e,Q)}(e,t,n,A,i,o,s);if(Array.isArray(e)){if(0===e.length)return null;let Q;for(let a=0;ao?-1:o>i||-1===t?1:-1===n||A.length>e.length?-1:e.length>A.length?1:0} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */class V{constructor({conditions:A}){this._conditions=new Set(A)}resolve(A,e,t){const n=z(A.path);if(void 0===e.exports)return"."===n?void 0!==e.module?AA(e.module):void 0!==e.main?AA(e.main):"index.js":A.path;const i=`/node_modules/${A.pkg}@${A.version}/`,o=function(A,e,t,n,i){let o=t.exports;if(function(A,e,t){if("string"==typeof A||Array.isArray(A))return!0;if("object"!=typeof A||null===A)return!1;const n=Object.getOwnPropertyNames(A);let i=!1,o=0;for(let A=0;A=A.length&&e.endsWith(n)&&1===Z(r,A)&&A.lastIndexOf("*")===t&&(r=A,s=e.slice(t,e.length-n.length))}else A.endsWith("/")&&e.startsWith(A)&&1===Z(r,A)&&(r=A,s=e.slice(A.length))}if(r){const t=o[r],Q=r.includes("*"),a=W(A,t,s,r,n,Q,!1,i);if(null==a)throw H(e,A,n);return Q||function(A,e,t,n){const i=G(e);console.warn(`Use of deprecated folder mapping "${A}" in the "exports" field module resolution of the package at ${i}${n?" imported from "+n:""}.\nUpdate this package.json to use a subpath pattern like "${A}*".`,"DeprecationWarning","DEP0148")}(r,A,0,n),a}throw H(e,A,n)}(new URL(i,"file://"),n,e,t,this._conditions);if(!o.pathname.startsWith(i))throw Error(`Unexpected error: ${o.pathname} expected to start with ${i}`);return o.pathname.slice(i.length)}}const z=A=>""===A?".":A.startsWith(".")||A.startsWith("/")?A:"./"+A,AA=A=>"."===A?"":A.startsWith("./")?A.slice(2):A; +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ +class eA{constructor(A,e){this._emittedExternalDependencies=new Set,this._nodeResolver=new V({conditions:["module","import","development","browser"]}),this._cdn=A,this._importMapResolver=e}async*process(A){const e=new D;e.add(this._handleProjectFiles(A,e)),yield*e}async*_handleProjectFiles(A,e){const t=new Y,n=()=>t.promise;for await(const i of A)if("file"===i.kind&&i.file.name.endsWith(".js"))e.add(this._handleModule(i,n,e));else if(yield i,"file"===i.kind&&"package.json"===i.file.name){let A;try{A=JSON.parse(i.file.content)}catch(A){yield nA(A,i.file)}void 0!==A&&t.resolve(A)}t.settled||t.resolve(void 0)}async*_handleModule(A,e,t){let n,i=A.file.content;await m;try{[n]=I(i)}catch(e){yield A;const t=tA(e,A.file.name);return void(void 0!==t&&(yield t))}const o=[];for(let i=n.length-1;i>=0;i--){const{n:s}=n[i];void 0!==s&&o.push({info:n[i],newSpecifierPromise:this._handleSpecifier(s,A.file.name,e,t)})}for(const{info:{s:e,e:t,n,d:s},newSpecifierPromise:r}of o){let o;try{o=await r}catch(o){yield{kind:"diagnostic",filename:A.file.name,diagnostic:{message:`Could not resolve module "${n}": ${o.message}`,range:{start:S(i,e),end:S(i,t)}}};continue}if(o===n)continue;const Q=-1!==s?`'${o}'`:o;i=i.substring(0,e)+Q+i.substring(t)}A.file.content=i,yield A}async _handleSpecifier(A,e,t,n){const i=this._importMapResolver.resolve(A);if(null!==i)return i;const o=N(A);if("url"===o)return A;if("bare"===o)return this._handleBareSpecifier(A,e,t,n);if(!e.startsWith("node_modules/"))return A;const s=y(e,A).slice(14);if(!L(A))return this._handleBareSpecifier(s,e,(async()=>{}),n);const r=J(s);if(void 0===r)throw Error(`Invalid specifier "${s}"`);return n.add(this._fetchExternalDependency(r,n)),A}async _handleBareSpecifier(A,e,t,n){var i,o,s;let r=J(A);if(void 0===r)throw Error(`Invalid specifier "${A}"`);r.version||(r.version=null!==(s=null===(o=null===(i=await t())||void 0===i?void 0:i.dependencies)||void 0===o?void 0:o[r.pkg])&&void 0!==s?s:"latest"),r.version=await this._cdn.resolveVersion(r);const Q=await this._cdn.fetchPackageJson(r);return r.path=this._nodeResolver.resolve(r,Q,e),L(r.path)||(r=await this._cdn.canonicalize(r)),n.add(this._fetchExternalDependency(r,n)),((A,e)=>{const t=A.split("/"),n=e.split("/");let i=0;for(;i{if(null===i)try{i=await this._cdn.fetchPackageJson(A)}catch{i=void 0}return i}),e)}}const tA=(A,e)=>{const t=A.message.match(/@:(\d+):(\d+)$/);if(null===t)return;const n=Number(t[1])-1,i=Number(t[2])-1;return{kind:"diagnostic",filename:e,diagnostic:{message:"es-module-lexer error: "+A.message,range:{start:{line:n,character:i},end:{line:n,character:i+1}}}}},nA=(A,e)=>{var t;const n=null!==(t=iA(A.message,e.content))&&void 0!==t?t:{line:0,character:0};return{kind:"diagnostic",filename:e.name,diagnostic:{message:"Invalid package.json: "+A,range:{start:n,end:S(e.content,e.content.length)}}}},iA=(A,e)=>{const t=A.match(/at position (\d+)/);if(null!==t)return S(e,Number(t[1]));const n=A.match(/at line (\d+) column (\d+)/);return null!==n?{line:Number(n[1])-1,character:Number(n[2])-1}:void 0},oA={target:A.ScriptTarget.ES2021,module:A.ModuleKind.ESNext,experimentalDecorators:!0,skipDefaultLibCheck:!0,skipLibCheck:!0,allowJs:!0,moduleResolution:A.ModuleResolutionKind.NodeNext,jsx:A.JsxEmit.React,lib:["dom","esnext"]};class sA{constructor(){this.compilerOptions=oA,this.serviceHost=new rA(self.origin,oA),this.service=A.createLanguageService(this.serviceHost,A.createDocumentRegistry())}}class rA{constructor(A,e){this.files=new Map,this.packageRoot=A,this.compilerOptions=e}updateFileContentIfNeeded(A,e){const t=this.files.get(A);t&&t.content!==e?(t.content=e,t.version+=1):this.files.set(A,{content:e,version:0})}sync(A){A.forEach(((A,e)=>this.updateFileContentIfNeeded(e,A))),this._removeDeletedFiles(A)}_removeDeletedFiles(A){this.getScriptFileNames().forEach((e=>{e.includes("node_modules")||A.has(e)||this.files.delete(e)}))}getCompilationSettings(){return this.compilerOptions}getScriptFileNames(){return[...this.files.keys()]}getScriptVersion(A){var e,t;return null!==(t=null===(e=this.files.get(A))||void 0===e?void 0:e.version.toString())&&void 0!==t?t:"-1"}fileExists(A){return this.files.has(A)}readFile(A){var e;return null===(e=this.files.get(A))||void 0===e?void 0:e.content}getScriptSnapshot(e){if(this.fileExists(e))return A.ScriptSnapshot.fromString(this.readFile(e))}getCurrentDirectory(){return this.packageRoot}getDefaultLibFileName(){return"__lib.d.ts"}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */class QA{constructor(A){this._fetchCache=new Map,this._versionCache=new Map,this._urlPrefix=A}async fetch(A){const{file:e}=await this._fetch(A);return e}async canonicalize(A){let e=R(A.version);if(!e){const t=U(A),n=this._versionCache.get(t);void 0!==n&&(A={...A,version:n},e=!0)}if(!e||""===L(A.path)){const{url:e}=await this._fetch(A);A=this._parseUnpkgUrl(e)}return A}async resolveVersion({pkg:A,version:e}){return(await this.canonicalize({pkg:A,version:e,path:"package.json"})).version}async fetchPackageJson({pkg:A,version:e}){const{url:t,file:{content:n}}=await this._fetch({pkg:A,version:e,path:"package.json"});try{return JSON.parse(n)}catch(A){throw Error(`Error parsing CDN package.json from ${t}: ${A}`)}}async _fetch(A){var e;let t=R(A.version);if(!t){const e=U(A),n=this._versionCache.get(e);void 0!==n&&(A={...A,version:n},t=!0)}const n=_(A),i=this._fetchCache.get(n);if(void 0!==i)return i.promise;const o=new Y;this._fetchCache.set(n,o);const s=this._urlPrefix+n,r=await fetch(s),Q=await r.text();if(200!==r.status){const A=Error(`CDN HTTP ${r.status} error (${s}): ${Q}`);return o.reject(A),o.promise}if(!t){const e=this._parseUnpkgUrl(r.url);this._versionCache.set(U(A),e.version),this._fetchCache.set(_(e),o)}const a={url:r.url,file:{content:Q,contentType:null!==(e=r.headers.get("content-type"))&&void 0!==e?e:"text/plain"}};return o.resolve(a),o.promise}_parseUnpkgUrl(A){if(A.startsWith(this._urlPrefix)){const e=J(A.slice(this._urlPrefix.length));if(void 0!==e)return e}throw Error("Unexpected CDN URL format: "+A)}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */class aA{constructor(A){this.importMap=A}resolve(A){var e;for(const[t,n]of Object.entries(null!==(e=this.importMap.imports)&&void 0!==e?e:{})){if(t===A)return n;if(t.endsWith("/")&&A.startsWith(t)){if(!n.endsWith("/"))return console.warn(`Could not resolve module specifier "${A}" using import map key "${t}" because address "${n}" must end in a forward-slash.`),null;const e=A.substring(t.length);let i;try{i=new URL(e,n)}catch{return console.warn(`Could not resolve module specifier "${A}" using import map key "${t}" because "${e}" could not be parsed relative to "${n}".`),null}const o=i.href;return o.startsWith(n)?o:(console.warn(`Could not resolve module specifier "${A}" using import map key "${t}" because "${e}" backtracked above "${n}".`),null)}}return null}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */let gA,CA="";function BA(A){const e=JSON.stringify(A);return gA&&CA===e||(CA=e,gA=new EA(A)),gA}class EA{constructor(A){var e;this.importMapResolver=new aA(A.importMap),this.cdn=new QA(null!==(e=A.cdnBaseUrl)&&void 0!==e?e:"https://unpkg.com/"),this.languageServiceContext=new sA}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */class cA{layout(A,e){var t,n;const i={},o=[{dependencies:A,nodeModules:i,parent:null}];for(;o.length>0;){const A=o.shift();for(const[i,s]of Object.entries(A.dependencies)){let r=A,Q=!1;for(;null!==r.parent;){const A=null===(t=r.parent.nodeModules[i])||void 0===t?void 0:t.version;if(void 0!==A){Q=A===s;break}r=r.parent}if(Q)continue;const a={};r.nodeModules[i]={version:s,nodeModules:a};const g=null===(n=e[i])||void 0===n?void 0:n[s];void 0!==g&&o.push({dependencies:g,nodeModules:a,parent:r})}}return i}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const lA=Symbol();class dA{static async fetchTypes(A,e,t,n,i){const o=new dA(A,e,t);await Promise.allSettled([...n.map((A=>o._handleBareAndRelativeSpecifiers(A,lA))),...i.map((A=>o._addTypeScriptStandardLib(A))),o._fetchTypesPackages()]);const s=(new cA).layout(o._rootDependencies,o._dependencyGraph),r=new Map;return await o._materializeNodeModulesTree(s,r,""),{files:r,layout:s,dependencyGraph:{root:o._rootDependencies,deps:o._dependencyGraph}}}constructor(A,e,t){this._rootDependencies={},this._dependencyGraph={},this._filesByPackageVersion=new Map,this._cdn=A,this._importMapResolver=e,this._rootPackageJson=t}async _fetchTypesPackages(){if(void 0===this._rootPackageJson||void 0===this._rootPackageJson.dependencies)return;const A=Object.keys(this._rootPackageJson.dependencies).filter((A=>A.startsWith("@types/")));0!==A.length&&await Promise.allSettled(A.map((A=>this._handleBareSpecifier(A,lA))))}async _addTypeScriptStandardLib(A){return this._handleBareSpecifier(`typescript/lib/lib.${A.toLowerCase()}.js`,lA)}async _handleBareAndRelativeSpecifiers(e,t){const n=A.preProcessFile(e,void 0,!0),i=[];for(const{fileName:A}of n.importedFiles){const e=N(A);"bare"===e?i.push(this._handleBareSpecifier(A,t)):"relative"===e&&t!==lA&&i.push(this._handleRelativeSpecifier(A,t))}for(const{fileName:A}of n.libReferenceDirectives)i.push(this._addTypeScriptStandardLib(A));await Promise.allSettled(i)}async _handleBareSpecifier(A,e){var t,n;let i=J(A);if(void 0===i)return;const o=null!==this._importMapResolver.resolve(A);if(o||(i.version=await this._getDependencyVersion(e,i.pkg)),i.path=await this._getDtsPath(i),o||(i=await this._cdn.canonicalize(i)),e!==lA&&i.pkg===e.pkg||this._addEdgeToDependencyGraph(e,i),void 0!==(null===(n=null===(t=this._filesByPackageVersion.get(i.pkg))||void 0===t?void 0:t.get(i.version))||void 0===n?void 0:n.get(i.path)))return;const s=await this._fetchAndAddToOutputFiles(i);void 0===s.error&&await this._handleBareAndRelativeSpecifiers(s.result,i)}async _handleRelativeSpecifier(A,e){var t,n;const i={pkg:e.pkg,version:e.version,path:M(y(e.path,A).slice(1))};if(i.path=F(i.path,"d.ts"),void 0!==(null===(n=null===(t=this._filesByPackageVersion.get(i.pkg))||void 0===t?void 0:t.get(i.version))||void 0===n?void 0:n.get(i.path)))return;const o=await this._fetchAndAddToOutputFiles(i);void 0===o.error&&await this._handleBareAndRelativeSpecifiers(o.result,i)}async _getDependencyVersion(A,e){var t,n;const i=A===lA?this._rootPackageJson:await this._fetchPackageJsonAndAddToOutputFiles(A);return null!==(n=null===(t=null==i?void 0:i.dependencies)||void 0===t?void 0:t[e])&&void 0!==n?n:"latest"}async _getDtsPath(A){var e,t,n;if(""!==A.path)return F(A.path,"d.ts");const i=await this._fetchPackageJsonAndAddToOutputFiles(A);return null!==(n=null!==(t=null!==(e=null==i?void 0:i.typings)&&void 0!==e?e:null==i?void 0:i.types)&&void 0!==t?t:void 0!==(null==i?void 0:i.main)?F(i.main,"d.ts"):void 0)&&void 0!==n?n:"index.d.ts"}async _fetchPackageJsonAndAddToOutputFiles(A){const e=await this._fetchAndAddToOutputFiles({...A,path:"package.json"});if(void 0!==e.error)throw Error(`Could not fetch package.json for ${A.pkg}@${A.version}: ${e.error}`);return JSON.parse(e.result)}async _fetchAndAddToOutputFiles(A){const e=this._importMapResolver.resolve(q(`${A.pkg}/${A.path}`));null===e&&(A=await this._cdn.canonicalize(A));let t=this._filesByPackageVersion.get(A.pkg);void 0===t&&(t=new Map,this._filesByPackageVersion.set(A.pkg,t));let n=t.get(A.version);void 0===n&&(n=new Map,t.set(A.version,n));let i=n.get(A.path);if(void 0!==i)return i;const o=new Y;let s;if(i=o.promise,n.set(A.path,i),null!==e){const A=await fetch(e);if(200!==A.status){const e={error:A.status};return o.resolve(e),e}s=await A.text()}else try{s=(await this._cdn.fetch(A)).content}catch{const A={error:404};return o.resolve(A),A}const r={result:s};return o.resolve(r),r}_addEdgeToDependencyGraph(A,e){if(A===lA)this._rootDependencies[e.pkg]=e.version;else{let t=this._dependencyGraph[A.pkg];void 0===t&&(t={},this._dependencyGraph[A.pkg]=t);let n=t[A.version];void 0===n&&(n={},t[A.version]=n),n[e.pkg]=e.version}}async _materializeNodeModulesTree(A,e,t){var n;for(const[i,o]of Object.entries(A)){const A=null===(n=this._filesByPackageVersion.get(i))||void 0===n?void 0:n.get(o.version);if(void 0!==A){for(const[n,o]of A){const A=await o;if(void 0===A.error){const o=`${t}${i}/${n}`;e.set(o,A.result)}}await this._materializeNodeModulesTree(o.nodeModules,e,`${t}${i}/node_modules/`)}}}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */function pA(e){var t;return{code:e.code,source:null!==(t=e.source)&&void 0!==t?t:"typescript",message:A.flattenDiagnosticMessageText(e.messageText,"\n"),severity:hA[e.category],range:{start:void 0!==e.file&&void 0!==e.start?e.file.getLineAndCharacterOfPosition(e.start):{character:0,line:0},end:void 0!==e.file&&void 0!==e.start&&void 0!==e.length?e.file.getLineAndCharacterOfPosition(e.start+e.length):{character:0,line:0}}}}const hA={[A.DiagnosticCategory.Error]:1,[A.DiagnosticCategory.Warning]:2,[A.DiagnosticCategory.Message]:3,[A.DiagnosticCategory.Suggestion]:4}; +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */function fA(A){if(!A||0===A.length)return"";let e="";return A.forEach((A=>{e+=A.text})),e}function uA(A){var e;return null!==(e=null==A?void 0:A.map((A=>A.text)))&&void 0!==e?e:[]} +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */const IA={compileProject:async(A,e,t)=>{const n=BA(e),i=new eA(n.cdn,n.importMapResolver).process(async function*(A,e){const t=A.languageServiceContext.service,n=A.languageServiceContext.serviceHost;let i;const o=[];for await(const A of e)if("file"===A.kind&&(A.file.name.endsWith(".ts")||A.file.name.endsWith(".jsx")||A.file.name.endsWith(".tsx")))o.push(A.file);else if(yield A,"file"===A.kind&&"package.json"===A.file.name)try{i=JSON.parse(A.file.content)}catch(A){}if(0===o.length)return;const s=new Map,r=o.map((A=>({file:A,url:new URL(A.name,self.origin).href})));for(const{file:A,url:e}of r)s.set(e,A.content);const Q=void 0===i?{type:"module"}:"module"===i.type?i:{...i,type:"module"};s.set(new URL("package.json",self.origin).href,JSON.stringify(Q)),n.sync(s);const a=t.getProgram();if(void 0===a)throw Error("Unexpected error: program was undefined");for(const{file:A,url:e}of r){for(const n of t.getSyntacticDiagnostics(e))yield{kind:"diagnostic",filename:A.name,diagnostic:pA(n)};const n=a.getSourceFile(e);let i;a.emit(n,((A,e)=>{i={name:new URL(A).pathname.slice(1),content:e,contentType:"text/javascript"}})),void 0!==i&&(yield{kind:"file",file:i})}const g=await dA.fetchTypes(A.cdn,A.importMapResolver,i,r.map((A=>A.file.content)),A.languageServiceContext.compilerOptions.lib);for(const[A,e]of g.files){const t=new URL("node_modules/"+A,self.origin).href;n.updateFileContentIfNeeded(t,e)}for(const{file:A,url:e}of r)for(const n of t.getSemanticDiagnostics(e))yield{kind:"diagnostic",filename:A.name,diagnostic:pA(n)}} +/** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */(n,A.map((A=>({kind:"file",file:A})))));for await(const A of i)t(A);t({kind:"done"})},getCompletions:async(A,e,t,n,i)=>{const o=BA(i),s=o.languageServiceContext.service,r=o.languageServiceContext.serviceHost,Q={};"."===t&&(Q.triggerCharacter=".");const a=new URL(A,self.origin).href;return r.updateFileContentIfNeeded(a,e),s.getCompletionsAtPosition(A,n,Q)},getCompletionItemDetails:async(A,e,t,n)=>{var i;const o=BA(t).languageServiceContext.service.getCompletionEntryDetails(A,e,n,void 0,void 0,void 0,void 0);return{text:fA(null==o?void 0:o.displayParts),tags:null!==(i=null==o?void 0:o.tags)&&void 0!==i?i:[],documentation:uA(null==o?void 0:o.documentation)}}};Q(IA); diff --git a/playwright.config.ts b/playwright.config.ts deleted file mode 100644 index 4fa396c3..00000000 --- a/playwright.config.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -const config = { - testDir: 'src/test/playwright', - // There is some flakiness, especially in webkit. - // - // TODO(aomarks) Investigate this further. Haven't been able to isolate the - // flakes yet, but it could indicate a genuine problem. - // https://github.com/google/playground-elements/issues/229 - retries: 3, - // Not running both browsers at the same time helps with flakiness too. Could - // this imply a race condition that is influenced by CPU load? - workers: 1, - // Defaults to 30 seconds. We shouldn't need that much time, and it's better - // to fail fast and retry. - timeout: 10000, - projects: [ - { - name: 'chromium', - use: { - browserName: 'chromium', - }, - }, - // Webkit tests are *very* flakey compared to Chrome. Temporarily disabled. - // { - // name: 'webkit', - // use: { - // browserName: 'webkit', - // }, - // }, - // Sadly playwright Firefox does not currently work with service workers at - // all, see https://github.com/microsoft/playwright/issues/7288. - // { - // name: 'firefox', - // use: { - // browserName: 'firefox', - // }, - // }, - ], -}; -export default config; diff --git a/configurator/project/index.html b/project/index.html similarity index 100% rename from configurator/project/index.html rename to project/index.html diff --git a/configurator/project/my-element.ts b/project/my-element.ts similarity index 100% rename from configurator/project/my-element.ts rename to project/my-element.ts diff --git a/project/package.json b/project/package.json new file mode 100644 index 00000000..bb43a6a9 --- /dev/null +++ b/project/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "lit": "^2.0.0", + "@lit/reactive-element": "^1.0.0", + "lit-element": "^3.0.0", + "lit-html": "^2.0.0" + } +} diff --git a/configurator/project/project.json b/project/project.json similarity index 100% rename from configurator/project/project.json rename to project/project.json diff --git a/release-process.md b/release-process.md deleted file mode 100644 index cda219b6..00000000 --- a/release-process.md +++ /dev/null @@ -1,39 +0,0 @@ -# playground-elements Release Process - -This document outlines the process for publishing playground-elements to [npm](https://www.npmjs.com/package/playground-elements). - -Prerequisites: - -- Must have npm publish permissions for playground-elements. Note: it can take a few hours for the permissions to propagate and allow publishing. - -> **Warning** -> This release process has manual steps. At the ⚠️ emoji, proceed with caution. - -## Steps - -1. Manually create a release PR. Prior examples [#264](https://github.com/google/playground-elements/pull/376) [#245](https://github.com/google/playground-elements/pull/245) - 1. Create a branch from `main`. E.g., `git checkout -b release-vX-XX-X` - 1. Modify the CHANGELOG.md to reflect the release version - 1. Run `npm version --no-git-tag-version [patch|minor|major]` to update `package.json` and `package-lock.json` with the correct version bump. This will also automatically run `npm run update-version-module` and stage the `src/shared/version.ts` file. - 1. Commit and create PR with name “Release ” -1. Get code review & tests passing on PR. Squash and merge once approved. -1. Checkout the `main` branch and `git pull`. `git status` and `git log` to ensure on `main` and last commit was the release commit. - -> **Warning** -> Manual Publish to NPM - proceed with caution - -1. ⚠️ Running `npm publish` will always replace the `latest` tag with the version just published. The `latest` tag is what users get from `npm install playground-elements`. If publishing a pre-release, use `npm publish --no-tag`. Otherwise for a normal release, use `npm publish`. -1. Check https://www.npmjs.com/package/playground-elements to validate that the publish succeeded, or run `npm info playground-elements` -1. Add a [Github Release via this dashboard.](https://github.com/google/playground-elements/releases) - 1. Press “Draft a new release” - 1. Click “Choose a tag” and type in the version that was released. You will create this new tag when publishing the release notes. It will be associated with the latest commit on `main` which is your release. - 1. Release title should be identical to the tag. - 1. In the “describe this release” textbox, copy paste the `CHANGELOG.md` for the release. - 1. Press “Publish release”. - -Great job! You've successfully released playground-elements to npm and tagged the release. - -Verification links: - -- NPM: https://www.npmjs.com/package/playground-elements -- Tagged release: https://github.com/google/playground-elements/releases diff --git a/rollup.config.common.js b/rollup.config.common.js deleted file mode 100644 index e4852319..00000000 --- a/rollup.config.common.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import terser from '@rollup/plugin-terser'; - -const terserOptions = { - warnings: true, - ecma: 2017, - compress: { - unsafe: true, - passes: 2, - }, - output: { - // "some" preserves @license and @preserve comments - comments: 'some', - inline_script: false, - }, - mangle: { - properties: false, - }, -}; - -export const maybeTerser = process.env.NO_TERSER ? [] : [terser(terserOptions)]; diff --git a/rollup.config.configurator.js b/rollup.config.configurator.js deleted file mode 100644 index d0e2496c..00000000 --- a/rollup.config.configurator.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import resolve from '@rollup/plugin-node-resolve'; -import terser from '@rollup/plugin-terser'; -import copy from 'rollup-plugin-copy'; - -export default [ - { - input: 'configurator/playground-configurator.js', - output: { - file: 'configurator/deploy/playground-configurator.js', - format: 'esm', - }, - plugins: [ - resolve(), - terser({ - warnings: true, - ecma: 2017, - compress: { - unsafe: true, - passes: 2, - }, - output: { - comments: 'some', - }, - mangle: { - properties: false, - }, - }), - copy({ - targets: [ - { - src: 'configurator/index.html', - dest: 'configurator/deploy/', - }, - { - src: 'configurator/project', - dest: 'configurator/deploy/', - }, - { - src: 'playground-typescript-worker.js', - dest: 'configurator/deploy/', - }, - { - src: 'playground-service-worker.js', - dest: 'configurator/deploy/', - }, - { - src: 'playground-service-worker-proxy.html', - dest: 'configurator/deploy/', - }, - ], - }), - ], - }, -]; diff --git a/rollup.config.service-worker.js b/rollup.config.service-worker.js deleted file mode 100644 index 6e8cb4e1..00000000 --- a/rollup.config.service-worker.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import resolve from '@rollup/plugin-node-resolve'; -import * as fs from 'fs'; -import {maybeTerser} from './rollup.config.common.js'; - -/** - * Rollup plugin which generates an HTML file with all input JavaScript - * bundles inlined into script tags. - */ -function inlineHtml(htmlOutPath) { - return { - name: 'inline-html', - generateBundle: async (_outputOptions, bundles, isWrite) => { - if (!isWrite) { - return; - } - const scripts = []; - for (const [name, bundle] of Object.entries(bundles)) { - scripts.push(``); - // Don't emit the input bundle as its own file. - delete bundles[name]; - } - const html = `${scripts.join('')}`; - await fs.promises.writeFile(htmlOutPath, html, 'utf8'); - }, - }; -} - -export default [ - // Generate playground-service-worker-proxy.html, the HTML file + inline - // script that proxies between a project and a service worker on a possibly - // different origin. - { - input: 'playground-service-worker-proxy.js', - output: { - file: 'playground-service-worker-proxy-temp-bundle.js', - format: 'esm', - }, - plugins: [ - ...maybeTerser, - inlineHtml('playground-service-worker-proxy.html'), - ], - }, - { - input: 'service-worker/playground-service-worker.js', - output: { - file: 'playground-service-worker.js', - format: 'iife', - exports: 'none', - }, - plugins: [resolve(), ...maybeTerser], - } -]; diff --git a/rollup.config.typescript.js b/rollup.config.typescript.js deleted file mode 100644 index a440c401..00000000 --- a/rollup.config.typescript.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import commonjs from '@rollup/plugin-commonjs'; - -/** - * This Rollup config generates a JS module version of typescript from its - * CommonJS version. - * - * It's generated separately from the main Rollup config because it is an input - * to bundles generated there. We could also run this commonjs transform in the - * main Rollup config, but having a genuine module in the sources makes a few - * things easier: - * - * - We can import it into tests without also having to configure the commonjs - * transform there. @web/test-runner does support running the commonjs Rollup - * plugin, but for some reason it was still erroring. - * - * - The development loop generating the worker bundle is slightly faster, - * because we don't need to run the commonjs transform every time we build the - * worker. - * - * - We use module imports in the worker, for a faster development mode that - * doesn't bundle. Having only module sources makes this easier too. - */ -export default [ - { - input: 'node_modules/typescript/lib/typescript.js', - output: { - file: 'internal/typescript.js', - format: 'esm', - }, - plugins: [ - commonjs({ - ignore: (id) => true, - }), - ], - }, -]; diff --git a/rollup.config.web-worker.js b/rollup.config.web-worker.js deleted file mode 100644 index 557007e0..00000000 --- a/rollup.config.web-worker.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import resolve from '@rollup/plugin-node-resolve'; -import {maybeTerser} from './rollup.config.common.js'; -import * as path from 'path'; - -const internalTypescriptPath = path.resolve(process.cwd(), 'internal/typescript.js'); - -export default { - input: 'playground-typescript-worker-entrypoint.js', - external(id, parentId, isResolved) { - if (!isResolved && parentId !== undefined) { - id = path.resolve(path.dirname(parentId), id); - } - return id === internalTypescriptPath; - }, - output: { - file: 'playground-typescript-worker.js', - format: 'esm', - exports: 'none', - }, - plugins: [resolve(), ...maybeTerser], -}; diff --git a/scripts/theme-generator.html b/scripts/theme-generator.html deleted file mode 100644 index 7890fbe9..00000000 --- a/scripts/theme-generator.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - -
- - background - default-color - - -
cursor
- - -
selection
- - -
gutter-background
-
gutter-filler-background
-
gutter-border
-
gutter-box-shadow
-
linenumber
- - - - - atom - attribute - builtin - comment - def - keyword - meta - number - operator - qualifier - string - string-2 - tag - type - variable - variable-2 - variable-3 - - - callee - property - - -
- - diff --git a/scripts/theme-generator.js b/scripts/theme-generator.js deleted file mode 100644 index e7b43eff..00000000 --- a/scripts/theme-generator.js +++ /dev/null @@ -1,181 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -// This script generates the following files: -// -// 1) themes/*.css : A CSS file for each of the standard CodeMirror themes, which -// expresses that theme in terms of CSS custom properties. -// -// 2) src/themes/*.css.ts : A JavaScript module for each file in #2 that exports -// the style as a lit CSSResult. -// -// 3) src/configurator/themes.ts : An aggregation of all theme names and theme -// CSSResults, for use by the configurator. -// -// We convert each standard CodeMirror theme to a set of CSS custom properties by -// loading ./theme-generator.html in a playwright-controlled Chromium browser, -// loading each of the original themes stylesheets, and extracting colors from -// probe nodes that mimic the structure of /actual CodeMirror DOM. - -/* eslint-env browser */ - -import * as fs from 'fs'; -import * as pathlib from 'path'; -import * as url from 'url'; - -import * as webDevServer from '@web/dev-server'; -import * as playwright from 'playwright'; -import CleanCSS from 'clean-css'; - -const rootDir = pathlib.resolve( - pathlib.dirname(url.fileURLToPath(import.meta.url)), - '..' -); - -const mkdirAndWriteUtf8 = async (path, data) => { - await fs.promises.mkdir(pathlib.dirname(path), {recursive: true}); - await fs.promises.writeFile(path, data, 'utf8'); -}; - -// The main reason we use a CSS minifier here is to remove redundant rules from -// the default stylesheet, because we replace its fixed color values with var()s -// simply by appending rules to the end of the stylesheet. For example, we want -// to remove the first rule from: -// -// .cm-string { color: blue; } -// .cm-string { color: var(--playground-code-string-color); } -const minifier = new CleanCSS({level: {2: {all: true}}, format: 'beautify'}); -const minifyCss = (cssText) => { - const result = minifier.minify(cssText); - if (result.errors.length !== 0) { - throw new Error(`CleanCSS errors: ${result.errors.join(';')}`); - } - let minified = result.styles; - return minified; -}; - -const postMinifyCss = (css) => { - // The string value of `window.getComputedStyle(...).background` includes all - // values, but in practice only color and url are set, so we can strip off - // most of it. - css = css.replace( - / none repeat scroll 0% 0%\s*\/\s*auto padding-box border-box/g, - '' - ); - // The computed value of a `border` property includes all values even when - // width is 0. We can strip off the rest when width is 0. - css = css.replace(/0px none rgb.*;/g, '0px;'); - return css; -}; - -const makeThemeCss = (themeName, results, defaultResults) => { - const excludeDefaults = Object.values(results).filter( - (r) => defaultResults[r.to].value !== r.value - ); - return postMinifyCss( - minifyCss(`.playground-theme-${themeName} { -${excludeDefaults.map(({to, value}) => ` ${to}: ${value};`).join('\n')} -}`) - ); -}; - -const makeCssModule = (css) => { - return `import {css} from 'lit'; -const style = css\` -${css} -\`; -export default style; -`; -}; - -const main = async () => { - const serverPromise = webDevServer.startDevServer({ - config: { - rootDir, - }, - }); - - const browser = await playwright.chromium.launch({ - headless: true, - args: ['--auto-open-devtools-for-tabs'], - }); - const context = await browser.newContext(); - const page = await context.newPage(); - const server = await serverPromise; - - const url = `http://localhost:${server.config.port}/scripts/theme-generator.html`; - await page.goto(url); - - const writes = []; - - // Default style - const defaultResults = await page.evaluate(() => window.probe('default')); - - // Themes - const excludeThemes = new Set([ - // This file just removes box-shadow for some reason, not a real theme. - 'ambiance-mobile.css', - ]); - const themeFilenames = fs - .readdirSync( - pathlib.resolve(rootDir, 'node_modules', 'codemirror-5', 'theme') - ) - .filter((name) => !excludeThemes.has(name)); - const themeNames = []; - for (const filename of themeFilenames) { - const themeName = filename.replace(/\.css$/, ''); - themeNames.push(themeName); - const styleUrl = `/node_modules/codemirror-5/theme/${filename}`; - const results = await page.evaluate( - ([themeName, styleUrl]) => window.probe(themeName, styleUrl), - [themeName, styleUrl] - ); - const css = makeThemeCss(themeName, results, defaultResults); - writes.push( - mkdirAndWriteUtf8(pathlib.join(rootDir, 'themes', filename), css) - ); - writes.push( - mkdirAndWriteUtf8( - pathlib.join(rootDir, 'src', 'themes', `${filename}.ts`), - makeCssModule(css) - ) - ); - } - - // All themes for configurator - const allThemesTs = ` -export const themeNames = [ -${themeNames.map((themeName) => ` '${themeName}',`).join('\n')} -] as const; - -${themeNames - .map( - (themeName) => - `import t${themeName.replace( - /-/g, - '_' - )} from '../themes/${themeName}.css.js';` - ) - .join('\n')} - - export const themeStyles = [ - ${themeNames - .map((themeName) => ` t${themeName.replace(/-/g, '_')},`) - .join('\n')} - ] as const; -`; - - writes.push( - mkdirAndWriteUtf8( - pathlib.join(rootDir, 'src', 'configurator', 'themes.ts'), - allThemesTs - ) - ); - - await Promise.all([browser.close(), server.stop(), ...writes]); -}; - -main(); diff --git a/scripts/update-version-module.js b/scripts/update-version-module.js deleted file mode 100644 index 03c16437..00000000 --- a/scripts/update-version-module.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import * as fs from 'fs/promises'; -import * as crypto from 'crypto'; -import {dirname, join} from 'path'; -import {fileURLToPath} from 'url'; - -// This script is automatically run before pack/publish to ensure that the -// src/shared/version.ts module contains the current NPM package version and -// service worker hash. -// -// We use the version number to generate a correct unpkg.com URL for the default -// sandbox location, and we use the service worker hash to determine when we -// need to force a service worker update. - -/* eslint-env node */ - -const thisDir = dirname(fileURLToPath(import.meta.url)); - -const getNpmVersion = async () => { - const path = join(thisDir, '..', 'package.json'); - const data = await fs.readFile(path, 'utf8'); - const parsed = JSON.parse(data); - return parsed.version; -}; - -const getServiceWorkerHash = async () => { - const path = join(thisDir, '..', 'playground-service-worker.js'); - const code = await fs.readFile(path, 'utf8'); - // Note in theory Terser could minimize the version code differently, but it - // should be obvious because this script will start to fail. - const versionPattern = - /version:\s*(?["'`])(?[a-z0-9]+)\k/g; - const matches = [...code.matchAll(versionPattern)]; - if (matches.length !== 1) { - throw new Error( - 'Expected exactly one version string in playground-service-worker.js. ' + - `Found ${matches.length}.` - ); - } - // We must remove the version string itself from the service worker code - // before hashing, so that we get a stable hash. - const oldHash = matches[0].groups.hex; - if (!oldHash) { - throw new Error('Could not find "hash" capture group in regexp match.'); - } - const hashableCode = code.replace(oldHash, ''); - const hash = crypto - .createHash('sha256') - .update(hashableCode) - // Hex is a little nicer than base64 because it doesn't use the _/= - // charaters which makes copy/paste annoying (can't double click on it). - .digest('hex') - // 8 hex chars = 32 hash bits. Should be sufficient. - .slice(0, 8); - return hash; -}; - -const newVersionModuleCode = `/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -// DO NOT UPDATE MANUALLY. - -// This file is automatically generated by scripts/update-version-module.js -// before publishing. -export const npmVersion = '${await getNpmVersion()}'; -export const serviceWorkerHash = '${await getServiceWorkerHash()}'; -`; - -const versionModulePath = join(thisDir, '..', 'src', 'shared', 'version.ts'); -const oldVersionModuleCode = await fs.readFile(versionModulePath, 'utf8'); -if (oldVersionModuleCode !== newVersionModuleCode) { - await fs.writeFile(versionModulePath, newVersionModuleCode, 'utf8'); - console.log( - 'Updated src/shared/version.ts, please commit this change and rebuild.' - ); - // Fail to help the publisher remember to commit. - process.exit(1); -} else { - console.log('src/shared/version.ts already up to date.'); -} diff --git a/src/cm-lang-lit.ts b/src/cm-lang-lit.ts deleted file mode 100644 index c43c7d41..00000000 --- a/src/cm-lang-lit.ts +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {cssLanguage} from '@codemirror/lang-css'; -import {htmlLanguage} from '@codemirror/lang-html'; -import {javascriptLanguage, jsxLanguage} from '@codemirror/lang-javascript'; -import {xmlLanguage} from '@codemirror/lang-xml'; -import {LanguageSupport, LRLanguage} from '@codemirror/language'; -import { - type Input, - type NestedParse, - parseMixed, - type SyntaxNode, - type SyntaxNodeRef, -} from '@lezer/common'; -import type {LRParser} from '@lezer/lr'; - -const parsers: Record = { - html: htmlLanguage.parser, - css: cssLanguage.parser, - svg: xmlLanguage.parser, - mathml: xmlLanguage.parser, -}; - -const litParseWrapper = parseMixed((ref: SyntaxNodeRef, input: Input) => { - if (ref.name !== 'TemplateString') { - return null; - } - - // Get the tag name and find the parser for it. - const tag = ref.node.prevSibling; - if (tag === null) { - return null; - } - - // Safety check for range validity - if (ref.from >= ref.to) { - return null; - } - - // Handle unclosed template literals by ensuring we have valid ranges - const safeFrom = ref.from; - const safeTo = Math.max(ref.to, safeFrom + 1); // Ensure to > from - let tagName: string; - - if (tag.name === 'MemberExpression') { - const prop = tag.lastChild; - if (prop?.name !== 'PropertyName') { - return null; - } - tagName = input.read(prop.from, prop.to); - } else if (tag.name === 'VariableName') { - tagName = input.read(tag.from, tag.to); - } else { - return null; - } - const parser = parsers[tagName]; - if (parser === undefined) { - return null; - } - - // If there are no interpolations, just return the parser to substitute for - // the entire template string. - if (ref.node.firstChild === null) { - return {parser} satisfies NestedParse; - } - - // If we have interpolations, return the parser and the overlay ranges that - // match the template strings between the interpolations. - const overlay: Array<{from: number; to: number}> = []; - let from = safeFrom; - let child: SyntaxNode | null = ref.node.firstChild; - - while (child !== null) { - // Only add range if it's valid (from < to) - if (from < child.from) { - overlay.push({from, to: child.from}); - } - from = child.to; - child = child.nextSibling; - } - - // Only add final range if it's valid - if (from < safeTo) { - overlay.push({from, to: safeTo}); - } - - // If we have no valid ranges, just return the parser without overlay - if (overlay.length === 0) { - return {parser} satisfies NestedParse; - } - - return {parser, overlay} satisfies NestedParse; -}); - -/** - * Taken from @codemirror/lang-javascript's implementation - * - * This defines what are brackets and comments in JavaScript. This enables - * features like auto-closing brackets and comment creation with cmd+/ as well - * as what syntax will generate indentations when hitting enter. - */ -const jsLanguageData = { - closeBrackets: {brackets: ['(', '[', '{', "'", '"', '`']}, - commentTokens: {line: '//', block: {open: '/*', close: '*/'}}, - indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/, - wordChars: '$', -}; - -export const litLanguage = LRLanguage.define({ - name: 'lit', - parser: javascriptLanguage.parser.configure({ - wrap: litParseWrapper, - }), - languageData: jsLanguageData, -}); - -export const litJsxLanguage = LRLanguage.define({ - name: 'lit-jsx', - parser: jsxLanguage.parser.configure({ - wrap: litParseWrapper, - }), - languageData: jsLanguageData, -}); - -export const litTypeScriptLanguage = LRLanguage.define({ - name: 'lit-typescript', - parser: javascriptLanguage.parser.configure({ - dialect: 'ts', - wrap: litParseWrapper, - }), - languageData: jsLanguageData, -}); - -export const litTsxLanguage = LRLanguage.define({ - name: 'lit-tsx', - parser: jsxLanguage.parser.configure({ - dialect: 'jsx ts', - wrap: litParseWrapper, - }), - languageData: jsLanguageData, -}); - -/** - * Language support for Lit, which builds on JavaScript/TypeScript and adds - * support for HTML, CSS, SVG, and MathML tagged template literals. - */ -export const lit = (config: {jsx?: boolean; typescript?: boolean} = {}) => { - const lang = config.jsx - ? config.typescript - ? litTsxLanguage - : litJsxLanguage - : config.typescript - ? litTypeScriptLanguage - : litLanguage; - - return new LanguageSupport(lang, [ - lang.extension, - htmlLanguage.extension, - cssLanguage.extension, - xmlLanguage.extension, - ]); -}; diff --git a/src/codemirror-extension-mixin.ts b/src/codemirror-extension-mixin.ts deleted file mode 100644 index 6bc7bfc4..00000000 --- a/src/codemirror-extension-mixin.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type {Extension} from '@codemirror/state'; - -/** - * An interface for declarative CodeMirror extension elements. - */ -export interface CodemirrorExtension { - /** - * Whether the extension has been successfully registered with an editor. - */ - isRegistered: boolean; - /** - * The function to call to unregister this extension, provided by the editor. - * @internal - */ - _unregister?: () => void; - /** - * Return the CodeMirror extension provided by this element. - */ - getExtensions(): Extension | Extension[]; -} - -/** - * Fired by a declarative CodeMirror extension element to announce its extension. - * - * Bubbles and is composed. - */ -export class RegisterCodemirrorExtensionEvent extends Event { - static readonly eventName = 'register-codemirror-extension'; - /** - * A function that returns the extension, or an array of extensions, to - * register. - */ - getExtensions: () => Extension | Extension[]; - - constructor(getExtensions: () => Extension | Extension[]) { - super(RegisterCodemirrorExtensionEvent.eventName, { - bubbles: true, - composed: true, - }); - this.getExtensions = getExtensions; - } -} - -/** - * Fired by a playground editor in response to a - * `RegisterCodemirrorExtensionEvent`. - * - * Does not bubble. - */ -export class CodemirrorExtensionRegisteredEvent extends Event { - static readonly eventName = 'codemirror-extension-registered'; - /** - * A function that the extension element can call to unregister its - * extension. - */ - unregister: () => void; - - constructor(unregister: () => void) { - super(CodemirrorExtensionRegisteredEvent.eventName, { - bubbles: false, - composed: false, - }); - this.unregister = unregister; - } -} - -/** - * Fired by a playground editor on its extension elements when it is ready to - * receive extensions. This is used to handle the race condition where an - * extension is defined and connected before the editor is. - * - * Does not bubble. - */ -export class PlaygroundEditorReadyEvent extends Event { - static readonly eventName = 'playground-editor-ready'; - constructor() { - super(PlaygroundEditorReadyEvent.eventName, { - bubbles: false, - composed: false, - }); - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type Constructor = new (...args: any[]) => T; - -interface WithWcCallbacks extends HTMLElement { - connectedCallback?(): void; - disconnectedCallback?(): void; -} - -/** - * A mixin for creating a declarative CodeMirror extension. - * - * A declarative CodeMirror extension is a custom element that provides a - * CodeMirror extension to any parent playground element that contains a - * CodeMirror editor. - * - * This mixin handles the event-based communication with the editor, so that a - * consuming class only needs to implement the `getExtensions()` method. - */ -export const codemirrorExtensionMixin = < - T extends Constructor ->( - superClass: T -) => { - return class CodemirrorExtensionElement - extends superClass - implements CodemirrorExtension - { - isRegistered = false; - _unregister?: () => void; - - /** - * This method must be implemented by the consuming class. - * @returns A CodeMirror `Extension` or array of `Extension`s. - */ - getExtensions(): Extension | Extension[] { - throw new Error('getExtensions() must be implemented'); - } - - override connectedCallback() { - super.connectedCallback?.(); - this.addEventListener( - CodemirrorExtensionRegisteredEvent.eventName, - (e: Event) => { - const event = e as CodemirrorExtensionRegisteredEvent; - this.isRegistered = true; - this._unregister = event.unregister; - event.stopPropagation(); - } - ); - this.addEventListener(PlaygroundEditorReadyEvent.eventName, () => { - if (!this.isRegistered) { - this.dispatchEvent( - new RegisterCodemirrorExtensionEvent(() => this.getExtensions()) - ); - } - }); - this.dispatchEvent( - new RegisterCodemirrorExtensionEvent(() => this.getExtensions()) - ); - } - - override disconnectedCallback(): void { - super.disconnectedCallback?.(); - this._unregister?.(); - this.isRegistered = false; - } - }; -}; diff --git a/src/configurator/highlight-tokens.ts b/src/configurator/highlight-tokens.ts deleted file mode 100644 index e5425305..00000000 --- a/src/configurator/highlight-tokens.ts +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -export const tokens = [ - { - id: 'codeBackground', - label: 'Background', - cssProperty: '--playground-code-background', - defaultValue: '#ffffff', - }, - { - id: 'synDefault', - label: 'Default', - cssProperty: '--playground-code-default-color', - cmClass: '.cm-line', - defaultValue: '#000000', - }, - { - id: 'synKeyword', - label: 'Keyword', - cssProperty: '--playground-code-keyword-color', - cmClass: 'tok-keyword', - defaultValue: '#770088', - }, - { - id: 'synAtom', - label: 'Atom', - cssProperty: '--playground-code-atom-color', - cmClass: 'tok-atom', - defaultValue: '#221199', - }, - { - id: 'synNumber', - label: 'Number', - cssProperty: '--playground-code-number-color', - cmClass: 'tok-number', - defaultValue: '#116644', - }, - { - id: 'synBool', - label: 'Bool', - cssProperty: '--playground-code-bool-color', - cmClass: 'tok-bool', - defaultValue: '#221199', - }, - { - id: 'synDef', - label: 'Def', - cssProperty: '--playground-code-def-color', - cmClass: 'tok-definition', - defaultValue: '#0000ff', - }, - { - id: 'synVariable', - label: 'Variable', - cssProperty: '--playground-code-variable-color', - cmClass: 'tok-variableName', - defaultValue: '#000000', - }, - { - id: 'synProperty', - label: 'Property', - cssProperty: '--playground-code-property-color', - cmClass: 'tok-propertyName', - defaultValue: '#000000', - }, - { - id: 'synOperator', - label: 'Operator', - cssProperty: '--playground-code-operator-color', - cmClass: 'tok-operator', - defaultValue: '#000000', - }, - { - id: 'synVariable2', - label: 'Variable 2', - cssProperty: '--playground-code-variable-2-color', - cmClass: 'tok-variableName2', - defaultValue: '#0055aa', - }, - { - id: 'synVariable3', - label: 'Variable 3', - cssProperty: '--playground-code-variable-3-color', - cmClass: 'tok-namespace', - defaultValue: '#008855', - }, - { - id: 'synType', - label: 'Type', - cssProperty: '--playground-code-type-color', - cmClass: 'tok-typeName', - defaultValue: '#008855', - }, - { - id: 'synComment', - label: 'Comment', - cssProperty: '--playground-code-comment-color', - cmClass: 'tok-comment', - defaultValue: '#aa5500', - }, - { - id: 'synString', - label: 'String', - cssProperty: '--playground-code-string-color', - cmClass: 'tok-string', - defaultValue: '#aa1111', - }, - { - id: 'synString2', - label: 'String 2', - cssProperty: '--playground-code-string-2-color', - cmClass: 'tok-string2', - defaultValue: '#ff5500', - }, - { - id: 'synMeta', - label: 'Meta', - cssProperty: '--playground-code-meta-color', - cmClass: 'tok-meta', - defaultValue: '#555555', - }, - { - id: 'synQualifier', - label: 'Qualifier', - cssProperty: '--playground-code-qualifier-color', - cmClass: 'tok-modifier', - defaultValue: '#555555', - }, - { - id: 'synBuiltin', - label: 'Builtin', - cssProperty: '--playground-code-builtin-color', - cmClass: 'tok-labelName', - defaultValue: '#3300aa', - }, - { - id: 'synTag', - label: 'Tag', - cssProperty: '--playground-code-tag-color', - cmClass: 'tok-tagName', - defaultValue: '#117700', - }, - { - id: 'synAttribute', - label: 'Attribute', - cssProperty: '--playground-code-attribute-color', - cmClass: 'tok-attributeName', - defaultValue: '#0000cc', - }, - { - id: 'synCallee', - label: 'Callee', - cssProperty: '--playground-code-callee-color', - cmClass: 'tok-labelName', - defaultValue: '#000000', - }, - // TODO(aomarks) local? -] as const; diff --git a/src/configurator/knobs.ts b/src/configurator/knobs.ts deleted file mode 100644 index d9f0a787..00000000 --- a/src/configurator/knobs.ts +++ /dev/null @@ -1,311 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * This kinda turned into something like storybook.js and similar. Maybe we - * should just use another library. - */ - -import {themeNames} from './themes.js'; -import {tokens} from './highlight-tokens.js'; - -interface BaseKnob { - id: Id; - label: string; - section: string; - default: T; - cssProperty?: string; - formatCss?: (value: T) => string; - htmlAttribute?: string; -} - -interface CheckboxKnob extends BaseKnob { - type: 'checkbox'; -} - -interface SliderKnob extends BaseKnob { - type: 'slider'; - min: number; - max: number; -} - -interface ColorKnob extends BaseKnob { - type: 'color'; - unsetLabel?: string; - // Gross hack. When we load a new theme, we change color knob defaults. But if - // we switch back to the default theme, this is how we know what the original - // default was. - originalDefault?: string; -} - -interface SelectKnob - extends BaseKnob { - type: 'select'; - options: ReadonlyArray; -} - -interface InputKnob extends BaseKnob { - type: 'input'; - placeholder?: string; - inputType?: string; -} - -function checkbox( - def: Omit, 'type'> -): CheckboxKnob { - return {type: 'checkbox', ...def}; -} - -function slider( - def: Omit, 'type'> -): SliderKnob { - return {type: 'slider', ...def}; -} - -function color( - def: Omit, 'type'> -): ColorKnob { - return {type: 'color', ...def}; -} - -function select( - def: Omit, 'type'> -): SelectKnob { - return {type: 'select', ...def}; -} - -function input( - def: Omit, 'type'> -): InputKnob { - return {type: 'input', ...def}; -} - -const pixels = (value: number) => value + 'px'; - -export const knobs = [ - // code style - select({ - id: 'theme', - label: 'Theme', - section: 'code', - options: ['default', ...themeNames], - default: 'default', - }), - slider({ - id: 'fontSize', - label: 'Font size', - section: 'code', - cssProperty: '--playground-code-font-size', - formatCss: pixels, - min: 1, - max: 30, - default: 14, - }), - select({ - id: 'fontFamily', - label: 'Font', - section: 'code', - cssProperty: '--playground-code-font-family', - options: ['monospace', 'Roboto Mono', 'Source Code Pro', 'Ubuntu Mono'], - formatCss: (value: string | number | boolean) => { - if (value !== 'monospace') { - return `${value}, monospace`; - } - return value; - }, - default: 'monospace', - }), - - ...tokens.map((token) => { - const {id, label, cssProperty, defaultValue} = token; - return color({ - id, - label, - cssProperty, - default: defaultValue, - originalDefault: defaultValue, - section: 'code', - }); - }), - - // features - input({ - id: 'cdnBaseUrl', - label: 'CDN Base URL', - section: 'features', - default: '', - placeholder: 'Resolves to https://unpkg.com', - htmlAttribute: 'cdn-base-url', - inputType: 'text', - }), - checkbox({ - id: 'resizable', - label: 'Resizable', - section: 'features', - default: false, - htmlAttribute: 'resizable', - }), - checkbox({ - id: 'editableFileSystem', - label: 'Editable filesystem', - section: 'features', - default: false, - htmlAttribute: 'editable-file-system', - }), - checkbox({ - id: 'lineNumbers', - label: 'Line numbers', - section: 'features', - default: false, - htmlAttribute: 'line-numbers', - }), - checkbox({ - id: 'lineWrapping', - label: 'Line wrapping', - section: 'features', - default: false, - htmlAttribute: 'line-wrapping', - }), - checkbox({ - id: 'noCompletions', - label: 'No completions', - section: 'features', - default: false, - htmlAttribute: 'no-completions', - }), - - // general appearance - color({ - id: 'highlight', - label: 'Highlight', - cssProperty: '--playground-highlight-color', - default: '#6200ee', - section: 'general appearance', - }), - color({ - id: 'pageBackground', - label: 'Page background', - default: '#cccccc', - originalDefault: '#cccccc', - section: 'general appearance', - }), - slider({ - id: 'radius', - label: 'Radius', - cssProperty: 'border-radius', - formatCss: pixels, - min: 0, - max: 30, - default: 0, - section: 'general appearance', - }), - checkbox({ - id: 'borders', - label: 'Borders', - cssProperty: '--playground-border', - formatCss: (value: string | number | boolean) => - value ? '1px solid #ddd' : 'none', - default: true, - section: 'general appearance', - }), - - // tab bar - color({ - id: 'tabBarBackground', - label: 'Background', - cssProperty: '--playground-tab-bar-background', - default: '#eaeaea', - section: 'tab bar', - }), - color({ - id: 'tabBarForeground', - label: 'Foreground', - cssProperty: '--playground-tab-bar-foreground-color', - default: '#000000', - section: 'tab bar', - }), - slider({ - id: 'barHeight', - label: 'Bar height', - cssProperty: '--playground-bar-height', - formatCss: pixels, - min: 10, - max: 100, - default: 40, - section: 'tab bar', - }), - - // preview - color({ - id: 'previewToolbarBackground', - label: 'Background', - cssProperty: '--playground-preview-toolbar-background', - default: '#ffffff', - section: 'preview', - }), - color({ - id: 'previewToolbarForeground', - label: 'Foreground', - cssProperty: '--playground-preview-toolbar-foreground-color', - default: '#444444', - section: 'preview', - }), - slider({ - id: 'previewWidth', - label: 'Preview width', - cssProperty: '--playground-preview-width', - formatCss: (val) => `${val}%`, - min: 0, - max: 100, - default: 30, - section: 'preview', - }), -] as const; - -export type Knob = (typeof knobs)[number]; -export type KnobId = Knob['id']; - -type KnobsById = {[K in Knob as K['id']]: K}; -export const knobsById = {} as KnobsById; -export const knobsBySection = {} as {[section: string]: Knob[]}; -for (const knob of knobs) { - // Cast to an arbitrary specific Knob type here because TypeScript isn't quite - // clever enough to know that the id will match the type. - knobsById[(knob as (typeof knobs)[0]).id] = knob as (typeof knobs)[0]; - let catArr = knobsBySection[knob.section]; - if (catArr === undefined) { - catArr = knobsBySection[knob.section] = []; - } - catArr.push(knob); -} -export const knobIds = Object.keys(knobsById) as KnobId[]; -export const knobSectionNames = Object.keys(knobsBySection); - -export type KnobsOfType = Exclude< - { - [K in Knob as K['id']]: K extends {type: T} ? K : never; - }[KnobId], - never ->; - -export type KnobValueType = KnobsById[T]['default']; - -export class KnobValues { - private values = new Map(); - - getValue(id: T): KnobValueType { - if (this.values.has(id)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return this.values.get(id) as any; - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return knobsById[id].default as any; - } - - setValue(id: T, value: KnobValueType) { - this.values.set(id, value); - } -} diff --git a/src/configurator/playground-configurator.ts b/src/configurator/playground-configurator.ts deleted file mode 100644 index 6a830e7a..00000000 --- a/src/configurator/playground-configurator.ts +++ /dev/null @@ -1,708 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, html, css, nothing} from 'lit'; -import {customElement, state, query} from 'lit/decorators.js'; - -import '../playground-ide.js'; -import {PlaygroundIde} from '../playground-ide.js'; -import '../playground-code-editor.js'; -import { - Knob, - KnobId, - KnobValueType, - KnobValues, - KnobsOfType, - knobIds, - knobSectionNames, - knobs, - knobsById, - knobsBySection, -} from './knobs.js'; -import {themeStyles} from './themes.js'; -import '@material/mwc-dialog'; -import '@material/mwc-button'; -import './playground-theme-detector.js'; -import {tokens} from './highlight-tokens.js'; - -/** - * A configurator for the playground-* elements. - */ -@customElement('playground-configurator') -export class PlaygroundConfigurator extends LitElement { - static override styles = [ - ...themeStyles, - css` - :host { - display: flex; - font-family: Roboto, Arial, Helvetica, sans-serif; - } - - #lhs { - overflow-y: auto; - width: 300px; - border-right: 1px solid #ccc; - box-shadow: -2px 0 6px 0px rgb(0 0 0 / 50%); - z-index: 1; - color: #424242; - font-size: 13px; - } - - #rhs { - display: flex; - flex-direction: column; - flex: 1; - overflow: auto; - } - - #container { - display: flex; - justify-content: center; - align-items: center; - flex: 1; - /* To position the GitHub cat corner. */ - position: relative; - } - - playground-ide { - flex: 1; - margin: 50px; - max-width: 900px; - } - - #code { - display: flex; - flex-wrap: wrap; - border-top: 1px solid #ccc; - height: 30%; - overflow-y: auto; - padding: 10px; - --playground-code-font-family: 'Roboto Mono', monospace; - --playground-code-font-size: 12px; - --playground-code-background: transparent; - background-color: #f7f7f7; - } - - #code > div { - min-width: 50%; - } - - h3 { - color: #949494; - font-weight: 400; - text-transform: uppercase; - } - - #code h3 { - margin: 0; - } - - #lhs section { - padding: 15px; - border-bottom: 1px solid #ccc; - } - - .sectionLabel { - margin-top: 5px; - } - - .knobs { - display: grid; - grid-template-columns: repeat(4, 1fr); - row-gap: 15px; - column-gap: 10px; - align-items: center; - } - - input[type='color'] { - width: 30px; - } - - .knobs label { - text-align: right; - cursor: pointer; - } - - #container { - flex: 1; - } - - .knobs select, - .knobs input[type='text'] { - grid-column: 2 / -1; - } - - .sliderAndValue { - display: flex; - align-items: center; - grid-column: 2 / -1; - } - - .sliderValue { - margin-left: 5px; - } - - #openDetectorButton { - background: #0075ff; - opacity: 0.8; - color: white; - padding: 5px; - border: none; - border-radius: 2px; - cursor: pointer; - font-size: 14px; - grid-column-start: 2; - grid-column-end: -1; - } - - #openDetectorButton:hover { - opacity: 1; - } - `, - ]; - - private _values = new KnobValues(); - - @state() - private _themeDetectorOpen = false; - - @query('playground-ide') - private _ide!: PlaygroundIde; - - override connectedCallback() { - super.connectedCallback(); - this._readUrlParams(new URL(document.location.href).searchParams); - } - - private async _setValue(id: T, value: KnobValueType) { - await this._setValues(new Map([[id, value]])); - } - - private async _setValues(values: Map) { - // Apply the theme first, because it sets new defaults, and we want any - // other values to take precedence. - const theme = values.get('theme'); - if (theme) { - await this._applyTheme(theme as KnobValueType<'theme'>); - } - for (const [id, value] of values) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this._values.setValue(id, value as any); - } - this._setUrlParams(); - this.requestUpdate(); - } - - private async _applyTheme(theme: KnobValueType<'theme'>) { - this._values.setValue('theme', theme); - - if (theme === 'default') { - // The default theme isn't a stylesheet we can load and probe. We just - // have to know the original colors. - for (const token of tokens) { - const knob = knobsById[token.id]; - if (knob.originalDefault) { - knob.default = knob.originalDefault; - } - this._values.setValue(knob.id, knob.default); - } - this._setUrlParams(); - this.requestUpdate(); - return; - } - - // Reset each syntax highlighting knob to its default. - for (const token of tokens) { - const knob = knobsById[token.id]; - this._values.setValue(knob.id, knob.default); - } - - // Update to apply the theme stylesheet. - this.requestUpdate(); - await this.updateComplete; - - // Extract the new custom property values from the theme stylesheet for each - // syntax token. - const style = window.getComputedStyle(this._ide); - for (const token of tokens) { - const knob = knobsById[token.id]; - if (!knob.cssProperty) { - continue; - } - - const rgb = style.getPropertyValue(knob.cssProperty); - const hex = toHex(rgb); - - // Change the value and the default. Change the default because the theme - // already applies this value. - this._values.setValue(knob.id, hex); - knob.default = hex; - } - } - - private _readUrlParams(params: URLSearchParams) { - const values = new Map(); - for (const id of knobIds) { - const urlValue = params.get(id); - if (urlValue === null) { - continue; - } - const knob = knobsById[id]; - switch (knob.type) { - case 'checkbox': - values.set(knob.id, urlValue === 'y'); - break; - case 'color': - values.set(knob.id, '#' + urlValue); - break; - case 'slider': - values.set(knob.id, Number(urlValue)); - break; - case 'select': - values.set(knob.id, urlValue); - break; - case 'input': - values.set(knob.id, urlValue); - break; - default: - throwUnreachable(knob, `Unexpected knob type ${(knob as Knob).type}`); - } - } - this._setValues(values); - } - - private _setUrlParams() { - const params = new URLSearchParams(); - for (const knob of knobs) { - const value = this._values.getValue(knob.id); - if (value === knob.default) { - continue; - } - switch (knob.type) { - case 'checkbox': - params.set(knob.id, (value as boolean) ? 'y' : 'n'); - break; - case 'color': - params.set(knob.id, (value as string).substring(1)); - break; - case 'slider': - params.set(knob.id, String(value as number)); - break; - case 'select': - params.set(knob.id, value as string); - break; - case 'input': - params.set(knob.id, value as string); - break; - default: - throwUnreachable(knob, `Unexpected knob type ${(knob as Knob).type}`); - } - } - history.replaceState(null, '', '?' + params.toString()); - } - - override render() { - return html` - - - - ${this._themeDetectorOpen - ? html`` - : nothing} - - -
${this._knobs}
- -
-
- - - - ${githubCorner} -
- -
-
-

CSS

- - -
- -
-

HTML

- - -
-
-
- `; - } - - private get _knobs() { - return knobSectionNames.map( - (section) => - html`
- -
- ${knobsBySection[section].map((knob) => this._knob(knob))} -
-
` - ); - } - - private get _htmlText() { - return `${this._themeImport} - - -`; - } - - private get _themeImport() { - const theme = this._values.getValue('theme'); - if (theme === 'default') { - return ''; - } - return `\n`; - } - - private get _htmlTextAttributes() { - const attributes = []; - for (const id of knobIds) { - const knob: Knob = knobsById[id]; - if (!knob.htmlAttribute) { - continue; - } - const value = this._values.getValue(id); - if (value === knob.default) { - continue; - } - switch (knob.type) { - case 'checkbox': - if (value) { - attributes.push(`\n ${knob.htmlAttribute}`); - } - break; - default: - attributes.push(`\n ${knob.htmlAttribute}="${value}"`); - break; - } - } - const theme = this._values.getValue('theme'); - if (theme !== 'default') { - attributes.push(`\n class="playground-theme-${theme}"`); - } - return attributes.join(''); - } - - private get _cssText() { - const props = []; - for (const id of knobIds) { - const knob: Knob = knobsById[id]; - if (!(knob as Knob).cssProperty) { - continue; - } - const value = this._values.getValue(id); - let line = `${knob.cssProperty}: ${ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - knob.formatCss ? (knob as any).formatCss(value) : value - };`; - if (value === knob.default) { - continue; - } else { - line = ` ${line}`; - } - props.push(line); - } - return ` -#playground { -${props.join('\n')} -} - `; - } - - private _knob(knob: Knob) { - let widget; - switch (knob.type) { - case 'select': - widget = this._selectKnob(knob); - break; - case 'slider': - widget = this._sliderKnob(knob); - break; - case 'color': - widget = this._colorKnob(knob); - break; - case 'checkbox': - widget = this._checkboxKnob(knob); - break; - case 'input': - widget = this._inputKnob(knob); - } - if (!widget) { - return nothing; - } - const label = html``; - if (knob.id === 'theme') { - const themeButton = html``; - return [label, widget, html``, themeButton]; - } - return [label, widget]; - } - - private _selectKnob(knob: KnobsOfType<'select'>) { - const value = this._values.getValue(knob.id); - return html` - - `; - } - - private _sliderKnob(knob: KnobsOfType<'slider'>) { - const value = this._values.getValue(knob.id); - return html` - - { - this._setValue(knob.id, Number(event.target.value)); - }} - /> - ${knob.formatCss ? knob.formatCss(value) : value} - - `; - } - - private _colorKnob(knob: KnobsOfType<'color'>) { - let value = this._values.getValue(knob.id); - return html` - ${'unsetLabel' in knob - ? html` -
- { - value = event.target.checked ? '' : '#ffffff'; - this._setValue(knob.id, value); - }} - /> - -
- - ` - : ''} - { - this._setValue(knob.id, event.target.value); - }} - /> - `; - } - - private _checkboxKnob(knob: KnobsOfType<'checkbox'>) { - const value = this._values.getValue(knob.id); - return html` - { - this._setValue(knob.id, event.target.checked); - }} - /> - `; - } - - private _inputKnob(knob: KnobsOfType<'input'>) { - const value = this._values.getValue(knob.id); - return html` - { - this._setValue(knob.id, event.target.value); - }} - /> - `; - } - - private _openThemeDetector() { - this._themeDetectorOpen = true; - } - - private _closeThemeDetector() { - this._themeDetectorOpen = false; - } - - private async _onThemeDetectorApply( - event: CustomEvent<{properties: Map}> - ) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const values = new Map(); - values.set('theme', 'default'); - - const propertyToHex = new Map(); - for (const [property, rgb] of event.detail.properties) { - propertyToHex.set(property, rgb ? toHex(rgb) : undefined); - } - - const defaultColorKnob = knobsById['synDefault']; - const defaultColor = - propertyToHex.get(defaultColorKnob.cssProperty!) || - defaultColorKnob.default; - - for (const knob of knobs) { - if (knob.cssProperty) { - if (propertyToHex.has(knob.cssProperty)) { - const hex = propertyToHex.get(knob.cssProperty) || defaultColor; - values.set(knob.id, hex); - } - } - } - - this._setValues(values); - - this._closeThemeDetector(); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-configurator': PlaygroundConfigurator; - } -} - -function throwUnreachable(_x: never, msg: string) { - throw new Error(msg); -} - -/** - * https://tholman.com/github-corners/ - */ -const githubCorner = html``; - -/** - * Convert "rgb(r, g, b)" to "#rrggbb". - */ -const toHex = (rgbStr: string): string => { - const match = rgbStr.match( - /^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/ - ); - if (!match) { - return ''; - } - const [, r, g, b] = match; - const toHex = (decStr: string) => - Number(decStr).toString(16).padStart(2, '0'); - return `#${toHex(r)}${toHex(g)}${toHex(b)}`; -}; diff --git a/src/configurator/playground-theme-detector.ts b/src/configurator/playground-theme-detector.ts deleted file mode 100644 index b692978c..00000000 --- a/src/configurator/playground-theme-detector.ts +++ /dev/null @@ -1,382 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, html, css} from 'lit'; -import {customElement, state, query} from 'lit/decorators.js'; -import '../playground-code-editor.js'; -import {PlaygroundCodeEditor} from '../playground-code-editor.js'; -import {tokens} from './highlight-tokens.js'; - -@customElement('playground-theme-detector') -export class PlaygroundThemeDetector extends LitElement { - static override styles = css` - ol { - padding-left: 24px; - } - - li { - margin-bottom: 1em; - } - - button, - label { - cursor: pointer; - } - - #pasteArea { - cursor: pointer; - } - - iframe { - width: 100%; - pointer-events: none; - margin-bottom: 1em; - } - - playground-code-editor { - position: absolute; - visibility: hidden; - width: 1px; - } - - #palette { - display: flex; - margin-bottom: 2em; - } - - .color { - height: 25px; - flex: 1; - } - - #buttons { - display: flex; - justify-content: flex-end; - } - - #buttons > button { - margin-left: 1em; - font-size: 18px; - } - `; - - @state() - private _filetype: 'ts' | 'html' | 'css' = 'ts'; - - @state() - private _iframeSrcdoc = ''; - - @state() - private _codeText = ''; - - @state() - private _propertyValues = new Map([ - ['--playground-code-background', null], - ...tokens.map(({cssProperty}) => [cssProperty, null]), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ] as any); - - @query('iframe') - private _iframeWithUserHtml!: HTMLIFrameElement; - - @query('playground-code-editor') - private _playgroundWithUserText!: PlaygroundCodeEditor; - - override render() { - return html` -

Theme detector

- -
    -
  1. - Pick a theme in VSCode
    - or any editor that copies as styled HTML -
  2. - -
  3. - Open a file with a variety of syntax
    - or click to copy a sample to paste: -
    - - - -
  4. - -
  5. Select All and Copy
  6. - -
  7. - Confirm the filetype: -
    - - - -
  8. -
  9. Click in the box below to paste and extract:
  10. -
- -
- -
- - - -
- ${[...this._propertyValues].map( - ([prop, color]) => - html`` - )} -
- -
- - -
- `; - } - - async _copySample(filetype: 'ts' | 'html' | 'css') { - this._filetype = filetype; - await navigator.clipboard.writeText(sampleFiles[this._filetype]); - } - - async _onClickPasteButton() { - const {html, text} = await this._readClipboard(); - if (!html || !text) { - return; - } - // Load the HTML format of the paste into a sandboxed iframe. - this._iframeSrcdoc = `` + html; - // Load the text format of the paste into our own highlighter. - this._codeText = text; - } - - private async _readClipboard(): Promise<{html: string; text: string}> { - let html = ''; - let text = ''; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const items = await (navigator.clipboard as any).read(); - for (const item of items) { - for (const type of item.types) { - if (type === 'text/html') { - const blob = await item.getType(type); - html = await blob.text(); - } else if (type === 'text/plain') { - const blob = await item.getType(type); - text = await blob.text(); - } - } - } - return {html, text}; - } - - private _extractStyles() { - if (!this._iframeSrcdoc) { - // We get an iframe load event even if there is no srcdoc. - return; - } - - // Map from CM6 token names to CSS property base names - // This maintains backward compatibility with the CSS custom property names - const tokenToCssProperty: Record = { - line: 'default', - typeName: 'type', - variableName: 'variable', - propertyName: 'property', - variableName2: 'variable-2', - string2: 'string-2', - namespace: 'variable-3', - className: 'class-name', - modifier: 'qualifier', - labelName: 'builtin', - tagName: 'tag', - attributeName: 'attribute', - }; - - // Create a map from example text fragments to the CSS property for that - // token, extracted from *our* version of the highlighted text. E.g.: - // - // import => --playground-code-keyword-color - // "foo" => --playground-code-string-color - // 42 => --playground-code-number-color - const fragmentToProperty = new Map(); - const ourWalker = document.createTreeWalker( - this._playgroundWithUserText.shadowRoot!, - NodeFilter.SHOW_TEXT - ); - while (ourWalker.nextNode()) { - const textNode = ourWalker.currentNode; - const parent = textNode.parentElement; - if (parent === null) { - continue; - } - - let property; - const cmClasses = [...parent.classList].filter( - (c) => c.startsWith('cm-') || c.startsWith('tok-') - ); - - if (cmClasses.length > 0) { - // The last CodeMirror class tends to be more specific (e.g. `callee` is - // more specific than `variable`). - const lastClass = cmClasses[cmClasses.length - 1]; - const cmToken = lastClass.replace(/^(cm-)|(tok-)/, ''); - - // Use the mapping to get the correct CSS property base name - const cssPropertyBase = tokenToCssProperty[cmToken] || cmToken; - property = `--playground-code-${cssPropertyBase}-color`; - } else { - continue; - } - - const text = textNode.textContent!; - - // The same token can appear multiple times but with different meaning. We - // can assume they'll appear in the same order in the iframe HTML as they - // do here, which is captured by the order of items in this array. - let arr = fragmentToProperty.get(text); - if (!arr) { - arr = []; - fragmentToProperty.set(text, arr); - } - arr.push(property); - } - - // Now walk over the HTML pasted by the user. Look for the example fragments - // we found above and query for their color. - const doc = this._iframeWithUserHtml.contentDocument!; - const theirWalker = doc.createTreeWalker( - doc.body, - NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT - ); - let foundBackground = false; - while (theirWalker.nextNode()) { - const node = theirWalker.currentNode; - - if (node.nodeType === Node.TEXT_NODE) { - // Codemirror 6 separates #id in css into # and id, but vscode does not. - // so in this case we want to match #id to id so that we can get the - // "builtin" color token. - const text = node.textContent!.replace(/^#id$/, 'id'); - const properties = fragmentToProperty.get(text); - if (properties) { - for (const property of properties) { - if (this._propertyValues.get(property) === null) { - const color = window.getComputedStyle(node.parentElement!).color; - this._propertyValues.set(property, color); - break; // Only set the first null property - } - } - } - } else if (!foundBackground && node.nodeType === Node.ELEMENT_NODE) { - // Use the first non-transparent background (depth first). - const background = window.getComputedStyle( - node as Element - ).backgroundColor; - if (background !== 'rgba(0, 0, 0, 0)') { - foundBackground = true; - this._propertyValues.set('--playground-code-background', background); - } - } - } - - // We updated the properties map in-place. - this.requestUpdate(); - } - - _onClickApply() { - this.dispatchEvent( - new CustomEvent<{properties: Map}>('apply', { - detail: { - properties: this._propertyValues, - }, - }) - ); - } - - _onClickCancel() { - this.dispatchEvent(new CustomEvent('cancel')); - } -} - -const sampleFiles = { - ts: ` -// Playground Sample TypeScript file -/* Another kind of comment */ -let variable = 1 + 1 === 2 === true; -const fn = (param: number) => param; -fn(3); -'string1'; -\`string2\`; -\`string3 \${variable}\` -export class Class { - property: string; -} -html\` - - - -\`; -css\` - /* CSS comment */ - p, #id, .class, a, :hover { - color: red; - content: 'c'; - } -\`; -`.trim(), - - html: ` - - - -`.trim(), - - css: ` -/* Playground sample CSS file */ -p, #id, .class, a, :hover { - color: red; - content: 'c'; -} -`.trim(), -} as const; diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 87a5e6b1..00000000 --- a/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -export * from './playground-ide.js'; -export * from './codemirror-extension-mixin.js'; diff --git a/src/internal/build.ts b/src/internal/build.ts deleted file mode 100644 index ac00b756..00000000 --- a/src/internal/build.ts +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {Deferred} from '../shared/deferred.js'; - -import { - SampleFile, - BuildOutput, - FileBuildOutput, - DiagnosticBuildOutput, - HttpError, -} from '../shared/worker-api.js'; -import {Diagnostic} from 'vscode-languageserver-protocol'; - -const unreachable = (n: never) => n; - -type State = 'active' | 'done' | 'cancelled'; - -const errorNotFound: HttpError = { - status: /* Not Found */ 404, - body: 'Playground file not found', -}; - -const errorCancelled: HttpError = { - status: /* Service Unavailable */ 503, - body: 'Playground build cancelled', -}; - -/** - * The results of a particular Playground build. - */ -export class PlaygroundBuild { - diagnostics = new Map(); - private _state: State = 'active'; - private _stateChange = new Deferred(); - private _files = new Map>(); - private _diagnosticsCallback: () => void; - private _diagnosticsDebounceId: number | undefined; - - /** - * @param diagnosticsCallback Function that will be invoked when one or more - * new diagnostics have been received. Fires at most once per animation frame. - */ - constructor(diagnosticsCallback: () => void) { - this._diagnosticsCallback = diagnosticsCallback; - } - - /** - * The current state of this build. - */ - state(): State { - // Note this could be a getter, but TypeScript optimistically preserves - // type-narrowing on properties between awaits, which makes usage awkward in - // this case (see https://github.com/microsoft/TypeScript/issues/31429). - return this._state; - } - - /** - * Promise of the next state change. - */ - get stateChange(): Promise { - return this._stateChange.promise; - } - - /** - * Set this build's state to cancelled, ignore any future build results, and - * fail any pending file gets. - */ - cancel(): void { - this._errorPendingFileRequests(errorCancelled); - this._changeState('cancelled'); - } - - /** - * Return a promise of a build output with the given name. If the file is not - * received before the build is completed or cancelled, this promise will be - * rejected. - */ - async getFile(name: string): Promise { - let deferred = this._files.get(name); - if (deferred === undefined) { - if (this._state === 'done') { - return errorNotFound; - } else if (this._state === 'cancelled') { - return errorCancelled; - } - deferred = new Deferred(); - this._files.set(name, deferred); - } - return deferred.promise; - } - - /** - * Handle a worker build output. - */ - onOutput(output: BuildOutput) { - if (this._state !== 'active') { - return; - } - if (output.kind === 'file') { - this._onFile(output); - } else if (output.kind === 'diagnostic') { - this._onDiagnostic(output); - } else if (output.kind === 'done') { - this._onDone(); - } else { - throw new Error( - `Unexpected BuildOutput kind: ${ - (unreachable(output) as BuildOutput).kind - }` - ); - } - } - - private _changeState(state: State) { - this._state = state; - this._stateChange.resolve(); - this._stateChange = new Deferred(); - } - - private _onFile(output: FileBuildOutput) { - let deferred = this._files.get(output.file.name); - if (deferred === undefined) { - deferred = new Deferred(); - this._files.set(output.file.name, deferred); - } - deferred.resolve(output.file); - } - - private _onDiagnostic(output: DiagnosticBuildOutput) { - let arr = this.diagnostics.get(output.filename); - if (arr === undefined) { - arr = []; - this.diagnostics.set(output.filename, arr); - } - arr.push(output.diagnostic); - if (this._diagnosticsDebounceId === undefined) { - this._diagnosticsDebounceId = requestAnimationFrame(() => { - if (this._state !== 'cancelled') { - this._diagnosticsDebounceId = undefined; - this._diagnosticsCallback(); - } - }); - } - } - - private _onDone() { - this._errorPendingFileRequests(errorNotFound); - this._changeState('done'); - } - - private _errorPendingFileRequests(error: HttpError) { - for (const file of this._files.values()) { - if (!file.settled) { - file.resolve(error); - } - } - } -} diff --git a/src/internal/overlay.ts b/src/internal/overlay.ts deleted file mode 100644 index 757a44ff..00000000 --- a/src/internal/overlay.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, css, html} from 'lit'; -import {customElement} from 'lit/decorators.js'; - -/** - * An absolutely positioned scrim with a floating message. - */ -@customElement('playground-internal-overlay') -export class PlaygroundInternalOverlay extends LitElement { - static override styles = css` - :host { - position: absolute; - width: 100%; - height: 100%; - box-sizing: border-box; - left: 0; - top: 0; - display: flex; - align-items: center; - justify-content: center; - background: transparent; - z-index: 9; - background: rgba(0, 0, 0, 0.32); - overflow-y: auto; - } - - #message { - background: #fff; - color: #000; - padding: 10px 20px; - border-radius: 5px; - box-shadow: rgba(0, 0, 0, 0.3) 0 2px 10px; - } - `; - - override render() { - return html`
`; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-internal-overlay': PlaygroundInternalOverlay; - } -} diff --git a/src/internal/tab-bar.ts b/src/internal/tab-bar.ts deleted file mode 100644 index b9032f07..00000000 --- a/src/internal/tab-bar.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, LitElement} from 'lit'; -import {customElement, property} from 'lit/decorators.js'; -import {ifDefined} from 'lit/directives/if-defined.js'; - -import {PlaygroundInternalTab} from './tab.js'; - -/** - * A horizontal bar of tabs. - * - * Slots: - * - default: The tabs. - */ -@customElement('playground-internal-tab-bar') -export class PlaygroundInternalTabBar extends LitElement { - static override 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; - - override 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 deleted file mode 100644 index 81210120..00000000 --- a/src/internal/tab.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, LitElement, PropertyValues} from 'lit'; -import {customElement, property, query} from 'lit/decorators.js'; - -/** - * 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 override styles = css` - :host { - display: flex; - } - - button { - flex: 1; - border: none; - font-size: inherit; - font-family: inherit; - 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%; - } - - :host([active]) > button::after { - content: ''; - position: absolute; - left: 0; - bottom: 0; - width: 100%; - height: 2px; - background: var( - --playground-tab-bar-indicator-color, - var(--playground-highlight-color, #6200ee) - ); - } - `; - - /** - * 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; - - override render() { - return html``; - } - - override updated(changes: PropertyValues) { - if (changes.has('active') && this.active) { - this.dispatchEvent( - new CustomEvent<{tab?: PlaygroundInternalTab}>('tabchange', { - detail: {tab: this}, - bubbles: true, - }) - ); - } - } - - override focus() { - this._button.focus(); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-internal-tab': PlaygroundInternalTab; - } -} diff --git a/src/internal/typescript.d.ts b/src/internal/typescript.d.ts deleted file mode 100644 index 9d908989..00000000 --- a/src/internal/typescript.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import ts from 'typescript'; -export default ts; diff --git a/src/playground-code-editor.ts b/src/playground-code-editor.ts deleted file mode 100644 index 829b8120..00000000 --- a/src/playground-code-editor.ts +++ /dev/null @@ -1,1227 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, css, PropertyValues, html, nothing, render} from 'lit'; -import { - customElement, - property, - query, - state, - queryAssignedElements, -} from 'lit/decorators.js'; -import {ifDefined} from 'lit/directives/if-defined.js'; -import { - EditorState, - Extension, - StateEffect, - StateField, - Range, - Compartment, - Transaction, - Annotation, -} from '@codemirror/state'; -import { - EditorView, - ViewUpdate, - lineNumbers as cmLineNumbers, - keymap, - Decoration, - DecorationSet, - WidgetType, - highlightSpecialChars, - drawSelection, - dropCursor, -} from '@codemirror/view'; -import {lit} from './cm-lang-lit.js'; -import {html as cmHtml} from '@codemirror/lang-html'; -import {css as cmCss} from '@codemirror/lang-css'; -import { - autocompletion, - closeBrackets, - closeBracketsKeymap, - Completion, - completionKeymap, - CompletionContext, - CompletionResult, -} from '@codemirror/autocomplete'; -import {syntaxHighlighting} from '@codemirror/language'; -import { - history, - defaultKeymap, - historyKeymap, - indentWithTab, -} from '@codemirror/commands'; -import { - bracketMatching, - foldGutter, - foldKeymap, - indentOnInput, -} from '@codemirror/language'; -import {classHighlighter} from '@lezer/highlight'; - -import './internal/overlay.js'; -import {Diagnostic} from 'vscode-languageserver-protocol'; -import { - EditorCompletion, - EditorPosition, - EditorToken, -} from './shared/worker-api.js'; -import {highlightSelectionMatches, searchKeymap} from '@codemirror/search'; -import {lintKeymap} from '@codemirror/lint'; -import {playgroundTheme} from './playground-styles.js'; -import { - CodemirrorExtensionRegisteredEvent, - PlaygroundEditorReadyEvent, - RegisterCodemirrorExtensionEvent, -} from './codemirror-extension-mixin.js'; - -// TODO(aomarks) Could we upstream this to lit-element? It adds much stricter -// types to the ChangedProperties type. -interface TypedMap extends Map { - get(key: K): T[K]; - set(key: K, value: T[K]): this; - delete(key: K): boolean; - keys(): MapIterator; - values(): MapIterator; - entries(): MapIterator<{[K in keyof T]: [K, T[K]]}[keyof T]>; -} - -const unreachable = (n: never) => n; - -// Annotation to mark programmatic changes (not user edits) -const programmaticChangeAnnotation = Annotation.define(); - -/** - * A basic text editor with syntax highlighting for HTML, CSS, and JavaScript. - */ -@customElement('playground-code-editor') -export class PlaygroundCodeEditor extends LitElement { - static override styles = [ - css` - :host { - display: block; - } - - :host, - #focusContainer { - border-end-start-radius: inherit; - } - - #focusContainer { - height: 100%; - position: relative; - } - #focusContainer:focus { - outline: none; - } - - .cm-editor { - height: 100% !important; - border-radius: inherit; - } - - .cm-foldMarker { - font-family: sans-serif; - } - .cm-foldMarker:hover { - cursor: pointer; - /* Pretty much any color from the theme is good enough. */ - color: var(--playground-code-keyword-color, #770088); - } - - #keyboardHelp { - font-size: 18px; - font-family: sans-serif; - padding: 10px 20px; - } - - .diagnostic { - position: relative; - } - - .diagnostic::before { - /* It would be nice to use "text-decoration: red wavy underline" here, - but unfortunately it renders nothing at all for single characters. - See https://bugs.chromium.org/p/chromium/issues/detail?id=668042. */ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=='); - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 3px; - } - - #tooltip { - position: absolute; - padding: 7px; - z-index: 4; - font-family: var(--playground-code-font-family, monospace); - } - - #tooltip > div { - background: var(--playground-code-background, #fff); - color: var(--playground-code-default-color, #000); - /* Kind of hacky... line number color tends to work out as a good - default border, because it's usually visible on top of the - background, but slightly muted. */ - border: 1px solid var(--playground-code-linenumber-color, #ccc); - padding: 5px; - } - - [contenteditable='true'] { - outline: none; - } - - slot[name='extensions'] { - display: none; - } - `, - ]; - - /** - * A CodeMirror extension or extensions to apply to the editor. - */ - @property({attribute: false}) - extensions?: Extension | Extension[]; - - protected _editorView?: EditorView; - - get cursorPosition(): EditorPosition { - if (!this._editorView) { - return {ch: 0, line: 0}; - } - const pos = this._editorView.state.selection.main.head; - const line = this._editorView.state.doc.lineAt(pos); - return { - ch: pos - line.from, - line: line.number - 1, - }; - } - - get cursorIndex(): number { - if (!this._editorView) return 0; - return this._editorView.state.selection.main.head; - } - - get tokenUnderCursor(): EditorToken { - if (!this._editorView) return {start: 0, end: 0, string: ''}; - - const pos = this._editorView.state.selection.main.head; - const line = this._editorView.state.doc.lineAt(pos); - - const wordRange = this._editorView.state.wordAt(pos); - if (wordRange) { - const start = wordRange.from - line.from; - const end = wordRange.to - line.from; - return { - start, - end, - string: line.text.slice(start, end), - }; - } - - return { - start: 0, - end: 0, - string: '', - }; - } - - // We store _value ourselves, rather than using a public reactive property, so - // that we can set this value internally without triggering an update. - private _value?: string; - - @property() - get value() { - return this._value; - } - - set value(v: string | undefined) { - const oldValue = this._value; - this._value = v; - this.requestUpdate('value', oldValue); - } - - /** - * Provide a `documentKey` to create a CodeMirror document instance which - * isolates history and value changes per `documentKey`. - * - * Use to keep edit history separate between files while reusing the same - * playground-code-editor instance. - */ - @property({attribute: false}) - // eslint-disable-next-line @typescript-eslint/ban-types - documentKey?: object; - - /** - * WeakMap associating a `documentKey` with CodeMirror document state. - * A WeakMap is used so that this component does not become the source of - * memory leaks. - */ - // eslint-disable-next-line @typescript-eslint/ban-types - private readonly _docCache = new WeakMap(); - - /** - * The type of the file being edited, as represented by its usual file - * extension. - */ - @property() - type: 'js' | 'ts' | 'html' | 'css' | 'json' | 'jsx' | 'tsx' | undefined; - - /** - * If true, display a left-hand-side gutter with line numbers. Default false - * (hidden). - */ - @property({type: Boolean, attribute: 'line-numbers', reflect: true}) - lineNumbers = false; - - /** - * If true, wrap for long lines. Default false - */ - @property({type: Boolean, attribute: 'line-wrapping', reflect: true}) - lineWrapping = false; - - /** - * If true, this editor is not editable. - */ - @property({type: Boolean, reflect: true}) - readonly = false; - - /** - * If true, will disable code completions in the code-editor. - */ - @property({type: Boolean, attribute: 'no-completions'}) - noCompletions = false; - - /** - * Diagnostics to display on the current file. - */ - @property({attribute: false}) - diagnostics?: Array; - - @state() - _completions?: EditorCompletion[]; - - @state() - _completionsOpen = false; - - /** - * How to handle `playground-hide` and `playground-fold` comments. - * - * See https://github.com/google/playground-elements#hiding--folding for - * more details. - * - * Options: - * - on: Hide and fold regions, and hide the special comments. - * - off: Don't hide or fold regions, but still hide the special comments. - * - off-visible: Don't hide or fold regions, and show the special comments as - * literal text. - */ - @property() - pragmas: 'on' | 'off' | 'off-visible' = 'on'; - - @state() - private _tooltipDiagnostic?: { - diagnostic: Diagnostic; - position: string; - }; - - @state() - private _showKeyboardHelp = false; - - @query('#focusContainer') - private _focusContainer?: HTMLDivElement; - - @query('.cm-content') - private _editorContent?: HTMLDivElement; - - @queryAssignedElements({slot: 'extensions', flatten: true}) - private _extensionElements!: HTMLElement[]; - - private _diagnosticDecorations: DecorationSet = Decoration.none; - private _diagnosticsMouseoverListenerActive = false; - private _lastTransactions: Transaction[] = []; - private _declarativeExtensions = new Set(); - private _hasNotifiedExtensionsReady = false; - - // Compartments for dynamic configuration - private readonly _lineNumbersCompartment = new Compartment(); - private readonly _lineWrappingCompartment = new Compartment(); - private readonly _languageCompartment = new Compartment(); - private readonly _readOnlyCompartment = new Compartment(); - private readonly _autocompletionCompartment = new Compartment(); - private readonly _declarativeExtensionsCompartment = new Compartment(); - private readonly _programmaticExtensionsCompartment = new Compartment(); - - autocompleteDelay = 1250; - private _lastAutocompleteRequest = 0; - - // Create StateField for storing diagnostics decorations - private readonly _diagnosticField = StateField.define({ - create: () => Decoration.none, - update: () => { - return this._diagnosticDecorations; - }, - provide: (f) => EditorView.decorations.from(f), - }); - - override createRenderRoot() { - const root = this.attachShadow({mode: 'open'}); - this._editorView?.setRoot(root); - root.adoptedStyleSheets = [ - ...PlaygroundCodeEditor.styles.map((s) => s.styleSheet!), - ...root.adoptedStyleSheets, - ]; - return root; - } - - override update(changedProperties: PropertyValues) { - const changedTyped = changedProperties as TypedMap< - Omit< - PlaygroundCodeEditor, - keyof LitElement | 'render' | 'update' | 'createRenderRoot' - > & {extensions: Extension | Extension[]} - >; - - const view = this._editorView; - - // Collect all CodeMirror state effects (configuration changes) to dispatch them together - // in a single transaction at the end of the update cycle. - const effects: StateEffect[] = []; - - for (const prop of changedTyped.keys()) { - switch (prop) { - case 'extensions': - effects.push( - this._programmaticExtensionsCompartment.reconfigure( - [this.extensions ?? []].flat() - ) - ); - break; - case 'documentKey': { - const docKey = this.documentKey ?? {}; - let docState = this._docCache.get(docKey); - const lastKey = changedProperties.get('documentKey'); - let needsHideAndFold = false; - - // If a documentKey was previously active, cache its EditorState. - // This preserves the content and history when the user switches away - // from it and switches back later. - if (lastKey && this._editorView) { - const lastState = this._editorView.state; - this._docCache.set(lastKey, lastState); - - // Value differs, so that means we need to update the view to - // reflect the new state's value. - if (lastState.doc.toString() !== this.value) { - view?.dispatch({ - changes: [ - { - from: 0, - to: lastState.doc.length, - insert: this.value ?? '', - }, - ], - annotations: programmaticChangeAnnotation.of(true), - }); - } - } - - if (!docState) { - // No cached EditorState exists for the new documentKey because it's - // likely being loaded for the first time. - docState = this._createEditorState(this.value ?? ''); - this._docCache.set(docKey, docState); - needsHideAndFold = true; - } else if (docState.doc.toString() !== this.value) { - // A cached EditorState exists, but its content differs from the - // value property. We need to sync the cached state with the new - // value to preserve cmd+z history. - const tempView = new EditorView({state: docState}); - tempView.dispatch({ - changes: [ - { - from: 0, - to: docState.doc.length, - insert: this.value ?? '', - }, - ], - annotations: programmaticChangeAnnotation.of(true), - }); - docState = tempView.state; - this._docCache.set(docKey, docState); - tempView.destroy(); - } - - // Replace the entire view with the new editor state. Unlike CM5, CM6 - // is modular, and the history stays on the state object rather than - // the editor / view. - this._editorView?.setState(docState); - - // If a brand new document state was created, hiding and folding - // regions must be reapplied to this new state. - if (needsHideAndFold) { - void this._applyHideAndFoldRegions(); - } - break; - } - case 'value': - if (changedTyped.has('documentKey')) { - // Handled in the `documentKey` case. - break; - } - - if (this.value !== view?.state.doc.toString()) { - // The 'value' property was changed externally and it differs from - // the editor's current document content, so we need to update the - // view model to match. - view?.dispatch({ - // Mark as an input userEvent so that the user can undo / redo - // this change - userEvent: 'input', - changes: [ - { - from: 0, - to: view.state.doc.length, - insert: this.value ?? '', - }, - ], - annotations: programmaticChangeAnnotation.of(true), - }); - } - break; - case 'lineNumbers': - effects.push( - this._lineNumbersCompartment.reconfigure( - this.lineNumbers ? cmLineNumbers() : [] - ) - ); - break; - case 'lineWrapping': - effects.push( - this._lineWrappingCompartment.reconfigure( - this.lineWrapping ? EditorView.lineWrapping : [] - ) - ); - break; - case 'type': { - const lang = this._getLanguageExtension(); - effects.push(this._languageCompartment.reconfigure(lang || [])); - break; - } - case 'readonly': - effects.push( - this._readOnlyCompartment.reconfigure( - this.readonly ? EditorState.readOnly.of(true) : [] - ) - ); - break; - case 'pragmas': - void this._applyHideAndFoldRegions(); - break; - case 'diagnostics': - this._showDiagnostics(); - break; - case 'cursorIndex': { - const index = this.cursorIndex ?? 0; - if (view && index >= 0 && index <= view.state.doc.length) { - view.dispatch({ - selection: {anchor: index, head: index}, - }); - } - break; - } - case 'cursorPosition': { - const pos = this.cursorPosition ?? {ch: 0, line: 0}; - // Convert line/ch position to absolute position - const line = Math.max( - 0, - Math.min(pos.line, view!.state.doc.lines - 1) - ); - const lineObj = view!.state.doc.line(line + 1); - const ch = Math.max(0, Math.min(pos.ch, lineObj.length)); - const index = lineObj.from + ch; - - view?.dispatch({ - selection: {anchor: index, head: index}, - }); - break; - } - case 'noCompletions': - effects.push( - this._autocompletionCompartment.reconfigure( - this.noCompletions ? [] : [this._getAutocompletions()] - ) - ); - break; - case '_completions': - this._showCompletions(); - break; - case 'tokenUnderCursor': - case 'autocompleteDelay': - case '_completionsOpen': - // Ignored properties that do not require direct editor state updates - // or are handled by other mechanisms (e.g., getters, internal state changes). - break; - default: - unreachable(prop); - } - } - - // If any configuration changes (effects like line numbers, wrapping, language mode) were queued - // during the property update loop, dispatch them to the CodeMirror editor now. - // This applies all pending configuration updates in a single, batched operation, - // which is generally more performant and ensures consistency. - if (effects.length > 0) { - view?.dispatch({effects}); - } - - super.update(changedProperties); - } - - override render() { - if (this.readonly) { - return this._editorView?.dom; - } - return html` -
- - ${this._showKeyboardHelp - ? html` -

- Press Enter to start editing
- Press Escape to exit editor -

-
` - : nothing} - ${this._editorView?.dom} -
-
- ${this._tooltipDiagnostic?.diagnostic.message} -
-
-
- `; - } - - override connectedCallback() { - if (!this._editorView) { - this._editorView = new EditorView({ - state: this._createEditorState(this.value ?? ''), - root: this.shadowRoot ?? undefined, - }); - } - super.connectedCallback(); - } - - private _onSlotChange() { - if (this._hasNotifiedExtensionsReady) { - return; - } - - this._hasNotifiedExtensionsReady = true; - this._notifyExtensionsReady(); - } - - override disconnectedCallback() { - this._editorView?.destroy(); - this._editorView = undefined; - super.disconnectedCallback(); - } - - private _createEditorState(content: string): EditorState { - const baseExtensions: Extension[] = [ - syntaxHighlighting(classHighlighter, {fallback: true}), - highlightSpecialChars(), - history(), - drawSelection(), - dropCursor(), - EditorState.allowMultipleSelections.of(true), - indentOnInput(), - bracketMatching(), - closeBrackets(), - highlightSelectionMatches(), - keymap.of([ - ...closeBracketsKeymap, - ...defaultKeymap, - ...searchKeymap, - ...historyKeymap, - ...foldKeymap, - ...completionKeymap, - ...lintKeymap, - indentWithTab, - ]), - this._diagnosticField, - - this._readOnlyCompartment.of( - this.readonly ? EditorState.readOnly.of(true) : [] - ), - - this._lineNumbersCompartment.of( - this.lineNumbers ? [cmLineNumbers(), foldGutter()] : [] - ), - - this._lineWrappingCompartment.of( - this.lineWrapping ? EditorView.lineWrapping : [] - ), - - this._languageCompartment.of( - (() => { - return this._getLanguageExtension() || []; - })() - ), - - this._autocompletionCompartment.of( - this.noCompletions ? [] : [this._getAutocompletions()] - ), - - this._declarativeExtensionsCompartment.of([ - ...this._declarativeExtensions, - ]), - - this._programmaticExtensionsCompartment.of( - [this.extensions ?? []].flat() - ), - playgroundTheme, - ]; - - // Listen for changes - baseExtensions.push( - EditorView.updateListener.of((update: ViewUpdate) => { - if (update.docChanged) { - this._lastTransactions = [...update.transactions]; - this._value = update.state.doc.toString(); - - const isUndoRedo = update.transactions.some( - (tr) => - tr.annotation(Transaction.userEvent) === 'undo' || - tr.annotation(Transaction.userEvent) === 'redo' - ); - - // Check if ALL transactions are programmatic (not user edits). - // We fire the change event if ANY transaction is a user edit, even if - // there are also programmatic transactions in the same update. - const allProgrammatic = update.transactions.every( - (tr) => tr.annotation(programmaticChangeAnnotation) === true - ); - - // External changes are usually things like the editor switching which - // file it is displaying. - if (allProgrammatic) { - // Apply hide/fold regions when value changes from outside - void this._applyHideAndFoldRegions(); - this._showDiagnostics(); - } else { - if (isUndoRedo) { - // Always reapply hide/fold regions after undo/redo - void this._applyHideAndFoldRegions(); - } - // Only fire change event for user-initiated edits - this.dispatchEvent(new Event('change')); - } - } - }) - ); - - return EditorState.create({ - doc: content, - extensions: baseExtensions, - }); - } - - private _notifyExtensionsReady() { - for (const el of this._extensionElements) { - el.dispatchEvent(new PlaygroundEditorReadyEvent()); - } - } - - private _onRegisterExtension(e: RegisterCodemirrorExtensionEvent) { - e.stopPropagation(); - const newExtensions = e.getExtensions(); - const newExtArr = Array.isArray(newExtensions) - ? [...newExtensions] - : [newExtensions]; - - for (const ext of newExtArr) { - this._declarativeExtensions.add(ext); - } - - const unregister = () => { - for (const ext of newExtArr) { - this._declarativeExtensions.delete(ext); - } - this._reconfigureDeclarativeExtensions(); - }; - - e.composedPath()[0].dispatchEvent( - new CodemirrorExtensionRegisteredEvent(unregister) - ); - this._reconfigureDeclarativeExtensions(); - } - - private _reconfigureDeclarativeExtensions() { - this._editorView?.dispatch({ - effects: this._declarativeExtensionsCompartment.reconfigure([ - ...this._declarativeExtensions, - ]), - }); - } - - private _getLanguageExtension(): Extension | null { - switch (this.type) { - case 'js': - return lit(); - case 'jsx': - return lit({jsx: true}); - case 'ts': - return lit({typescript: true}); - case 'tsx': - return lit({typescript: true, jsx: true}); - case 'html': - return cmHtml(); - case 'css': - return cmCss(); - case 'json': - return lit(); - default: - return null; - } - } - - private _currentFiletypeSupportsCompletion() { - // Currently we are only supporting code completion for these. Change - // this in a case that we start to support configuring completions for - // other languages too. - return ['ts', 'js', 'tsx', 'jsx'].includes(this.type as string); - } - - override focus() { - this._editorContent?.focus(); - } - - private _customCompletionSource = async ( - context: CompletionContext - ): Promise => { - if (this.noCompletions) { - return null; - } - - // Only show completions when explicitly requested or when there's - // a token to complete - const wordBefore = context.matchBefore(/\w*/); - if ( - (!wordBefore || wordBefore.from === wordBefore.to) && - !context.explicit - ) { - return null; - } - - const wasTextEvent = this._lastTransactions.some( - (transaction) => - transaction.annotation(Transaction.userEvent) === 'input.type' - ); - const now = Date.now(); - const wasRecent = - now - this._lastAutocompleteRequest <= this.autocompleteDelay; - - if (now > this._lastAutocompleteRequest) { - this._lastAutocompleteRequest = now; - } - - const isRefinement = - !context.explicit && - wasTextEvent && - (wordBefore?.text?.startsWith('.') || - (wasRecent && (wordBefore?.text?.length ?? 0) > 1)); - - let resolve: ( - value: EditorCompletion[] | Promise - ) => void; - - const completionsPromise = new Promise((res) => { - resolve = res; - }); - - this.dispatchEvent( - new CustomEvent('request-completions', { - detail: { - isRefinement, - fileContent: this.value, - tokenUnderCursor: this.tokenUnderCursor.string, - cursorIndex: this.cursorIndex, - provideCompletions: (completions: EditorCompletion[]) => { - resolve(completions); - }, - }, - }) - ); - - const completions = await completionsPromise; - - if (context.aborted) { - return null; - } - - if (!completions || completions.length <= 0) { - return null; - } - - const optionsPromises = completions.map(async (comp, i) => { - return { - label: comp.displayText || comp.text, - detail: - comp.details !== undefined ? (await comp.details).text : undefined, - apply: comp.text, - boost: i === 0 ? 99 : undefined, // Boost first suggestion - } satisfies Completion; - }); - - const options = await Promise.all(optionsPromises); - - return { - from: wordBefore?.from ?? 0, - options, - }; - }; - - private _getAutocompletions() { - return autocompletion({ - // Only show completions when we explicitly support the language. - // Otherwise, default to whatever Codemirror does for it by default. - override: this._currentFiletypeSupportsCompletion() - ? [this._customCompletionSource] - : undefined, - }); - } - - private _showCompletions() { - if ( - !this._editorView || - !this._completions || - this._completions.length <= 0 - ) - return; - } - - private _onMousedown() { - // Directly focus editable region. - this._editorContent?.focus(); - } - - private _onFocus() { - // Outer container was focused, either by tabbing from outside, or by - // pressing Escape. - this._showKeyboardHelp = true; - } - - private _onBlur() { - // Outer container was unfocused, either by tabbing away from it, or by - // pressing Enter. - this._showKeyboardHelp = false; - } - - private _onKeyDown(event: KeyboardEvent) { - if (event.key === 'Enter' && event.target === this._focusContainer) { - this._editorContent?.focus(); - // Prevent typing a newline from this same event. - event.preventDefault(); - } else if (event.key === 'Escape') { - // If the user has completions selection UI opened up, Escape's default action - // is to close the completion UI instead of escaping the code editor instance. - // Therefore we only focus on the focusContainer in situations where the completions - // UI is not open. - if (!this._completionsOpen) { - // Note there is no API for "select the next naturally focusable element", - // so instead we just re-focus the outer container, from which point the - // user can tab to move focus entirely elsewhere. - this._focusContainer?.focus(); - } - } - } - - private async _applyHideAndFoldRegions() { - if (!this._editorView) { - return; - } - - if (this.pragmas === 'off-visible') { - return; - } - - const pattern = this._maskPatternForLang(); - if (pattern === undefined) { - return; - } - - // CM6 decorations can be used for the '...' of hide/fold regions because - // they are designed to modify the appearance of what is rendered in the - // editor, so we also use it to simply hide the hide comments as well. - const decorations: Range[] = []; - const text = this._editorView.state.doc.toString(); - // Annotations in CM6 are used for attaching metadata, in this case the - // fold ID, to dispatched actions. - const unfoldAnnotation = Annotation.define(); - - for (const match of text.matchAll(pattern)) { - const [, opener, kind, content, closer] = match; - const openerStart = match.index ?? 0; - const foldId = openerStart; // Use the start position as the UID for the fold - - const openerEnd = openerStart + opener.length; - - // Hide opening comment - decorations.push(Decoration.replace({}).range(openerStart, openerEnd)); - - const contentStart = openerEnd; - let contentEnd; - - if (content && closer) { - contentEnd = contentStart + content.length; - const closerStart = contentEnd; - const closerEnd = contentEnd + closer.length; - - // Hide closing comment - decorations.push(Decoration.replace({}).range(closerStart, closerEnd)); - } else { - // No matching end comment. Include the entire rest of the file. - contentEnd = text.length; - } - - const view = this._editorView!; - - if (this.pragmas === 'on') { - if (kind === 'fold') { - // Add fold widget and extract the content after the fold for display - const lines = content?.split('\n') || []; - const lastLine = - lines.length > 0 ? lines[lines.length - 1].trim() : ''; - - // Make sure we're showing the actual content, not just ellipses - const displayText = `…${lastLine}`; - - // Create a widget that shows the folded "..." content - const widget = new (class extends WidgetType { - toDOM() { - const wrapper = document.createElement('div'); - const span = html` - view.dispatch({ - annotations: unfoldAnnotation.of(foldId), - })} - >${displayText}`; - render(span, wrapper); - return wrapper.children[0] as HTMLElement; - } - })(); - - decorations.push( - Decoration.replace({ - widget: widget, - kind: 'fold', - foldId, - }).range(contentStart, contentEnd) - ); - } else if (kind === 'hide') { - // Hide content - decorations.push( - Decoration.replace({kind: 'hide'}).range(contentStart, contentEnd) - ); - } - } - } - - // Add the extension to the editor - const hideAndFoldField = StateField.define({ - create: () => Decoration.set(decorations, true), - update: (decoration, transaction) => { - // Check if the the user wants to unfold because they clicked the '...' - const foldIdToRemove = transaction.annotation(unfoldAnnotation); - - if (foldIdToRemove !== undefined) { - // Only remove the specific fold decoration with matching ID - const newDecorations: Range[] = []; - decoration.between(0, Infinity, (from, to, value) => { - if ( - !( - value.spec.kind === 'fold' && - value.spec.foldId === foldIdToRemove - ) - ) { - newDecorations.push(value.range(from, to)); - } - }); - return Decoration.set(newDecorations); - } - - return decoration.map(transaction.changes); - }, - provide: (field) => EditorView.decorations.from(field), - }); - - this._editorView.dispatch({ - effects: StateEffect.appendConfig.of(hideAndFoldField), - }); - } - - private _maskPatternForLang(): RegExp | undefined { - switch (this.type) { - case 'js': - case 'ts': - case 'css': - case 'jsx': - case 'tsx': - // We consume all leading whitespace and one trailing newline for each - // start/end comment. This lets us put start/end comments on their own - // line and indent them like the surrounding without affecting the - // selected region. - return /( *\/\* *playground-(?hide|fold) *\*\/\n?)(?:(.*?)( *\/\* *playground-\k-end *\*\/\n?))?/gs; - case 'html': - return /( *\n?)(?:(.*?)( *\n?))?/gs; - default: - return undefined; - } - } - - private _showDiagnostics() { - if (!this._editorView) { - return; - } - - this._tooltipDiagnostic = undefined; - - if (!this.diagnostics?.length) { - if (this._diagnosticsMouseoverListenerActive) { - this._editorView?.dom.removeEventListener( - 'mouseover', - this._onMouseOverWithDiagnostics - ); - this._diagnosticsMouseoverListenerActive = false; - } - - // Clear diagnostic decorations - this._diagnosticDecorations = Decoration.none; - this._editorView.dispatch({ - effects: StateEffect.appendConfig.of([this._diagnosticField]), - }); - - return; - } - - if (!this._diagnosticsMouseoverListenerActive) { - this._editorView?.dom.addEventListener( - 'mouseover', - this._onMouseOverWithDiagnostics - ); - this._diagnosticsMouseoverListenerActive = true; - } - - // Create decorations for each diagnostic - const decorations: Range[] = []; - - for (let i = 0; i < this.diagnostics.length; i++) { - const diagnostic = this.diagnostics[i]; - - // Create a decoration that adds a CSS class to the range - const decoration = Decoration.mark({ - class: `diagnostic diagnostic-${i}`, - }); - - // Convert line/character positions to absolute positions - const startLine = this._editorView.state.doc.line( - diagnostic.range.start.line + 1 - ); - const endLine = this._editorView.state.doc.line( - diagnostic.range.end.line + 1 - ); - - const startPos = startLine.from + diagnostic.range.start.character; - let endPos = endLine.from + diagnostic.range.end.character; - - // CM6 will throw if decorations don't have a valid range - if (endPos - startPos <= 0) { - endPos = startPos + 1; - } - - decorations.push(decoration.range(startPos, endPos)); - } - - // Set the diagnostic decorations - this._diagnosticDecorations = Decoration.set(decorations, true); - - // Apply the decorations to the editor - this._editorView.dispatch({ - effects: StateEffect.appendConfig.of([this._diagnosticField]), - }); - } - - // Using property assignment syntax so that it's already bound to `this` for - // add/removeEventListener. - private _onMouseOverWithDiagnostics = (event: MouseEvent) => { - if (!this.diagnostics?.length) { - return; - } - // Find the diagnostic by extracting the diagnostic index from the class name - const idxMatch = (event.target as Element).className?.match( - /diagnostic-(\d+)/ - ); - if (idxMatch === null) { - this._tooltipDiagnostic = undefined; - return; - } - const idx = Number(idxMatch[1]); - const diagnostic = this.diagnostics[idx]; - if (diagnostic === this._tooltipDiagnostic?.diagnostic) { - // Already showing the tooltip for this diagnostic. - return; - } - - // Position the tooltip relative to the squiggly code span. To maximize - // available space, place it above/below and left/right depending on which - // quadrant the span is in. - let position = ''; - const hostRect = this.getBoundingClientRect(); - const spanRect = (event.target as Element).getBoundingClientRect(); - const hostCenterY = hostRect.y + hostRect.height / 2; - if (spanRect.y < hostCenterY) { - // Note the rects are viewport relative, so the extra subtractions here - // are to convert to host-relative. - position += `top:${spanRect.y + spanRect.height - hostRect.y}px;`; - } else { - position += `bottom:${hostRect.bottom - spanRect.y}px;`; - } - const hostCenterX = hostRect.x + hostRect.width / 2; - if (spanRect.left < hostCenterX) { - position += `left:${Math.max(0, spanRect.x - hostRect.x)}px`; - } else { - position += `right:${Math.max(0, hostRect.right - spanRect.right)}px`; - } - this._tooltipDiagnostic = {diagnostic, position}; - }; -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-code-editor': PlaygroundCodeEditor; - } -} diff --git a/src/playground-connected-element.ts b/src/playground-connected-element.ts deleted file mode 100644 index 1256b14e..00000000 --- a/src/playground-connected-element.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement} from 'lit'; -import {property, state} from 'lit/decorators.js'; -import {PlaygroundProject} from './playground-project.js'; - -/** - * Base class that connects an element to a . - */ -export class PlaygroundConnectedElement extends LitElement { - /** - * The project that this element is associated with. Either the - * `` node itself, or its `id` in the host scope. - */ - @property() - set project(elementOrId: PlaygroundProject | string | undefined) { - if (typeof elementOrId === 'string') { - // Defer querying the host to a rAF because if the host renders this - // element before the one we're querying for, it might not quite exist - // yet. - requestAnimationFrame(() => { - const root = this.getRootNode() as ShadowRoot | Document; - this._project = - (root.getElementById(elementOrId) as PlaygroundProject | null) ?? - undefined; - }); - } else { - this._project = elementOrId; - } - } - - /** - * The actual `` node, determined by the `project` - * property. - */ - @state() - protected _project?: PlaygroundProject; -} diff --git a/src/playground-file-editor.ts b/src/playground-file-editor.ts deleted file mode 100644 index 6235d4f7..00000000 --- a/src/playground-file-editor.ts +++ /dev/null @@ -1,259 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, PropertyValues} from 'lit'; -import {customElement, property, query} from 'lit/decorators.js'; -import {live} from 'lit/directives/live.js'; - -import './playground-code-editor.js'; -import {PlaygroundConnectedElement} from './playground-connected-element.js'; -import {Extension} from '@codemirror/state'; - -import {PlaygroundProject} from './playground-project.js'; -import {PlaygroundCodeEditor} from './playground-code-editor.js'; -import {CodeEditorChangeData} from './shared/worker-api.js'; - -/** - * A text editor associated with a . - */ -@customElement('playground-file-editor') -export class PlaygroundFileEditor extends PlaygroundConnectedElement { - static override styles = css` - :host { - display: block; - /* Prevents scrollbars from changing container size and shifting layout - slightly. */ - box-sizing: border-box; - height: 350px; - } - - :host, - playground-code-editor { - border-end-start-radius: inherit; - } - - slot { - height: 100%; - display: block; - background: var(--playground-code-background, unset); - } - - slot[name='extensions'] { - display: none; - } - - playground-code-editor { - height: 100%; - border-radius: inherit; - border-top-left-radius: 0; - border-top-right-radius: 0; - } - `; - - @query('playground-code-editor') - private _editor!: PlaygroundCodeEditor; - - /** - * The name of the project file that is currently being displayed. - */ - @property() - filename?: string; - - /** - * If true, display a left-hand-side gutter with line numbers. Default false - * (hidden). - */ - @property({type: Boolean, attribute: 'line-numbers'}) - lineNumbers = false; - - /** - * If true, wrap for long lines. Default false - */ - @property({type: Boolean, attribute: 'line-wrapping'}) - lineWrapping = false; - - /** - * How to handle `playground-hide` and `playground-fold` comments. - * - * See https://github.com/google/playground-elements#hiding--folding for - * more details. - * - * Options: - * - on: Hide and fold regions, and hide the special comments. - * - off: Don't hide or fold regions, but still hide the special comments. - * - off-visible: Don't hide or fold regions, and show the special comments as - * literal text. - */ - @property() - pragmas: 'on' | 'off' | 'off-visible' = 'on'; - - /** - * If true, this editor is not editable. - */ - @property({type: Boolean, reflect: true}) - readonly = false; - - /** - * If true, will disable code completions in the code-editor. - */ - @property({type: Boolean, attribute: 'no-completions'}) - noCompletions = false; - - /** - * A CodeMirror extension or extensions to apply to the editor. - */ - @property({attribute: false}) - extensions?: Extension | Extension[]; - - private get _files() { - return this._project?.files ?? []; - } - - private get _currentFile() { - return this.filename - ? this._files.find((file) => file.name === this.filename) - : undefined; - } - - override async update(changedProperties: PropertyValues) { - if (changedProperties.has('_project')) { - const oldProject = changedProperties.get('_project') as PlaygroundProject; - if (oldProject) { - oldProject.removeEventListener( - 'filesChanged', - this._onProjectFilesChanged - ); - oldProject.removeEventListener('compileDone', this._onCompileDone); - oldProject.removeEventListener( - 'diagnosticsChanged', - this._onDiagnosticsChanged - ); - } - if (this._project) { - this._project.addEventListener( - 'filesChanged', - this._onProjectFilesChanged - ); - this._project.addEventListener('compileDone', this._onCompileDone); - this._project.addEventListener( - 'diagnosticsChanged', - this._onDiagnosticsChanged - ); - } - this._onProjectFilesChanged(); - } - super.update(changedProperties); - } - - override render() { - return html` - ${this._files - ? html` - - - - ` - : html``} - `; - } - - private _onProjectFilesChanged = () => { - this.filename ??= this._files[0]?.name; - this.requestUpdate(); - }; - - private _onCompileDone = () => { - // Propagate diagnostics. - this.requestUpdate(); - }; - - private _onDiagnosticsChanged = () => { - // Propagate diagnostics. - this.requestUpdate(); - }; - - private _onEdit() { - if ( - this._project === undefined || - this._currentFile === undefined || - this._editor.value === undefined - ) { - return; - } - this._project.editFile(this._currentFile, this._editor.value); - } - - private async _onRequestCompletions(e: CustomEvent) { - const codeEditorChangeData = e.detail as CodeEditorChangeData; - codeEditorChangeData.fileName = this.filename ?? ''; - const completions = await this._project?.getCompletions( - codeEditorChangeData - ); - if (completions) { - codeEditorChangeData.provideCompletions(completions); - } - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-file-editor': PlaygroundFileEditor; - } -} - -const mimeTypeToTypeEnum = (mimeType?: string) => { - // TODO: infer type based on extension too - if (mimeType === undefined) { - return; - } - const encodingSepIndex = mimeType.indexOf(';'); - if (encodingSepIndex !== -1) { - mimeType = mimeType.substring(0, encodingSepIndex); - } - switch (mimeType) { - // TypeScript: this is the mime-type returned by servers - // .ts files aren't usually served to browsers, so they don't yet - // have their own mime-type. - case 'video/mp2t': - return 'ts'; - case 'text/javascript': - case 'application/javascript': - return 'js'; - case 'text/jsx': - return 'jsx'; - case 'text/typescript-jsx': - return 'tsx'; - case 'application/json': - return 'json'; - case 'text/html': - return 'html'; - case 'text/css': - return 'css'; - } - return undefined; -}; diff --git a/src/playground-file-system-controls.ts b/src/playground-file-system-controls.ts deleted file mode 100644 index 8ba3b453..00000000 --- a/src/playground-file-system-controls.ts +++ /dev/null @@ -1,319 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, PropertyValues, nothing} from 'lit'; -import {customElement, property, query} from 'lit/decorators.js'; - -// Note despite usual best practices, we should _not_ import -// @material/mwc-list-item directly, because @material/mwc-list already imports -// it, and this causes a duplicate registration error on unpkg.com because of -// redirects. -import '@material/mwc-list'; -import '@material/mwc-button'; -import '@material/mwc-textfield'; -import '@material/mwc-menu/mwc-menu-surface.js'; - -import {MenuSurface} from '@material/mwc-menu/mwc-menu-surface.js'; -import {TextField} from '@material/mwc-textfield'; -import {List} from '@material/mwc-list'; -import {Button} from '@material/mwc-button'; - -import {PlaygroundConnectedElement} from './playground-connected-element.js'; - -/** - * Floating controls for creating, deleting, and renaming files in playground - * virtual file system. - */ -@customElement('playground-file-system-controls') -export class PlaygroundFileSystemControls extends PlaygroundConnectedElement { - static override styles = css` - mwc-menu-surface { - --mdc-theme-primary: var( - --playground-floating-controls-color, - var(--playground-highlight-color, #6200ee) - ); - } - - mwc-menu-surface.menu { - --mdc-typography-subtitle1-font-size: 13px; - --mdc-list-item-graphic-margin: 14px; - } - - mwc-list-item { - min-width: 100px; - height: 40px; - } - - mwc-menu-surface.rename > .wrapper, - mwc-menu-surface.newfile > .wrapper { - padding: 18px; - } - - .actions { - margin-top: 18px; - display: flex; - justify-content: flex-end; - } - - .actions > * { - margin-left: 12px; - } - `; - - /** - * The element that these controls will be positioned adjacent to. - */ - @property({attribute: false}) - anchorElement?: HTMLElement; - - /** - * The kind of control to display: - * - * - closed: Hidden. - * - menu: Menu with "Rename" and "Delete" items. - * - rename: Control for renaming an existing file. - * - newfile: Control for creating a new file. - */ - @property() - state: 'closed' | 'menu' | 'rename' | 'newfile' = 'closed'; - - /** - * When state is "menu" or "newfile", the name of the relevant file. - */ - @property() - filename?: string; - - @query('mwc-menu-surface') - private _surface!: MenuSurface; - - @query('.menu-list') - private _menuList?: List; - - @query('.filename-input') - private _filenameInput?: TextField; - - @query('.submit-button') - private _submitButton?: Button; - - private _postStateChangeRenderDone = false; - - override update(changedProperties: PropertyValues) { - if (changedProperties.has('state')) { - this._postStateChangeRenderDone = false; - } - super.update(changedProperties); - } - - override render() { - return html`
${this._surfaceContents}
`; - } - - override async updated() { - if (this._postStateChangeRenderDone) { - return; - } - if (this.state === 'menu') { - // Focus the first item so that keyboard controls work. - const menuList = this._menuList; - if (menuList) { - await menuList.updateComplete; - menuList.focusItemAtIndex(0); - } - } else if (this.state === 'rename' || this.state === 'newfile') { - // Focus the filename input. - const input = this._filenameInput; - if (input) { - await input.updateComplete; - input.focus(); - if (this.state === 'rename') { - // Pre-select just the basename (e.g. "foo" in "foo.html"), since - // users typically don't want to edit the extension. - input.setSelectionRange(0, input.value.lastIndexOf('.')); - } - } - } - this._postStateChangeRenderDone = true; - } - - private get _surfaceContents() { - switch (this.state) { - case 'closed': - return nothing; - case 'menu': - return this._menu; - case 'rename': - return this._rename; - case 'newfile': - return this._newFile; - } - } - - private get _menu() { - return html` - - - Rename - - - - - - Delete - - - - - - `; - } - - private get _rename() { - return html` - -
- Cancel - Rename -
- `; - } - - private get _newFile() { - return html` - -
- Cancel - Create -
- `; - } - - private _onSurfaceClosed() { - this.state = 'closed'; - } - - private _onClickCancel() { - this._surface.close(); - } - - private _onMenuAction(event: CustomEvent<{index: number}>) { - switch (event.detail.index) { - case 0: - return this._onMenuSelectRename(); - case 1: - return this._onMenuSelectDelete(); - } - } - - private _onMenuSelectRename() { - this.state = 'rename'; - } - - private _onMenuSelectDelete() { - this._surface.close(); - if (this._project && this.filename) { - this._project.deleteFile(this.filename); - } - } - - private _onFilenameInputChange() { - // Force re-evaluation of the _filenameInputValid getter (instead of managing - // an internal property). - this.requestUpdate(); - } - - private get _filenameInputValid(): boolean { - return !!( - this._project && - this._filenameInput && - this._project.isValidNewFilename(this._filenameInput.value) - ); - } - - private _onFilenameInputKeydown(event: KeyboardEvent) { - // Slightly hacky... rather than needing to know which action to perform in - // each context, we just click whatever submit button we're rendering. - if (event.key === 'Enter' && this._submitButton?.disabled === false) { - event.preventDefault(); - this._submitButton.click(); - } - } - - private _onSubmitRename() { - this._surface.close(); - const oldFilename = this.filename; - const newFilename = this._filenameInput?.value; - if (this._project && oldFilename && newFilename) { - this._project.renameFile(oldFilename, newFilename); - } - } - - private _onSubmitNewFile() { - this._surface.close(); - const filename = this._filenameInput?.value; - if (this._project && filename) { - this._project.addFile(filename); - this.dispatchEvent( - new CustomEvent<{filename: string}>('newFile', { - detail: {filename}, - }) - ); - } - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-file-system-controls': PlaygroundFileSystemControls; - } -} diff --git a/src/playground-ide.ts b/src/playground-ide.ts deleted file mode 100644 index ed25f439..00000000 --- a/src/playground-ide.ts +++ /dev/null @@ -1,424 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, html, css, PropertyValues, nothing} from 'lit'; -import {customElement, query, property} from 'lit/decorators.js'; -import {Extension} from '@codemirror/state'; - -import './playground-project.js'; -import './playground-tab-bar.js'; -import './playground-file-editor.js'; -import './playground-preview.js'; -import {PlaygroundProject} from './playground-project.js'; -import {ProjectManifest} from './shared/worker-api.js'; -import {npmVersion, serviceWorkerHash} from './shared/version.js'; - -/** - * A multi-file code editor component with live preview that works without a - * server. - * - * loads a project configuration file and the set of source - * files it describes from the network. The source files can be edited locally. - * To serve the locally edited files to the live preview, - * registers a service worker to serve files to the preview from the main UI - * thread directly, without a network roundtrip. - * - * The project manifest is a JSON file with a "files" property. "files" is an - * object with properties for each file. The key is the filename, relative to - * the project manifest. - * - * Example project manifest: - * ```json - * { - * "files": { - * "./index.html": {}, - * "./my-element.js": {}, - * } - * } - * ``` - * - * Files can also be given as - * - * - * ``` - */ -@customElement('playground-ide') -export class PlaygroundIde extends LitElement { - static override styles = css` - :host { - display: flex; - height: 350px; - min-width: 200px; - border: var(--playground-border, solid 1px #ddd); - /* The invisible resize bar has a high z-index so that it's above - CodeMirror. But we don't want it also above other elements on the page. - Force a new stacking context. */ - isolation: isolate; - } - - #lhs { - display: flex; - flex-direction: column; - height: 100%; - flex: 1; - min-width: 100px; - border-radius: inherit; - border-right: var(--playground-border, solid 1px #ddd); - } - - playground-tab-bar { - border-start-start-radius: inherit; - flex-shrink: 0; - } - - playground-file-editor { - flex: 1; - height: calc(100% - var(--playground-bar-height, 40px)); - } - - #rhs { - height: 100%; - width: max(100px, var(--playground-preview-width, 30%)); - position: relative; - border-radius: inherit; - } - - playground-preview { - height: 100%; - width: 100%; - border-radius: inherit; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - - slot { - display: none; - } - - #resizeBar { - position: absolute; - top: 0; - left: -5px; - width: 10px; - height: 100%; - z-index: 9; - cursor: col-resize; - } - - #resizeOverlay { - display: none; - } - #resizeOverlay.resizing { - display: block; - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - z-index: 99999; - cursor: col-resize; - } - `; - - /** - * A document-relative path to a project configuration file. - * - * When both `projectSrc` and `files` are set, the one set most recently wins. - * Slotted children win only if both `projectSrc` and `files` are undefined. - */ - @property({attribute: 'project-src', hasChanged: () => false}) - get projectSrc(): string | undefined { - // To minimize synchronization complexity, we delegate the `projectSrc` and - // `files` getters/setters directly to our . The only - // case we need to handle is properties set before upgrade or before we - // first render the . - // - // Note we set `hasChanged: () => false` because we don't need to trigger - // `update` when this property changes. (Why be a lit property at all? - // Because we want [1] to respond to attribute changes, and [2] to inherit - // property values set before upgrade). - // - // TODO(aomarks) Maybe a "delegate" decorator for this pattern? - return this._project?.projectSrc ?? this._projectSrcSetBeforeRender; - } - - set projectSrc(src: string | undefined) { - const project = this._project; - if (project) { - project.projectSrc = src; - } else { - this._projectSrcSetBeforeRender = src; - } - } - - /** - * Get or set the project config. - * - * When both `projectSrc` and `config` are set, the one set most recently - * wins. Slotted children win only if both `projectSrc` and `config` are - * undefined. - */ - @property({attribute: false, hasChanged: () => false}) - get config(): ProjectManifest | undefined { - // Note this is declared a @property only to capture properties set before - // upgrade. Attribute reflection and update lifecycle disabled because they - // are not needed in this case. - return this._project?.config ?? this._configSetBeforeRender; - } - set config(config: ProjectManifest | undefined) { - const project = this._project; - if (project) { - project.config = config; - } else { - this._configSetBeforeRender = config; - } - } - - /** - * Base URL for script execution sandbox. - * - * It is highly advised to change this property to a URL on a separate origin - * which has no privileges to perform sensitive actions or access sensitive - * data. This is because this element will execute arbitrary JavaScript, and - * does not have the ability to sanitize or sandbox it. - * - * This URL must host the following files from the playground-elements - * package: - * 1. playground-service-worker.js - * 2. playground-service-worker-proxy.html - * - * Defaults to the directory containing the script that defines this element - * on the same origin (typically something like - * "/node_modules/playground-elements/"). - */ - @property({attribute: 'sandbox-base-url'}) - sandboxBaseUrl = `https://unpkg.com/playground-elements@${npmVersion}/`; - - /** - * The service worker scope to register on - */ - // TODO: generate this? - @property({attribute: 'sandbox-scope'}) - sandboxScope = `__playground_swfs_${serviceWorkerHash}/`; - - /** - * Base URL for the CDN used to resolve bare module specifiers. - * - * Examples: - * - "" (default, but resolves to "https://unpkg.com") - * - "https://unpkg.com" - * - "https://cdn.jsdelivr.net/npm" - */ - @property({attribute: 'cdn-base-url'}) - cdnBaseUrl = ''; - - /** - * 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'}) - editableFileSystem = false; - - /** - * If true, display a left-hand-side gutter with line numbers. Default false - * (hidden). - */ - @property({type: Boolean, attribute: 'line-numbers'}) - lineNumbers = false; - - /** - * If true, wrap for long lines. Default false - */ - @property({type: Boolean, attribute: 'line-wrapping'}) - lineWrapping = false; - - /** - * If true, allow the user to change the relative size of the LHS editor and - * RHS preview by clicking and dragging in the space between them. - */ - @property({type: Boolean}) - resizable = false; - - /** - * How to handle `playground-hide` and `playground-fold` comments. - * - * See https://github.com/google/playground-elements#hiding--folding for - * more details. - * - * Options: - * - on: Hide and fold regions, and hide the special comments. - * - off: Don't hide or fold regions, but still hide the special comments. - * - off-visible: Don't hide or fold regions, and show the special comments as - * literal text. - */ - @property() - pragmas: 'on' | 'off' | 'off-visible' = 'on'; - - /** - * The HTML file used in the preview. - */ - @property({attribute: 'html-file'}) - htmlFile = 'index.html'; - - /** - * If true, will disable code completions in the code-editor. - */ - @property({type: Boolean, attribute: 'no-completions'}) - noCompletions = false; - - /** - * A CodeMirror extension or extensions to apply to the editor. - */ - @property({attribute: false}) - extensions?: Extension | Extension[]; - - /** - * Indicates whether the user has modified, added, or removed any project - * files. Resets whenever a new project is loaded. - */ - get modified(): boolean { - return this._project?.modified ?? false; - } - - @query('playground-project') - private _project!: PlaygroundProject | null; - - @query('#resizeBar') - private _resizeBar!: HTMLDivElement; - - @query('#rhs') - private _rhs!: HTMLDivElement; - - private _configSetBeforeRender?: ProjectManifest; - private _projectSrcSetBeforeRender?: string; - - override render() { - const projectId = 'project'; - const editorId = 'editor'; - return html` - - - - -
- - - - - - -
- -
- ${this.resizable - ? html`
` - : nothing} - - -
- `; - } - - override firstUpdated() { - if (this._configSetBeforeRender) { - this._project!.config = this._configSetBeforeRender; - this._configSetBeforeRender = undefined; - } - if (this._projectSrcSetBeforeRender) { - this._project!.projectSrc = this._projectSrcSetBeforeRender; - this._projectSrcSetBeforeRender = undefined; - } - } - - override async update(changedProperties: PropertyValues) { - if (changedProperties.has('resizable') && this.resizable === false) { - // Note we set this property on the RHS element instead of the host so - // that when "resizable" is toggled, we don't reset a host value that the - // user might have set. - this._rhs?.style.removeProperty('--playground-preview-width'); - } - super.update(changedProperties); - } - - private _onResizeBarPointerdown({pointerId}: PointerEvent) { - const bar = this._resizeBar; - bar.setPointerCapture(pointerId); - - const rhsStyle = this._rhs.style; - const {left: hostLeft, right: hostRight} = this.getBoundingClientRect(); - const hostWidth = hostRight - hostLeft; - const rhsMinWidth = 100; - const rhsMaxWidth = hostWidth - 100; - - const onPointermove = (event: PointerEvent) => { - const rhsWidth = Math.min( - rhsMaxWidth, - Math.max(rhsMinWidth, hostRight - event.clientX) - ); - const percent = (rhsWidth / hostWidth) * 100; - rhsStyle.setProperty('--playground-preview-width', `${percent}%`); - }; - bar.addEventListener('pointermove', onPointermove); - - const onPointerup = () => { - bar.releasePointerCapture(pointerId); - bar.removeEventListener('pointermove', onPointermove); - bar.removeEventListener('pointerup', onPointerup); - }; - bar.addEventListener('pointerup', onPointerup); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-ide': PlaygroundIde; - } -} diff --git a/src/playground-preview.ts b/src/playground-preview.ts deleted file mode 100644 index 44fc28bf..00000000 --- a/src/playground-preview.ts +++ /dev/null @@ -1,335 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, PropertyValues, nothing, TemplateResult} from 'lit'; -import {customElement, property, query, state} from 'lit/decorators.js'; -import {classMap} from 'lit/directives/class-map.js'; -import '@material/mwc-icon-button'; -import {PlaygroundProject} from './playground-project.js'; -import '@material/mwc-linear-progress'; -import {PlaygroundConnectedElement} from './playground-connected-element.js'; -import './internal/overlay.js'; - -/** - * An HTML preview component consisting of an iframe and a floating reload - * button. - * - * @fires reload - Fired when the user clicks the reload button - */ -@customElement('playground-preview') -export class PlaygroundPreview extends PlaygroundConnectedElement { - static override styles = css` - :host { - display: flex; - flex-direction: column; - background: white; - font-family: sans-serif; - height: 350px; - position: relative; /* for the error message overlay */ - } - - #toolbar { - flex: 0 0 var(--playground-bar-height, 40px); - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: var(--playground-border, solid 1px #ddd); - font-size: 15px; - color: var(--playground-preview-toolbar-foreground-color, #444); - border-radius: inherit; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - background: var(--playground-preview-toolbar-background, white); - } - - #location { - margin: 0 10px; - } - - #reload-button { - --mdc-icon-button-size: 30px; - --mdc-icon-size: 18px; - } - - #content { - max-height: 100%; - position: relative; - flex: 1; - } - - #content.error { - display: none; - } - - #error { - padding: 0 20px; - } - - mwc-linear-progress { - /* There is no way to directly specify the height of a linear progress - bar, but zooming works well enough. It's 4px by default, and we want it to - be 2px to match the tab bar indicator.*/ - zoom: 0.5; - --mdc-linear-progress-buffer-color: transparent; - position: absolute; - top: -6px; - width: 100%; - --mdc-theme-primary: var(--playground-highlight-color, #6200ee); - } - - iframe, - slot { - width: 100%; - height: 100%; - } - - iframe { - border: none; - } - - [hidden] { - display: none; - } - `; - - /** - * The HTML file used in the preview. - */ - @property({attribute: 'html-file'}) - htmlFile = 'index.html'; - - /** - * The string to display in the location bar. - */ - @property() - location = 'Result'; - - @query('iframe', true) - iframe!: HTMLIFrameElement | null; - - @query('slot') - private _slot?: HTMLSlotElement; - - /** - * Whether the iframe is currently loading. - */ - @state() - private _loading = true; - - /** - * Whether to show the loading bar. - */ - @state() - private _showLoadingBar = false; - - /** - * Whether the iframe has fired its "load" event at least once. - */ - @state() - private _loadedAtLeastOnce = false; - - /** - * An error to display instead of the iframe when something has gone wrong. - */ - @state() - private _error?: TemplateResult; - - constructor() { - super(); - if (navigator.serviceWorker === undefined) { - this._error = html`

- Sorry! Preview unavailable because this browser doesn't - support - service workers. -

-

- Note: Firefox - doesn't - support service workers in private browsing mode. -

`; - } - } - - override update(changedProperties: PropertyValues) { - if (changedProperties.has('_project')) { - const oldProject = changedProperties.get('_project') as PlaygroundProject; - if (oldProject) { - oldProject.removeEventListener('urlChanged', this.reload); - // To be more responsive, we start loading as soon as compilation - // starts. This is safe because requests block on compilation finishing. - oldProject.removeEventListener('compileStart', this.reload); - } - if (this._project) { - this._project.addEventListener('urlChanged', this.reload); - this._project.addEventListener('compileStart', this.reload); - } - } - super.update(changedProperties); - } - - private get _indexUrl() { - const base = this._project?.baseUrl; - if (!base || !this.htmlFile) { - return ''; - } - const url = new URL(this.htmlFile, base); - return url.toString(); - } - - override render() { - return html` -
- ${this.location} - - - - - - -
- -
- - - ${this._loadedAtLeastOnce ? nothing : html``} - - -
- - ${this._error - ? html` - - ${this._error} - ` - : nothing} - `; - } - - override updated() { - // TODO(aomarks) If we instead use an `ifDefined(this._indexUrl)` binding in - // the template, then the preview loads twice. I must be doing something - // dumb, but this hacky way of synchronizing the src works correctly for - // now. Figure out the more elegant solution. - if (this.iframe && this.iframe.src !== this._indexUrl) { - this.iframe.src = this._indexUrl; - } - } - - reload = () => { - const iframe = this.iframe; - if (!iframe) { - return; - } - // Reloading the iframe can cause a history entry to be added to the parent - // window (on Chrome but not Firefox, and only when the parent/iframe origins - // are different). Removing the iframe from the DOM while we initiate the - // reload prevents a history entry from being added. - const {parentNode, nextSibling} = iframe; - if (parentNode) { - iframe.remove(); - } - // Note we can't use contentWindow.location.reload() here, because the - // IFrame might be on a different origin. - iframe.src = ''; - iframe.src = this._indexUrl; - if (parentNode) { - parentNode.insertBefore(iframe, nextSibling); - } - this._loading = true; - this._showLoadingBar = true; - }; - - override async firstUpdated() { - // Loading should be initially indicated only when we're not pre-rendering, - // because in that case there should be no visible change once the actual - // iframe loads, and the indicator is distracting. - if (this._loading && !this._slotHasAnyVisibleChildren()) { - this._showLoadingBar = true; - } - - // The latest version of MWC forwards the aria-label attribute to the - // progressbar role correctly - // (https://github.com/material-components/material-components-web-components/pull/2264), - // but until 0.21.0 is released we'll need to fix it up ourselves. - const progress = this.shadowRoot!.querySelector('mwc-linear-progress')!; - await progress.updateComplete; - progress.shadowRoot - ?.querySelector('[role=progressbar]') - ?.setAttribute('aria-label', 'Preview is loading'); - } - - private _slotHasAnyVisibleChildren() { - const assigned = this._slot?.assignedNodes({flatten: true}); - if (!assigned) { - return false; - } - for (const node of assigned) { - if (node.nodeType === Node.COMMENT_NODE) { - continue; - } - if ( - node.nodeType === Node.TEXT_NODE && - (node.textContent || '').trim() === '' - ) { - continue; - } - return true; - } - return false; - } - - private _onIframeLoad() { - if (this._indexUrl) { - // Check "src" because the iframe will fire a "load" for a blank page - // before "src" is set. - this._loading = false; - this._loadedAtLeastOnce = true; - this._showLoadingBar = false; - } - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-preview': PlaygroundPreview; - } -} diff --git a/src/playground-project.ts b/src/playground-project.ts deleted file mode 100644 index 906c86f3..00000000 --- a/src/playground-project.ts +++ /dev/null @@ -1,1092 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LitElement, html, css, PropertyValues} from 'lit'; -import {customElement, property, query, state} from 'lit/decorators.js'; -import {wrap, Remote, proxy} from 'comlink'; - -import { - SampleFile, - ServiceWorkerAPI, - ProjectManifest, - PlaygroundMessage, - WorkerAPI, - CONFIGURE_PROXY, - CONNECT_PROJECT_TO_SW, - ACKNOWLEDGE_SW_CONNECTION, - ModuleImportMap, - HttpError, - UPDATE_SERVICE_WORKER, - CodeEditorChangeData, - CompletionInfoWithDetails, -} from './shared/worker-api.js'; -import { - getRandomString, - endWithSlash, - forceSkypackRawMode, -} from './shared/util.js'; -import { - completionEntriesAsEditorCompletions, - populateCompletionInfoWithDetailGetters, - sortCompletionItems, -} from './shared/completion-utils.js'; -import {npmVersion, serviceWorkerHash} from './shared/version.js'; -import {Deferred} from './shared/deferred.js'; -import {PlaygroundBuild} from './internal/build.js'; - -import {Diagnostic} from 'vscode-languageserver-protocol'; - -// Each has a unique session ID used to scope requests from -// the preview iframes. -const sessions = new Set(); -const generateUniqueSessionId = (): string => { - let sessionId; - do { - sessionId = getRandomString(); - } while (sessions.has(sessionId)); - sessions.add(sessionId); - return sessionId; -}; - -declare global { - interface HTMLElementEventMap { - filesChanged: FilesChangedEvent; - } -} - -export class FilesChangedEvent extends Event { - projectLoaded: boolean; - constructor(projectLoaded = false) { - super('filesChanged'); - this.projectLoaded = projectLoaded; - } -} - -/** - * Coordinates and elements. - */ -@customElement('playground-project') -export class PlaygroundProject extends LitElement { - /** - * A document-relative path to a project configuration file. - * - * When both `projectSrc` and `files` are set, the one set most recently wins. - * Slotted children win only if both `projectSrc` and `files` are undefined - */ - @property({attribute: 'project-src', hasChanged: () => false}) - get projectSrc(): string | undefined { - if (this._source.type === 'url') { - return this._source.url; - } - return undefined; - } - - set projectSrc(url: string | undefined) { - if (url) { - if (this._source.type !== 'url' || this._source.url !== url) { - this._source = {type: 'url', url}; - } - } else if (this._source.type === 'url') { - this._source = {type: 'none'}; - } - } - - /** - * Get or set the project config. - * - * When both `projectSrc` and `config` are set, the one set most recently - * wins. Slotted children win only if both `projectSrc` and `config` are - * undefined. - */ - @property({attribute: false, hasChanged: () => false}) - get config(): ProjectManifest | undefined { - // Note this is declared a @property only to capture properties set before - // upgrade. Attribute reflection and update lifecycle disabled because they - // are not needed in this case. - return { - files: Object.fromEntries( - (this._files ?? []).map((file) => [ - file.name, - { - ...file, - name: undefined, - }, - ]) - ), - importMap: this._validImportMap, - }; - } - set config(config: ProjectManifest | undefined) { - if (config) { - this._source = {type: 'direct', config}; - } else if (this._source.type === 'direct') { - this._source = {type: 'none'}; - } - } - - get files(): SampleFile[] | undefined { - return this._files; - } - - /** - * This property is used to settle which of the multiple ways a project can be - * specified was set most recently. - */ - @state() - private _source: - | { - type: 'none'; - } - | { - type: 'direct'; - config: ProjectManifest; - } - | { - type: 'url'; - url: string; - } - | { - type: 'slot'; - files: SampleFile[]; - importMap: ModuleImportMap; - } = {type: 'none'}; - - /** - * Base URL for script execution sandbox. - * - * It is highly advised to change this property to a URL on a separate origin - * which has no privileges to perform sensitive actions or access sensitive - * data. This is because this element will execute arbitrary JavaScript, and - * does not have the ability to sanitize or sandbox it. - * - * This URL must host the following files from the playground-elements - * package: - * 1. playground-service-worker.js - * 2. playground-service-worker-proxy.html - * - * Defaults to the directory containing the script that defines this element - * on the same origin (typically something like - * "/node_modules/playground-elements/"). - */ - @property({attribute: 'sandbox-base-url'}) - sandboxBaseUrl = `https://unpkg.com/playground-elements@${npmVersion}/`; - - /** - * Base URL for the CDN used to resolve bare module specifiers. - * - * Examples: - * - "" (default, but resolves to "https://unpkg.com") - * - "https://unpkg.com" (default) - * - "https://cdn.jsdelivr.net/npm" - */ - @property({attribute: 'cdn-base-url'}) - cdnBaseUrl = ''; - - /** - * The service worker scope to register on - */ - // TODO: generate this? - @property({attribute: 'sandbox-scope'}) - sandboxScope = `__playground_swfs_${serviceWorkerHash}/`; - - private _build?: PlaygroundBuild; - - /** - * Map from filename to array of Language Server Protocol diagnostics - * resulting from the latest compilation. - */ - get diagnostics(): Map | undefined { - return this._build?.diagnostics; - } - - private _completionInfo?: CompletionInfoWithDetails; - - /** - * A pristine copy of the original project files, used for the `modified` - * getter. - */ - private _pristineFiles?: SampleFile[]; - - // Store config value separately to maintain proper resolution order - private _configCdnBaseUrl?: string; - - /** - * Cached value for the `modified` getter. When undefined, the modified state - * is unknown and must be computed. - */ - private _modified: boolean | undefined = false; - - /** - * Indicates whether the user has modified, added, or removed any project - * files. Resets whenever a new project is loaded. - */ - get modified(): boolean { - if (this._modified === undefined) { - if (this._files === undefined && this._pristineFiles === undefined) { - this._modified = false; - } else if ( - this._files === undefined || - this._pristineFiles === undefined - ) { - this._modified = true; - } else { - this._modified = !playgroundFilesDeepEqual( - this._files, - this._pristineFiles - ); - } - } - return this._modified; - } - - /** - * A unique identifier for this instance so the service worker can keep an - * independent cache of files for it. - */ - private readonly _sessionId: string = generateUniqueSessionId(); - - /** - * The active project files. - */ - private _files?: SampleFile[]; - - @state() - private _serviceWorkerAPI?: Remote; - - private _deferredTypeScriptWorkerApi = new Deferred>(); - - private _validImportMap: ModuleImportMap = {}; - - private set _importMap(importMap: ModuleImportMap) { - const errors = validateImportMap(importMap); - if (errors.length > 0) { - for (const error of errors) { - console.error(error); - } - this._validImportMap = {}; - } else { - this._validImportMap = importMap; - } - } - - private get _importMap(): ModuleImportMap { - return this._validImportMap; - } - - @query('slot') - private _slot!: HTMLSlotElement; - - @query('iframe') - private _serviceWorkerProxyIframe!: HTMLIFrameElement; - - private get _normalizedSandboxBaseUrl() { - const url = new URL(this.sandboxBaseUrl, import.meta.url); - url.pathname = endWithSlash(url.pathname); - return url; - } - - get baseUrl() { - // Make sure that we've connected to the Service Worker and loaded the - // project files before generating the preview URL. This ensures that there - // are files to load when the iframe navigates to the URL. - if (this._serviceWorkerAPI === undefined || this._files === undefined) { - return undefined; - } - // TODO (justinfagnani): lookup URL to show from project config - const indexUrl = new URL( - `${endWithSlash(this.sandboxScope)}${this._sessionId}/`, - this._normalizedSandboxBaseUrl - ); - return indexUrl.href; - } - - private get _serviceWorkerProxyIframeUrl() { - // We include the session ID as a query parameter so that the service worker - // can figure out which proxy client goes with which session. We use an - // #anchor instead of a ?queryParam because unpkg.com strips all - // ?queryParams. - return new URL( - `playground-service-worker-proxy.html#playground-session-id=${this._sessionId}`, - this._normalizedSandboxBaseUrl - ).href; - } - - static override styles = css` - iframe { - display: none; - } - `; - - override async update(changedProperties: PropertyValues) { - if (changedProperties.has('_source')) { - void this._loadProjectFromSource(); - } - if ( - changedProperties.has('sandboxScope') || - changedProperties.has('sandboxBaseUrl') || - changedProperties.has('_serviceWorkerAPI') - ) { - this.dispatchEvent(new CustomEvent('urlChanged')); - } - if ( - changedProperties.has('cdnBaseUrl') && - // do not trigger a reload on first render - changedProperties.get('cdnBaseUrl') !== undefined - ) { - // needs to trigger a full reload and recompile as if we had made a file - // change - this._modified = undefined; - void this.saveDebounced(); - } - super.update(changedProperties); - } - - private async _loadProjectFromSource() { - const source = this._source; - switch (source.type) { - case 'none': - this._files = undefined; - this._configCdnBaseUrl = undefined; - this._importMap = {}; - break; - case 'direct': - { - const {files, importMap} = await expandProjectConfig( - source.config, - document.baseURI - ); - // Note the source could have changed while fetching, hence the - // double-check here. - if (source !== this._source) { - return; - } - this._files = files; - this._importMap = importMap; - this._configCdnBaseUrl = source.config.cdnBaseUrl; - } - break; - case 'slot': - this._files = source.files; - this._importMap = source.importMap; - this._configCdnBaseUrl = undefined; - break; - case 'url': - { - const {files, importMap, cdnBaseUrl} = await fetchProjectConfig( - new URL(source.url, document.baseURI).href - ); - // Note the source could have changed while fetching, hence the - // double-check here. - if (source !== this._source) { - return; - } - this._files = files; - this._importMap = importMap; - this._configCdnBaseUrl = cdnBaseUrl; - } - break; - default: - // Exhaustive check. - source as void; - break; - } - this._pristineFiles = - this._files && (JSON.parse(JSON.stringify(this._files)) as SampleFile[]); - this._modified = false; - this.dispatchEvent(new FilesChangedEvent(true)); - void this.save(); - } - - override render() { - return html` - - - `; - } - - private _slotChange() { - const {type} = this._source; - if (type !== 'none' && type !== 'slot') { - // It's a little tricky to do "most recent wins" with slots, because the - // slotchange event will always fire after the first render, giving the - // illusion that it was set after the other methods. We could do some - // extra book-keeping to make this work, but it doesn't seem worth the - // complexity, because it should be very rare to [1] set a `projectSrc` or - // `files`, and then [2] slot some new children. - return; - } - const files: SampleFile[] = []; - let importMap: ModuleImportMap | undefined = undefined; - for (const s of this._slot.assignedElements({flatten: true})) { - const typeAttr = s.getAttribute('type'); - if (!typeAttr?.startsWith('sample/')) { - continue; - } - const fileType = typeAttr.substring('sample/'.length); - let content = s.textContent ?? ''; - if (fileType === 'html') { - // Replace usages of `</script>` with ``. Match against - // `</` so that other usages of < aren't replaced. - content = content.replace(/<\//g, ' 0 || importMap !== undefined) { - this._source = {type: 'slot', files, importMap: importMap ?? {}}; - } - } - - override async firstUpdated() { - const typescriptWorkerScriptUrl = forceSkypackRawMode( - new URL('./playground-typescript-worker.js', import.meta.url) - ); - let worker: Worker; - if (typescriptWorkerScriptUrl.origin === window.location.origin) { - // Easy case. - worker = new Worker(typescriptWorkerScriptUrl, {type: 'module'}); - } else { - // If the worker script is different-origin, we need to fetch it ourselves - // and create a blob URL. - const resp = await fetch(typescriptWorkerScriptUrl.href); - const text = await resp.text(); - const blobUrl = URL.createObjectURL( - new Blob([text], {type: 'application/javascript'}) - ); - worker = new Worker(blobUrl); - URL.revokeObjectURL(blobUrl); - } - this._deferredTypeScriptWorkerApi.resolve(wrap(worker)); - } - - private _onServiceWorkerProxyIframeLoad() { - // This channel is persistent, and is only used to receive new service - // worker channel ports from the proxy iframe. Note we can get new service - // worker ports at any time from the proxy, when the service worker updates. - const {port1, port2} = new MessageChannel(); - port1.addEventListener( - 'message', - (event: MessageEvent) => { - if (event.data.type === CONNECT_PROJECT_TO_SW) { - this._onNewServiceWorkerPort(event.data.port); - } - } - ); - port1.start(); - this._postMessageToServiceWorkerProxyIframe( - { - type: CONFIGURE_PROXY, - scope: this.sandboxScope, - port: port2, - }, - [port2] - ); - } - - private _onNewServiceWorkerPort(port: MessagePort) { - const onMessage = (e: MessageEvent) => { - if (e.data.type === ACKNOWLEDGE_SW_CONNECTION) { - port.removeEventListener('message', onMessage); - if (e.data.version === serviceWorkerHash) { - this._serviceWorkerAPI = wrap(port); - void this._serviceWorkerAPI.setFileAPI( - proxy({ - getFile: (name: string) => this._getFile(name), - }), - this._sessionId - ); - } else { - // Version mismatch. Request the service worker be updated - // immediately. We'll get back here again after it updates via a - // CONNECT_PROJECT_TO_SW message from the proxy. - console.info( - `Playground service worker is outdated. ` + - `Want ${serviceWorkerHash} but got ${e.data.version}. ` + - `Waiting for update.` - ); - this._postMessageToServiceWorkerProxyIframe({ - type: UPDATE_SERVICE_WORKER, - }); - } - } - }; - port.addEventListener('message', onMessage); - port.start(); - } - - private _postMessageToServiceWorkerProxyIframe( - message: PlaygroundMessage, - transfer?: Transferable[] - ) { - // This iframe exists to proxy messages between this project and the service - // worker, because the service worker may be running on a different origin - // for security. - const iframeWindow = this._serviceWorkerProxyIframe.contentWindow; - if (!iframeWindow) { - throw new Error( - 'Unexpected internal error: ' + - ' service worker proxy iframe had no contentWindow' - ); - } - // We could constrain targetOrigin to - // `this._normalizedSandboxBaseUrl.origin`, but unclear if that provides any - // security benefit, and would add the limitation that the sandboxBaseUrl - // can't redirect to another origin. - iframeWindow.postMessage(message, '*', transfer); - } - - private async _getFile(name: string): Promise { - if (this._build === undefined) { - return { - status: /* Service Unavailable */ 503, - body: 'Playground build not started', - }; - } - return this._build.getFile(name); - } - - /** - * Build this project immediately, cancelling any previous build. - */ - async save() { - this._build?.cancel(); - const build = new PlaygroundBuild(() => { - this.dispatchEvent(new CustomEvent('diagnosticsChanged')); - }); - this._build = build; - this.dispatchEvent(new CustomEvent('compileStart')); - const workerApi = await this._deferredTypeScriptWorkerApi.promise; - if (build.state() !== 'active') { - return; - } - const cdnBaseUrl = this._getEffectiveCdnBaseUrl(); - void workerApi.compileProject( - this._files ?? [], - { - importMap: this._importMap, - cdnBaseUrl, - }, - proxy((result) => build.onOutput(result)) - ); - await build.stateChange; - if (build.state() !== 'done') { - return; - } - this.dispatchEvent(new CustomEvent('compileDone')); - } - - async getCompletions(changeData: CodeEditorChangeData) { - const tokenUnderCursorAsString = changeData.tokenUnderCursor.trim(); - // If the user is starting a new word, we need to fetch relevant completion items - // from the TypeScript Language Service. If we are however building on top of - // a already fetched completions list, by narrowing keyword matches, we can - // just work with what we have fetched earlier. - if (!changeData.isRefinement) { - const workerApi = await this._deferredTypeScriptWorkerApi.promise; - const completionInfo = await workerApi.getCompletions( - changeData.fileName, - changeData.fileContent, - tokenUnderCursorAsString, - changeData.cursorIndex, - { - importMap: this._importMap, - cdnBaseUrl: this._getEffectiveCdnBaseUrl(), - } - ); - if (completionInfo) { - const getCompletionDetailsFunction = - this._getCompletionDetails.bind(this); - // We pre-generate the getter for each completion item's details, so that - // if neeeded, they can fetch their details themselves. - this._completionInfo = populateCompletionInfoWithDetailGetters( - completionInfo, - changeData.fileName, - changeData.cursorIndex, - getCompletionDetailsFunction - ); - } - } - - const skipFuzzySearch = - changeData.tokenUnderCursor === '.' || changeData.tokenUnderCursor === ''; - // In the case that the search word is a period or empty, we don't really - // have any material to fuzzy find with, so we don't have need - // for running the search results through a fuzzy search. - // For this case, we just return the entries as completion items as is. - let completions = []; - if (skipFuzzySearch) { - completions = completionEntriesAsEditorCompletions( - this._completionInfo?.entries, - changeData.tokenUnderCursor - ); - } else { - completions = sortCompletionItems( - this._completionInfo?.entries, - tokenUnderCursorAsString - ); - } - // We want to pre-fetch the first completion item, if it's present - // so that when the data gets to the code-editor, the detail hopefully - // is already loaded. - // - // Note invoking this getter actually triggers the fetch. - void completions[0]?.details; - return completions; - } - - private async _getCompletionDetails( - filename: string, - cursorIndex: number, - completionWord: string - ) { - const workerApi = await this._deferredTypeScriptWorkerApi.promise; - const completionItemDetails = await workerApi.getCompletionItemDetails( - filename, - cursorIndex, - { - importMap: this._importMap, - cdnBaseUrl: this._getEffectiveCdnBaseUrl(), - }, - completionWord - ); - - return completionItemDetails; - } - - private lastSave = Promise.resolve(); - private savePending = false; - /** - * A simple debouncer that aims for maximal responsiveness when compiles are fast. - * - * There is no meaning to when the returned promise resolves. - */ - async saveDebounced() { - if (this.savePending) { - return; - } - this.savePending = true; - await this.lastSave; - this.savePending = false; - this.lastSave = this.save(); - } - - isValidNewFilename(name: string): boolean { - if (!name) { - return false; - } - const existing = this._files?.find((file) => file.name === name); - if (existing !== undefined) { - return existing.hidden === true; - } - return true; - } - - editFile(file: SampleFile, newContent: string) { - // Note this method takes the file object itself rather than the name like - // add/delete/rename, because edits happen at high frequency so we don't - // want to be doing any searches. - file.content = newContent; - this._modified = undefined; - void this.saveDebounced(); - } - - addFile(name: string) { - if (!this._files || !this.isValidNewFilename(name)) { - return; - } - const existing = this._files?.find((file) => file.name === name); - if (existing?.hidden === true) { - // If a file already exists but is hidden, then we allow the user to - // "create" it, which is actually unhiding it. - existing.hidden = false; - } else { - this._files.push({ - name, - content: '', - contentType: typeFromFilename(name), - }); - } - this._modified = undefined; - this.requestUpdate(); - this.dispatchEvent(new FilesChangedEvent()); - void this.save(); - } - - deleteFile(filename: string) { - if (!this._files) { - return; - } - const idx = this._files.findIndex((file) => file.name === filename); - if (idx < 0) { - return; - } - this._files = [...this._files.slice(0, idx), ...this._files.slice(idx + 1)]; - this._modified = undefined; - this.dispatchEvent(new FilesChangedEvent()); - void this.save(); - } - - renameFile(oldName: string, newName: string) { - if (!oldName || !this._files) { - return; - } - if (!this.isValidNewFilename(newName)) { - return; - } - const file = this._files.find((file) => file.name === oldName); - if (!file) { - return; - } - // TODO(aomarks) Check name is unique; - file.name = newName; - file.contentType = typeFromFilename(newName); - this._files = [...this._files]; - this._modified = undefined; - this.dispatchEvent(new FilesChangedEvent()); - void this.save(); - } - - /** - * Returns the effective CDN base URL, considering all possible sources - * in the correct priority order. - */ - private _getEffectiveCdnBaseUrl(): string { - return this.cdnBaseUrl || this._configCdnBaseUrl || 'https://unpkg.com'; - } -} - -/** - * Fetches and expands the given JSON project config URL. - */ -const fetchProjectConfig = async ( - url: string, - alreadyFetchedFilenames = new Set(), - alreadyFetchedConfigUrls = new Set() -): Promise<{ - files: Array; - importMap: ModuleImportMap; - cdnBaseUrl?: string; -}> => { - if (alreadyFetchedConfigUrls.has(url)) { - throw new Error( - `Circular project config extends: ${[ - ...alreadyFetchedConfigUrls.values(), - url, - ].join(' extends ')}` - ); - } - alreadyFetchedConfigUrls.add(url); - const resp = await fetch(url); - if (resp.status !== 200) { - throw new Error( - `Error ${ - resp.status - } fetching project config from ${url}: ${await resp.text()}` - ); - } - let config: Partial; - try { - config = await resp.json(); - } catch (e) { - throw new Error( - `Error parsing project config JSON from ${url}: ${(e as Error).message}` - ); - } - const result = await expandProjectConfig( - config, - url, - alreadyFetchedFilenames, - alreadyFetchedConfigUrls - ); - - return { - ...result, - cdnBaseUrl: config.cdnBaseUrl, - }; -}; - -/** - * Expands a partial project config by following its `extends` property, and - * fetching the content for all files. - */ -const expandProjectConfig = async ( - config: ProjectManifest, - baseUrl: string, - alreadyFetchedFilenames = new Set(), - alreadyFetchedConfigUrls = new Set() -): Promise<{ - files: Array; - importMap: ModuleImportMap; - cdnBaseUrl?: string; -}> => { - const filePromises: Array> = []; - for (const [filename, info] of Object.entries(config.files ?? {})) { - // A higher precedence config is already handling this file. - if (alreadyFetchedFilenames.has(filename)) { - continue; - } - alreadyFetchedFilenames.add(filename); - if (info.content === undefined) { - filePromises.push( - (async () => { - const resp = await fetch(new URL(filename, baseUrl).href); - - return { - ...info, - name: filename, - content: await resp.text(), - contentType: - resp.headers.get('Content-Type')?.toLowerCase() ?? 'text/plain', - }; - })() - ); - } else { - filePromises.push( - Promise.resolve({ - ...info, - name: filename, - content: info.content ?? '', - contentType: typeFromFilename(filename) ?? 'text/plain', - }) - ); - } - } - - // Start extends config fetch before we block on file fetches. - const extendsConfigPromise = config.extends - ? fetchProjectConfig( - new URL(config.extends, baseUrl).href, - alreadyFetchedFilenames, - alreadyFetchedConfigUrls - ) - : undefined; - - const files = await Promise.all(filePromises); - const importMap = config.importMap ?? {}; - let cdnBaseUrl = config.cdnBaseUrl; - - if (extendsConfigPromise) { - const extendsConfig = await extendsConfigPromise; - // Parent files go after our own. - files.push(...extendsConfig.files); - importMap.imports = { - ...extendsConfig.importMap?.imports, - // Our imports take precedence over our parents. - ...importMap.imports, - }; - // Only use parent's cdn if we don't have our own - cdnBaseUrl = cdnBaseUrl ?? extendsConfig.cdnBaseUrl; - } - - return {files, importMap, cdnBaseUrl}; -}; - -const typeFromFilename = (filename: string) => { - const idx = filename.lastIndexOf('.'); - if (idx === -1 || idx === filename.length - 1) { - return undefined; - } - const extension = filename.slice(idx + 1); - return typeEnumToMimeType(extension); -}; - -const typeEnumToMimeType = (type?: string) => { - if (type === undefined) { - return; - } - - switch (type) { - // TypeScript - case 'ts': - return 'video/mp2t'; - case 'js': - return 'application/javascript; charset=utf-8'; - case 'json': - return 'application/json; charset=utf-8'; - case 'jsx': - return 'text/jsx; charset=utf-8'; - case 'tsx': - return 'text/typescript-jsx; charset=utf-8'; - case 'html': - return 'text/html; charset=utf-8'; - case 'css': - return 'text/css; charset=utf-8'; - // taken from MDN's common MIME types - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types - case 'svg': - return 'image/svg+xml'; - case 'png': - return 'image/png'; - case 'gif': - return 'image/gif'; - case 'jpeg': - case 'jpg': - return 'image/jpeg'; - case 'ico': - return 'image/vnd.microsoft.icon'; - case 'webp': - return 'image/webp'; - case 'webm': - return 'video/webm'; - case 'mid': - case 'midi': - return 'audio/midi'; - case 'mp3': - return 'audio/mpeg'; - case 'weba': - return 'audio/webm'; - } - return undefined; -}; - -/** - * Validate an import map configuration (https://wicg.github.io/import-maps/). - * Returns an array of errors. If empty, the import map is valid. - */ -const validateImportMap = (importMap: unknown): string[] => { - const errors = []; - - if (typeof importMap !== 'object' || importMap === null) { - errors.push( - `Import map is invalid because it must be an object,` + - ` but it was ${importMap === null ? 'null' : typeof importMap}.` - ); - return errors; - } - - const invalidKeys = Object.keys(importMap).filter((key) => key !== 'imports'); - if (invalidKeys.length > 0) { - errors.push( - `Invalid import map properties: ${[...invalidKeys].join(', ')}.` + - ` Only "imports" are currently supported.` - ); - } - const imports = (importMap as {imports: unknown}).imports; - if (imports === undefined) { - return errors; - } - - if (typeof imports !== 'object' || imports === null) { - errors.push( - `Import map "imports" property is invalid` + - ` because it must be an object,` + - ` but it was ${imports === null ? 'null' : typeof imports}.` - ); - return errors; - } - - for (const [specifierKey, resolutionResult] of Object.entries(imports)) { - if (typeof resolutionResult !== 'string') { - errors.push( - `Import map key "${specifierKey}" is invalid because` + - ` address must be a string, but was` + - ` ${resolutionResult === null ? 'null' : typeof resolutionResult}` - ); - continue; - } - if (specifierKey.endsWith('/') && !resolutionResult.endsWith('/')) { - errors.push( - `Import map key "${specifierKey}" is invalid because` + - ` address "${resolutionResult}" must end in a forward-slash.` - ); - } - try { - new URL(resolutionResult); - } catch { - errors.push( - `Import map key "${specifierKey}" is invalid because` + - ` address "${resolutionResult}" is not a valid URL.` - ); - } - } - - return errors; -}; - -declare global { - interface HTMLElementTagNameMap { - 'playground-project': PlaygroundProject; - } -} - -/** - * Trim shared leading whitespace from all lines, and remove empty - * leading/trailing lines. - */ -const outdent = (str: string): string => { - // Remove leading/trailing empty lines (we don't use trim() because we don't - // want to remove leading whitespace on the first content line). - str = str.replace(/(^[\n\s]*\n)|(\n[\n\s]*$)/g, ''); - let shortestIndent; - for (const line of str.split(/\n/g)) { - const indent = line.match(/^\s*/)![0].length; - if (shortestIndent === undefined || indent < shortestIndent) { - shortestIndent = indent; - } - } - return str.replace(RegExp(`^\\s{${shortestIndent ?? 0}}`, 'gm'), ''); -}; - -/** - * Test whether two lists of Playground files are deeply equal. - */ -const playgroundFilesDeepEqual = ( - filesA: SampleFile[], - filesB: SampleFile[] -): boolean => { - if (filesA.length !== filesB.length) { - return false; - } - for (let i = 0; i < filesA.length; i++) { - const fileA = filesA[i]; - const fileB = filesB[i]; - if ( - fileA.name !== fileB.name || - fileA.contentType !== fileB.contentType || - fileA.hidden !== fileB.hidden || - fileA.label !== fileB.label - ) { - return false; - } - } - for (let i = 0; i < filesA.length; i++) { - const fileA = filesA[i]; - const fileB = filesB[i]; - if (fileA.content !== fileB.content) { - return false; - } - } - return true; -}; diff --git a/src/playground-service-worker-proxy.ts b/src/playground-service-worker-proxy.ts deleted file mode 100644 index 05f2aa93..00000000 --- a/src/playground-service-worker-proxy.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { - PlaygroundMessage, - CONNECT_SW_TO_PROJECT, - CONNECT_PROJECT_TO_SW, - CONFIGURE_PROXY, - MISSING_FILE_API, - UPDATE_SERVICE_WORKER, -} from './shared/worker-api.js'; - -void (async () => { - try { - // Note we detect same-origin here by actually trying to access the parent - // window. We can't trust the parent to compare the origins of the URLs, - // because a redirect could have lead us back to the same origin. - parent.window.console.warn( - 'Playground sandbox is executing with the same origin as its parent.', - 'This is a security risk.', - 'https://github.com/google/playground-elements#sandbox-security' - ); - // eslint-disable-next-line no-empty - } catch {} - - // Wait for our parent to send us: - // 1. The URL and scope of the Service Worker to register. - // 2. A MessagePort, on which we'll forward up new Service Worker ports. - const {scope, port: parentPort} = await new Promise<{ - scope: string; - port: MessagePort; - }>((resolve) => { - const listener = (event: MessageEvent) => { - if (event.data.type === CONFIGURE_PROXY) { - window.removeEventListener('message', listener); - resolve(event.data); - } - }; - window.addEventListener('message', listener); - }); - - const registration = await navigator.serviceWorker.register( - new URL('playground-service-worker.js', import.meta.url).href, - {scope} - ); - - /** https://www.w3.org/TR/service-workers/#get-newest-worker-algorithm */ - const getNewestWorker = () => - registration.installing ?? registration.waiting ?? registration.active; - - /** - * Resolve when the given service worker reaches its activated state. - */ - const activated = async (sw: ServiceWorker): Promise => { - if (sw.state === 'activated') { - return; - } - return new Promise((resolve) => { - const aborter = new AbortController(); - sw.addEventListener( - 'statechange', - () => { - if (sw.state === 'activated') { - resolve(); - aborter.abort(); - } - }, - {signal: aborter.signal} - ); - }); - }; - - /** The service worker we most recently connected to. */ - let connected: ServiceWorker | null = null; - - const connectToNewest = async (force = false) => { - const sw = getNewestWorker(); - if (!force && sw === connected) { - // This can happen because on a fresh install we'll call connectToNewest() - // but "updatefound" will also fire and call it too. - return; - } - connected = sw; - if (sw === null) { - // Can't find a way to reproduce this scenario, possibly can't happen. - console.error('No playground service worker found.'); - return; - } - - // Don't connect to the project until the service worker is activated. - // Otherwise the project might try to load a preview before the service - // worker is actively controlling the preview's URL space. - await activated(sw); - if (sw !== connected) { - // A new service worker appeared while we were waiting. This probably - // can't happen in practice. - return; - } - - const {port1, port2} = new MessageChannel(); - const projectMessage: PlaygroundMessage = { - type: CONNECT_PROJECT_TO_SW, - port: port1, - }; - parentPort.postMessage(projectMessage, [port1]); - const swMessage: PlaygroundMessage = { - type: CONNECT_SW_TO_PROJECT, - port: port2, - }; - sw.postMessage(swMessage, [port2]); - }; - - void connectToNewest(); - - registration.addEventListener('updatefound', () => { - // We can get a new service worker at any time, so we need to listen for - // updates and connect to new workers on demand. - void connectToNewest(); - }); - - // A message from the service worker. - navigator.serviceWorker.addEventListener( - 'message', - (event: MessageEvent) => { - if (event.source !== connected) { - // Ignore messages from outdated service workers. - return; - } - if (event.data.type === MISSING_FILE_API) { - // A fetch was made for a session that the service worker doesn't have a - // file API for. Most likely the service worker was stopped and lost its - // state, as can happen at any time. The fetch re-awakened it, and now - // the fetch is waiting for us to re-connect. - // - // Force required because we usually avoid connecting to a service - // worker we've already connected to, but in this case that's exactly - // what we must do. - void connectToNewest(true); - } - } - ); - - // A message from the project. - window.addEventListener( - 'message', - async (event: MessageEvent) => { - if (event.data.type === UPDATE_SERVICE_WORKER) { - // When the project handshakes with the service worker, it may notice a - // version mismatch, and will send this message to request an update. - const newestBefore = getNewestWorker(); - await registration.update(); - if (getNewestWorker() === newestBefore) { - // The update() promise resolves when the check has finished, but it - // might not have actually found a new service worker. In that case, - // maybe one of these things happened: - // - // - The project code is outdated so the page needs to be reloaded. - // - The server(s) are returning mismatched versions. - // - A caching issue is preventing the new version from being fetched. - // - // TODO(aomarks) Show a more prominent error directly on the preview - // prompting the user to reload the page. Otherwise it will just spin - // forever. - console.error('Playground service worker update failed.'); - } - } - } - ); -})(); diff --git a/src/playground-styles.ts b/src/playground-styles.ts deleted file mode 100644 index aa758396..00000000 --- a/src/playground-styles.ts +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { EditorView } from 'codemirror'; - -/* - * @fileoverview - * - * This file is derived from \`code-mirror@^5/lib/codemirror.css\`, modified in - * the following ways: - * - * - CSS custom properties added. - * - Rules for anything that doesn't include custom properties removed. - * - Updated to use CodeMirror 6 classHighlighter classes. - * - Added styles for tooltips - */ - -export const playgroundTheme = EditorView.theme({ - '& .cm-scroller': { - fontSize: 'var(--playground-code-font-size, 14px)', - fontFamily: 'var(--playground-code-font-family, monospace)', - lineHeight: 'var(--playground-code-line-height, 1.4em)', - }, - '& .cm-line': { - padding: 'var(--playground-code-line-padding, 0 4px)', - }, - '& .cm-tooltip': { - backgroundColor: 'var(--playground-code-background, white)', - border: '1px solid var(--playground-code-selection-background, silver)', - fontSize: 'var(--playground-code-font-size, 14px)', - fontFamily: 'var(--playground-code-font-family, monospace)', - color: 'var(--playground-code-default-color, #000)', - }, - '& .cm-completionOption': { - color: 'var(--playground-code-default-color, black)', - }, - '& .cm-tooltip-autocomplete .cm-completionOption.cm-completionOption-selected': { - background: 'var(--playground-code-background, rgba(0, 0, 0, 0.2))', - }, - '& .cm-completionOption mark': { - color: 'var(--playground-code-qualifier-color, #555)', - }, - '& .cm-tooltip-autocomplete > ul > li > span.cm-completionDetail': { - visibility: 'hidden', - flex: 1, - flexBasis: '80%', - fontSize: 'calc(var(--playground-code-font-size, 14px) * .9)', - lineHeight: 'calc(var(--playground-code-font-size, 14px) * 1.2)', - color: 'var(--playground-code-string-2-color, #00f)', - opacity: '0.8', - textAlign: 'right', - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }, - '& .cm-tooltip-autocomplete .cm-completionMatchedText': { - color: 'var(--playground-code-keyword-color, #708)', - }, - '& .cm-tooltip-autocomplete li[aria-selected="true"] .cm-completionDetail': { - visibility: 'visible', - }, - '& .cm-tooltip.cm-tooltip-autocomplete > ul': { - maxWidth: 'min(600px, 95vw)', - }, - '& .cm-tooltip.cm-tooltip-autocomplete > ul > li[role="option"]': { - display: 'flex', - paddingInline: '6px', - }, - '& .cm-tooltip.cm-tooltip-autocomplete .cm-completionIcon': { - display: 'none', - }, - '& .cm-tooltip-autocomplete ul li[aria-selected]': { - color: 'var(--playground-code-default-color, #000)', - }, - '& .cm-tooltip-autocomplete > ul > li[aria-selected]': { - backgroundColor: 'var(--playground-code-selection-background, #d7d4f0)', - flex: 1, - }, - '&': { - padding: 'var(--playground-code-padding, 0)', - height: '350px', - color: 'var(--playground-code-default-color, #000)', - backgroundColor: 'var(--playground-code-background, #fff)', - }, - '& .cm-scrollbar-filler, & .cm-gutter-filler': { - backgroundColor: 'var(--playground-code-background, #fff)', - }, - '& .cm-gutters': { - borderRight: 'var(--playground-code-gutter-border-right, none)', - backgroundColor: 'var(--playground-code-gutter-background, var(--playground-code-background, #fff))', - boxShadow: 'var(--playground-code-gutter-box-shadow, none)', - }, - '& .cm-gutterElement': { - color: 'var(--playground-code-linenumber-color, #767676)', - }, - '& .cm-cursor, & .cm-dropCursor': { - borderLeft: '1.2px solid var(--playground-code-cursor-color, var(--playground-code-default-color, #000))', - }, - '& .tok-variableName': { - color: 'var(--playground-code-variable-color, #000)', - }, - '& .tok-keyword': { - color: 'var(--playground-code-keyword-color, #708)', - }, - '& .tok-literal': { - color: 'var(--playground-code-literal-color, var(--playground-code-keyword-color, #219))', - }, - '& .tok-atom, & .tok-literal': { - color: 'var(--playground-code-atom-color, #219)', - }, - '& .tok-number': { - color: 'var(--playground-code-number-color, #164)', - }, - '& .tok-bool': { - color: 'var(--playground-code-bool-color, var(--playground-code-atom-color, #219))', - }, - '& .tok-propertyName': { - color: 'var(--playground-code-property-color, #000)', - }, - '& .tok-className': { - color: 'var(--playground-code-class-name, var(--playground-code-type-color, #085))', - }, - '& .tok-definition': { - color: 'var(--playground-code-def-color, #00f)', - }, - '& .tok-operator': { - color: 'var(--playground-code-operator-color, #000)', - }, - '& .tok-variableName2': { - color: 'var(--playground-code-variable-2-color, #05a)', - }, - '& .tok-namespace': { - color: 'var(--playground-code-variable-3-color, #085)', - }, - '& .tok-typeName': { - color: 'var(--playground-code-type-color, #085)', - }, - '& .tok-comment': { - color: 'var(--playground-code-comment-color, #a50)', - }, - '& .tok-string': { - color: 'var(--playground-code-string-color, #a11)', - }, - '& .tok-string2': { - color: 'var(--playground-code-string-2-color, #f50)', - }, - '& .tok-meta': { - color: 'var(--playground-code-meta-color, #555)', - }, - '& .tok-modifier': { - color: 'var(--playground-code-qualifier-color, #555)', - }, - '& .tok-standard': { - color: 'var(--playground-code-builtin-color, #30a)', - }, - '& .tok-tagName': { - color: 'var(--playground-code-tag-color, #170)', - }, - '& .tok-attributeName': { - color: 'var(--playground-code-attribute-color, #00c)', - }, - '& .tok-labelName': { - color: 'var(--playground-code-builtin-color, #30a)', - }, - '& .cm-selectionBackground': { - backgroundColor: 'var(--playground-code-selection-background, #d7d4f0)', - }, - '&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': { - backgroundColor: 'var(--playground-code-selection-background, #d7d4f0)', - }, - '& .cm-line::selection, & .cm-line > span::selection, & .cm-line > span > span::selection': { - backgroundColor: 'var(--playground-code-selection-background, #d7d4f0)', - }, -}); diff --git a/src/playground-tab-bar.ts b/src/playground-tab-bar.ts deleted file mode 100644 index 7aeb07d7..00000000 --- a/src/playground-tab-bar.ts +++ /dev/null @@ -1,343 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {html, css, PropertyValues, nothing} from 'lit'; -import {customElement, property, state, query} from 'lit/decorators.js'; - -import '@material/mwc-icon-button'; - -import './internal/tab-bar.js'; -import './internal/tab.js'; -import './playground-file-system-controls.js'; - -import {PlaygroundConnectedElement} from './playground-connected-element.js'; - -import {PlaygroundFileEditor} from './playground-file-editor.js'; -import {PlaygroundFileSystemControls} from './playground-file-system-controls.js'; -import {FilesChangedEvent, PlaygroundProject} from './playground-project.js'; -import {PlaygroundInternalTab} from './internal/tab.js'; - -/** - * A horizontal bar of tabs for switching between playground files, with - * optional controls for create/delete/rename. - */ -@customElement('playground-tab-bar') -export class PlaygroundTabBar extends PlaygroundConnectedElement { - static override styles = css` - :host { - display: flex; - font-size: var(--playground-tab-bar-font-size, 14px); - height: var(--playground-bar-height, 40px); - background: var(--playground-tab-bar-background, #eaeaea); - align-items: center; - } - - 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); - } - - playground-internal-tab[active] { - color: var( - --playground-tab-bar-active-color, - var(--playground-highlight-color, #6200ee) - ); - background: var(--playground-tab-bar-active-background, transparent); - } - - :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 { - color: var(--playground-tab-bar-foreground-color); - } - - .add-file-button { - margin: 0 4px; - opacity: 70%; - --mdc-icon-button-size: 24px; - --mdc-icon-size: 24px; - } - - .add-file-button:hover { - opacity: 1; - } - `; - - /** - * 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', reflect: true}) - editableFileSystem = false; - - @state() - private _activeFileName = ''; - - @state() - private _activeFileIndex = 0; - - @query('playground-file-system-controls') - private _fileSystemControls?: PlaygroundFileSystemControls; - - /** - * The actual `` node, determined by the `editor` - * property. - */ - @state() - private _editor?: PlaygroundFileEditor; - - /** - * The editor that this tab bar controls. Either the - * `` node itself, or its `id` in the host scope. - */ - @property() - set editor(elementOrId: PlaygroundFileEditor | string) { - if (typeof elementOrId === 'string') { - // Defer querying the host to a rAF because if the host renders this - // element before the one we're querying for, it might not quite exist - // yet. - requestAnimationFrame(() => { - const root = this.getRootNode() as ShadowRoot | Document; - this._editor = - (root.getElementById(elementOrId) as PlaygroundFileEditor | null) ?? - undefined; - }); - } else { - this._editor = elementOrId; - } - } - - private get _visibleFiles() { - return (this._project?.files ?? []).filter(({hidden}) => !hidden); - } - - override update(changedProperties: PropertyValues) { - if (changedProperties.has('_project')) { - const oldProject = changedProperties.get('_project') as PlaygroundProject; - if (oldProject) { - oldProject.removeEventListener( - 'filesChanged', - this._onProjectFilesChanged - ); - } - if (this._project) { - this._handleFilesChanged(true); - this._project.addEventListener( - 'filesChanged', - this._onProjectFilesChanged - ); - } - } - if (changedProperties.has('_activeFileName') && this._editor) { - this._editor.filename = this._activeFileName; - this._setNewActiveFile(); - } - super.update(changedProperties); - } - - override render() { - return html` - - ${this._visibleFiles.map( - ({name, label}) => - html` - ${label || name} - ${this.editableFileSystem - ? html` - - - - - ` - : nothing} - ` - )} - - - ${this.editableFileSystem - ? html` - - - - - - - - - - ` - : nothing} - `; - } - - private _onProjectFilesChanged = (event: FilesChangedEvent) => { - this._handleFilesChanged(event.projectLoaded); - }; - - private _handleFilesChanged(newProjectLoaded = false) { - if (newProjectLoaded) { - const fileToSelect = this._visibleFiles.find( - (file) => file.selected - )?.name; - if (fileToSelect !== undefined) { - this._activeFileName = fileToSelect; - } - } - this._setNewActiveFile(); - this.requestUpdate(); - } - - 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; - } - } - - private _onOpenMenu( - event: CustomEvent<{index: number; anchor: HTMLElement}> - ) { - const controls = this._fileSystemControls; - if (!controls) { - return; - } - controls.state = 'menu'; - // Figure out which file the open menu should be associated with. It's not - // necessarily the active tab, since you can click on the menu button for a - // tab without activating that tab. - // - // We're looking for a "data-filename" attribute in the event path, which - // should be on the . - // - // Note that we can't be sure what the target of the click event will be. - // Between MWC v0.25.1 and v0.25.2, when clicking on an , - // the target changed from the to its internal . - for (const el of event.composedPath()) { - if (el instanceof HTMLElement && el.dataset['filename']) { - controls.filename = el.dataset['filename']; - break; - } - } - controls.anchorElement = event.target as HTMLElement; - event.stopPropagation(); - } - - private _onClickAddFile(event: Event) { - const controls = this._fileSystemControls; - if (!controls) { - return; - } - controls.state = 'newfile'; - controls.anchorElement = event.target as HTMLElement; - } - - private _onNewFile(event: CustomEvent<{filename: string}>) { - this._activeFileName = event.detail.filename; - // TODO(aomarks) We should focus the editor here. However, - // CodeMirror.focus() isn't working for some reason. - } - - /** - * Whenever a file is created, deleted, or renamed, figure out what the best - * new active tab should be. - */ - private _setNewActiveFile() { - // Stay on the same filename if it's still around, even though its index - // might have changed. - if (this._activeFileName) { - const index = this._visibleFiles.findIndex( - (file) => file.name === this._activeFileName - ); - if (index >= 0) { - this._activeFileIndex = index; - return; - } - } - - // Stay on the same index, or the nearest one to the left of where we were - // before. - for (let i = this._activeFileIndex; i >= 0; i--) { - const file = this._visibleFiles[i]; - if (file && !file.hidden) { - this._activeFileName = file.name; - return; - } - } - - // No visible file to display. - this._activeFileIndex = 0; - this._activeFileName = ''; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'playground-tab-bar': PlaygroundTabBar; - } -} diff --git a/src/playground-typescript-worker-entrypoint.ts b/src/playground-typescript-worker-entrypoint.ts deleted file mode 100755 index 37e90ade..00000000 --- a/src/playground-typescript-worker-entrypoint.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {expose} from 'comlink'; -import {build} from './typescript-worker/build.js'; -import {WorkerAPI} from './shared/worker-api.js'; -import { - getCompletionItemDetails, - queryCompletions, -} from './typescript-worker/completions.js'; - -const workerAPI: WorkerAPI = { - compileProject: build, - getCompletions: queryCompletions, - getCompletionItemDetails: getCompletionItemDetails, -}; -expose(workerAPI); diff --git a/src/service-worker/playground-service-worker.ts b/src/service-worker/playground-service-worker.ts deleted file mode 100755 index 0d47c9b9..00000000 --- a/src/service-worker/playground-service-worker.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { - ACKNOWLEDGE_SW_CONNECTION, - CONNECT_SW_TO_PROJECT, - MISSING_FILE_API, - PlaygroundMessage, - ServiceWorkerAPI, - FileAPI, -} from '../shared/worker-api.js'; -import {expose} from 'comlink'; -import {Deferred} from '../shared/deferred.js'; -import {serviceWorkerHash} from '../shared/version.js'; - -// eslint-disable-next-line no-var -declare var self: ServiceWorkerGlobalScope; - -type SessionID = string; - -/** - * A collection of FileAPI objects registered by instances, - * keyed by session ID. - */ -const fileAPIs = new Map>(); - -/** - * API exposed to the UI thread via Comlink. The static methods on this class - * become instance methods on SwControllerAPI. - */ -const workerAPI: ServiceWorkerAPI = { - setFileAPI(fileAPI: FileAPI, sessionID: SessionID) { - let deferred = fileAPIs.get(sessionID); - if (deferred === undefined || deferred.settled) { - deferred = new Deferred(); - fileAPIs.set(sessionID, deferred); - } - deferred.resolve(fileAPI); - }, -}; - -const findSessionProxyClient = async ( - sessionId: string -): Promise => { - for (const client of await self.clients.matchAll({ - includeUncontrolled: true, - })) { - const hash = new URL(client.url).hash; - const hashParams = new URLSearchParams(hash.slice(1)); - if (hashParams.get('playground-session-id') === sessionId) { - return client; - } - } - return undefined; -}; - -const getFileApi = async (sessionId: string): Promise => { - let deferred = fileAPIs.get(sessionId); - if (deferred !== undefined) { - return deferred.promise; - } - // Find the proxy that manages this session, and tell it to connect us to the - // session file API. Service Workers can stop and start at any time, clearing - // global state. This kind of restart does _not_ count as a state change. The - // only way we can tell this has happened is that a fetch occurs for a session - // we don't know about. - const client = await findSessionProxyClient(sessionId); - if (client === undefined) { - // This could happen if a user directly opened a playground URL after a - // proxy iframe has been destroyed. - return undefined; - } - deferred = new Deferred(); - fileAPIs.set(sessionId, deferred); - const missingMessage: PlaygroundMessage = {type: MISSING_FILE_API}; - client.postMessage(missingMessage); - return deferred.promise; -}; - -const getFile = async (_e: FetchEvent, path: string, sessionId: SessionID) => { - const fileAPI = await getFileApi(sessionId); - if (fileAPI === undefined) { - return new Response('Playground project not available', { - status: /* Service Unavailable */ 503, - }); - } - const fileOrError = await fileAPI.getFile(path); - if ('status' in fileOrError) { - const {body, status} = fileOrError; - return new Response(body, {status}); - } - const {content, contentType} = fileOrError; - const headers = new Headers(); - // By default, a browser is only able to allocate a separate process or thread - // for the Playground preview iframe if it is hosted on a different _site_ - // (protocol + top-level domain) from the parent window. For example, lit.dev - // and playground.lit.dev are the same site, but different origins. By setting - // this Origin-Agent-Cluster header, we additionally allow process isolation - // for different origins even if they are same-site. - // - // Note that _all_ responses from the sandbox origin must include this header - // in order isolation to be possible, because the browser persists the setting - // based on the first response it gets from that origin, so users will also - // need to configure their HTTP server's response headers, since this line - // only affects responses handled by the the service worker, and not e.g. the - // service worker script itself. - // - // See: - // https://web.dev/origin-agent-cluster/ - // https://html.spec.whatwg.org/multipage/origin.html#origin-keyed-agent-clusters - headers.set('Origin-Agent-Cluster', '?1'); - if (contentType) { - headers.set('Content-Type', contentType); - } - return new Response(content, {headers}); -}; - -const onFetch = (e: FetchEvent) => { - const url = e.request.url; - if (url.startsWith(self.registration.scope)) { - const {filePath, sessionId} = parseScopedUrl(url); - if (sessionId !== undefined) { - e.respondWith(getFile(e, filePath!, sessionId)); - } - } -}; - -const parseScopedUrl = (url: string) => { - const scope = self.registration.scope; - // URLs in scope will be of the form: {scope}{sessionId}/{filePath}. Scope is - // always a full URL prefix, including a trailing slash. Strip query params or - // else the filename won't match. - const sessionAndPath = url.substring(scope.length).split('?')[0]; - const slashIndex = sessionAndPath.indexOf('/'); - let sessionId, filePath: string | undefined; - if (slashIndex === -1) { - console.warn(`Invalid sample file URL: ${url}`); - } else { - sessionId = sessionAndPath.slice(0, slashIndex); - filePath = sessionAndPath.slice(slashIndex + 1); - } - return { - sessionId, - filePath, - }; -}; - -const onInstall = () => { - // Force this service worker to become the active service worker, in case - // it's an updated worker and waiting. - void self.skipWaiting(); -}; - -const onActivate = (event: ExtendableEvent) => { - // Make sure active clients use this service worker instance without being - // reloaded. - event.waitUntil(self.clients.claim()); -}; - -const onMessage = ( - e: Omit & {data: PlaygroundMessage} -) => { - // Receive a handshake message from a page and setup Comlink. - if (e.data.type === CONNECT_SW_TO_PROJECT) { - const ack: PlaygroundMessage = { - type: ACKNOWLEDGE_SW_CONNECTION, - version: serviceWorkerHash, - }; - e.data.port.postMessage(ack); - expose(workerAPI, e.data.port); - } -}; - -self.addEventListener('fetch', onFetch); -self.addEventListener('activate', onActivate); -self.addEventListener('install', onInstall); -self.addEventListener('message', onMessage); diff --git a/src/service-worker/tsconfig.json b/src/service-worker/tsconfig.json deleted file mode 100644 index 0b5038c1..00000000 --- a/src/service-worker/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "composite": true, - "outDir": "../../service-worker", - "rootDir": ".", - "tsBuildInfoFile": "../../service-worker/.tsbuildinfo", - "lib": ["ES2017", "WebWorker"], - "skipLibCheck": true - }, - "include": ["*.ts"], - "exclude": [], - "references": [ - { - "path": "../shared" - } - ] -} diff --git a/src/shared/completion-utils.ts b/src/shared/completion-utils.ts deleted file mode 100644 index 8ebe3d0e..00000000 --- a/src/shared/completion-utils.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Fuse from 'fuse.js'; -import {CompletionInfo} from 'typescript'; -import { - EditorCompletion, - EditorCompletionMatch, - CompletionEntryWithDetails, - CompletionInfoWithDetails, - EditorCompletionDetails, -} from './worker-api.js'; - -export function sortCompletionItems( - completions: CompletionEntryWithDetails[] | undefined, - searchWord: string -): EditorCompletion[] { - if (!completions) return []; - // If the user input a letter or a partial word, we want to offer - // the closest matches first, and the weaker matches after. We will use - // Fuse to score our completions by their fuzzy matches. - // See https://fusejs.io/api/options.html - const fuse = new Fuse(completions ?? [], { - // Keep the threshold a bit lower than the default - // so that the matching isn't too forgiving/confusing, but so - // that a small typo doesn't delete all of the matches - threshold: 0.3, - shouldSort: true, - isCaseSensitive: true, - includeScore: true, - includeMatches: true, - keys: ['name'], - // Match characters so that at least most of the word matches - minMatchCharLength: Math.max(searchWord.length / 1.2, 1), - }); - const relevantCompletions = fuse.search(searchWord); - - const editorCompletions: EditorCompletion[] = relevantCompletions - // Map the relevant info from fuse scoring - .map( - (item) => - ({ - text: item.item.name, - displayText: item.item.name, - score: item.score ?? 0, - matches: item.matches as EditorCompletionMatch[], - get details() { - return item.item.details; - }, - } as EditorCompletion) - ) - // Sort the completions by how well they matched the given keyword - .sort((a, b) => { - if (a.score === b.score) { - return a.text.localeCompare(b.text); - } - return a.score - b.score; - }); - - return editorCompletions; -} - -export function completionEntriesAsEditorCompletions( - completions: CompletionEntryWithDetails[] | undefined, - prefix = '' -): EditorCompletion[] { - return ( - completions?.map( - (comp) => - ({ - // Since the completion engine will only append the word - // given as the text property here, auto-completing from a period - // would replace the period with the word. This is why we need - // to append the period into the text property. This is not visible to the - // user however, so no harm is done. - text: prefix + comp.name, - displayText: comp.name, - score: Number.parseInt(comp.sortText), - get details() { - return comp.details; - }, - } as EditorCompletion) - ) ?? [] - ); -} - -/** - * Create a array of completion entries with a details fetching - * function built in, so that the code editor can use it to fetch - * the details when needed itself, instead of having to ask the project - * layer for them. - */ -export function populateCompletionInfoWithDetailGetters( - completionInfo: CompletionInfo, - filename: string, - cursorIndex: number, - getCompletionDetailsFunction: ( - filename: string, - cursorIndex: number, - completionWord: string - ) => Promise -) { - const completionInfoWithDetails = completionInfo as CompletionInfoWithDetails; - completionInfoWithDetails.entries = completionInfo?.entries.map( - (entry) => - ({ - ...entry, - // Details are fetched using a proxy pattern, in which the details - // are not instantiated until requested for. When asking for details - // from the completion item, the getter is called, launching the - // query if needed. - _details: undefined, - get details() { - if (!this._details) { - this._details = getCompletionDetailsFunction( - filename, - cursorIndex, - entry.name - ); - } - return this._details; - }, - } as CompletionEntryWithDetails) - ); - return completionInfoWithDetails; -} diff --git a/src/shared/deferred.ts b/src/shared/deferred.ts deleted file mode 100644 index 545812ab..00000000 --- a/src/shared/deferred.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -export class Deferred { - readonly promise: Promise; - private _resolve!: (value: T) => void; - private _reject!: (reason?: unknown) => void; - settled = false; - - constructor() { - this.promise = new Promise((resolve, reject) => { - this._resolve = resolve; - this._reject = reject; - }); - } - - resolve(value: T) { - this.settled = true; - this._resolve(value); - } - - reject(reason: unknown) { - this.settled = true; - this._reject(reason); - } -} diff --git a/src/shared/tsconfig.json b/src/shared/tsconfig.json deleted file mode 100644 index de67a511..00000000 --- a/src/shared/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "composite": true, - "outDir": "../../shared", - "rootDir": ".", - "tsBuildInfoFile": "../../shared/.tsbuildinfo", - "lib": ["ES2017", "WebWorker"], - "skipLibCheck": true - }, - "include": ["*.ts"], - "exclude": [] -} diff --git a/src/shared/util.ts b/src/shared/util.ts deleted file mode 100644 index 2ed6aab3..00000000 --- a/src/shared/util.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -export const endWithSlash = (s: string) => (s.endsWith('/') ? s : s + '/'); - -export const getRandomString = () => - crypto.getRandomValues(new Uint32Array(1))[0].toString(32); - -/** - * If the given URL object is a Skypack URL, perform an in-place update that - * switches from optimized mode to raw mode. - * - * See https://github.com/google/playground-elements/issues/107 - */ -export const forceSkypackRawMode = (url: URL): URL => { - if (url.hostname === 'cdn.skypack.dev') { - url.pathname = url.pathname.replace( - /mode=imports\/(un)?optimized/, - 'mode=raw' - ); - } - return url; -}; - -export type Result = - | {result: V; error?: undefined} - | {result?: undefined; error: E}; diff --git a/src/shared/version.ts b/src/shared/version.ts deleted file mode 100644 index b3ff1b43..00000000 --- a/src/shared/version.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -// DO NOT UPDATE MANUALLY. - -// This file is automatically generated by scripts/update-version-module.js -// before publishing. -export const npmVersion = '0.21.2'; -export const serviceWorkerHash = '09cd6a4e'; diff --git a/src/shared/worker-api.ts b/src/shared/worker-api.ts deleted file mode 100755 index f3931238..00000000 --- a/src/shared/worker-api.ts +++ /dev/null @@ -1,232 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {CompletionEntry, CompletionInfo, WithMetadata} from 'typescript'; -import {Diagnostic} from 'vscode-languageserver-protocol'; - -/** - * Sent from the project to the proxy, with configuration and a port for further - * messages. - */ -export const CONFIGURE_PROXY = 1; - -/** - * Sent from the proxy to the service worker, with a port that will be connected - * to the project. - */ -export const CONNECT_SW_TO_PROJECT = 2; - -/** - * Sent from the proxy to the project, with a port that will be connected to the - * service worker. - */ -export const CONNECT_PROJECT_TO_SW = 3; - -/** - * Sent from the service worker to the project, to confirm that the port was - * received. - */ -export const ACKNOWLEDGE_SW_CONNECTION = 4; - -/** - * Sent from the service worker to the proxy, to notify when a file API is - * missing and hence a re-connection is probably required. - */ -export const MISSING_FILE_API = 5; - -/** - * Sent from the project to the service worker proxy when there is a version - * mismatch to request a call to ServiceWorkerRegistration.update(). - */ -export const UPDATE_SERVICE_WORKER = 6; - -export type PlaygroundMessage = - | { - type: typeof CONFIGURE_PROXY; - scope: string; - port: MessagePort; - } - | { - type: typeof CONNECT_SW_TO_PROJECT; - port: MessagePort; - } - | { - type: typeof CONNECT_PROJECT_TO_SW; - port: MessagePort; - } - | { - type: typeof ACKNOWLEDGE_SW_CONNECTION; - version: string; - } - | { - type: typeof MISSING_FILE_API; - } - | { - type: typeof UPDATE_SERVICE_WORKER; - }; - -export interface ServiceWorkerAPI { - setFileAPI(fileAPI: FileAPI, sessionID: string): void; -} - -export interface WorkerConfig { - importMap: ModuleImportMap; - cdnBaseUrl: string; -} - -export interface EditorToken { - /** The character (on the given line) at which the token starts. */ - start: number; - /** The character at which the token ends. */ - end: number; - /** Code string under the cursor. */ - string: string; -} - -export interface EditorPosition { - ch: number; - line: number; -} - -type RangeTuple = [number, number]; - -export type EditorCompletionMatch = { - indices: ReadonlyArray; -}; - -export interface EditorCompletion { - text: string; - displayText: string; - score: number; - matches?: EditorCompletionMatch[]; - details: Promise; -} - -export interface EditorTagInfo { - name: string; - text?: EditorTag[]; -} - -export interface EditorTag { - text: string; - kind: string; -} - -export interface EditorCompletionDetails { - text: string; - tags: EditorTagInfo[]; - documentation: string[]; -} - -export interface WorkerAPI { - compileProject( - files: Array, - config: WorkerConfig, - emit: (result: BuildOutput) => void - ): Promise; - getCompletions( - filename: string, - fileContent: string, - tokenUnderCursor: string, - cursorIndex: number, - config: WorkerConfig - ): Promise | undefined>; - getCompletionItemDetails( - filename: string, - cursorIndex: number, - config: WorkerConfig, - completionWord: string - ): Promise; -} - -export interface HttpError { - status: number; - body: string; -} - -export interface FileAPI { - getFile(name: string): Promise; -} - -export interface SampleFile { - /** Filename. */ - name: string; - /** Optional display label. */ - label?: string; - /** File contents. */ - content: string; - /** MIME type. */ - contentType?: string; - /** Don't display in tab bar. */ - hidden?: boolean; - /** Whether the file should be selected when loaded */ - selected?: boolean; -} - -export interface FileOptions { - /** Optional file content. If omitted, files are fetched by name. */ - content?: string; - /** - * Optional content MIME type. If omitted, type is taken from fetch - * Content-Type header if available, otherwise inferred from filename. - */ - contentType?: string; - /** Optional display label. */ - label?: string; - /** Don't display in tab bar. */ - hidden?: boolean; - /** Whether the file should be selected when loaded */ - selected?: boolean; -} - -export interface ProjectManifest { - /** Optional project manifest URL to extend from */ - extends?: string; - files?: {[filename: string]: FileOptions}; - importMap?: ModuleImportMap; - cdnBaseUrl?: string; -} - -export interface ModuleImportMap { - imports?: {[name: string]: string}; - // No scopes for now. -} - -export interface CodeEditorChangeData { - isRefinement: boolean; - fileName: string; - fileContent: string; - tokenUnderCursor: string; - cursorIndex: number; - provideCompletions: (completions: EditorCompletion[]) => void; -} - -export interface CompletionEntryWithDetails extends CompletionEntry { - _details: undefined | Promise; - details: Promise; -} - -export interface CompletionInfoWithDetails - extends WithMetadata { - entries: CompletionEntryWithDetails[]; -} - -export type BuildOutput = FileBuildOutput | DiagnosticBuildOutput | DoneOutput; - -export type FileBuildOutput = { - kind: 'file'; - file: SampleFile; -}; - -export type DiagnosticBuildOutput = { - kind: 'diagnostic'; - filename: string; - diagnostic: Diagnostic; -}; - -export type DoneOutput = { - kind: 'done'; -}; diff --git a/src/test/bare-module-worker_test.ts b/src/test/bare-module-worker_test.ts deleted file mode 100644 index 4a521483..00000000 --- a/src/test/bare-module-worker_test.ts +++ /dev/null @@ -1,1190 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {checkTransform} from './worker-test-util.js'; - -import { - BuildOutput, - ModuleImportMap, - SampleFile, -} from '../shared/worker-api.js'; -import {CdnData} from './fake-cdn-plugin.js'; - -const browser = (() => { - const ua = navigator.userAgent; - if (ua.includes('Chrome')) { - return 'chrome'; - } - if (ua.includes('Firefox')) { - return 'firefox'; - } - if (ua.includes('Safari')) { - return 'safari'; - } - return 'chrome'; -})(); - -suite('bare module worker', () => { - test('empty project', async () => { - const files: SampleFile[] = []; - const cdn: CdnData = {}; - const expected: BuildOutput[] = []; - await checkTransform(files, expected, {}, cdn); - }); - - test('one simple static import', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/index.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'index', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'index', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('multiple static and dynamic imports', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: ` - import {a} from "foo/index.js"; - const {b} = import("foo/index.js"); - import {c} from "foo/index.js"; - const {d} = import("foo/index.js"); - `, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: ` - export const a = 'a'; - export const b = 'b'; - export const c = 'c'; - export const d = 'd'; - `, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: ` - import {a} from "./node_modules/foo@1.0.0/index.js"; - const {b} = import('./node_modules/foo@1.0.0/index.js'); - import {c} from "./node_modules/foo@1.0.0/index.js"; - const {d} = import('./node_modules/foo@1.0.0/index.js'); - `, - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: ` - export const a = 'a'; - export const b = 'b'; - export const c = 'c'; - export const d = 'd'; - `, - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('namespaced NPM package', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "@foo/bar/index.js";', - }, - ]; - const cdn: CdnData = { - '@foo/bar': { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'index', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/@foo/bar@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/@foo/bar@1.0.0/index.js', - content: 'index', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('default module uses package.json "module" field as 1st choice', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'module.js': { - content: 'module', - }, - 'main.js': { - content: 'main', - }, - 'index.js': { - content: 'index', - }, - 'package.json': { - content: `{ - "module": "module.js", - "main": "main.js" - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/module.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/module.js', - content: 'module', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('default module uses package.json "main" field as 2nd choice', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'module.js': { - content: 'module', - }, - 'main.js': { - content: 'main', - }, - 'index.js': { - content: 'index', - }, - 'package.json': { - content: `{ - "main": "main.js" - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/main.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/main.js', - content: 'main', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('default module uses "index.js" field as 3rd choice', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'module.js': { - content: 'module', - }, - 'main.js': { - content: 'main', - }, - 'index.js': { - content: 'index', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'index', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('project file in nested directory', async () => { - const files: SampleFile[] = [ - { - name: 'some/sub/dir/index.js', - content: 'import "foo/index.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'index', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'some/sub/dir/index.js', - content: 'import "../../../node_modules/foo@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'index', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('import chain in dependency', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/a.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'a.js': { - content: 'import "./b.js";', - }, - 'b.js': { - content: 'import "./c.js";', - }, - 'c.js': { - content: 'c', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/a.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/a.js', - content: 'import "./b.js";', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/b.js', - content: 'import "./c.js";', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/c.js', - content: 'c', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('circular import in dependency', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/a.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'a.js': { - content: 'import "./b.js";', - }, - 'b.js': { - content: 'import "./a.js";', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/a.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/a.js', - content: 'import "./b.js";', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/b.js', - content: 'import "./a.js";', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test("version specified in local project's package.json", async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/index.js";', - }, - { - name: 'package.json', - content: ` - { - "dependencies": { - "foo": "^2.0.0" - } - } - `, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'foo1', - }, - }, - }, - '2.0.0': { - files: { - 'index.js': { - content: 'foo2', - }, - }, - }, - '3.0.0': { - files: { - 'index.js': { - content: 'foo3', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@2.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@2.0.0/index.js', - content: 'foo2', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'package.json', - content: ` - { - "dependencies": { - "foo": "^2.0.0" - } - } - `, - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test("version specified in dependency's package.json", async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/index.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'import "bar";', - }, - 'package.json': { - content: `{ - "dependencies": { - "bar": "^2.0.0" - } - }`, - }, - }, - }, - }, - }, - bar: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'bar1', - }, - }, - }, - '2.0.0': { - files: { - 'index.js': { - content: 'bar2', - }, - }, - }, - '3.0.0': { - files: { - 'index.js': { - content: 'bar3', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'import "../bar@2.0.0/index.js";', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/bar@2.0.0/index.js', - content: 'bar2', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('extension-less import in project file', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/bar";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'bar.js': { - content: 'bar', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/bar.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/bar.js', - contentType: 'text/javascript; charset=utf-8', - content: 'bar', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('extension-less import in dependency', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/a.js";', - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'a.js': { - content: 'import "./b";', - }, - 'b.js': { - content: 'b', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/a.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/a.js', - contentType: 'text/javascript; charset=utf-8', - content: 'import "./b.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/b.js', - contentType: 'text/javascript; charset=utf-8', - content: 'b', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('non-existent dependency', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "non-existent/index.js";', - }, - ]; - const cdn: CdnData = {}; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "non-existent/index.js";', - }, - }, - { - diagnostic: { - message: - 'Could not resolve module "non-existent/index.js": CDN HTTP 404 error (/non-existent@latest/package.json): Not Found', - range: { - end: { - character: 29, - line: 0, - }, - start: { - character: 8, - line: 0, - }, - }, - }, - filename: 'index.js', - kind: 'diagnostic', - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('invalid package.json', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo/index.js";', - }, - { - name: 'package.json', - content: `{ - "dependencies": XXX - }`, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'foo1', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "./node_modules/foo@1.0.0/index.js";', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'foo1', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'package.json', - content: `{ - "dependencies": XXX - }`, - }, - }, - { - diagnostic: { - message: - 'Invalid package.json: ' + - { - chrome: - 'SyntaxError: Unexpected token \'X\', ..."dencies": XXX\n "... is not valid JSON', - firefox: - 'SyntaxError: JSON.parse: unexpected character at line 2 column 28 of the JSON data', - safari: - 'SyntaxError: JSON Parse error: Unexpected identifier "XXX"', - }[browser], - range: { - start: - browser === 'safari' || browser === 'chrome' - ? {line: 0, character: 0} - : {line: 1, character: 27}, - end: {line: 2, character: 10}, - }, - }, - filename: 'package.json', - kind: 'diagnostic', - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('use import map', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'import "foo";', - }, - ]; - const importMap: ModuleImportMap = { - imports: { - foo: 'http://example.com/foo', - }, - }; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'foo', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'import "http://example.com/foo";', - }, - }, - ]; - await checkTransform(files, expected, importMap, cdn); - }); - - test('prefers "import" condition exports', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: ` - import 'foo'; - import 'foo/bar.js'; - `, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'esm/index.js': { - content: 'ESM', - }, - 'esm/bar.js': { - content: 'ESM', - }, - 'cjs/index.js': { - content: 'CJS', - }, - 'cjs/bar.js': { - content: 'CJS', - }, - 'index.js': { - content: 'NONE', - }, - 'bar.js': { - content: 'NONE', - }, - 'package.json': { - content: `{ - "exports": { - ".": { - "cjs": "./cjs/index.js", - "import": "./esm/index.js", - "default": "./index.js" - }, - "./bar.js": { - "cjs": "./cjs/bar.js", - "import": "./esm/bar.js", - "default": "./bar.js" - } - } - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: ` - import './node_modules/foo@1.0.0/esm/index.js'; - import './node_modules/foo@1.0.0/esm/bar.js'; - `, - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/esm/index.js', - content: 'ESM', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/esm/bar.js', - content: 'ESM', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('prefers "development" condition exports', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: ` - import 'foo'; - import 'foo/bar.js'; - `, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'PROD', - }, - 'bar.js': { - content: 'PROD', - }, - 'development/index.js': { - content: 'DEV', - }, - 'development/bar.js': { - content: 'DEV', - }, - 'package.json': { - content: `{ - "exports": { - ".": { - "development": "./development/index.js", - "default": "./index.js" - }, - "./bar.js": { - "development": "./development/bar.js", - "default": "./bar.js" - } - } - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: ` - import './node_modules/foo@1.0.0/development/index.js'; - import './node_modules/foo@1.0.0/development/bar.js'; - `, - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/development/index.js', - content: 'DEV', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/development/bar.js', - content: 'DEV', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('prefers "import" + "browser" condition exports over default', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: ` - import 'foo'; - import 'foo/bar.js'; - `, - }, - ]; - - const cdn: CdnData = { - foo: { - versions: { - '1.0.0': { - files: { - 'browser/index.js': { - content: 'BROWSER', - }, - 'browser/bar.js': { - content: 'BROWSER', - }, - 'default/index.js': { - content: 'DEFAULT', - }, - 'default/bar.js': { - content: 'DEFAULT', - }, - 'package.json': { - content: `{ - "exports": { - ".": { - "import": { - "browser": "./browser/index.js" - }, - "default": "./default/index.js" - }, - "./bar.js": { - "import": { - "browser": "./browser/bar.js" - }, - "default": "./default/bar.js" - } - } - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: ` - import './node_modules/foo@1.0.0/browser/index.js'; - import './node_modules/foo@1.0.0/browser/bar.js'; - `, - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/browser/index.js', - content: 'BROWSER', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/browser/bar.js', - content: 'BROWSER', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('@lion/button style import', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: ` - import '@lion/button/define'; - `, - }, - ]; - const cdn: CdnData = { - '@lion/button': { - versions: { - '0.14.3': { - files: { - 'define.js': { - // Note this is a bare module specifier referring to its own - // package, so package exports must be consulted again; there is - // no file called "define-button.js". - content: "import '@lion/button/define-button';", - }, - 'lion-button.js': { - content: 'customElements.define(...);', - }, - 'package.json': { - content: `{ - "exports": { - "./define-button": "./lion-button.js", - "./define": "./define.js" - } - }`, - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: ` - import './node_modules/@lion/button@0.14.3/define.js'; - `, - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/@lion/button@0.14.3/define.js', - content: "import './lion-button.js';", - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/@lion/button@0.14.3/lion-button.js', - content: 'customElements.define(...);', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); -}); diff --git a/src/test/cdn-base-url_test.ts b/src/test/cdn-base-url_test.ts deleted file mode 100644 index 62858e64..00000000 --- a/src/test/cdn-base-url_test.ts +++ /dev/null @@ -1,340 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import {checkTransform} from './worker-test-util.js'; -import {PlaygroundProject} from '../playground-project.js'; -import {PlaygroundIde} from '../playground-ide.js'; -import { - SampleFile, - BuildOutput, - ProjectManifest, - DiagnosticBuildOutput, -} from '../shared/worker-api.js'; -import {CdnData} from './fake-cdn-plugin.js'; - -suite('CDN Base URL Configuration', () => { - let container: HTMLDivElement; - - setup(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - teardown(() => { - container.remove(); - }); - - suite('CachingCdn URL Handling', () => { - test('resolves bare modules using CDN base URL', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {html} from "lit"; - console.log(html\`Hello\`); - `, - }, - ]; - const cdn: CdnData = { - lit: { - versions: { - '2.0.0': { - files: { - 'package.json': { - content: '{"main": "index.js"}', - }, - 'index.js': { - content: - 'export const html = (strings, ...values) => ({ strings, values });', - }, - 'index.d.ts': { - content: - 'export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => unknown;', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'diagnostic', - filename: 'index.ts', - diagnostic: { - code: 2307, - message: - "Cannot find module 'lit' or its corresponding type declarations.", - range: { - start: { - line: 1, - character: 31, - }, - end: { - line: 1, - character: 36, - }, - }, - severity: 1, - source: 'typescript', - }, - } as DiagnosticBuildOutput, - { - kind: 'diagnostic', - filename: 'index.ts', - diagnostic: { - code: 2584, - message: - "Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.", - range: { - start: {line: 2, character: 12}, - end: {line: 2, character: 19}, - }, - severity: 1, - source: 'typescript', - }, - } as DiagnosticBuildOutput, - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import { html } from "lit@2.0.0";\nconsole.log(html `Hello`);\n', - contentType: 'text/javascript', - }, - }, - ]; - - // Create a spy to capture the URL used for fetching - let capturedUrl: string | null = null; - const originalFetch = window.fetch; - window.fetch = function ( - url: string | URL | Request, - init?: RequestInit - ) { - const urlString = - url instanceof URL - ? url.toString() - : url instanceof Request - ? url.url - : url; - if (urlString.includes('lit')) { - console.log('Captured URL:', urlString); - capturedUrl = urlString; - } - return originalFetch(url, init); - } as typeof window.fetch; - - try { - // Import map is configured to use the CDN via the fake CDN provider - await checkTransform( - files, - expected, - { - imports: { - lit: 'lit@2.0.0', - }, - }, - cdn - ); - - // Verify the correct CDN URL was used - assert.exists(capturedUrl, 'A CDN URL should have been captured'); - assert.include( - capturedUrl!, - '/fake-cdn/', - 'The CDN URL should include the fake CDN path' - ); - assert.include( - capturedUrl!, - 'lit@', - 'The CDN URL should include the package name' - ); - } finally { - window.fetch = originalFetch; - } - }); - - test('uses default CDN base URL when not specified', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {html} from "lit"; - console.log(html\`Hello\`); - `, - }, - ]; - const cdn: CdnData = { - lit: { - versions: { - '2.0.0': { - files: { - 'package.json': { - content: '{"main": "index.js"}', - }, - 'index.js': { - content: - 'export const html = (strings, ...values) => ({ strings, values });', - }, - 'index.d.ts': { - content: - 'export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => unknown;', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'diagnostic', - filename: 'index.ts', - diagnostic: { - code: 2307, - message: - "Cannot find module 'lit' or its corresponding type declarations.", - range: { - start: { - line: 1, - character: 31, - }, - end: { - line: 1, - character: 36, - }, - }, - severity: 1, - source: 'typescript', - }, - } as DiagnosticBuildOutput, - { - kind: 'diagnostic', - filename: 'index.ts', - diagnostic: { - code: 2584, - message: - "Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.", - range: { - start: {line: 2, character: 12}, - end: {line: 2, character: 19}, - }, - severity: 1, - source: 'typescript', - }, - } as DiagnosticBuildOutput, - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import { html } from "lit@2.0.0";\nconsole.log(html `Hello`);\n', - contentType: 'text/javascript', - }, - }, - ]; - - // Test with default CDN base URL - await checkTransform( - files, - expected, - { - imports: { - lit: 'lit@2.0.0', - }, - }, - cdn - ); - }); - }); - - suite('PlaygroundProject CDN base URL', () => { - test('sets cdnBaseUrl property', async () => { - const project = document.createElement( - 'playground-project' - ) as PlaygroundProject; - project.cdnBaseUrl = 'https://cdn.jsdelivr.net/npm'; - container.appendChild(project); - await project.updateComplete; - assert.equal(project.cdnBaseUrl, 'https://cdn.jsdelivr.net/npm'); - }); - }); - - suite('PlaygroundIDE CDN base URL', () => { - test('passes cdnBaseUrl property to playground-project', async function () { - // Increase timeout for this test - this.timeout(10000); - - // Import the component first - await import('../playground-ide.js'); - - const ide = document.createElement('playground-ide') as PlaygroundIde; - ide.cdnBaseUrl = 'https://cdn.jsdelivr.net/npm'; - container.appendChild(ide); - - // Wait for component to initialize - await ide.updateComplete; - - // Wait for a bit to ensure shadow DOM is created - await new Promise((resolve) => setTimeout(resolve, 100)); - - // Ensure shadow root exists - assert.exists(ide.shadowRoot, 'IDE should have a shadow root'); - - // Get and check the project component - const project = ide.shadowRoot!.querySelector( - 'playground-project' - ) as PlaygroundProject; - assert.exists(project, 'Playground project should exist in shadow root'); - - // Wait for project to update - await project.updateComplete; - - // Check the CDN property - assert.equal(project.cdnBaseUrl, 'https://cdn.jsdelivr.net/npm'); - }); - }); - - suite('End-to-end CDN URL resolution', () => { - test('correctly resolves modules using the configured CDN base URL', async function () { - this.timeout(10000); - - // Create a playground-ide with custom CDN base URL - const ide = document.createElement('playground-ide') as PlaygroundIde; - const customCdnBaseUrl = 'https://custom-cdn.example.com/packages'; - ide.cdnBaseUrl = customCdnBaseUrl; - - // Add a simple project that imports from a bare module - const projectConfig: ProjectManifest = { - files: { - 'index.ts': { - content: 'import {html} from "lit";\nconsole.log(html`Hello`);', - }, - }, - importMap: { - imports: { - lit: 'lit@2.0.0', - }, - }, - }; - - ide.config = projectConfig; - - container.appendChild(ide); - await ide.updateComplete; - - // Get the project component and verify its CDN base URL - const project = ide.shadowRoot!.querySelector( - 'playground-project' - ) as PlaygroundProject; - assert.equal( - project.cdnBaseUrl, - customCdnBaseUrl, - 'CDN base URL should be passed from IDE to project' - ); - }); - }); -}); diff --git a/src/test/codemirror-extension-mixin_test.ts b/src/test/codemirror-extension-mixin_test.ts deleted file mode 100644 index 6937bf4b..00000000 --- a/src/test/codemirror-extension-mixin_test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import {html, render, LitElement} from 'lit'; -import {customElement} from 'lit/decorators.js'; -import {expect} from '@open-wc/testing'; -import {spy} from 'sinon'; - -import { - codemirrorExtensionMixin, - RegisterCodemirrorExtensionEvent, - CodemirrorExtensionRegisteredEvent, - PlaygroundEditorReadyEvent, - CodemirrorExtension, -} from '../codemirror-extension-mixin.js'; - -@customElement('test-extension') -class TestExtension - extends codemirrorExtensionMixin(LitElement) - implements CodemirrorExtension -{ - override getExtensions() { - return []; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'test-extension': TestExtension; - } -} - -suite('CodemirrorExtensionMixin', () => { - let container: HTMLElement; - - setup(async () => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - teardown(() => { - container.remove(); - }); - - test('fires register event on connect', async () => { - const registrationSpy = spy(); - container.addEventListener( - RegisterCodemirrorExtensionEvent.eventName, - registrationSpy - ); - - const newEl = document.createElement('test-extension') as TestExtension; - container.appendChild(newEl); - await newEl.updateComplete; - - expect(registrationSpy.calledOnce).to.be.true; - const event = registrationSpy.args[0][0]; - expect(event).to.be.an.instanceOf(RegisterCodemirrorExtensionEvent); - }); - - test('becomes registered and stores unregister callback', async () => { - render(html``, container); - const el = container.querySelector('test-extension')!; - const unregisterSpy = spy(); - expect(el.isRegistered).to.be.false; - - el.dispatchEvent(new CodemirrorExtensionRegisteredEvent(unregisterSpy)); - - expect(el.isRegistered).to.be.true; - expect(el._unregister).to.equal(unregisterSpy); - }); - - test('calls unregister on disconnect', async () => { - const unregisterSpy = spy(); - render(html``, container); - const el = container.querySelector('test-extension')!; - el.dispatchEvent(new CodemirrorExtensionRegisteredEvent(unregisterSpy)); - expect(unregisterSpy.called).to.be.false; - - el.remove(); // This triggers disconnectedCallback - - expect(unregisterSpy.calledOnce).to.be.true; - }); - - test('retries registration on editor-ready event if not registered', async () => { - const registrationSpy = spy(); - render(html``, container); - const el = container.querySelector('test-extension')!; - container.addEventListener( - RegisterCodemirrorExtensionEvent.eventName, - registrationSpy - ); - - el.isRegistered = false; - // The first registration happens on connect, so we reset the spy. - registrationSpy.resetHistory(); - - el.dispatchEvent(new PlaygroundEditorReadyEvent()); - - expect(registrationSpy.calledOnce, 'fired on ready event').to.be.true; - }); - - test('does not retry registration on editor-ready event if already registered', async () => { - const registrationSpy = spy(); - container.addEventListener( - RegisterCodemirrorExtensionEvent.eventName, - registrationSpy - ); - - const unregisterSpy = spy(); - render(html``, container); - const el = container.querySelector('test-extension')!; - el.dispatchEvent(new CodemirrorExtensionRegisteredEvent(unregisterSpy)); - expect(el.isRegistered).to.be.true; - - // The first registration happens on connect, so we reset the spy. - registrationSpy.resetHistory(); - - el.dispatchEvent(new PlaygroundEditorReadyEvent()); - - expect(registrationSpy.notCalled).to.be.true; - }); -}); diff --git a/src/test/completions_test.ts b/src/test/completions_test.ts deleted file mode 100644 index a6ca6397..00000000 --- a/src/test/completions_test.ts +++ /dev/null @@ -1,289 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import '../playground-ide.js'; -import '../playground-code-editor.js'; - -import {assert} from '@esm-bundle/chai'; -import {sendKeys} from '@web/test-runner-commands'; -import {html, ReactiveElement, render} from 'lit'; - -import {PlaygroundCodeEditor} from '../playground-code-editor.js'; -import {PlaygroundProject} from '../playground-project.js'; - -const AUTOCOMPLETE_WRAPPER_CLASS = '.cm-tooltip-autocomplete ul'; -const ACTIVE_SELECTOR = `${AUTOCOMPLETE_WRAPPER_CLASS} [aria-selected="true"]`; -const COMPLETION_LABEL = `${AUTOCOMPLETE_WRAPPER_CLASS} .cm-completionLabel`; - -suite('completions', () => { - let container: HTMLDivElement; - let project: PlaygroundProject | undefined | null; - let editor: PlaygroundCodeEditor | undefined | null; - let testRunning: boolean; - - setup(async () => { - testRunning = true; - container = document.createElement('div'); - document.body.appendChild(container); - render( - html` - - - - -
- `, - container - ); - await assertPreviewContains(''); - - project = document - .querySelector('playground-ide') - ?.shadowRoot?.querySelector('playground-project'); - - editor = document - .querySelector('playground-ide') - ?.shadowRoot?.querySelector('playground-file-editor') - ?.shadowRoot?.querySelector('playground-code-editor'); - }); - - teardown(() => { - testRunning = false; - container.remove(); - }); - - const emulateUser = async (word: string) => { - const chars = word.split(''); - while (chars.length > 0) { - const c = chars.shift(); - if (c) { - await raf(); - await raf(); - await sendKeys({ - type: c, - }); - } - } - }; - - const waitForIframeLoad = (iframe: HTMLElement) => - new Promise((resolve) => { - iframe.addEventListener('load', () => resolve(), {once: true}); - }); - - const assertPreviewContains = async (text: string) => { - const iframe = (await pierce( - 'playground-ide', - 'playground-preview', - 'iframe' - )) as HTMLIFrameElement; - await waitForIframeLoad(iframe); - // TODO(aomarks) Chromium and Webkit both fire iframe "load" after the - // contentDocument has actually loaded, but Firefox fires it before. Why is - // that? If not for that, we wouldn't need to poll here. - await new Promise((resolve) => { - const check = () => { - if (iframe.contentDocument?.body?.textContent?.includes(text)) { - resolve(); - } else if (testRunning) { - setTimeout(check, 10); - } - }; - check(); - }); - }; - - const waitForElement = ( - parent: ParentNode | null | undefined, - elementName: string - ) => { - return new Promise((resolve, reject) => { - (function tryToFindElem(attempt) { - if (parent?.querySelector(elementName)) { - return resolve(''); - } - if (attempt > 20) { - return reject( - new Error(`Element ${elementName} not found after 20 attempts`) - ); - } - setTimeout(() => tryToFindElem(attempt + 1), 200); - })(1); - }); - }; - - const waitForCompletionsToAppear = () => - waitForElement(editor?.shadowRoot, ACTIVE_SELECTOR); - - const raf = async () => - new Promise((r) => requestAnimationFrame(() => setTimeout(r, 50))); - const wait = async (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const pierce = async (...selectors: string[]) => { - let node = document.body; - for (const selector of selectors) { - const result = (node.shadowRoot ?? node).querySelector(selector); - assert.instanceOf(result, Element); - if ((result as ReactiveElement).updateComplete) { - await (result as ReactiveElement).updateComplete; - } - node = result as HTMLElement; - } - return node; - }; - - const waitForCompileDone = () => - new Promise((resolve) => { - project?.addEventListener( - 'compileDone', - async () => { - resolve(''); - }, - {once: true} - ); - }); - - test('displays completion items on input', async () => { - await waitForCompileDone(); - editor?.focus(); - - await wait(200); - await emulateUser('document.query'); - - try { - await waitForCompletionsToAppear(); - await waitForElement(editor?.shadowRoot, AUTOCOMPLETE_WRAPPER_CLASS); - await raf(); - await raf(); - - const completionItemList = editor?.shadowRoot?.querySelector( - AUTOCOMPLETE_WRAPPER_CLASS - ); - - assert.isNotNull(completionItemList, 'Completion item list should exist'); - assert.isDefined( - completionItemList, - 'Completion item list should be defined' - ); - - assert.isAtLeast( - completionItemList?.children.length || 0, - 1, - 'Should have at least one completion item' - ); - } catch (error) { - console.error('Completion test failed:', error); - console.log('Editor value:', editor?.value); - throw error; - } - }); - - test('can navigate the completion item list', async () => { - await waitForCompileDone(); - editor?.focus(); - - await wait(200); - await emulateUser('document.que'); - await waitForCompletionsToAppear(); - await raf(); - await raf(); - await wait(100); - - sendKeys({ - press: 'ArrowDown', - }); - - await raf(); - await raf(); - - const activeHint = editor?.shadowRoot?.querySelector(ACTIVE_SELECTOR); - - assert.match( - activeHint!.id, - /^cm-ac-.+-1$/, - 'Active hint should have the ID cm-complete-0-1 marking the second hint' - ); - }); - - test('enter key confirms completion item selection', async () => { - await waitForCompileDone(); - editor?.focus(); - await emulateUser('document.queryS'); - - try { - await waitForCompletionsToAppear(); - - await raf(); - await raf(); - await raf(); - - const editorChange = new Promise((resolve) => { - const changeHandler = () => { - editor?.removeEventListener('change', changeHandler); - resolve(''); - }; - editor?.addEventListener('change', changeHandler); - setTimeout(() => { - resolve(''); - }, 20000); - }); - - await sendKeys({ - press: 'Enter', - }); - - await editorChange; - - assert.include( - editor?.value || '', - 'document.query', - 'Completion should be visible in the code editor' - ); - - await wait(500); - - const completionItemList = editor?.shadowRoot?.querySelector( - AUTOCOMPLETE_WRAPPER_CLASS - ); - assert.isNull( - completionItemList, - 'Completion item list should disappear on completion confirmation' - ); - } catch (error) { - console.error('Enter key confirmation test failed:', error); - console.log('Editor value:', editor?.value); - throw error; - } - }); - - test('completions should contain local scoped items', async () => { - await waitForCompileDone(); - editor?.focus(); - await emulateUser(`function reallySpecificFunctionName() { - console.log("foo"); - }`); - await sendKeys({press: 'Enter'}); - await emulateUser('reallySpecifi'); - await waitForElement(editor?.shadowRoot, AUTOCOMPLETE_WRAPPER_CLASS); - - const completionItemList = editor?.shadowRoot?.querySelector( - AUTOCOMPLETE_WRAPPER_CLASS - ); - assert.isNotNull(completionItemList); - - const completionItemText = ( - completionItemList?.querySelector(COMPLETION_LABEL) as HTMLElement - ).innerText; - assert.equal( - completionItemText, - 'reallySpecificFunctionName', - 'Completion item should be the created function' - ); - }); -}); diff --git a/src/test/extensions_test.ts b/src/test/extensions_test.ts deleted file mode 100644 index f0f731b6..00000000 --- a/src/test/extensions_test.ts +++ /dev/null @@ -1,531 +0,0 @@ -import {html, render} from 'lit'; -import {customElement} from 'lit/decorators.js'; -import {assert} from '@esm-bundle/chai'; -import {codemirrorExtensionMixin} from '../codemirror-extension-mixin.js'; -import {EditorView} from '@codemirror/view'; -import '../playground-code-editor.js'; -import '../playground-ide.js'; -import type {PlaygroundIde} from '../playground-ide.js'; -import type {PlaygroundCodeEditor} from '../playground-code-editor.js'; - -@customElement('test-theme-extension') -export class TestThemeExtension extends codemirrorExtensionMixin(HTMLElement) { - hasFired = false; - override getExtensions() { - this.hasFired = true; - - return EditorView.theme({ - '&': { - backgroundColor: 'rgb(255, 0, 0)', - }, - }); - } -} - -@customElement('test-theme-extension-2') -export class TestThemeExtension2 extends codemirrorExtensionMixin(HTMLElement) { - hasFired = false; - override getExtensions() { - this.hasFired = true; - return EditorView.theme({ - '&': { - color: 'rgb(0, 255, 0)', - }, - }); - } -} - -@customElement('test-attribute-extension') -export class TestAttributeExtension extends codemirrorExtensionMixin( - HTMLElement -) { - hasFired = false; - override getExtensions() { - this.hasFired = true; - return EditorView.contentAttributes.of({ - 'data-foo': 'bar', - }); - } -} - -function getFiredPromise() { - let resolve: (value: unknown) => void; - const hasFired = new Promise((res) => { - resolve = res; - }); - - const listener = () => { - resolve?.(true); - }; - - return {hasFired, listener}; -} - -async function getCodeMirrorBackgroundColor( - el: PlaygroundCodeEditor, - selector: string = '.cm-editor', - styleProp: keyof CSSStyleDeclaration = 'backgroundColor' -) { - await el.updateComplete; - let color = ''; - await new Promise((resolve) => { - const check = async () => { - await el.updateComplete; - await el.updateComplete; - const cm = el.shadowRoot!.querySelector(selector) as HTMLDivElement; - - if (!cm) { - setTimeout(check, 30); - return; - } - // Firefox won't trigger a style recalc for some reason in a test, so we - // need to invalidate the style cache, so we create a new style element, - // prepend it, get the value of the color, and remove the style element. - // If you remove the style element before we get the color, Firefox will - // return to the wrong cached color. - const s = document.createElement('style'); - s.textContent = `${selector} { height: ${Math.random() * 20 + 1}px; }`; - cm.before(s); - await new Promise((resolve) => requestAnimationFrame(resolve)); - await new Promise((resolve) => setTimeout(resolve, 100)); - cm.style.width = `${Math.random() * 20 + 1}px`; - await new Promise((resolve) => requestAnimationFrame(resolve)); - await new Promise((resolve) => setTimeout(resolve, 100)); - color = getComputedStyle(cm)[styleProp] as string; - cm.style.width = ''; - s.remove(); - resolve(); - }; - check(); - }); - return color; -} - -suite('Extensions', () => { - let container: HTMLElement; - - setup(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - teardown(() => { - container.remove(); - }); - - async function getEditor(ide: PlaygroundIde) { - await ide.updateComplete; - const fileEditor = ide.shadowRoot!.querySelector('playground-file-editor')!; - await fileEditor.updateComplete; - const editor = fileEditor.shadowRoot!.querySelector( - 'playground-code-editor' - )!; - await editor.updateComplete; - return editor; - } - - suite('Declarative Extensions', () => { - test('editor with declarative extension', async () => { - const {hasFired, listener} = getFiredPromise(); - render( - html` - - - - `, - container - ); - const editor = container.querySelector('playground-code-editor')!; - await editor.updateComplete; - await hasFired; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - }); - - test('ide with declarative extension', async () => { - const {hasFired, listener} = getFiredPromise(); - render( - html` - - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await hasFired; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - }); - - test('ide with multiple declarative extensions', async () => { - const {hasFired: firstFired, listener: firstListener} = getFiredPromise(); - const {hasFired: secondFired, listener: secondListener} = - getFiredPromise(); - render( - html` - - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - - await Promise.all([firstFired, secondFired]); - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - assert.equal( - await getCodeMirrorBackgroundColor(editor, '.cm-content', 'color'), - 'rgb(0, 255, 0)' - ); - }); - - test('multiple extensions are registered', async () => { - const {hasFired: firstFired, listener: firstListener} = getFiredPromise(); - const {hasFired: secondFired, listener: secondListener} = - getFiredPromise(); - render( - html` - - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - await ide.updateComplete; - const editor = await getEditor(ide); - await Promise.all([firstFired, secondFired]); - - // For now, just check that we can access the editor - we'll verify the actual extensions work via color tests - assert.isNotNull(editor, 'Should be able to access the code editor'); - }); - - test('ide with multiple non-overriding declarative extensions', async () => { - const {hasFired: firstFired, listener: firstListener} = getFiredPromise(); - const {hasFired: secondFired, listener: secondListener} = - getFiredPromise(); - render( - html` - - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await Promise.all([firstFired, secondFired]); - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - const cmContent = editor.shadowRoot!.querySelector('.cm-content')!; - assert.equal(cmContent.getAttribute('data-foo'), 'bar'); - }); - - test('disconnecting a declarative extension', async () => { - const {hasFired, listener} = getFiredPromise(); - render( - html` - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await hasFired; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - - const declarativeExtension = ide.querySelector('test-theme-extension')!; - declarativeExtension.remove(); - await ide.updateComplete; - - assert.notEqual( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - }); - }); - - suite('Programmatic Extensions', () => { - test('ide with programmatic extension', async () => { - if (navigator.userAgent.toLowerCase().includes('firefox')) { - test.skip( - 'Firefox has a bug where the background color is not updated correctly in a test environment' - ); - return; - } - - const programmaticTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - render( - html` - - - - `, - container - ); - const editor = await getEditor( - container.querySelector('playground-ide')! - ); - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(0, 0, 255)' - ); - }); - - test('code-editor with programmatic extension (direct)', async () => { - const programmaticTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - render( - html` - - - `, - container - ); - const editor = container.querySelector('playground-code-editor')!; - await editor.updateComplete; - await editor.updateComplete; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(0, 0, 255)' - ); - }); - - test('programmatic extension type handling', async () => { - const programmaticTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - - render( - html` - - - `, - container - ); - const editor = container.querySelector('playground-code-editor')!; - await editor.updateComplete; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(0, 0, 255)' - ); - }); - - test('changing programmatic extensions', async () => { - if (navigator.userAgent.toLowerCase().includes('firefox')) { - test.skip( - 'Firefox has a bug where the background color is not updated correctly in a test environment' - ); - return; - } - - const blueTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - const greenTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 255, 0)', - }, - }); - render( - html` - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(0, 0, 255)' - ); - - ide.extensions = [greenTheme]; - await ide.updateComplete; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(0, 255, 0)' - ); - }); - }); - - suite('Mixed Programmatic and Declarative Extensions', () => { - test('ide with both declarative and programmatic extensions', async () => { - const {hasFired, listener} = getFiredPromise(); - const programmaticTheme = EditorView.theme({ - '&': { - color: 'rgb(0, 0, 255)', - }, - }); - render( - html` - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await hasFired; - - assert.equal( - await getCodeMirrorBackgroundColor(editor), - 'rgb(255, 0, 0)' - ); - assert.equal( - await getCodeMirrorBackgroundColor(editor, '.cm-content', 'color'), - 'rgb(0, 0, 255)' - ); - }); - }); - test('conflicting declarative and programmatic extensions', async () => { - const {hasFired, listener} = getFiredPromise(); - const programmaticTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - render( - html` - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await hasFired; - - // Programmatic should override declarative. - assert.equal(await getCodeMirrorBackgroundColor(editor), 'rgb(255, 0, 0)'); - }); - - test('non-conflicting declarative and programmatic extensions', async () => { - const {hasFired, listener} = getFiredPromise(); - const programmaticTheme = EditorView.theme({ - '&': { - backgroundColor: 'rgb(0, 0, 255)', - }, - }); - render( - html` - - - - - `, - container - ); - const ide = container.querySelector('playground-ide')!; - const editor = await getEditor(ide); - await hasFired; - - assert.equal(await getCodeMirrorBackgroundColor(editor), 'rgb(0, 0, 255)'); - const cmContent = editor.shadowRoot!.querySelector('.cm-content')!; - assert.equal(cmContent.getAttribute('data-foo'), 'bar'); - }); -}); diff --git a/src/test/fake-cdn-plugin.ts b/src/test/fake-cdn-plugin.ts deleted file mode 100644 index e213ecd1..00000000 --- a/src/test/fake-cdn-plugin.ts +++ /dev/null @@ -1,196 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {TestRunnerPlugin} from '@web/test-runner-core/dist/server/TestRunnerPlugin.js'; -import semver from 'semver'; - -/** - * A plugin for @web/test-runner that simulates an NPM CDN like unpkg.com. It - * extends the built-in @web/test-runner server, and can be re-configured from - * the test suite itself between each test using a server command - * (https://modern-web.dev/docs/test-runner/commands/). - * - * Usage: - * - * import {executeServerCommand} from '@web/test-runner-commands'; - * - * const cdnData = { - * "foo": { - * "versions": { - * "1.2.3": { - * "files": { - * "package.json": { - * "content": `{ - * "main": "lib/index.js" - * }` - * }, - * "lib/index.js": { - * "content": "console.log('hello');" - * }, - * } - * } - * } - * } - * }; - * const {cdnBaseUrl, id} = await executeServerCommand('set-fake-cdn-data', cdnData); - * // Redirects to /foo@1.2.3/lib/index.js and serves its content. - * const result = await fetch(new URL("foo@^1.0.0", cdnBaseUrl).href); - * await executeServerCommand('delete-fake-cdn-data', id); - */ -export function fakeCdnPlugin(): TestRunnerPlugin { - const pathPrefix = '/fake-cdn/'; - let baseUrl: string | undefined; - const dataMap = new Map(); - let _nextId = 0; - - return { - name: 'fake-cdn', - - serverStart(args) { - baseUrl = `http://${args.config.hostname}:${args.config.port}${pathPrefix}`; - }, - - executeCommand({command, payload}) { - if (command === 'set-fake-cdn-data') { - // Create a separate data store for each configuration, so that we can - // support concurrent tests. - const id = String(_nextId++); - dataMap.set(id, payload as CdnData); - return { - id, - cdnBaseUrl: `${baseUrl}${id}/`, - }; - } else if (command === 'delete-fake-cdn-data') { - // Allow deleting test data so that memory doesn't grow unbounded, - // especially for when we're in a long running --watch mode session. - const id = payload as string; - dataMap.delete(id); - return true; - } - return null; - }, - - serve(ctx) { - if (!ctx.path.startsWith(pathPrefix)) { - return undefined; - } - const urlMatch = ctx.path.slice(pathPrefix.length).match(/^(\d+)\/(.*)/); - if (urlMatch === null) { - ctx.response.status = 404; - return undefined; - } - const id = urlMatch[1]; - const data = dataMap.get(id); - if (data === undefined) { - ctx.response.status = 404; - return undefined; - } - const specifier = decodeURIComponent(urlMatch[2]); - const parsed = parseNpmModuleSpecifier(specifier); - if (!parsed) { - ctx.response.status = 404; - return undefined; - } - const {pkg, semverRangeOrTag, path} = parsed; - const packageData = data[pkg]; - if (!packageData) { - ctx.response.status = 404; - return undefined; - } - // Note we don't support tags other than "latest" for now, but we could - // easily add that to CdnData if needed. - const semverRange = - semverRangeOrTag === '' || semverRangeOrTag === 'latest' - ? '*' - : semverRangeOrTag; - const versions = Object.keys(packageData.versions); - const version = semver.maxSatisfying(versions, semverRange); - if (!version) { - ctx.response.status = 404; - return undefined; - } - if (version !== semverRange) { - // The version in the URL was a range, rather than a concrete version. - // Redirect to the concrete version's URL. Note that redirecting here, - // rather than just serving the resolved file directly, is an important - // behavior of unpkg that we want to preserve in tests, because we rely - // on being able to extract resolved versions from redirect URLs. - ctx.response.status = 302; - ctx.response.redirect(`${pathPrefix}${id}/${pkg}@${version}/${path}`); - return undefined; - } - const versionData = packageData.versions[version]; - if (!versionData) { - ctx.response.status = 404; - return undefined; - } - if (path === '') { - const packageJson = JSON.parse( - versionData.files['package.json']?.content ?? '{}' - ) as {main?: string}; - // Only look at the "main" field, not "module", because that's how - // unpkg.com works when it's not in ?module mode, which is how we're - // using it (so that we get raw bare module specifiers). - const main = packageJson.main ?? 'index.js'; - ctx.response.status = 302; - ctx.response.redirect(`${pathPrefix}${id}/${pkg}@${version}/${main}`); - return undefined; - } - const file = versionData.files[path]; - if (file !== undefined) { - ctx.response.status = file.status ?? 200; - ctx.response.body = file.content; - ctx.response.type = path.endsWith('.js') - ? 'text/javascript' - : path.endsWith('.json') - ? 'application/json' - : 'text/plain'; - return undefined; - } - if (path === 'package.json') { - // You can't publish to NPM without a package.json; for convenience in - // testing, just make an empty one if the test data didn't contain one. - return { - body: '{}', - type: 'application/json', - }; - } - if (versionData.files[path + '.js']) { - ctx.response.status = 302; - ctx.response.redirect(ctx.path + '.js'); - return undefined; - } - ctx.response.status = 404; - return undefined; - }, - }; -} - -export type CdnData = { - [pkg: string]: { - versions: { - [version: string]: { - files: { - [path: string]: { - content: string; - status?: number; - }; - }; - }; - }; - }; -}; - -const parseNpmModuleSpecifier = ( - specifier: string -): {pkg: string; semverRangeOrTag: string; path: string} | undefined => { - const match = specifier.match(/^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?\/?(.*)$/); - if (match === null) { - return undefined; - } - const [, pkg, semverRangeOrTag, path] = match; - return {pkg, semverRangeOrTag, path}; -}; diff --git a/src/test/node-module-resolver_test.ts b/src/test/node-module-resolver_test.ts deleted file mode 100644 index 446f1ee1..00000000 --- a/src/test/node-module-resolver_test.ts +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import {NodeModuleResolver} from '../typescript-worker/node-module-resolver.js'; - -import {PackageJson} from '../typescript-worker/util.js'; - -suite('NodeModuleResolver', () => { - const check = ({ - path, - packageJson, - conditions = ['default', 'module', 'import'], - expected, - }: { - path: string; - packageJson: PackageJson; - conditions?: string[]; - expected: string; - }) => { - const resolver = new NodeModuleResolver({conditions}); - const actual = resolver.resolve( - {pkg: 'mydep', version: '1.2.3', path}, - packageJson, - './my-element.js' - ); - assert.equal(actual, expected); - }; - - test('default with path', () => { - check({ - path: 'foo.js', - packageJson: {}, - expected: 'foo.js', - }); - }); - - test('default no path', () => { - check({ - path: '', - packageJson: {}, - expected: 'index.js', - }); - }); - - test('default with main', () => { - check({ - path: '', - packageJson: { - main: 'main.js', - }, - expected: 'main.js', - }); - }); - - test('exports default module', () => { - check({ - path: '', - packageJson: { - exports: { - '.': './main.js', - }, - }, - expected: 'main.js', - }); - }); - - test('exports main sugar', () => { - check({ - path: '', - packageJson: { - exports: './main.js', - }, - expected: 'main.js', - }); - }); - - test('exports remapped module', () => { - check({ - path: 'foo.js', - packageJson: { - exports: { - './foo.js': './lib/foo.js', - }, - }, - expected: 'lib/foo.js', - }); - }); - - test('throws if exports but no mapping', () => { - assert.throws(() => { - check({ - path: 'foo.js', - packageJson: { - exports: { - './bar.js': './lib/bar.js', - }, - }, - expected: 'Package subpath', - }); - }, 'Package subpath \'./foo.js\' is not defined by "exports" in /node_modules/mydep@1.2.3/package.json imported from ./my-element.js'); - }); - - test("throws if target doesn't start with ./", () => { - assert.throws(() => { - check({ - path: 'foo.js', - packageJson: { - exports: { - './foo.js': 'dist/foo.js', - }, - }, - expected: '', - }); - }, 'Invalid "exports" target "dist/foo.js" defined for \'./foo.js\' in the package config /node_modules/mydep@1.2.3/package.json imported from ./my-element.js; targets must start with "./"'); - }); - - test('subpath export', () => { - check({ - path: 'features/foo.js', - packageJson: { - exports: { - './features/*': './src/features/*', - }, - }, - expected: 'src/features/foo.js', - }); - }); - - test('banned subpath export', () => { - assert.throws(() => { - check({ - path: 'features/private/foo.js', - packageJson: { - exports: { - './features/*': './src/features/*', - './features/private/*': null, - }, - }, - expected: '', - }); - }, 'Package subpath \'./features/private/foo.js\' is not defined by "exports" in /node_modules/mydep@1.2.3/package.json imported from ./my-element.js'); - }); - - test('conditions', () => { - check({ - path: '', - packageJson: { - exports: { - '.': { - import: './main.js', - require: './main.cjs', - }, - }, - }, - expected: 'main.js', - }); - }); - - test('conditions with main sugar', () => { - check({ - path: '', - packageJson: { - exports: { - import: './main.js', - require: './main.cjs', - }, - }, - expected: 'main.js', - }); - }); - - test('condition precedence', () => { - check({ - path: '', - packageJson: { - exports: { - '.': { - development: './dev.js', - default: './prod.js', - }, - }, - }, - conditions: ['development'], - expected: 'dev.js', - }); - }); - - test('nested conditions', () => { - const path = ''; - const packageJson = { - exports: { - node: { - import: './feature-node.mjs', - require: './feature-node.cjs', - }, - default: './feature.mjs', - }, - }; - check({ - path, - packageJson, - conditions: ['browser'], - expected: 'feature.mjs', - }); - check({ - path, - packageJson, - conditions: ['node', 'import'], - expected: 'feature-node.mjs', - }); - check({ - path, - packageJson, - conditions: ['node', 'require'], - expected: 'feature-node.cjs', - }); - }); - - test('target array, first is valid', () => { - check({ - path: '', - packageJson: { - exports: { - '.': ['./main.js', 'INVALID'], - }, - }, - expected: 'main.js', - }); - }); - - test('target array, second is valid', () => { - check({ - path: '', - packageJson: { - exports: { - '.': ['INVALID', './main.js'], - }, - }, - expected: 'main.js', - }); - }); -}); diff --git a/src/test/node-modules-layout-maker_test.ts b/src/test/node-modules-layout-maker_test.ts deleted file mode 100644 index 71d74628..00000000 --- a/src/test/node-modules-layout-maker_test.ts +++ /dev/null @@ -1,303 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import { - NodeModulesLayoutMaker, - DependencyGraph, - NodeModulesDirectory, - PackageDependencies, -} from '../typescript-worker/node-modules-layout-maker.js'; - -suite('NodeModulesLayoutMaker', () => { - const checkLayout = ( - rootDeps: PackageDependencies, - depGraph: DependencyGraph, - expected: NodeModulesDirectory - ) => { - const layoutMaker = new NodeModulesLayoutMaker(); - const actual = layoutMaker.layout(rootDeps, depGraph); - assert.deepEqual(actual, expected); - }; - - test('no dependencies', () => { - // ROOT - const rootDeps: PackageDependencies = {}; - const depGraph: DependencyGraph = {}; - const expected: NodeModulesDirectory = {}; - checkLayout(rootDeps, depGraph, expected); - }); - - test('only direct dependencies', () => { - // ROOT - // /\ - // / \ - // v v - // A1 B2 - const rootDeps: PackageDependencies = { - a: '1', - b: '2', - }; - const depGraph: DependencyGraph = {}; - // ROOT - // ├── A1 - // └── B2 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - b: {version: '2', nodeModules: {}}, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('simple chain', () => { - // ROOT - // | - // v - // A1 - // | - // v - // B2 - // | - // v - // C3 - const rootDeps: PackageDependencies = { - a: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {b: '2'}}, - b: {2: {c: '3'}}, - }; - // ROOT - // ├── A1 - // ├── B2 - // └── C3 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - b: {version: '2', nodeModules: {}}, - c: {version: '3', nodeModules: {}}, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('version conflict between root and branch', () => { - // ROOT - // /\ - // v v - // A1 B1 - // | - // v - // B2 - const rootDeps: PackageDependencies = { - a: '1', - b: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {b: '2'}}, - }; - // ROOT - // ├── A1 - // │ └── B2 - // └── B1 - const expected: NodeModulesDirectory = { - a: { - version: '1', - nodeModules: { - b: {version: '2', nodeModules: {}}, - }, - }, - b: {version: '1', nodeModules: {}}, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('version conflict between root and longer branch', () => { - // ROOT - // /\ - // / \ - // v v - // A1 B1 - // | - // v - // C1 - // | - // v - // B2 - const rootDeps: PackageDependencies = { - a: '1', - b: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {c: '1'}}, - c: {1: {b: '2'}}, - }; - // ROOT - // ├── A1 - // ├── B1 - // └── C1 - // └── B2 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - b: {version: '1', nodeModules: {}}, - c: { - version: '1', - nodeModules: { - b: { - version: '2', - nodeModules: {}, - }, - }, - }, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('version conflict between two branches', () => { - // ROOT - // /\ - // / \ - // v v - // A1 B1 - // | | - // v v - // C1 C2 - const rootDeps: PackageDependencies = { - a: '1', - b: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {c: '1'}}, - b: {1: {c: '2'}}, - }; - // ROOT - // ├── A1 - // ├── B1 - // │ └── C2 - // └── C1 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - b: { - version: '1', - nodeModules: { - c: {version: '2', nodeModules: {}}, - }, - }, - c: {version: '1', nodeModules: {}}, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('version conflict requiring directory duplication', () => { - // ROOT - // /|\ - // / | \ - // / | \ - // v v v - // A1 B1 C1 - // \ / - // \ / - // v - // A2 --> D1 - const rootDeps: PackageDependencies = { - a: '1', - b: '1', - c: '1', - }; - const depGraph: DependencyGraph = { - a: {2: {d: '1'}}, - b: {1: {a: '2'}}, - c: {1: {a: '2'}}, - }; - // ROOT - // ├── A1 - // ├── B1 - // │ └── A2 - // ├── C1 - // │ └── A2 - // └── D1 - const expected: NodeModulesDirectory = { - a: { - version: '1', - nodeModules: {}, - }, - b: { - version: '1', - nodeModules: { - a: {version: '2', nodeModules: {}}, - }, - }, - c: { - version: '1', - nodeModules: { - a: {version: '2', nodeModules: {}}, - }, - }, - d: { - version: '1', - nodeModules: {}, - }, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('short loop', () => { - // ROOT --> A1 --> B1 - // ^ | - // | | - // +-----+ - const rootDeps: PackageDependencies = { - a: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {b: '1'}}, - b: {1: {a: '1'}}, - }; - // ROOT - // ├── A1 - // └── B1 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - b: {version: '1', nodeModules: {}}, - }; - checkLayout(rootDeps, depGraph, expected); - }); - - test('longer loop on a branch', () => { - // ROOT - // /\ - // / \ - // v v - // A1 C1 - // / ^ - // / \ - // v \ - // B1 --> C2 - const rootDeps: PackageDependencies = { - a: '1', - c: '1', - }; - const depGraph: DependencyGraph = { - a: {1: {b: '1'}}, - b: {1: {c: '2'}}, - c: {2: {a: '1'}}, - }; - // ROOT - // ├── A1 - // ├── C1 - // └── B1 - // └── C2 - const expected: NodeModulesDirectory = { - a: {version: '1', nodeModules: {}}, - c: {version: '1', nodeModules: {}}, - b: { - version: '1', - nodeModules: { - c: {version: '2', nodeModules: {}}, - }, - }, - }; - checkLayout(rootDeps, depGraph, expected); - }); -}); diff --git a/src/test/playground-code-editor_test.ts b/src/test/playground-code-editor_test.ts deleted file mode 100644 index 93b1078e..00000000 --- a/src/test/playground-code-editor_test.ts +++ /dev/null @@ -1,691 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import '../playground-code-editor.js'; -import {PlaygroundCodeEditor} from '../playground-code-editor.js'; -import {sendKeys} from '@web/test-runner-commands'; -import {EditorView} from '@codemirror/view'; -import {undo} from '@codemirror/commands'; - -const raf = async () => new Promise((r) => requestAnimationFrame(r)); -const wait = async (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - -suite('playground-code-editor', () => { - let container: HTMLDivElement; - - setup(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - teardown(() => { - container.remove(); - }); - - test('is registered', () => { - assert.instanceOf( - document.createElement('playground-code-editor'), - PlaygroundCodeEditor - ); - }); - - test('renders initial value', async () => { - const editor = document.createElement('playground-code-editor'); - editor.value = 'foo'; - container.appendChild(editor); - await editor.updateComplete; - assert.include(editor.shadowRoot!.innerHTML, 'foo'); - }); - - test('renders updated value', async () => { - const editor = document.createElement('playground-code-editor'); - editor.value = 'foo'; - container.appendChild(editor); - await editor.updateComplete; - editor.value = 'bar'; - await editor.updateComplete; - assert.include(editor.shadowRoot!.innerHTML, 'bar'); - }); - - test('dispatches change event', async () => { - const editor = document.createElement('playground-code-editor'); - editor.value = 'foo'; - container.appendChild(editor); - await editor.updateComplete; - await new Promise((resolve) => { - editor.addEventListener('change', () => resolve()); - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - // Update the text via a CodeMirror 6 transaction - editorInternals._editorView!.dispatch({ - changes: { - from: 0, - to: editorInternals._editorView!.state.doc.length, - insert: 'bar', - }, - }); - }); - }); - - test('does NOT dispatch change event when switching documentKey and value together', async () => { - const editor = document.createElement('playground-code-editor'); - const DOCUMENT_KEY1 = {doc: 1}; - const DOCUMENT_KEY2 = {doc: 2}; - - editor.value = 'document 1'; - editor.documentKey = DOCUMENT_KEY1; - container.appendChild(editor); - await editor.updateComplete; - await raf(); - - let changeCount = 0; - editor.addEventListener('change', () => { - changeCount++; - }); - - // This simulates what playground-file-editor does when switching files - // Both value AND documentKey change together in a single update - editor.value = 'document 2'; - editor.documentKey = DOCUMENT_KEY2; - - // Wait for Lit's update cycle - await editor.updateComplete; - await raf(); - - // Wait for any potential async change events - await wait(100); - - // Switch back - this is where the bug manifests in lit.dev - editor.value = 'document 1 modified'; - editor.documentKey = DOCUMENT_KEY1; - await editor.updateComplete; - await raf(); - await wait(100); - - assert.equal( - changeCount, - 0, - 'Switching documentKey and value together should not fire change event' - ); - }); - - test('does NOT dispatch change event when switching documentKey', async () => { - const editor = document.createElement('playground-code-editor'); - const DOCUMENT_KEY1 = {dockey: 1}; - const DOCUMENT_KEY2 = {dockey: 2}; - - editor.value = 'document 1'; - editor.documentKey = DOCUMENT_KEY1; - container.appendChild(editor); - await editor.updateComplete; - await raf(); - - let changeCount = 0; - editor.addEventListener('change', () => changeCount++); - - // Switch to a different document - should NOT fire change event - editor.value = 'document 2'; - editor.documentKey = DOCUMENT_KEY2; - await editor.updateComplete; - await raf(); - - assert.equal( - changeCount, - 0, - 'Switching documentKey should not fire change event' - ); - - // Switch back to first document - should NOT fire change event - editor.value = 'document 1'; - editor.documentKey = DOCUMENT_KEY1; - await editor.updateComplete; - await raf(); - - assert.equal( - changeCount, - 0, - 'Switching back to original documentKey should not fire change event' - ); - }); - - test('dispatches change event only for user edits, not programmatic changes', async () => { - const editor = document.createElement('playground-code-editor'); - editor.value = 'foo'; - container.appendChild(editor); - await editor.updateComplete; - await raf(); - - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - - let changeCount = 0; - editor.addEventListener('change', () => changeCount++); - - // Programmatic change - should NOT fire - editor.value = 'bar'; - await editor.updateComplete; - await raf(); - assert.equal(changeCount, 0, 'No change event after programmatic update'); - - // User edit via CodeMirror - SHOULD fire - editorInternals._editorView.dispatch({ - changes: { - from: 0, - to: editorInternals._editorView.state.doc.length, - insert: 'baz', - }, - }); - await raf(); - assert.equal(changeCount, 1, 'Change event fired after user edit'); - - // Another programmatic change - should NOT fire - editor.value = 'qux'; - await editor.updateComplete; - await raf(); - assert.equal( - changeCount, - 1, - 'No additional change event after another programmatic update' - ); - }); - - suite('history', () => { - let editor: PlaygroundCodeEditor; - let editorInternals: { - _editorView: EditorView; - }; - - setup(async () => { - editor = document.createElement('playground-code-editor'); - // For correct history, CodeMirror needs to be initialized and attached to - // the DOM. - container.appendChild(editor); - await raf(); - editorInternals = editor as unknown as typeof editorInternals; - }); - - teardown(() => { - editor.remove(); - }); - - test(`and doc instance cache won't drive editor value`, async () => { - const DOCUMENT_KEY1 = {dockey: 1}; - const DOCUMENT_KEY2 = {dockey: 2}; - editor.value = 'document key 1'; - editor.documentKey = DOCUMENT_KEY1; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 1' - ); - editor.value = 'document key 2'; - editor.documentKey = DOCUMENT_KEY2; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 2' - ); - // If only the documentKey is changed, the current value is set on the - // document cache. The `value` property drives the CodeMirror contents. - editor.documentKey = DOCUMENT_KEY1; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 2' - ); - - // Changing documentKey and unsetting the value should clear the editor. - editor.value = undefined; - editor.documentKey = DOCUMENT_KEY2; - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), ''); - - // Unset the cache should result in a - editor.documentKey = undefined; - editor.value = 'value with no cache'; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'value with no cache' - ); - }); - - test(`is cleared on unsetting documentKey`, async () => { - const DOCUMENT_KEY1 = {dockey: 1}; - editor.value = 'no cache'; - await raf(); - editor.documentKey = DOCUMENT_KEY1; - await raf(); - editor.value = 'update on cache'; - await raf(); - editor.documentKey = undefined; - await raf(); - assert.equal( - editorInternals._editorView!.state.doc.toString(), - 'update on cache' - ); - // No-op, because unsetting documentKey clears history. - undo(editorInternals._editorView!); - await raf(); - assert.equal( - editorInternals._editorView!.state.doc.toString(), - 'update on cache' - ); - await raf(); - editor.value = 'changed'; - await raf(); - assert.equal( - editorInternals._editorView!.state.doc.toString(), - 'changed' - ); - undo(editorInternals._editorView!); - await raf(); - assert.equal( - editorInternals._editorView!.state.doc.toString(), - 'update on cache' - ); - }); - - test('is updated if value gets changed with doc cache', async () => { - const DOCUMENT_KEY1 = {dockey: 1}; - const DOCUMENT_KEY2 = {dockey: 2}; - editor.value = 'document key 1'; - editor.documentKey = DOCUMENT_KEY1; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 1' - ); - editor.value = 'document key 2'; - editor.documentKey = DOCUMENT_KEY2; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 2' - ); - editor.documentKey = DOCUMENT_KEY1; - editor.value = 'override document key 1'; - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'override document key 1' - ); - undo(editorInternals._editorView); - await raf(); - assert.equal( - editorInternals._editorView.state.doc.toString(), - 'document key 1' - ); - }); - - test('is maintained without using documentKey', async () => { - editor.value = 'foo'; - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'foo'); - editor.value = 'bar'; - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'bar'); - undo(editorInternals._editorView); - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'foo'); - }); - - test('is maintained with a document key', async () => { - const DOCUMENT_KEY1 = {}; - editor.documentKey = DOCUMENT_KEY1; - editor.value = 'foo'; - await editor.updateComplete; - assert.equal(editorInternals._editorView.state.doc.toString(), 'foo'); - editor.value = 'bar'; - await editor.updateComplete; - assert.equal(editorInternals._editorView.state.doc.toString(), 'bar'); - undo(editorInternals._editorView); - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'foo'); - }); - - test('is associated to the documentKey property', async () => { - const DOCUMENT_KEY1 = {}; - const DOCUMENT_KEY2 = {}; - editor.documentKey = DOCUMENT_KEY1; - editor.value = 'foo'; - await editor.updateComplete; - editor.value = 'potato'; - editor.documentKey = DOCUMENT_KEY2; - await editor.updateComplete; - assert.equal(editorInternals._editorView.state.doc.toString(), 'potato'); - undo(editorInternals._editorView); - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'potato'); - }); - - test('can be rehydrated from a saved document instance', async () => { - const DOCUMENT_KEY1 = {}; - const DOCUMENT_KEY2 = {}; - - editor.documentKey = DOCUMENT_KEY1; - editor.value = 'foo'; - - await raf(); - editor.value = 'bar'; - await raf(); - editor.documentKey = DOCUMENT_KEY2; - await raf(); - editor.value = 'potato'; - await raf(); - editor.documentKey = DOCUMENT_KEY1; - editor.value = 'bar'; - await raf(); - - assert.equal(editorInternals._editorView.state.doc.toString(), 'bar'); - undo(editorInternals._editorView); - await raf(); - assert.equal(editorInternals._editorView.state.doc.toString(), 'foo'); - }); - }); - - suite('syntax highlight', () => { - /** - * Traverse the given root node depth first, and return the first node whose - * trimmed text content is exactly equal to the given text. - */ - const findNodeWithText = (node: Node, text: string): Node | undefined => { - if (node.textContent?.trim() === text) { - return node; - } - for (const child of Array.from(node.childNodes)) { - const r = findNodeWithText(child, text); - if (r) { - return r; - } - } - return undefined; - }; - - const assertHighlight = async ( - type: PlaygroundCodeEditor['type'], - value: string, - text: string, - color: string - ) => { - const editor = document.createElement('playground-code-editor'); - editor.type = type; - editor.value = value; - container.appendChild(editor); - await editor.updateComplete; - const element = findNodeWithText(editor.shadowRoot!, text); - assert.isDefined(element); - const style = window.getComputedStyle(element as HTMLElement); - assert.equal(style.color, color); - }; - - const typeColor = 'rgb(0, 136, 85)'; - const boolColor = 'rgb(34, 17, 153)'; - const keywordColor = 'rgb(119, 0, 136)'; - const literalColor = 'rgb(34, 17, 153)'; - const stringColor = 'rgb(170, 17, 17)'; - - test('html', async () => - assertHighlight('html', '

foo

', 'p', typeColor)); - - test('css', async () => - assertHighlight('css', 'p { color: blue; }', 'blue', literalColor)); - - test('js', async () => - assertHighlight('js', 'if (true) {}', 'true', boolColor)); - - test('html-in-js', async () => - assertHighlight( - 'js', - 'import {LitElement, html} from "lit";', - 'import', - keywordColor - )); - - test('ts', async () => - assertHighlight('ts', 'const x: string;', 'string', typeColor)); - - test('jsx', async () => - assertHighlight('jsx', 'const foo = () =>

foo

;', 'p', typeColor)); - - test('tsx', async () => - assertHighlight( - 'tsx', - 'const x: () => unknown = () =>

foo

;', - 'p', - typeColor - )); - - test('html-in-js', async () => - assertHighlight('js', 'html`

foo

`', 'p', typeColor)); - - test('html-in-ts', async () => - assertHighlight('ts', 'html`

foo

`', 'p', typeColor)); - - test('css-in-js', async () => - assertHighlight('js', 'css`p { color: blue; }`', 'blue', literalColor)); - - test('css-in-ts', async () => - assertHighlight('ts', 'css`p { color: blue; }`', 'blue', literalColor)); - - test('json', async () => - assertHighlight('json', '{"foo": 123}', '"foo"', stringColor)); - }); - - suite('comment toggle', () => { - async function assertToggle( - type: PlaygroundCodeEditor['type'], - value: string, - expect: string - ) { - const editor = document.createElement('playground-code-editor'); - editor.type = type; - editor.value = value; - container.appendChild(editor); - await editor.updateComplete; - - await raf(); - await raf(); - - const focusContainer = - editor.shadowRoot!.querySelector('#focusContainer')!; - - editor.focus(); - - await wait(100); - - // The Meta key might not be available on all test platforms, so we instead - // send both Meta+/ and Control+/ to toggle comments. - await sendKeys({ - down: 'Meta', - }); - await sendKeys({ - press: 'Slash', - }); - await sendKeys({ - up: 'Meta', - }); - await sendKeys({ - down: 'Control', - }); - await sendKeys({ - press: 'Slash', - }); - await sendKeys({ - up: 'Control', - }); - - await wait(100); - await raf(); - await editor.updateComplete; - - assert.include(focusContainer.innerText, expect); - - await sendKeys({ - down: 'Meta', - }); - await sendKeys({ - press: 'Slash', - }); - await sendKeys({ - up: 'Meta', - }); - await sendKeys({ - down: 'Control', - }); - await sendKeys({ - press: 'Slash', - }); - await sendKeys({ - up: 'Control', - }); - - await wait(100); - await raf(); - await editor.updateComplete; - - assert.include(focusContainer.innerText, value); - } - - test('ts', async () => - assertToggle('ts', 'const g = 3;', '// const g = 3;')); - - test('js', async () => - assertToggle('js', 'const g = 3;', '// const g = 3;')); - - test('html', async () => - assertToggle('html', '

foo

', '')); - - test('css', async () => - assertToggle('css', 'p { color: blue; }', '/* p { color: blue; } */')); - - test('ignored when readonly', async () => { - const editor = document.createElement('playground-code-editor'); - editor.type = 'ts'; - editor.readonly = true; - editor.value = 'const g = 3;'; - container.appendChild(editor); - await editor.updateComplete; - - // TODO(aomarks) There's some flakiness here that requires a little pause. - await raf(); - - editor.focus(); - await sendKeys({ - down: 'Control', - }); - await sendKeys({ - press: 'Slash', - }); - await sendKeys({ - up: 'Control', - }); - await raf(); - - assert.include( - // There isn't a focusContainer when the editor is in readonly mode. - editor.shadowRoot!.querySelector('div')!.innerText, - 'const g = 3;' - ); - }); - }); - - suite('tokenUnderCursor', () => { - let editor: PlaygroundCodeEditor; - let editorInternals: { - _editorView: EditorView; - }; - - setup(async () => { - editor = document.createElement('playground-code-editor'); - container.appendChild(editor); - await raf(); - editorInternals = editor as unknown as typeof editorInternals; - }); - - teardown(() => { - editor.remove(); - }); - - test('returns token for JavaScript identifier', async () => { - editor.type = 'js'; - editor.value = 'const myVariable = 42;'; - await raf(); - - // Position cursor inside 'myVariable' - const pos = 'const my'.length; - editorInternals._editorView.dispatch({ - selection: {anchor: pos, head: pos}, - }); - await raf(); - - const token = editor.tokenUnderCursor; - assert.equal(token.string, 'myVariable'); - assert.equal(token.start, 6); // After 'const ' - assert.equal(token.end, 16); // Before ' = 42' - }); - - test('returns token for HTML tag', async () => { - editor.type = 'html'; - editor.value = '
'; - await raf(); - - const pos = ' { - editor.type = 'css'; - editor.value = 'body { color: red; }'; - await raf(); - - const pos = 'body { co'.length; - editorInternals._editorView.dispatch({ - selection: {anchor: pos, head: pos}, - }); - await raf(); - - const token = editor.tokenUnderCursor; - assert.equal(token.string, 'color'); - }); - - test('handles empty document', async () => { - editor.type = 'js'; - editor.value = ''; - await raf(); - - const token = editor.tokenUnderCursor; - assert.equal(token.string, ''); - assert.equal(token.start, 0); - assert.equal(token.end, 0); - }); - - test('handles cursor at punctuation', async () => { - editor.type = 'js'; - editor.value = 'obj.property'; - await raf(); - - const pos = 'obj'.length; - editorInternals._editorView.dispatch({ - selection: {anchor: pos, head: pos}, - }); - await raf(); - - const token = editor.tokenUnderCursor; - assert.isTrue(token.string.length > 0); - }); - }); -}); diff --git a/src/test/playground-ide_test.ts b/src/test/playground-ide_test.ts deleted file mode 100644 index e7f56a5e..00000000 --- a/src/test/playground-ide_test.ts +++ /dev/null @@ -1,1567 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import {html, render} from 'lit'; -import {PlaygroundIde} from '../playground-ide.js'; -import '../playground-ide.js'; -import {sendKeys, executeServerCommand} from '@web/test-runner-commands'; - -import {ReactiveElement} from '@lit/reactive-element'; -import {PlaygroundCodeEditor} from '../playground-code-editor.js'; -import {PlaygroundProject} from '../playground-project.js'; -import {PlaygroundFileEditor} from '../playground-file-editor.js'; -import {PlaygroundPreview} from '../playground-preview.js'; -import {EditorView} from '@codemirror/view'; -import {undo, redo, historyField} from '@codemirror/commands'; - -const LINE_CLASS = '.cm-line'; -const LINE_GUTTERS_CLASS = '.cm-gutters'; -const LINE_GUTTER_CLASS = '.cm-gutter:not(.cm-foldGutter)'; -const WRAP_CLASS = '.cm-lineWrapping'; -const CONTENT_CLASS = '.cm-content'; -const LINE_NUMBER_CLASS = '.cm-gutterElement'; - -function editorSetValue(view: EditorView, value: string): void { - view.dispatch({ - userEvent: 'input', - changes: [ - { - from: 0, - to: view.state.doc.length, - insert: value, - }, - ], - }); -} - -// There is browser variability with zero width spaces. This helper keeps tests -// consistent. -function innerTextWithoutSpaces(el?: HTMLElement | null): string { - return el?.innerText.replace(/[\u200B\s]/g, '') ?? ''; -} -suite('playground-ide', () => { - let container: HTMLDivElement; - let testRunning: boolean; - - setup(() => { - container = document.createElement('div'); - document.body.appendChild(container); - testRunning = true; - }); - - teardown(() => { - container.remove(); - testRunning = false; - }); - - test('is registered', () => { - assert.instanceOf(document.createElement('playground-ide'), PlaygroundIde); - }); - - const raf = async () => new Promise((r) => requestAnimationFrame(r)); - - const pierce = async (...selectors: string[]) => { - let node = document.body; - for (const selector of selectors) { - const result = (node.shadowRoot ?? node).querySelector(selector); - assert.instanceOf(result, Element); - if ((result as ReactiveElement).updateComplete) { - await (result as ReactiveElement).updateComplete; - } - node = result as HTMLElement; - } - return node; - }; - - // TODO(aomarks) Use sendKeys instead - // https://modern-web.dev/docs/test-runner/commands/#send-keys - const updateCurrentFile = async ( - editor: PlaygroundCodeEditor, - newValue: string - ) => { - const editorView = ( - editor as unknown as { - _editorView: EditorView; - } - )._editorView; - editorSetValue(editorView, newValue); - }; - - const waitForIframeLoad = (iframe: HTMLElement) => - new Promise((resolve) => { - iframe.addEventListener('load', () => resolve(), {once: true}); - }); - - const assertPreviewContains = async (text: string) => { - const iframe = (await pierce( - 'playground-ide', - 'playground-preview', - 'iframe' - )) as HTMLIFrameElement; - await waitForIframeLoad(iframe); - // TODO(aomarks) Chromium and Webkit both fire iframe "load" after the - // contentDocument has actually loaded, but Firefox fires it before. Why is - // that? If not for that, we wouldn't need to poll here. - await new Promise((resolve) => { - const check = () => { - if (iframe.contentDocument?.body?.textContent?.includes(text)) { - resolve(); - } else if (testRunning) { - setTimeout(check, 10); - } - }; - check(); - }); - }; - - const assertTabSelected = async (filename: string) => { - await new Promise((r) => setTimeout(r)); - const tabBar = await pierce('playground-ide', 'playground-tab-bar'); - while (testRunning) { - const selectedTab = tabBar.shadowRoot!.querySelector( - 'playground-internal-tab[active]' - ); - if (selectedTab) { - assert.include( - selectedTab.textContent?.trim(), - filename, - `Selected tab did not contain '${filename}')` - ); - break; - } - await new Promise((r) => setTimeout(r, 10)); - } - }; - - test('renders HTML', async () => { - render( - html` - - - - `, - container - ); - await assertPreviewContains('Hello HTML'); - }); - - test('handles multiple script tags', async () => { - render( - html` - - - - `, - container - ); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - // Wait for the editor to instantiate. - await raf(); - - assert.include( - editorInternals._editorView.state.doc.toString(), - `` - ); - assert.include( - editorInternals._editorView.state.doc.toString(), - `` - ); - }); - - test('renders JS', async () => { - render( - html` - - - - - `, - container - ); - await assertPreviewContains('Hello JS'); - }); - - test('renders TS', async () => { - render( - html` - - - - - `, - container - ); - await assertPreviewContains('Hello TS'); - }); - - test('renders JSX', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: ` - - - - - `, - }, - 'hello-react.jsx': { - content: ` - import { React, ReactDOM } from "./mock-react.js"; - - const container = document.querySelector('body'); - const root = ReactDOM.createRoot(container); - root.render(<>hello react jsx!); - `, - }, - // `mock-react.js` avoids pulling `react` and `react-dom` from unpkg. - // It expresses the a minimum subset required of the React API to append - // a `TextNode` to the `body` of the playground html document. - // - // If more in depth integration tests are required, preact would be a - // more robust alternative. - 'mock-react.js': { - content: ` - class React { - static Fragment = 'fragment'; - static createElement( - tag, - props, - children, - ) { - return document.createTextNode(children); - } - } - - class ReactRoot { - root; - constructor(root) { - this.root = root; - } - render(children) { - this.root.appendChild(children); - } - } - - class ReactDOM { - static createRoot(root) { - return new ReactRoot(root); - } - } - - export {React, ReactDOM}; - `, - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('hello react jsx!'); - }); - - test('renders TSX', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: ` - - - - - `, - }, - 'hello-react.tsx': { - content: ` - import { React, ReactDOM } from "./mock-react.js"; - - const container = document.querySelector('body'); - const root = ReactDOM.createRoot(container!); - root.render(<>hello react tsx!); - `, - }, - // `mock-react.ts` avoids pulling `react` and `react-dom` from unpkg. - // It expresses the a minimum subset required of the React API to append - // a `TextNode` to the `body` of the playground html document. - // - // If more in depth integration tests are required, preact would be a - // more robust alternative. - 'mock-react.ts': { - content: ` - class React { - static Fragment = 'fragment'; - static createElement( - tag: unknown, - props: unknown, - children: string, - ) { - return document.createTextNode(children); - } - } - - class ReactRoot { - root: HTMLElement; - constructor(root: HTMLElement) { - this.root = root; - } - render(children: Element) { - this.root.appendChild(children); - } - } - - class ReactDOM { - static createRoot(root: HTMLElement): ReactRoot { - return new ReactRoot(root); - } - } - - export {React, ReactDOM}; - `, - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('hello react tsx!'); - }); - - test('re-renders HTML', async () => { - render( - html` - - - - `, - container - ); - await assertPreviewContains('Hello HTML 1'); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - updateCurrentFile(editor, 'Hello HTML 2'); - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - // Note we shouldn't await the save(), because assertPreviewContains waits - // for an iframe load event, and we can legitimately get an iframe load - // before the full compile is done since we serve each asset as soon as it - // is ready. - project.save(); - await assertPreviewContains('Hello HTML 2'); - }); - - test('hidden file is not displayed in tab bar', async () => { - render( - html` - - - - - `, - container - ); - await assertPreviewContains('Hello JS'); - const tabBar = await pierce('playground-ide', 'playground-tab-bar'); - const tabs = tabBar.shadowRoot?.querySelectorAll('playground-internal-tab'); - assert.equal(tabs?.length, 1); - }); - - test('file label is displayed in tab bar', async () => { - render( - html` - - - - - `, - container - ); - await assertPreviewContains('Hello JS'); - const tabBar = await pierce('playground-ide', 'playground-tab-bar'); - const tabs = tabBar.shadowRoot?.querySelectorAll('playground-internal-tab'); - const texts = Array.from(tabs ?? []).map((tab) => tab.textContent?.trim()); - assert.deepEqual(texts, ['HTML', 'JS']); - }); - - test('reads files from config property', async () => { - const ide = document.createElement('playground-ide')!; - ide.sandboxBaseUrl = '/'; - container.appendChild(ide); - ide.config = { - files: { - 'index.html': { - content: 'Hello HTML', - }, - }, - }; - await assertPreviewContains('Hello HTML'); - }); - - test('line wrapping enabled', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.lineWrapping = true; - ide.config = { - files: { - 'index.html': { - content: 'Foo\n Bar that has an indent', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('Foo\n Bar that has an indent'); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - const codemirrorContainer = editor.shadowRoot!.querySelector( - CONTENT_CLASS - ) as HTMLElement; - const codeMirrorLongLine = editor.shadowRoot!.querySelectorAll( - LINE_CLASS - )[1] as HTMLElement; - - assert.include( - Array.from(codemirrorContainer?.classList), - WRAP_CLASS.replace('.', '') - ); - - const elStyles = getComputedStyle(codeMirrorLongLine); - - assert.include(elStyles.paddingLeft, '4px'); - }); - - test('line wrapping enabled with line numbers', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.lineWrapping = true; - ide.lineNumbers = true; - ide.config = { - files: { - 'index.html': { - content: - 'Foo\n Bar that has an indent and a lot of a lot of a lot of a lot of a lot of a lot of a lot of a lot of a lot of text', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains( - 'Foo\n Bar that has an indent and a lot of a lot of a lot of a lot of a lot of a lot of a lot of a lot of a lot of text' - ); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - const codemirrorContainer = editor.shadowRoot!.querySelector( - CONTENT_CLASS - ) as HTMLElement; - const codeMirrorShortLine = editor.shadowRoot!.querySelectorAll( - LINE_CLASS - )[0] as HTMLElement; - const codeMirrorLongLine = editor.shadowRoot!.querySelectorAll( - LINE_CLASS - )[1] as HTMLElement; - - assert.include( - Array.from(codemirrorContainer?.classList), - WRAP_CLASS.replace('.', '') - ); - - const {height: smallHeight} = codeMirrorShortLine.getBoundingClientRect(); - const {height: largeHeight} = codeMirrorLongLine.getBoundingClientRect(); - - assert.isAbove(largeHeight, smallHeight); - }); - - test('a11y: is contenteditable', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: 'Foo', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('Foo'); - - const cmCode = await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor', - '.cm-content' - ); - - assert.equal(cmCode.getAttribute('contenteditable'), 'true'); - }); - - test('a11y: line numbers get aria-hidden attribute', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.lineNumbers = true; - ide.config = { - files: { - 'index.html': { - content: 'Foo\nBar', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('Foo\nBar'); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - const queryGutters = () => - editor.shadowRoot!.querySelector(LINE_GUTTERS_CLASS); - const queryGutter = () => - editor.shadowRoot!.querySelector(LINE_GUTTER_CLASS); - - const queryLineNumbers = () => - [ - ...((queryGutter()?.querySelectorAll( - LINE_NUMBER_CLASS - ) as NodeListOf) ?? []), - ].filter((el) => el.style.visibility !== 'hidden'); - - // Initial render with line-numbers enabled. - assert.equal(queryLineNumbers().length, 2, 'initial'); - assert.equal(queryGutters()?.getAttribute('aria-hidden'), 'true'); - - // Disable line numbers. - ide.lineNumbers = false; - await raf(); - assert.equal(queryLineNumbers().length, 0, 'off'); - - // Re-enable line numbers. - ide.lineNumbers = true; - await raf(); - assert.equal(queryLineNumbers().length, 2, 'turned back on'); - - // Add a line. - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - editorSetValue(editorInternals._editorView, editor.value + '\nBaz'); - await raf(); - assert.equal(queryLineNumbers().length, 3, 'added line'); - }); - - test('a11y: focusing shows keyboard prompt', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: 'Foo', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('Foo'); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const focusContainer = editor.shadowRoot!.querySelector( - '#focusContainer' - ) as HTMLElement; - const editableRegion = editor.shadowRoot!.querySelector( - '.cm-content' - ) as HTMLElement; - const keyboardHelp = 'Press Enter'; - - // Not focused initially - assert.notInclude(focusContainer.textContent, keyboardHelp); - - // When the inner container is focused, show the keyboard prompt - focusContainer.focus(); - await raf(); - assert.isTrue(focusContainer.matches(':focus')); - assert.include(focusContainer.textContent, keyboardHelp); - - // Press Enter to start editing - focusContainer.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'})); - await raf(); - assert.isTrue(editableRegion.matches(':focus')); - assert.notInclude(focusContainer.textContent, keyboardHelp); - - // Press Escape to stop editing - editableRegion.dispatchEvent( - new KeyboardEvent('keydown', {key: 'Escape', bubbles: true}) - ); - await raf(); - assert.isTrue(focusContainer.matches(':focus')); - assert.include(focusContainer.textContent, keyboardHelp); - - // Focus something else entirely - focusContainer.blur(); - await raf(); - assert.isFalse(focusContainer.matches(':focus')); - assert.isFalse(editableRegion.matches(':focus')); - assert.notInclude(focusContainer.textContent, keyboardHelp); - }); - - test('ignores query params when serving files', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: '', - }, - 'foo.html': { - content: 'foo.html loaded', - }, - }, - }; - container.appendChild(ide); - await assertPreviewContains('foo.html loaded'); - }); - - test('create new files', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: 'Hello', - }, - 'package.json': { - content: '{"dependencies":{}}', - hidden: true, - }, - }, - }; - container.appendChild(ide); - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - // Need to defer another microtask for the config to initialize. - await new Promise((resolve) => requestAnimationFrame(resolve)); - - // Already exists. - assert.isFalse(project.isValidNewFilename('index.html')); - - // Does not exist. - assert.isTrue(project.isValidNewFilename('newfile.ts')); - project.addFile('newfile.ts'); - assert.isFalse(project.isValidNewFilename('newfile.ts')); - - // Exists but is hidden. Creating it unhides it and reveals the existing - // content. - assert.isTrue(project.isValidNewFilename('package.json')); - project.addFile('package.json'); - assert.isFalse(project.isValidNewFilename('package.json')); - const packageJson = project.files?.find( - (file) => file.name === 'package.json' - ); - assert.isFalse(packageJson?.hidden); - assert.equal(packageJson?.content, '{"dependencies":{}}'); - }); - - test('modified property', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.html': { - content: 'Old content', - }, - }, - }; - container.appendChild(ide); - - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - - // Need to defer another microtask for the config to initialize. - await new Promise((resolve) => requestAnimationFrame(resolve)); - - // Note the double checks are here to add coverage for cached states. - assert.isFalse(ide.modified); - assert.isFalse(ide.modified); - - project.addFile('potato.html'); - assert.isTrue(ide.modified); - assert.isTrue(ide.modified); - - project.deleteFile('potato.html'); - assert.isFalse(ide.modified); - assert.isFalse(ide.modified); - - project.renameFile('index.html', 'potato.html'); - assert.isTrue(ide.modified); - assert.isTrue(ide.modified); - - project.renameFile('potato.html', 'index.html'); - assert.isFalse(ide.modified); - assert.isFalse(ide.modified); - - editorSetValue(editorInternals._editorView, 'New content'); - assert.isTrue(ide.modified); - assert.isTrue(ide.modified); - - editorSetValue(editorInternals._editorView, 'Old content'); - assert.isFalse(ide.modified); - assert.isFalse(ide.modified); - - project.addFile('potato.html'); - assert.isTrue(ide.modified); - assert.isTrue(ide.modified); - - ide.config = { - files: { - 'index.html': { - content: 'Different content', - }, - }, - }; - await new Promise((resolve) => requestAnimationFrame(resolve)); - assert.isFalse(ide.modified); - assert.isFalse(ide.modified); - }); - - test('returns the correct cursor position and index', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.js': { - content: '', - }, - }, - }; - container.appendChild(ide); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - const codeToAdd = `console.log("Foo"); - console.log("bar");`; - - await new Promise((resolve) => window.requestAnimationFrame(resolve)); - - editor.focus(); - await sendKeys({ - type: codeToAdd, - }); - - assert.equal(editor.value, codeToAdd); - assert.equal(editor.cursorIndex, codeToAdd.length); - const cursorPosition = editor.cursorPosition; - assert.equal(cursorPosition.line, 1); - assert.equal(cursorPosition.ch, 23); - }); - - test('returns the token under cursor', async () => { - const ide = document.createElement('playground-ide'); - ide.sandboxBaseUrl = '/'; - ide.config = { - files: { - 'index.js': { - content: 'console.log("Foo")', - }, - }, - }; - container.appendChild(ide); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - - await new Promise((resolve) => window.requestAnimationFrame(resolve)); - - editor.focus(); - - await sendKeys({ - press: 'ArrowRight', - }); - - const tokenUnderCursor = editor.tokenUnderCursor; - - assert.equal(tokenUnderCursor.start, 0); - assert.equal(tokenUnderCursor.end, 7); - assert.equal(tokenUnderCursor.string, 'console'); - }); - - // TODO(aomarks) This test fails in Firefox. - (navigator.userAgent.includes('Firefox') ? test.skip : test)( - 'reloading preview does not modify history', - async () => { - const historyLengthBefore = window.history.length; - - // NOTE: For some reason, the parent window's history only seems to be - // affected when the iframe origin is different. - const separateOrigin = (await executeServerCommand( - 'separate-origin' - )) as string; - - render( - html` - - - - `, - container - ); - const iframe = (await pierce( - 'playground-ide', - 'playground-preview', - 'iframe' - )) as HTMLIFrameElement; - await waitForIframeLoad(iframe); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - updateCurrentFile(editor, 'Hello HTML 2'); - - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - project.save(); - await waitForIframeLoad(iframe); - - const historyLengthAfter = window.history.length; - assert.equal(historyLengthAfter, historyLengthBefore); - } - ); - - test('reloading preview does not create a new iframe element', async () => { - render( - html` - - - - `, - container - ); - - const preview = (await pierce( - 'playground-ide', - 'playground-preview' - )) as PlaygroundPreview; - - const iframe = preview.iframe!; - - await waitForIframeLoad(iframe); - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - updateCurrentFile(editor, 'Hello HTML 2'); - - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - - await Promise.all([waitForIframeLoad(iframe), project.save()]); - - const newIframe = (await pierce( - 'playground-ide', - 'playground-preview', - 'iframe' - )) as HTMLIFrameElement; - - assert.equal(newIframe, iframe); - }); - - test('delete file using menu', async () => { - render( - html` - - - - `, - container - ); - await assertPreviewContains('Hello HTML'); - - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - assert.lengthOf(project.files ?? [], 1); - - // Between MWC v0.25.1 and v0.25.2, when clicking on an , - // the target changed from the to its internal . - const menuButtonSvg = await pierce( - 'playground-ide', - 'playground-tab-bar', - '.menu-button > svg' - ); - menuButtonSvg.dispatchEvent(new Event('click', {bubbles: true})); - - const deleteButton = await pierce( - 'playground-ide', - 'playground-tab-bar', - 'playground-file-system-controls', - '#deleteButton' - ); - deleteButton.click(); - - assert.lengthOf(project.files ?? [], 0); - }); - - test('uses custom htmlFile property', async () => { - const ide = document.createElement('playground-ide')!; - ide.sandboxBaseUrl = '/'; - ide.htmlFile = 'src/index.html'; - container.appendChild(ide); - ide.config = { - files: { - 'src/index.html': { - content: 'Hello HTML', - }, - 'other.html': { - content: 'Other HTML', - }, - }, - }; - await assertPreviewContains('Hello HTML'); - - // test that the preview updates when the htmlFile property changes - ide.htmlFile = 'other.html'; - await assertPreviewContains('Other HTML'); - }); - - test('undo/redo changes to a file', async () => { - render( - html` - - - - -
- `, - container - ); - const codemirror = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const codemirrorInternals = codemirror as unknown as { - _editorView: EditorView; - }; - await assertPreviewContains('Hello JS'); - editorSetValue( - codemirrorInternals._editorView, - "document.body.textContent = 'Hello 2'" - ); - await assertPreviewContains('Hello 2'); - undo(codemirrorInternals._editorView); - await assertPreviewContains('Hello JS'); - redo(codemirrorInternals._editorView); - await assertPreviewContains('Hello 2'); - }); - - test('undo/redo should not cross project file boundaries', async () => { - const JS_CONTENT = `document.body.textContent = 'Hello JS';`; - render( - html` - - - - - `, - container - ); - const fileEditor = (await pierce( - 'playground-ide', - 'playground-file-editor' - )) as PlaygroundFileEditor; - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - - await raf(); - assert.equal(fileEditor.filename, 'hello.js'); - assert.equal( - editorInternals._editorView.state.doc.toString().trim(), - JS_CONTENT - ); - - fileEditor.filename = 'index.html'; - await raf(); - undo(editorInternals._editorView); - - await raf(); - // Expect to still be on the html page. - assert.notEqual( - editorInternals._editorView.state.doc.toString().trim(), - JS_CONTENT - ); - }); - - test('undo/redo history persists when files change', async () => { - const JS_CONTENT = `document.body.textContent = 'Hello JS';`; - render( - html` - - - - - `, - container - ); - const fileEditor = (await pierce( - 'playground-ide', - 'playground-file-editor' - )) as PlaygroundFileEditor; - - const editor = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const editorInternals = editor as unknown as { - _editorView: EditorView; - }; - - await raf(); - assert.equal(fileEditor.filename, 'hello.js'); - assert.equal( - editorInternals._editorView.state.doc.toString().trim(), - JS_CONTENT - ); - - editorSetValue(editorInternals._editorView, '// initial text'); - - await raf(); - - editorSetValue(editorInternals._editorView, '// some more text'); - - await raf(); - editorSetValue( - editorInternals._editorView, - "document.body.textContent = 'Hello 2'" - ); - - fileEditor.filename = 'index.html'; - await raf(); - assert.include( - editorInternals._editorView.state.doc.toString().trim(), - ` - -
- `, - container - ); - const project = (await pierce( - 'playground-ide', - 'playground-project' - )) as PlaygroundProject; - const codemirror = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const codemirrorInternals = codemirror as unknown as { - _editorView: EditorView; - }; - await raf(); - assert.include( - codemirrorInternals._editorView.state.doc.toString(), - 'Hello JS' - ); - editorSetValue( - codemirrorInternals._editorView, - "document.body.textContent = 'Hello 2'" - ); - project.renameFile('hello.js', 'potato.js'); - await raf(); - assert.include( - codemirrorInternals._editorView.state.doc.toString(), - 'Hello 2' - ); - undo(codemirrorInternals._editorView); - await raf(); - assert.include( - codemirrorInternals._editorView.state.doc.toString(), - 'Hello JS' - ); - redo(codemirrorInternals._editorView); - await raf(); - assert.include( - codemirrorInternals._editorView.state.doc.toString(), - 'Hello 2' - ); - }); - - test('code remains folded when switching files', async () => { - render( - html` - - - - - `, - container - ); - const EXPECTED_FOLDED = "…console.log('potato');"; - const fileEditor = (await pierce( - 'playground-ide', - 'playground-file-editor' - )) as PlaygroundFileEditor; - const codemirror = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - fileEditor.filename = 'index.html'; - await raf(); - assert.include( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - `src="hello.js">` - ); - fileEditor.filename = 'hello.js'; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - }); - - test('code remains folded when switching files that both have folds', async () => { - render( - html` - - - - - `, - container - ); - const EXPECTED_FOLDED = "…console.log('potato');"; - const fileEditor = (await pierce( - 'playground-ide', - 'playground-file-editor' - )) as PlaygroundFileEditor; - const codemirror = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - fileEditor.filename = 'index.html'; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - '…' - ); - fileEditor.filename = 'hello.js'; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - }); - - test('code remains folded on value change and undo', async () => { - render( - html` - - - - - `, - container - ); - const EXPECTED_FOLDED = "…console.log('potato');"; - const codemirror = (await pierce( - 'playground-ide', - 'playground-file-editor', - 'playground-code-editor' - )) as PlaygroundCodeEditor; - const codemirrorInternals = codemirror as unknown as { - _editorView: EditorView; - }; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - codemirror.value = `/* playground-fold */ -document.body.textContent = 'Hello JS'; -/* playground-fold-end */ - -console.log('tomato');`; - await raf(); - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - "…console.log('tomato');" - ); - - undo(codemirrorInternals._editorView); - await raf(); - - assert.equal( - innerTextWithoutSpaces( - codemirror?.shadowRoot?.querySelector('*') - ), - EXPECTED_FOLDED - ); - }); - - test('focuses file with selected flag, from config', async () => { - const ide = document.createElement('playground-ide')!; - ide.sandboxBaseUrl = '/'; - container.appendChild(ide); - // Start with a.html selected - ide.config = { - files: { - 'index.html': { - content: 'index', - }, - 'a.html': { - content: 'A', - selected: true, - }, - 'b.html': { - content: 'B', - }, - }, - }; - await assertTabSelected('a.html'); - // Change to b.html selected - ide.config = { - files: { - 'index.html': { - content: 'index', - }, - 'a.html': { - content: 'A', - }, - 'b.html': { - content: 'B', - selected: true, - }, - }, - }; - await assertTabSelected('b.html'); - // Nothing selected; should stay on b.html - ide.config = { - files: { - 'index.html': { - content: 'index', - }, - 'b.html': { - content: 'B', - }, - 'a.html': { - content: 'A', - }, - }, - }; - await assertTabSelected('b.html'); - }); - - test('focuses file with selected flag, from slots', async () => { - // Start with a.html selected - render( - html` - - - - - - `, - container - ); - const ide = container.firstElementChild as PlaygroundIde; - await assertTabSelected('a.html'); - // Change to b.html selected - ide.textContent = ''; - render( - html` - - - - `, - ide - ); - await assertTabSelected('b.html'); - // Nothing selected; should stay on b.html - render( - html` - - - - `, - ide - ); - await assertTabSelected('b.html'); - }); -}); diff --git a/src/test/playwright/service-worker.spec.ts b/src/test/playwright/service-worker.spec.ts deleted file mode 100644 index 1f074c5e..00000000 --- a/src/test/playwright/service-worker.spec.ts +++ /dev/null @@ -1,286 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {test, expect} from '@playwright/test'; -import {startDevServer} from '@web/dev-server'; -import {readFile} from 'fs/promises'; -// eslint-disable-next-line import/extensions -import {Deferred} from '../../shared/deferred.js'; - -import type {Page} from 'playwright'; -import type {DevServer, Plugin} from '@web/dev-server-core'; - -const indexHtml = ` - - - - - - - - - - - - - -`; - -test.describe('service worker', () => { - let server: DevServer; - let indexUrl: string; - let originalSwCode: string; - let originalSwVersion: string; - - /** - * When serving the service worker script, substitute the entire script for - * the given code. - */ - const setServiceWorkerCode = (code: string) => { - swCode = code; - }; - let swCode: string; - - /** - * When serving the service worker script, substitute the given version in - * place of the real one. - */ - const setServiceWorkerVersion = (version: string) => { - swVersion = version; - }; - let swVersion: string; - - /** - * When serving component code, substitute the given expected service worker - * version in place of the real one. - */ - const setExpectedVersion = (version: string) => { - expectedVersion = version; - }; - let expectedVersion: string; - - const setServiceWorkerAndExpectedVersion = (version: string) => { - setServiceWorkerVersion(version); - setExpectedVersion(version); - }; - - /** - * Return a proimse that resolves the next time the service worker is served. - */ - const serviceWorkerServed = () => serviceWorkerServedDeferred.promise; - let serviceWorkerServedDeferred = new Deferred(); - - test.beforeAll(async () => { - originalSwCode = await readFile('./playground-service-worker.js', 'utf8'); - - const versionPattern = - /version:\s*(?["'`])(?[a-z0-9]+)\k/g; - const versionMatches = [...originalSwCode.matchAll(versionPattern)]; - if (versionMatches.length !== 1) { - throw new Error( - 'Expected 1 version string in playground-service-worker.js. ' + - `Found ${versionMatches.length}.` - ); - } - const hex = versionMatches[0].groups?.['hex']; - if (!hex) { - throw new Error('Could not find "hex" capture group in regexp match.'); - } - originalSwVersion = hex; - - const plugin: Plugin = { - name: 'test-plugin', - - serve(ctx) { - if (ctx.path === '/') { - return indexHtml; - } - return undefined; - }, - - transform(ctx) { - let body = ctx.body as string; - if (typeof body !== 'string') { - throw new Error('Expected string body'); - } - if (ctx.path.endsWith('playground-service-worker.js')) { - body = swCode - .replace(originalSwVersion, swVersion) - // Extreme hack! We need some way to check which service worker - // served a response. Prepend the version into all responses. - .replace(/new Response\(/g, `new Response("${swVersion} "+`); - serviceWorkerServedDeferred.resolve(); - serviceWorkerServedDeferred = new Deferred(); - } else { - body = body.replace(originalSwVersion, expectedVersion); - } - return {body}; - }, - - transformCacheKey() { - // By default @web/dev-server will cache transformed responses in memory - // based purely on the request path. We need to override this because - // [1] we serve varying responses for the same path, and [2] we want to - // observe every response so we can resolve a promise. - return String(Math.random()); - }, - }; - - server = await startDevServer({ - config: { - rootDir: '.', - nodeResolve: true, - plugins: [plugin], - }, - }); - indexUrl = `http://localhost:${server.config.port}/`; - }); - - test.beforeEach(() => { - setServiceWorkerCode(originalSwCode); - setServiceWorkerAndExpectedVersion(originalSwVersion); - serviceWorkerServedDeferred = new Deferred(); - }); - - test.afterAll(async () => { - await server.stop(); - }); - - const getIframeBodyText = async (page: Page): Promise => { - const iframe = await page.waitForSelector('playground-preview iframe'); - const contentFrame = await iframe.contentFrame(); - if (contentFrame === null) { - throw new Error('iframe had null contentFrame'); - } - const bodyText = await contentFrame.textContent('body'); - if (bodyText === null) { - throw new Error('contentFrame had null body text'); - } - return bodyText; - }; - - const expectIframeServesVersion = async ( - page: Page, - version: string - ): Promise => { - const text = await getIframeBodyText(page); - expect(text).toEqual(`${version} index.html`); - }; - - const clickReloadButton = async (page: Page): Promise => { - await page.click('#reload-button'); - }; - - const expectConsoleLog = (page: Page, expect: string): Promise => - new Promise((resolve) => - page.on('console', async (msg) => { - const text = await msg.text(); - if (text === expect) { - resolve(); - } - }) - ); - - test('simple fresh load', async ({browser}) => { - const ctx = await browser.newContext(); - const page = await ctx.newPage(); - - setServiceWorkerAndExpectedVersion('new'); - await page.goto(indexUrl); - await expectIframeServesVersion(page, 'new'); - }); - - test('updates after tab reload', async ({browser}) => { - const ctx = await browser.newContext(); - const page = await ctx.newPage(); - - setServiceWorkerAndExpectedVersion('old'); - await page.goto(indexUrl); - await expectIframeServesVersion(page, 'old'); - - setServiceWorkerAndExpectedVersion('new'); - await page.reload(); - await expectIframeServesVersion(page, 'new'); - }); - - test('two tabs at same version', async ({browser}) => { - const ctx = await browser.newContext(); - const page1 = await ctx.newPage(); - const page2 = await ctx.newPage(); - - setServiceWorkerAndExpectedVersion('new'); - await page1.goto(indexUrl); - await page2.goto(indexUrl); - await expectIframeServesVersion(page1, 'new'); - await expectIframeServesVersion(page2, 'new'); - }); - - test('two tabs both update after tab reload', async ({browser}) => { - const ctx = await browser.newContext(); - const page1 = await ctx.newPage(); - const page2 = await ctx.newPage(); - - setServiceWorkerAndExpectedVersion('old'); - await page1.goto(indexUrl); - await page2.goto(indexUrl); - await expectIframeServesVersion(page1, 'old'); - await expectIframeServesVersion(page2, 'old'); - - setServiceWorkerAndExpectedVersion('new'); - await page1.reload(); - await page2.reload(); - await expectIframeServesVersion(page1, 'new'); - await expectIframeServesVersion(page2, 'new'); - }); - - test('two tabs at different versions', async ({browser}) => { - const ctx = await browser.newContext(); - const page1 = await ctx.newPage(); - const page2 = await ctx.newPage(); - - setServiceWorkerAndExpectedVersion('old'); - await page1.goto(indexUrl); - await page2.goto(indexUrl); - await expectIframeServesVersion(page1, 'old'); - await expectIframeServesVersion(page2, 'old'); - - setServiceWorkerAndExpectedVersion('new'); - await page1.reload(); - await expectIframeServesVersion(page1, 'new'); - - // The other tab can still keep using the old version because the new one is - // one a different scope and not contending for the same URL space. - await clickReloadButton(page2); - await expectIframeServesVersion(page2, 'old'); - }); - - test('recover from outdated service worker', async ({browser}) => { - const ctx = await browser.newContext(); - const page = await ctx.newPage(); - - setServiceWorkerVersion('old'); - - const oldServedAndNewSwappedIn = (async () => { - await serviceWorkerServed(); - setServiceWorkerVersion('new'); - })(); - - setExpectedVersion('new'); - const loggedAboutUpdate = expectConsoleLog( - page, - 'Playground service worker is outdated. Want new but got old. Waiting for update.' - ); - await page.goto(indexUrl); - await oldServedAndNewSwappedIn; - await loggedAboutUpdate; - await expectIframeServesVersion(page, 'new'); - }); -}); diff --git a/src/test/types-fetcher_test.ts b/src/test/types-fetcher_test.ts deleted file mode 100644 index 24d42e9c..00000000 --- a/src/test/types-fetcher_test.ts +++ /dev/null @@ -1,1157 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {TypesFetcher} from '../typescript-worker/types-fetcher.js'; -import {ImportMapResolver} from '../typescript-worker/import-map-resolver.js'; -import {configureFakeCdn} from './worker-test-util.js'; -import {assert} from '@esm-bundle/chai'; -import {CachingCdn} from '../typescript-worker/caching-cdn.js'; - -import {ModuleImportMap} from '../shared/worker-api.js'; -import {CdnData} from './fake-cdn-plugin.js'; -import {PackageJson} from '../typescript-worker/util.js'; -import { - DependencyGraph, - NodeModulesDirectory, - PackageDependencies, -} from '../typescript-worker/node-modules-layout-maker.js'; - -interface ExpectedDependencyGraph { - root: PackageDependencies; - deps: DependencyGraph; -} - -const checkTypesFetcher = async (opts: { - sourceTexts: string[]; - packageJson: PackageJson; - cdnData: CdnData; - tsLibs?: string[]; - importMap?: ModuleImportMap; - expectedFiles: Map; - expectedDependencyGraph?: ExpectedDependencyGraph; - expectedLayout?: NodeModulesDirectory; -}) => { - const {cdnBaseUrl, deleteCdnData} = await configureFakeCdn(opts.cdnData); - try { - await checkTypesFetcherImpl(opts, cdnBaseUrl); - } finally { - await deleteCdnData(); - } -}; - -const checkTypesFetcherImpl = async ( - opts: Parameters[0], - cdnBaseUrl: string -) => { - const cdn = new CachingCdn(cdnBaseUrl); - const importMapResolver = new ImportMapResolver(opts.importMap ?? {}); - const actual = await TypesFetcher.fetchTypes( - cdn, - importMapResolver, - opts.packageJson, - opts.sourceTexts, - opts.tsLibs ?? [] - ); - if (opts.expectedDependencyGraph !== undefined) { - assert.deepEqual(actual.dependencyGraph, opts.expectedDependencyGraph); - } - if (opts.expectedLayout !== undefined) { - assert.deepEqual(actual.layout, opts.expectedLayout); - } - // Note assert.deepEqual does compare Maps correctly, but it always displays - // "{}" as the difference in the error message, hence this conversion :( - assert.deepEqual( - [...actual.files].sort(([keyA], [keyB]) => keyA.localeCompare(keyB)), - [...opts.expectedFiles].sort(([keyA], [keyB]) => keyA.localeCompare(keyB)) - ); -}; - -suite('types fetcher', () => { - test('no sources', async () => { - const sourceTexts: string[] = []; - const packageJson: PackageJson = {}; - const cdnData: CdnData = {}; - const expectedFiles = new Map(); - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {}, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = {}; - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedLayout, - expectedDependencyGraph, - expectedFiles, - }); - }); - - test('no dependencies', async () => { - const sourceTexts: string[] = [`export const foo = "foo";`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = {}; - const expectedFiles = new Map(); - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {}, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = {}; - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('only direct dependencies', async () => { - // ROOT - // /\ - // / \ - // v v - // A1 B2 - const sourceTexts: string[] = [`import 'a';`, `import 'b';`]; - const packageJson: PackageJson = { - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const a: 1;`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const b: 1;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0', b: '1.0.0'}, - deps: {}, - }; - // ROOT - // ├── A1 - // └── B2 - const expectedLayout: NodeModulesDirectory = { - a: {version: '1.0.0', nodeModules: {}}, - b: {version: '1.0.0', nodeModules: {}}, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', 'declare export const a: 1;'], - ['b/package.json', '{}'], - ['b/index.d.ts', 'declare export const b: 1;'], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('dependency shared between root and branch', async () => { - // ROOT - // /\ - // / \ - // v v - // A1 -> B1 - const sourceTexts: string[] = [`import 'a';`, `import 'b';`]; - const packageJson: PackageJson = { - dependencies: { - a: '^1.0.0', - b: '^1.1.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.1.0': { - files: { - 'index.d.ts': { - content: `import 'b';`, - }, - 'package.json': { - content: `{"dependencies": {"b": "^1.2.0"}}`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.3.0': { - files: { - 'index.d.ts': { - content: `declare export const b: 1;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.1.0', b: '1.3.0'}, - deps: { - a: { - '1.1.0': { - b: '1.3.0', - }, - }, - }, - }; - // ROOT - // ├── A1 - // └── B2 - const expectedLayout: NodeModulesDirectory = { - a: {version: '1.1.0', nodeModules: {}}, - b: {version: '1.3.0', nodeModules: {}}, - }; - const expectedFiles = new Map([ - ['a/package.json', `{"dependencies": {"b": "^1.2.0"}}`], - ['a/index.d.ts', `import 'b';`], - ['b/package.json', '{}'], - ['b/index.d.ts', 'declare export const b: 1;'], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('simple chain', async () => { - // ROOT - // | - // v - // A1 - // | - // v - // B2 - // | - // v - // C3 - const sourceTexts: string[] = [`import 'a';`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'b';`, - }, - }, - }, - }, - }, - b: { - versions: { - '2.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'c';`, - }, - }, - }, - }, - }, - c: { - versions: { - '3.0.0': { - files: { - 'index.d.ts': { - content: `declare export const c: 3;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0'}, - deps: { - a: { - '1.0.0': { - b: '2.0.0', - }, - }, - b: { - '2.0.0': { - c: '3.0.0', - }, - }, - }, - }; - // ROOT - // ├── A1 - // ├── B2 - // └── C3 - const expectedLayout: NodeModulesDirectory = { - a: {version: '1.0.0', nodeModules: {}}, - b: {version: '2.0.0', nodeModules: {}}, - c: {version: '3.0.0', nodeModules: {}}, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', `declare export * from 'b';`], - ['b/package.json', '{}'], - ['b/index.d.ts', `declare export * from 'c';`], - ['c/package.json', '{}'], - ['c/index.d.ts', `declare export const c: 3;`], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('short loop', async () => { - // ROOT --> A1 --> B1 - // ^ | - // | | - // +-----+ - const sourceTexts: string[] = [`import 'a';`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'b';`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'a';`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0'}, - deps: { - a: { - '1.0.0': { - b: '1.0.0', - }, - }, - b: { - '1.0.0': { - a: '1.0.0', - }, - }, - }, - }; - // ROOT - // ├── A1 - // └── B1 - const expectedLayout: NodeModulesDirectory = { - a: {version: '1.0.0', nodeModules: {}}, - b: {version: '1.0.0', nodeModules: {}}, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', `declare export * from 'b';`], - ['b/package.json', '{}'], - ['b/index.d.ts', `declare export * from 'a';`], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('bare -> relative -> bare', async () => { - // ROOT - // | - // v - // A1 --> A1/other - // | - // v - // B1 - const sourceTexts: string[] = [`import 'a';`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - a: { - versions: { - '1.2.3': { - files: { - 'index.d.ts': { - content: `import "./other.js";`, - }, - 'other.d.ts': { - content: 'import "b";', - }, - }, - }, - }, - }, - b: { - versions: { - '1.3.4': { - files: { - 'index.d.ts': { - content: `declare export const b: 2;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.2.3'}, - deps: { - a: { - '1.2.3': {b: '1.3.4'}, - }, - }, - }; - // ROOT - // ├── A1 - // └── B1 - const expectedLayout: NodeModulesDirectory = { - a: { - version: '1.2.3', - nodeModules: {}, - }, - b: { - version: '1.3.4', - nodeModules: {}, - }, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', `import "./other.js";`], - ['a/other.d.ts', `import "b";`], - ['b/package.json', '{}'], - ['b/index.d.ts', `declare export const b: 2;`], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('version conflict between root and branch', async () => { - // ROOT - // /\ - // v v - // A1 B1 - // | - // v - // B2 - const sourceTexts: string[] = [`import 'a';`, `import 'b';`]; - const packageJson: PackageJson = { - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'b';`, - }, - 'package.json': { - content: `{"dependencies": {"b": "^2.0.0"}}`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const b: 1;`, - }, - }, - }, - '2.0.0': { - files: { - 'index.d.ts': { - content: `declare export const b: 2;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0', b: '1.0.0'}, - deps: { - a: { - '1.0.0': { - b: '2.0.0', - }, - }, - }, - }; - // ROOT - // ├── A1 - // │ └── B2 - // └── B1 - const expectedLayout: NodeModulesDirectory = { - a: { - version: '1.0.0', - nodeModules: { - b: {version: '2.0.0', nodeModules: {}}, - }, - }, - b: {version: '1.0.0', nodeModules: {}}, - }; - const expectedFiles = new Map([ - ['a/package.json', `{"dependencies": {"b": "^2.0.0"}}`], - ['a/index.d.ts', `declare export * from 'b';`], - ['a/node_modules/b/package.json', '{}'], - ['a/node_modules/b/index.d.ts', `declare export const b: 2;`], - ['b/package.json', '{}'], - ['b/index.d.ts', `declare export const b: 1;`], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('tslibs', async () => { - const sourceTexts: string[] = []; - const tsLibs = ['es2020', 'DOM']; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - typescript: { - versions: { - '4.3.5': { - files: { - 'lib/lib.es2020.d.ts': { - // References are the same as imports from our perspective. - content: `/// `, - }, - 'lib/lib.es2020.promise.d.ts': { - content: `interface PromiseConstructor { }`, - }, - // Note standard lib files are always lower-case. - 'lib/lib.dom.d.ts': { - content: `interface HTMLElement { }`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: { - typescript: '4.3.5', - }, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = { - typescript: { - version: '4.3.5', - nodeModules: {}, - }, - }; - const expectedFiles = new Map([ - [ - 'typescript/lib/lib.es2020.d.ts', - `/// `, - ], - [ - 'typescript/lib/lib.es2020.promise.d.ts', - `interface PromiseConstructor { }`, - ], - ['typescript/lib/lib.dom.d.ts', `interface HTMLElement { }`], - ]); - await checkTypesFetcher({ - sourceTexts, - tsLibs, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('@types package', async () => { - const sourceTexts: string[] = []; - const packageJson: PackageJson = { - dependencies: { - '@types/a': '1.0.0', - }, - }; - const cdnData: CdnData = { - '@types/a': { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: 'declare module a { export const a: 1; }', - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: { - '@types/a': '1.0.0', - }, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = { - '@types/a': { - version: '1.0.0', - nodeModules: {}, - }, - }; - const expectedFiles = new Map([ - ['@types/a/index.d.ts', 'declare module a { export const a: 1; }'], - ['@types/a/package.json', '{}'], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('declare module', async () => { - // Declaring a module should not count as an import, but anything imported - // from within the declare module block should. - const sourceTexts: string[] = [ - ` - declare module "x" { - declare export * from "a"; - } - `, - ]; - const packageJson: PackageJson = { - dependencies: { - a: '^1.0.0', - x: '^1.0.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: ` - declare module "a" { - declare export * from "a/internal.js"; - }`, - }, - 'internal.d.ts': { - content: `declare export const a: 1;`, - }, - }, - }, - }, - }, - x: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const x: 1;`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0'}, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = { - a: { - version: '1.0.0', - nodeModules: {}, - }, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - [ - 'a/index.d.ts', - ` - declare module "a" { - declare export * from "a/internal.js"; - }`, - ], - ['a/internal.d.ts', 'declare export const a: 1;'], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('version conflict requiring directory duplication', async () => { - // ROOT - // /|\ - // / | \ - // / | \ - // v v v - // A1 B1 C1 - // \ / - // \ / - // v - // A2 - const sourceTexts: string[] = [ - `import 'a'; - import 'b'; - import 'c'; - `, - ]; - const packageJson: PackageJson = { - dependencies: { - a: '1.0.0', - b: '1.0.0', - c: '1.0.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const: 1;`, - }, - }, - }, - '2.0.0': { - files: { - 'index.d.ts': { - content: `declare export const: 2;`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'a';`, - }, - 'package.json': { - content: `{"dependencies": {"a": "2.0.0"}}`, - }, - }, - }, - }, - }, - c: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export * from 'a';`, - }, - 'package.json': { - content: `{"dependencies": {"a": "2.0.0"}}`, - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: {a: '1.0.0', b: '1.0.0', c: '1.0.0'}, - deps: { - b: { - '1.0.0': { - a: '2.0.0', - }, - }, - c: { - '1.0.0': { - a: '2.0.0', - }, - }, - }, - }; - // ROOT - // ├── A1 - // ├── B1 - // │ └── A2 - // └── C1 - // └── A2 - const expectedLayout: NodeModulesDirectory = { - a: { - version: '1.0.0', - nodeModules: {}, - }, - b: { - version: '1.0.0', - nodeModules: { - a: { - version: '2.0.0', - nodeModules: {}, - }, - }, - }, - c: { - version: '1.0.0', - nodeModules: { - a: { - version: '2.0.0', - nodeModules: {}, - }, - }, - }, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', `declare export const: 1;`], - ['b/package.json', `{"dependencies": {"a": "2.0.0"}}`], - ['b/index.d.ts', `declare export * from 'a';`], - ['b/node_modules/a/package.json', `{}`], - ['b/node_modules/a/index.d.ts', `declare export const: 2;`], - ['c/package.json', `{"dependencies": {"a": "2.0.0"}}`], - ['c/index.d.ts', `declare export * from 'a';`], - ['c/node_modules/a/package.json', `{}`], - ['c/node_modules/a/index.d.ts', `declare export const: 2;`], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); - - test('import map: specifier includes filename', async () => { - const sourceTexts: string[] = [`import {foo} from 'foo/foo.js';`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - foo: { - versions: { - '2.0.0': { - files: {}, - }, - '1.2.3': { - files: { - 'foo.d.ts': { - content: 'declare export const foo: string;', - }, - }, - }, - }, - }, - }; - // Note we're using the fake CDN in a slightly different way in this test by - // directly providing the URL in the import maps. - const {cdnBaseUrl, deleteCdnData} = await configureFakeCdn(cdnData); - const importMap: ModuleImportMap = { - imports: { - foo: `${cdnBaseUrl}foo@1.2.3`, - 'foo/': `${cdnBaseUrl}foo@1.2.3/`, - }, - }; - const expectedFiles = new Map([ - ['foo/foo.d.ts', 'declare export const foo: string;'], - ]); - try { - await checkTypesFetcherImpl( - { - sourceTexts, - packageJson, - cdnData, - importMap, - expectedFiles, - }, - cdnBaseUrl - ); - } finally { - await deleteCdnData(); - } - }); - - test('import map: dependency has relative import', async () => { - const sourceTexts: string[] = [`import {foo} from 'foo/foo.js';`]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - foo: { - versions: { - '2.0.0': { - files: {}, - }, - '1.2.3': { - files: { - 'foo.d.ts': { - content: 'export * from "./bar.js";', - }, - 'bar.d.ts': { - content: 'declare export const foo: string;', - }, - }, - }, - }, - }, - }; - const {cdnBaseUrl, deleteCdnData} = await configureFakeCdn(cdnData); - const importMap: ModuleImportMap = { - imports: { - foo: `${cdnBaseUrl}foo@1.2.3`, - 'foo/': `${cdnBaseUrl}foo@1.2.3/`, - }, - }; - const expectedFiles = new Map([ - ['foo/foo.d.ts', 'export * from "./bar.js";'], - ['foo/bar.d.ts', 'declare export const foo: string;'], - ]); - try { - await checkTypesFetcherImpl( - { - sourceTexts, - packageJson, - cdnData, - importMap, - expectedFiles, - }, - cdnBaseUrl - ); - } finally { - await deleteCdnData(); - } - }); - - test('import map: reads "typings" from package.json', async () => { - const sourceTexts: string[] = [ - `import {foo} from 'foo'; - import {foo as alsofoo} from 'alsofoo';`, - ]; - const packageJson: PackageJson = {}; - const cdnData: CdnData = { - foo: { - versions: { - '2.0.0': { - files: {}, - }, - '1.2.3': { - files: { - 'package.json': { - content: '{"typings": "typings.d.ts"}', - }, - 'typings.d.ts': { - content: 'declare export const foo: string;', - }, - }, - }, - }, - }, - }; - const {cdnBaseUrl, deleteCdnData} = await configureFakeCdn(cdnData); - const importMap: ModuleImportMap = { - imports: { - foo: `${cdnBaseUrl}foo@1.2.3`, - 'foo/': `${cdnBaseUrl}foo@1.2.3/`, - // Two packages can be mapped to the same URL. The typings will be - // duplicated into both node_modules/ directories. - alsofoo: `${cdnBaseUrl}foo@1.2.3`, - 'alsofoo/': `${cdnBaseUrl}foo@1.2.3/`, - }, - }; - const expectedFiles = new Map([ - ['foo/package.json', '{"typings": "typings.d.ts"}'], - ['foo/typings.d.ts', 'declare export const foo: string;'], - ['alsofoo/package.json', '{"typings": "typings.d.ts"}'], - ['alsofoo/typings.d.ts', 'declare export const foo: string;'], - ]); - try { - await checkTypesFetcherImpl( - { - sourceTexts, - packageJson, - cdnData, - importMap, - expectedFiles, - }, - cdnBaseUrl - ); - } finally { - await deleteCdnData(); - } - }); - - test('CDN HTTP errors', async () => { - // a/b/c should still resolve, even though there are 404 and 500 errors - // served by other imports. - const sourceTexts: string[] = [ - `import 'a'; - import 'missing'; - import 'b'; - import 'broken'; - import 'c';`, - ]; - const packageJson: PackageJson = { - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - c: '^1.0.0', - broken: '^1.0.0', - }, - }; - const cdnData: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const a: 1;`, - }, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const b: 1;`, - }, - }, - }, - }, - }, - c: { - versions: { - '1.0.0': { - files: { - 'index.d.ts': { - content: `declare export const c: 1;`, - }, - }, - }, - }, - }, - broken: { - versions: { - '1.0.0': { - files: { - 'package.json': { - status: 500, - content: 'Internal error', - }, - 'index.d.ts': { - status: 500, - content: 'Internal error', - }, - }, - }, - }, - }, - }; - const expectedDependencyGraph: ExpectedDependencyGraph = { - root: { - a: '1.0.0', - b: '1.0.0', - c: '1.0.0', - }, - deps: {}, - }; - const expectedLayout: NodeModulesDirectory = { - a: { - version: '1.0.0', - nodeModules: {}, - }, - b: { - version: '1.0.0', - nodeModules: {}, - }, - c: { - version: '1.0.0', - nodeModules: {}, - }, - }; - const expectedFiles = new Map([ - ['a/package.json', '{}'], - ['a/index.d.ts', 'declare export const a: 1;'], - ['b/package.json', '{}'], - ['b/index.d.ts', 'declare export const b: 1;'], - ['c/package.json', '{}'], - ['c/index.d.ts', 'declare export const c: 1;'], - ]); - await checkTypesFetcher({ - sourceTexts, - packageJson, - cdnData, - expectedFiles, - expectedDependencyGraph, - expectedLayout, - }); - }); -}); diff --git a/src/test/typescript-worker_test.ts b/src/test/typescript-worker_test.ts deleted file mode 100644 index bcf3ecf8..00000000 --- a/src/test/typescript-worker_test.ts +++ /dev/null @@ -1,727 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {checkTransform} from './worker-test-util.js'; - -import {BuildOutput, SampleFile} from '../shared/worker-api.js'; -import {CdnData} from './fake-cdn-plugin.js'; - -suite('typescript builder', () => { - test('empty project', async () => { - const files: SampleFile[] = []; - const expected: BuildOutput[] = []; - await checkTransform(files, expected); - }); - - test('compiles ts file to js', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: 'export const foo: number = 3;', - }, - ]; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'export const foo = 3;\n', - contentType: 'text/javascript', - }, - }, - ]; - await checkTransform(files, expected); - }); - - test('ignores js file', async () => { - const files: SampleFile[] = [ - { - name: 'index.js', - content: 'export const foo: number = 3;', - }, - ]; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: 'export const foo: number = 3;', - }, - }, - ]; - await checkTransform(files, expected); - }); - - test('emits syntax error', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ':', - }, - ]; - const expected: BuildOutput[] = [ - { - diagnostic: { - code: 1128, - message: 'Declaration or statement expected.', - range: { - end: { - character: 1, - line: 0, - }, - start: { - character: 0, - line: 0, - }, - }, - severity: 1, - source: 'typescript', - }, - filename: 'index.ts', - kind: 'diagnostic', - }, - { - kind: 'file', - file: { - name: 'index.js', - // TODO(aomarks) This should probably return a 400 error instead of an - // empty but valid file. - content: '', - contentType: 'text/javascript', - }, - }, - ]; - await checkTransform(files, expected); - }); - - test('emits local semantic error', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - let foo: number = 3; - foo = "foo"; - `, - }, - ]; - const expected: BuildOutput[] = [ - { - diagnostic: { - code: 2322, - message: "Type 'string' is not assignable to type 'number'.", - range: { - end: { - character: 13, - line: 2, - }, - start: { - character: 10, - line: 2, - }, - }, - severity: 1, - source: 'typescript', - }, - filename: 'index.ts', - kind: 'diagnostic', - }, - { - kind: 'file', - file: { - name: 'index.js', - content: 'let foo = 3;\n' + 'foo = "foo";\n', - contentType: 'text/javascript', - }, - }, - ]; - await checkTransform(files, expected); - }); - - test('emits semantic error from bare module', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {strFn} from "foo"; - import {numFn} from "foo/bar.js"; - strFn(123); - numFn("str"); - `, - }, - ]; - const cdn: CdnData = { - foo: { - versions: { - '2.0.0': { - files: { - 'package.json': { - content: '{"main": "index.js"}', - }, - 'index.js': { - content: 'export const strFn = (s) => s;', - }, - 'bar.js': { - content: 'export const numFn = (n) => n;', - }, - 'index.d.ts': { - content: 'export declare const strFn: (s: string) => string;', - }, - 'bar.d.ts': { - content: 'export declare const numFn: (n: number) => number;', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - diagnostic: { - code: 2345, - message: - "Argument of type 'number' is not assignable to parameter of type 'string'.", - range: { - end: { - character: 19, - line: 3, - }, - start: { - character: 16, - line: 3, - }, - }, - severity: 1, - source: 'typescript', - }, - filename: 'index.ts', - kind: 'diagnostic', - }, - { - diagnostic: { - code: 2345, - message: - "Argument of type 'string' is not assignable to parameter of type 'number'.", - range: { - end: { - character: 21, - line: 4, - }, - start: { - character: 16, - line: 4, - }, - }, - severity: 1, - source: 'typescript', - }, - filename: 'index.ts', - kind: 'diagnostic', - }, - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import { strFn } from "./node_modules/foo@2.0.0/index.js";\nimport { numFn } from "./node_modules/foo@2.0.0/bar.js";\nstrFn(123);\nnumFn("str");\n', - contentType: 'text/javascript', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@2.0.0/index.js', - content: 'export const strFn = (s) => s;', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@2.0.0/bar.js', - content: 'export const numFn = (n) => n;', - contentType: 'text/javascript; charset=utf-8', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('respects package.json dependency for semantic errors', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {foo} from "foo"; - foo(123); - `, - }, - { - name: 'package.json', - content: `{ - "dependencies": { - "foo": "^1.0.0" - } - }`, - }, - ]; - const cdn: CdnData = { - foo: { - // foo takes a string in 1.0.0, and a number in 2.0.0. We should expect - // an error because we depend on 1.0.0. - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'export const foo = (s) => s;', - }, - 'index.d.ts': { - content: ` - import type {t} from './type.js'; - export declare const foo: (s: t) => t; - `, - }, - 'type.d.ts': { - content: `export type t = string;`, - }, - }, - }, - '2.0.0': { - files: { - 'index.js': { - content: 'export const foo = (n) => n;', - }, - 'index.d.ts': { - content: 'export declare const foo: (n: number) => number;', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - diagnostic: { - code: 2345, - message: - "Argument of type 'number' is not assignable to parameter of type 'string'.", - range: { - end: { - character: 17, - line: 2, - }, - start: { - character: 14, - line: 2, - }, - }, - severity: 1, - source: 'typescript', - }, - filename: 'index.ts', - kind: 'diagnostic', - }, - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import { foo } from "./node_modules/foo@1.0.0/index.js";\nfoo(123);\n', - contentType: 'text/javascript', - }, - }, - { - kind: 'file', - file: { - name: 'node_modules/foo@1.0.0/index.js', - content: 'export const foo = (s) => s;', - contentType: 'text/javascript; charset=utf-8', - }, - }, - { - kind: 'file', - file: { - name: 'package.json', - content: `{ - "dependencies": { - "foo": "^1.0.0" - } - }`, - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('prefers typings from: typings, types, main, index.d.ts', async () => { - const wrong = { - content: 'export type StringType = number;', - }; - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {StringType} from "a"; - export const str: StringType = "foo"; - `, - }, - ]; - const cdn: CdnData = { - a: { - versions: { - '1.0.0': { - files: { - 'package.json': { - content: `{ - "typings": "typings.d.ts", - "types": "types.d.ts", - "main": "main.js" - }`, - }, - 'typings.d.ts': { - content: 'export * from "b";', - }, - 'types.d.ts': wrong, - 'main.d.ts': wrong, - 'index.d.ts': wrong, - }, - }, - }, - }, - b: { - versions: { - '1.0.0': { - files: { - 'package.json': { - content: `{ - "types": "types.d.ts", - "main": "main.js" - }`, - }, - 'typings.d.ts': wrong, - 'types.d.ts': { - content: 'export * from "c";', - }, - 'main.d.ts': wrong, - 'index.d.ts': wrong, - }, - }, - }, - }, - c: { - versions: { - '1.0.0': { - files: { - 'package.json': { - content: `{ - "main": "main.js" - }`, - }, - 'typings.d.ts': wrong, - 'types.d.ts': wrong, - 'main.d.ts': { - content: 'export * from "d";', - }, - 'index.d.ts': wrong, - }, - }, - }, - }, - d: { - versions: { - '1.0.0': { - files: { - 'package.json': { - content: `{}`, - }, - 'typings.d.ts': wrong, - 'types.d.ts': wrong, - 'main.d.ts': wrong, - 'index.d.ts': { - content: 'export type StringType = string;', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: `export const str = "foo";\n`, - contentType: 'text/javascript', - }, - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('handles multiple versions', async () => { - const files: SampleFile[] = [ - { - name: 'index.ts', - content: ` - import {num} from "foo"; - import {str} from "str-or-num"; - const a: string = str; - const b: number = num - `, - }, - { - name: 'package.json', - content: `{ - "dependencies": { - "foo": "^1.0.0", - "str-or-num": "^1.0.0" - } - }`, - }, - ]; - const cdn: CdnData = { - 'str-or-num': { - versions: { - '1.0.0': { - files: { - 'index.js': { - content: 'export const str = "str";', - }, - 'index.d.ts': { - content: 'declare export const str: string;', - }, - }, - }, - '2.0.0': { - files: { - 'index.js': { - content: 'export const num = 0;', - }, - 'index.d.ts': { - content: 'declare export const num: number;', - }, - }, - }, - }, - }, - foo: { - versions: { - '1.0.0': { - files: { - 'package.json': { - content: `{ - "dependencies": { - "str-or-num": "^2.0.0" - } - }`, - }, - 'index.js': { - content: `export * from 'str-or-num';`, - }, - 'index.d.ts': { - content: `declare export * from 'str-or-num';`, - }, - }, - }, - }, - }, - typescript: { - versions: { - '4.3.5': { - files: { - 'lib/lib.dom.d.ts': { - content: '', - }, - 'lib/lib.esnext.d.ts': { - content: '', - }, - 'lib/lib.dom.iterable.d.ts': { - content: '', - }, - }, - }, - }, - }, - }; - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import { num } from "./node_modules/foo@1.0.0/index.js";\nimport { str } from "./node_modules/str-or-num@1.0.0/index.js";\nconst a = str;\nconst b = num;\n', - contentType: 'text/javascript', - }, - }, - { - file: { - content: "export * from '../str-or-num@2.0.0/index.js';", - contentType: 'text/javascript; charset=utf-8', - name: 'node_modules/foo@1.0.0/index.js', - }, - kind: 'file', - }, - { - file: { - content: 'export const str = "str";', - contentType: 'text/javascript; charset=utf-8', - name: 'node_modules/str-or-num@1.0.0/index.js', - }, - kind: 'file', - }, - { - file: { - content: 'export const num = 0;', - contentType: 'text/javascript; charset=utf-8', - name: 'node_modules/str-or-num@2.0.0/index.js', - }, - kind: 'file', - }, - { - file: { - content: - '{\n "dependencies": {\n "foo": "^1.0.0",\n "str-or-num": "^1.0.0"\n }\n }', - name: 'package.json', - }, - kind: 'file', - }, - ]; - await checkTransform(files, expected, {}, cdn); - }); - - test('compiles jsx file to js', async () => { - const files: SampleFile[] = [ - { - name: 'index.jsx', - content: ` - import React from "react"; - export const foo = (greeting) =>
{greeting}
- `, - }, - { - name: 'package.json', - content: `{ - "dependencies": { - "react": "^18.1.0" - } - }`, - }, - ]; - - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import React from "./node_modules/react@18.1.0/index.js";\nexport const foo = (greeting) => React.createElement("div", null, greeting);\n', - contentType: 'text/javascript', - }, - }, - { - kind: 'file', - file: { - content: 'export const createElement = (tag, props, children) => {};', - contentType: 'text/javascript; charset=utf-8', - name: 'node_modules/react@18.1.0/index.js', - }, - }, - { - kind: 'file', - file: { - content: - '{\n "dependencies": {\n "react": "^18.1.0"\n }\n }', - name: 'package.json', - }, - }, - ]; - - const cdn: CdnData = { - react: { - versions: { - '18.1.0': { - files: { - 'index.js': { - content: - 'export const createElement = (tag, props, children) => {};', - }, - }, - }, - }, - }, - }; - - await checkTransform(files, expected, {}, cdn); - }); - - test('compiles tsx file to js', async () => { - const files: SampleFile[] = [ - { - name: 'index.tsx', - content: ` - import * as React from "react"; - export const foo = (greeting: string) =>
{greeting}
- `, - }, - { - name: 'package.json', - content: `{ - "dependencies": { - "react": "^18.1.0" - } - }`, - }, - ]; - - const expected: BuildOutput[] = [ - { - kind: 'file', - file: { - name: 'index.js', - content: - 'import * as React from "./node_modules/react@18.1.0/index.js";\nexport const foo = (greeting) => React.createElement("div", null, greeting);\n', - contentType: 'text/javascript', - }, - }, - { - kind: 'file', - file: { - content: 'export const createElement = (tag, props, children) => {};', - contentType: 'text/javascript; charset=utf-8', - name: 'node_modules/react@18.1.0/index.js', - }, - }, - { - kind: 'file', - file: { - content: - '{\n "dependencies": {\n "react": "^18.1.0"\n }\n }', - name: 'package.json', - }, - }, - ]; - - const cdn: CdnData = { - react: { - versions: { - '18.1.0': { - files: { - 'index.js': { - content: - 'export const createElement = (tag, props, children) => {};', - }, - 'index.d.ts': { - content: - 'declare export const createElement(tag: unknown, props: unknown, children: unknown) => unknown;', - }, - }, - }, - }, - }, - }; - - await checkTransform(files, expected, {}, cdn); - }); -}); diff --git a/src/test/util_test.ts b/src/test/util_test.ts deleted file mode 100644 index b03f6302..00000000 --- a/src/test/util_test.ts +++ /dev/null @@ -1,502 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import { - MergedAsyncIterables, - relativeUrlPath, - resolveUrlPath, - classifySpecifier, - parseNpmStyleSpecifier, - fileExtension, - changeFileExtension, - charToLineAndChar, -} from '../typescript-worker/util.js'; - -suite('MergedAsyncIterables', () => { - const flush = async (iterable: AsyncIterable): Promise => { - const results: T[] = []; - for await (const value of iterable) { - results.push(value); - } - return results; - }; - - const raf = () => new Promise((resolve) => requestAnimationFrame(resolve)); - - test('zero iterables', async () => { - const expected: unknown[] = []; - const merged = new MergedAsyncIterables(); - const actual = await flush(merged); - assert.deepEqual(actual, expected); - }); - - test('one iterable', async () => { - const a = (async function* () { - yield 'a0'; - yield 'a1'; - })(); - const expected = ['a0', 'a1']; - const merged = new MergedAsyncIterables(); - merged.add(a); - const actual = await flush(merged); - assert.deepEqual(actual, expected); - }); - - test('throws if iterator added after complete', async () => { - const merged = new MergedAsyncIterables(); - merged.add( - (async function* () { - yield 'a'; - })() - ); - await flush(merged); - assert.throws(() => { - merged.add( - (async function* () { - yield 'b'; - })() - ); - }); - }); - - test('two iterables', async () => { - const a = (async function* () { - await raf(); - yield 'a0'; - yield 'a1'; - })(); - const b = (async function* () { - yield 'b0'; - yield 'b1'; - })(); - const expected = ['b0', 'b1', 'a0', 'a1']; - const merged = new MergedAsyncIterables(); - merged.add(a); - merged.add(b); - const actual = await flush(merged); - assert.deepEqual(actual, expected); - }); - - test('three iterables', async () => { - const a = (async function* () { - await raf(); // 0 - await raf(); // 1 - yield 'a0'; - await raf(); // 2 - await raf(); // 3 - yield 'a1'; - })(); - const b = (async function* () { - yield 'b0'; - await raf(); // 0 - await raf(); // 1 - await raf(); // 2 - await raf(); // 3 - await raf(); // 4 - yield 'b1'; - })(); - const c = (async function* () { - await raf(); // 0 - yield 'c0'; - await raf(); // 1 - await raf(); // 2 - yield 'c1'; - })(); - const expected = ['b0', 'c0', 'a0', 'c1', 'a1', 'b1']; - const merged = new MergedAsyncIterables(); - merged.add(a); - merged.add(b); - merged.add(c); - const actual = await flush(merged); - assert.deepEqual(actual, expected); - }); - - test('recursively add iterables', async () => { - const merged = new MergedAsyncIterables(); - const a = (async function* () { - yield 'a0'; - merged.add( - (async function* () { - await raf(); - yield 'b0'; - merged.add( - (async function* () { - yield 'c0'; - })() - ); - await raf(); - yield 'b1'; - })() - ); - yield 'a1'; - })(); - const expected = ['a0', 'a1', 'b0', 'c0', 'b1']; - merged.add(a); - const actual = await flush(merged); - assert.deepEqual(actual, expected); - }); - - test('notice a new iterator while waiting on an existing one', async () => { - const merged = new MergedAsyncIterables(); - - merged.add( - (async function* () { - await raf(); - yield 'slow'; - })() - ); - - // The key thing about this test is that we've started iterating before - // adding the second source. - const actual: string[] = []; - const done = (async () => { - for await (const value of merged) { - actual.push(value); - } - })(); - - merged.add( - (async function* () { - yield 'fast'; - })() - ); - - await done; - const expected = ['fast', 'slow']; - assert.deepEqual(actual, expected); - }); -}); - -suite('relativeUrlPath', () => { - const cases: Array<{from: string; to: string; expected: string}> = [ - { - from: 'index.js', - to: 'my-element.js', - expected: './my-element.js', - }, - { - from: 'index.js', - to: 'node_modules/foo/foo.js', - expected: './node_modules/foo/foo.js', - }, - { - from: 'node_modules/foo/foo.js', - to: 'node_modules/foo/foo2.js', - expected: './foo2.js', - }, - { - from: 'node_modules/foo/foo.js', - to: 'node_modules/bar/bar.js', - expected: '../bar/bar.js', - }, - { - from: 'node_modules/foo/a/b/c.js', - to: 'node_modules/bar/a/b/c.js', - expected: '../../../bar/a/b/c.js', - }, - { - from: 'index.js', - to: 'index.js', - expected: '', - }, - { - from: '', - to: 'index.js', - expected: './index.js', - }, - { - from: 'index.js', - to: '', - expected: './', - }, - { - from: '', - to: '', - expected: '', - }, - ]; - - for (const {from, to, expected} of cases) { - test(`"${from}" -> "${to}"`, () => { - const actual = relativeUrlPath(from, to); - assert.equal(actual, expected); - }); - } -}); - -suite('resolveUrlPath', () => { - const cases: Array<{a: string; b: string; expected: string}> = [ - { - a: 'index.js', - b: './my-element.js', - expected: '/my-element.js', - }, - { - a: 'index.js', - b: './node_modules/foo/foo.js', - expected: '/node_modules/foo/foo.js', - }, - { - a: 'node_modules/foo/foo.js', - b: './foo2.js', - expected: '/node_modules/foo/foo2.js', - }, - { - a: 'node_modules/foo/foo.js', - b: '../bar/bar.js', - expected: '/node_modules/bar/bar.js', - }, - { - a: 'node_modules/foo/a/b/c.js', - b: '../../../bar/a/b/c.js', - expected: '/node_modules/bar/a/b/c.js', - }, - { - a: 'index.js', - b: '', - expected: '/index.js', - }, - { - a: 'node_modules/index.js', - b: '.', - expected: '/node_modules/', - }, - { - a: 'node_modules/index.js', - b: './', - expected: '/node_modules/', - }, - { - a: 'node_modules/index.js', - b: '../', - expected: '/', - }, - ]; - - for (const {a, b, expected} of cases) { - test(`"${a}" -> "${b}"`, () => { - const actual = resolveUrlPath(a, b); - assert.equal(actual, expected); - }); - } -}); - -suite('classifySpecifier', () => { - const cases: Array<{specifier: string; expected: string}> = [ - { - specifier: 'foo', - expected: 'bare', - }, - { - specifier: 'foo.js', - expected: 'bare', - }, - { - specifier: './foo.js', - expected: 'relative', - }, - { - specifier: '../foo.js', - expected: 'relative', - }, - { - specifier: '../../foo/bar.js', - expected: 'relative', - }, - { - specifier: '/foo.js', - expected: 'relative', - }, - { - specifier: 'http://example.com/foo.js', - expected: 'url', - }, - ]; - - for (const {specifier, expected} of cases) { - test(specifier, () => { - const actual = classifySpecifier(specifier); - assert.equal(actual, expected); - }); - } -}); - -suite('parseNpmStyleSpecifier', () => { - const cases: Array<{ - specifier: string; - expected: ReturnType; - }> = [ - { - specifier: 'foo', - expected: {pkg: 'foo', version: '', path: ''}, - }, - { - specifier: 'foo@^1.2.3', - expected: {pkg: 'foo', version: '^1.2.3', path: ''}, - }, - { - specifier: 'foo/bar.js', - expected: {pkg: 'foo', version: '', path: 'bar.js'}, - }, - { - specifier: 'foo@^1.2.3/bar.js', - expected: {pkg: 'foo', version: '^1.2.3', path: 'bar.js'}, - }, - { - specifier: '@ns/foo', - expected: {pkg: '@ns/foo', version: '', path: ''}, - }, - { - specifier: '@ns/foo@^1.2.3', - expected: {pkg: '@ns/foo', version: '^1.2.3', path: ''}, - }, - { - specifier: '@ns/foo/bar.js', - expected: {pkg: '@ns/foo', version: '', path: 'bar.js'}, - }, - { - specifier: '@ns/foo@^1.2.3/bar.js', - expected: {pkg: '@ns/foo', version: '^1.2.3', path: 'bar.js'}, - }, - { - specifier: '', - expected: undefined, - }, - ]; - - for (const {specifier, expected} of cases) { - test(specifier, () => { - const actual = parseNpmStyleSpecifier(specifier); - assert.deepEqual(actual, expected); - }); - } -}); - -suite('fileExtension', () => { - const cases: Array<{ - path: string; - expected: string; - }> = [ - { - path: 'foo', - expected: '', - }, - { - path: 'foo.js', - expected: 'js', - }, - { - path: 'foo.ts', - expected: 'ts', - }, - { - path: 'foo.ts/bar.js', - expected: 'js', - }, - ]; - - for (const {path, expected} of cases) { - test(path, () => { - const actual = fileExtension(path); - assert.equal(actual, expected); - }); - } -}); - -suite('changeFileExtension', () => { - const cases: Array<{ - path: string; - newExt: string; - expected: string; - }> = [ - { - path: 'foo', - newExt: 'd.ts', - expected: 'foo.d.ts', - }, - { - path: 'foo.js', - newExt: 'd.ts', - expected: 'foo.d.ts', - }, - { - path: '', - newExt: 'd.ts', - expected: '.d.ts', - }, - { - path: 'foo.js', - newExt: '', - expected: 'foo.', - }, - ]; - - for (const {path, newExt, expected} of cases) { - test(`"${path}" -> "${newExt}"`, () => { - const actual = changeFileExtension(path, newExt); - assert.equal(actual, expected); - }); - } -}); - -suite('charToLineAndChar', () => { - const cases: Array<{ - str: string; - char: number; - expected: ReturnType; - }> = [ - { - str: 'foo\nbar\nbaz', - // ^ - char: 0, - expected: {line: 0, character: 0}, - }, - { - str: 'foo\nbar\nbaz', - // ^^ - char: 3, - expected: {line: 0, character: 3}, - }, - { - str: 'foo\nbar\nbaz', - // ^ - char: 4, - expected: {line: 1, character: 0}, - }, - { - str: 'foo\r\nbar\r\nbaz', - // ^^ - char: 3, - expected: {line: 0, character: 3}, - }, - { - str: 'foo\r\nbar\r\nbaz', - // ^^ - char: 4, - expected: {line: 0, character: 4}, - }, - { - str: 'foo\r\nbar\r\nbaz', - // ^ - char: 5, - expected: {line: 1, character: 0}, - }, - { - str: 'foo\nbar\nbaz', - // ^ - char: 10, - expected: {line: 2, character: 2}, - }, - ]; - - for (const {str, char, expected} of cases) { - test(`${char} in ${JSON.stringify(str)}`, () => { - const actual = charToLineAndChar(str, char); - assert.deepEqual(actual, expected); - }); - } -}); diff --git a/src/test/worker-test-util.ts b/src/test/worker-test-util.ts deleted file mode 100644 index 79c7ed7d..00000000 --- a/src/test/worker-test-util.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {assert} from '@esm-bundle/chai'; -import {build} from '../typescript-worker/build.js'; -import {executeServerCommand} from '@web/test-runner-commands'; - -import { - BuildOutput, - ModuleImportMap, - SampleFile, -} from '../shared/worker-api.js'; -import {CdnData} from './fake-cdn-plugin.js'; - -export const configureFakeCdn = async ( - data: CdnData -): Promise<{cdnBaseUrl: string; deleteCdnData: () => Promise}> => { - const {cdnBaseUrl, id} = (await executeServerCommand( - 'set-fake-cdn-data', - data - )) as {cdnBaseUrl: string; id: number}; - const deleteCdnData = async () => { - await executeServerCommand('delete-fake-cdn-data', id); - }; - return { - cdnBaseUrl, - deleteCdnData, - }; -}; - -export const checkTransform = async ( - files: SampleFile[], - expected: BuildOutput[], - importMap: ModuleImportMap = {}, - cdnData: CdnData = {} -) => { - const {cdnBaseUrl, deleteCdnData} = await configureFakeCdn(cdnData); - try { - const results: BuildOutput[] = []; - await new Promise((resolve) => { - const emit = (result: BuildOutput) => { - if (result.kind === 'done') { - resolve(); - } else { - results.push(result); - } - }; - build(files, {importMap, cdnBaseUrl}, emit); - }); - - for (const result of results) { - if (result.kind === 'diagnostic') { - // Sometimes diagnostics contain a CDN URL to help with debugging - // (usually the unpkg.com URL). But that will be a local dynamic URL in - // testing, so we'll substitute a static string so that we can do a - // simple equality test. - while (result.diagnostic.message.includes(cdnBaseUrl)) { - result.diagnostic.message = result.diagnostic.message.replace( - cdnBaseUrl, - '/' - ); - } - } - } - - assert.deepEqual( - results.sort(sortBuildOutput), - expected.sort(sortBuildOutput) - ); - } finally { - await deleteCdnData(); - } -}; - -const sortBuildOutput = (a: BuildOutput, b: BuildOutput) => { - if (a.kind === 'file' && b.kind === 'file') { - return a.file.name.localeCompare(b.file.name); - } - if (a.kind === 'diagnostic' && b.kind === 'diagnostic') { - return a.diagnostic.message.localeCompare(b.diagnostic.message); - } - return a.kind.localeCompare(b.kind); -}; diff --git a/src/typescript-worker/bare-module-transformer.ts b/src/typescript-worker/bare-module-transformer.ts deleted file mode 100644 index 2efe4195..00000000 --- a/src/typescript-worker/bare-module-transformer.ts +++ /dev/null @@ -1,426 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import * as esModuleLexer from 'es-module-lexer'; -import { - MergedAsyncIterables, - parseNpmStyleSpecifier, - resolveUrlPath, - charToLineAndChar, - fileExtension, - classifySpecifier, - relativeUrlPath, -} from './util.js'; -import {Deferred} from '../shared/deferred.js'; -import {NodeModuleResolver} from './node-module-resolver.js'; - -import { - BuildOutput, - DiagnosticBuildOutput, - FileBuildOutput, - SampleFile, -} from '../shared/worker-api.js'; -import {ImportMapResolver} from './import-map-resolver.js'; -import {CachingCdn} from './caching-cdn.js'; -import {NpmFileLocation, PackageJson} from './util.js'; - -/** - * Transforms bare module specifiers in .js files to canonical local paths, and - * adds the corresponding modules to the virtual filesystem. - * - * For example, transforms: - * import {html} from "lit"; - * Into: - * import {html} from "./node_modules/lit@2.1.2/index.js"; - * - * Dependencies are served from within the local - * "/node_modules/" path. This allows us to transform not - * only our own project files, but the entire module dependency graph too. - * - * Specifiers are canonicalized to include the latest concrete version that is - * compatible with the semver range, and to make default modules and file - * extensions explicit. This provides improved module de-duplication over - * unpkg.com's "?module" mode, which does not canonicalize. - * - * Version constraints are read from the "dependencies" field of package.json - * files, both in dependencies and in the top-level project itself. If the - * project doesn't contain a package.json file, the latest versions are assumed. - */ -export class BareModuleTransformer { - private _cdn: CachingCdn; - private _importMapResolver: ImportMapResolver; - private _emittedExternalDependencies = new Set(); - private _nodeResolver = new NodeModuleResolver({ - conditions: ['module', 'import', 'development', 'browser'], - }); - - constructor(cdn: CachingCdn, importMapResolver: ImportMapResolver) { - this._cdn = cdn; - this._importMapResolver = importMapResolver; - } - - async *process( - results: AsyncIterable | Iterable - ): AsyncIterable { - // This "output" iterable helps us emit all build outputs as soon as they - // are available as we asynchronously walk the dependency tree. - const output = new MergedAsyncIterables(); - output.add(this._handleProjectFiles(results, output)); - yield* output; - } - - /** - * Handle files from the top-level project. - */ - private async *_handleProjectFiles( - results: AsyncIterable | Iterable, - output: MergedAsyncIterables - ): AsyncIterable { - // The project might contain a package.json, which will determine our - // top-level version constraints. Resolve it lazily. - const packageJson = new Deferred(); - const getPackageJson = () => packageJson.promise; - for await (const result of results) { - if (result.kind === 'file' && result.file.name.endsWith('.js')) { - output.add(this._handleModule(result, getPackageJson, output)); - } else { - yield result; - if (result.kind === 'file' && result.file.name === 'package.json') { - let parsed: PackageJson | undefined; - try { - parsed = JSON.parse(result.file.content) as PackageJson; - } catch (e) { - yield makeJsonParseDiagnostic(e as Error, result.file); - } - if (parsed !== undefined) { - packageJson.resolve(parsed); - } - } - } - } - if (!packageJson.settled) { - // We never found a package.json. - packageJson.resolve(undefined); - } - } - - /** - * Transform all of the imported module specifiers in the given JS module, - * emit the transformed file, and process any dependencies corresponding to - * those specifiers. - */ - private async *_handleModule( - file: FileBuildOutput, - getPackageJson: () => Promise, - output: MergedAsyncIterables - ): AsyncIterable { - let js = file.file.content; - let specifiers; - await esModuleLexer.init; - try { - [specifiers] = esModuleLexer.parse(js); - } catch (e) { - yield file; - const diagnostic = makeEsModuleLexerDiagnostic( - e as Error, - file.file.name - ); - if (diagnostic !== undefined) { - yield diagnostic; - } - return; - } - const transforms = []; - // Note we iterating backwards so that the character offsets are not - // invalidated after each substitution. - for (let i = specifiers.length - 1; i >= 0; i--) { - const {n: oldSpecifier} = specifiers[i]; - if (oldSpecifier === undefined) { - // E.g. A dynamic import that's not a static string, like - // `import(someVariable)`. We can't handle this, skip. - continue; - } - transforms.push({ - info: specifiers[i], - newSpecifierPromise: this._handleSpecifier( - oldSpecifier, - file.file.name, - getPackageJson, - output - ), - }); - } - for (const { - info: {s: start, e: end, n: oldSpecifier, d: dynamicStart}, - newSpecifierPromise, - } of transforms) { - let newSpecifier; - try { - newSpecifier = await newSpecifierPromise; - } catch (e) { - // TODO(aomarks) If this was a TypeScript file, the user isn't going to - // see this diagnostic, since we're looking at the JS file. To show it - // correctly on the original file, we'll need source maps support. - yield { - kind: 'diagnostic', - filename: file.file.name, - diagnostic: { - message: `Could not resolve module "${oldSpecifier}": ${ - (e as Error).message - }`, - range: { - start: charToLineAndChar(js, start), - end: charToLineAndChar(js, end), - }, - }, - }; - continue; - } - if (newSpecifier === oldSpecifier) { - continue; - } - // For dynamic imports, the start/end range doesn't include quotes. - const isDynamic = dynamicStart !== -1; - const replacement = isDynamic ? `'${newSpecifier}'` : newSpecifier; - js = js.substring(0, start) + replacement + js.substring(end); - } - file.file.content = js; - yield file; - } - - /** - * Transform the given module specifier and process the dependency - * corresponding to it if needed. - */ - private async _handleSpecifier( - specifier: string, - referrer: string, - getPackageJson: () => Promise, - output: MergedAsyncIterables - ): Promise { - const fromImportMap = this._importMapResolver.resolve(specifier); - if (fromImportMap !== null) { - return fromImportMap; - } - const kind = classifySpecifier(specifier); - if (kind === 'url') { - return specifier; - } - if (kind === 'bare') { - return this._handleBareSpecifier( - specifier, - referrer, - getPackageJson, - output - ); - } - // Anything else is a relative specifier. - if (!referrer.startsWith('node_modules/')) { - // A relative specifier within a top-level project file. This specifier - // must resolve to another top-level project file, so there's nothing more - // we need to do here. - return specifier; - } - // E.g. if `referrer` is "node_modules/foo@1.2.3/a.js" and `specifier` is - // "./b.js", then `absolute` will be "node_modules/foo@1.2.3/b.js", and - // `bare` will be "foo@1.2.3/b.js". - const absolute = resolveUrlPath(referrer, specifier); - const bare = absolute.slice('/node_modules/'.length); - if (!fileExtension(specifier)) { - // We can't simply return the existing relative specifier if there's no - // ".js" extension, because we still need to do path canonicalization. For - // example: "./foo" could refer to "./foo.js" or "./foo/index.js" - // depending on what files are published to this package. We need to - // consult the CDN to figure that out. - return this._handleBareSpecifier( - bare, - referrer, - // Note we never need a package.json here, because the version is - // already included in the specifier itself at this point. We also - // wouldn't want to pass this scope's `getPackageJson`, because it would - // be the wrong one. - async () => undefined, - output - ); - } - // This relative specifier is good as-is, since it has an extension. We just - // need to fetch it. - const parsed = parseNpmStyleSpecifier(bare); - if (parsed === undefined) { - throw new Error(`Invalid specifier "${bare}"`); - } - output.add(this._fetchExternalDependency(parsed, output)); - return specifier; - } - - /** - * Canonicalize the given bare module specifier, then fetch it and add it to - * the local filesystem. - */ - private async _handleBareSpecifier( - specifier: string, - referrer: string, - getPackageJson: () => Promise, - output: MergedAsyncIterables - ): Promise { - let location = parseNpmStyleSpecifier(specifier); - if (location === undefined) { - throw new Error(`Invalid specifier "${specifier}"`); - } - if (!location.version) { - location.version = - (await getPackageJson())?.dependencies?.[location.pkg] ?? 'latest'; - } - // Resolve the version number before resolving the module, so that any error - // messages generated by the NodeModuleResolver will contain a concrete - // version number. - location.version = await this._cdn.resolveVersion(location); - const packageJson = await this._cdn.fetchPackageJson(location); - location.path = this._nodeResolver.resolve(location, packageJson, referrer); - if (!fileExtension(location.path)) { - // TODO(aomarks) It's safe to use unpkg's redirection-based - // canonicalization for this final file-extension-adding step ("./foo" -> - // "./foo.js"), because we've already applied package exports remappings - // (if we did this in reverse order, unpkg could give us a 404 for a file - // that only exists as a package export). However, it would be safer and a - // better separation of concerns to move this final file-extension-adding - // step directly into the NodeResolver class. - location = await this._cdn.canonicalize(location); - } - output.add(this._fetchExternalDependency(location, output)); - const absolute = `node_modules/${location.pkg}@${location.version}/${location.path}`; - const relative = relativeUrlPath(referrer, absolute); - return relative; - } - - /** - * Fetch the given external module, and add it to the local filesystem under - * its "node_modules/" path. - */ - private async *_fetchExternalDependency( - location: NpmFileLocation, - output: MergedAsyncIterables - ) { - const path = `${location.pkg}@${location.version}/${location.path}`; - if (this._emittedExternalDependencies.has(path)) { - // We already emitted this dependency. Avoid import loops and wasteful - // double fetches. - return; - } - this._emittedExternalDependencies.add(path); - let asset; - try { - asset = await this._cdn.fetch(location); - } catch (e) { - // TODO(aomarks) This file will end up as a 404 error when fetched from - // the preview iframe, because we're simply omitting this file from our - // output on error. We should instead allow FileBuildOutput to carry an - // HTTP status code, so then we could propagate this specific error to be - // served by the service worker, so that it shows up more usefully in the - // network tab. - console.error(`Error fetching ${path} from CDN: ${(e as Error).message}`); - return; - } - let packageJson: PackageJson | undefined | null = null; - const getPackageJson = async (): Promise => { - if (packageJson === null) { - try { - packageJson = await this._cdn.fetchPackageJson(location); - } catch { - packageJson = undefined; - } - } - return packageJson; - }; - yield* this._handleModule( - { - kind: 'file', - file: { - name: `node_modules/${path}`, - content: asset.content, - contentType: asset.contentType, - }, - }, - getPackageJson, - output - ); - } -} - -/** - * Create a useful Playground diagnostic from an es-module-lexer exception. - */ -const makeEsModuleLexerDiagnostic = ( - e: Error, - filename: string -): DiagnosticBuildOutput | undefined => { - const match = e.message.match(/@:(\d+):(\d+)$/); - if (match === null) { - return undefined; - } - const line = Number(match[1]) - 1; - const character = Number(match[2]) - 1; - return { - kind: 'diagnostic', - filename, - diagnostic: { - message: `es-module-lexer error: ${e.message}`, - range: { - start: {line, character}, - end: {line, character: character + 1}, - }, - }, - }; -}; - -/** - * Create a useful Playground diagnostic from a JSON.parse exception. - */ -const makeJsonParseDiagnostic = ( - e: Error, - file: SampleFile -): DiagnosticBuildOutput => { - const start = extractPositionFromJsonParseError(e.message, file.content) ?? { - line: 0, - character: 0, - }; - return { - kind: 'diagnostic', - filename: file.name, - diagnostic: { - message: `Invalid package.json: ${e}`, - range: { - start, - // To the rest of the file. - end: charToLineAndChar(file.content, file.content.length), - }, - }, - }; -}; - -/** - * Try to extract the line and character from a `JSON.parse` exception message. - * - * Chrome and Firefox often include this information, but using different - * formats. Safari never includes this information. - */ -const extractPositionFromJsonParseError = ( - message: string, - json: string -): {line: number; character: number} | undefined => { - const chrome = message.match(/at position (\d+)/); - if (chrome !== null) { - return charToLineAndChar(json, Number(chrome[1])); - } - const firefox = message.match(/at line (\d+) column (\d+)/); - if (firefox !== null) { - return { - line: Number(firefox[1]) - 1, - character: Number(firefox[2]) - 1, - }; - } - return undefined; -}; diff --git a/src/typescript-worker/build.ts b/src/typescript-worker/build.ts deleted file mode 100644 index 00fd1191..00000000 --- a/src/typescript-worker/build.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {BareModuleTransformer} from './bare-module-transformer.js'; - -import {SampleFile, BuildOutput, WorkerConfig} from '../shared/worker-api.js'; -import {getWorkerContext} from './worker-context.js'; -import {processTypeScriptFiles} from './typescript-builder.js'; - -export const build = async ( - files: Array, - config: WorkerConfig, - emit: (result: BuildOutput) => void -): Promise => { - const workerContext = getWorkerContext(config); - const bareModuleBuilder = new BareModuleTransformer( - workerContext.cdn, - workerContext.importMapResolver - ); - - const results = bareModuleBuilder.process( - processTypeScriptFiles( - workerContext, - files.map((file) => ({kind: 'file', file})) - ) - ); - for await (const result of results) { - emit(result); - } - emit({kind: 'done'}); -}; diff --git a/src/typescript-worker/caching-cdn.ts b/src/typescript-worker/caching-cdn.ts deleted file mode 100644 index 298ea68a..00000000 --- a/src/typescript-worker/caching-cdn.ts +++ /dev/null @@ -1,234 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { - fileExtension, - parseNpmStyleSpecifier, - isExactSemverVersion, - pkgVersion, - pkgVersionPath, -} from './util.js'; -import {Deferred} from '../shared/deferred.js'; - -import {NpmFileLocation, PackageJson} from './util.js'; - -export interface CdnFile { - content: string; - contentType: string; -} - -/** - * An interface to unpkg.com or a similar NPM CDN service. - */ -export class CachingCdn { - private readonly _cdnBaseUrl: string; - - /** - * A cache for all fetch operations to avoid redundant network requests. - * Maps from package-version-path to a promise that resolves with the URL and - * file content. - */ - private readonly _fetchCache = new Map< - string, - Deferred<{url: string; file: CdnFile}> - >(); - - /** - * Maps from package + version ranges/tags to resolved semver versions. This - * allows us to canonicalize more efficiently, because once we've resolved - * e.g. "foo@^1.0.0/foo.js" to "foo@1.2.3/foo.js", we can then canonicalize - * "foo@^1.0.0/bar.js" without another fetch. - */ - private readonly _versionCache = new Map(); - - /** - * @param cdnBaseUrl Base URL for the CDN (e.g., 'https://unpkg.com') - */ - constructor(cdnBaseUrl: string) { - this._cdnBaseUrl = cdnBaseUrl.endsWith('/') - ? cdnBaseUrl.slice(0, -1) - : cdnBaseUrl; - } - - /** - * Fetch a file from the CDN. - */ - async fetch(location: NpmFileLocation): Promise { - const {file} = await this._fetch(location); - return file; - } - - /** - * Resolve a package location to a CDN URL using the configured provider - */ - private _resolveCdnUrl(location: NpmFileLocation): string { - // Construct the URL directly using the CDN base URL - const packageSpec = `${location.pkg}@${location.version}`; - - const path = location.path ? `/${location.path}` : ''; - - return `${this._cdnBaseUrl}/${packageSpec}${path}`; - } - - /** - * Return a version of the given CDN file specifier where version ranges and - * NPM tags are resolved to concrete semver versions, and ambiguous paths are - * resolved to concrete ones. - * - * E.g. foo@^1.0.0 -> foo@1.2.3/index.js - * - * TODO(aomarks) Remove this method in favor of separate resolveVersion and - * fileExists methods, so that the caller can fully control resolution. We - * shouldn't rely on unpkg's redirection logic for resolving paths anymore, - * because it doesn't follow Node package exports, which can arbitrary remap - * paths. - */ - async canonicalize(location: NpmFileLocation): Promise { - let exact = isExactSemverVersion(location.version); - if (!exact) { - const pv = pkgVersion(location); - const resolved = this._versionCache.get(pv); - if (resolved !== undefined) { - location = {...location, version: resolved}; - exact = true; - } - } - if (!exact || fileExtension(location.path) === '') { - const {url} = await this._fetch(location); - location = this._parseCdnUrl(url)!; - } - return location; - } - - /** - * Resolve the concrete version of the given package and version range - */ - async resolveVersion({ - pkg, - version, - }: { - pkg: string; - version: string; - }): Promise { - return (await this.canonicalize({pkg, version, path: 'package.json'})) - .version; - } - - /** - * Fetch and parse a package's package.json file. - */ - async fetchPackageJson({ - pkg, - version, - }: { - pkg: string; - version: string; - }): Promise { - const { - url, - file: {content}, - } = await this._fetch({pkg, version, path: 'package.json'}); - try { - return JSON.parse(content) as PackageJson; - } catch (e) { - throw new Error(`Error parsing CDN package.json from ${url}: ${e}`); - } - } - - private async _fetch( - location: NpmFileLocation - ): Promise<{url: string; file: CdnFile}> { - let exact = isExactSemverVersion(location.version); - if (!exact) { - const pv = pkgVersion(location); - const resolved = this._versionCache.get(pv); - if (resolved !== undefined) { - location = {...location, version: resolved}; - exact = true; - } - } - const pvp = pkgVersionPath(location); - const cached = this._fetchCache.get(pvp); - if (cached !== undefined) { - return cached.promise; - } - const deferred = new Deferred<{ - url: string; - file: CdnFile; - }>(); - this._fetchCache.set(pvp, deferred); - const url = this._resolveCdnUrl(location); - let res: Response; - let content = ''; - try { - res = await fetch(url); - content = await res.text(); - - if (res.status !== 200) { - const errorMessage = `CDN HTTP ${res.status} error (${url}): ${content}`; - console.warn(errorMessage); - const err = new Error(errorMessage); - deferred.reject(err); - return deferred.promise; - } - } catch (e) { - // Error usually happens if it's a 404 on the CDN causing the fetch to - // throw a cors error - console.warn( - `Network error fetching ${url}: ${ - e instanceof Error ? e.message : String(e) - }` - ); - const err = new Error( - `Failed to fetch from CDN (${url}): ${ - e instanceof Error ? e.message : String(e) - }` - ); - deferred.reject(err); - return deferred.promise; - } - if (!exact) { - const canonical = this._parseCdnUrl(res.url); - if (canonical) { - this._versionCache.set(pkgVersion(location), canonical.version); - this._fetchCache.set(pkgVersionPath(canonical), deferred); - } - } - - const result = { - url: res.url, - file: { - content, - contentType: res.headers.get('content-type') ?? 'text/plain', - }, - }; - deferred.resolve(result); - return deferred.promise; - } - - private _parseCdnUrl(url: string): NpmFileLocation | undefined { - // Check if the URL starts with our CDN base URL - if (!url.startsWith(this._cdnBaseUrl)) { - const errorMessage = `Failed to parse CDN URL: ${url} - URL does not start with CDN base URL: ${this._cdnBaseUrl}`; - console.warn(errorMessage); - return undefined; - } - - // Extract the path after the CDN base URL - const path = url.slice(this._cdnBaseUrl.length + 1); // +1 for the trailing slash - - // Use the utility function to parse the path as an NPM-style specifier - const parsed = parseNpmStyleSpecifier(path); - - if (parsed) { - return parsed; - } - - const errorMessage = `Failed to parse CDN URL: ${url} - could not extract package information`; - console.warn(errorMessage); - return undefined; - } -} diff --git a/src/typescript-worker/completions.ts b/src/typescript-worker/completions.ts deleted file mode 100644 index 0d30348b..00000000 --- a/src/typescript-worker/completions.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import { - CompletionInfo, - GetCompletionsAtPositionOptions, - SymbolDisplayPart, - WithMetadata, -} from 'typescript'; -import {EditorCompletionDetails, WorkerConfig} from '../shared/worker-api.js'; -import {getWorkerContext} from './worker-context.js'; - -/** - * Query completions from the Language Service, and sort them by - * relevance for user to use. - */ -export const queryCompletions = async ( - filename: string, - fileContent: string, - tokenUnderCursor: string, - cursorIndex: number, - config: WorkerConfig -): Promise | undefined> => { - const workerContext = getWorkerContext(config); - - const languageService = workerContext.languageServiceContext.service; - const languageServiceHost = workerContext.languageServiceContext.serviceHost; - const searchWordIsPeriod = tokenUnderCursor === '.'; - - const options = {} as GetCompletionsAtPositionOptions; - if (searchWordIsPeriod) { - options.triggerCharacter = '.'; - } - // Update language service status so that the file is up to date - const fileAbsolutePath = new URL(filename, self.origin).href; - // TODO: Could this cause a race condition between the build phase - // and the completion phase, and could that be a problem? - languageServiceHost.updateFileContentIfNeeded(fileAbsolutePath, fileContent); - - // Fetch the collection of completions, the language service offers us for our current context. - // This list of completions is quite vast, and therefore we will need to do some extra sorting - // and filtering on it before sending it back to the browser. - const completions = languageService.getCompletionsAtPosition( - filename, - cursorIndex, - options - ); - - return completions; -}; - -/** - * Acquire extra information on the hovered completion item. - * This includes some package info, context and signatures. - * - * This is done separate from acquiring completions, since it's slower, and - * is done on a per completion basis. - */ -export const getCompletionItemDetails = async ( - filename: string, - cursorIndex: number, - config: WorkerConfig, - completionWord: string -): Promise => { - const workerContext = getWorkerContext(config); - const languageService = workerContext.languageServiceContext.service; - - // Only passing relevant params for now, since the other values - // are not needed for current functionality - const details = languageService.getCompletionEntryDetails( - filename, - cursorIndex, - completionWord, - undefined, - undefined, - undefined, - undefined - ); - - const detailInformation: EditorCompletionDetails = { - text: displayPartsToString(details?.displayParts), - tags: details?.tags ?? [], - documentation: getDocumentations(details?.documentation), - }; - return detailInformation; -}; - -function displayPartsToString( - displayParts: SymbolDisplayPart[] | undefined -): string { - if (!displayParts || displayParts.length === 0) return ''; - - let displayString = ''; - displayParts.forEach((part) => { - displayString += part.text; - }); - return displayString; -} - -function getDocumentations( - documentation: SymbolDisplayPart[] | undefined -): string[] { - return documentation?.map((doc) => doc.text) ?? []; -} diff --git a/src/typescript-worker/diagnostic.ts b/src/typescript-worker/diagnostic.ts deleted file mode 100644 index 40b09518..00000000 --- a/src/typescript-worker/diagnostic.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import ts from '../internal/typescript.js'; -import * as lsp from 'vscode-languageserver-protocol'; - -/** - * Convert a diagnostic from TypeScript format to Language Server Protocol - * format. - */ -export function makeLspDiagnostic(tsDiagnostic: ts.Diagnostic): lsp.Diagnostic { - return { - code: tsDiagnostic.code, - source: tsDiagnostic.source ?? 'typescript', - message: ts.flattenDiagnosticMessageText(tsDiagnostic.messageText, '\n'), - severity: diagnosticCategoryMapping[tsDiagnostic.category], - range: { - start: - tsDiagnostic.file !== undefined && tsDiagnostic.start !== undefined - ? tsDiagnostic.file.getLineAndCharacterOfPosition(tsDiagnostic.start) - : {character: 0, line: 0}, - end: - tsDiagnostic.file !== undefined && - tsDiagnostic.start !== undefined && - tsDiagnostic.length !== undefined - ? tsDiagnostic.file.getLineAndCharacterOfPosition( - tsDiagnostic.start + tsDiagnostic.length - ) - : {character: 0, line: 0}, - }, - }; -} - -/** - * We don't want a runtime import of 'vscode-languageserver-protocol' just for the - * DiagnosticSeverity constants. We can duplicate the values instead, and assert - * we got them right with a type constraint. - */ -const diagnosticCategoryMapping: { - [ts.DiagnosticCategory.Error]: (typeof lsp.DiagnosticSeverity)['Error']; - [ts.DiagnosticCategory.Warning]: (typeof lsp.DiagnosticSeverity)['Warning']; - [ts.DiagnosticCategory - .Message]: (typeof lsp.DiagnosticSeverity)['Information']; - [ts.DiagnosticCategory.Suggestion]: (typeof lsp.DiagnosticSeverity)['Hint']; -} = { - [ts.DiagnosticCategory.Error]: 1, - [ts.DiagnosticCategory.Warning]: 2, - [ts.DiagnosticCategory.Message]: 3, - [ts.DiagnosticCategory.Suggestion]: 4, -}; diff --git a/src/typescript-worker/import-map-resolver.ts b/src/typescript-worker/import-map-resolver.ts deleted file mode 100644 index e33aca93..00000000 --- a/src/typescript-worker/import-map-resolver.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {ModuleImportMap} from '../shared/worker-api.js'; - -/** - * Resolves module specifiers using an import map. - * - * For overview, see https://github.com/WICG/import-maps. For algorithm, see - * https://wicg.github.io/import-maps/#resolving - * - * TODO(aomarks) Add support for `scopes`. - */ -export class ImportMapResolver { - private importMap: ModuleImportMap; - - constructor(importMap: ModuleImportMap) { - this.importMap = importMap; - } - - resolve(specifier: string): string | null { - for (const [specifierKey, resolutionResult] of Object.entries( - this.importMap.imports ?? {} - )) { - // Note that per spec we shouldn't do a lookup for the exact match case, - // because if a trailing-slash mapping also matches and comes first, it - // should have precedence. - if (specifierKey === specifier) { - return resolutionResult; - } - - if (specifierKey.endsWith('/') && specifier.startsWith(specifierKey)) { - if (!resolutionResult.endsWith('/')) { - console.warn( - `Could not resolve module specifier "${specifier}"` + - ` using import map key "${specifierKey}" because` + - ` address "${resolutionResult}" must end in a forward-slash.` - ); - return null; - } - - const afterPrefix = specifier.substring(specifierKey.length); - let url; - try { - url = new URL(afterPrefix, resolutionResult); - } catch { - console.warn( - `Could not resolve module specifier "${specifier}"` + - ` using import map key "${specifierKey}" because` + - ` "${afterPrefix}" could not be parsed` + - ` relative to "${resolutionResult}".` - ); - return null; - } - - const urlSerialized = url.href; - if (!urlSerialized.startsWith(resolutionResult)) { - console.warn( - `Could not resolve module specifier "${specifier}"` + - ` using import map key "${specifierKey}" because` + - ` "${afterPrefix}" backtracked above "${resolutionResult}".` - ); - return null; - } - return urlSerialized; - } - } - return null; - } -} diff --git a/src/typescript-worker/language-service-context.ts b/src/typescript-worker/language-service-context.ts deleted file mode 100644 index e907e395..00000000 --- a/src/typescript-worker/language-service-context.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import ts from '../internal/typescript.js'; - -const compilerOptions = { - target: ts.ScriptTarget.ES2021, - module: ts.ModuleKind.ESNext, - experimentalDecorators: true, - skipDefaultLibCheck: true, - skipLibCheck: true, - allowJs: true, - moduleResolution: ts.ModuleResolutionKind.NodeNext, - jsx: ts.JsxEmit.React, - lib: ['dom', 'esnext'], -}; - -/** - * Compiles a project, returning a Map of compiled file contents. The map only - * contains context for files that are compiled. Other files are skipped. - * - * TODO (justinfagnani): We could share a DocumentRegistry across - * multiple instances to save memory and type analysis of - * common lib files like lit-element, lib.d.ts and dom.d.ts. - */ -export class LanguageServiceContext { - readonly compilerOptions = compilerOptions; - - readonly serviceHost = new WorkerLanguageServiceHost( - self.origin, - compilerOptions - ); - - readonly service = ts.createLanguageService( - this.serviceHost, - ts.createDocumentRegistry() - ); -} - -interface VersionedFile { - version: number; - content: string; -} - -class WorkerLanguageServiceHost implements ts.LanguageServiceHost { - readonly compilerOptions: ts.CompilerOptions; - readonly packageRoot: string; - readonly files: Map = new Map(); - - constructor(packageRoot: string, compilerOptions: ts.CompilerOptions) { - this.packageRoot = packageRoot; - this.compilerOptions = compilerOptions; - } - - /* - * When a new new "process" command is received, we iterate through all of the files, - * and update files accordingly depending on if they have new content or not. - * - * With how the TS API works, we can use simple versioning to tell the - * Language service that a file has been updated - * - * If the file submitted is a new file, we add it to our collection - */ - updateFileContentIfNeeded(fileName: string, content: string) { - const file = this.files.get(fileName); - if (file && file.content !== content) { - file.content = content; - file.version += 1; - } else { - this.files.set(fileName, {content, version: 0}); - } - } - - /** - * Sync up the freshly acquired project files. - * In the syncing process files yet to be added are added, and versioned. - * Files that existed already but are modified are updated, and their version number - * gets bumped fo that the languageservice knows to update these files. - * */ - sync(files: Map) { - files.forEach((file, fileName) => - this.updateFileContentIfNeeded(fileName, file) - ); - this._removeDeletedFiles(files); - } - - private _removeDeletedFiles(files: Map) { - this.getScriptFileNames().forEach((fileName) => { - // Do not delete the dependency files, as then they will get re-applied every compilation. - // This is because the compilation step is aware of these files, but the completion step isn't. - if (!fileName.includes('node_modules') && !files.has(fileName)) { - this.files.delete(fileName); - } - }); - } - - getCompilationSettings(): ts.CompilerOptions { - return this.compilerOptions; - } - - getScriptFileNames(): string[] { - return [...this.files.keys()]; - } - - getScriptVersion(fileName: string) { - return this.files.get(fileName)?.version.toString() ?? '-1'; - } - - fileExists(fileName: string): boolean { - return this.files.has(fileName); - } - - readFile(fileName: string): string | undefined { - return this.files.get(fileName)?.content; - } - - getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined { - if (!this.fileExists(fileName)) { - return undefined; - } - return ts.ScriptSnapshot.fromString(this.readFile(fileName)!); - } - - getCurrentDirectory(): string { - return this.packageRoot; - } - - getDefaultLibFileName(): string { - return '__lib.d.ts'; - } -} diff --git a/src/typescript-worker/node-module-resolver.ts b/src/typescript-worker/node-module-resolver.ts deleted file mode 100644 index 890ab264..00000000 --- a/src/typescript-worker/node-module-resolver.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {packageExportsResolve} from './node/resolve.js'; -import {NpmFileLocation, PackageJson, PackageJsonWithExports} from './util.js'; - -/** - * Resolves a path according to the Node package exports algorithm. - * - * Documentation: - * - * Node: https://nodejs.org/api/packages.html#packages_package_entry_points - * Rollup: https://github.com/rollup/plugins/tree/master/packages/node-resolve/#package-entrypoints - * Webpack: https://webpack.js.org/guides/package-exports/ - * - * Reference implementations: - * - * Node: https://github.com/nodejs/node/blob/a9dd03b1ec89a75186f05967fc76ec0704050c36/lib/internal/modules/esm/resolve.js#L615 - * Rollup: - * https://github.com/rollup/plugins/blob/53fb18c0c2852598200c547a0b1d745d15b5b487/packages/node-resolve/src/package/resolvePackageImportsExports.js#L6 - */ -export class NodeModuleResolver { - private readonly _conditions: Set; - - constructor({conditions}: {conditions: string[]}) { - this._conditions = new Set(conditions); - } - - /** - * @param location Package/version/path to resolve. - * @param packageJson The package's package.json (parsed object, not string). - * @param base Path of the importing module, used for error messages (e.g. - * "./my-element.js"). - * @return The resolved subpath. - * @throws If the given subpath could not be resolved. - */ - resolve( - location: NpmFileLocation, - packageJson: PackageJson, - base: string - ): string { - const packageSubpath = addRelativePrefix(location.path); - - if (packageJson.exports === undefined) { - if (packageSubpath === '.') { - if (packageJson.module !== undefined) { - return removeRelativePrefix(packageJson.module); - } - if (packageJson.main !== undefined) { - return removeRelativePrefix(packageJson.main); - } - return 'index.js'; - } - return location.path; - } - - // Node's resolve functions works with file:// URLs. It doesn't really - // matter what we use as the base, but let's make one that matches the - // Playground URL space for dependencies, so that errors make sense. - const packageBase = `/node_modules/${location.pkg}@${location.version}/`; - const packageJsonUrl = new URL(packageBase, 'file://'); - - const resolved = packageExportsResolve( - packageJsonUrl, - packageSubpath, - packageJson as PackageJsonWithExports, - base, - this._conditions - ); - if (!resolved.pathname.startsWith(packageBase)) { - throw new Error( - `Unexpected error: ${resolved.pathname} expected to start with ${packageBase}` - ); - } - return resolved.pathname.slice(packageBase.length); - } -} - -/** - * Convert e.g. "" to "." and "foo.js" to "./foo.js". - */ -const addRelativePrefix = (path: string): string => { - if (path === '') { - return '.'; - } - if (!path.startsWith('.') && !path.startsWith('/')) { - return './' + path; - } - return path; -}; - -/** - * Convert e.g. "." to "" and "./foo.js" to "foo.js". - */ -const removeRelativePrefix = (path: string): string => { - if (path === '.') { - return ''; - } - if (path.startsWith('./')) { - return path.slice(2); - } - return path; -}; diff --git a/src/typescript-worker/node-modules-layout-maker.ts b/src/typescript-worker/node-modules-layout-maker.ts deleted file mode 100644 index 2c689379..00000000 --- a/src/typescript-worker/node-modules-layout-maker.ts +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -type VersionNumber = string; - -/** - * Like the "dependencies" field of a package.json file, except the version - * numbers are always concrete instead of semver ranges. - */ -export interface PackageDependencies { - [pkg: string]: VersionNumber; -} - -/** - * Maps from NPM package name, to the versions of that package, to its - * dependencies. - */ -export interface DependencyGraph { - [pkg: string]: { - [version: string]: PackageDependencies; - }; -} - -/** - * The contents of a "node_modules/" directory. Keys are NPM package names. - * Values are objects containing the version, and the contents of a nested - * "node_modules/" directory. - */ -export interface NodeModulesDirectory { - [pkg: string]: { - version: VersionNumber; - nodeModules: NodeModulesDirectory; - }; -} - -/** - * Temporary data structure used during graph traversal to associate a node in - * the dependency graph with its corresponding node_modules/ directory, and the - * parent of that directory. - */ -interface GraphTraversalState { - dependencies: PackageDependencies; - nodeModules: NodeModulesDirectory; - parent: GraphTraversalState | null; -} - -/** - * Given an NPM-style dependency graph, makes a directory structure comprised of - * nested "node_modules/" folders that is compatible with the layout expected by - * the Node module resolution algorithm - * (https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders). - * - * Attempts to create the flattest directory layout possible to reduce file - * duplication, without causing version conflicts. - * - * For example, given the dependency graph: - * - * ROOT - * /|\ - * / | \ - * / | \ - * v v v - * A1 B1 C1 - * \ / - * \ / - * v - * A2 --> D1 - * - * Returns the directory tree: - * - * ROOT - * ├── A1 - * ├── B1 - * │ └── A2 - * ├── C1 - * │ └── A2 - * └── D1 - */ -export class NodeModulesLayoutMaker { - layout( - rootDeps: PackageDependencies, - depGraph: DependencyGraph - ): NodeModulesDirectory { - const rootNodeModulesDir: NodeModulesDirectory = {}; - // Traverse the dependency graph using breadth-first search so that we - // "install" all of a package's direct dependencies before moving on to its - // transitive dependencies. - const bfsQueue: Array = [ - { - dependencies: rootDeps, - nodeModules: rootNodeModulesDir, - parent: null, - }, - ]; - while (bfsQueue.length > 0) { - const currentNode = bfsQueue.shift()!; - for (const [pkg, version] of Object.entries(currentNode.dependencies)) { - // Find the best node_modules/ directory to install this dependency - // into. We're looking for the directory that is closest to the root - // (including the root itself), but which has no conflicting version of - // the same package along the path. - let installLocation = currentNode; - let alreadyInstalled = false; - while (installLocation.parent !== null) { - const parentVersion = - installLocation.parent.nodeModules[pkg]?.version; - if (parentVersion !== undefined) { - alreadyInstalled = parentVersion === version; - break; - } - installLocation = installLocation.parent; - } - if (alreadyInstalled) { - // This package was already installed at the exact same version in - // some reachable ancestor directory, so we're already done. - continue; - } - // "Install" this dependency. - const nestedNodeModules = {}; - installLocation.nodeModules[pkg] = { - version, - nodeModules: nestedNodeModules, - }; - // Add this dependency's own dependencies onto the breadth-first search - // queue. - const childDependencies = depGraph[pkg]?.[version]; - if (childDependencies !== undefined) { - bfsQueue.push({ - dependencies: childDependencies, - nodeModules: nestedNodeModules, - parent: installLocation, - }); - } - } - } - return rootNodeModulesDir; - } -} diff --git a/src/typescript-worker/node/errors.ts b/src/typescript-worker/node/errors.ts deleted file mode 100644 index 09e7c752..00000000 --- a/src/typescript-worker/node/errors.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @license - * Copyright 2017 Node.js contributors. All rights reserved. - * SPDX-License-Identifier: MIT - */ - -// This file is derived from -// https://github.com/nodejs/node/blob/a9dd03b1ec89a75186f05967fc76ec0704050c36/lib/internal/errors.js -// and adapted for use in playground-elements. - -import {fileURLToPath} from './url.js'; -import {PackageExportsTarget} from '../util.js'; - -export class InvalidModuleSpecifierError extends Error { - constructor(request: string, reason: string, base?: string) { - super( - `Invalid module "${request}" ${reason}${ - base ? ` imported from ${base}` : '' - }` - ); - } -} - -export class InvalidPackageConfigError extends Error { - constructor(path: string, base: string, message: string) { - super( - `Invalid package config ${path}${base ? ` while importing ${base}` : ''}${ - message ? `. ${message}` : '' - }` - ); - } -} - -export class InvalidPackageTargetError extends Error { - constructor( - pkgPath: URL, - key: string, - target: PackageExportsTarget, - isImport = false, - base?: string - ) { - const relError = - typeof target === 'string' && - !isImport && - target.length && - !target.startsWith('./'); - let msg; - if (key === '.') { - msg = - `Invalid "exports" main target ${JSON.stringify(target)} defined ` + - `in the package config ${fileURLToPath(pkgPath)}package.json${ - base ? ` imported from ${base}` : '' - }${relError ? '; targets must start with "./"' : ''}`; - } else { - msg = `Invalid "${ - isImport ? 'imports' : 'exports' - }" target ${JSON.stringify( - target - )} defined for '${key}' in the package config ${fileURLToPath( - pkgPath - )}package.json${base ? ` imported from ${base}` : ''}${ - relError ? '; targets must start with "./"' : '' - }`; - } - super(msg); - } -} -export class PackagePathNotExportedError extends Error { - constructor(pkgPath: string, subpath: string, base?: string) { - if (subpath === '.') { - super( - `No "exports" main defined in ${pkgPath}package.json${ - base ? ` imported from ${base}` : '' - }` - ); - } else { - super( - `Package subpath '${subpath}' is not defined by "exports" in ${pkgPath}package.json${ - base ? ` imported from ${base}` : '' - }` - ); - } - } -} diff --git a/src/typescript-worker/node/resolve.ts b/src/typescript-worker/node/resolve.ts deleted file mode 100644 index 7fd946e9..00000000 --- a/src/typescript-worker/node/resolve.ts +++ /dev/null @@ -1,417 +0,0 @@ -/** - * @license - * Copyright 2020 Node.js contributors. All rights reserved. - * SPDX-License-Identifier: MIT - */ - -// This file is derived from -// https://github.com/nodejs/node/blob/a9dd03b1ec89a75186f05967fc76ec0704050c36/lib/internal/modules/esm/resolve.js -// and adapted for use in playground-elements. - -import {fileURLToPath} from './url.js'; -import { - InvalidModuleSpecifierError, - InvalidPackageConfigError, - InvalidPackageTargetError, - PackagePathNotExportedError, -} from './errors.js'; -import { - PackageExports, - PackageExportsPathOrConditionMap, - PackageExportsTarget, - PackageJsonWithExports, -} from '../util.js'; - -function emitFolderMapDeprecation( - match: string, - pjsonUrl: URL, - isExports: boolean, - base: string -): void { - const pjsonPath = fileURLToPath(pjsonUrl); - console.warn( - `Use of deprecated folder mapping "${match}" in the ${ - isExports ? '"exports"' : '"imports"' - } field module resolution of the package at ${pjsonPath}${ - base ? ` imported from ${base}` : '' - }.\n` + - `Update this package.json to use a subpath pattern like "${match}*".`, - 'DeprecationWarning', - 'DEP0148' - ); -} - -function makeExportsNotFoundError( - subpath: string, - packageJSONUrl: URL, - base: string -): PackagePathNotExportedError { - return new PackagePathNotExportedError( - fileURLToPath(new URL('.', packageJSONUrl)), - subpath, - base - ); -} - -function makeInvalidSubpathError( - subpath: string, - packageJSONUrl: URL, - internal: boolean, - base: string -) { - const reason = `request is not a valid subpath for the "${ - internal ? 'imports' : 'exports' - }" resolution of ${fileURLToPath(packageJSONUrl)}`; - return new InvalidModuleSpecifierError(subpath, reason, base); -} - -function makeInvalidPackageTargetError( - subpath: string, - target: PackageExportsTarget, - packageJSONUrl: URL, - internal: boolean, - base: string -) { - if (typeof target === 'object' && target !== null) { - target = JSON.stringify(target, null, ''); - } else { - target = `${target}`; - } - return new InvalidPackageTargetError( - packageJSONUrl, - subpath, - target, - internal, - base - ); -} - -const invalidSegmentRegEx = /(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/; -const patternRegEx = /\*/g; - -function resolvePackageTargetString( - target: string, - subpath: string, - match: string, - packageJSONUrl: URL, - base: string, - pattern: boolean, - internal: boolean, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _conditions: Set -): URL { - if (subpath !== '' && !pattern && target[target.length - 1] !== '/') { - throw makeInvalidPackageTargetError( - match, - target, - packageJSONUrl, - internal, - base - ); - } - - if (!target.startsWith('./')) { - // TODO(aomarks) Add when support here for package "imports" is added. - throw makeInvalidPackageTargetError( - match, - target, - packageJSONUrl, - internal, - base - ); - } - - if (invalidSegmentRegEx.test(target.slice(2))) { - throw makeInvalidPackageTargetError( - match, - target, - packageJSONUrl, - internal, - base - ); - } - - const resolved = new URL(target, packageJSONUrl); - const resolvedPath = resolved.pathname; - const packagePath = new URL('.', packageJSONUrl).pathname; - - if (!resolvedPath.startsWith(packagePath)) { - throw makeInvalidPackageTargetError( - match, - target, - packageJSONUrl, - internal, - base - ); - } - - if (subpath === '') { - return resolved; - } - - if (invalidSegmentRegEx.test(subpath)) { - throw makeInvalidSubpathError( - match + subpath, - packageJSONUrl, - internal, - base - ); - } - - if (pattern) { - return new URL(resolved.href.replace(patternRegEx, subpath)); - } - return new URL(subpath, resolved); -} - -function isArrayIndex(key: string): boolean { - const keyNum = +key; - if (`${keyNum}` !== key) { - return false; - } - return keyNum >= 0 && keyNum < 0xffff_ffff; -} - -function resolvePackageTarget( - packageJSONUrl: URL, - target: PackageExportsTarget, - subpath: string, - packageSubpath: string, - base: string, - pattern: boolean, - internal: boolean, - conditions: Set -): URL | null | undefined { - if (typeof target === 'string') { - return resolvePackageTargetString( - target, - subpath, - packageSubpath, - packageJSONUrl, - base, - pattern, - internal, - conditions - ); - } else if (Array.isArray(target)) { - if (target.length === 0) { - return null; - } - - let lastException; - for (let i = 0; i < target.length; i++) { - const targetItem = target[i]; - let resolved; - try { - resolved = resolvePackageTarget( - packageJSONUrl, - targetItem, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - } catch (e) { - lastException = e; - if (e instanceof InvalidPackageTargetError) { - continue; - } - throw e; - } - if (resolved === undefined) continue; - if (resolved === null) { - lastException = null; - continue; - } - return resolved; - } - if (lastException === undefined || lastException === null) { - return lastException; - } - throw lastException; - } else if (typeof target === 'object' && target !== null) { - const keys = Object.getOwnPropertyNames(target); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (isArrayIndex(key)) { - throw new InvalidPackageConfigError( - fileURLToPath(packageJSONUrl), - base, - '"exports" cannot contain numeric property keys.' - ); - } - } - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (key === 'default' || conditions.has(key)) { - const conditionalTarget = target[key]; - const resolved = resolvePackageTarget( - packageJSONUrl, - conditionalTarget, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - if (resolved === undefined) continue; - return resolved; - } - } - return undefined; - } else if (target === null) { - return null; - } - throw makeInvalidPackageTargetError( - packageSubpath, - target, - packageJSONUrl, - internal, - base - ); -} - -function isConditionalExportsMainSugar( - // Note we are avoiding locals called exactly "exports" because of - // incompatibilities with JS Compiler which can produce code that expects to - // be able to reference a global called "exports". - _exports: PackageExports, - packageJSONUrl: URL, - base: string -): boolean { - if (typeof _exports === 'string' || Array.isArray(_exports)) { - return true; - } - if (typeof _exports !== 'object' || _exports === null) { - return false; - } - - const keys = Object.getOwnPropertyNames(_exports); - let isConditionalSugar = false; - let i = 0; - for (let j = 0; j < keys.length; j++) { - const key = keys[j]; - const curIsConditionalSugar = key === '' || key[0] !== '.'; - if (i++ === 0) { - isConditionalSugar = curIsConditionalSugar; - } else if (isConditionalSugar !== curIsConditionalSugar) { - throw new InvalidPackageConfigError( - fileURLToPath(packageJSONUrl), - base, - '"exports" cannot contain some keys starting with \'.\' and some not.' + - ' The exports object must either be an object of package subpath keys' + - ' or an object of main entry condition name keys only.' - ); - } - } - return isConditionalSugar; -} - -export function packageExportsResolve( - packageJSONUrl: URL, - packageSubpath: string, - packageConfig: PackageJsonWithExports, - base: string, - conditions: Set -): URL { - let _exports = packageConfig.exports; - if (isConditionalExportsMainSugar(_exports, packageJSONUrl, base)) { - _exports = {'.': _exports}; - } - _exports = _exports as PackageExportsPathOrConditionMap; - - if ( - Object.prototype.hasOwnProperty.call(_exports, packageSubpath) && - !packageSubpath.includes('*') && - !packageSubpath.endsWith('/') - ) { - const target = _exports[packageSubpath]; - const resolved = resolvePackageTarget( - packageJSONUrl, - target, - '', - packageSubpath, - base, - false, - false, - conditions - ); - if (resolved === null || resolved === undefined) { - throw makeExportsNotFoundError(packageSubpath, packageJSONUrl, base); - } - return resolved; - } - - let bestMatch = ''; - let bestMatchSubpath: string | undefined = undefined; - for (const key of Object.keys(_exports)) { - const patternIndex = key.indexOf('*'); - if ( - patternIndex !== -1 && - packageSubpath.startsWith(key.slice(0, patternIndex)) - ) { - const patternTrailer = key.slice(patternIndex + 1); - if ( - packageSubpath.length >= key.length && - packageSubpath.endsWith(patternTrailer) && - patternKeyCompare(bestMatch, key) === 1 && - key.lastIndexOf('*') === patternIndex - ) { - bestMatch = key; - bestMatchSubpath = packageSubpath.slice( - patternIndex, - packageSubpath.length - patternTrailer.length - ); - } - } else if ( - key.endsWith('/') && - packageSubpath.startsWith(key) && - patternKeyCompare(bestMatch, key) === 1 - ) { - bestMatch = key; - bestMatchSubpath = packageSubpath.slice(key.length); - } - } - - if (bestMatch) { - const target = _exports[bestMatch]; - const pattern = bestMatch.includes('*'); - const resolved = resolvePackageTarget( - packageJSONUrl, - target, - // bestMatchSubpath must be defined when bestMatch is not empty string - bestMatchSubpath!, - bestMatch, - base, - pattern, - false, - conditions - ); - if (resolved === null || resolved === undefined) { - throw makeExportsNotFoundError(packageSubpath, packageJSONUrl, base); - } - if (!pattern) { - emitFolderMapDeprecation(bestMatch, packageJSONUrl, true, base); - } - return resolved; - } - - throw makeExportsNotFoundError(packageSubpath, packageJSONUrl, base); -} - -function patternKeyCompare(a: string, b: string): -1 | 0 | 1 { - const aPatternIndex = a.indexOf('*'); - const bPatternIndex = b.indexOf('*'); - const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; - const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; - if (baseLenA > baseLenB) return -1; - if (baseLenB > baseLenA) return 1; - if (aPatternIndex === -1) return 1; - if (bPatternIndex === -1) return -1; - if (a.length > b.length) return -1; - if (b.length > a.length) return 1; - return 0; -} diff --git a/src/typescript-worker/node/url.ts b/src/typescript-worker/node/url.ts deleted file mode 100644 index 38501aac..00000000 --- a/src/typescript-worker/node/url.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright 2016 Node.js contributors. All rights reserved. - * SPDX-License-Identifier: MIT - */ - -// This file is derived from -// https://github.com/nodejs/node/blob/a9dd03b1ec89a75186f05967fc76ec0704050c36/lib/internal/url.js -// and adapted for use in playground-elements. - -export function fileURLToPath(path: URL | string): string { - if (typeof path === 'string') { - path = new URL(path); - } - if (path.protocol !== 'file:') { - throw new Error('The URL must be of scheme file'); - } - return path.pathname; -} diff --git a/src/typescript-worker/types-fetcher.ts b/src/typescript-worker/types-fetcher.ts deleted file mode 100644 index 390881fe..00000000 --- a/src/typescript-worker/types-fetcher.ts +++ /dev/null @@ -1,426 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import ts from '../internal/typescript.js'; -import {ImportMapResolver} from './import-map-resolver.js'; -import {Deferred} from '../shared/deferred.js'; -import { - parseNpmStyleSpecifier, - changeFileExtension, - classifySpecifier, - resolveUrlPath, - trimTrailingSlash, - trimLeadingSlash, -} from './util.js'; - -import {Result} from '../shared/util.js'; -import {CachingCdn} from './caching-cdn.js'; -import {PackageJson, NpmFileLocation} from './util.js'; -import { - PackageDependencies, - DependencyGraph, - NodeModulesDirectory, - NodeModulesLayoutMaker, -} from './node-modules-layout-maker.js'; - -type PackageName = string; -type PackageVersion = string; -type FilePath = string; -type FileContent = string; - -/** - * The top-level project. Used as a referrer. - */ -const root = Symbol(); - -/** - * Fetches typings for TypeScript imports and their transitive dependencies, and - * for standard libraries. - */ -export class TypesFetcher { - private readonly _cdn: CachingCdn; - private readonly _importMapResolver: ImportMapResolver; - private readonly _rootPackageJson: PackageJson | undefined; - - private readonly _rootDependencies: PackageDependencies = {}; - private readonly _dependencyGraph: DependencyGraph = {}; - private readonly _filesByPackageVersion = new Map< - PackageName, - Map>>> - >(); - - /** - * Fetch all ".d.ts" typing files for the full transitive dependency tree of - * the given project source files and standard libs. - * - * @param cdn Interface to unpkg.com or similar CDN service for fetching - * assets. - * @param importMapResolver Resolves bare modules to custom URLs, for - * optionally overriding the CDN. - * @param rootPackageJson The parsed package.json file for the root project, - * or undefined if there isn't one. - * @param sources Project TypeScript source file contents. All bare module - * imports in these sources will be followed. - * @param tsLibs Case-insensitive TypeScript standard libraries to fetch, e.g. - * "es2020", "DOM". - */ - static async fetchTypes( - cdn: CachingCdn, - importMapResolver: ImportMapResolver, - rootPackageJson: PackageJson | undefined, - sources: string[], - tsLibs: string[] - ): Promise<{ - files: Map; - layout: NodeModulesDirectory; - dependencyGraph: { - root: PackageDependencies; - deps: DependencyGraph; - }; - }> { - const fetcher = new TypesFetcher(cdn, importMapResolver, rootPackageJson); - // Note we use Promise.allSettled instead of Promise.all because we really - // do want to ignore exceptions due to 404s etc., and don't want one error - // to fail the entire tree. If the .d.ts files for an import fail to load - // for any reason, then they won't exist in the virtual filesystem passed to - // TypeScript, and the user will therefore see a "missing types" error. An - // improvement would be to surface some more detail to the user, though, - // especially for non-404 errors. - await Promise.allSettled([ - ...sources.map((source) => - fetcher._handleBareAndRelativeSpecifiers(source, root) - ), - ...tsLibs.map((lib) => fetcher._addTypeScriptStandardLib(lib)), - fetcher._fetchTypesPackages(), - ]); - const layout = new NodeModulesLayoutMaker().layout( - fetcher._rootDependencies, - fetcher._dependencyGraph - ); - const files = new Map(); - await fetcher._materializeNodeModulesTree(layout, files, ''); - // Note in practice we only really need "files", but it's useful to also - // return the dependency graph and layout for testing. - return { - files, - layout, - dependencyGraph: { - root: fetcher._rootDependencies, - deps: fetcher._dependencyGraph, - }, - }; - } - - private constructor( - cdn: CachingCdn, - importMapResolver: ImportMapResolver, - rootPackageJson: PackageJson | undefined - ) { - this._cdn = cdn; - this._importMapResolver = importMapResolver; - this._rootPackageJson = rootPackageJson; - } - - private async _fetchTypesPackages(): Promise { - if ( - this._rootPackageJson === undefined || - this._rootPackageJson.dependencies === undefined - ) { - return; - } - - const typesPackages = Object.keys( - this._rootPackageJson.dependencies - ).filter((k) => k.startsWith('@types/')); - - if (typesPackages.length === 0) { - return; - } - - await Promise.allSettled( - typesPackages.map((k) => this._handleBareSpecifier(k, root)) - ); - } - - private async _addTypeScriptStandardLib(lib: string): Promise { - return this._handleBareSpecifier( - `typescript/lib/lib.${lib.toLowerCase()}.js`, - root - ); - } - - private async _handleBareAndRelativeSpecifiers( - sourceText: string, - referrer: NpmFileLocation | typeof root - ): Promise { - const fileInfo = ts.preProcessFile(sourceText, undefined, true); - const promises = []; - for (const {fileName: specifier} of fileInfo.importedFiles) { - const kind = classifySpecifier(specifier); - if (kind === 'bare') { - promises.push(this._handleBareSpecifier(specifier, referrer)); - } else if (kind === 'relative' && referrer !== root) { - // Note we never need to follow relative imports from project root files - // because those can only be other project files, which are already - // being processed, since we pass all project files to this class. - promises.push(this._handleRelativeSpecifier(specifier, referrer)); - } - } - for (const {fileName: lib} of fileInfo.libReferenceDirectives) { - promises.push(this._addTypeScriptStandardLib(lib)); - } - await Promise.allSettled(promises); - } - - private async _handleBareSpecifier( - bare: string, - referrer: NpmFileLocation | typeof root - ): Promise { - let location = parseNpmStyleSpecifier(bare); - if (location === undefined) { - return; - } - // Versions don't make much sense with an import map, since you just have - // bare specifier -> URL. We can leave whatever version we already have; it - // will always be ignored. - const handledByImportMap = this._importMapResolver.resolve(bare) !== null; - // Get the version range based on the referrer's package.json. - if (!handledByImportMap) { - location.version = await this._getDependencyVersion( - referrer, - location.pkg - ); - } - // Get the ".d.ts" path by changing extension, or looking up the "typings" - // field, etc. - location.path = await this._getDtsPath(location); - // Resolve the concrete version. - if (!handledByImportMap) { - location = await this._cdn.canonicalize(location); - } - if (referrer === root || location.pkg !== referrer.pkg) { - // Note the two package names can be the same in the case that a typings - // file imports another module from the same package using its own bare - // module name, instead of a relative path. TypeScript does support this - // case, and it does happen (e.g. @material/base does this). We don't need - // a self-edge in the dependency graph, though. - this._addEdgeToDependencyGraph(referrer, location); - } - // Stop early if we've already handled this specifier. - if ( - this._filesByPackageVersion - .get(location.pkg) - ?.get(location.version) - ?.get(location.path) !== undefined - ) { - return; - } - // Ready to fetch and recurse. - const dtsResult = await this._fetchAndAddToOutputFiles(location); - if (dtsResult.error !== undefined) { - return; - } - await this._handleBareAndRelativeSpecifiers(dtsResult.result, location); - } - - private async _handleRelativeSpecifier( - relative: string, - referrer: NpmFileLocation - ): Promise { - const location = { - // We know package and version must be the same as the referrer, since - // this is a relative path, and we are therefore still in the same - // package. - pkg: referrer.pkg, - version: referrer.version, - // Make the path package-root relative, instead of referrer-path relative. - path: trimLeadingSlash(resolveUrlPath(referrer.path, relative).slice(1)), - }; - location.path = changeFileExtension(location.path, 'd.ts'); - // Stop early if we've already handled this specifier. - if ( - this._filesByPackageVersion - .get(location.pkg) - ?.get(location.version) - ?.get(location.path) !== undefined - ) { - return; - } - const dtsResult = await this._fetchAndAddToOutputFiles(location); - if (dtsResult.error !== undefined) { - return; - } - await this._handleBareAndRelativeSpecifiers(dtsResult.result, location); - } - - private async _getDependencyVersion( - from: NpmFileLocation | typeof root, - to: string - ): Promise { - const packageJson = - from === root - ? this._rootPackageJson - : await this._fetchPackageJsonAndAddToOutputFiles(from); - return packageJson?.dependencies?.[to] ?? 'latest'; - } - - private async _getDtsPath(location: NpmFileLocation): Promise { - if (location.path !== '') { - return changeFileExtension(location.path, 'd.ts'); - } - const packageJson = await this._fetchPackageJsonAndAddToOutputFiles( - location - ); - return ( - packageJson?.typings ?? - packageJson?.types ?? - (packageJson?.main !== undefined - ? changeFileExtension(packageJson.main, 'd.ts') - : undefined) ?? - 'index.d.ts' - ); - } - - private async _fetchPackageJsonAndAddToOutputFiles(location: { - pkg: string; - version: string; - }): Promise { - const result = await this._fetchAndAddToOutputFiles({ - ...location, - path: 'package.json', - }); - if (result.error !== undefined) { - throw new Error( - `Could not fetch package.json for ` + - `${location.pkg}@${location.version}: ${result.error}` - ); - } - return JSON.parse(result.result) as PackageJson; - } - - private async _fetchAndAddToOutputFiles( - location: NpmFileLocation - ): Promise> { - const importMapUrl = this._importMapResolver.resolve( - trimTrailingSlash(`${location.pkg}/${location.path}`) - ); - if (importMapUrl === null) { - location = await this._cdn.canonicalize(location); - } - - let versions = this._filesByPackageVersion.get(location.pkg); - if (versions === undefined) { - versions = new Map(); - this._filesByPackageVersion.set(location.pkg, versions); - } - let files = versions.get(location.version); - if (files === undefined) { - files = new Map(); - versions.set(location.version, files); - } - let promise = files.get(location.path); - if (promise !== undefined) { - return promise; - } - const deferred = new Deferred>(); - promise = deferred.promise; - files.set(location.path, promise); - - let content; - if (importMapUrl !== null) { - const r = await fetch(importMapUrl); - if (r.status !== 200) { - const err = {error: r.status}; - deferred.resolve(err); - return err; - } - content = await r.text(); - } else { - try { - const r = await this._cdn.fetch(location); - content = r.content; - } catch { - const err = {error: 404}; - deferred.resolve(err); - return err; - } - } - const result = {result: content}; - deferred.resolve(result); - return result; - } - - /** - * Record in our dependency graph that some package depends on another. - */ - private _addEdgeToDependencyGraph( - from: {pkg: string; version: string} | typeof root, - to: {pkg: string; version: string} - ) { - if (from === root) { - this._rootDependencies[to.pkg] = to.version; - } else { - let fromVersions = this._dependencyGraph[from.pkg]; - if (fromVersions === undefined) { - fromVersions = {}; - this._dependencyGraph[from.pkg] = fromVersions; - } - let deps = fromVersions[from.version]; - if (deps === undefined) { - deps = {}; - fromVersions[from.version] = deps; - } - deps[to.pkg] = to.version; - } - } - - /** - * Materialize a node_modules/ file tree for the given layout into the given - * file map, using the files we've fetched. - * - * For example, given the layout ... - * - * ROOT - * ├── A1 - * ├── B1 - * │ └── A2 - * └── C1 - * └── A2 - * - * ... and where each package just contains one "index.d.ts" file, then - * populates the file map with keys: - * - * a/index.d.ts - * b/index.d.ts - * b/node_modules/a/index.d.ts - * c/index.d.ts - * c/node_modules/a/index.d.ts - */ - private async _materializeNodeModulesTree( - layout: NodeModulesDirectory, - fileMap: Map, - prefix: FilePath - ): Promise { - for (const [pkg, entry] of Object.entries(layout)) { - const files = this._filesByPackageVersion.get(pkg)?.get(entry.version); - if (files === undefined) { - continue; - } - for (const [pkgRelativePath, promise] of files) { - const result = await promise; - if (result.error === undefined) { - const fullyQualifiedPath = `${prefix}${pkg}/${pkgRelativePath}`; - fileMap.set(fullyQualifiedPath, result.result); - } - } - await this._materializeNodeModulesTree( - entry.nodeModules, - fileMap, - `${prefix}${pkg}/node_modules/` - ); - } - } -} diff --git a/src/typescript-worker/typescript-builder.ts b/src/typescript-worker/typescript-builder.ts deleted file mode 100644 index 8041fb04..00000000 --- a/src/typescript-worker/typescript-builder.ts +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {BuildOutput, SampleFile} from '../shared/worker-api.js'; -import {TypesFetcher} from './types-fetcher.js'; -import {PackageJson} from './util.js'; -import {makeLspDiagnostic} from './diagnostic.js'; -import {WorkerContext} from './worker-context.js'; - -export async function* processTypeScriptFiles( - workerContext: WorkerContext, - results: AsyncIterable | Iterable -): AsyncIterable { - // Instantiate langservice variables for ease of access - const langService = workerContext.languageServiceContext.service; - const langServiceHost = workerContext.languageServiceContext.serviceHost; - let packageJson: PackageJson | undefined; - const compilerInputs = []; - for await (const result of results) { - if ( - result.kind === 'file' && - (result.file.name.endsWith('.ts') || - result.file.name.endsWith('.jsx') || - result.file.name.endsWith('.tsx')) - ) { - compilerInputs.push(result.file); - } else { - yield result; - if (result.kind === 'file' && result.file.name === 'package.json') { - try { - packageJson = JSON.parse(result.file.content) as PackageJson; - } catch (e) { - // A bit hacky, but BareModuleTransformer already emits a diagnostic - // for this case, so we don't need another one. - } - } - } - } - - if (compilerInputs.length === 0) { - return; - } - - // Immediately resolve local project files, and begin fetching types (but - // don't wait for them). - const loadedFiles = new Map(); - const inputFiles = compilerInputs.map((file) => ({ - file, - url: new URL(file.name, self.origin).href, - })); - - for (const {file, url} of inputFiles) { - loadedFiles.set(url, file.content); - } - - // TypeScript needs the local package.json because it's interested in the - // "types" and "imports" fields. - // - // We also change the default "type" field from "commonjs" to "module" because - // we're pretty much always in a web context, and wanting standard module - // semantics. - const defaultPackageJson = - packageJson === undefined - ? {type: 'module'} - : packageJson.type === 'module' - ? packageJson - : {...packageJson, type: 'module'}; - loadedFiles.set( - new URL('package.json', self.origin).href, - JSON.stringify(defaultPackageJson) - ); - - // Sync the new loaded files with the servicehost. - // If the file is missing, it's added, if the file is modified, - // the modification data and versioning will be handled by the servicehost. - // If a file is removed, it will be removed from the file list - langServiceHost.sync(loadedFiles); - - const program = langService.getProgram(); - if (program === undefined) { - throw new Error('Unexpected error: program was undefined'); - } - - for (const {file, url} of inputFiles) { - for (const tsDiagnostic of langService.getSyntacticDiagnostics(url)) { - yield { - kind: 'diagnostic', - filename: file.name, - diagnostic: makeLspDiagnostic(tsDiagnostic), - }; - } - const sourceFile = program.getSourceFile(url); - let compiled: SampleFile | undefined = undefined; - program!.emit(sourceFile, (url, content) => { - compiled = { - name: new URL(url).pathname.slice(1), - content, - contentType: 'text/javascript', - }; - }); - if (compiled !== undefined) { - yield {kind: 'file', file: compiled}; - } - } - - // Wait for all typings to be fetched, and then retrieve slower semantic - // diagnostics. - const typings = await TypesFetcher.fetchTypes( - workerContext.cdn, - workerContext.importMapResolver, - packageJson, - inputFiles.map((file) => file.file.content), - workerContext.languageServiceContext.compilerOptions.lib - ); - for (const [path, content] of typings.files) { - // TypeScript is going to look for these files as paths relative to our - // source files, so we need to add them to our filesystem with those URLs. - const url = new URL(`node_modules/${path}`, self.origin).href; - langServiceHost.updateFileContentIfNeeded(url, content); - } - for (const {file, url} of inputFiles) { - for (const tsDiagnostic of langService.getSemanticDiagnostics(url)) { - yield { - kind: 'diagnostic', - filename: file.name, - diagnostic: makeLspDiagnostic(tsDiagnostic), - }; - } - } -} diff --git a/src/typescript-worker/util.ts b/src/typescript-worker/util.ts deleted file mode 100644 index d1bc97e1..00000000 --- a/src/typescript-worker/util.ts +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * Merges multiple async iterables into one iterable. Order is not preserved. - * Iterables can be added before or during iteration. After exhausted, adding a - * new iterator throws. - */ -export class MergedAsyncIterables { - private readonly _buffer: Array<{value: T; emitted: () => void}> = []; - private _numSources = 0; - private _notify?: () => void; - private _done = false; - - async *[Symbol.asyncIterator]() { - while (this._numSources > 0) { - while (this._buffer.length > 0) { - const {value, emitted} = this._buffer.shift()!; - yield value; - // Let the loop in add() continue - emitted(); - } - // Wait until there is a new value or a source iterator was exhausted - await new Promise((resolve) => (this._notify = resolve)); - this._notify = undefined; - } - this._done = true; - } - - add(iterable: AsyncIterable) { - if (this._done) { - throw new Error( - 'Merged iterator is exhausted. Cannot add new source iterators.' - ); - } - this._numSources++; - void (async () => { - for await (const value of iterable) { - // Wait for this value to be emitted before continuing - await new Promise((emitted) => { - this._buffer.push({value, emitted}); - this._notify?.(); - }); - } - this._numSources--; - this._notify?.(); - })(); - } -} - -/** - * Return the relative path from two URL pathnames. - * - * E.g. given "a/b/c.js" and "a/d.js" return "../d.js". - */ -export const relativeUrlPath = (from: string, to: string): string => { - const fromParts = from.split('/'); - const toParts = to.split('/'); - let numCommon = 0; - while ( - numCommon < fromParts.length && - numCommon < toParts.length && - fromParts[numCommon] === toParts[numCommon] - ) { - numCommon++; - } - const numUp = fromParts.length - numCommon - 1; - return ( - (numUp === 0 ? './' : new Array(numUp + 1).join('../')) + - toParts.slice(numCommon).join('/') - ); -}; - -/** - * Resolve two URL pathnames into an absolute path. - * - * E.g. given "a/b/c.js" and "../d.js" return "a/d.js". - */ -export const resolveUrlPath = (a: string, b: string) => - // The base URL is arbitrary and "ws://_" is very short. - new URL(b, new URL(a, 'ws://_')).pathname; - -/** - * Return whether the given module import specifier is bare, a relative URL, or - * a fully qualified URL. - */ -export const classifySpecifier = ( - specifier: string -): 'bare' | 'relative' | 'url' => { - try { - // Note a specifier like "te:st.js" would be classified as a URL. This is - // ok, because we can assume bare specifiers are always prefixed with a NPM - // package name, which cannot contain ":" characters. - new URL(specifier).href; - return 'url'; - // eslint-disable-next-line no-empty - } catch {} - if (specifier.match(/^(\.){0,2}\//) !== null) { - return 'relative'; - } - return 'bare'; -}; - -export interface NpmFileLocation { - pkg: string; - version: string; - path: string; -} - -/** - * Parse the given module import specifier using format - * "[@][/]". - * - * E.g. given "foo@^1.2.3/bar.js" return { - * pkg: "foo", - * version: "^1.2.3", - * path: "bar.js" - * } - */ -export const parseNpmStyleSpecifier = ( - specifier: string -): NpmFileLocation | undefined => { - const match = specifier.match(/^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?\/?(.*)$/); - if (match === null) { - return undefined; - } - const [, pkg, version, path] = match as [ - unknown, - string, - string | undefined, - string - ]; - return {pkg, version: version ?? '', path}; -}; - -/** - * Return the file extension of the given URL path. Does not include the leading - * ".". Note this only considers the final ".", so e.g. given "foo.d.ts" this - * will return "ts". - */ -export const fileExtension = (path: string): string => { - const lastSlashIdx = path.lastIndexOf('/'); - const lastDotIdx = path.lastIndexOf('.'); - return lastDotIdx === -1 || lastDotIdx < lastSlashIdx - ? '' - : path.slice(lastDotIdx + 1); -}; - -/** - * Change the given URL path's file extension to a different one. `newExt` - * should not include the leading ".". Note this only considers the final ".", - * so e.g. given "foo.d.ts" and ".js" this will return "foo.d.js". - */ -export const changeFileExtension = (path: string, newExt: string): string => { - const oldExt = fileExtension(path); - if (oldExt === '') { - return path + '.' + newExt; - } - return path.slice(0, -oldExt.length) + newExt; -}; - -/** - * Given a string and string-relative character index, return the equivalent - * line number and line-relative character index. - */ -export const charToLineAndChar = ( - str: string, - char: number -): {line: number; character: number} => { - let line = 0; - let character = 0; - for (let i = 0; i < char && i < str.length; i++) { - if (str[i] === '\n') { - line++; - character = 0; - } else { - character++; - } - } - return {line, character}; -}; - -/** - * The "exports" field of a package.json. - * - * See https://nodejs.org/api/packages.html#packages_exports. - */ -export type PackageExports = - | PackageExportsTarget - | PackageExportsPathOrConditionMap; - -/** - * The export result for some path or condition. - */ -export type PackageExportsTarget = - // A concrete path. - | PackageExportsTargetPath - // Condition maps can be nested. - | PackageExportsConditionMap - // The first valid target in an array wins. - | PackageExportsTarget[] - // An explicit "not found". - | null; - -/** - * A concrete resolved path (e.g. "./lib/foo.js"). - */ -export type PackageExportsTargetPath = string; - -/** - * Map from a path or condition to a target. - */ -export type PackageExportsPathOrConditionMap = { - [pathOrCondition: string]: PackageExportsTarget; -}; - -/** - * Map from a condition to a target. - * - * Note this is technically the same type as PackageExportsPathOrConditionMap, - * but it's distinguished for clarity because "path" keys are only allowed in - * the top-level of the "exports" object. - */ -export type PackageExportsConditionMap = { - [condition: string]: PackageExportsTarget; -}; - -export interface PackageJson { - version?: string; - main?: string; - exports?: PackageExports; - module?: string; - types?: string; - typings?: string; - type?: string; - dependencies?: {[key: string]: string}; -} - -export interface PackageJsonWithExports extends PackageJson { - exports: PackageExports; -} - -/** - * Return whether the given string is an exact semver version, as opposed to a - * range or tag. - */ -export const isExactSemverVersion = (s: string) => - s.match( - // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string - /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ - ) !== null; - -export const pkgVersion = ({pkg, version}: {pkg: string; version: string}) => - `${pkg}@${version || 'latest'}`; - -export const pkgVersionPath = ({pkg, version, path}: NpmFileLocation) => - trimTrailingSlash(`${pkgVersion({pkg, version})}/${trimLeadingSlash(path)}`); - -export const trimLeadingSlash = (s: string) => - s.startsWith('/') ? s.slice(1) : s; - -export const trimTrailingSlash = (s: string) => - s.endsWith('/') ? s.slice(0, -1) : s; diff --git a/src/typescript-worker/worker-context.ts b/src/typescript-worker/worker-context.ts deleted file mode 100644 index b6188457..00000000 --- a/src/typescript-worker/worker-context.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - */ - -import {LanguageServiceContext} from './language-service-context.js'; -import {CachingCdn} from './caching-cdn.js'; -import {ImportMapResolver} from './import-map-resolver.js'; -import {WorkerConfig} from '../shared/worker-api.js'; - -let workerContext: WorkerContext | undefined; -let cacheKey = ''; - -/** - * Acquire the existing worker instance, or create a fresh one if missing. - * If the config differs from the existing instance's config, a new WorkerContext is - * instantiated and made the new instance. - */ -export function getWorkerContext(config: WorkerConfig) { - const configCacheKey = JSON.stringify(config); - if (workerContext && cacheKey === configCacheKey) { - return workerContext; - } - - cacheKey = configCacheKey; - workerContext = new WorkerContext(config); - return workerContext; -} - -export class WorkerContext { - readonly cdn: CachingCdn; - readonly importMapResolver: ImportMapResolver; - readonly languageServiceContext: LanguageServiceContext; - - constructor(config: WorkerConfig) { - this.importMapResolver = new ImportMapResolver(config.importMap); - this.cdn = new CachingCdn(config.cdnBaseUrl || 'https://unpkg.com'); - this.languageServiceContext = new LanguageServiceContext(); - } -} diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index f740f7c7..00000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "passed", - "failedTests": [] -} diff --git a/tsconfig-typescript-worker.json b/tsconfig-typescript-worker.json deleted file mode 100755 index 4f57aede..00000000 --- a/tsconfig-typescript-worker.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "composite": true, - "outDir": "./", - "rootDir": "./src", - "tsBuildInfoFile": "./typescript-worker/.tsbuildinfo", - "target": "es2019", - "lib": ["ES2020", "WebWorker"], - "skipLibCheck": true, - "skipDefaultLibCheck": true - }, - "include": [ - "src/typescript-worker/*.ts", - "src/typescript-worker/**/*.ts", - "src/playground-typescript-worker-entrypoint.ts" - ], - "exclude": [], - "references": [ - { - "path": "./src/shared" - } - ] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100755 index 3de50863..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "incremental": true, - "target": "es2019", - "module": "esnext", - "lib": ["ES2020", "ES2015.iterable", "DOM", "DOM.Iterable"], - "declaration": true, - "declarationMap": true, - "sourceMap": false, - "outDir": ".", - "rootDir": "src", - "tsBuildInfoFile": ".tsbuildinfo", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitThis": true, - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "importHelpers": true, - // TODO(aomarks) Remove when - // https://github.com/material-components/material-web/issues/2715 is fixed. - "skipLibCheck": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true - }, - "include": [ - "src/**/*.ts", - "src/internal/worker-api.ts", - "src/shared/util.ts" - ], - "exclude": [ - "src/service-worker", - "src/shared", - "src/typescript-worker", - "src/playground-typescript-worker-entrypoint.ts" - ], - "references": [ - { - "path": "src/service-worker" - }, - { - "path": "src/shared" - }, - { - "path": "./tsconfig-typescript-worker.json" - } - ] -} diff --git a/web-dev-server.config.js b/web-dev-server.config.js deleted file mode 100644 index cc349b85..00000000 --- a/web-dev-server.config.js +++ /dev/null @@ -1,24 +0,0 @@ -export default { - plugins: [ - { - // When we're using web-dev-server's --watch mode, we don't want our - // sample HTML files to get the injected web socket reload script tag. - // This plugin reverses that transformation just for those files. See - // https://github.com/modernweb-dev/web/issues/761 for a feature request - // to make this easier. - name: 'remove-injected-watch-script', - transform(ctx) { - if ( - ctx.url.match(/^(\/configurator\/project\/|\/demo\/.+\/).*\.html$/) - ) { - return { - body: ctx.body.replace( - /